--- autofs5-5.0.5.orig/debian/autofs5.dirs +++ autofs5-5.0.5/debian/autofs5.dirs @@ -0,0 +1 @@ +usr/share/autofs5/conffiles --- autofs5-5.0.5.orig/debian/autofs5.postrm +++ autofs5-5.0.5/debian/autofs5.postrm @@ -0,0 +1,12 @@ +#!/bin/sh +set -e + +if [ "$1" = "purge" ]; then + for CONFF in /etc/auto.master /etc/auto.net /etc/auto.misc /etc/auto.smb /etc/default/autofs; do + ucfr -p autofs5 $CONFF + ucf --purge $CONFF + rm -f $CONFF $CONFF.ucf-dist $CONFF.ucf-old $CONFF.ucf-new + done +fi + +#DEBHELPER# --- autofs5-5.0.5.orig/debian/changelog +++ autofs5-5.0.5/debian/changelog @@ -0,0 +1,214 @@ +autofs5 (5.0.5-0ubuntu6) karmic; urgency=low + + * backport to karmic + + -- Jeff Strunk Sun, 28 Aug 2011 16:30:00 -0600 + +autofs5 (5.0.5-0ubuntu6) natty; urgency=low + + * Remove mounting TYPE=nfs from start conditions, change to + start on filesystem and started networking to still solve + bug 733914 as well. (LP: #752730) + * Re-add sourcing of /etc/default/autofs to get OPTIONS so + upgrades won't lose their settings. + + -- Clint Byrum Sat, 09 Apr 2011 22:48:03 -0700 + +autofs5 (5.0.5-0ubuntu5) natty; urgency=low + + * Improve autofs.conf upstart script. Prevent race + when trying to start networking. (LP: #733914) + * debian/autofs5-ldap.install: Install schema in the right place. + (LP: #699855) + * Suggest smbfs if you want to use cifs. (LP: #579857) + * Dropped 13ldap_module_linkage.dpatch no longer needed. + * Refresh with missing upstream patches. + + -- Chuck Short Sat, 02 Apr 2011 22:25:34 -0400 + +autofs5 (5.0.5-0ubuntu4) natty; urgency=low + + * Add missing space to autofs.conf which was stopping autofs job + from ending at shutdown (LP:#718664). + + -- James Hunt Mon, 14 Feb 2011 11:01:18 +0000 + +autofs5 (5.0.5-0ubuntu3) natty; urgency=low + + * Fix FTBFS with ld --no-add-needed. + + -- Matthias Klose Fri, 07 Jan 2011 15:40:32 +0100 + +autofs5 (5.0.5-0ubuntu2) maverick; urgency=low + + [Joel Ebel] + * debian/patches/16group_buffer_size.patch: Increase group buffer size + geometrically rather than linearly when its found to be small. + (LP: #591100) + + [Chuck Short] + * debian/control: Fix conflict resolution. (LP: #520601) + + -- Chuck Short Wed, 30 Jun 2010 08:06:45 -0400 + +autofs5 (5.0.5-0ubuntu1) maverick; urgency=low + + * New upstream version: + - Dropped 10lsb_initscript.dpatch since we dont ship an init script. + - Fast forward through the upstream patches until 2010/06/21. + - Clean up lintian warnings. + - Bump to standards version 3.8.4. + + -- Chuck Short Mon, 21 Jun 2010 11:02:50 -0400 + +autofs5 (5.0.4-3.1ubuntu5) lucid; urgency=low + + FFE LP: #533029 + + * Replace init script with Upstart job: + - debian/rules, debian/autofs5.autofs.upstart: Add upstart job. + + -- Chuck Short Mon, 12 Apr 2010 08:56:32 -0400 + +autofs5 (5.0.4-3.1ubuntu4) lucid; urgency=low + + * debian/control: Update maintainer. + + -- Chuck Short Tue, 09 Feb 2010 09:39:56 -0500 + +autofs5 (5.0.4-3.1ubuntu3) lucid; urgency=low + + * debian/control: correctly define transitional packages for autofs, + autofs-ldap and autofs-hesiod (LP: #519119) + + -- Andrew Pollock Mon, 08 Feb 2010 22:38:34 -0800 + +autofs5 (5.0.4-3.1ubuntu2) lucid; urgency=low + + * debian/control: Provide a transitional package for upgrade from + autofs4 to autofs5. + + -- Chuck Short Thu, 04 Feb 2010 14:32:00 -0500 + +autofs5 (5.0.4-3.1ubuntu1) lucid; urgency=low + + * Merge from debian testing. Remaining changes: + - Removed experimental tag. + - Dropped Ubuntu fix for permissions of /etc/autofs_ldap_auth.conf in + favor of Debian's. + + -- Chuck Short Fri, 29 Jan 2010 06:13:19 +0000 + +autofs5 (5.0.4-3.1) unstable; urgency=low + + * Non-maintainer upload. + * add dh_fixperms -Xdebian/autofs5-ldap/etc/autofs_ldap_auth.conf to fix perms + (Closes: #557865) + + -- Patrick Winnertz Sat, 23 Jan 2010 14:54:16 +0100 + +autofs5 (5.0.4-3ubuntu2) lucid; urgency=low + + * debian/rules: Fix permissions of /etc/autofs_ldap_auth.conf. (LP: #368715) + + -- Chuck Short Thu, 07 Jan 2010 15:45:55 -0500 + +autofs5 (5.0.4-3ubuntu1) lucid; urgency=low + + * debian/control: Removed experimental tag + + -- Chuck Short Mon, 14 Dec 2009 14:39:24 -0500 + +autofs5 (5.0.4-3) unstable; urgency=low + + * Fix LSB initscript header to use keywords that + insserv knows about. Closes: #541841. + * Bump Standards version to 3.8.3. + * Add README.source. + + * Upload sponsored by Petter Reinholdtsen. + + -- Jan Christoph Nordholz Fri, 28 Aug 2009 21:24:14 +0200 + +autofs5 (5.0.4-2) unstable; urgency=low + + * Fast forward through the upstream patches until 2009/07/12. + * Adapt patch 10lsb_initscript, partially applied upstream. + * Bump Standards version to 3.8.2. + * Work around a typo in ./configure. + * Add a Homepage field. + * Clarify the GPL version. + * Add an example line suitable for nfsv4 environments to the + shipped auto.net. Closes: #533893. + + -- Jan Christoph Nordholz Sat, 25 Jul 2009 17:29:51 +0200 + +autofs5 (5.0.4-1) unstable; urgency=low + + * New upstream version (5.0.4 plus patchset as of 2009/03/09). + * Closes: #518728. + * Remove dpatch 14, applied upstream. + * New dpatch 14 to avoid using the relatively young SOCK_CLOEXEC + feature. + * Only invoke 'make clean' on clean target so ./configure isn't + purged. + * Fix a typo in the postinst regarding the ucf conffile handling. + * Add 'set -e' to package maintenance scripts. + * Drop unnecessary /var/run/autofs from package. + + -- Jan Christoph Nordholz Mon, 09 Mar 2009 01:16:48 +0100 + +autofs5 (5.0.3-3) unstable; urgency=high + + * Link ldap module against libssl, too. Closes: #490352. + * High urgency due to RC bugfix and no other changes. + + -- Jan Christoph Nordholz Fri, 11 Jul 2008 18:07:16 +0200 + +autofs5 (5.0.3-2) unstable; urgency=low + + * Update upstream patchset (2008/06/12) - five new patches. + * Bump Standards version to 3.8.0, debhelper to v7. + * Link ldap module against kerberos. Closes: #485470. + * /dev/urandom is sufficiently random for our purpose - use it + instead of /dev/random, which might block. Closes: #481257. + * Add watch file. + + -- Jan Christoph Nordholz Thu, 12 Jun 2008 22:24:27 +0200 + +autofs5 (5.0.3-1) unstable; urgency=low + + * Upload to unstable. + * New upstream version 5.0.3 plus current patchset (as of 2008/04/27). + * Bump Standards to 3.7.3, debhelper to v6. + * Add build-dependency on libxml2-dev. + + -- Jan Christoph Nordholz Mon, 28 Apr 2008 15:55:37 +0200 + +autofs5 (5.0.2-2) experimental; urgency=low + + * Work around configure's automatic detection attempts of /sbin/modprobe + and the /proc filesystem. In the former case, this saves us an + unnecessary build-dependency. + This should get the autobuilders going. + * Add Recommends: module-init-tools in accordance with #416597. + + -- Jan Christoph Nordholz Tue, 17 Jul 2007 13:33:12 +0200 + +autofs5 (5.0.2-1) experimental; urgency=low + + * Initial release: + * Upstream autofs 5.0.2 including the patches: + autofs-5.0.2-add-krb5-include + autofs-5.0.2-bad-proto-init + autofs-5.0.2-add-missing-multi-support + autofs-5.0.2-add-multi-nsswitch-lookup + * Own patches: + * Add LSB header to initscript. + * Configure the default auto.master location to be in /etc. + * Build the usual package triplet (plain, -ldap and -hesiod). + * Build the ldap module with SASL support. + * Be cautious and upload to experimental. + + -- Jan Christoph Nordholz Fri, 06 Jul 2007 19:26:12 +0200 + --- autofs5-5.0.5.orig/debian/configure_override +++ autofs5-5.0.5/debian/configure_override @@ -0,0 +1,13 @@ +#!/bin/bash + +test -n include/config.h || exit 1 + +cat - <>include/config.h + +/* override by Debian build system */ +#ifndef $1 +# define $1 $2 +#endif /* $1 */ +EOF + +exit 0 --- autofs5-5.0.5.orig/debian/autofs5-hesiod.dirs +++ autofs5-5.0.5/debian/autofs5-hesiod.dirs @@ -0,0 +1 @@ +usr/lib/autofs --- autofs5-5.0.5.orig/debian/control +++ autofs5-5.0.5/debian/control @@ -0,0 +1,80 @@ +Source: autofs5 +Section: utils +Priority: extra +Maintainer: Ubuntu Developers +XSBC-Orginal-Maintainer: Jan Christoph Nordholz +Standards-Version: 3.8.4 +Build-Depends: debhelper (>= 7), dpatch, autoconf, flex, bison, libhesiod-dev, libldap-dev, libsasl2-dev, libssl-dev, libkrb5-dev, libxml2-dev +Homepage: http://www.kernel.org/pub/linux/daemons/autofs/v5/ + +Package: autofs5 +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, ucf +Recommends: nfs-common, module-init-tools +Suggests: smbfs +Description: kernel-based automounter for Linux, version 5 + Autofs controls the operation of the automount daemons. The + automount daemons automatically mount filesystems when they + are used and unmount them after a period of inactivity. This + is done based on a set of pre-configured maps. + . + The kernel automounter implements an almost complete SunOS + style automounter under Linux. A recent version of the kernel + autofs4 module (builtin or separate) is required. + +Package: autofs5-ldap +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, autofs5 +Description: LDAP map support for autofs, version 5 + Autofs controls the operation of the automount daemons. The + automount daemons automatically mount filesystems when they + are used and unmount them after a period of inactivity. This + is done based on a set of pre-configured maps. + . + The kernel automounter implements an almost complete SunOS + style automounter under Linux. A recent version of the kernel + autofs4 module (builtin or separate) is required. + . + This is the LDAP module of the autofs experimental branch. + +Package: autofs5-hesiod +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, autofs5 +Description: Hesiod map support for autofs, version 5 + Autofs controls the operation of the automount daemons. The + automount daemons automatically mount filesystems when they + are used and unmount them after a period of inactivity. This + is done based on a set of pre-configured maps. + . + The kernel automounter implements an almost complete SunOS + style automounter under Linux. A recent version of the kernel + autofs4 module (builtin or separate) is required. + . + This is the Hesiod module of the autofs experimental branch. + +Package: autofs +Architecture: any +Depends: ${misc:Depends}, autofs5 +Conflicts: autofs ( << 4.1.4+debian-2.1ubuntu2 ) +Description: dummy transitional package from autofs to autofs5 + This transitional package helps users to transition from the autofs package to + the autofs5 package. Once this package and its dependencies are installed you + can safely remove it. + +Package: autofs-ldap +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, autofs5-ldap +Conflicts: autofs-ldap ( << 4.1.4+debian-2.1ubuntu2 ) +Description: dummy transitional package from autofs-ldap to autofs5-ldap + This transitional package helps users to transition from the autofs-ldap + package to the autofs5-ldap package. Once this package and its dependencies + are installed you can safely remove it. + +Package: autofs-hesiod +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, autofs5-hesiod +Conflicts: autofs-hesiod ( << 4.1.4+debian-2.1ubuntu2 ) +Description: dummy transitional package from autofs-hesiod to autofs5-hesiod + This transitional package helps users to transition from the autofs-ldap + package to the autofs5-ldap package. Once this package and its dependencies + are installed you can safely remove it. --- autofs5-5.0.5.orig/debian/copyright +++ autofs5-5.0.5/debian/copyright @@ -0,0 +1,66 @@ +This is the experimental (v5) branch of the automount daemon which can be +retrieved at ftp://ftp.kernel.org/pub/linux/daemons/autofs/v5/. +Development is taking place at the autofs kernel.org mailing list, available +at http://linux.kernel.org/mailman/listinfo/autofs. + +It was packaged for Debian (and is presently maintained) by Jan Christoph +Nordholz . + +Copyright holder: Transmeta Corporation + +License (exceptions listed below): + Copyright (C) 1997-2000 Transmeta Corporation -- 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., 51 Franklin St, Fifth Floor, + Boston, MA 02110-1301, 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. + + Portions Copyright (C) 1999-2000 Jeremy Fitzhardinge + Portions Copyright (C) 2001-2005 Ian Kent + +License for lib/syslog.c and lib/syslog.h: + Copyright (C) 1983,1988,1993 + The Regents of the University of California. All rights reserved. + + These files are licensed under the BSD License. + +License for modules/cyrus-sasl.c: + Copyright (C) 2005 Red Hat, Inc. -- All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * 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. + * Neither the name of Red Hat, Inc., 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER + 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. + +On Debian systems, the complete text of the GNU General Public License, version 2 +can be found in the file /usr/share/common-licenses/GPL-2. + +On Debian systems, the complete text of the BSD License can be found in the file +/usr/share/common-licenses/BSD. --- autofs5-5.0.5.orig/debian/README.source +++ autofs5-5.0.5/debian/README.source @@ -0,0 +1,6 @@ +The changes to the upstream source of this Debian package are managed +by the patch management system 'dpatch'. See the dpatch documentation +at /usr/share/doc/dpatch/README.source.gz for further information on +how to comfortably create new patches or edit existing ones. + + -- Jan Christoph Nordholz, 28 Aug 2009 --- autofs5-5.0.5.orig/debian/autofs5.postinst +++ autofs5-5.0.5/debian/autofs5.postinst @@ -0,0 +1,20 @@ +#!/bin/sh +set -e + +if [ "$1" = "configure" ]; then + ucfr autofs5 /etc/auto.master + ucfr autofs5 /etc/auto.net + ucfr autofs5 /etc/auto.misc + ucfr autofs5 /etc/auto.smb + ucfr autofs5 /etc/default/autofs + # fix for a previous typo + ucfr -p autofs5 /etc/default.autofs5 + + ucf /usr/share/autofs5/conffiles/auto.master /etc/auto.master + ucf /usr/share/autofs5/conffiles/auto.net /etc/auto.net + ucf /usr/share/autofs5/conffiles/auto.misc /etc/auto.misc + ucf /usr/share/autofs5/conffiles/auto.smb /etc/auto.smb + ucf /usr/share/autofs5/conffiles/default.autofs5 /etc/default/autofs +fi + +#DEBHELPER# --- autofs5-5.0.5.orig/debian/autofs5.install +++ autofs5-5.0.5/debian/autofs5.install @@ -0,0 +1,3 @@ +README usr/share/doc/autofs5/ +README.[cnrsv]* usr/share/doc/autofs5/ +CREDITS usr/share/doc/autofs5/ --- autofs5-5.0.5.orig/debian/rules +++ autofs5-5.0.5/debian/rules @@ -0,0 +1,60 @@ +#!/usr/bin/make -f + +.PHONY: clean build install binary binary-indep binary-arch + +clean: + dh_testdir + dh_testroot + rm -f build.stamp install.stamp + $(MAKE) clean + rm -f Makefile.conf config.log config.status include/config.h + dpatch deapply-all + dh_clean + +build: build.stamp +build.stamp: + dh_testdir + dpatch apply-all + ./configure --prefix=/usr \ + --with-confdir=/etc/default --mandir=/usr/share/man \ + --with-mapdir=/etc --with-hesiod --with-openldap --with-sasl \ + --enable-forced-shutdown --enable-ignore-busy + chmod 0751 debian/configure_override + debian/configure_override HAVE_MODPROBE + debian/configure_override PATH_MODPROBE \"/sbin/modprobe\" + debian/configure_override HAVE_LINUX_PROCFS + $(MAKE) + touch build.stamp + +install: install.stamp +install.stamp: build + dh_testdir + dh_testroot + dh_clean + $(MAKE) DESTDIR=../debian/autofs5 install + dh_installdirs + mv debian/autofs5/etc/auto.* debian/autofs5/usr/share/autofs5/conffiles/ + mv debian/autofs5/etc/default/autofs debian/autofs5/usr/share/autofs5/conffiles/default.autofs5 + mv debian/autofs5/usr/lib/autofs/lookup_ldap* debian/autofs5-ldap/usr/lib/autofs/ + mv debian/autofs5/usr/lib/autofs/*_hesiod* debian/autofs5-hesiod/usr/lib/autofs/ + mv debian/autofs5/etc/autofs_ldap_auth.conf debian/autofs5-ldap/etc/ + rm -rf debian/autofs5/var + +binary: binary-arch binary-indep +binary-arch: install + dh_testdir + dh_testroot + dh_install + dh_installchangelogs CHANGELOG + dh_installdocs + dh_installinit -pautofs5 --name=autofs -- start 19 2 3 4 5 . stop 81 0 1 6 . + dh_strip + dh_compress + dh_fixperms -Xdebian/autofs5-ldap/etc/autofs_ldap_auth.conf + dh_installdeb + dh_shlibdeps + dh_gencontrol + dh_md5sums + dh_builddeb + +binary-indep: --- autofs5-5.0.5.orig/debian/autofs5-ldap.dirs +++ autofs5-5.0.5/debian/autofs5-ldap.dirs @@ -0,0 +1,3 @@ +usr/lib/autofs +etc +etc/ldap --- autofs5-5.0.5.orig/debian/watch +++ autofs5-5.0.5/debian/watch @@ -0,0 +1,2 @@ +version=3 +ftp://ftp.kernel.org/pub/linux/daemons/autofs/v5/autofs-(5[^-]*)\.tar\.bz2 --- autofs5-5.0.5.orig/debian/compat +++ autofs5-5.0.5/debian/compat @@ -0,0 +1 @@ +7 --- autofs5-5.0.5.orig/debian/autofs5-ldap.install +++ autofs5-5.0.5/debian/autofs5-ldap.install @@ -0,0 +1,2 @@ +samples/autofs.schema etc/ldap/schema +samples/ldap* usr/share/doc/autofs5-ldap/examples/ --- autofs5-5.0.5.orig/debian/autofs5.autofs.upstart +++ autofs5-5.0.5/debian/autofs5.autofs.upstart @@ -0,0 +1,19 @@ +description "Automounter" +author "Chuck Short " + +start on filesystem and started networking +stop on runlevel [!2345] + +expect fork +respawn + +pre-start script + modprobe -q autofs4 || true +end script + +script + if [ -f /etc/default/autofs ] ; then + . /etc/default/autofs + fi + exec /usr/sbin/automount $OPTIONS +end script --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-fix-master-map-source-server-unavialable-handling.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-fix-master-map-source-server-unavialable-handling.dpatch @@ -0,0 +1,147 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-fix-master-map-source-server-unavialable-handling.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - fix master map source server unavailable handling + +From: Ian Kent + +If we get an NSS_STATUS_UNAVAIL from any server when trying to read +the master map we have no choice but to not update mounted automounts +because we can't know what entries may have come from the server that +isn't avialable. So we leave everything the way it is and wait until +the next re-read to update our mounts. +--- + + CHANGELOG | 1 + + daemon/automount.c | 5 +++-- + daemon/lookup.c | 9 +++++++++ + include/master.h | 1 + + lib/master.c | 9 ++++++++- + modules/lookup_file.c | 2 -- + 6 files changed, 22 insertions(+), 5 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index d95542d..fc4e738 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -29,6 +29,7 @@ + - add locality as valid ldap master map attribute. + - add locality as valid ldap master map attribute fix. + - add simple bind authentication. ++- fix master map source server unavailable handling. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/daemon/automount.c b/daemon/automount.c +index 7c44d4b..915928b 100644 +--- a/daemon/automount.c ++++ b/daemon/automount.c +@@ -1478,7 +1478,6 @@ static void handle_mounts_cleanup(void *arg) + master_free_mapent_sources(ap->entry, 1); + master_free_mapent(ap->entry); + } +- master_mutex_unlock(); + + if (clean) { + if (rmdir(path) == -1) { +@@ -1497,7 +1496,9 @@ static void handle_mounts_cleanup(void *arg) + */ + if (!submount) + pthread_kill(state_mach_thid, SIGTERM); +- ++ ++ master_mutex_unlock(); ++ + return; + } + +diff --git a/daemon/lookup.c b/daemon/lookup.c +index a4b9a80..8537861 100644 +--- a/daemon/lookup.c ++++ b/daemon/lookup.c +@@ -157,6 +157,9 @@ int lookup_nss_read_master(struct master *master, time_t age) + result = do_read_master(master, "file", age); + } + ++ if (result == NSS_STATUS_UNAVAIL) ++ master->read_fail = 1; ++ + return !result; + } else { + char *name = master->name; +@@ -194,6 +197,9 @@ int lookup_nss_read_master(struct master *master, time_t age) + result = do_read_master(master, source, age); + master->name = name; + ++ if (result == NSS_STATUS_UNAVAIL) ++ master->read_fail = 1; ++ + return !result; + } + } +@@ -248,6 +254,9 @@ int lookup_nss_read_master(struct master *master, time_t age) + continue; + } + ++ if (result == NSS_STATUS_UNAVAIL) ++ master->read_fail = 1; ++ + status = check_nss_result(this, result); + if (status >= 0) { + free_sources(&nsslist); +diff --git a/include/master.h b/include/master.h +index c519e97..0d6aa82 100644 +--- a/include/master.h ++++ b/include/master.h +@@ -56,6 +56,7 @@ struct master { + unsigned int recurse; + unsigned int depth; + unsigned int reading; ++ unsigned int read_fail; + unsigned int default_ghost; + unsigned int default_logging; + unsigned int default_timeout; +diff --git a/lib/master.c b/lib/master.c +index 83019aa..196b6b9 100644 +--- a/lib/master.c ++++ b/lib/master.c +@@ -794,6 +794,7 @@ struct master *master_new(const char *name, unsigned int timeout, unsigned int g + master->recurse = 0; + master->depth = 0; + master->reading = 0; ++ master->read_fail = 0; + master->default_ghost = ghost; + master->default_timeout = timeout; + master->default_logging = defaults_get_logging(); +@@ -821,7 +822,13 @@ int master_read_master(struct master *master, time_t age, int readall) + master_init_scan(); + + lookup_nss_read_master(master, age); +- master_mount_mounts(master, age, readall); ++ if (!master->read_fail) ++ master_mount_mounts(master, age, readall); ++ else { ++ master->read_fail = 0; ++ if (!readall) ++ master_mount_mounts(master, age, readall); ++ } + + master_mutex_lock(); + +diff --git a/modules/lookup_file.c b/modules/lookup_file.c +index e43ab2f..6104d0c 100644 +--- a/modules/lookup_file.c ++++ b/modules/lookup_file.c +@@ -656,8 +656,6 @@ int lookup_read_map(struct autofs_point *ap, time_t age, void *context) + if (!status) { + warn(ap->logopt, + "failed to read included map %s", key); +- fclose(f); +- return NSS_STATUS_UNAVAIL; + } + } else { + char *s_key; --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-add-lsb-force-reload-and-try-restart.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-add-lsb-force-reload-and-try-restart.dpatch @@ -0,0 +1,56 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-add-lsb-force-reload-and-try-restart.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - add lsb force-reload and try-restart + +From: Ian Kent + +LSB specifies two additional init script options, force-reload and +try-restart. The force-reload option is supposed to do what restart +does and does that. The try-restart option is essentially condrestart +and is another option for that action. This change is made only to +RedHat init script. +--- + + redhat/autofs.init.in | 10 +++------- + 1 files changed, 3 insertions(+), 7 deletions(-) + + +diff --git a/redhat/autofs.init.in b/redhat/autofs.init.in +index 05ab145..4a915ec 100644 +--- a/redhat/autofs.init.in ++++ b/redhat/autofs.init.in +@@ -173,7 +173,7 @@ case "$1" in + status) + status -p /var/run/autofs.pid -l autofs $prog + ;; +- restart) ++ restart|force-reload) + restart + ;; + forcerestart) +@@ -183,19 +183,15 @@ case "$1" in + reload) + reload + ;; +- condrestart) ++ condrestart|try-restart) + if [ -f /var/lock/subsys/autofs ]; then + restart + fi + ;; + usage) +- echo $"Usage: $0 {start|forcestart|stop|status|restart|forcerestart|reload|condrestart}" ++ echo $"Usage: $0 {start|forcestart|stop|status|restart|force-reload|forcerestart|reload|condrestart|try-restart}" + exit 0 + ;; +- try-restart|force-reload) +- echo "$1 service action not supported" +- exit 3 +- ;; + *) + echo "unknown, invalid or excess argument(s)" + exit 2 --- autofs5-5.0.5.orig/debian/patches/11default_automaster_location.dpatch +++ autofs5-5.0.5/debian/patches/11default_automaster_location.dpatch @@ -0,0 +1,21 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## default_automaster_location.dpatch by +## +## DP: Set /etc/auto.master as the default location of the automounter +## DP: master map, because that file is surely available (the package +## DP: installs a default one). If the admin already has an auto.master +## DP: map in a different place, he can customize the file later. + +@DPATCH@ + +--- autofs5-5.0.2/samples/autofs.conf.default.in.orig 2007-07-06 19:21:33.000000000 +0200 ++++ autofs5-5.0.2/samples/autofs.conf.default.in 2007-07-06 19:21:41.000000000 +0200 +@@ -3,7 +3,7 @@ + # + # MASTER_MAP_NAME - default map name for the master map. + # +-#MASTER_MAP_NAME="auto.master" ++MASTER_MAP_NAME="/etc/auto.master" + # + # TIMEOUT - set the default mount timeout (default 600). + # --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-fix-memory-leak-on-reload.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-fix-memory-leak-on-reload.dpatch @@ -0,0 +1,78 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-fix-memory-leak-on-reload.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - fix memory leak on reload + +From: Ian Kent + +When sending a signal to the automount daemon to re-load the maps a map +entry cache is pre-allocated before checking if the entry already exists. +If the master map entry was found to exist the pre-allocated cache was +not being freed. + +If there are a large number of entries in the master map and there are +frequent re-load requests sent to the daemon the memory leak will cause +the system to become unstable fairly quilkly. + +Since the map entry cache (allocated for each map entry) is fairly large +these days (and is configurable) pre-allocating it is no longer a cheap +operation. This patch fixes the memory leak and only allocates a map +entry cache if the entry does not already exist. +--- + + CHANGELOG | 1 + + lib/master.c | 17 +++++++++++++++-- + 2 files changed, 16 insertions(+), 2 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index 20566a6..df2ec09 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -16,6 +16,7 @@ + - check for path mount location in generic module. + - dont fail mount on access fail. + - fix rpc fail on large export list. ++- fix memory leak on reload. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/lib/master.c b/lib/master.c +index 8455f40..83019aa 100644 +--- a/lib/master.c ++++ b/lib/master.c +@@ -190,9 +190,15 @@ master_add_map_source(struct master_mapent *entry, + + master_source_writelock(entry); + +- if (!entry->maps) ++ if (!entry->maps) { ++ source->mc = cache_init(entry->ap, source); ++ if (!source->mc) { ++ master_free_map_source(source, 0); ++ master_source_unlock(entry); ++ return NULL; ++ } + entry->maps = source; +- else { ++ } else { + struct map_source *this, *last, *next; + + /* Typically there only a few map sources */ +@@ -205,6 +211,13 @@ master_add_map_source(struct master_mapent *entry, + return this; + } + ++ source->mc = cache_init(entry->ap, source); ++ if (!source->mc) { ++ master_free_map_source(source, 0); ++ master_source_unlock(entry); ++ return NULL; ++ } ++ + last = NULL; + next = entry->maps; + while (next) { --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-fix-rpc-large-export-list.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-fix-rpc-large-export-list.dpatch @@ -0,0 +1,148 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-fix-rpc-large-export-list.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - fix rpc fail on large export list + +From: Ian Kent + +If the export list on a server is larger than the UDP transport packet +size the transfer will fail and autofs will try TCP instead, but there +were some problems with the conversion to allow for IPv6 using libtirpc. + +When creating the local socket for an RPC connection we incorrectly +performed a connect instead of a bind to the ilocal TCP socket. Aslo the +timed connect, which should be done before creating the RPC client was +not being done, which can lead to lengthy timeouts. +--- + + CHANGELOG | 1 + + lib/rpc_subs.c | 47 ++++++++++++++++++++++++----------------------- + 2 files changed, 25 insertions(+), 23 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index 88bcc1b..20566a6 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -15,6 +15,7 @@ + - fix pidof init script usage. + - check for path mount location in generic module. + - dont fail mount on access fail. ++- fix rpc fail on large export list. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/lib/rpc_subs.c b/lib/rpc_subs.c +index 628f0fc..3b11dce 100644 +--- a/lib/rpc_subs.c ++++ b/lib/rpc_subs.c +@@ -53,6 +53,7 @@ + /* Get numeric value of the n bits starting at position p */ + #define getbits(x, p, n) ((x >> (p + 1 - n)) & ~(~0 << n)) + ++static int connect_nb(int, struct sockaddr *, socklen_t, struct timeval *); + inline void dump_core(void); + + static CLIENT *rpc_clntudp_create(struct sockaddr *addr, struct conn_info *info, int *fd) +@@ -97,11 +98,17 @@ static CLIENT *rpc_clnttcp_create(struct sockaddr *addr, struct conn_info *info, + struct sockaddr_in *in4_raddr; + struct sockaddr_in6 *in6_raddr; + CLIENT *client = NULL; ++ socklen_t slen; + + switch (addr->sa_family) { + case AF_INET: + in4_raddr = (struct sockaddr_in *) addr; + in4_raddr->sin_port = htons(info->port); ++ slen = sizeof(struct sockaddr_in); ++ ++ if (connect_nb(*fd, addr, slen, &info->timeout) < 0) ++ break; ++ + client = clnttcp_create(in4_raddr, + info->program, info->version, fd, + info->send_sz, info->recv_sz); +@@ -114,6 +121,11 @@ static CLIENT *rpc_clnttcp_create(struct sockaddr *addr, struct conn_info *info, + #else + in6_raddr = (struct sockaddr_in6 *) addr; + in6_raddr->sin6_port = htons(info->port); ++ slen = sizeof(struct sockaddr_in6); ++ ++ if (connect_nb(*fd, addr, slen, &info->timeout) < 0) ++ break; ++ + client = clnttcp6_create(in6_raddr, + info->program, info->version, fd, + info->send_sz, info->recv_sz); +@@ -260,32 +272,21 @@ static CLIENT *rpc_do_create_client(struct sockaddr *addr, struct conn_info *inf + return NULL; + } + ++ if (!info->client) { ++ *fd = open_sock(addr->sa_family, type, proto); ++ if (*fd < 0) ++ return NULL; ++ ++ if (bind(*fd, laddr, slen) < 0) ++ return NULL; ++ } ++ + switch (info->proto->p_proto) { + case IPPROTO_UDP: +- if (!info->client) { +- *fd = open_sock(addr->sa_family, type, proto); +- if (*fd < 0) +- return NULL; +- +- if (bind(*fd, laddr, slen) < 0) { +- close(*fd); +- return NULL; +- } +- } + client = rpc_clntudp_create(addr, info, fd); + break; + + case IPPROTO_TCP: +- if (!info->client) { +- *fd = open_sock(addr->sa_family, type, proto); +- if (*fd < 0) +- return NULL; +- +- if (connect_nb(*fd, laddr, slen, &info->timeout) < 0) { +- close(*fd); +- return NULL; +- } +- } + client = rpc_clnttcp_create(addr, info, fd); + break; + +@@ -327,7 +328,7 @@ static CLIENT *create_udp_client(struct conn_info *info) + if (client) + goto done; + +- if (!info->client) { ++ if (!info->client && fd != RPC_ANYSOCK) { + close(fd); + fd = RPC_ANYSOCK; + } +@@ -352,7 +353,7 @@ static CLIENT *create_udp_client(struct conn_info *info) + if (client) + break; + +- if (!info->client) { ++ if (!info->client && fd != RPC_ANYSOCK) { + close(fd); + fd = RPC_ANYSOCK; + } +@@ -477,7 +478,7 @@ static CLIENT *create_tcp_client(struct conn_info *info) + if (client) + break; + +- if (!info->client) { ++ if (!info->client && fd != RPC_ANYSOCK) { + close(fd); + fd = RPC_ANYSOCK; + } --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-make-verbose-mode-a-little-less-verbose.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-make-verbose-mode-a-little-less-verbose.dpatch @@ -0,0 +1,100 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-make-verbose-mode-a-little-less-verbose.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - Make "verbose" mode a little less verbose + +From: Leonardo Chiquitto + +Remove some log message duplication for verbose logging. +--- + + daemon/automount.c | 2 +- + daemon/lookup.c | 2 +- + modules/mount_changer.c | 2 +- + modules/mount_ext2.c | 2 +- + modules/mount_generic.c | 2 +- + modules/mount_nfs.c | 2 +- + 6 files changed, 6 insertions(+), 6 deletions(-) + + +diff --git a/daemon/automount.c b/daemon/automount.c +index 206734b..9939a25 100644 +--- a/daemon/automount.c ++++ b/daemon/automount.c +@@ -512,7 +512,7 @@ static int umount_subtree_mounts(struct autofs_point *ap, const char *path, unsi + * it already to ensure it's ok to remove any offset triggers. + */ + if (!is_mm_root && is_mounted(_PATH_MOUNTED, path, MNTS_REAL)) { +- info(ap->logopt, "unmounting dir = %s", path); ++ debug(ap->logopt, "unmounting dir = %s", path); + if (umount_ent(ap, path)) { + warn(ap->logopt, "could not umount dir %s", path); + left++; +diff --git a/daemon/lookup.c b/daemon/lookup.c +index f5d9da8..a4bd07f 100644 +--- a/daemon/lookup.c ++++ b/daemon/lookup.c +@@ -688,7 +688,7 @@ static int lookup_name_file_source_instance(struct autofs_point *ap, struct map_ + char *type, *format; + + if (stat(map->argv[0], &st) == -1) { +- warn(ap->logopt, "file map not found"); ++ debug(ap->logopt, "file map not found"); + return NSS_STATUS_NOTFOUND; + } + +diff --git a/modules/mount_changer.c b/modules/mount_changer.c +index f4d82dd..d7bfa09 100644 +--- a/modules/mount_changer.c ++++ b/modules/mount_changer.c +@@ -129,7 +129,7 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int + + return 1; + } else { +- info(ap->logopt, MODPREFIX "mounted %s type %s on %s", ++ debug(ap->logopt, MODPREFIX "mounted %s type %s on %s", + what, fstype, fullpath); + return 0; + } +diff --git a/modules/mount_ext2.c b/modules/mount_ext2.c +index 26d59d1..1edf347 100644 +--- a/modules/mount_ext2.c ++++ b/modules/mount_ext2.c +@@ -140,7 +140,7 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int + + return 1; + } else { +- info(ap->logopt, ++ debug(ap->logopt, + MODPREFIX "mounted %s type %s on %s", + what, fstype, fullpath); + return 0; +diff --git a/modules/mount_generic.c b/modules/mount_generic.c +index da85d1a..79e3d32 100644 +--- a/modules/mount_generic.c ++++ b/modules/mount_generic.c +@@ -122,7 +122,7 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int + + return 1; + } else { +- info(ap->logopt, MODPREFIX "mounted %s type %s on %s", ++ debug(ap->logopt, MODPREFIX "mounted %s type %s on %s", + loc, fstype, fullpath); + free(loc); + return 0; +diff --git a/modules/mount_nfs.c b/modules/mount_nfs.c +index 21e1929..9110eba 100644 +--- a/modules/mount_nfs.c ++++ b/modules/mount_nfs.c +@@ -251,7 +251,7 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int + } + + if (!err) { +- info(ap->logopt, MODPREFIX "mounted %s on %s", loc, fullpath); ++ debug(ap->logopt, MODPREFIX "mounted %s on %s", loc, fullpath); + free(loc); + free_host_list(&hosts); + return 0; --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-fix-mountd-vers-retry.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-fix-mountd-vers-retry.dpatch @@ -0,0 +1,91 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-fix-mountd-vers-retry.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - fix mountd vers retry + +From: Ian Kent + +The autofs RPC function used to get the exports list from a host to +be used by the hosts internal map did not try all potentially available +mountd versions. This leads to a failure to get the export list when +certain mountd protocol versions are disabled. +--- + + CHANGELOG | 1 + + lib/rpc_subs.c | 26 +++++++++++++++++++++----- + 2 files changed, 22 insertions(+), 5 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index 5ad2836..e55b873 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -59,6 +59,7 @@ + - fix isspace() wild card substition. + - auto adjust ldap page size. + - fix prune cache valid check. ++- fix mountd vers retry. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/lib/rpc_subs.c b/lib/rpc_subs.c +index 3b11dce..9da3d38 100644 +--- a/lib/rpc_subs.c ++++ b/lib/rpc_subs.c +@@ -53,6 +53,12 @@ + /* Get numeric value of the n bits starting at position p */ + #define getbits(x, p, n) ((x >> (p + 1 - n)) & ~(~0 << n)) + ++static const rpcvers_t mount_vers[] = { ++ MOUNTVERS_NFSV3, ++ MOUNTVERS_POSIX, ++ MOUNTVERS, ++}; ++ + static int connect_nb(int, struct sockaddr *, socklen_t, struct timeval *); + inline void dump_core(void); + +@@ -846,6 +852,7 @@ static int rpc_get_exports_proto(struct conn_info *info, exports *exp) + enum clnt_stat status; + int proto = info->proto->p_proto; + unsigned int option = info->close_option; ++ int vers_entry; + + if (info->proto->p_proto == IPPROTO_UDP) { + info->send_sz = UDPMSGSIZE; +@@ -862,10 +869,19 @@ static int rpc_get_exports_proto(struct conn_info *info, exports *exp) + + client->cl_auth = authunix_create_default(); + +- status = clnt_call(client, MOUNTPROC_EXPORT, +- (xdrproc_t) xdr_void, NULL, +- (xdrproc_t) xdr_exports, (caddr_t) exp, +- info->timeout); ++ vers_entry = 0; ++ while (1) { ++ status = clnt_call(client, MOUNTPROC_EXPORT, ++ (xdrproc_t) xdr_void, NULL, ++ (xdrproc_t) xdr_exports, (caddr_t) exp, ++ info->timeout); ++ if (status != RPC_PROGVERSMISMATCH) ++ break; ++ if (++vers_entry > 2) ++ break; ++ CLNT_CONTROL(client, CLSET_VERS, ++ (void *) &mount_vers[vers_entry]); ++ } + + /* Only play with the close options if we think it completed OK */ + if (proto == IPPROTO_TCP && status == RPC_SUCCESS) { +@@ -934,7 +950,7 @@ exports rpc_get_exports(const char *host, long seconds, long micros, unsigned in + info.addr = NULL; + info.addr_len = 0; + info.program = MOUNTPROG; +- info.version = MOUNTVERS; ++ info.version = mount_vers[0]; + info.send_sz = 0; + info.recv_sz = 0; + info.timeout.tv_sec = seconds; --- autofs5-5.0.5.orig/debian/patches/13ldap_module_linkage.dpatch +++ autofs5-5.0.5/debian/patches/13ldap_module_linkage.dpatch @@ -0,0 +1,18 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 13ldap_module_linkage.dpatch by +## +## DP: lookup_ldap.so has symbol references to libcrypto and libkrb5, +## DP: so link to them explicitly. + +@DPATCH@ +--- autofs5-5.0.3.orig/modules/Makefile 2008-06-12 21:53:14.000000000 +0200 ++++ autofs5-5.0.3/modules/Makefile 2008-06-12 21:53:26.000000000 +0200 +@@ -43,7 +43,7 @@ + ifeq ($(SASL), 1) + SASL_OBJ = cyrus-sasl.o + LDAP_FLAGS += $(SASL_FLAGS) $(XML_FLAGS) -DLDAP_THREAD_SAFE +- LIBLDAP += $(LIBSASL) $(XML_LIBS) ++ LIBLDAP += $(LIBSASL) $(XML_LIBS) -lcrypto -lkrb5 + endif + endif + --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-remove-state-machine-timed-wait.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-remove-state-machine-timed-wait.dpatch @@ -0,0 +1,124 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-remove-state-machine-timed-wait.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - remove state machine timed wait + +From: Ian Kent + +We are seeing a problem using timed waits when running under KVM. + +Using timed condition waits in the state machine (and in some other +places) has been used because of observed task throughput problems +in the past. Also, we've seen condition waits not reacting to signals +occassionaly. + +But now we are seeing problems with the setup of the wait time within +KVM VMs causing the condition wait to go into a tight loop using +excessive CPU. + +Changing the state queue handler to not use timed waits appears to +not have the previously observed throughput problems, hopefully we +won't see lost signals either. +--- + + CHANGELOG | 1 + + daemon/state.c | 30 +++++++----------------------- + 2 files changed, 8 insertions(+), 23 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index f12128c..a998a67 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -43,6 +43,7 @@ + - fix mapent becomes negative during lookup. + - check each dc server individually. + - fix negative cache included map lookup. ++- remove state machine timed wait. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/daemon/state.c b/daemon/state.c +index 27bc6de..38617c3 100644 +--- a/daemon/state.c ++++ b/daemon/state.c +@@ -197,11 +197,11 @@ void expire_cleanup(void *arg) + } + } + ++ st_set_done(ap); ++ + if (next != ST_INVAL) + __st_add_task(ap, next); + +- st_set_done(ap); +- + st_mutex_unlock(); + + return; +@@ -332,11 +332,10 @@ static void do_readmap_cleanup(void *arg) + st_mutex_lock(); + + ap->readmap_thread = 0; +- st_ready(ap); + st_set_done(ap); +- + if (!ap->submount) + alarm_add(ap, ap->exp_runfreq); ++ st_ready(ap); + + st_mutex_unlock(); + +@@ -1060,8 +1059,6 @@ static void *st_queue_handler(void *arg) + { + struct list_head *head; + struct list_head *p; +- struct timespec wait; +- struct timeval now; + int status, ret; + + st_mutex_lock(); +@@ -1072,17 +1069,11 @@ static void *st_queue_handler(void *arg) + * entry is added. + */ + head = &state_queue; +- gettimeofday(&now, NULL); +- wait.tv_sec = now.tv_sec + 1; +- wait.tv_nsec = now.tv_usec * 1000; + + while (list_empty(head)) { +- status = pthread_cond_timedwait(&cond, &mutex, &wait); +- if (status) { +- if (status == ETIMEDOUT) +- break; ++ status = pthread_cond_wait(&cond, &mutex); ++ if (status) + fatal(status); +- } + } + + p = head->next; +@@ -1108,18 +1099,11 @@ static void *st_queue_handler(void *arg) + } + + while (1) { +- gettimeofday(&now, NULL); +- wait.tv_sec = now.tv_sec + 1; +- wait.tv_nsec = now.tv_usec * 1000; +- + signaled = 0; + while (!signaled) { +- status = pthread_cond_timedwait(&cond, &mutex, &wait); +- if (status) { +- if (status == ETIMEDOUT) +- break; ++ status = pthread_cond_wait(&cond, &mutex); ++ if (status) + fatal(status); +- } + } + + head = &state_queue; --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-expire-thread-use-pending-mutex.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-expire-thread-use-pending-mutex.dpatch @@ -0,0 +1,500 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-expire-thread-use-pending-mutex.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - expire thread use pending mutex + +From: Ian Kent + +Some time ago the mount request thread creation was changed to +use its own mutex for its condition handling due to execution +order problems under heavy mount request pressure. When there +are a large number of master map entries we see the same problem +with expire thread creation. This patch changes the expire thread +creation to use the same approach as the mount thread creation. +--- + + CHANGELOG | 1 + + daemon/direct.c | 76 +++++++++++---------------------------------------- + daemon/indirect.c | 76 +++++++++++---------------------------------------- + include/automount.h | 41 ++++++++++++++++++++++++++++ + 4 files changed, 76 insertions(+), 118 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index 5f6465a..e9deabf 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -46,6 +46,7 @@ + - remove state machine timed wait. + - remove extra read master map call. + - fix error handing in do_mount_indirect(). ++- expire thread use pending mutex. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/daemon/direct.c b/daemon/direct.c +index 9b4e57b..4e8749b 100644 +--- a/daemon/direct.c ++++ b/daemon/direct.c +@@ -35,6 +35,7 @@ + #include + #include + ++#define INCLUDE_PENDING_FUNCTIONS + #include "automount.h" + + /* Attribute to create detached thread */ +@@ -48,8 +49,6 @@ pthread_key_t key_mnt_direct_params; + pthread_key_t key_mnt_offset_params; + pthread_once_t key_mnt_params_once = PTHREAD_ONCE_INIT; + +-static pthread_mutex_t ea_mutex = PTHREAD_MUTEX_INITIALIZER; +- + static void key_mnt_params_destroy(void *arg) + { + struct mnt_params *mp; +@@ -952,17 +951,6 @@ void *expire_proc_direct(void *arg) + return NULL; + } + +-static void pending_cond_destroy(void *arg) +-{ +- struct pending_args *mt; +- int status; +- +- mt = (struct pending_args *) arg; +- status = pthread_cond_destroy(&mt->cond); +- if (status) +- fatal(status); +-} +- + static void expire_send_fail(void *arg) + { + struct ioctl_ops *ops = get_ioctl_ops(); +@@ -972,19 +960,6 @@ static void expire_send_fail(void *arg) + mt->ioctlfd, mt->wait_queue_token, -ENOENT); + } + +-static void free_pending_args(void *arg) +-{ +- struct pending_args *mt = arg; +- free(mt); +-} +- +-static void expire_mutex_unlock(void *arg) +-{ +- int status = pthread_mutex_unlock(&ea_mutex); +- if (status) +- fatal(status); +-} +- + static void *do_expire_direct(void *arg) + { + struct ioctl_ops *ops = get_ioctl_ops(); +@@ -995,9 +970,7 @@ static void *do_expire_direct(void *arg) + + args = (struct pending_args *) arg; + +- status = pthread_mutex_lock(&ea_mutex); +- if (status) +- fatal(status); ++ pending_mutex_lock(args); + + memcpy(&mt, args, sizeof(struct pending_args)); + +@@ -1008,7 +981,7 @@ static void *do_expire_direct(void *arg) + if (status) + fatal(status); + +- expire_mutex_unlock(NULL); ++ pending_mutex_unlock(args); + + pthread_cleanup_push(expire_send_fail, &mt); + +@@ -1124,7 +1097,7 @@ int handle_packet_expire_direct(struct autofs_point *ap, autofs_packet_expire_di + if (status) + fatal(status); + +- status = pthread_mutex_lock(&ea_mutex); ++ status = pthread_mutex_init(&mt->mutex, NULL); + if (status) + fatal(status); + +@@ -1140,6 +1113,8 @@ int handle_packet_expire_direct(struct autofs_point *ap, autofs_packet_expire_di + debug(ap->logopt, "token %ld, name %s", + (unsigned long) pkt->wait_queue_token, mt->name); + ++ pending_mutex_lock(mt); ++ + status = pthread_create(&thid, &th_attr_detached, do_expire_direct, mt); + if (status) { + error(ap->logopt, "expire thread create failed"); +@@ -1147,8 +1122,9 @@ int handle_packet_expire_direct(struct autofs_point *ap, autofs_packet_expire_di + mt->ioctlfd, pkt->wait_queue_token, -status); + cache_unlock(mc); + master_source_unlock(ap->entry); +- expire_mutex_unlock(NULL); ++ pending_mutex_unlock(mt); + pending_cond_destroy(mt); ++ pending_mutex_destroy(mt); + free_pending_args(mt); + pthread_setcancelstate(state, NULL); + return 1; +@@ -1158,8 +1134,9 @@ int handle_packet_expire_direct(struct autofs_point *ap, autofs_packet_expire_di + master_source_unlock(ap->entry); + + pthread_cleanup_push(free_pending_args, mt); ++ pthread_cleanup_push(pending_mutex_destroy, mt); + pthread_cleanup_push(pending_cond_destroy, mt); +- pthread_cleanup_push(expire_mutex_unlock, NULL); ++ pthread_cleanup_push(pending_mutex_unlock, mt); + pthread_setcancelstate(state, NULL); + + mt->signaled = 0; +@@ -1167,7 +1144,7 @@ int handle_packet_expire_direct(struct autofs_point *ap, autofs_packet_expire_di + gettimeofday(&now, NULL); + wait.tv_sec = now.tv_sec + 2; + wait.tv_nsec = now.tv_usec * 1000; +- status = pthread_cond_wait(&mt->cond, &ea_mutex); ++ status = pthread_cond_timedwait(&mt->cond, &mt->mutex, &wait); + if (status && status != ETIMEDOUT) + fatal(status); + } +@@ -1175,6 +1152,7 @@ int handle_packet_expire_direct(struct autofs_point *ap, autofs_packet_expire_di + pthread_cleanup_pop(1); + pthread_cleanup_pop(1); + pthread_cleanup_pop(1); ++ pthread_cleanup_pop(1); + + return 0; + } +@@ -1188,22 +1166,6 @@ static void mount_send_fail(void *arg) + ops->close(ap->logopt, mt->ioctlfd); + } + +-static void pending_mutex_destroy(void *arg) +-{ +- struct pending_args *mt = (struct pending_args *) arg; +- int status = pthread_mutex_destroy(&mt->mutex); +- if (status) +- fatal(status); +-} +- +-static void mount_mutex_unlock(void *arg) +-{ +- struct pending_args *mt = (struct pending_args *) arg; +- int status = pthread_mutex_unlock(&mt->mutex); +- if (status) +- fatal(status); +-} +- + static void *do_mount_direct(void *arg) + { + struct ioctl_ops *ops = get_ioctl_ops(); +@@ -1214,9 +1176,7 @@ static void *do_mount_direct(void *arg) + + args = (struct pending_args *) arg; + +- status = pthread_mutex_lock(&args->mutex); +- if (status) +- fatal(status); ++ pending_mutex_lock(args); + + memcpy(&mt, args, sizeof(struct pending_args)); + +@@ -1227,7 +1187,7 @@ static void *do_mount_direct(void *arg) + if (status) + fatal(status); + +- mount_mutex_unlock(args); ++ pending_mutex_unlock(args); + + pthread_cleanup_push(mount_send_fail, &mt); + +@@ -1434,9 +1394,7 @@ int handle_packet_missing_direct(struct autofs_point *ap, autofs_packet_missing_ + if (status) + fatal(status); + +- status = pthread_mutex_lock(&mt->mutex); +- if (status) +- fatal(status); ++ pending_mutex_lock(mt); + + mt->ap = ap; + mt->ioctlfd = ioctlfd; +@@ -1458,7 +1416,7 @@ int handle_packet_missing_direct(struct autofs_point *ap, autofs_packet_missing_ + cache_unlock(mc); + master_source_unlock(ap->entry); + master_mutex_unlock(); +- mount_mutex_unlock(mt); ++ pending_mutex_unlock(mt); + pending_cond_destroy(mt); + pending_mutex_destroy(mt); + free_pending_args(mt); +@@ -1474,7 +1432,7 @@ int handle_packet_missing_direct(struct autofs_point *ap, autofs_packet_missing_ + pthread_cleanup_push(free_pending_args, mt); + pthread_cleanup_push(pending_mutex_destroy, mt); + pthread_cleanup_push(pending_cond_destroy, mt); +- pthread_cleanup_push(mount_mutex_unlock, mt); ++ pthread_cleanup_push(pending_mutex_unlock, mt); + pthread_setcancelstate(state, NULL); + + mt->signaled = 0; +diff --git a/daemon/indirect.c b/daemon/indirect.c +index 09d784b..f3651bd 100644 +--- a/daemon/indirect.c ++++ b/daemon/indirect.c +@@ -34,13 +34,12 @@ + #include + #include + ++#define INCLUDE_PENDING_FUNCTIONS + #include "automount.h" + + /* Attribute to create detached thread */ + extern pthread_attr_t th_attr_detached; + +-static pthread_mutex_t ea_mutex = PTHREAD_MUTEX_INITIALIZER; +- + static int unlink_mount_tree(struct autofs_point *ap, struct mnt_list *mnts) + { + struct mnt_list *this; +@@ -587,17 +586,6 @@ void *expire_proc_indirect(void *arg) + return NULL; + } + +-static void pending_cond_destroy(void *arg) +-{ +- struct pending_args *mt; +- int status; +- +- mt = (struct pending_args *) arg; +- status = pthread_cond_destroy(&mt->cond); +- if (status) +- fatal(status); +-} +- + static void expire_send_fail(void *arg) + { + struct ioctl_ops *ops = get_ioctl_ops(); +@@ -607,19 +595,6 @@ static void expire_send_fail(void *arg) + ap->ioctlfd, mt->wait_queue_token, -ENOENT); + } + +-static void free_pending_args(void *arg) +-{ +- struct pending_args *mt = arg; +- free(mt); +-} +- +-static void expire_mutex_unlock(void *arg) +-{ +- int status = pthread_mutex_unlock(&ea_mutex); +- if (status) +- fatal(status); +-} +- + static void *do_expire_indirect(void *arg) + { + struct ioctl_ops *ops = get_ioctl_ops(); +@@ -629,9 +604,7 @@ static void *do_expire_indirect(void *arg) + + args = (struct pending_args *) arg; + +- status = pthread_mutex_lock(&ea_mutex); +- if (status) +- fatal(status); ++ pending_mutex_lock(args); + + memcpy(&mt, args, sizeof(struct pending_args)); + +@@ -642,7 +615,7 @@ static void *do_expire_indirect(void *arg) + if (status) + fatal(status); + +- expire_mutex_unlock(NULL); ++ pending_mutex_unlock(args); + + pthread_cleanup_push(expire_send_fail, &mt); + +@@ -690,7 +663,7 @@ int handle_packet_expire_indirect(struct autofs_point *ap, autofs_packet_expire_ + if (status) + fatal(status); + +- status = pthread_mutex_lock(&ea_mutex); ++ status = pthread_mutex_init(&mt->mutex, NULL); + if (status) + fatal(status); + +@@ -700,21 +673,25 @@ int handle_packet_expire_indirect(struct autofs_point *ap, autofs_packet_expire_ + mt->len = pkt->len; + mt->wait_queue_token = pkt->wait_queue_token; + ++ pending_mutex_lock(mt); ++ + status = pthread_create(&thid, &th_attr_detached, do_expire_indirect, mt); + if (status) { + error(ap->logopt, "expire thread create failed"); + ops->send_fail(ap->logopt, + ap->ioctlfd, pkt->wait_queue_token, -status); +- expire_mutex_unlock(NULL); ++ pending_mutex_unlock(mt); + pending_cond_destroy(mt); ++ pending_mutex_destroy(mt); + free_pending_args(mt); + pthread_setcancelstate(state, NULL); + return 1; + } + + pthread_cleanup_push(free_pending_args, mt); ++ pthread_cleanup_push(pending_mutex_destroy, mt); + pthread_cleanup_push(pending_cond_destroy, mt); +- pthread_cleanup_push(expire_mutex_unlock, NULL); ++ pthread_cleanup_push(pending_mutex_unlock, mt); + pthread_setcancelstate(state, NULL); + + mt->signaled = 0; +@@ -722,7 +699,7 @@ int handle_packet_expire_indirect(struct autofs_point *ap, autofs_packet_expire_ + gettimeofday(&now, NULL); + wait.tv_sec = now.tv_sec + 2; + wait.tv_nsec = now.tv_usec * 1000; +- status = pthread_cond_timedwait(&mt->cond, &ea_mutex, &wait); ++ status = pthread_cond_timedwait(&mt->cond, &mt->mutex, &wait); + if (status && status != ETIMEDOUT) + fatal(status); + } +@@ -730,6 +707,7 @@ int handle_packet_expire_indirect(struct autofs_point *ap, autofs_packet_expire_ + pthread_cleanup_pop(1); + pthread_cleanup_pop(1); + pthread_cleanup_pop(1); ++ pthread_cleanup_pop(1); + + return 0; + } +@@ -743,22 +721,6 @@ static void mount_send_fail(void *arg) + ap->ioctlfd, mt->wait_queue_token, -ENOENT); + } + +-static void pending_mutex_destroy(void *arg) +-{ +- struct pending_args *mt = (struct pending_args *) arg; +- int status = pthread_mutex_destroy(&mt->mutex); +- if (status) +- fatal(status); +-} +- +-static void mount_mutex_unlock(void *arg) +-{ +- struct pending_args *mt = (struct pending_args *) arg; +- int status = pthread_mutex_unlock(&mt->mutex); +- if (status) +- fatal(status); +-} +- + static void *do_mount_indirect(void *arg) + { + struct ioctl_ops *ops = get_ioctl_ops(); +@@ -770,9 +732,7 @@ static void *do_mount_indirect(void *arg) + + args = (struct pending_args *) arg; + +- status = pthread_mutex_lock(&args->mutex); +- if (status) +- fatal(status); ++ pending_mutex_lock(args); + + memcpy(&mt, args, sizeof(struct pending_args)); + +@@ -783,7 +743,7 @@ static void *do_mount_indirect(void *arg) + if (status) + fatal(status); + +- mount_mutex_unlock(args); ++ pending_mutex_unlock(args); + + pthread_cleanup_push(mount_send_fail, &mt); + +@@ -879,9 +839,7 @@ int handle_packet_missing_indirect(struct autofs_point *ap, autofs_packet_missin + if (status) + fatal(status); + +- status = pthread_mutex_lock(&mt->mutex); +- if (status) +- fatal(status); ++ pending_mutex_lock(mt); + + mt->ap = ap; + strncpy(mt->name, pkt->name, pkt->len); +@@ -898,7 +856,7 @@ int handle_packet_missing_indirect(struct autofs_point *ap, autofs_packet_missin + ops->send_fail(ap->logopt, + ap->ioctlfd, pkt->wait_queue_token, -status); + master_mutex_unlock(); +- mount_mutex_unlock(mt); ++ pending_mutex_unlock(mt); + pending_cond_destroy(mt); + pending_mutex_destroy(mt); + free_pending_args(mt); +@@ -911,7 +869,7 @@ int handle_packet_missing_indirect(struct autofs_point *ap, autofs_packet_missin + pthread_cleanup_push(free_pending_args, mt); + pthread_cleanup_push(pending_mutex_destroy, mt); + pthread_cleanup_push(pending_cond_destroy, mt); +- pthread_cleanup_push(mount_mutex_unlock, mt); ++ pthread_cleanup_push(pending_mutex_unlock, mt); + pthread_setcancelstate(state, NULL); + + mt->signaled = 0; +diff --git a/include/automount.h b/include/automount.h +index 9e1feb0..7d4efcc 100644 +--- a/include/automount.h ++++ b/include/automount.h +@@ -375,6 +375,47 @@ struct pending_args { + unsigned long wait_queue_token; /* Associated kernel wait token */ + }; + ++#ifdef INCLUDE_PENDING_FUNCTIONS ++static void pending_cond_destroy(void *arg) ++{ ++ struct pending_args *mt = (struct pending_args *) arg; ++ int status; ++ status = pthread_cond_destroy(&mt->cond); ++ if (status) ++ fatal(status); ++} ++ ++static void pending_mutex_destroy(void *arg) ++{ ++ struct pending_args *mt = (struct pending_args *) arg; ++ int status = pthread_mutex_destroy(&mt->mutex); ++ if (status) ++ fatal(status); ++} ++ ++static void free_pending_args(void *arg) ++{ ++ struct pending_args *mt = (struct pending_args *) arg; ++ free(mt); ++} ++ ++static void pending_mutex_lock(void *arg) ++{ ++ struct pending_args *mt = (struct pending_args *) arg; ++ int status = pthread_mutex_lock(&mt->mutex); ++ if (status) ++ fatal(status); ++} ++ ++static void pending_mutex_unlock(void *arg) ++{ ++ struct pending_args *mt = (struct pending_args *) arg; ++ int status = pthread_mutex_unlock(&mt->mutex); ++ if (status) ++ fatal(status); ++} ++#endif ++ + struct thread_stdenv_vars { + uid_t uid; + gid_t gid; --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-remove-extra-read-master-map-call.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-remove-extra-read-master-map-call.dpatch @@ -0,0 +1,43 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-remove-extra-read-master-map-call.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - remove extra read master map call + +From: Ian Kent + +Fix a mistake with a recent patch where a call to lookup_read_master() +which should have been removed wasn't. +--- + + CHANGELOG | 1 + + lib/master.c | 1 - + 2 files changed, 1 insertions(+), 1 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index a998a67..e5d743b 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -44,6 +44,7 @@ + - check each dc server individually. + - fix negative cache included map lookup. + - remove state machine timed wait. ++- remove extra read master map call. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/lib/master.c b/lib/master.c +index 62d6fc0..03d8f77 100644 +--- a/lib/master.c ++++ b/lib/master.c +@@ -840,7 +840,6 @@ int master_read_master(struct master *master, time_t age, int readall) + lookup_nss_read_master(master, age); + cache_unlock(nc); + +- lookup_nss_read_master(master, age); + if (!master->read_fail) + master_mount_mounts(master, age, readall); + else { --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-fix-stale-init-for-file-map-instance.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-fix-stale-init-for-file-map-instance.dpatch @@ -0,0 +1,45 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-fix-stale-init-for-file-map-instance.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - fix stale initialization for file map instance + +From: Ian Kent + +Somehow, during the changes to minimize reading of file maps, an error +of not initializing a field of the map source instance structure got +through undetected. This has the effect of preventing all file map +lookups, following the first one, to fail. +--- + + CHANGELOG | 1 + + daemon/lookup.c | 1 + + 2 files changed, 2 insertions(+), 0 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index 7997d1d..8b62370 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -7,6 +7,7 @@ + - fix compile fail with when LDAP is excluded. + - more code analysis corrections (and fix a typo in an init script). + - fix backwards #ifndef INET6. ++- fix stale initialization for file map instance. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/daemon/lookup.c b/daemon/lookup.c +index 9d5a5c8..665ada0 100644 +--- a/daemon/lookup.c ++++ b/daemon/lookup.c +@@ -398,6 +398,7 @@ static enum nsswitch_status read_map_source(struct nss_source *this, + tmap.instance = map->instance; + tmap.recurse = map->recurse; + tmap.depth = map->depth; ++ tmap.stale = map->stale; + tmap.argc = 0; + tmap.argv = NULL; + --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-fix-strdup-return-value-check.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-fix-strdup-return-value-check.dpatch @@ -0,0 +1,48 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-fix-strdup-return-value-check.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - fix strdup() return value check + +From: Ian Kent + +Patch posted by Leonardo Chiquitto. + +Fix copy and paste error when checking strdup() return value, originally +reported by David Binderman in: + +http://bugzilla.novell.com/show_bug.cgi?id=523348 +--- + + CHANGELOG | 1 + + lib/defaults.c | 2 +- + 2 files changed, 2 insertions(+), 1 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index 35ac649..3166898 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -21,6 +21,7 @@ + - dont connect at ldap lookup module init. + - fix random selection option. + - fix disable timeout. ++- fix strdup() return value check (Leonardo Chiquitto). + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/lib/defaults.c b/lib/defaults.c +index cb8354d..5ce71b7 100644 +--- a/lib/defaults.c ++++ b/lib/defaults.c +@@ -65,7 +65,7 @@ static char *get_env_string(const char *name) + return NULL; + + res = strdup(val); +- if (!val) ++ if (!res) + return NULL; + + return res; --- autofs5-5.0.5.orig/debian/patches/patch_order-5.0.5 +++ autofs5-5.0.5/debian/patches/patch_order-5.0.5 @@ -0,0 +1,49 @@ +# +# Source: /work/autofs/releases/autofs-5.0/autofs-5.0.5.tar.gz +# Patchdir: autofs-5.0.5 +# +autofs-5.0.5-fix-included-map-read-fail-handling.patch +autofs-5.0.5-refactor-ldap-sasl-bind.patch +autofs-5.0.4-add-mount-wait-parameter.patch +autofs-5.0.5-special-case-cifs-escapes.patch +autofs-5.0.5-fix-libxml2-workaround-configure.patch +autofs-5.0.5-more-code-analysis-corrections.patch +autofs-5.0.5-fix-backwards-ifndef-INET6.patch +autofs-5.0.5-fix-stale-init-for-file-map-instance.patch +autofs-5.0.5-fix-ext4-fsck-at-mount.patch +autofs-5.0.5-dont-use-master_lex_destroy-to-clear-parse-buffer.patch +autofs-5.0.5-make-documentation-for-set-log-priority-clearer.patch +autofs-5.0.5-fix-timeout-in-connect_nb.patch +autofs-5.0.5-fix-pidof-init-script-usage.patch +autofs-5.0.5-check-for-path-mount-location-in-generic-module.patch +autofs-5.0.5-dont-fail-mount-on-access-fail.patch +autofs-5.0.5-fix-rpc-large-export-list.patch +autofs-5.0.5-fix-memory-leak-on-reload.patch +autofs-5.0.5-update-kernel-patches-2.6.18-and-2.6.19.patch +autofs-5.0.5-dont-connect-at-ldap-lookup-module-init.patch +autofs-5.0.5-fix-random-selection-option.patch +autofs-5.0.5-fix-disable-timeout.patch +autofs-5.0.5-fix-strdup-return-value-check.patch +autofs-5.0.5-fix-reconnect-get-base-dn.patch +autofs-5.0.5-add-sasl-mutex-callbacks.patch +autofs-5.0.5-fix-get-qdn-fail.patch +autofs-5.0.5-fix-ampersand-escape-in-auto-smb.patch +autofs-5.0.5-add-locality-as-valid-ldap-master-map-attribute.patch +autofs-5.0.5-add-locality-as-valid-ldap-master-map-attribute-fix.patch +autofs-5.0.5-make-nfs4-default-for-redhat-replicated-selection.patch +autofs-5.0.5-add-simple-bind-auth.patch +autofs-5.0.5-fix-master-map-source-server-unavialable-handling.patch +autofs-5.0.5-add-autofs_ldap_auth_conf-man-page.patch +autofs-5.0.5-fix-random-selection-for-host-on-different-network.patch +autofs-5.0.5-make-redhat-init-script-more-lsb-compliant.patch +autofs-5.0.5-dont-hold-lock-for-simple-mounts.patch +autofs-5.0.5-fix-remount-locking.patch +autofs-5.0.5-fix-wildcard-map-entry-match.patch +autofs-5.0.5-fix-parse_sun-module-init.patch +autofs-5.0.5-dont-check-null-cache-on-expire.patch +autofs-5.0.5-fix-null-cache-race.patch +autofs-5.0.5-fix-cache_init-on-source-re-read.patch +autofs-5.0.5-mapent-becomes-negative-during-lookup.patch +autofs-5.0.5-check-each-dc-server.patch +autofs-5.0.5-fix-negative-cache-included-map-lookup.patch +autofs-5.0.5-remove-state-machine-timed-wait.patch --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-more-code-analysis-corrections.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-more-code-analysis-corrections.dpatch @@ -0,0 +1,247 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-more-code-analysis-corrections.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - more code analysis corrections (and fix a typo in an init script) + +From: Jeff Moyer + +- fix an obvious type in Redhat init script. +- don't call ldap_msgfree when result pointer is null. +- check return of ldap_parse_result as pointers will be invalid on fail. +- get rid of a bogus assignment in defaults_free_searchdns. +- get rid of unused optlen variable in parse_sun.c. +- check return status of stat(2) in do_mount_direct(). +- get rid of unused name variable in master_add_map_source(). +- check return from ops->askumount() in expire_cleanup(). +- in mount_autofs.c:mount_mount(), don't increment val since we never + look at it again. +- in autofs_sasl_dispose() ctxt must always be valid or we would have + a much bigger problem. +- in st_start_handler() and alarm_start_handler() it is possible for + pthread_attr_destroy() to be called with a NULL pointer. +- we could end up with a non-null result pointer after a failed call to + ldap_search_s(), well maybe, so check for it anyway. + +Signed-off-by: Jeff Moyer +--- + + CHANGELOG | 1 + + daemon/direct.c | 2 +- + daemon/state.c | 5 +++-- + lib/alarm.c | 3 ++- + lib/defaults.c | 1 - + lib/master.c | 6 +----- + modules/cyrus-sasl.c | 2 +- + modules/lookup_ldap.c | 13 +++++++++++-- + modules/mount_autofs.c | 2 +- + modules/parse_sun.c | 3 +-- + redhat/autofs.init.in | 2 +- + 11 files changed, 23 insertions(+), 17 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index 23351c8..b9b1602 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -5,6 +5,7 @@ + - add mount wait timeout parameter. + - special case cifs escapes. + - fix compile fail with when LDAP is excluded. ++- more code analysis corrections (and fix a typo in an init script). + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/daemon/direct.c b/daemon/direct.c +index 0c78627..9b4e57b 100644 +--- a/daemon/direct.c ++++ b/daemon/direct.c +@@ -1245,7 +1245,7 @@ static void *do_mount_direct(void *arg) + } + + status = stat(mt.name, &st); +- if (!S_ISDIR(st.st_mode) || st.st_dev != mt.dev) { ++ if (status != 0 || !S_ISDIR(st.st_mode) || st.st_dev != mt.dev) { + error(ap->logopt, + "direct trigger not valid or already mounted %s", + mt.name); +diff --git a/daemon/state.c b/daemon/state.c +index 71af46a..27bc6de 100644 +--- a/daemon/state.c ++++ b/daemon/state.c +@@ -160,7 +160,7 @@ void expire_cleanup(void *arg) + * been signaled to shutdown. + */ + rv = ops->askumount(ap->logopt, ap->ioctlfd, &idle); +- if (!idle && !ap->shutdown) { ++ if (!rv && !idle && !ap->shutdown) { + next = ST_READY; + if (!ap->submount) + alarm_add(ap, ap->exp_runfreq); +@@ -1198,7 +1198,8 @@ int st_start_handler(void) + + status = pthread_create(&thid, pattrs, st_queue_handler, NULL); + +- pthread_attr_destroy(pattrs); ++ if (pattrs) ++ pthread_attr_destroy(pattrs); + + return !status; + } +diff --git a/lib/alarm.c b/lib/alarm.c +index 46df38a..f403d8f 100755 +--- a/lib/alarm.c ++++ b/lib/alarm.c +@@ -239,7 +239,8 @@ int alarm_start_handler(void) + + status = pthread_create(&thid, pattrs, alarm_handler, NULL); + +- pthread_attr_destroy(pattrs); ++ if (pattrs) ++ pthread_attr_destroy(pattrs); + + return !status; + } +diff --git a/lib/defaults.c b/lib/defaults.c +index 2204b18..cb8354d 100644 +--- a/lib/defaults.c ++++ b/lib/defaults.c +@@ -534,7 +534,6 @@ void defaults_free_searchdns(struct ldap_searchdn *sdn) + struct ldap_searchdn *this = sdn; + struct ldap_searchdn *next; + +- next = this; + while (this) { + next = this->next; + free(this->basedn); +diff --git a/lib/master.c b/lib/master.c +index e43f835..8455f40 100644 +--- a/lib/master.c ++++ b/lib/master.c +@@ -152,7 +152,7 @@ master_add_map_source(struct master_mapent *entry, + { + struct map_source *source; + char *ntype, *nformat; +- const char **tmpargv, *name = NULL; ++ const char **tmpargv; + + source = malloc(sizeof(struct map_source)); + if (!source) +@@ -188,10 +188,6 @@ master_add_map_source(struct master_mapent *entry, + source->argc = argc; + source->argv = tmpargv; + +- /* Can be NULL for "hosts" map */ +- if (argv) +- name = argv[0]; +- + master_source_writelock(entry); + + if (!entry->maps) +diff --git a/modules/cyrus-sasl.c b/modules/cyrus-sasl.c +index 828143e..92e2226 100644 +--- a/modules/cyrus-sasl.c ++++ b/modules/cyrus-sasl.c +@@ -911,7 +911,7 @@ void autofs_sasl_dispose(struct lookup_context *ctxt) + { + int status, ret; + +- if (ctxt && ctxt->sasl_conn) { ++ if (ctxt->sasl_conn) { + sasl_dispose(&ctxt->sasl_conn); + ctxt->sasl_conn = NULL; + } +diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c +index f1fb9ce..d8bd169 100644 +--- a/modules/lookup_ldap.c ++++ b/modules/lookup_ldap.c +@@ -389,13 +389,16 @@ static int get_query_dn(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt + error(logopt, + MODPREFIX "query failed for search dn %s: %s", + this->basedn, ldap_err2string(rv)); ++ if (result) { ++ ldap_msgfree(result); ++ result = NULL; ++ } + } + + this = this->next; + } + + if (!result) { +- ldap_msgfree(result); + error(logopt, + MODPREFIX "failed to find query dn under search base dns"); + free(query); +@@ -1954,6 +1957,12 @@ do_paged: + sp->cookie = NULL; + } + ++ if (rv != LDAP_SUCCESS) { ++ debug(ap->logopt, ++ MODPREFIX "ldap_parse_result failed with %d", rv); ++ goto out_free; ++ } ++ + /* + * Parse the page control returned to get the cookie and + * determine whether there are more pages. +@@ -1970,8 +1979,8 @@ do_paged: + if (returnedControls) + ldap_controls_free(returnedControls); + ++out_free: + ldap_control_free(pageControl); +- + return rv; + } + +diff --git a/modules/mount_autofs.c b/modules/mount_autofs.c +index afb1859..2a5d860 100644 +--- a/modules/mount_autofs.c ++++ b/modules/mount_autofs.c +@@ -119,7 +119,7 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, + else if (strncmp(cp, "timeout=", 8) == 0) { + char *val = strchr(cp, '='); + unsigned tout; +- if (val++) { ++ if (val) { + int ret = sscanf(cp, "timeout=%u", &tout); + if (ret) + timeout = tout; +diff --git a/modules/parse_sun.c b/modules/parse_sun.c +index db36ae2..921daf4 100644 +--- a/modules/parse_sun.c ++++ b/modules/parse_sun.c +@@ -1334,7 +1334,7 @@ int parse_mount(struct autofs_point *ap, const char *name, + char *pmapent, *options; + const char *p; + int mapent_len, rv = 0; +- int optlen, cur_state; ++ int cur_state; + int slashify = ctxt->slashify_colons; + unsigned int append_options; + +@@ -1389,7 +1389,6 @@ int parse_mount(struct autofs_point *ap, const char *name, + logerr(MODPREFIX "strdup: %s", estr); + return 1; + } +- optlen = strlen(options); + + p = skipspace(pmapent); + +diff --git a/redhat/autofs.init.in b/redhat/autofs.init.in +index fded1d8..806302b 100644 +--- a/redhat/autofs.init.in ++++ b/redhat/autofs.init.in +@@ -172,7 +172,7 @@ case "$1" in + fi + ;; + *) +- echo $"Usage: $0 {start|forcestart|stop|status|restart|orcerestart|reload|condrestart}" ++ echo $"Usage: $0 {start|forcestart|stop|status|restart|forcerestart|reload|condrestart}" + exit 1; + ;; + esac --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-mapent-becomes-negative-during-lookup.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-mapent-becomes-negative-during-lookup.dpatch @@ -0,0 +1,89 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-mapent-becomes-negative-during-lookup.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - mapent becomes negative during lookup + +From: Ian Kent + +During a mount request it is possible for a mapent to become negative +between the time it is checked on entry and when we fetch the mount +location information. This is because we drop the cache lock after +the initial check and take it back again before getting the location +information. +--- + + CHANGELOG | 1 + + modules/lookup_file.c | 2 +- + modules/lookup_ldap.c | 2 +- + modules/lookup_nisplus.c | 2 +- + modules/lookup_yp.c | 2 +- + 5 files changed, 5 insertions(+), 4 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index bfee5de..4788f44 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -40,6 +40,7 @@ + - dont check null cache on expire. + - fix null cache race. + - fix cache_init() on source re-read. ++- fix mapent becomes negative during lookup. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/modules/lookup_file.c b/modules/lookup_file.c +index 676be9e..b207947 100644 +--- a/modules/lookup_file.c ++++ b/modules/lookup_file.c +@@ -1047,7 +1047,7 @@ do_cache_lookup: + if (!me) + me = cache_lookup_distinct(mc, "*"); + } +- if (me && (me->source == source || *me->key == '/')) { ++ if (me && me->mapent && (me->source == source || *me->key == '/')) { + pthread_cleanup_push(cache_lock_cleanup, mc); + strcpy(mapent_buf, me->mapent); + mapent = mapent_buf; +diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c +index f02d0dc..9aac960 100644 +--- a/modules/lookup_ldap.c ++++ b/modules/lookup_ldap.c +@@ -2872,7 +2872,7 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void * + if (!me) + me = cache_lookup_distinct(mc, "*"); + } +- if (me && (me->source == source || *me->key == '/')) { ++ if (me && me->mapent && (me->source == source || *me->key == '/')) { + strcpy(mapent_buf, me->mapent); + mapent = mapent_buf; + } +diff --git a/modules/lookup_nisplus.c b/modules/lookup_nisplus.c +index 9b7941a..bcd5973 100644 +--- a/modules/lookup_nisplus.c ++++ b/modules/lookup_nisplus.c +@@ -569,7 +569,7 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void * + if (!me) + me = cache_lookup_distinct(mc, "*"); + } +- if (me && (me->source == source || *me->key == '/')) { ++ if (me && me->mapent && (me->source == source || *me->key == '/')) { + mapent_len = strlen(me->mapent); + mapent = malloc(mapent_len + 1); + strcpy(mapent, me->mapent); +diff --git a/modules/lookup_yp.c b/modules/lookup_yp.c +index fb0ae9f..9d35be5 100644 +--- a/modules/lookup_yp.c ++++ b/modules/lookup_yp.c +@@ -670,7 +670,7 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void * + if (!me) + me = cache_lookup_distinct(mc, "*"); + } +- if (me && (me->source == source || *me->key == '/')) { ++ if (me && me->mapent && (me->source == source || *me->key == '/')) { + mapent_len = strlen(me->mapent); + mapent = alloca(mapent_len + 1); + strcpy(mapent, me->mapent); --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-auto-adjust-ldap-page-size.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-auto-adjust-ldap-page-size.dpatch @@ -0,0 +1,123 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-auto-adjust-ldap-page-size.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - auto adjust ldap page size + +From: Ian Kent + +When doing a paged LDAP request, if an LDAP server is configured with +request size limits less than the size autofs requests the query fails +with an LDAP_ADMINLIMIT_EXCEEDED. To fix this, when the error is returned +halve the request size and try again until we get down to a ridiculously +small size. +--- + + CHANGELOG | 1 + + modules/lookup_ldap.c | 32 ++++++++++++++++++++++++-------- + 2 files changed, 25 insertions(+), 8 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index 72590f7..5c1005a 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -57,6 +57,7 @@ + - add option to dump configured automount maps. + - use weight only for server selection. + - fix isspace() wild card substition. ++- auto adjust ldap page size. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c +index 71aee1b..6ddd30b 100644 +--- a/modules/lookup_ldap.c ++++ b/modules/lookup_ldap.c +@@ -55,6 +55,7 @@ struct ldap_search_params { + LDAP *ldap; + char *query, **attrs; + struct berval *cookie; ++ ber_int_t pageSize; + int morePages; + ber_int_t totalCount; + LDAPMessage *result; +@@ -1946,7 +1947,6 @@ static int do_paged_query(struct ldap_search_params *sp, struct lookup_context * + struct autofs_point *ap = sp->ap; + LDAPControl *pageControl=NULL, *controls[2] = { NULL, NULL }; + LDAPControl **returnedControls = NULL; +- static ber_int_t pageSize = 1000; + static char pagingCriticality = 'T'; + int rv, scope = LDAP_SCOPE_SUBTREE; + +@@ -1959,7 +1959,8 @@ static int do_paged_query(struct ldap_search_params *sp, struct lookup_context * + * Check for Size Limit exceeded and force run through loop + * and requery using page control. + */ +- if (rv == LDAP_SIZELIMIT_EXCEEDED) ++ if (rv == LDAP_SIZELIMIT_EXCEEDED || ++ rv == LDAP_ADMINLIMIT_EXCEEDED) + sp->morePages = TRUE; + else { + debug(ap->logopt, +@@ -1974,7 +1975,7 @@ do_paged: + /* we need to use page controls so requery LDAP */ + debug(ap->logopt, MODPREFIX "geting page of results"); + +- rv = ldap_create_page_control(sp->ldap, pageSize, sp->cookie, ++ rv = ldap_create_page_control(sp->ldap, sp->pageSize, sp->cookie, + pagingCriticality, &pageControl); + if (rv != LDAP_SUCCESS) { + warn(ap->logopt, MODPREFIX "failed to create page control"); +@@ -1989,10 +1990,11 @@ do_paged: + ctxt->qdn, scope, sp->query, sp->attrs, + 0, controls, NULL, NULL, 0, &sp->result); + if ((rv != LDAP_SUCCESS) && (rv != LDAP_PARTIAL_RESULTS)) { +- debug(ap->logopt, +- MODPREFIX "query failed for %s: %s", +- sp->query, ldap_err2string(rv)); + ldap_control_free(pageControl); ++ if (rv != LDAP_ADMINLIMIT_EXCEEDED) ++ debug(ap->logopt, ++ MODPREFIX "query failed for %s: %s", ++ sp->query, ldap_err2string(rv)); + return rv; + } + +@@ -2347,18 +2349,32 @@ static int read_one_map(struct autofs_point *ap, + MODPREFIX "searching for \"%s\" under \"%s\"", sp.query, ctxt->qdn); + + sp.cookie = NULL; ++ sp.pageSize = 1000; + sp.morePages = FALSE; + sp.totalCount = 0; + sp.result = NULL; + + do { + rv = do_paged_query(&sp, ctxt); +- if (rv == LDAP_SIZELIMIT_EXCEEDED) +- { ++ if (rv == LDAP_SIZELIMIT_EXCEEDED) { + debug(ap->logopt, MODPREFIX "result size exceed"); + if (sp.result) + ldap_msgfree(sp.result); ++ continue; ++ } + ++ if (rv == LDAP_ADMINLIMIT_EXCEEDED) { ++ if (sp.result) ++ ldap_msgfree(sp.result); ++ sp.pageSize = sp.pageSize / 2; ++ if (sp.pageSize < 5) { ++ debug(ap->logopt, MODPREFIX ++ "administrative result size too small"); ++ unbind_ldap_connection(ap->logopt, sp.ldap, ctxt); ++ *result_ldap = rv; ++ free(sp.query); ++ return NSS_STATUS_UNAVAIL; ++ } + continue; + } + --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-fix-wildcard-map-entry-match.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-fix-wildcard-map-entry-match.dpatch @@ -0,0 +1,71 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-fix-wildcard-map-entry-match.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - fix wildcard map entry match + +From: Ian Kent + +In some cases we can get a key string that includes a '*' at the start. +This causes an incorrect comparison in the cache library routines and can +lead to a segmentation fault. + +This patch enures that the key length is also considered when checking the +wildcard key entry. +--- + + CHANGELOG | 1 + + daemon/lookup.c | 4 ++-- + lib/cache.c | 2 +- + 3 files changed, 4 insertions(+), 3 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index 6ef2d5a..76207c8 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -35,6 +35,7 @@ + - make redhat init script more lsb compliant. + - don't hold lock for simple mounts. + - fix remount locking. ++- fix wildcard map entry match. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/daemon/lookup.c b/daemon/lookup.c +index 8537861..ec979c9 100644 +--- a/daemon/lookup.c ++++ b/daemon/lookup.c +@@ -600,7 +600,7 @@ int lookup_ghost(struct autofs_point *ap, const char *root) + cache_readlock(mc); + me = cache_enumerate(mc, NULL); + while (me) { +- if (*me->key == '*') ++ if (!strcmp(me->key, "*")) + goto next; + + if (*me->key == '/') { +@@ -1035,7 +1035,7 @@ void lookup_prune_one_cache(struct autofs_point *ap, struct mapent_cache *mc, ti + + key = strdup(me->key); + me = cache_enumerate(mc, me); +- if (!key || *key == '*') { ++ if (!key || !strcmp(key, "*")) { + if (key) + free(key); + continue; +diff --git a/lib/cache.c b/lib/cache.c +index cd62ac2..440b3e8 100644 +--- a/lib/cache.c ++++ b/lib/cache.c +@@ -719,7 +719,7 @@ int cache_update(struct mapent_cache *mc, struct map_source *ms, const char *key + me = cache_lookup(mc, key); + while (me && me->source != ms) + me = cache_lookup_key_next(me); +- if (!me || (*me->key == '*' && *key != '*')) { ++ if (!me || (!strcmp(me->key, "*") && strcmp(key, "*"))) { + ret = cache_add(mc, ms, key, mapent, age); + if (!ret) { + debug(logopt, "failed for %s", key); --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-replace-gplv3-code.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-replace-gplv3-code.dpatch @@ -0,0 +1,800 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-replace-gplv3-code.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - replace GPLv3 code + +From: Ian Kent + +The code to get SRV records from DNS was taken from Samba. +Samba is a GPLv3 licensed work which forces autofs to GPLv3. + +I don't know enough about GPLv3 to know if that is a good thing +but I also don't like autofs being forced to GPLv3 because one +of the copyright holders won't grant permission to use the code +under a GPLv2 license. +--- + + CHANGELOG | 1 + modules/dclist.c | 590 +++++++++++++++++------------------------------------- + 2 files changed, 192 insertions(+), 399 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index b9d8299..347d7d7 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -61,6 +61,7 @@ + - fix prune cache valid check. + - fix mountd vers retry. + - fix expire race. ++- replace GPLv3 code. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/modules/dclist.c b/modules/dclist.c +index 967581c..aeb107f 100644 +--- a/modules/dclist.c ++++ b/modules/dclist.c +@@ -1,19 +1,10 @@ + /* +- * Copyright 2009 Ian Kent +- * Copyright 2009 Red Hat, Inc. +- * +- * This module was apapted from code contained in the Samba distribution +- * file source/libads/dns.c which contained the following copyright +- * information: +- * +- * Unix SMB/CIFS implementation. +- * DNS utility library +- * Copyright (C) Gerald (Jerry) Carter 2006. +- * Copyright (C) Jeremy Allison 2007. ++ * Copyright 2011 Ian Kent ++ * Copyright 2011 Red Hat, Inc. + * + * 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; either version 3 of the License, or ++ * the Free Software Foundation, 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, +@@ -25,7 +16,9 @@ + * along with this program. If not, see . + */ + ++#include + #include ++#include + #include + #include + #include +@@ -39,80 +32,21 @@ + #include "automount.h" + #include "dclist.h" + +-#define MAX_DNS_PACKET_SIZE 0xffff +-#define MAX_DNS_NAME_LENGTH MAXHOSTNAMELEN +-/* The longest time we will cache dns srv records */ +-#define MAX_TTL (60*60*1) /* 1 hours */ +- +-#ifdef NS_HFIXEDSZ /* Bind 8/9 interface */ +-#if !defined(C_IN) /* AIX 5.3 already defines C_IN */ +-# define C_IN ns_c_in +-#endif +-#if !defined(T_A) /* AIX 5.3 already defines T_A */ +-# define T_A ns_t_a +-#endif +- +-# define T_SRV ns_t_srv +-#if !defined(T_NS) /* AIX 5.3 already defines T_NS */ +-# define T_NS ns_t_ns +-#endif +-#else +-# ifdef HFIXEDSZ +-# define NS_HFIXEDSZ HFIXEDSZ +-# else +-# define NS_HFIXEDSZ sizeof(HEADER) +-# endif /* HFIXEDSZ */ +-# ifdef PACKETSZ +-# define NS_PACKETSZ PACKETSZ +-# else /* 512 is usually the default */ +-# define NS_PACKETSZ 512 +-# endif /* PACKETSZ */ +-# define T_SRV 33 +-#endif +- +-#define SVAL(buf, pos) (*(const uint16_t *)((const char *)(buf) + (pos))) +-#define IVAL(buf, pos) (*(const uint32_t *)((const char *)(buf) + (pos))) +- +-#if __BYTE_ORDER == __LITTLE_ENDIAN +-#define SREV(x) ((((x)&0xFF)<<8) | (((x)>>8)&0xFF)) +-#define IREV(x) ((SREV(x)<<16) | (SREV((x)>>16))) +-#else +-#define SREV(x) (x) +-#define IREV(x) (x) +-#endif +- +-#define RSVAL(buf, pos) SREV(SVAL(buf, pos)) +-#define RIVAL(buf, pos) IREV(IVAL(buf, pos)) +- +-#define QSORT_CAST (int (*)(const void *, const void *)) +- +-/* DNS query section in replies */ +- +-struct dns_query { +- const char *hostname; +- uint16_t type; +- uint16_t in_class; +-}; +- +-/* DNS RR record in reply */ ++#define MAX_TTL (60*60) /* 1 hour */ + +-struct dns_rr { +- const char *hostname; +- uint16_t type; +- uint16_t in_class; +- uint32_t ttl; +- uint16_t rdatalen; +- uint8_t *rdata; ++struct rr { ++ unsigned int type; ++ unsigned int class; ++ unsigned long ttl; ++ unsigned int len; + }; + +-/* SRV records */ +- +-struct dns_rr_srv { +- const char *hostname; +- uint16_t priority; +- uint16_t weight; +- uint16_t port; +- uint32_t ttl; ++struct srv_rr { ++ const char *name; ++ unsigned int priority; ++ unsigned int weight; ++ unsigned int port; ++ unsigned long ttl; + }; + + static pthread_mutex_t dclist_mutex = PTHREAD_MUTEX_INITIALIZER; +@@ -133,374 +67,224 @@ static void dclist_mutex_unlock(void) + return; + } + +-static int dns_parse_query(unsigned int logopt, +- uint8_t *start, uint8_t *end, +- uint8_t **ptr, struct dns_query *q) ++static int do_srv_query(unsigned int logopt, char *name, u_char **packet) + { +- uint8_t *p = *ptr; +- char hostname[MAX_DNS_NAME_LENGTH]; +- char buf[MAX_ERR_BUF]; +- int namelen; +- +- if (!start || !end || !q || !*ptr) +- return 0; +- +- memset(q, 0, sizeof(*q)); +- +- /* See RFC 1035 for details. If this fails, then return. */ +- +- namelen = dn_expand(start, end, p, hostname, sizeof(hostname)); +- if (namelen < 0) { +- error(logopt, "failed to expand query hostname"); +- return 0; +- } ++ unsigned int len = PACKETSZ; ++ unsigned int last_len = len; ++ char ebuf[MAX_ERR_BUF]; ++ u_char *buf; ++ ++ while (1) { ++ buf = malloc(last_len); ++ if (!buf) { ++ char *estr = strerror_r(errno, ebuf, MAX_ERR_BUF); ++ error(logopt, "malloc: %s", estr); ++ return -1; ++ } + +- p += namelen; +- q->hostname = strdup(hostname); +- if (!q) { +- char *estr = strerror_r(errno, buf, MAX_ERR_BUF); +- error(logopt, "strdup: %s", estr); +- return 0; +- } ++ len = res_query(name, C_IN, T_SRV, buf, last_len); ++ if (len < 0) { ++ char *estr = strerror_r(errno, ebuf, MAX_ERR_BUF); ++ error(logopt, "Failed to resolve %s (%s)", name, estr); ++ free(buf); ++ return -1; ++ } + +- /* check that we have space remaining */ ++ if (len == last_len) { ++ /* These shouldn't too large, bump by PACKETSZ only */ ++ last_len += PACKETSZ; ++ free(buf); ++ continue; ++ } + +- if (p + 4 > end) { +- error(logopt, "insufficient buffer space for result"); +- free((void *) q->hostname); +- return 0; ++ break; + } + +- q->type = RSVAL(p, 0); +- q->in_class = RSVAL(p, 2); +- p += 4; ++ *packet = buf; + +- *ptr = p; +- +- return 1; ++ return len; + } + +-static int dns_parse_rr(unsigned int logopt, +- uint8_t *start, uint8_t *end, +- uint8_t **ptr, struct dns_rr *rr) ++static int get_name_len(u_char *buffer, u_char *start, u_char *end) + { +- uint8_t *p = *ptr; +- char hostname[MAX_DNS_NAME_LENGTH]; +- char buf[MAX_ERR_BUF]; +- int namelen; +- +- if (!start || !end || !rr || !*ptr) +- return 0; +- +- memset(rr, 0, sizeof(*rr)); +- +- /* pull the name from the answer */ +- +- namelen = dn_expand(start, end, p, hostname, sizeof(hostname)); +- if (namelen < 0) { +- error(logopt, "failed to expand query hostname"); +- return 0; +- } +- p += namelen; +- rr->hostname = strdup(hostname); +- if (!rr->hostname) { +- char *estr = strerror_r(errno, buf, MAX_ERR_BUF); +- error(logopt, "strdup: %s", estr); +- return 0; +- } +- +- /* check that we have space remaining */ +- +- if (p + 10 > end) { +- error(logopt, "insufficient buffer space for result"); +- free((void *) rr->hostname); +- return 0; +- } +- +- /* pull some values and then skip onto the string */ +- +- rr->type = RSVAL(p, 0); +- rr->in_class = RSVAL(p, 2); +- rr->ttl = RIVAL(p, 4); +- rr->rdatalen = RSVAL(p, 8); +- +- p += 10; +- +- /* sanity check the available space */ +- +- if (p + rr->rdatalen > end) { +- error(logopt, "insufficient buffer space for data"); +- free((void *) rr->hostname); +- return 0; +- } +- +- /* save a point to the rdata for this section */ +- +- rr->rdata = p; +- p += rr->rdatalen; +- +- *ptr = p; +- +- return 1; ++ char tmp[MAXDNAME]; ++ return dn_expand(buffer, end, start, tmp, MAXDNAME); + } + +-static int dns_parse_rr_srv(unsigned int logopt, +- uint8_t *start, uint8_t *end, +- uint8_t **ptr, struct dns_rr_srv *srv) ++static int get_data_offset(u_char *buffer, ++ u_char *start, u_char *end, ++ struct rr *rr) + { +- struct dns_rr rr; +- uint8_t *p; +- char dcname[MAX_DNS_NAME_LENGTH]; +- char buf[MAX_ERR_BUF]; +- int namelen; +- +- if (!start || !end || !srv || !*ptr) +- return 0; +- +- /* Parse the RR entry. Coming out of the this, ptr is at the beginning +- of the next record */ +- +- if (!dns_parse_rr(logopt, start, end, ptr, &rr)) { +- error(logopt, "Failed to parse RR record"); +- return 0; +- } ++ u_char *cp = start; ++ int name_len; + +- if (rr.type != T_SRV) { +- error(logopt, "Bad answer type (%d)", rr.type); +- return 0; +- } +- +- p = rr.rdata; ++ name_len = get_name_len(buffer, start, end); ++ if (name_len < 0) ++ return -1; ++ cp += name_len; + +- srv->priority = RSVAL(p, 0); +- srv->weight = RSVAL(p, 2); +- srv->port = RSVAL(p, 4); +- srv->ttl = rr.ttl; ++ GETSHORT(rr->type, cp); ++ GETSHORT(rr->class, cp); ++ GETLONG(rr->ttl, cp); ++ GETSHORT(rr->len, cp); + +- p += 6; ++ return (cp - start); ++} + +- namelen = dn_expand(start, end, p, dcname, sizeof(dcname)); +- if (namelen < 0) { +- error(logopt, "Failed to expand dcname"); +- return 0; ++static struct srv_rr *parse_srv_rr(unsigned int logopt, ++ u_char *buffer, u_char *start, u_char *end, ++ struct rr *rr, struct srv_rr *srv) ++{ ++ u_char *cp = start; ++ char ebuf[MAX_ERR_BUF]; ++ char tmp[MAXDNAME]; ++ int len; ++ ++ GETSHORT(srv->priority, cp); ++ GETSHORT(srv->weight, cp); ++ GETSHORT(srv->port, cp); ++ srv->ttl = rr->ttl; ++ ++ len = dn_expand(buffer, end, cp, tmp, MAXDNAME); ++ if (len < 0) { ++ error(logopt, "failed to expand name"); ++ return NULL; + } +- +- srv->hostname = strdup(dcname); +- if (!srv->hostname) { +- char *estr = strerror_r(errno, buf, MAX_ERR_BUF); ++ srv->name = strdup(tmp); ++ if (!srv->name) { ++ char *estr = strerror_r(errno, ebuf, MAX_ERR_BUF); + error(logopt, "strdup: %s", estr); +- return 0; ++ return NULL; + } + +- debug(logopt, "Parsed %s [%u, %u, %u]", +- srv->hostname, srv->priority, srv->weight, srv->port); +- +- return 1; ++ return srv; + } + +-/********************************************************************* +- Sort SRV record list based on weight and priority. See RFC 2782. +-*********************************************************************/ +- +-static int dnssrvcmp(struct dns_rr_srv *a, struct dns_rr_srv *b) ++static int cmp(struct srv_rr *a, struct srv_rr *b) + { +- if (a->priority == b->priority) { +- /* randomize entries with an equal weight and priority */ +- if (a->weight == b->weight) +- return 0; ++ if (a->priority < b->priority) ++ return -1; + +- /* higher weights should be sorted lower */ +- if (a->weight > b->weight) +- return -1; +- else +- return 1; +- } ++ if (a->priority > b->priority) ++ return 1; + +- if (a->priority < b->priority) ++ if (!a->weight || a->weight == b->weight) ++ return 0; ++ ++ if (a->weight > b->weight) + return -1; + + return 1; + } + +-#define DNS_FAILED_WAITTIME 30 +- +-static int dns_send_req(unsigned int logopt, +- const char *name, int q_type, uint8_t **rbuf, +- int *resp_length) ++static void free_srv_rrs(struct srv_rr *dcs, unsigned int count) + { +- uint8_t *buffer = NULL; +- size_t buf_len = 0; +- int resp_len = NS_PACKETSZ; +- static time_t last_dns_check = 0; +- static unsigned int last_dns_status = 0; +- time_t now = time(NULL); +- char buf[MAX_ERR_BUF]; +- +- /* Try to prevent bursts of DNS lookups if the server is down */ +- +- /* Protect against large clock changes */ +- +- if (last_dns_check > now) +- last_dns_check = 0; ++ int i; + +- /* IF we had a DNS timeout or a bad server and we are still +- in the 30 second cache window, just return the previous +- status and save the network timeout. */ +- +- if ((last_dns_status == ETIMEDOUT || +- last_dns_status == ECONNREFUSED) && +- ((last_dns_check + DNS_FAILED_WAITTIME) > now)) { +- char *estr = strerror_r(last_dns_status, buf, MAX_ERR_BUF); +- debug(logopt, "Returning cached status (%s)", estr); +- return last_dns_status; ++ for (i = 0; i < count; i++) { ++ if (dcs[i].name) ++ free((void *) dcs[i].name); + } +- +- /* Send the Query */ +- do { +- if (buffer) +- free(buffer); +- +- buf_len = resp_len * sizeof(uint8_t); +- +- if (buf_len) { +- buffer = malloc(buf_len); +- if (!buffer) { +- char *estr = strerror_r(errno, buf, MAX_ERR_BUF); +- error(logopt, "malloc: %s", estr); +- last_dns_status = ENOMEM; +- last_dns_check = time(NULL); +- return last_dns_status; +- } +- } +- +- resp_len = res_query(name, C_IN, q_type, buffer, buf_len); +- if (resp_len < 0) { +- char *estr = strerror_r(errno, buf, MAX_ERR_BUF); +- error(logopt, "Failed to resolve %s (%s)", name, estr); +- free(buffer); +- last_dns_status = ENOENT; +- last_dns_check = time(NULL); +- return last_dns_status; +- } +- +- /* On AIX, Solaris, and possibly some older glibc systems (e.g. SLES8) +- truncated replies never give back a resp_len > buflen +- which ends up causing DNS resolve failures on large tcp DNS replies */ +- +- if (buf_len == resp_len) { +- if (resp_len == MAX_DNS_PACKET_SIZE) { +- error(logopt, +- "DNS reply too large when resolving %s", +- name); +- free(buffer); +- last_dns_status = EMSGSIZE; +- last_dns_check = time(NULL); +- return last_dns_status; +- } +- +- resp_len = MIN(resp_len * 2, MAX_DNS_PACKET_SIZE); +- } +- } while (buf_len < resp_len && resp_len <= MAX_DNS_PACKET_SIZE); +- +- *rbuf = buffer; +- *resp_length = resp_len; +- +- last_dns_check = time(NULL); +- last_dns_status = 0; +- +- return 0; ++ free(dcs); + } + +-static int dns_lookup_srv(unsigned int logopt, const char *name, +- struct dns_rr_srv **dclist, int *numdcs) ++int get_srv_rrs(unsigned int logopt, ++ char *name, struct srv_rr **dcs, unsigned int *dcs_count) + { +- uint8_t *buffer = NULL; +- int resp_len = 0; +- struct dns_rr_srv *dcs = NULL; +- int query_count, answer_count; +- uint8_t *p = buffer; +- int rrnum; +- int idx = 0; +- char buf[MAX_ERR_BUF]; +- int ret; ++ struct srv_rr *srvs; ++ unsigned int srv_num; ++ HEADER *header; ++ u_char *packet; ++ u_char *start; ++ u_char *end; ++ unsigned int count; ++ int i, len; ++ char ebuf[MAX_ERR_BUF]; ++ ++ len = do_srv_query(logopt, name, &packet); ++ if (len < 0) ++ return 0; + +- if (!name || !dclist) +- return -EINVAL; ++ header = (HEADER *) packet; ++ start = packet + sizeof(HEADER); ++ end = packet + len; + +- /* Send the request. May have to loop several times in case +- of large replies */ ++ srvs = NULL; ++ srv_num = 0; + +- ret = dns_send_req(logopt, name, T_SRV, &buffer, &resp_len); +- if (ret) { +- error(logopt, "Failed to send DNS query"); +- return ret; ++ /* Skip over question */ ++ len = get_name_len(packet, start, end); ++ if (len < 0) { ++ error(logopt, "failed to get name length"); ++ goto error_out; + } +- p = buffer; + +- /* For some insane reason, the ns_initparse() et. al. routines are only +- available in libresolv.a, and not the shared lib. Who knows why.... +- So we have to parse the DNS reply ourselves */ ++ start += len + QFIXEDSZ; + +- /* Pull the answer RR's count from the header. +- * Use the NMB ordering macros */ ++ count = ntohs(header->ancount); + +- query_count = RSVAL(p, 4); +- answer_count = RSVAL(p, 6); ++ debug(logopt, "%d records returned in the answer section", count); + +- debug(logopt, +- "%d records returned in the answer section.", +- answer_count); ++ if (count <= 0) { ++ error(logopt, "no records found in answers section"); ++ goto error_out; ++ } + +- if (answer_count) { +- dcs = malloc(sizeof(struct dns_rr_srv) * answer_count); +- if (!dcs) { +- char *estr = strerror_r(errno, buf, MAX_ERR_BUF); +- error(logopt, "malloc: %s", estr); +- free(buffer); +- return ENOMEM; +- } ++ srvs = malloc(sizeof(struct srv_rr) * count); ++ if (!srvs) { ++ char *estr = strerror_r(errno, ebuf, MAX_ERR_BUF); ++ error(logopt, "malloc: %s", estr); ++ goto error_out; + } ++ memset(srvs, 0, sizeof(struct srv_rr) * count); + +- /* now skip the header */ ++ srv_num = 0; ++ for (i = 0; i < count && (start < end); i++) { ++ unsigned int data_offset; ++ struct srv_rr srv; ++ struct srv_rr *psrv; ++ struct rr rr; + +- p += NS_HFIXEDSZ; ++ memset(&rr, 0, sizeof(struct rr)); + +- /* parse the query section */ ++ data_offset = get_data_offset(packet, start, end, &rr); ++ if (data_offset <= 0) { ++ error(logopt, "failed to get start of data"); ++ goto error_out; ++ } ++ start += data_offset; + +- for (rrnum = 0; rrnum < query_count; rrnum++) { +- struct dns_query q; ++ if (rr.type != T_SRV) ++ continue; + +- ret = dns_parse_query(logopt, buffer, buffer+resp_len, &p, &q); +- if (!ret) { +- error(logopt, +- "Failed to parse query record [%d]", rrnum); +- free(buffer); +- free(dcs); +- return EBADMSG; ++ psrv = parse_srv_rr(logopt, packet, start, end, &rr, &srv); ++ if (psrv) { ++ memcpy(&srvs[srv_num], psrv, sizeof(struct srv_rr)); ++ srv_num++; + } +- } + +- /* now we are at the answer section */ ++ start += rr.len; ++ } ++ free(packet); + +- for (rrnum = 0; rrnum < answer_count; rrnum++) { +- ret = dns_parse_rr_srv(logopt, +- buffer, buffer+resp_len, +- &p, &dcs[rrnum]); +- if (!ret) { +- error(logopt, +- "Failed to parse answer record [%d]", rrnum); +- free(buffer); +- free(dcs); +- return EBADMSG; +- } ++ if (!srv_num) { ++ error(logopt, "no srv resource records found"); ++ goto error_srvs; + } +- idx = rrnum; + +- qsort(dcs, idx, sizeof(struct dns_rr_srv), QSORT_CAST dnssrvcmp); ++ qsort(srvs, srv_num, sizeof(struct srv_rr), ++ (int (*)(const void *, const void *)) cmp); + +- *dclist = dcs; +- *numdcs = idx; ++ *dcs = srvs; ++ *dcs_count = srv_num; + ++ return 1; ++ ++error_out: ++ free(packet); ++error_srvs: ++ if (srvs) ++ free_srv_rrs(srvs, srv_num); + return 0; + } + +@@ -553,14 +337,14 @@ void free_dclist(struct dclist *dclist) + static char *getdnsdomainname(unsigned int logopt) + { + struct addrinfo hints, *ni; +- char name[MAX_DNS_NAME_LENGTH + 1]; ++ char name[MAXDNAME + 1]; + char buf[MAX_ERR_BUF]; + char *dnsdomain = NULL; + char *ptr; + int ret; + + memset(name, 0, sizeof(name)); +- if (gethostname(name, MAX_DNS_NAME_LENGTH) == -1) { ++ if (gethostname(name, MAXDNAME) == -1) { + char *estr = strerror_r(errno, buf, MAX_ERR_BUF); + error(logopt, "gethostname: %s", estr); + return NULL; +@@ -593,14 +377,12 @@ struct dclist *get_dc_list(unsigned int logopt, const char *uri) + { + LDAPURLDesc *ludlist = NULL; + LDAPURLDesc **ludp; +- struct dns_rr_srv *dcs; + unsigned int min_ttl = MAX_TTL; + struct dclist *dclist = NULL;; + char buf[MAX_ERR_BUF]; + char *dn_uri, *esc_uri; + char *domain; + char *list; +- int numdcs; + int ret; + + if (strcmp(uri, "ldap:///") && strcmp(uri, "ldaps:///")) { +@@ -679,6 +461,8 @@ struct dclist *get_dc_list(unsigned int logopt, const char *uri) + list = NULL; + for (ludp = &ludlist; *ludp != NULL;) { + LDAPURLDesc *lud = *ludp; ++ struct srv_rr *dcs = NULL; ++ unsigned int numdcs = 0; + size_t req_len, len; + char *request = NULL; + char *tmp; +@@ -716,7 +500,7 @@ struct dclist *get_dc_list(unsigned int logopt, const char *uri) + } + + dclist_mutex_lock(); +- if (dns_lookup_srv(logopt, request, &dcs, &numdcs)) { ++ if (!get_srv_rrs(logopt, request, &dcs, &numdcs)) { + error(logopt, + "DNS SRV query failed for domain %s", domain); + dclist_mutex_unlock(); +@@ -733,7 +517,7 @@ struct dclist *get_dc_list(unsigned int logopt, const char *uri) + for (i = 0; i < numdcs; i++) { + if (dcs[i].ttl > 0 && dcs[i].ttl < min_ttl) + min_ttl = dcs[i].ttl; +- len += strlen(dcs[i].hostname); ++ len += strlen(dcs[i].name); + if (dcs[i].port > 0) + len += sizeof(":65535"); + } +@@ -742,6 +526,8 @@ struct dclist *get_dc_list(unsigned int logopt, const char *uri) + if (!tmp) { + char *estr = strerror_r(errno, buf, MAX_ERR_BUF); + error(logopt, "realloc: %s", estr); ++ if (dcs) ++ free_srv_rrs(dcs, numdcs); + goto out_error; + } + +@@ -755,13 +541,15 @@ struct dclist *get_dc_list(unsigned int logopt, const char *uri) + strcat(tmp, " "); + strcat(tmp, lud->lud_scheme); + strcat(tmp, "://"); +- strcat(tmp, dcs[i].hostname); ++ strcat(tmp, dcs[i].name); + if (dcs[i].port > 0) { + char port[7]; + ret = snprintf(port, 7, ":%d", dcs[i].port); + if (ret > 6) { + error(logopt, + "invalid port: %u", dcs[i].port); ++ if (dcs) ++ free_srv_rrs(dcs, numdcs); + goto out_error; + } + strcat(tmp, port); +@@ -771,10 +559,14 @@ struct dclist *get_dc_list(unsigned int logopt, const char *uri) + + *ludp = lud->lud_next; + ber_memfree(domain); ++ free_srv_rrs(dcs, numdcs); + } + + ldap_free_urldesc(ludlist); + ++ if (!list) ++ goto out_error; ++ + dclist->expire = time(NULL) + min_ttl; + dclist->uri = list; + --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-add-autofs_ldap_auth_conf-man-page.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-add-autofs_ldap_auth_conf-man-page.dpatch @@ -0,0 +1,266 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-add-autofs_ldap_auth_conf-man-page.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - add autofs_ldap_auth.conf man page + +From: Ian Kent + + +--- + + CHANGELOG | 1 + man/auto.master.5.in | 3 + + man/autofs.5 | 1 + man/autofs.8.in | 1 + man/autofs_ldap_auth.conf.5.in | 93 ++++++++++++++++++++++++++++++++++++++++ + man/automount.8 | 1 + samples/autofs_ldap_auth.conf | 63 --------------------------- + 7 files changed, 101 insertions(+), 62 deletions(-) + create mode 100644 man/autofs_ldap_auth.conf.5.in + + +diff --git a/CHANGELOG b/CHANGELOG +index fc4e738..e319b4d 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -30,6 +30,7 @@ + - add locality as valid ldap master map attribute fix. + - add simple bind authentication. + - fix master map source server unavailable handling. ++- add autofs_ldap_auth.conf man page. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/man/auto.master.5.in b/man/auto.master.5.in +index 792035f..453ff98 100644 +--- a/man/auto.master.5.in ++++ b/man/auto.master.5.in +@@ -365,6 +365,8 @@ and set the location of the client certificate and private key + in the per-user configuration. The location of these files and the configuration + entry requirements is system dependent so the documentation for your + installation will need to be consulted to get further information. ++.P ++See \fBautofs_ldap_auth.conf\fP(5) for more information. + .SH EXAMPLE + .sp + .RS +.2i +@@ -399,6 +401,7 @@ configuration will be used to locate the source of the map + .BR automount (8), + .BR autofs (5), + .BR autofs (8). ++.BR autofs_ldap_auth.conf (5) + .SH AUTHOR + This manual page was written by Christoph Lameter , + for the Dean GNU/Linux system. Edited by and +diff --git a/man/autofs.5 b/man/autofs.5 +index 5a01791..c5614e1 100644 +--- a/man/autofs.5 ++++ b/man/autofs.5 +@@ -229,6 +229,7 @@ and LDAP only. + .BR auto.master (5), + .BR autofs (8), + .BR mount (8). ++.BR autofs_ldap_auth.conf (5) + .SH AUTHOR + This manual page was written by Christoph Lameter , + for the Debian GNU/Linux system. Edited by H. Peter Avian +diff --git a/man/autofs.8.in b/man/autofs.8.in +index 4828b39..ac0670d 100644 +--- a/man/autofs.8.in ++++ b/man/autofs.8.in +@@ -50,6 +50,7 @@ will display the status of, + .BR automount (8), + .BR autofs (5), + .BR auto.master (5). ++.BR autofs_ldap_auth.conf (5) + .SH AUTHOR + This manual page was written by Christoph Lameter , + for the Debi GNU/Linux system. Edited by H. Peter Anvin +diff --git a/man/autofs_ldap_auth.conf.5.in b/man/autofs_ldap_auth.conf.5.in +new file mode 100644 +index 0000000..ecec20d +--- /dev/null ++++ b/man/autofs_ldap_auth.conf.5.in +@@ -0,0 +1,93 @@ ++.\" t ++.TH AUTOFS_LDAP_AUTH.CONF 5 "19 Feb 2010" ++.SH NAME ++autofs_ldap_auth.conf \- autofs LDAP authentication configuration ++.SH "DESCRIPTION" ++LDAP authenticated binds, TLS encrypted connections and certification ++may be used by setting appropriate values in the autofs authentication ++configuration file and configuring the LDAP client with appropriate ++settings. The default location of this file is ++.nh ++.BR @@autofsmapdir@@/autofs_ldap_auth.conf . ++.hy ++If this file exists it will be used to establish whether TLS or authentication ++should be used. ++.P ++An example of this file is: ++.sp ++.RS +.2i ++.ta 1.0i ++.nf ++ ++ ++.fi ++.RE ++.sp ++If TLS encryption is to be used the location of the Certificate Authority ++certificate must be set within the LDAP client configuration in ++order to validate the server certificate. If, in addition, a certified ++connection is to be used then the client certificate and private key file ++locations must also be configured within the LDAP client. ++.SH "OPTIONS" ++This files contains a single XML element, as shown in the example above, with ++several attributes. ++.TP ++The possible attributes are: ++.TP ++\fBusetls="yes"|"no"\fP ++Determines whether an encrypted connection to the ldap server ++should be attempted. ++.TP ++\fBtlsrequired="yes"|"no"\fP ++This flag tells whether the ldap connection must be encrypted. If set to "yes", ++the automounter will fail to start if an encrypted connection cannot be ++established. ++.TP ++\fBauthrequired="yes"|"no"|"autodetect"|"simple"\fP ++This option tells whether an authenticated connection to the ldap server is ++required in order to perform ldap queries. If the flag is set to yes, only ++sasl authenticated connections will be allowed. If it is set to no then ++authentication is not needed for ldap server connections. If it is set to ++autodetect then the ldap server will be queried to establish a suitable sasl ++authentication mechanism. If no suitable mechanism can be found, connections ++to the ldap server are made without authentication. Finally, if it is set to ++simple, then simple authentication will be used instead of SASL. ++.TP ++\fBauthtype="GSSAPI"|"LOGIN"|"PLAIN"|"ANONYMOUS"|"DIGEST-MD5"\fP ++This attribute can be used to specify a preferred authentication mechanism. ++ In normal operations, the automounter will attempt to authenticate to the ++ldap server using the list of supportedSASLmechanisms obtained from the ++directory server. Explicitly setting the authtype will bypass this selection ++and only try the mechanism specified. ++.TP ++\fBuser=""\fP ++This attribute holds the authentication identity used by authentication ++mechanisms that require it. Legal values for this attribute include any ++printable characters that can be used by the selected authentication ++mechanism. ++.TP ++\fBsecret=""\fP ++This attribute holds the secret used by authentication mechanisms that ++require it. Legal values for this attribute include any printable ++characters that can be used by the selected authentication mechanism. ++.TP ++\fBclientprinc=""\fP ++When using GSSAPI authentication, this attribute is consulted to determine ++the principal name to use when authenticating to the directory server. By ++default, this will be set to "autofsclient/@. ++.TP ++\fBcredentialcache=""\fP ++When using GSSAPI authentication, this attribute can be used to specify an ++externally configured credential cache that is used during authentication. ++By default, autofs will setup a memory based credential cache. ++.SH "SEE ALSO" ++.BR auto.master (5), ++.SH AUTHOR ++This manual page was written by Ian Kent . +diff --git a/man/automount.8 b/man/automount.8 +index d9a45c2..18f74bf 100644 +--- a/man/automount.8 ++++ b/man/automount.8 +@@ -152,6 +152,7 @@ constructed has been detached from the mount tree. + .BR autofs (8), + .BR auto.master (5), + .BR mount (8). ++.BR autofs_ldap_auth.conf (5) + .SH BUGS + Don't know, I've fixed everything I know about. + +diff --git a/samples/autofs_ldap_auth.conf b/samples/autofs_ldap_auth.conf +index be5e7dd..4033ba0 100644 +--- a/samples/autofs_ldap_auth.conf ++++ b/samples/autofs_ldap_auth.conf +@@ -1,68 +1,7 @@ + + + + + +If we encounter a recursive autofs mount in the mount location +path, and call access(2) to perform the mount, the mount may +succeed but the access(2) call return a fail. In the case where +there are multiple processes waiting on this mount they will all +get the failure return which may be incorrect for other waiters. +Ignoring the return code from the access(2) call and allowing the +mount to go ahead anyway should give the VFS the chance to check +the access for each individual process and so return an accurate +retult. +--- + + CHANGELOG | 1 + + daemon/spawn.c | 12 +++++++++--- + 2 files changed, 10 insertions(+), 3 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index 8429e20..88bcc1b 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -14,6 +14,7 @@ + - fix timeout in connect_nb(). + - fix pidof init script usage. + - check for path mount location in generic module. ++- dont fail mount on access fail. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/daemon/spawn.c b/daemon/spawn.c +index 7c254d9..285f4d7 100644 +--- a/daemon/spawn.c ++++ b/daemon/spawn.c +@@ -189,9 +189,15 @@ static int do_spawn(unsigned logopt, unsigned int wait, + } + setpgrp(); + +- /* Trigger the recursive mount */ +- if (access(argv[loc], F_OK) == -1) +- _exit(errno); ++ /* ++ * Trigger the recursive mount. ++ * ++ * Ignore the access(2) return code as there may be ++ * multiple waiters for this mount and we need to ++ * let the VFS handle access returns to each ++ * individual waiter. ++ */ ++ access(argv[loc], F_OK); + + seteuid(0); + setegid(0); --- autofs5-5.0.5.orig/debian/patches/17ld.dpatch +++ autofs5-5.0.5/debian/patches/17ld.dpatch @@ -0,0 +1,64 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## +## DP: Fix FTBFS with ld --no-add-needed and ld --as-needed. + +@DPATCH@ +--- autofs5-5.0.5.orig/aclocal.m4 ++++ autofs5-5.0.5/aclocal.m4 +@@ -223,8 +223,8 @@ + [AC_MSG_CHECKING(for libhesiod) + + # save current ldflags +-af_check_hesiod_save_ldflags="$LDFLAGS" +-LDFLAGS="$LDFLAGS -lhesiod -lresolv" ++af_check_hesiod_save_libs="$LIBS" ++LIBS="$LIBS -lhesiod -lresolv" + + AC_TRY_LINK( + [ #include ], +@@ -234,8 +234,8 @@ + AC_MSG_RESULT(yes) ], + [ AC_MSG_RESULT(no) ]) + +-# restore ldflags +-LDFLAGS="$af_check_hesiod_save_ldflags" ++# restore libs ++LIBS="$af_check_hesiod_save_libs" + ]) + + dnl -------------------------------------------------------------------------- +--- autofs5-5.0.5.orig/daemon/Makefile ++++ autofs5-5.0.5/daemon/Makefile +@@ -20,7 +20,7 @@ + CFLAGS += -DAUTOFS_FLAG_DIR=\"$(autofsflagdir)\" + CFLAGS += -DVERSION_STRING=\"$(version)\" + LDFLAGS += -rdynamic +-LIBS = -ldl ++LIBS = -ldl -lpthread + + ifeq ($(LDAP), 1) + ifeq ($(SASL), 1) +--- autofs5-5.0.5.orig/configure ++++ autofs5-5.0.5/configure +@@ -3979,8 +3979,8 @@ + $as_echo_n "checking for libhesiod... " >&6; } + + # save current ldflags +-af_check_hesiod_save_ldflags="$LDFLAGS" +-LDFLAGS="$LDFLAGS -lhesiod -lresolv" ++af_check_hesiod_save_libs="$LIBS" ++LIBS="$LIBS -lhesiod -lresolv" + + cat >conftest.$ac_ext <<_ACEOF + /* confdefs.h. */ +@@ -4034,8 +4034,8 @@ + rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext + +-# restore ldflags +-LDFLAGS="$af_check_hesiod_save_ldflags" ++# restore libs ++LIBS="$af_check_hesiod_save_libs" + + if test "$HAVE_HESIOD" == "1"; then + --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-dont-use-master_lex_destroy-to-clear-parse-buffer.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-dont-use-master_lex_destroy-to-clear-parse-buffer.dpatch @@ -0,0 +1,45 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-dont-use-master_lex_destroy-to-clear-parse-buffer.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - don't use master_lex_destroy() to clear parse buffer + +From: Ian Kent + +Using master_lex_destroy() does not seem not to resolve the original +problem it set out to solve in all cases. Change to using memset() to +clear the buffer instead. +--- + + CHANGELOG | 1 + + lib/master_tok.l | 2 +- + 2 files changed, 2 insertions(+), 1 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index e37dadb..329b028 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -9,6 +9,7 @@ + - fix backwards #ifndef INET6. + - fix stale initialization for file map instance. + - add "preen" fsck for ext4 mounts. ++- don't use master_lex_destroy() to clear parse buffer. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/lib/master_tok.l b/lib/master_tok.l +index 373248b..be2ce10 100644 +--- a/lib/master_tok.l ++++ b/lib/master_tok.l +@@ -414,7 +414,7 @@ static void master_echo(void) + + void master_set_scan_buffer(const char *buffer) + { +- master_lex_destroy(); ++ memset(buff, 0, sizeof(buff)); + optr = buff; + + line = buffer; --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-add-sasl-mutex-callbacks.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-add-sasl-mutex-callbacks.dpatch @@ -0,0 +1,108 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-add-sasl-mutex-callbacks.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - add sasl mutex callbacks + +From: Ian Kent + +We missed the fact that Cyrus SASL requires the user to provide mutex +handling functions when being used in a threaded environment. + +Original patch contributed by Kazuhiro Kikuchi (of Fujitsu), slightly +modified by myself. +--- + + CHANGELOG | 1 + + modules/cyrus-sasl.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 58 insertions(+), 0 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index e2abae3..224a34a 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -23,6 +23,7 @@ + - fix disable timeout. + - fix strdup() return value check (Leonardo Chiquitto). + - fix reconnect get base dn. ++- add missing sasl mutex callbacks. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/modules/cyrus-sasl.c b/modules/cyrus-sasl.c +index 92e2226..d117f0a 100644 +--- a/modules/cyrus-sasl.c ++++ b/modules/cyrus-sasl.c +@@ -944,12 +944,69 @@ void autofs_sasl_dispose(struct lookup_context *ctxt) + } + } + ++static void *sasl_mutex_new(void) ++{ ++ pthread_mutex_t* mutex; ++ ++ mutex = malloc(sizeof(pthread_mutex_t)); ++ if (!mutex) ++ return 0; ++ ++ pthread_mutex_init(mutex, NULL); ++ ++ return (void *) mutex; ++} ++ ++static int sasl_mutex_lock(void *mutex __attribute__((unused))) ++{ ++ int rc; ++ ++ if (!mutex) ++ return SASL_FAIL; ++ ++ rc = pthread_mutex_lock((pthread_mutex_t *) mutex); ++ ++ return (rc==0 ? SASL_OK : SASL_FAIL); ++} ++ ++static int sasl_mutex_unlock(void *mutex __attribute__((unused))) ++{ ++ int rc; ++ ++ if (!mutex) ++ return SASL_FAIL; ++ ++ rc = pthread_mutex_unlock((pthread_mutex_t *) mutex); ++ ++ return (rc==0 ? SASL_OK : SASL_FAIL); ++} ++ ++static void sasl_mutex_dispose(void *mutex __attribute__((unused))) ++{ ++ int rc; ++ ++ if (!mutex) ++ return; ++ ++ rc = pthread_mutex_destroy((pthread_mutex_t *) mutex); ++ if (rc == 0) ++ free(mutex); ++ ++ return; ++} ++ + /* + * Initialize the sasl callbacks, which increments the global + * use counter. + */ + int autofs_sasl_client_init(unsigned logopt) + { ++ ++ sasl_set_mutex(sasl_mutex_new, ++ sasl_mutex_lock, ++ sasl_mutex_unlock, ++ sasl_mutex_dispose); ++ + /* Start up Cyrus SASL--only needs to be done at library load. */ + if (sasl_client_init(callbacks) != SASL_OK) { + error(logopt, "sasl_client_init failed"); --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-fix-reconnect-get-base-dn.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-fix-reconnect-get-base-dn.dpatch @@ -0,0 +1,47 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-fix-reconnect-get-base-dn.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - fix reconnect get base dn + +From: Ian Kent + +If connect to an LDAP server but fail to find a valid query dn a +subsequent reconnect succeeds without setting the schema fields +used for constructing queries. A segfault then occurs when we try +to construct a query using the schema values that should have been +set during the query dn validation. +--- + + CHANGELOG | 1 + + modules/lookup_ldap.c | 2 +- + 2 files changed, 2 insertions(+), 1 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index 3166898..e2abae3 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -22,6 +22,7 @@ + - fix random selection option. + - fix disable timeout. + - fix strdup() return value check (Leonardo Chiquitto). ++- fix reconnect get base dn. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c +index 079ded1..e3c0c51 100644 +--- a/modules/lookup_ldap.c ++++ b/modules/lookup_ldap.c +@@ -556,7 +556,7 @@ static int do_bind(unsigned logopt, LDAP *ldap, const char *uri, struct lookup_c + } + } + +- if (!need_base) ++ if (ctxt->schema && !need_base) + return 1; + + /* --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-fix-ampersand-escape-in-auto-smb.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-fix-ampersand-escape-in-auto-smb.dpatch @@ -0,0 +1,42 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-fix-ampersand-escape-in-auto-smb.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - fix ampersand escape in auto.smb + +From: Ian Kent + +CIFS share names containing an ampersand need to be escaped. +--- + + CHANGELOG | 1 + + samples/auto.smb | 1 + + 2 files changed, 2 insertions(+), 0 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index 5a921e1..a11a969 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -25,6 +25,7 @@ + - fix reconnect get base dn. + - add missing sasl mutex callbacks. + - fix get query dn failure. ++- fix ampersand escape in auto.smb. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/samples/auto.smb b/samples/auto.smb +index fb39053..2dfb8f8 100755 +--- a/samples/auto.smb ++++ b/samples/auto.smb +@@ -26,6 +26,7 @@ $SMBCLIENT -gNL $key 2>/dev/null| awk -v key="$key" -v opts="$opts" -F'|' -- ' + # Enclose mount dir and location in quotes + # Double quote "$" in location as it is special + gsub(/\$$/, "\\$", loc); ++ gsub(/\&/,"\\\\&",loc) + print " \\\n\t \"/" dir "\"", "\"://" key "/" loc "\"" + } + END { if (!first) print "\n"; else exit 1 } --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-fix-timeout-in-connect_nb.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-fix-timeout-in-connect_nb.dpatch @@ -0,0 +1,50 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-fix-timeout-in-connect_nb.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - fix timeout in connect_nb() + +From: Ian Kent + +When changing the timed wait from using select(2) to poll(2) in +connect_nb(), to overcome the 1024 file handle limit of select(), +the wait timeout was not converted from seconds to milliseconds. +--- + + CHANGELOG | 1 + + lib/rpc_subs.c | 7 +++++++ + 2 files changed, 8 insertions(+), 0 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index ccf2d32..dd093e2 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -11,6 +11,7 @@ + - add "preen" fsck for ext4 mounts. + - don't use master_lex_destroy() to clear parse buffer. + - make documentation for set-log-priority clearer. ++- fix timeout in connect_nb(). + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/lib/rpc_subs.c b/lib/rpc_subs.c +index cafc775..628f0fc 100644 +--- a/lib/rpc_subs.c ++++ b/lib/rpc_subs.c +@@ -161,6 +161,13 @@ static int connect_nb(int fd, struct sockaddr *addr, socklen_t len, struct timev + if (ret == 0) + goto done; + ++ if (timeout != -1) { ++ if (timeout >= (INT_MAX - 1)/1000) ++ timeout = INT_MAX - 1; ++ else ++ timeout = timeout * 1000; ++ } ++ + pfd[0].fd = fd; + pfd[0].events = POLLOUT; + --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-include-krb5-library.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-include-krb5-library.dpatch @@ -0,0 +1,210 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-include-krb5-library.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - include krb5 library + +From: Ian Kent + +Since the Cyrus SASL module calls Kerberos directly we should be +linking against the Kerberos librarys. +--- + + Makefile.conf.in | 2 ++ + aclocal.m4 | 19 +++++++++++++++ + configure | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++- + configure.in | 5 +++- + modules/Makefile | 4 ++- + 5 files changed, 93 insertions(+), 4 deletions(-) + + +diff --git a/Makefile.conf.in b/Makefile.conf.in +index 7670364..80093c1 100644 +--- a/Makefile.conf.in ++++ b/Makefile.conf.in +@@ -31,6 +31,8 @@ XML_FLAGS = @XML_FLAGS@ + SASL = @HAVE_SASL@ + LIBSASL= @LIBSASL@ + SASL_FLAGS = @SASL_FLAGS@ ++KRB5_LIBS=@KRB5_LIBS@ ++KRB5_FLAGS=@KRB5_FLAGS@ + + # NIS+ support: yes (1) no (0) + NISPLUS = @HAVE_NISPLUS@ +diff --git a/aclocal.m4 b/aclocal.m4 +index e7f1a30..750a159 100644 +--- a/aclocal.m4 ++++ b/aclocal.m4 +@@ -215,6 +215,25 @@ else + fi]) + + dnl -------------------------------------------------------------------------- ++dnl AF_CHECK_KRB5 ++dnl ++dnl Check for Kerberos 5 ++dnl -------------------------------------------------------------------------- ++AC_DEFUN([AF_CHECK_KRB5], ++[AC_PATH_PROGS(KRB5_CONFIG, krb5-config, no) ++AC_MSG_CHECKING(for Kerberos library) ++if test "$KRB5_CONFIG" = "no" ++then ++ AC_MSG_RESULT(no) ++ HAVE_KRB5=0 ++else ++ AC_MSG_RESULT(yes) ++ HAVE_KRB5=1 ++ KRB5_LIBS=`$KRB5_CONFIG --libs` ++ KRB5_FLAGS=`$KRB5_CONFIG --cflags` ++fi]) ++ ++dnl -------------------------------------------------------------------------- + dnl AF_CHECK_LIBHESIOD + dnl + dnl Check for lib hesiod +diff --git a/configure b/configure +index f5b7d07..352b0d6 100755 +--- a/configure ++++ b/configure +@@ -640,6 +640,8 @@ ac_subst_vars='LTLIBOBJS + LIBOBJS + DAEMON_LDFLAGS + DAEMON_CFLAGS ++KRB5_FLAGS ++KRB5_LIBS + LIBSASL + HAVE_SASL + SASL_FLAGS +@@ -657,6 +659,7 @@ LIBHESIOD + HAVE_HESIOD + LIBRESOLV + LIBNSL ++KRB5_CONFIG + XML_CONFIG + PATH_RPCGEN + RPCGEN +@@ -3786,7 +3789,7 @@ $as_echo "no" >&6; } + fi + fi + +-# LDAP SASL auth need libxml ++# LDAP SASL auth needs libxml and Kerberos + for ac_prog in xml2-config + do + # Extract the first word of "$ac_prog", so it can be a program name with args. +@@ -3864,6 +3867,66 @@ _ACEOF + fi + fi + fi ++for ac_prog in krb5-config ++do ++ # Extract the first word of "$ac_prog", so it can be a program name with args. ++set dummy $ac_prog; ac_word=$2 ++{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 ++$as_echo_n "checking for $ac_word... " >&6; } ++if test "${ac_cv_path_KRB5_CONFIG+set}" = set; then ++ $as_echo_n "(cached) " >&6 ++else ++ case $KRB5_CONFIG in ++ [\\/]* | ?:[\\/]*) ++ ac_cv_path_KRB5_CONFIG="$KRB5_CONFIG" # Let the user override the test with a path. ++ ;; ++ *) ++ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ++ ac_cv_path_KRB5_CONFIG="$as_dir/$ac_word$ac_exec_ext" ++ $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 ++ break 2 ++ fi ++done ++done ++IFS=$as_save_IFS ++ ++ ;; ++esac ++fi ++KRB5_CONFIG=$ac_cv_path_KRB5_CONFIG ++if test -n "$KRB5_CONFIG"; then ++ { $as_echo "$as_me:$LINENO: result: $KRB5_CONFIG" >&5 ++$as_echo "$KRB5_CONFIG" >&6; } ++else ++ { $as_echo "$as_me:$LINENO: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++ ++ ++ test -n "$KRB5_CONFIG" && break ++done ++test -n "$KRB5_CONFIG" || KRB5_CONFIG="no" ++ ++{ $as_echo "$as_me:$LINENO: checking for Kerberos library" >&5 ++$as_echo_n "checking for Kerberos library... " >&6; } ++if test "$KRB5_CONFIG" = "no" ++then ++ { $as_echo "$as_me:$LINENO: result: no" >&5 ++$as_echo "no" >&6; } ++ HAVE_KRB5=0 ++else ++ { $as_echo "$as_me:$LINENO: result: yes" >&5 ++$as_echo "yes" >&6; } ++ HAVE_KRB5=1 ++ KRB5_LIBS=`$KRB5_CONFIG --libs` ++ KRB5_FLAGS=`$KRB5_CONFIG --cflags` ++fi + + # + # glibc/libc 6 new libraries +@@ -5241,6 +5304,8 @@ fi + + + ++ ++ + LDFLAGS="${AF_tmp_ldflags}" + + # +diff --git a/configure.in b/configure.in +index 78085bd..233edab 100644 +--- a/configure.in ++++ b/configure.in +@@ -145,8 +145,9 @@ AF_CHECK_PROG(RPCGEN, rpcgen, , $searchpath) + # + AF_SLOPPY_MOUNT() + +-# LDAP SASL auth need libxml ++# LDAP SASL auth needs libxml and Kerberos + AF_CHECK_LIBXML() ++AF_CHECK_KRB5() + + # + # glibc/libc 6 new libraries +@@ -275,6 +276,8 @@ AC_SUBST(XML_LIBS) + AC_SUBST(SASL_FLAGS) + AC_SUBST(HAVE_SASL) + AC_SUBST(LIBSASL) ++AC_SUBST(KRB5_LIBS) ++AC_SUBST(KRB5_FLAGS) + LDFLAGS="${AF_tmp_ldflags}" + + # +diff --git a/modules/Makefile b/modules/Makefile +index 0bb9464..164d412 100644 +--- a/modules/Makefile ++++ b/modules/Makefile +@@ -42,8 +42,8 @@ ifeq ($(LDAP), 1) + MODS += lookup_ldap.so + ifeq ($(SASL), 1) + SASL_OBJ = cyrus-sasl.o +- LDAP_FLAGS += $(SASL_FLAGS) $(XML_FLAGS) -DLDAP_THREAD_SAFE +- LIBLDAP += $(LIBSASL) $(XML_LIBS) ++ LDAP_FLAGS += $(SASL_FLAGS) $(XML_FLAGS) $(KRB5_FLAGS) -DLDAP_THREAD_SAFE ++ LIBLDAP += $(LIBSASL) $(XML_LIBS) $(KRB5_LIBS) + endif + endif + --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-fix-backwards-ifndef-INET6.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-fix-backwards-ifndef-INET6.dpatch @@ -0,0 +1,54 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-fix-backwards-ifndef-INET6.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - fix backwards #ifndef INET6 + +From: Jeff Moyer + +Fix reversed macro checks for INET6 in get_proximity(). + +Signed-off-by: Jeff Moyer +--- + + CHANGELOG | 1 + + modules/replicated.c | 4 ++-- + 2 files changed, 3 insertions(+), 2 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index b9b1602..7997d1d 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -6,6 +6,7 @@ + - special case cifs escapes. + - fix compile fail with when LDAP is excluded. + - more code analysis corrections (and fix a typo in an init script). ++- fix backwards #ifndef INET6. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/modules/replicated.c b/modules/replicated.c +index a66de9f..4cd3eb4 100644 +--- a/modules/replicated.c ++++ b/modules/replicated.c +@@ -231,7 +231,7 @@ static unsigned int get_proximity(struct sockaddr *host_addr) + break; + + case AF_INET6: +-#ifndef INET6 ++#ifdef INET6 + if (host_addr->sa_family == AF_INET) + break; + +@@ -313,7 +313,7 @@ static unsigned int get_proximity(struct sockaddr *host_addr) + break; + + case AF_INET6: +-#ifndef INET6 ++#ifdef INET6 + if (host_addr->sa_family == AF_INET) + break; + --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-add-locality-as-valid-ldap-master-map-attribute-fix.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-add-locality-as-valid-ldap-master-map-attribute-fix.dpatch @@ -0,0 +1,61 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-add-locality-as-valid-ldap-master-map-attribute-fix.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - add locality as valid ldap master map attribute fix + +From: Ian Kent + +A recent change enabled the use of the locality ("l") attribute in map name +dns used in the master map. + +When using an entry like: +/mp yp:lnxhome + +the l following the ":" would match a dn patern in the tokenizer leading +to a syntax error. This has exposed a bug present for some time as, for +the map entry syntax above, this could also happen if the map name started +with another attribute, such as "cn" or "o". +--- + + CHANGELOG | 1 + + lib/master_tok.l | 4 ++-- + 2 files changed, 3 insertions(+), 2 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index 6ca1827..5973824 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -27,6 +27,7 @@ + - fix get query dn failure. + - fix ampersand escape in auto.smb. + - add locality as valid ldap master map attribute. ++- add locality as valid ldap master map attribute fix. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/lib/master_tok.l b/lib/master_tok.l +index 2693c51..d05d1fb 100644 +--- a/lib/master_tok.l ++++ b/lib/master_tok.l +@@ -210,7 +210,7 @@ OPTNTOUT (-n{OPTWS}|-n{OPTWS}={OPTWS}|--negative-timeout{OPTWS}|--negative-timeo + } + + {MTYPE} | +- {MTYPE}/{DNSERVERSTR}{DNATTRSTR} | ++ {MTYPE}/{DNSERVERSTR}{DNATTRSTR}= | + {MTYPE}/{DNATTRSTR}= { + tlen = master_leng - 1; + if (bptr != buff && isblank(master_text[tlen])) { +@@ -250,7 +250,7 @@ OPTNTOUT (-n{OPTWS}|-n{OPTWS}={OPTWS}|--negative-timeout{OPTWS}|--negative-timeo + yyless(0); + } + +- {DNSERVERSTR}{DNATTRSTR} { ++ {DNSERVERSTR}{DNATTRSTR}= { + BEGIN(DNSTR); + yyless(0); + } --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-add-simple-bind-auth.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-add-simple-bind-auth.dpatch @@ -0,0 +1,138 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-add-simple-bind-auth.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - add simple bind authentication + +From: James Y Knight + +This patch adds the ability to do a simple bind against an LDAP server with +the configured username and password. +--- + + CHANGELOG | 1 + + include/lookup_ldap.h | 1 + + modules/lookup_ldap.c | 21 +++++++++++++-------- + samples/autofs_ldap_auth.conf | 16 +++++++++------- + 4 files changed, 24 insertions(+), 15 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index 5973824..d95542d 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -28,6 +28,7 @@ + - fix ampersand escape in auto.smb. + - add locality as valid ldap master map attribute. + - add locality as valid ldap master map attribute fix. ++- add simple bind authentication. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/include/lookup_ldap.h b/include/lookup_ldap.h +index dcae220..1e1c7a4 100644 +--- a/include/lookup_ldap.h ++++ b/include/lookup_ldap.h +@@ -97,6 +97,7 @@ struct lookup_context { + #define LDAP_AUTH_NOTREQUIRED 0x0001 + #define LDAP_AUTH_REQUIRED 0x0002 + #define LDAP_AUTH_AUTODETECT 0x0004 ++#define LDAP_AUTH_USESIMPLE 0x0008 + + /* lookup_ldap.c */ + LDAP *init_ldap_connection(unsigned logopt, const char *uri, struct lookup_context *ctxt); +diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c +index 8387951..d7d4f71 100644 +--- a/modules/lookup_ldap.c ++++ b/modules/lookup_ldap.c +@@ -137,11 +137,13 @@ static void uris_mutex_unlock(struct lookup_context *ctxt) + return; + } + +-int bind_ldap_anonymous(unsigned logopt, LDAP *ldap, const char *uri, struct lookup_context *ctxt) ++int bind_ldap_simple(unsigned logopt, LDAP *ldap, const char *uri, struct lookup_context *ctxt) + { + int rv; + +- if (ctxt->version == 2) ++ if (ctxt->auth_required == LDAP_AUTH_USESIMPLE) ++ rv = ldap_simple_bind_s(ldap, ctxt->user, ctxt->secret); ++ else if (ctxt->version == 2) + rv = ldap_simple_bind_s(ldap, ctxt->base, NULL); + else + rv = ldap_simple_bind_s(ldap, NULL, NULL); +@@ -517,12 +519,12 @@ static int do_bind(unsigned logopt, LDAP *ldap, const char *uri, struct lookup_c + rv = autofs_sasl_bind(logopt, ldap, ctxt); + debug(logopt, MODPREFIX "autofs_sasl_bind returned %d", rv); + } else { +- rv = bind_ldap_anonymous(logopt, ldap, uri, ctxt); +- debug(logopt, MODPREFIX "ldap anonymous bind returned %d", rv); ++ rv = bind_ldap_simple(logopt, ldap, uri, ctxt); ++ debug(logopt, MODPREFIX "ldap simple bind returned %d", rv); + } + #else +- rv = bind_ldap_anonymous(logopt, ldap, uri, ctxt); +- debug(logopt, MODPREFIX "ldap anonymous bind returned %d", rv); ++ rv = bind_ldap_simple(logopt, ldap, uri, ctxt); ++ debug(logopt, MODPREFIX "ldap simple bind returned %d", rv); + #endif + + if (rv != 0) +@@ -971,11 +973,13 @@ int parse_ldap_config(unsigned logopt, struct lookup_context *ctxt) + auth_required = LDAP_AUTH_NOTREQUIRED; + else if (!strcasecmp(authrequired, "autodetect")) + auth_required = LDAP_AUTH_AUTODETECT; ++ else if (!strcasecmp(authrequired, "simple")) ++ auth_required = LDAP_AUTH_USESIMPLE; + else { + error(logopt, + MODPREFIX + "The authrequired property must have value " +- "\"yes\", \"no\" or \"autodetect\"."); ++ "\"yes\", \"no\", \"autodetect\", or \"simple\"."); + ret = -1; + goto out; + } +@@ -991,7 +995,8 @@ int parse_ldap_config(unsigned logopt, struct lookup_context *ctxt) + goto out; + } + +- if (authtype && authtype_requires_creds(authtype)) { ++ if (auth_required == LDAP_AUTH_USESIMPLE || ++ (authtype && authtype_requires_creds(authtype))) { + ret = get_property(logopt, root, "user", &user); + ret |= get_property(logopt, root, "secret", &secret); + if (ret != 0 || (!user || !secret)) { +diff --git a/samples/autofs_ldap_auth.conf b/samples/autofs_ldap_auth.conf +index a1f60c0..be5e7dd 100644 +--- a/samples/autofs_ldap_auth.conf ++++ b/samples/autofs_ldap_auth.conf +@@ -17,17 +17,19 @@ tlsrequired - This flag tells whether the ldap connection must be + + authrequired - This option tells whether an authenticated connection to + the ldap server is required in order to perform ldap queries. +- If this flag is set to yes, then only authenticated connections ++ If the flag is set to yes, only sasl authenticated connections + will be allowed. If it is set to no then authentication is not +- needed for ldap server connections. Finally, if it is set to +- autodetect then the ldap server will be queried to establish +- a suitable authentication mechanism. If no suitable mechanism +- can be found, connections to the ldap server are made without +- authentication. +- Legal values for this option include: ++ needed for ldap server connections. If it is set to autodetect ++ then the ldap server will be queried to establish a suitable sasl ++ authentication mechanism. If no suitable mechanism can be found, ++ connections to the ldap server are made without authentication. ++ Finally, if it is set to simple, then simple authentication will ++ be used instead of SASL. ++ + "yes" + "no" + "autodetect" ++ "simple" + + authtype - This attribute can be used to specify a preferred + authentication mechanism. In normal operations, the --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-check-for-path-mount-location-in-generic-module.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-check-for-path-mount-location-in-generic-module.dpatch @@ -0,0 +1,119 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-check-for-path-mount-location-in-generic-module.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - check for path mount location in generic module + +From: Ian Kent + +Currently we check for dependent mounts in the mount location path +for bind mounts and loopback mounts. But we can have the case where +a mount other than a loopback mount uses a local path and is not a +bind mount. In this case we need to check the local path for dependent +mounts. To do this we can check the mount location prior to spawning +the mount and if it starts with a "/" then it is a local path and +the check is needed. +--- + + CHANGELOG | 1 + + daemon/spawn.c | 41 +++++++++++++++++++++++++++-------------- + 2 files changed, 28 insertions(+), 14 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index cc2efab..8429e20 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -13,6 +13,7 @@ + - make documentation for set-log-priority clearer. + - fix timeout in connect_nb(). + - fix pidof init script usage. ++- check for path mount location in generic module. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/daemon/spawn.c b/daemon/spawn.c +index db356d4..7c254d9 100644 +--- a/daemon/spawn.c ++++ b/daemon/spawn.c +@@ -154,22 +154,30 @@ static int do_spawn(unsigned logopt, unsigned int wait, + + f = fork(); + if (f == 0) { ++ char **pargv = (char **) argv; ++ int loc = 0; ++ + reset_signals(); + close(pipefd[0]); + dup2(pipefd[1], STDOUT_FILENO); + dup2(pipefd[1], STDERR_FILENO); + close(pipefd[1]); + +- /* Bind mount - check target exists */ +- if (use_access) { +- char **pargv = (char **) argv; +- int argc = 0; +- pid_t pgrp = getpgrp(); ++ /* what to mount must always be second last */ ++ while (*pargv++) ++ loc++; ++ loc -= 2; + +- /* what to mount must always be second last */ +- while (*pargv++) +- argc++; +- argc -= 2; ++ /* ++ * If the mount location starts with a "/" then it is ++ * a local path. In this case it is a bind mount, a ++ * loopback mount or a file system that uses a local ++ * path so we need to check for dependent mounts. ++ * ++ * I hope host names are never allowed "/" as first char ++ */ ++ if (use_access && *(argv[loc]) == '/') { ++ pid_t pgrp = getpgrp(); + + /* + * Pretend to be requesting user and set non-autofs +@@ -182,7 +190,7 @@ static int do_spawn(unsigned logopt, unsigned int wait, + setpgrp(); + + /* Trigger the recursive mount */ +- if (access(argv[argc], F_OK) == -1) ++ if (access(argv[loc], F_OK) == -1) + _exit(errno); + + seteuid(0); +@@ -312,7 +320,7 @@ int spawn_mount(unsigned logopt, ...) + #ifdef ENABLE_MOUNT_LOCKING + options = SPAWN_OPT_LOCK; + #else +- options = SPAWN_OPT_NONE; ++ options = SPAWN_OPT_ACCESS; + #endif + + va_start(arg, logopt); +@@ -344,12 +352,17 @@ int spawn_mount(unsigned logopt, ...) + p = argv + 2; + } + while ((*p = va_arg(arg, char *))) { +- if (options == SPAWN_OPT_NONE && !strcmp(*p, "-o")) { ++ if (options == SPAWN_OPT_ACCESS && !strcmp(*p, "-t")) { + *(++p) = va_arg(arg, char *); + if (!*p) + break; +- if (strstr(*p, "loop")) +- options = SPAWN_OPT_ACCESS; ++ /* ++ * A cifs mount location begins with a "/" but ++ * is not a local path, so don't try to resolve ++ * it. Mmmm ... does anyone use smbfs these days? ++ */ ++ if (strstr(*p, "cifs")) ++ options = SPAWN_OPT_NONE; + } + p++; + } --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.4-always-read-file-maps-mount-lookup-map-read-fix.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.4-always-read-file-maps-mount-lookup-map-read-fix.dpatch @@ -0,0 +1,54 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.4-always-read-file-maps-mount-lookup-map-read-fix.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - always read file maps mount lookup map read fix + +From: Ian Kent + +If, during a mount lookup, a file map is found to have changed and the +browse option is not being used, the file map won't be refreshed, even +though file maps should always be read into the cache. + +A previous change for the "always read file maps" optimization moved +the check for the browse option into the map module read function so +checking for this in send_map_update_request() is not needed and +causes nobrowse file maps to not be read if they have changed. This +isn't quite optimal as there will be a partial read of the file map +to satisfy the lookup and a full read of the map done by the queued +update request. I don't think anything can be done about that though. +--- + + CHANGELOG | 1 + + lib/master.c | 3 --- + 2 files changed, 1 insertions(+), 3 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index 577ae41..e05038b 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -50,6 +50,7 @@ + - remove ERR_remove_state() openssl call. + - fix init script restart option. + - fix init script status privilege error. ++- always read file maps mount lookup map read fix. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/lib/master.c b/lib/master.c +index 12f2d22..ebeccce 100644 +--- a/lib/master.c ++++ b/lib/master.c +@@ -489,9 +489,6 @@ void send_map_update_request(struct autofs_point *ap) + struct map_source *map; + int status, need_update = 0; + +- if (!(ap->flags & MOUNT_FLAG_GHOST)) +- return; +- + status = pthread_mutex_lock(&instance_mutex); + if (status) + fatal(status); --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-use-weight-only-for-server-selection.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-use-weight-only-for-server-selection.dpatch @@ -0,0 +1,596 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-use-weight-only-for-server-selection.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - use weight only for server selection + +From: Ian Kent + +When using weighted server names in map entries the server response +time is also taken into consideration when selecting a server for +the target of the mount. In some cases people need to be able to +rely on selection strictly by weight. We add pseudo option +"--use-weight-only" that can be used in with master map entries +or with individual map entries to provide for this. For individual +map entries the option "no-use-weight-only" can also be used to +override the master map option. +--- + + CHANGELOG | 1 + + daemon/automount.c | 8 +++-- + include/automount.h | 3 ++ + include/replicated.h | 3 +- + lib/master_parse.y | 12 ++++++-- + lib/master_tok.l | 1 + + man/auto.master.5.in | 6 ++++ + man/autofs.5 | 7 +++++ + modules/mount_nfs.c | 15 +++++++--- + modules/parse_sun.c | 36 +++++++++++++++++++++--- + modules/replicated.c | 76 ++++++++++++++++++++++++++++++-------------------- + 11 files changed, 120 insertions(+), 48 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index 11054da..c98204d 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -55,6 +55,7 @@ + - add external bind method. + - fix add simple bind auth. + - add option to dump configured automount maps. ++- use weight only for server selection. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/daemon/automount.c b/daemon/automount.c +index 1b1007d..6b4e0d0 100644 +--- a/daemon/automount.c ++++ b/daemon/automount.c +@@ -57,8 +57,8 @@ const char *fifodir = AUTOFS_FIFO_DIR "/autofs.fifo"; + const char *global_options; /* Global option, from command line */ + + static char *pid_file = NULL; /* File in which to keep pid */ +-unsigned int global_random_selection; /* use random policy when selecting +- * which multi-mount host to mount */ ++unsigned int global_selection_options; ++ + long global_negative_timeout = -1; + int do_force_unlink = 0; /* Forceably unlink mount tree at startup */ + +@@ -1855,7 +1855,7 @@ int main(int argc, char *argv[]) + timeout = defaults_get_timeout(); + ghost = defaults_get_browse_mode(); + logging = defaults_get_logging(); +- global_random_selection = 0; ++ global_selection_options = 0; + global_options = NULL; + have_global_options = 0; + foreground = 0; +@@ -1898,7 +1898,7 @@ int main(int argc, char *argv[]) + exit(0); + + case 'r': +- global_random_selection = 1; ++ global_selection_options |= MOUNT_FLAG_RANDOM_SELECT; + break; + + case 'n': +diff --git a/include/automount.h b/include/automount.h +index 7d4efcc..5002747 100644 +--- a/include/automount.h ++++ b/include/automount.h +@@ -443,6 +443,9 @@ struct kernel_mod_version { + /* Mount being re-mounted */ + #define MOUNT_FLAG_REMOUNT 0x0008 + ++/* Use server weight only for selection */ ++#define MOUNT_FLAG_USE_WEIGHT_ONLY 0x0010 ++ + struct autofs_point { + pthread_t thid; + char *path; /* Mount point name */ +diff --git a/include/replicated.h b/include/replicated.h +index 519689d..6eb56e0 100644 +--- a/include/replicated.h ++++ b/include/replicated.h +@@ -56,6 +56,7 @@ struct host { + size_t addr_len; + char *path; + unsigned int version; ++ unsigned int options; + unsigned int proximity; + unsigned int weight; + unsigned long cost; +@@ -65,7 +66,7 @@ struct host { + void seed_random(void); + void free_host_list(struct host **); + int parse_location(unsigned, struct host **, const char *, unsigned int); +-int prune_host_list(unsigned, struct host **, unsigned int, const char *, unsigned int); ++int prune_host_list(unsigned, struct host **, unsigned int, const char *); + void dump_host_list(struct host *); + + #endif +diff --git a/lib/master_parse.y b/lib/master_parse.y +index b82129f..845cbed 100644 +--- a/lib/master_parse.y ++++ b/lib/master_parse.y +@@ -58,8 +58,9 @@ static char *format; + static long timeout; + static long negative_timeout; + static unsigned ghost; +-extern unsigned global_random_selection; ++extern unsigned global_selection_options; + static unsigned random_selection; ++static unsigned use_weight; + static char **tmp_argv; + static int tmp_argc; + static char **local_argv; +@@ -98,7 +99,7 @@ static int master_fprintf(FILE *, char *, ...); + %token COMMENT + %token MAP + %token OPT_TIMEOUT OPT_NTIMEOUT OPT_NOGHOST OPT_GHOST OPT_VERBOSE +-%token OPT_DEBUG OPT_RANDOM ++%token OPT_DEBUG OPT_RANDOM OPT_USE_WEIGHT + %token COLON COMMA NL DDASH + %type map + %type options +@@ -181,6 +182,7 @@ line: + | PATH OPTION { master_notify($2); YYABORT; } + | PATH NILL { master_notify($2); YYABORT; } + | PATH OPT_RANDOM { master_notify($1); YYABORT; } ++ | PATH OPT_USE_WEIGHT { master_notify($1); YYABORT; } + | PATH OPT_DEBUG { master_notify($1); YYABORT; } + | PATH OPT_TIMEOUT { master_notify($1); YYABORT; } + | PATH OPT_GHOST { master_notify($1); YYABORT; } +@@ -558,6 +560,7 @@ daemon_option: OPT_TIMEOUT NUMBER { timeout = $2; } + | OPT_VERBOSE { verbose = 1; } + | OPT_DEBUG { debug = 1; } + | OPT_RANDOM { random_selection = 1; } ++ | OPT_USE_WEIGHT { use_weight = 1; } + ; + + mount_option: OPTION +@@ -622,7 +625,8 @@ static void local_init_vars(void) + timeout = -1; + negative_timeout = 0; + ghost = defaults_get_browse_mode(); +- random_selection = global_random_selection; ++ random_selection = global_selection_options & MOUNT_FLAG_RANDOM_SELECT; ++ use_weight = 0; + tmp_argv = NULL; + tmp_argc = 0; + local_argv = NULL; +@@ -808,6 +812,8 @@ int master_parse_entry(const char *buffer, unsigned int default_timeout, unsigne + } + if (random_selection) + entry->ap->flags |= MOUNT_FLAG_RANDOM_SELECT; ++ if (use_weight) ++ entry->ap->flags |= MOUNT_FLAG_USE_WEIGHT_ONLY; + if (negative_timeout) + entry->ap->negative_timeout = negative_timeout; + +diff --git a/lib/master_tok.l b/lib/master_tok.l +index d05d1fb..c7fbe37 100644 +--- a/lib/master_tok.l ++++ b/lib/master_tok.l +@@ -363,6 +363,7 @@ OPTNTOUT (-n{OPTWS}|-n{OPTWS}={OPTWS}|--negative-timeout{OPTWS}|--negative-timeo + -g|--ghost|-?browse { return(OPT_GHOST); } + -v|--verbose { return(OPT_VERBOSE); } + -d|--debug { return(OPT_DEBUG); } ++ -w|--use-weight-only { return(OPT_USE_WEIGHT); } + -r|--random-multimount-selection { return(OPT_RANDOM); } + + {OPTWS}","{OPTWS} { return(COMMA); } +diff --git a/man/auto.master.5.in b/man/auto.master.5.in +index 453ff98..380b706 100644 +--- a/man/auto.master.5.in ++++ b/man/auto.master.5.in +@@ -153,6 +153,12 @@ list of replicated servers. This option is applied to this mount + only, overriding the global setting that may be specified on the + command line. + .TP ++.I "\-w, \-\-use-weight-only" ++Use only specified weights for server selection where more than one ++server is specified in the map entry. If no server weights are given ++then each available server will be tried in the order listed, within ++proximity. ++.TP + .I "\-n, \-\-negative\-timeout " + Set the timeout for caching failed key lookups. This option can be + used to override the global default given either on the command line +diff --git a/man/autofs.5 b/man/autofs.5 +index c5614e1..2161116 100644 +--- a/man/autofs.5 ++++ b/man/autofs.5 +@@ -49,6 +49,13 @@ is used to treat errors when mounting file systems as fatal. This is important w + multiple file systems should be mounted (`multi-mounts'). If this option + is given, no file system is mounted at all if at least one file system + can't be mounted. ++.I -use-weight-only ++is used to make the weight the sole factor in selecting a server when multiple ++servers are present in a map entry. ++and ++.I -no-use-weight-only ++can be used to negate the option if it is present in the master map entry ++for the map but is not wanted for the given mount. + + .SS location + The location specifies from where the file system is to be mounted. In the +diff --git a/modules/mount_nfs.c b/modules/mount_nfs.c +index 9110eba..817b9c6 100644 +--- a/modules/mount_nfs.c ++++ b/modules/mount_nfs.c +@@ -63,7 +63,8 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int + struct host *this, *hosts = NULL; + unsigned int mount_default_proto, vers; + char *nfsoptions = NULL; +- unsigned int random_selection = ap->flags & MOUNT_FLAG_RANDOM_SELECT; ++ unsigned int flags = ap->flags & ++ (MOUNT_FLAG_RANDOM_SELECT | MOUNT_FLAG_USE_WEIGHT_ONLY); + int len, status, err, existed = 1; + int nosymlink = 0; + int ro = 0; /* Set if mount bind should be read-only */ +@@ -112,9 +113,13 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int + while (*comma == ' ' || *comma == '\t') + end--; + +- if (strncmp("nosymlink", cp, end - cp + 1) == 0) ++ if (strncmp("nosymlink", cp, end - cp + 1) == 0) { + nosymlink = 1; +- else { ++ } else if (strncmp("no-use-weight-only", cp, end - cp + 1) == 0) { ++ flags &= ~MOUNT_FLAG_USE_WEIGHT_ONLY; ++ } else if (strncmp("use-weight-only", cp, end - cp + 1) == 0) { ++ flags |= MOUNT_FLAG_USE_WEIGHT_ONLY; ++ } else { + /* Check for options that also make sense + with bind mounts */ + if (strncmp("ro", cp, end - cp + 1) == 0) +@@ -137,11 +142,11 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int + else if (mount_default_proto == 4) + vers = vers | NFS4_VERS_MASK; + +- if (!parse_location(ap->logopt, &hosts, what, random_selection)) { ++ if (!parse_location(ap->logopt, &hosts, what, flags)) { + info(ap->logopt, MODPREFIX "no hosts available"); + return 1; + } +- prune_host_list(ap->logopt, &hosts, vers, nfsoptions, random_selection); ++ prune_host_list(ap->logopt, &hosts, vers, nfsoptions); + + if (!hosts) { + info(ap->logopt, MODPREFIX "no hosts available"); +diff --git a/modules/parse_sun.c b/modules/parse_sun.c +index 1f91ad1..4bddcc9 100644 +--- a/modules/parse_sun.c ++++ b/modules/parse_sun.c +@@ -529,6 +529,7 @@ static int sun_mount(struct autofs_point *ap, const char *root, + { + char *fstype = "nfs"; /* Default filesystem type */ + int nonstrict = 1; ++ int use_weight_only = ap->flags & MOUNT_FLAG_USE_WEIGHT_ONLY; + int rv, cur_state; + char *mountpoint; + char *what; +@@ -575,6 +576,10 @@ static int sun_mount(struct autofs_point *ap, const char *root, + memcpy(np, cp, comma - cp + 1); + np += comma - cp + 1; + } ++ } else if (strncmp("no-use-weight-only", cp, 18) == 0) { ++ use_weight_only = -1; ++ } else if (strncmp("use-weight-only", cp, 15) == 0) { ++ use_weight_only = MOUNT_FLAG_USE_WEIGHT_ONLY; + } else if (strncmp("bg", cp, 2) == 0 || + strncmp("nofg", cp, 4) == 0) { + continue; +@@ -593,11 +598,10 @@ static int sun_mount(struct autofs_point *ap, const char *root, + options = noptions; + } + +- + if (!strcmp(fstype, "autofs") && ctxt->macros) { + char *noptions = NULL; + +- if (!options) { ++ if (!options || *options == '\0') { + noptions = alloca(strlen(ctxt->macros) + 1); + *noptions = '\0'; + } else { +@@ -610,7 +614,7 @@ static int sun_mount(struct autofs_point *ap, const char *root, + } + } + +- if (noptions) { ++ if (noptions && *noptions != '\0') { + strcat(noptions, ctxt->macros); + options = noptions; + } else { +@@ -624,7 +628,7 @@ static int sun_mount(struct autofs_point *ap, const char *root, + + type = ap->entry->maps->type; + if (type && !strcmp(type, "hosts")) { +- if (options) { ++ if (options && *options != '\0') { + int len = strlen(options); + int suid = strstr(options, "suid") ? 0 : 7; + int dev = strstr(options, "dev") ? 0 : 6; +@@ -669,6 +673,30 @@ static int sun_mount(struct autofs_point *ap, const char *root, + memcpy(what, loc, loclen); + what[loclen] = '\0'; + ++ /* Add back "[no-]use-weight-only" for NFS mounts only */ ++ if (use_weight_only) { ++ char *tmp; ++ int len; ++ ++ if (options && *options != '\0') { ++ len = strlen(options) + 19; ++ tmp = alloca(len); ++ strcpy(tmp, options); ++ strcat(tmp, ","); ++ if (use_weight_only == MOUNT_FLAG_USE_WEIGHT_ONLY) ++ strcat(tmp, "use-weight-only"); ++ else ++ strcat(tmp, "no-use-weight-only"); ++ } else { ++ tmp = alloca(19); ++ if (use_weight_only == MOUNT_FLAG_USE_WEIGHT_ONLY) ++ strcpy(tmp, "use-weight-only"); ++ else ++ strcpy(tmp, "no-use-weight-only"); ++ } ++ options = tmp; ++ } ++ + debug(ap->logopt, MODPREFIX + "mounting root %s, mountpoint %s, " + "what %s, fstype %s, options %s", +diff --git a/modules/replicated.c b/modules/replicated.c +index 9eefb19..975c254 100644 +--- a/modules/replicated.c ++++ b/modules/replicated.c +@@ -351,7 +351,8 @@ static unsigned int get_proximity(struct sockaddr *host_addr) + + static struct host *new_host(const char *name, + struct sockaddr *addr, size_t addr_len, +- unsigned int proximity, unsigned int weight) ++ unsigned int proximity, unsigned int weight, ++ unsigned int options) + { + struct host *new; + struct sockaddr *tmp2; +@@ -385,6 +386,7 @@ static struct host *new_host(const char *name, + new->addr = tmp2; + new->proximity = proximity; + new->weight = weight; ++ new->options = options; + + return new; + } +@@ -519,9 +521,11 @@ static unsigned short get_port_option(const char *options) + static unsigned int get_nfs_info(unsigned logopt, struct host *host, + struct conn_info *pm_info, struct conn_info *rpc_info, + const char *proto, unsigned int version, +- const char *options, unsigned int random_selection) ++ const char *options) + { + char *have_port_opt = options ? strstr(options, "port=") : NULL; ++ unsigned int random_selection = host->options & MOUNT_FLAG_RANDOM_SELECT; ++ unsigned int use_weight_only = host->options & MOUNT_FLAG_USE_WEIGHT_ONLY; + struct pmap parms; + struct timeval start, end; + struct timezone tz; +@@ -675,7 +679,10 @@ done_ver: + * Average response time to 7 significant places as + * integral type. + */ +- host->cost = (unsigned long) ((taken * 1000000) / count); ++ if (use_weight_only) ++ host->cost = 1; ++ else ++ host->cost = (unsigned long) ((taken * 1000000) / count); + + /* Allow for user bias */ + if (host->weight) +@@ -689,8 +696,7 @@ done_ver: + } + + static int get_vers_and_cost(unsigned logopt, struct host *host, +- unsigned int version, const char *options, +- unsigned int random_selection) ++ unsigned int version, const char *options) + { + struct conn_info pm_info, rpc_info; + time_t timeout = RPC_TIMEOUT; +@@ -717,8 +723,7 @@ static int get_vers_and_cost(unsigned logopt, struct host *host, + + if (version & UDP_REQUESTED) { + supported = get_nfs_info(logopt, host, +- &pm_info, &rpc_info, "udp", vers, +- options, random_selection); ++ &pm_info, &rpc_info, "udp", vers, options); + if (supported) { + ret = 1; + host->version |= (supported << 8); +@@ -727,8 +732,7 @@ static int get_vers_and_cost(unsigned logopt, struct host *host, + + if (version & TCP_REQUESTED) { + supported = get_nfs_info(logopt, host, +- &pm_info, &rpc_info, "tcp", vers, +- options, random_selection); ++ &pm_info, &rpc_info, "tcp", vers, options); + if (supported) { + ret = 1; + host->version |= supported; +@@ -739,10 +743,11 @@ static int get_vers_and_cost(unsigned logopt, struct host *host, + } + + static int get_supported_ver_and_cost(unsigned logopt, struct host *host, +- unsigned int version, const char *options, +- unsigned int random_selection) ++ unsigned int version, const char *options) + { + char *have_port_opt = options ? strstr(options, "port=") : NULL; ++ unsigned int random_selection = host->options & MOUNT_FLAG_RANDOM_SELECT; ++ unsigned int use_weight_only = host->options & MOUNT_FLAG_USE_WEIGHT_ONLY; + struct conn_info pm_info, rpc_info; + struct pmap parms; + const char *proto; +@@ -855,7 +860,10 @@ done: + + if (status) { + /* Response time to 7 significant places as integral type. */ +- host->cost = (unsigned long) (taken * 1000000); ++ if (use_weight_only) ++ host->cost = 1; ++ else ++ host->cost = (unsigned long) (taken * 1000000); + + /* Allow for user bias */ + if (host->weight) +@@ -870,8 +878,7 @@ done: + } + + int prune_host_list(unsigned logopt, struct host **list, +- unsigned int vers, const char *options, +- unsigned int random_selection) ++ unsigned int vers, const char *options) + { + struct host *this, *last, *first; + struct host *new = NULL; +@@ -892,6 +899,7 @@ int prune_host_list(unsigned logopt, struct host **list, + this = first; + while (this && this->proximity == PROXIMITY_LOCAL) + this = this->next; ++ first = this; + + /* + * Check for either a list containing only proximity local hosts +@@ -903,8 +911,6 @@ int prune_host_list(unsigned logopt, struct host **list, + return 1; + + proximity = this->proximity; +- first = this; +- this = first; + while (this) { + struct host *next = this->next; + +@@ -912,8 +918,7 @@ int prune_host_list(unsigned logopt, struct host **list, + break; + + if (this->name) { +- status = get_vers_and_cost(logopt, this, vers, +- options, random_selection); ++ status = get_vers_and_cost(logopt, this, vers, options); + if (!status) { + if (this == first) { + first = next; +@@ -1022,8 +1027,7 @@ int prune_host_list(unsigned logopt, struct host **list, + add_host(&new, this); + } else { + status = get_supported_ver_and_cost(logopt, this, +- selected_version, options, +- random_selection); ++ selected_version, options); + if (status) { + this->version = selected_version; + remove_host(list, this); +@@ -1041,8 +1045,7 @@ int prune_host_list(unsigned logopt, struct host **list, + + static int add_new_host(struct host **list, + const char *host, unsigned int weight, +- struct addrinfo *host_addr, +- unsigned int random_selection) ++ struct addrinfo *host_addr, unsigned int options) + { + struct host *new; + unsigned int prx; +@@ -1054,10 +1057,21 @@ static int add_new_host(struct host **list, + * We can't use PROXIMITY_LOCAL or we won't perform an RPC ping + * to remove hosts that may be down. + */ +- if (random_selection) ++ if (options & MOUNT_FLAG_RANDOM_SELECT) + prx = PROXIMITY_SUBNET; +- else ++ else { + prx = get_proximity(host_addr->ai_addr); ++ /* ++ * If we want the weight to be the determining factor ++ * when selecting a host then all hosts must have the ++ * same proximity. However, if this is the local machine ++ * it should always be used since it is certainly available. ++ */ ++ if (prx != PROXIMITY_LOCAL && ++ (options & MOUNT_FLAG_USE_WEIGHT_ONLY)) ++ prx = PROXIMITY_SUBNET; ++ } ++ + /* + * If we tried to add an IPv6 address and we don't have IPv6 + * support return success in the hope of getting an IPv4 +@@ -1069,7 +1083,7 @@ static int add_new_host(struct host **list, + return 0; + + addr_len = sizeof(struct sockaddr); +- new = new_host(host, host_addr->ai_addr, addr_len, prx, weight); ++ new = new_host(host, host_addr->ai_addr, addr_len, prx, weight, options); + if (!new) + return 0; + +@@ -1082,7 +1096,7 @@ static int add_new_host(struct host **list, + } + + static int add_host_addrs(struct host **list, const char *host, +- unsigned int weight, unsigned int random_selection) ++ unsigned int weight, unsigned int options) + { + struct addrinfo hints, *ni, *this; + int ret; +@@ -1098,7 +1112,7 @@ static int add_host_addrs(struct host **list, const char *host, + + this = ni; + while (this) { +- ret = add_new_host(list, host, weight, this, random_selection); ++ ret = add_new_host(list, host, weight, this, options); + if (!ret) + break; + this = this->ai_next; +@@ -1121,7 +1135,7 @@ try_name: + + this = ni; + while (this) { +- ret = add_new_host(list, host, weight, this, random_selection); ++ ret = add_new_host(list, host, weight, this, options); + if (!ret) + break; + this = this->ai_next; +@@ -1209,7 +1223,7 @@ static char *seek_delim(const char *s) + } + + int parse_location(unsigned logopt, struct host **hosts, +- const char *list, unsigned int random_selection) ++ const char *list, unsigned int options) + { + char *str, *p, *delim; + unsigned int empty = 1; +@@ -1264,7 +1278,7 @@ int parse_location(unsigned logopt, struct host **hosts, + } + + if (p != delim) { +- if (!add_host_addrs(hosts, p, weight, random_selection)) { ++ if (!add_host_addrs(hosts, p, weight, options)) { + if (empty) { + p = next; + continue; +@@ -1286,7 +1300,7 @@ int parse_location(unsigned logopt, struct host **hosts, + *delim = '\0'; + next = delim + 1; + +- if (!add_host_addrs(hosts, p, weight, random_selection)) { ++ if (!add_host_addrs(hosts, p, weight, options)) { + p = next; + continue; + } --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-special-case-cifs-escapes.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-special-case-cifs-escapes.dpatch @@ -0,0 +1,105 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-special-case-cifs-escapes.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - special case cifs escapes + +From: Ian Kent + +Since "\" is a valid seperator for cifs shares it can't be used to escape +characters in the share name passed to mount.cifs. So we have no choice +but to require that the seperator we use is "/" and de-quote the string +before sending it to mount.cifs. +--- + + CHANGELOG | 1 + + modules/mount_generic.c | 36 ++++++++++++++++++++++++++++++------ + 2 files changed, 31 insertions(+), 6 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index fadb229..671c979 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -3,6 +3,7 @@ + - fix included map read fail handling. + - refactor ldap sasl bind handling. + - add mount wait timeout parameter. ++- special case cifs escapes. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/modules/mount_generic.c b/modules/mount_generic.c +index 8edad8b..da85d1a 100644 +--- a/modules/mount_generic.c ++++ b/modules/mount_generic.c +@@ -39,6 +39,7 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int + { + char fullpath[PATH_MAX]; + char buf[MAX_ERR_BUF]; ++ char *loc; + int err; + int len, status, existed = 1; + +@@ -74,22 +75,44 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int + if (!status) + existed = 0; + ++ /* ++ * Special case quoting for cifs share names. ++ * ++ * Since "\" is a valid seperator for cifs shares it can't be ++ * used to escape characters in the share name passed to ++ * mount.cifs. So we have no choice but to require that the ++ * seperator we use is "/" and de-quote the string before ++ * sending it to mount.cifs. ++ */ ++ loc = NULL; ++ if (strcmp(fstype, "cifs")) ++ loc = strdup(what); ++ else ++ loc = dequote(what, strlen(what), ap->logopt); ++ if (!loc) { ++ error(ap->logopt, ++ MODPREFIX "failed to alloc buffer for mount location"); ++ return 1; ++ } ++ + if (options && options[0]) { + debug(ap->logopt, + MODPREFIX "calling mount -t %s " SLOPPY "-o %s %s %s", +- fstype, options, what, fullpath); ++ fstype, options, loc, fullpath); + + err = spawn_mount(ap->logopt, "-t", fstype, +- SLOPPYOPT "-o", options, what, fullpath, NULL); ++ SLOPPYOPT "-o", options, loc, fullpath, NULL); + } else { + debug(ap->logopt, MODPREFIX "calling mount -t %s %s %s", +- fstype, what, fullpath); +- err = spawn_mount(ap->logopt, "-t", fstype, what, fullpath, NULL); ++ fstype, loc, fullpath); ++ err = spawn_mount(ap->logopt, "-t", fstype, loc, fullpath, NULL); + } + + if (err) { + info(ap->logopt, MODPREFIX "failed to mount %s (type %s) on %s", +- what, fstype, fullpath); ++ loc, fstype, fullpath); ++ ++ free(loc); + + if (ap->type != LKP_INDIRECT) + return 1; +@@ -100,7 +123,8 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int + return 1; + } else { + info(ap->logopt, MODPREFIX "mounted %s type %s on %s", +- what, fstype, fullpath); ++ loc, fstype, fullpath); ++ free(loc); + return 0; + } + } --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-fix-random-selection-option.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-fix-random-selection-option.dpatch @@ -0,0 +1,45 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-fix-random-selection-option.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - fix random selection option + +From: Ian Kent + +When parsing the master map we fail to check if the random selection +option has been seen and set the random selection option unconditionally. +--- + + CHANGELOG | 1 + + lib/master_parse.y | 3 ++- + 2 files changed, 3 insertions(+), 1 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index f38fc3f..c976f79 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -19,6 +19,7 @@ + - fix memory leak on reload. + - update kernel patches for 2.6.18 and 2.6.19. + - dont connect at ldap lookup module init. ++- fix random selection option. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/lib/master_parse.y b/lib/master_parse.y +index 454a2ed..8adb393 100644 +--- a/lib/master_parse.y ++++ b/lib/master_parse.y +@@ -811,7 +811,8 @@ int master_parse_entry(const char *buffer, unsigned int default_timeout, unsigne + ops->timeout(ap->logopt, ap->ioctlfd, &tout); + } + } +- entry->ap->flags |= MOUNT_FLAG_RANDOM_SELECT; ++ if (random_selection) ++ entry->ap->flags |= MOUNT_FLAG_RANDOM_SELECT; + if (negative_timeout) + entry->ap->negative_timeout = negative_timeout; + --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-fix-direct-map-not-updating-on-reread.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-fix-direct-map-not-updating-on-reread.dpatch @@ -0,0 +1,50 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-fix-direct-map-not-updating-on-reread.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - fix direct map not updating on reread + +From: Ian Kent + +If the map type is explicitly specified for a map the map isn't +properly updated when a re-read is requested. This is because +the map stale flag is incorrectly cleared after after the lookup +module reads the map instead of at the completion of the update +procedure. The map stale flag should only be cleared if the map +read fails for some reason, otherwise it is updated when the +refresh is completed. +--- + + CHANGELOG | 1 + + daemon/lookup.c | 3 ++- + 2 files changed, 3 insertions(+), 1 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index e05038b..46eb3ce 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -51,6 +51,7 @@ + - fix init script restart option. + - fix init script status privilege error. + - always read file maps mount lookup map read fix. ++- fix direct map not updating on reread. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/daemon/lookup.c b/daemon/lookup.c +index a4bd07f..a9a1f4d 100644 +--- a/daemon/lookup.c ++++ b/daemon/lookup.c +@@ -295,7 +295,8 @@ static int do_read_map(struct autofs_point *ap, struct map_source *map, time_t a + + status = lookup->lookup_read_map(ap, age, lookup->context); + +- map->stale = 0; ++ if (status != NSS_STATUS_SUCCESS) ++ map->stale = 0; + + /* + * For maps that don't support enumeration return success --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-add-external-bind-method.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-add-external-bind-method.dpatch @@ -0,0 +1,425 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-add-external-bind-method.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - add external bind method + +From: Ian Kent + +Add sasl external bind handler. +--- + + CHANGELOG | 1 + include/lookup_ldap.h | 7 ++ + man/autofs_ldap_auth.conf.5.in | 24 +++++++- + modules/Makefile | 5 +- + modules/cyrus-sasl-extern.c | 117 ++++++++++++++++++++++++++++++++++++++++ + modules/cyrus-sasl.c | 20 +++++++ + modules/lookup_ldap.c | 78 ++++++++++++++++++++++----- + 7 files changed, 234 insertions(+), 18 deletions(-) + create mode 100644 modules/cyrus-sasl-extern.c + + +diff --git a/CHANGELOG b/CHANGELOG +index 46eb3ce..b107515 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -52,6 +52,7 @@ + - fix init script status privilege error. + - always read file maps mount lookup map read fix. + - fix direct map not updating on reread. ++- add external bind method. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/include/lookup_ldap.h b/include/lookup_ldap.h +index 1e1c7a4..4067ccc 100644 +--- a/include/lookup_ldap.h ++++ b/include/lookup_ldap.h +@@ -10,6 +10,7 @@ + #include + #endif + ++#include "list.h" + #include "dclist.h" + + struct ldap_schema { +@@ -76,9 +77,13 @@ struct lookup_context { + int kinit_done; + int kinit_successful; + #ifdef WITH_SASL ++ /* Kerberos */ + krb5_context krb5ctxt; + krb5_ccache krb5_ccache; + sasl_conn_t *sasl_conn; ++ /* SASL external */ ++ char *extern_cert; ++ char *extern_key; + #endif + /* keytab file name needs to be added */ + +@@ -111,6 +116,8 @@ int autofs_sasl_bind(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt); + void autofs_sasl_unbind(struct lookup_context *ctxt); + void autofs_sasl_dispose(struct lookup_context *ctxt); + void autofs_sasl_done(void); ++/* cyrus-sasl-extern */ ++int do_sasl_extern(LDAP *ldap, struct lookup_context *ctxt); + #endif + + #endif +diff --git a/man/autofs_ldap_auth.conf.5.in b/man/autofs_ldap_auth.conf.5.in +index ecec20d..2260952 100644 +--- a/man/autofs_ldap_auth.conf.5.in ++++ b/man/autofs_ldap_auth.conf.5.in +@@ -60,12 +60,30 @@ authentication mechanism. If no suitable mechanism can be found, connections + to the ldap server are made without authentication. Finally, if it is set to + simple, then simple authentication will be used instead of SASL. + .TP +-\fBauthtype="GSSAPI"|"LOGIN"|"PLAIN"|"ANONYMOUS"|"DIGEST-MD5"\fP ++\fBauthtype="GSSAPI"|"LOGIN"|"PLAIN"|"ANONYMOUS"|"DIGEST-MD5|EXTERNAL"\fP + This attribute can be used to specify a preferred authentication mechanism. +- In normal operations, the automounter will attempt to authenticate to the ++In normal operations, the automounter will attempt to authenticate to the + ldap server using the list of supportedSASLmechanisms obtained from the + directory server. Explicitly setting the authtype will bypass this selection +-and only try the mechanism specified. ++and only try the mechanism specified. The EXTERNAL mechanism may be used to ++authenticate using a client certificate and requires that authrequired ++set to "yes" if using SSL or usetls, tlsrequired and authrequired all set to ++"yes" if using TLS, in addition to authtype being set to EXTERNAL. ++.sp ++If using authtype EXTERNAL two additional configuration entries are ++required: ++.sp ++\fBexternal_cert=""\fP ++.sp ++This specifies the path of the file containing the client certificate. ++.sp ++\fBexternal_key=""\fP ++.sp ++This specifies the path of the file containing the client certificate key. ++.sp ++These two configuration entries are mandatory when using the EXTERNAL method ++as the HOME environment variable cannot be assumed to be set or, if it is, ++to be set to the location we expect. + .TP + \fBuser=""\fP + This attribute holds the authentication identity used by authentication +diff --git a/modules/Makefile b/modules/Makefile +index 164d412..9ad3915 100644 +--- a/modules/Makefile ++++ b/modules/Makefile +@@ -41,7 +41,7 @@ ifeq ($(LDAP), 1) + SRCS += lookup_ldap.c + MODS += lookup_ldap.so + ifeq ($(SASL), 1) +- SASL_OBJ = cyrus-sasl.o ++ SASL_OBJ = cyrus-sasl.o cyrus-sasl-extern.o + LDAP_FLAGS += $(SASL_FLAGS) $(XML_FLAGS) $(KRB5_FLAGS) -DLDAP_THREAD_SAFE + LIBLDAP += $(LIBSASL) $(XML_LIBS) $(KRB5_LIBS) + endif +@@ -92,6 +92,9 @@ lookup_hesiod.so: lookup_hesiod.c + cyrus-sasl.o: cyrus-sasl.c + $(CC) $(CFLAGS) $(LDAP_FLAGS) -c $< + ++cyrus-sasl-extern.o: cyrus-sasl-extern.c ++ $(CC) $(CFLAGS) $(LDAP_FLAGS) -c $< ++ + lookup_ldap.so: lookup_ldap.c dclist.o $(SASL_OBJ) + $(CC) $(SOLDFLAGS) $(CFLAGS) $(LDAP_FLAGS) -o lookup_ldap.so \ + lookup_ldap.c dclist.o $(SASL_OBJ) \ +diff --git a/modules/cyrus-sasl-extern.c b/modules/cyrus-sasl-extern.c +new file mode 100644 +index 0000000..5bb3028 +--- /dev/null ++++ b/modules/cyrus-sasl-extern.c +@@ -0,0 +1,117 @@ ++/* ++ * cyrus-sasl-extern.c - Module for Cyrus sasl external authentication. ++ * ++ * Copyright 2010 Ian Kent ++ * Copyright 2010 Red Hat, Inc. ++ * 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. ++ * ++ * 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. ++ */ ++ ++#include "config.h" ++ ++#ifdef WITH_SASL ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "lookup_ldap.h" ++ ++struct values { ++ char *mech; ++ char *realm; ++ char *authcid; ++ char *authzid; ++ char *password; ++ char **resps; ++ int nresps; ++}; ++ ++static int interaction(unsigned flags, sasl_interact_t *interact, void *values) ++{ ++ const char *val = interact->defresult; ++ struct values *vals = values; ++ ++ switch(interact->id) { ++ case SASL_CB_GETREALM: ++ if (values) ++ val = vals->realm; ++ break; ++ ++ case SASL_CB_AUTHNAME: ++ if (values) ++ val = vals->authcid; ++ break; ++ ++ case SASL_CB_PASS: ++ if (values) ++ val = vals->password; ++ break; ++ ++ case SASL_CB_USER: ++ if (values) ++ val = vals->authzid; ++ break; ++ ++ case SASL_CB_NOECHOPROMPT: ++ case SASL_CB_ECHOPROMPT: ++ break; ++ } ++ ++ if (val && !*val) ++ val = NULL; ++ ++ if (val || interact->id == SASL_CB_USER) { ++ interact->result = (val && *val) ? val : ""; ++ interact->len = strlen(interact->result); ++ } ++ ++ return LDAP_SUCCESS; ++} ++ ++int sasl_extern_interact(LDAP *ldap, unsigned flags, void *values, void *list) ++{ ++ sasl_interact_t *interact = list; ++ ++ if (!ldap) ++ return LDAP_PARAM_ERROR; ++ ++ while (interact->id != SASL_CB_LIST_END) { ++ int rc = interaction(flags, interact, values); ++ if (rc) ++ return rc; ++ interact++; ++ } ++ ++ return LDAP_SUCCESS; ++} ++ ++int do_sasl_extern(LDAP *ldap, struct lookup_context *ctxt) ++{ ++ int flags = LDAP_SASL_QUIET; ++ char *mech = ctxt->sasl_mech; ++ struct values values; ++ int rc; ++ ++ memset(&values, 0, sizeof(struct values)); ++ values.mech = mech; ++ ++ rc = ldap_sasl_interactive_bind_s(ldap, NULL, mech, NULL, NULL, ++ flags, sasl_extern_interact, &values); ++ return rc; ++} ++#endif +diff --git a/modules/cyrus-sasl.c b/modules/cyrus-sasl.c +index d117f0a..967edc3 100644 +--- a/modules/cyrus-sasl.c ++++ b/modules/cyrus-sasl.c +@@ -875,6 +875,26 @@ autofs_sasl_bind(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt) + if (ctxt->sasl_conn) + return 0; + ++ if (ctxt->sasl_mech && !strncmp(ctxt->sasl_mech, "EXTERNAL", 8)) { ++ int result; ++ ++ debug(logopt, ++ "Attempting sasl bind with mechanism %s", ++ ctxt->sasl_mech); ++ ++ result = do_sasl_extern(ldap, ctxt); ++ if (result) ++ debug(logopt, ++ "Failed to authenticate with mech %s", ++ ctxt->sasl_mech); ++ else ++ debug(logopt, ++ "sasl bind with mechanism %s succeeded", ++ ctxt->sasl_mech); ++ ++ return result; ++ } ++ + sasl_auth_id = ctxt->user; + sasl_auth_secret = ctxt->secret; + +diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c +index 3d47048..1432056 100644 +--- a/modules/lookup_ldap.c ++++ b/modules/lookup_ldap.c +@@ -41,6 +41,9 @@ + + int lookup_version = AUTOFS_LOOKUP_VERSION; /* Required by protocol */ + ++#define ENV_LDAPTLS_CERT "LDAPTLS_CERT" ++#define ENV_LDAPTLS_KEY "LDAPTLS_KEY" ++ + static struct ldap_schema common_schema[] = { + {"nisMap", "nisMapName", "nisObject", "cn", "nisMapEntry"}, + {"automountMap", "ou", "automount", "cn", "automountInformation"}, +@@ -61,6 +64,16 @@ struct ldap_search_params { + + static int decode_percent_hack(const char *, char **); + ++static int set_env(unsigned logopt, const char *name, const char *val) ++{ ++ int ret = setenv(name, val, 1); ++ if (ret == -1) { ++ error(logopt, "failed to set config value for %s", name); ++ return 0; ++ } ++ return 1; ++} ++ + #ifndef HAVE_LDAP_CREATE_PAGE_CONTROL + int ldap_create_page_control(LDAP *ldap, ber_int_t pagesize, + struct berval *cookie, char isCritical, +@@ -578,13 +591,17 @@ static LDAP *do_connect(unsigned logopt, const char *uri, struct lookup_context + { + LDAP *ldap; + +- ldap = init_ldap_connection(logopt, uri, ctxt); +- if (!ldap) +- return NULL; ++ if (ctxt->extern_cert && ctxt->extern_key) { ++ set_env(logopt, ENV_LDAPTLS_CERT, ctxt->extern_cert); ++ set_env(logopt, ENV_LDAPTLS_KEY, ctxt->extern_key); ++ } + +- if (!do_bind(logopt, ldap, uri, ctxt)) { +- unbind_ldap_connection(logopt, ldap, ctxt); +- return NULL; ++ ldap = init_ldap_connection(logopt, uri, ctxt); ++ if (ldap) { ++ if (!do_bind(logopt, ldap, uri, ctxt)) { ++ unbind_ldap_connection(logopt, ldap, ctxt); ++ ldap = NULL; ++ } + } + + return ldap; +@@ -839,6 +856,7 @@ int parse_ldap_config(unsigned logopt, struct lookup_context *ctxt) + xmlNodePtr root = NULL; + char *authrequired, *auth_conf, *authtype; + char *user = NULL, *secret = NULL; ++ char *extern_cert = NULL, *extern_key = NULL; + char *client_princ = NULL, *client_cc = NULL; + char *usetls, *tlsrequired; + +@@ -1023,6 +1041,26 @@ int parse_ldap_config(unsigned logopt, struct lookup_context *ctxt) + ret = -1; + goto out; + } ++ } else if (auth_required == LDAP_AUTH_REQUIRED && ++ (authtype && !strncmp(authtype, "EXTERNAL", 8))) { ++ ret = get_property(logopt, root, "external_cert", &extern_cert); ++ ret |= get_property(logopt, root, "external_key", &extern_key); ++ /* ++ * For EXTERNAL auth to function we need a client certificate ++ * and and certificate key. The ca certificate used to verify ++ * the server certificate must also be set correctly in the ++ * global configuration as the connection must be encrypted ++ * and the server and client certificates must have been ++ * verified for the EXTERNAL method to be offerred by the ++ * server. If the cert and key have not been set in the autofs ++ * configuration they must be set in the ldap rc file. ++ */ ++ if (ret != 0 || !extern_cert || !extern_key) { ++ if (extern_cert) ++ free(extern_cert); ++ if (extern_key) ++ free(extern_key); ++ } + } + + /* +@@ -1043,6 +1081,8 @@ int parse_ldap_config(unsigned logopt, struct lookup_context *ctxt) + ctxt->secret = secret; + ctxt->client_princ = client_princ; + ctxt->client_cc = client_cc; ++ ctxt->extern_cert = extern_cert; ++ ctxt->extern_key = extern_key; + + debug(logopt, MODPREFIX + "ldap authentication configured with the following options:"); +@@ -1052,14 +1092,20 @@ int parse_ldap_config(unsigned logopt, struct lookup_context *ctxt) + "auth_required: %u, " + "sasl_mech: %s", + use_tls, tls_required, auth_required, authtype); +- debug(logopt, MODPREFIX +- "user: %s, " +- "secret: %s, " +- "client principal: %s " +- "credential cache: %s", +- user, secret ? "specified" : "unspecified", +- client_princ, client_cc); +- ++ if (authtype && !strncmp(authtype, "EXTERNAL", 8)) { ++ debug(logopt, MODPREFIX "external cert: %s", ++ extern_cert ? extern_cert : "ldap default"); ++ debug(logopt, MODPREFIX "external key: %s ", ++ extern_key ? extern_key : "ldap default"); ++ } else { ++ debug(logopt, MODPREFIX ++ "user: %s, " ++ "secret: %s, " ++ "client principal: %s " ++ "credential cache: %s", ++ user, secret ? "specified" : "unspecified", ++ client_princ, client_cc); ++ } + out: + xmlFreeDoc(doc); + +@@ -1326,6 +1372,10 @@ static void free_context(struct lookup_context *ctxt) + defaults_free_searchdns(ctxt->sdns); + if (ctxt->dclist) + free_dclist(ctxt->dclist); ++ if (ctxt->extern_cert) ++ free(ctxt->extern_cert); ++ if (ctxt->extern_key) ++ free(ctxt->extern_key); + free(ctxt); + + return; --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-fix-null-cache-race.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-fix-null-cache-race.dpatch @@ -0,0 +1,205 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-fix-null-cache-race.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - fix null cache race + +From: Ian Kent + +The null map entry cache scope is across the entire master map but +it is used by individual master map entries during master map re-read +and subsequest updates resulting form it. The current null cache locking +doesn't properly account for this. + +To resolve this, when we re-read the master, map we need to block +access to the null cache until the master map has been read and the +null cache updated. +--- + + CHANGELOG | 1 + + daemon/automount.c | 4 +++- + include/automount.h | 1 + + lib/cache.c | 33 ++++++++++++++++++++++++++------- + lib/master.c | 27 ++++++++++++++++++++------- + lib/master_parse.y | 5 ----- + 6 files changed, 51 insertions(+), 20 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index 5d673ea..f022893 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -38,6 +38,7 @@ + - fix wildcard map entry match. + - fix parse_sun() module init. + - dont check null cache on expire. ++- fix null cache race. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/daemon/automount.c b/daemon/automount.c +index 5a1f189..206734b 100644 +--- a/daemon/automount.c ++++ b/daemon/automount.c +@@ -1273,14 +1273,16 @@ static int do_hup_signal(struct master *master, time_t age) + if (status) + fatal(status); + ++ master_mutex_lock(); + if (master->reading) { + status = pthread_mutex_unlock(&mrc.mutex); + if (status) + fatal(status); ++ master_mutex_unlock(); + return 1; + } +- + master->reading = 1; ++ master_mutex_unlock(); + + status = pthread_create(&thid, &th_attr_detached, do_read_master, NULL); + if (status) { +diff --git a/include/automount.h b/include/automount.h +index ae517a7..9e1feb0 100644 +--- a/include/automount.h ++++ b/include/automount.h +@@ -194,6 +194,7 @@ void cache_multi_writelock(struct mapent *me); + void cache_multi_unlock(struct mapent *me); + int cache_delete_offset_list(struct mapent_cache *mc, const char *key); + void cache_release(struct map_source *map); ++void cache_clean_null_cache(struct mapent_cache *mc); + void cache_release_null_cache(struct master *master); + struct mapent *cache_enumerate(struct mapent_cache *mc, struct mapent *me); + char *cache_get_offset(const char *prefix, char *offset, int start, struct list_head *head, struct list_head **pos); +diff --git a/lib/cache.c b/lib/cache.c +index 440b3e8..a096150 100644 +--- a/lib/cache.c ++++ b/lib/cache.c +@@ -228,15 +228,38 @@ struct mapent_cache *cache_init(struct autofs_point *ap, struct map_source *map) + return mc; + } + ++void cache_clean_null_cache(struct mapent_cache *mc) ++{ ++ struct mapent *me, *next; ++ int i; ++ ++ for (i = 0; i < mc->size; i++) { ++ me = mc->hash[i]; ++ if (me == NULL) ++ continue; ++ next = me->next; ++ free(me->key); ++ if (me->mapent) ++ free(me->mapent); ++ free(me); ++ ++ while (next != NULL) { ++ me = next; ++ next = me->next; ++ free(me->key); ++ free(me); ++ } ++ } ++ ++ return; ++} ++ + struct mapent_cache *cache_init_null_cache(struct master *master) + { + struct mapent_cache *mc; + unsigned int i; + int status; + +- if (master->nc) +- cache_release_null_cache(master); +- + mc = malloc(sizeof(struct mapent_cache)); + if (!mc) + return NULL; +@@ -264,8 +287,6 @@ struct mapent_cache *cache_init_null_cache(struct master *master) + if (status) + fatal(status); + +- cache_writelock(mc); +- + for (i = 0; i < mc->size; i++) { + mc->hash[i] = NULL; + INIT_LIST_HEAD(&mc->ino_index[i]); +@@ -274,8 +295,6 @@ struct mapent_cache *cache_init_null_cache(struct master *master) + mc->ap = NULL; + mc->map = NULL; + +- cache_unlock(mc); +- + return mc; + } + +diff --git a/lib/master.c b/lib/master.c +index 196b6b9..61f671c 100644 +--- a/lib/master.c ++++ b/lib/master.c +@@ -811,15 +811,28 @@ int master_read_master(struct master *master, time_t age, int readall) + unsigned int logopt = master->logopt; + struct mapent_cache *nc; + +- nc = cache_init_null_cache(master); +- if (!nc) { +- error(logopt, +- "failed to init null map cache for %s", master->name); +- return 0; ++ /* ++ * We need to clear and re-populate the null map entry cache ++ * before alowing anyone else to use it. ++ */ ++ if (master->nc) { ++ cache_writelock(master->nc); ++ nc = master->nc; ++ cache_clean_null_cache(nc); ++ } else { ++ nc = cache_init_null_cache(master); ++ if (!nc) { ++ error(logopt, ++ "failed to init null map cache for %s", ++ master->name); ++ return 0; ++ } ++ cache_writelock(nc); ++ master->nc = nc; + } +- master->nc = nc; +- + master_init_scan(); ++ lookup_nss_read_master(master, age); ++ cache_unlock(nc); + + lookup_nss_read_master(master, age); + if (!master->read_fail) +diff --git a/lib/master_parse.y b/lib/master_parse.y +index 8adb393..8b86810 100644 +--- a/lib/master_parse.y ++++ b/lib/master_parse.y +@@ -741,21 +741,16 @@ int master_parse_entry(const char *buffer, unsigned int default_timeout, unsigne + + /* Add null map entries to the null map cache */ + if (type && !strcmp(type, "null")) { +- cache_writelock(nc); + cache_update(nc, NULL, path, NULL, lineno); +- cache_unlock(nc); + local_free_vars(); + return 1; + } + + /* Ignore all subsequent matching nulled entries */ +- cache_readlock(nc); + if (cache_lookup_distinct(nc, path)) { +- cache_unlock(nc); + local_free_vars(); + return 1; + } +- cache_unlock(nc); + + if (debug || verbose) { + logopt = (debug ? LOGOPT_DEBUG : 0); --- autofs5-5.0.5.orig/debian/patches/12disable_default_auto_master.dpatch +++ autofs5-5.0.5/debian/patches/12disable_default_auto_master.dpatch @@ -0,0 +1,26 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 12disable_default_auto_master.dpatch by +## +## DP: Disable upstream's default of activating /mnt and /net. +## DP: In previous versions this was done as a security measure +## DP: (because the hosts map was processed without nosuid and nodev). + +@DPATCH@ +--- autofs5-5.0.3.orig/samples/auto.master 2008-04-27 17:45:28.000000000 +0200 ++++ autofs5-5.0.3/samples/auto.master 2008-04-28 15:49:19.000000000 +0200 +@@ -4,13 +4,13 @@ + # key [ -mount-options-separated-by-comma ] location + # For details of the format look at autofs(5). + # +-/misc /etc/auto.misc ++#/misc /etc/auto.misc + # + # NOTE: mounts done from a hosts map will be mounted with the + # "nosuid" and "nodev" options unless the "suid" and "dev" + # options are explicitly given. + # +-/net -hosts ++#/net -hosts + # + # Include central master map if it can be found using + # nsswitch sources. --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-add-locality-as-valid-ldap-master-map-attribute.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-add-locality-as-valid-ldap-master-map-attribute.dpatch @@ -0,0 +1,45 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-add-locality-as-valid-ldap-master-map-attribute.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - add locality as valid ldap master map attribute + +From: Ian Kent + +The master map dn string parsing is quite strict so we will need to add +allowable attributes as required. One such attribute is "l", the locality. +--- + + CHANGELOG | 1 + + lib/master_tok.l | 3 ++- + 2 files changed, 3 insertions(+), 1 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index a11a969..6ca1827 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -26,6 +26,7 @@ + - add missing sasl mutex callbacks. + - fix get query dn failure. + - fix ampersand escape in auto.smb. ++- add locality as valid ldap master map attribute. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/lib/master_tok.l b/lib/master_tok.l +index be2ce10..2693c51 100644 +--- a/lib/master_tok.l ++++ b/lib/master_tok.l +@@ -110,7 +110,8 @@ AT_OU ([oO][[uU]) + AT_DC ([dD][[cC]) + AT_O ([oO]) + AT_C ([cC]) +-DNATTRSTR ({AT_CN}|{AT_NMN}|{AT_AMN}|{AT_OU}|{AT_DC}|{AT_O}|{AT_C}) ++AT_L ([lL]) ++DNATTRSTR ({AT_CN}|{AT_NMN}|{AT_AMN}|{AT_OU}|{AT_DC}|{AT_O}|{AT_C}|{AT_L}) + DNNAMESTR1 ([[:alnum:]_.\- ]+) + DNNAMESTR2 ([[:alnum:]_.\-]+) + --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-fix-ext4-fsck-at-mount.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-fix-ext4-fsck-at-mount.dpatch @@ -0,0 +1,214 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-fix-ext4-fsck-at-mount.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - fix ext4 fsck at mount + +From: Ian Kent + +Autofs performs a "preen" fsck at max mount count for ext2 and ext3, but not +ext4. +--- + + CHANGELOG | 1 + + Makefile.conf.in | 3 ++ + configure | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++ + configure.in | 1 + + include/config.h.in | 6 +++++ + modules/Makefile | 10 ++++++-- + modules/mount_ext2.c | 11 +++++---- + 7 files changed, 88 insertions(+), 7 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index 8b62370..e37dadb 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -8,6 +8,7 @@ + - more code analysis corrections (and fix a typo in an init script). + - fix backwards #ifndef INET6. + - fix stale initialization for file map instance. ++- add "preen" fsck for ext4 mounts. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/Makefile.conf.in b/Makefile.conf.in +index f0287c3..7670364 100644 +--- a/Makefile.conf.in ++++ b/Makefile.conf.in +@@ -44,6 +44,9 @@ EXT2FS = @HAVE_E2FSCK@ + # Support for calling e3fsck when mounting ext3 filesystems + EXT3FS = @HAVE_E3FSCK@ + ++# Support for calling e4fsck when mounting ext4 filesystems ++EXT4FS = @HAVE_E4FSCK@ ++ + LEX = @PATH_LEX@ + YACC = @PATH_YACC@ + RPCGEN = @PATH_RPCGEN@ +diff --git a/configure b/configure +index 159f25f..f5b7d07 100755 +--- a/configure ++++ b/configure +@@ -668,6 +668,8 @@ PATH_LEX + LEX + HAVE_MODPROBE + MODPROBE ++HAVE_E4FSCK ++E4FSCK + HAVE_E3FSCK + E3FSCK + HAVE_E2FSCK +@@ -3407,6 +3409,67 @@ else + HAVE_E3FSCK=0 + fi + ++for ac_prog in fsck.ext4 e4fsck ++do ++ # Extract the first word of "$ac_prog", so it can be a program name with args. ++set dummy $ac_prog; ac_word=$2 ++{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 ++$as_echo_n "checking for $ac_word... " >&6; } ++if test "${ac_cv_path_E4FSCK+set}" = set; then ++ $as_echo_n "(cached) " >&6 ++else ++ case $E4FSCK in ++ [\\/]* | ?:[\\/]*) ++ ac_cv_path_E4FSCK="$E4FSCK" # Let the user override the test with a path. ++ ;; ++ *) ++ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $searchpath ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ++ ac_cv_path_E4FSCK="$as_dir/$ac_word$ac_exec_ext" ++ $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 ++ break 2 ++ fi ++done ++done ++IFS=$as_save_IFS ++ ++ ;; ++esac ++fi ++E4FSCK=$ac_cv_path_E4FSCK ++if test -n "$E4FSCK"; then ++ { $as_echo "$as_me:$LINENO: result: $E4FSCK" >&5 ++$as_echo "$E4FSCK" >&6; } ++else ++ { $as_echo "$as_me:$LINENO: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++ ++ ++ test -n "$E4FSCK" && break ++done ++ ++if test -n "$E4FSCK"; then ++ ++cat >>confdefs.h <<\_ACEOF ++#define HAVE_E4FSCK 1 ++_ACEOF ++ ++ ++cat >>confdefs.h <<_ACEOF ++#define PATH_E4FSCK "$E4FSCK" ++_ACEOF ++ ++ HAVE_E4FSCK=1 ++else ++ HAVE_E4FSCK=0 ++fi ++ + for ac_prog in modprobe + do + # Extract the first word of "$ac_prog", so it can be a program name with args. +diff --git a/configure.in b/configure.in +index f649a58..78085bd 100644 +--- a/configure.in ++++ b/configure.in +@@ -131,6 +131,7 @@ AF_PATH_INCLUDE(MOUNT, mount, /bin/mount, $searchpath) + AF_PATH_INCLUDE(UMOUNT, umount, /bin/umount, $searchpath) + AF_PATH_INCLUDE(E2FSCK, fsck.ext2 e2fsck, , $searchpath) + AF_PATH_INCLUDE(E3FSCK, fsck.ext3 e3fsck, , $searchpath) ++AF_PATH_INCLUDE(E4FSCK, fsck.ext4 e4fsck, , $searchpath) + AF_PATH_INCLUDE(MODPROBE, modprobe, , $searchpath) + + AF_CHECK_PROG(LEX, flex lex, , $searchpath) +diff --git a/include/config.h.in b/include/config.h.in +index 39cfa4b..dece33f 100644 +--- a/include/config.h.in ++++ b/include/config.h.in +@@ -18,6 +18,9 @@ + /* define if you have E3FSCK */ + #undef HAVE_E3FSCK + ++/* define if you have E4FSCK */ ++#undef HAVE_E4FSCK ++ + /* Define to 1 if you have the header file. */ + #undef HAVE_INTTYPES_H + +@@ -93,6 +96,9 @@ + /* define if you have E3FSCK */ + #undef PATH_E3FSCK + ++/* define if you have E4FSCK */ ++#undef PATH_E4FSCK ++ + /* define if you have LEX */ + #undef PATH_LEX + +diff --git a/modules/Makefile b/modules/Makefile +index 13b3bd8..0bb9464 100644 +--- a/modules/Makefile ++++ b/modules/Makefile +@@ -69,10 +69,16 @@ ifeq ($(EXT2FS), 1) + ifeq ($(EXT3FS), 1) + ln -fs mount_ext2.so $(INSTALLROOT)$(autofslibdir)/mount_ext3.so + endif +-else +- ifeq ($(EXT3FS), 1) ++ ifeq ($(EXT4FS), 1) ++ ln -fs mount_ext2.so $(INSTALLROOT)$(autofslibdir)/mount_ext4.so ++ endif ++else ifeq ($(EXT3FS), 1) + mv $(INSTALLROOT)$(autofslibdir)/mount_ext2.so $(INSTALLROOT)$(autofslibdir)/mount_ext3.so ++ ifeq ($(EXT4FS), 1) ++ ln -fs mount_ext3.so $(INSTALLROOT)$(autofslibdir)/mount_ext4.so + endif ++else ifeq ($(EXT4FS), 1) ++ mv $(INSTALLROOT)$(autofslibdir)/mount_ext2.so $(INSTALLROOT)$(autofslibdir)/mount_ext4.so + endif + + # +diff --git a/modules/mount_ext2.c b/modules/mount_ext2.c +index 724a5fa..26d59d1 100644 +--- a/modules/mount_ext2.c ++++ b/modules/mount_ext2.c +@@ -83,13 +83,14 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int + ro = 1; + } + ++ fsck_prog = PATH_E2FSCK; + #ifdef HAVE_E3FSCK +- if (!strcmp(fstype,"ext3") || !strcmp(fstype,"auto")) ++ if (!strcmp(fstype,"ext3")) + fsck_prog = PATH_E3FSCK; +- else +- fsck_prog = PATH_E2FSCK; +-#else +- fsck_prog = PATH_E2FSCK; ++#endif ++#ifdef HAVE_E4FSCK ++ if (!strcmp(fstype,"ext4")) ++ fsck_prog = PATH_E4FSCK; + #endif + if (ro) { + debug(ap->logopt, --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-fix-disable-timeout.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-fix-disable-timeout.dpatch @@ -0,0 +1,45 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-fix-disable-timeout.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - fix disable timeout + +From: Ian Kent + +Using a timeout of zero should disable expires but instead causes +the alarm handler to fire constant expires. +--- + + CHANGELOG | 1 + + lib/alarm.c | 3 +++ + 2 files changed, 4 insertions(+), 0 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index c976f79..35ac649 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -20,6 +20,7 @@ + - update kernel patches for 2.6.18 and 2.6.19. + - dont connect at ldap lookup module init. + - fix random selection option. ++- fix disable timeout. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/lib/alarm.c b/lib/alarm.c +index f403d8f..d5cdc05 100755 +--- a/lib/alarm.c ++++ b/lib/alarm.c +@@ -67,6 +67,9 @@ int alarm_add(struct autofs_point *ap, time_t seconds) + unsigned int empty = 1; + int status; + ++ if (!seconds) ++ return 1; ++ + new = malloc(sizeof(struct alarm)); + if (!new) + return 0; --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-fix-restart.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-fix-restart.dpatch @@ -0,0 +1,44 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-fix-restart.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - fix restart + +From: Ian Kent + +The recent LSB improvement change has introduced a problem with +the restart action. +--- + + CHANGELOG | 1 + + redhat/autofs.init.in | 2 +- + 2 files changed, 2 insertions(+), 1 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index ce9c385..02a5e36 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -48,6 +48,7 @@ + - fix error handing in do_mount_indirect(). + - expire thread use pending mutex. + - remove ERR_remove_state() openssl call. ++- fix init script restart option. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/redhat/autofs.init.in b/redhat/autofs.init.in +index 1e926ce..e2a4b78 100644 +--- a/redhat/autofs.init.in ++++ b/redhat/autofs.init.in +@@ -126,7 +126,7 @@ function stop() { + } + + function restart() { +- status > /dev/null 2>&1 ++ status autofs > /dev/null 2>&1 + if [ $? -eq 0 ]; then + stop + fi --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-fix-prune-cache-valid-check.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-fix-prune-cache-valid-check.dpatch @@ -0,0 +1,52 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-fix-prune-cache-valid-check.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - fix prune cache valid check + +From: Ian Kent + +During a map reload, when pruning the cache we look for a valid map entry +in another map. In lookup_prune_one_cache() There is a missing check for +the entry being in the current map which causes the directory cleanup code +from doing its job. +--- + + CHANGELOG | 1 + + daemon/lookup.c | 8 ++++++++ + 2 files changed, 9 insertions(+), 0 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index 5c1005a..5ad2836 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -58,6 +58,7 @@ + - use weight only for server selection. + - fix isspace() wild card substition. + - auto adjust ldap page size. ++- fix prune cache valid check. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/daemon/lookup.c b/daemon/lookup.c +index a9a1f4d..36e60c9 100644 +--- a/daemon/lookup.c ++++ b/daemon/lookup.c +@@ -1060,6 +1060,14 @@ void lookup_prune_one_cache(struct autofs_point *ap, struct mapent_cache *mc, ti + * cache entry. + */ + valid = lookup_source_valid_mapent(ap, key, LKP_DISTINCT); ++ if (valid && valid->mc == mc) { ++ /* ++ * We've found a map entry that has been removed from ++ * the current cache so it isn't really valid. ++ */ ++ cache_unlock(valid->mc); ++ valid = NULL; ++ } + if (!valid && + is_mounted(_PATH_MOUNTED, path, MNTS_REAL)) { + debug(ap->logopt, --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-fix-included-map-read-fail-handling.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-fix-included-map-read-fail-handling.dpatch @@ -0,0 +1,50 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-fix-included-map-read-fail-handling.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - fix included map read fail handling + +From: Ian Kent + +If an included map read fails an error is returned and subsequent +master map entries are not read. We should report the failure but +we shouldn't stop reading the master map. +--- + + CHANGELOG | 4 ++++ + modules/lookup_file.c | 7 ------- + 2 files changed, 4 insertions(+), 7 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index e734cb3..674a48b 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -1,3 +1,7 @@ ++??/??/20?? autofs-5.0.6 ++----------------------- ++- fix included map read fail handling. ++ + 03/09/2009 autofs-5.0.5 + ----------------------- + - fix dumb libxml2 check +diff --git a/modules/lookup_file.c b/modules/lookup_file.c +index a4ca39d..e43ab2f 100644 +--- a/modules/lookup_file.c ++++ b/modules/lookup_file.c +@@ -438,13 +438,6 @@ int lookup_read_master(struct master *master, time_t age, void *context) + MODPREFIX + "failed to read included master map %s", + master->name); +- if (!master->recurse) { +- master->name = save_name; +- master->depth--; +- master->recurse = 0; +- fclose(f); +- return NSS_STATUS_UNAVAIL; +- } + } + master->depth--; + master->recurse = 0; --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-fix-isspace-wild-card-substition.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-fix-isspace-wild-card-substition.dpatch @@ -0,0 +1,88 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-fix-isspace-wild-card-substition.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - fix isspace() wild card substition + +From: Ian Kent + +If there are characters that match isspace() (such as \t, \n, etc.) in a +passed map entry key and there is no space in the key these characters +won't be properly preserved, leading to failed or incorrect mounts. + +This is caused by an incorrect attempt at optimization, using a check +to see if a space is present in the passed key and only then processing +each character of the key individually, escaping any isspace() characters. +--- + + CHANGELOG | 1 + + modules/parse_sun.c | 40 +++++++++++++++++----------------------- + 2 files changed, 18 insertions(+), 23 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index c98204d..72590f7 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -56,6 +56,7 @@ + - fix add simple bind auth. + - add option to dump configured automount maps. + - use weight only for server selection. ++- fix isspace() wild card substition. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/modules/parse_sun.c b/modules/parse_sun.c +index 4bddcc9..3242e3b 100644 +--- a/modules/parse_sun.c ++++ b/modules/parse_sun.c +@@ -161,30 +161,24 @@ int expandsunent(const char *src, char *dst, const char *key, + case '&': + l = strlen(key); + /* +- * In order to ensure that any spaces in the key +- * re preserved, we need to escape them here. ++ * In order to ensure that any isspace() characters ++ * in the key are preserved, we need to escape them ++ * here. + */ +- if (strchr(key, ' ')) { +- const char *keyp = key; +- while (*keyp) { +- if (isspace(*keyp)) { +- if (dst) { +- *dst++ = '\\'; +- *dst++ = *keyp++; +- } else +- keyp++; +- l++; +- } else { +- if (dst) +- *dst++ = *keyp++; +- else +- keyp++; +- } +- } +- } else { +- if (dst) { +- strcpy(dst, key); +- dst += l; ++ const char *keyp = key; ++ while (*keyp) { ++ if (isspace(*keyp)) { ++ if (dst) { ++ *dst++ = '\\'; ++ *dst++ = *keyp++; ++ } else ++ keyp++; ++ l++; ++ } else { ++ if (dst) ++ *dst++ = *keyp++; ++ else ++ keyp++; + } + } + len += l; --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-update-kernel-patches-2.6.18-and-2.6.19.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-update-kernel-patches-2.6.18-and-2.6.19.dpatch @@ -0,0 +1,7645 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-update-kernel-patches-2.6.18-and-2.6.19.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - update kernel patches for 2.6.18 and 2.6.19 + +From: Ian Kent + +Leonardo Chiquitto spotted n error in the 2.6.18 kernel patch. +This mistake was made during the backport of the patch series +from 2.6.20 to 2.6.19 so the error exists in the 2.6.19 patch +as well. +--- + + CHANGELOG | 1 + patches/autofs4-2.6.18-v5-update-20100114.patch | 3929 +++++++++++++++++++++++ + patches/autofs4-2.6.19-v5-update-20100114.patch | 3668 +++++++++++++++++++++ + 3 files changed, 7598 insertions(+), 0 deletions(-) + create mode 100644 patches/autofs4-2.6.18-v5-update-20100114.patch + create mode 100644 patches/autofs4-2.6.19-v5-update-20100114.patch + + +diff --git a/CHANGELOG b/CHANGELOG +index df2ec09..a2569aa 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -17,6 +17,7 @@ + - dont fail mount on access fail. + - fix rpc fail on large export list. + - fix memory leak on reload. ++- update kernel patches for 2.6.18 and 2.6.19. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/patches/autofs4-2.6.18-v5-update-20100114.patch b/patches/autofs4-2.6.18-v5-update-20100114.patch +new file mode 100644 +index 0000000..961c104 +--- /dev/null ++++ b/patches/autofs4-2.6.18-v5-update-20100114.patch +@@ -0,0 +1,3929 @@ ++--- linux-2.6.18.orig/fs/autofs4/root.c +++++ linux-2.6.18/fs/autofs4/root.c ++@@ -26,25 +26,25 @@ static int autofs4_dir_rmdir(struct inod ++ static int autofs4_dir_mkdir(struct inode *,struct dentry *,int); ++ static int autofs4_root_ioctl(struct inode *, struct file *,unsigned int,unsigned long); ++ static int autofs4_dir_open(struct inode *inode, struct file *file); ++-static int autofs4_dir_close(struct inode *inode, struct file *file); ++-static int autofs4_dir_readdir(struct file * filp, void * dirent, filldir_t filldir); ++-static int autofs4_root_readdir(struct file * filp, void * dirent, filldir_t filldir); ++ static struct dentry *autofs4_lookup(struct inode *,struct dentry *, struct nameidata *); ++ static void *autofs4_follow_link(struct dentry *, struct nameidata *); ++ +++#define TRIGGER_FLAGS (LOOKUP_CONTINUE | LOOKUP_DIRECTORY) +++#define TRIGGER_INTENTS (LOOKUP_OPEN | LOOKUP_CREATE) +++ ++ const struct file_operations autofs4_root_operations = { ++ .open = dcache_dir_open, ++ .release = dcache_dir_close, ++ .read = generic_read_dir, ++- .readdir = autofs4_root_readdir, +++ .readdir = dcache_readdir, ++ .ioctl = autofs4_root_ioctl, ++ }; ++ ++ const struct file_operations autofs4_dir_operations = { ++ .open = autofs4_dir_open, ++- .release = autofs4_dir_close, +++ .release = dcache_dir_close, ++ .read = generic_read_dir, ++- .readdir = autofs4_dir_readdir, +++ .readdir = dcache_readdir, ++ }; ++ ++ struct inode_operations autofs4_indirect_root_inode_operations = { ++@@ -71,42 +71,10 @@ struct inode_operations autofs4_dir_inod ++ .rmdir = autofs4_dir_rmdir, ++ }; ++ ++-static int autofs4_root_readdir(struct file *file, void *dirent, ++- filldir_t filldir) ++-{ ++- struct autofs_sb_info *sbi = autofs4_sbi(file->f_dentry->d_sb); ++- int oz_mode = autofs4_oz_mode(sbi); ++- ++- DPRINTK("called, filp->f_pos = %lld", file->f_pos); ++- ++- /* ++- * Don't set reghost flag if: ++- * 1) f_pos is larger than zero -- we've already been here. ++- * 2) we haven't even enabled reghosting in the 1st place. ++- * 3) this is the daemon doing a readdir ++- */ ++- if (oz_mode && file->f_pos == 0 && sbi->reghost_enabled) ++- sbi->needs_reghost = 1; ++- ++- DPRINTK("needs_reghost = %d", sbi->needs_reghost); ++- ++- return dcache_readdir(file, dirent, filldir); ++-} ++- ++ static int autofs4_dir_open(struct inode *inode, struct file *file) ++ { ++ struct dentry *dentry = file->f_dentry; ++- struct vfsmount *mnt = file->f_vfsmnt; ++ struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); ++- struct dentry *cursor; ++- int status; ++- ++- status = dcache_dir_open(inode, file); ++- if (status) ++- goto out; ++- ++- cursor = file->private_data; ++- cursor->d_fsdata = NULL; ++ ++ DPRINTK("file=%p dentry=%p %.*s", ++ file, dentry, dentry->d_name.len, dentry->d_name.name); ++@@ -114,155 +82,31 @@ static int autofs4_dir_open(struct inode ++ if (autofs4_oz_mode(sbi)) ++ goto out; ++ ++- if (autofs4_ispending(dentry)) { ++- DPRINTK("dentry busy"); ++- dcache_dir_close(inode, file); ++- status = -EBUSY; ++- goto out; ++- } ++- ++- status = -ENOENT; ++- if (!d_mountpoint(dentry) && dentry->d_op && dentry->d_op->d_revalidate) { ++- struct nameidata nd; ++- int empty, ret; ++- ++- /* In case there are stale directory dentrys from a failed mount */ ++- spin_lock(&dcache_lock); ++- empty = list_empty(&dentry->d_subdirs); +++ /* +++ * An empty directory in an autofs file system is always a +++ * mount point. The daemon must have failed to mount this +++ * during lookup so it doesn't exist. This can happen, for +++ * example, if user space returns an incorrect status for a +++ * mount request. Otherwise we're doing a readdir on the +++ * autofs file system so just let the libfs routines handle +++ * it. +++ */ +++ spin_lock(&dcache_lock); +++ if (!d_mountpoint(dentry) && __simple_empty(dentry)) { ++ spin_unlock(&dcache_lock); ++- ++- if (!empty) ++- d_invalidate(dentry); ++- ++- nd.flags = LOOKUP_DIRECTORY; ++- ret = (dentry->d_op->d_revalidate)(dentry, &nd); ++- ++- if (!ret) { ++- dcache_dir_close(inode, file); ++- goto out; ++- } ++- } ++- ++- if (d_mountpoint(dentry)) { ++- struct file *fp = NULL; ++- struct vfsmount *fp_mnt = mntget(mnt); ++- struct dentry *fp_dentry = dget(dentry); ++- ++- if (!autofs4_follow_mount(&fp_mnt, &fp_dentry)) { ++- dput(fp_dentry); ++- mntput(fp_mnt); ++- dcache_dir_close(inode, file); ++- goto out; ++- } ++- ++- fp = dentry_open(fp_dentry, fp_mnt, file->f_flags); ++- status = PTR_ERR(fp); ++- if (IS_ERR(fp)) { ++- dcache_dir_close(inode, file); ++- goto out; ++- } ++- cursor->d_fsdata = fp; ++- } ++- return 0; ++-out: ++- return status; ++-} ++- ++-static int autofs4_dir_close(struct inode *inode, struct file *file) ++-{ ++- struct dentry *dentry = file->f_dentry; ++- struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); ++- struct dentry *cursor = file->private_data; ++- int status = 0; ++- ++- DPRINTK("file=%p dentry=%p %.*s", ++- file, dentry, dentry->d_name.len, dentry->d_name.name); ++- ++- if (autofs4_oz_mode(sbi)) ++- goto out; ++- ++- if (autofs4_ispending(dentry)) { ++- DPRINTK("dentry busy"); ++- status = -EBUSY; ++- goto out; ++- } ++- ++- if (d_mountpoint(dentry)) { ++- struct file *fp = cursor->d_fsdata; ++- if (!fp) { ++- status = -ENOENT; ++- goto out; ++- } ++- filp_close(fp, current->files); ++- } ++-out: ++- dcache_dir_close(inode, file); ++- return status; ++-} ++- ++-static int autofs4_dir_readdir(struct file *file, void *dirent, filldir_t filldir) ++-{ ++- struct dentry *dentry = file->f_dentry; ++- struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); ++- struct dentry *cursor = file->private_data; ++- int status; ++- ++- DPRINTK("file=%p dentry=%p %.*s", ++- file, dentry, dentry->d_name.len, dentry->d_name.name); ++- ++- if (autofs4_oz_mode(sbi)) ++- goto out; ++- ++- if (autofs4_ispending(dentry)) { ++- DPRINTK("dentry busy"); ++- return -EBUSY; +++ return -ENOENT; ++ } +++ spin_unlock(&dcache_lock); ++ ++- if (d_mountpoint(dentry)) { ++- struct file *fp = cursor->d_fsdata; ++- ++- if (!fp) ++- return -ENOENT; ++- ++- if (!fp->f_op || !fp->f_op->readdir) ++- goto out; ++- ++- status = vfs_readdir(fp, filldir, dirent); ++- file->f_pos = fp->f_pos; ++- if (status) ++- autofs4_copy_atime(file, fp); ++- return status; ++- } ++ out: ++- return dcache_readdir(file, dirent, filldir); +++ return dcache_dir_open(inode, file); ++ } ++ ++ static int try_to_fill_dentry(struct dentry *dentry, int flags) ++ { ++ struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); ++ struct autofs_info *ino = autofs4_dentry_ino(dentry); ++- int status = 0; ++- ++- /* Block on any pending expiry here; invalidate the dentry ++- when expiration is done to trigger mount request with a new ++- dentry */ ++- if (ino && (ino->flags & AUTOFS_INF_EXPIRING)) { ++- DPRINTK("waiting for expire %p name=%.*s", ++- dentry, dentry->d_name.len, dentry->d_name.name); ++- ++- status = autofs4_wait(sbi, dentry, NFY_NONE); ++- ++- DPRINTK("expire done status=%d", status); ++- ++- /* ++- * If the directory still exists the mount request must ++- * continue otherwise it can't be followed at the right ++- * time during the walk. ++- */ ++- status = d_invalidate(dentry); ++- if (status != -EBUSY) ++- return -ENOENT; ++- } +++ int status; ++ ++ DPRINTK("dentry=%p %.*s ino=%p", ++ dentry, dentry->d_name.len, dentry->d_name.name, dentry->d_inode); ++@@ -279,9 +123,6 @@ static int try_to_fill_dentry(struct den ++ ++ DPRINTK("mount done status=%d", status); ++ ++- if (status && dentry->d_inode) ++- return status; /* Try to get the kernel to invalidate this dentry */ ++- ++ /* Turn this into a real negative dentry? */ ++ if (status == -ENOENT) { ++ spin_lock(&dentry->d_lock); ++@@ -293,7 +134,8 @@ static int try_to_fill_dentry(struct den ++ return status; ++ } ++ /* Trigger mount for path component or follow link */ ++- } else if (flags & (LOOKUP_CONTINUE | LOOKUP_DIRECTORY) || +++ } else if (dentry->d_flags & DCACHE_AUTOFS_PENDING || +++ flags & (TRIGGER_FLAGS | TRIGGER_INTENTS) || ++ current->link_count) { ++ DPRINTK("waiting for mount name=%.*s", ++ dentry->d_name.len, dentry->d_name.name); ++@@ -320,7 +162,8 @@ static int try_to_fill_dentry(struct den ++ spin_lock(&dentry->d_lock); ++ dentry->d_flags &= ~DCACHE_AUTOFS_PENDING; ++ spin_unlock(&dentry->d_lock); ++- return status; +++ +++ return 0; ++ } ++ ++ /* For autofs direct mounts the follow link triggers the mount */ ++@@ -335,50 +178,62 @@ static void *autofs4_follow_link(struct ++ DPRINTK("dentry=%p %.*s oz_mode=%d nd->flags=%d", ++ dentry, dentry->d_name.len, dentry->d_name.name, oz_mode, ++ nd->flags); ++- ++- /* If it's our master or we shouldn't trigger a mount we're done */ ++- lookup_type = nd->flags & (LOOKUP_CONTINUE | LOOKUP_DIRECTORY); ++- if (oz_mode || !lookup_type) +++ /* +++ * For an expire of a covered direct or offset mount we need +++ * to beeak out of follow_down() at the autofs mount trigger +++ * (d_mounted--), so we can see the expiring flag, and manage +++ * the blocking and following here until the expire is completed. +++ */ +++ if (oz_mode) { +++ spin_lock(&sbi->fs_lock); +++ if (ino->flags & AUTOFS_INF_EXPIRING) { +++ spin_unlock(&sbi->fs_lock); +++ /* Follow down to our covering mount. */ +++ if (!follow_down(&nd->mnt, &nd->dentry)) +++ goto done; +++ goto follow; +++ } +++ spin_unlock(&sbi->fs_lock); ++ goto done; +++ } ++ ++- /* If an expire request is pending wait for it. */ ++- if (ino && (ino->flags & AUTOFS_INF_EXPIRING)) { ++- DPRINTK("waiting for active request %p name=%.*s", ++- dentry, dentry->d_name.len, dentry->d_name.name); +++ /* If an expire request is pending everyone must wait. */ +++ autofs4_expire_wait(dentry); ++ ++- status = autofs4_wait(sbi, dentry, NFY_NONE); ++- ++- DPRINTK("request done status=%d", status); ++- } +++ /* We trigger a mount for almost all flags */ +++ lookup_type = nd->flags & (TRIGGER_FLAGS | TRIGGER_INTENTS); +++ if (!(lookup_type || dentry->d_flags & DCACHE_AUTOFS_PENDING)) +++ goto follow; ++ ++ /* ++- * If the dentry contains directories then it is an ++- * autofs multi-mount with no root mount offset. So ++- * don't try to mount it again. +++ * If the dentry contains directories then it is an autofs +++ * multi-mount with no root mount offset. So don't try to +++ * mount it again. ++ */ ++ spin_lock(&dcache_lock); ++- if (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) { +++ if (dentry->d_flags & DCACHE_AUTOFS_PENDING || +++ (!d_mountpoint(dentry) && __simple_empty(dentry))) { ++ spin_unlock(&dcache_lock); ++ ++ status = try_to_fill_dentry(dentry, 0); ++ if (status) ++ goto out_error; ++ ++- /* ++- * The mount succeeded but if there is no root mount ++- * it must be an autofs multi-mount with no root offset ++- * so we don't need to follow the mount. ++- */ ++- if (d_mountpoint(dentry)) { ++- if (!autofs4_follow_mount(&nd->mnt, &nd->dentry)) { ++- status = -ENOENT; ++- goto out_error; ++- } ++- } ++- ++- goto done; +++ goto follow; ++ } ++ spin_unlock(&dcache_lock); +++follow: +++ /* +++ * If there is no root mount it must be an autofs +++ * multi-mount with no root offset so we don't need +++ * to follow it. +++ */ +++ if (d_mountpoint(dentry)) { +++ if (!autofs4_follow_mount(&nd->mnt, &nd->dentry)) { +++ status = -ENOENT; +++ goto out_error; +++ } +++ } ++ ++ done: ++ return NULL; ++@@ -400,14 +255,36 @@ static int autofs4_revalidate(struct den ++ struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb); ++ int oz_mode = autofs4_oz_mode(sbi); ++ int flags = nd ? nd->flags : 0; ++- int status = 0; +++ int status; ++ ++ /* Pending dentry */ +++ spin_lock(&sbi->fs_lock); ++ if (autofs4_ispending(dentry)) { ++- if (!oz_mode) ++- status = try_to_fill_dentry(dentry, flags); ++- return !status; +++ /* The daemon never causes a mount to trigger */ +++ spin_unlock(&sbi->fs_lock); +++ +++ if (oz_mode) +++ return 1; +++ +++ /* +++ * If the directory has gone away due to an expire +++ * we have been called as ->d_revalidate() and so +++ * we need to return false and proceed to ->lookup(). +++ */ +++ if (autofs4_expire_wait(dentry) == -EAGAIN) +++ return 0; +++ +++ /* +++ * A zero status is success otherwise we have a +++ * negative error code. +++ */ +++ status = try_to_fill_dentry(dentry, flags); +++ if (status == 0) +++ return 1; +++ +++ return status; ++ } +++ spin_unlock(&sbi->fs_lock); ++ ++ /* Negative dentry.. invalidate if "old" */ ++ if (dentry->d_inode == NULL) ++@@ -421,9 +298,20 @@ static int autofs4_revalidate(struct den ++ DPRINTK("dentry=%p %.*s, emptydir", ++ dentry, dentry->d_name.len, dentry->d_name.name); ++ spin_unlock(&dcache_lock); ++- if (!oz_mode) ++- status = try_to_fill_dentry(dentry, flags); ++- return !status; +++ +++ /* The daemon never causes a mount to trigger */ +++ if (oz_mode) +++ return 1; +++ +++ /* +++ * A zero status is success otherwise we have a +++ * negative error code. +++ */ +++ status = try_to_fill_dentry(dentry, flags); +++ if (status == 0) +++ return 1; +++ +++ return status; ++ } ++ spin_unlock(&dcache_lock); ++ ++@@ -440,6 +328,17 @@ void autofs4_dentry_release(struct dentr ++ de->d_fsdata = NULL; ++ ++ if (inf) { +++ struct autofs_sb_info *sbi = autofs4_sbi(de->d_sb); +++ +++ if (sbi) { +++ spin_lock(&sbi->lookup_lock); +++ if (!list_empty(&inf->active)) +++ list_del(&inf->active); +++ if (!list_empty(&inf->expiring)) +++ list_del(&inf->expiring); +++ spin_unlock(&sbi->lookup_lock); +++ } +++ ++ inf->dentry = NULL; ++ inf->inode = NULL; ++ ++@@ -459,10 +358,116 @@ static struct dentry_operations autofs4_ ++ .d_release = autofs4_dentry_release, ++ }; ++ +++static struct dentry *autofs4_lookup_active(struct autofs_sb_info *sbi, struct dentry *parent, struct qstr *name) +++{ +++ unsigned int len = name->len; +++ unsigned int hash = name->hash; +++ const unsigned char *str = name->name; +++ struct list_head *p, *head; +++ +++ spin_lock(&dcache_lock); +++ spin_lock(&sbi->lookup_lock); +++ head = &sbi->active_list; +++ list_for_each(p, head) { +++ struct autofs_info *ino; +++ struct dentry *dentry; +++ struct qstr *qstr; +++ +++ ino = list_entry(p, struct autofs_info, active); +++ dentry = ino->dentry; +++ +++ spin_lock(&dentry->d_lock); +++ +++ /* Already gone? */ +++ if (atomic_read(&dentry->d_count) == 0) +++ goto next; +++ +++ qstr = &dentry->d_name; +++ +++ if (dentry->d_name.hash != hash) +++ goto next; +++ if (dentry->d_parent != parent) +++ goto next; +++ +++ if (qstr->len != len) +++ goto next; +++ if (memcmp(qstr->name, str, len)) +++ goto next; +++ +++ if (d_unhashed(dentry)) { +++ dget(dentry); +++ spin_unlock(&dentry->d_lock); +++ spin_unlock(&sbi->lookup_lock); +++ spin_unlock(&dcache_lock); +++ return dentry; +++ } +++next: +++ spin_unlock(&dentry->d_lock); +++ } +++ spin_unlock(&sbi->lookup_lock); +++ spin_unlock(&dcache_lock); +++ +++ return NULL; +++} +++ +++static struct dentry *autofs4_lookup_expiring(struct autofs_sb_info *sbi, struct dentry *parent, struct qstr *name) +++{ +++ unsigned int len = name->len; +++ unsigned int hash = name->hash; +++ const unsigned char *str = name->name; +++ struct list_head *p, *head; +++ +++ spin_lock(&dcache_lock); +++ spin_lock(&sbi->lookup_lock); +++ head = &sbi->expiring_list; +++ list_for_each(p, head) { +++ struct autofs_info *ino; +++ struct dentry *dentry; +++ struct qstr *qstr; +++ +++ ino = list_entry(p, struct autofs_info, expiring); +++ dentry = ino->dentry; +++ +++ spin_lock(&dentry->d_lock); +++ +++ /* Bad luck, we've already been dentry_iput */ +++ if (!dentry->d_inode) +++ goto next; +++ +++ qstr = &dentry->d_name; +++ +++ if (dentry->d_name.hash != hash) +++ goto next; +++ if (dentry->d_parent != parent) +++ goto next; +++ +++ if (qstr->len != len) +++ goto next; +++ if (memcmp(qstr->name, str, len)) +++ goto next; +++ +++ if (d_unhashed(dentry)) { +++ dget(dentry); +++ spin_unlock(&dentry->d_lock); +++ spin_unlock(&sbi->lookup_lock); +++ spin_unlock(&dcache_lock); +++ return dentry; +++ } +++next: +++ spin_unlock(&dentry->d_lock); +++ } +++ spin_unlock(&sbi->lookup_lock); +++ spin_unlock(&dcache_lock); +++ +++ return NULL; +++} +++ ++ /* Lookups in the root directory */ ++ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) ++ { ++ struct autofs_sb_info *sbi; +++ struct autofs_info *ino; +++ struct dentry *expiring, *unhashed; ++ int oz_mode; ++ ++ DPRINTK("name = %.*s", ++@@ -478,29 +483,67 @@ static struct dentry *autofs4_lookup(str ++ DPRINTK("pid = %u, pgrp = %u, catatonic = %d, oz_mode = %d", ++ current->pid, process_group(current), sbi->catatonic, oz_mode); ++ ++- /* ++- * Mark the dentry incomplete, but add it. This is needed so ++- * that the VFS layer knows about the dentry, and we can count ++- * on catching any lookups through the revalidate. ++- * ++- * Let all the hard work be done by the revalidate function that ++- * needs to be able to do this anyway.. ++- * ++- * We need to do this before we release the directory semaphore. ++- */ ++- dentry->d_op = &autofs4_root_dentry_operations; +++ unhashed = autofs4_lookup_active(sbi, dentry->d_parent, &dentry->d_name); +++ if (unhashed) +++ dentry = unhashed; +++ else { +++ /* +++ * Mark the dentry incomplete but don't hash it. We do this +++ * to serialize our inode creation operations (symlink and +++ * mkdir) which prevents deadlock during the callback to +++ * the daemon. Subsequent user space lookups for the same +++ * dentry are placed on the wait queue while the daemon +++ * itself is allowed passage unresticted so the create +++ * operation itself can then hash the dentry. Finally, +++ * we check for the hashed dentry and return the newly +++ * hashed dentry. +++ */ +++ dentry->d_op = &autofs4_root_dentry_operations; +++ +++ /* +++ * And we need to ensure that the same dentry is used for +++ * all following lookup calls until it is hashed so that +++ * the dentry flags are persistent throughout the request. +++ */ +++ ino = autofs4_init_ino(NULL, sbi, 0555); +++ if (!ino) +++ return ERR_PTR(-ENOMEM); +++ +++ dentry->d_fsdata = ino; +++ ino->dentry = dentry; +++ +++ spin_lock(&sbi->lookup_lock); +++ list_add(&ino->active, &sbi->active_list); +++ spin_unlock(&sbi->lookup_lock); +++ +++ d_instantiate(dentry, NULL); +++ } ++ ++ if (!oz_mode) { +++ mutex_unlock(&dir->i_mutex); +++ expiring = autofs4_lookup_expiring(sbi, +++ dentry->d_parent, +++ &dentry->d_name); +++ if (expiring) { +++ /* +++ * If we are racing with expire the request might not +++ * be quite complete but the directory has been removed +++ * so it must have been successful, so just wait for it. +++ */ +++ ino = autofs4_dentry_ino(expiring); +++ autofs4_expire_wait(expiring); +++ spin_lock(&sbi->lookup_lock); +++ if (!list_empty(&ino->expiring)) +++ list_del_init(&ino->expiring); +++ spin_unlock(&sbi->lookup_lock); +++ dput(expiring); +++ } +++ ++ spin_lock(&dentry->d_lock); ++ dentry->d_flags |= DCACHE_AUTOFS_PENDING; ++ spin_unlock(&dentry->d_lock); ++- } ++- dentry->d_fsdata = NULL; ++- d_add(dentry, NULL); ++- ++- if (dentry->d_op && dentry->d_op->d_revalidate) { ++- mutex_unlock(&dir->i_mutex); ++- (dentry->d_op->d_revalidate)(dentry, nd); +++ if (dentry->d_op && dentry->d_op->d_revalidate) +++ (dentry->d_op->d_revalidate)(dentry, nd); ++ mutex_lock(&dir->i_mutex); ++ } ++ ++@@ -515,19 +558,47 @@ static struct dentry *autofs4_lookup(str ++ if (sigismember (sigset, SIGKILL) || ++ sigismember (sigset, SIGQUIT) || ++ sigismember (sigset, SIGINT)) { +++ if (unhashed) +++ dput(unhashed); ++ return ERR_PTR(-ERESTARTNOINTR); ++ } ++ } +++ if (!oz_mode) { +++ spin_lock(&dentry->d_lock); +++ dentry->d_flags &= ~DCACHE_AUTOFS_PENDING; +++ spin_unlock(&dentry->d_lock); +++ } ++ } ++ ++ /* ++ * If this dentry is unhashed, then we shouldn't honour this ++- * lookup even if the dentry is positive. Returning ENOENT here ++- * doesn't do the right thing for all system calls, but it should ++- * be OK for the operations we permit from an autofs. +++ * lookup. Returning ENOENT here doesn't do the right thing +++ * for all system calls, but it should be OK for the operations +++ * we permit from an autofs. ++ */ ++- if (dentry->d_inode && d_unhashed(dentry)) ++- return ERR_PTR(-ENOENT); +++ if (!oz_mode && d_unhashed(dentry)) { +++ /* +++ * A user space application can (and has done in the past) +++ * remove and re-create this directory during the callback. +++ * This can leave us with an unhashed dentry, but a +++ * successful mount! So we need to perform another +++ * cached lookup in case the dentry now exists. +++ */ +++ struct dentry *parent = dentry->d_parent; +++ struct dentry *new = d_lookup(parent, &dentry->d_name); +++ if (new != NULL) +++ dentry = new; +++ else +++ dentry = ERR_PTR(-ENOENT); +++ +++ if (unhashed) +++ dput(unhashed); +++ +++ return dentry; +++ } +++ +++ if (unhashed) +++ return unhashed; ++ ++ return NULL; ++ } ++@@ -549,21 +620,32 @@ static int autofs4_dir_symlink(struct in ++ return -EACCES; ++ ++ ino = autofs4_init_ino(ino, sbi, S_IFLNK | 0555); ++- if (ino == NULL) ++- return -ENOSPC; +++ if (!ino) +++ return -ENOMEM; ++ ++- ino->size = strlen(symname); ++- ino->u.symlink = cp = kmalloc(ino->size + 1, GFP_KERNEL); +++ spin_lock(&sbi->lookup_lock); +++ if (!list_empty(&ino->active)) +++ list_del_init(&ino->active); +++ spin_unlock(&sbi->lookup_lock); ++ ++- if (cp == NULL) { ++- kfree(ino); ++- return -ENOSPC; +++ ino->size = strlen(symname); +++ cp = kmalloc(ino->size + 1, GFP_KERNEL); +++ if (!cp) { +++ if (!dentry->d_fsdata) +++ kfree(ino); +++ return -ENOMEM; ++ } ++ ++ strcpy(cp, symname); ++ ++ inode = autofs4_get_inode(dir->i_sb, ino); ++- d_instantiate(dentry, inode); +++ if (!inode) { +++ kfree(cp); +++ if (!dentry->d_fsdata) +++ kfree(ino); +++ return -ENOMEM; +++ } +++ d_add(dentry, inode); ++ ++ if (dir == dir->i_sb->s_root->d_inode) ++ dentry->d_op = &autofs4_root_dentry_operations; ++@@ -578,6 +660,7 @@ static int autofs4_dir_symlink(struct in ++ atomic_inc(&p_ino->count); ++ ino->inode = inode; ++ +++ ino->u.symlink = cp; ++ dir->i_mtime = CURRENT_TIME; ++ ++ return 0; ++@@ -589,9 +672,9 @@ static int autofs4_dir_symlink(struct in ++ * Normal filesystems would do a "d_delete()" to tell the VFS dcache ++ * that the file no longer exists. However, doing that means that the ++ * VFS layer can turn the dentry into a negative dentry. We don't want ++- * this, because since the unlink is probably the result of an expire. ++- * We simply d_drop it, which allows the dentry lookup to remount it ++- * if necessary. +++ * this, because the unlink is probably the result of an expire. +++ * We simply d_drop it and add it to a expiring list in the super block, +++ * which allows the dentry lookup to check for an incomplete expire. ++ * ++ * If a process is blocked on the dentry waiting for the expire to finish, ++ * it will invalidate the dentry and try to mount with a new one. ++@@ -620,7 +703,15 @@ static int autofs4_dir_unlink(struct ino ++ ++ dir->i_mtime = CURRENT_TIME; ++ ++- d_drop(dentry); +++ spin_lock(&dcache_lock); +++ spin_lock(&sbi->lookup_lock); +++ if (list_empty(&ino->expiring)) +++ list_add(&ino->expiring, &sbi->expiring_list); +++ spin_unlock(&sbi->lookup_lock); +++ spin_lock(&dentry->d_lock); +++ __d_drop(dentry); +++ spin_unlock(&dentry->d_lock); +++ spin_unlock(&dcache_lock); ++ ++ return 0; ++ } ++@@ -631,6 +722,9 @@ static int autofs4_dir_rmdir(struct inod ++ struct autofs_info *ino = autofs4_dentry_ino(dentry); ++ struct autofs_info *p_ino; ++ +++ DPRINTK("dentry %p, removing %.*s", +++ dentry, dentry->d_name.len, dentry->d_name.name); +++ ++ if (!autofs4_oz_mode(sbi)) ++ return -EACCES; ++ ++@@ -639,6 +733,10 @@ static int autofs4_dir_rmdir(struct inod ++ spin_unlock(&dcache_lock); ++ return -ENOTEMPTY; ++ } +++ spin_lock(&sbi->lookup_lock); +++ if (list_empty(&ino->expiring)) +++ list_add(&ino->expiring, &sbi->expiring_list); +++ spin_unlock(&sbi->lookup_lock); ++ spin_lock(&dentry->d_lock); ++ __d_drop(dentry); ++ spin_unlock(&dentry->d_lock); ++@@ -673,11 +771,21 @@ static int autofs4_dir_mkdir(struct inod ++ dentry, dentry->d_name.len, dentry->d_name.name); ++ ++ ino = autofs4_init_ino(ino, sbi, S_IFDIR | 0555); ++- if (ino == NULL) ++- return -ENOSPC; +++ if (!ino) +++ return -ENOMEM; +++ +++ spin_lock(&sbi->lookup_lock); +++ if (!list_empty(&ino->active)) +++ list_del_init(&ino->active); +++ spin_unlock(&sbi->lookup_lock); ++ ++ inode = autofs4_get_inode(dir->i_sb, ino); ++- d_instantiate(dentry, inode); +++ if (!inode) { +++ if (!dentry->d_fsdata) +++ kfree(ino); +++ return -ENOMEM; +++ } +++ d_add(dentry, inode); ++ ++ if (dir == dir->i_sb->s_root->d_inode) ++ dentry->d_op = &autofs4_root_dentry_operations; ++@@ -729,44 +837,6 @@ static inline int autofs4_get_protosubve ++ } ++ ++ /* ++- * Tells the daemon whether we need to reghost or not. Also, clears ++- * the reghost_needed flag. ++- */ ++-static inline int autofs4_ask_reghost(struct autofs_sb_info *sbi, int __user *p) ++-{ ++- int status; ++- ++- DPRINTK("returning %d", sbi->needs_reghost); ++- ++- status = put_user(sbi->needs_reghost, p); ++- if ( status ) ++- return status; ++- ++- sbi->needs_reghost = 0; ++- return 0; ++-} ++- ++-/* ++- * Enable / Disable reghosting ioctl() operation ++- */ ++-static inline int autofs4_toggle_reghost(struct autofs_sb_info *sbi, int __user *p) ++-{ ++- int status; ++- int val; ++- ++- status = get_user(val, p); ++- ++- DPRINTK("reghost = %d", val); ++- ++- if (status) ++- return status; ++- ++- /* turn on/off reghosting, with the val */ ++- sbi->reghost_enabled = val; ++- return 0; ++-} ++- ++-/* ++ * Tells the daemon whether it can umount the autofs mount. ++ */ ++ static inline int autofs4_ask_umount(struct vfsmount *mnt, int __user *p) ++@@ -830,11 +900,6 @@ static int autofs4_root_ioctl(struct ino ++ case AUTOFS_IOC_SETTIMEOUT: ++ return autofs4_get_set_timeout(sbi, p); ++ ++- case AUTOFS_IOC_TOGGLEREGHOST: ++- return autofs4_toggle_reghost(sbi, p); ++- case AUTOFS_IOC_ASKREGHOST: ++- return autofs4_ask_reghost(sbi, p); ++- ++ case AUTOFS_IOC_ASKUMOUNT: ++ return autofs4_ask_umount(filp->f_vfsmnt, p); ++ ++--- linux-2.6.18.orig/fs/namei.c +++++ linux-2.6.18/fs/namei.c ++@@ -372,6 +372,29 @@ void release_open_intent(struct nameidat ++ fput(nd->intent.open.file); ++ } ++ +++static inline struct dentry *do_revalidate(struct dentry *dentry, struct nameidata *nd) +++{ +++ int status = dentry->d_op->d_revalidate(dentry, nd); +++ if (unlikely(status <= 0)) { +++ /* +++ * The dentry failed validation. +++ * If d_revalidate returned 0 attempt to invalidate +++ * the dentry otherwise d_revalidate is asking us +++ * to return a fail status. +++ */ +++ if (!status) { +++ if (!d_invalidate(dentry)) { +++ dput(dentry); +++ dentry = NULL; +++ } +++ } else { +++ dput(dentry); +++ dentry = ERR_PTR(status); +++ } +++ } +++ return dentry; +++} +++ ++ /* ++ * Internal lookup() using the new generic dcache. ++ * SMP-safe ++@@ -386,12 +409,9 @@ static struct dentry * cached_lookup(str ++ if (!dentry) ++ dentry = d_lookup(parent, name); ++ ++- if (dentry && dentry->d_op && dentry->d_op->d_revalidate) { ++- if (!dentry->d_op->d_revalidate(dentry, nd) && !d_invalidate(dentry)) { ++- dput(dentry); ++- dentry = NULL; ++- } ++- } +++ if (dentry && dentry->d_op && dentry->d_op->d_revalidate) +++ dentry = do_revalidate(dentry, nd); +++ ++ return dentry; ++ } ++ ++@@ -484,10 +504,9 @@ static struct dentry * real_lookup(struc ++ */ ++ mutex_unlock(&dir->i_mutex); ++ if (result->d_op && result->d_op->d_revalidate) { ++- if (!result->d_op->d_revalidate(result, nd) && !d_invalidate(result)) { ++- dput(result); +++ result = do_revalidate(result, nd); +++ if (!result) ++ result = ERR_PTR(-ENOENT); ++- } ++ } ++ return result; ++ } ++@@ -767,12 +786,12 @@ need_lookup: ++ goto done; ++ ++ need_revalidate: ++- if (dentry->d_op->d_revalidate(dentry, nd)) ++- goto done; ++- if (d_invalidate(dentry)) ++- goto done; ++- dput(dentry); ++- goto need_lookup; +++ dentry = do_revalidate(dentry, nd); +++ if (!dentry) +++ goto need_lookup; +++ if (IS_ERR(dentry)) +++ goto fail; +++ goto done; ++ ++ fail: ++ return PTR_ERR(dentry); ++--- linux-2.6.18.orig/fs/autofs/init.c +++++ linux-2.6.18/fs/autofs/init.c ++@@ -24,7 +24,7 @@ static struct file_system_type autofs_fs ++ .owner = THIS_MODULE, ++ .name = "autofs", ++ .get_sb = autofs_get_sb, ++- .kill_sb = kill_anon_super, +++ .kill_sb = autofs_kill_sb, ++ }; ++ ++ static int __init init_autofs_fs(void) ++--- linux-2.6.18.orig/fs/autofs/inode.c +++++ linux-2.6.18/fs/autofs/inode.c ++@@ -19,11 +19,20 @@ ++ #include "autofs_i.h" ++ #include ++ ++-static void autofs_put_super(struct super_block *sb) +++void autofs4_kill_sb(struct super_block *sb) ++ { ++ struct autofs_sb_info *sbi = autofs_sbi(sb); ++ unsigned int n; ++ +++ /* +++ * In the event of a failure in get_sb_nodev the superblock +++ * info is not present so nothing else has been setup, so +++ * just call kill_anon_super when we are called from +++ * deactivate_super. +++ */ +++ if (!sbi) +++ goto out_kill_sb; +++ ++ if ( !sbi->catatonic ) ++ autofs_catatonic_mode(sbi); /* Free wait queues, close pipe */ ++ ++@@ -35,14 +44,15 @@ static void autofs_put_super(struct supe ++ ++ kfree(sb->s_fs_info); ++ +++out_kill_sb: ++ DPRINTK(("autofs: shutting down\n")); +++ kill_anon_super(sb); ++ } ++ ++ static void autofs_read_inode(struct inode *inode); ++ ++ static struct super_operations autofs_sops = { ++ .read_inode = autofs_read_inode, ++- .put_super = autofs_put_super, ++ .statfs = simple_statfs, ++ }; ++ ++@@ -136,7 +146,8 @@ int autofs_fill_super(struct super_block ++ ++ s->s_fs_info = sbi; ++ sbi->magic = AUTOFS_SBI_MAGIC; ++- sbi->catatonic = 0; +++ sbi->pipe = NULL; +++ sbi->catatonic = 1; ++ sbi->exp_timeout = 0; ++ sbi->oz_pgrp = process_group(current); ++ autofs_initialize_hash(&sbi->dirhash); ++@@ -180,6 +191,7 @@ int autofs_fill_super(struct super_block ++ if ( !pipe->f_op || !pipe->f_op->write ) ++ goto fail_fput; ++ sbi->pipe = pipe; +++ sbi->catatonic = 0; ++ ++ /* ++ * Success! Install the root dentry now to indicate completion. ++@@ -198,6 +210,7 @@ fail_iput: ++ iput(root_inode); ++ fail_free: ++ kfree(sbi); +++ s->s_fs_info = NULL; ++ fail_unlock: ++ return -EINVAL; ++ } ++--- linux-2.6.18.orig/fs/autofs/autofs_i.h +++++ linux-2.6.18/fs/autofs/autofs_i.h ++@@ -151,6 +151,7 @@ extern const struct file_operations auto ++ /* Initializing function */ ++ ++ int autofs_fill_super(struct super_block *, void *, int); +++void autofs_kill_sb(struct super_block *); ++ ++ /* Queue management functions */ ++ ++--- linux-2.6.18.orig/fs/autofs4/autofs_i.h +++++ linux-2.6.18/fs/autofs4/autofs_i.h ++@@ -14,6 +14,7 @@ ++ /* Internal header file for autofs */ ++ ++ #include +++#include ++ #include ++ #include ++ ++@@ -21,6 +22,9 @@ ++ #define AUTOFS_IOC_FIRST AUTOFS_IOC_READY ++ #define AUTOFS_IOC_COUNT 32 ++ +++#define AUTOFS_DEV_IOCTL_IOC_FIRST (AUTOFS_DEV_IOCTL_VERSION) +++#define AUTOFS_DEV_IOCTL_IOC_COUNT (AUTOFS_IOC_COUNT - 11) +++ ++ #include ++ #include ++ #include ++@@ -35,11 +39,27 @@ ++ /* #define DEBUG */ ++ ++ #ifdef DEBUG ++-#define DPRINTK(fmt,args...) do { printk(KERN_DEBUG "pid %d: %s: " fmt "\n" , current->pid , __FUNCTION__ , ##args); } while(0) +++#define DPRINTK(fmt, args...) \ +++do { \ +++ printk(KERN_DEBUG "pid %d: %s: " fmt "\n", \ +++ current->pid, __FUNCTION__, ##args); \ +++} while (0) ++ #else ++ #define DPRINTK(fmt,args...) do {} while(0) ++ #endif ++ +++#define AUTOFS_WARN(fmt, args...) \ +++do { \ +++ printk(KERN_WARNING "pid %d: %s: " fmt "\n", \ +++ current->pid, __FUNCTION__, ##args); \ +++} while (0) +++ +++#define AUTOFS_ERROR(fmt, args...) \ +++do { \ +++ printk(KERN_ERR "pid %d: %s: " fmt "\n", \ +++ current->pid, __FUNCTION__, ##args); \ +++} while (0) +++ ++ #define AUTOFS_SUPER_MAGIC 0x0187 ++ ++ /* Unified info structure. This is pointed to by both the dentry and ++@@ -54,10 +74,18 @@ struct autofs_info { ++ ++ int flags; ++ +++ struct completion expire_complete; +++ +++ struct list_head active; +++ struct list_head expiring; +++ ++ struct autofs_sb_info *sbi; ++ unsigned long last_used; ++ atomic_t count; ++ +++ uid_t uid; +++ gid_t gid; +++ ++ mode_t mode; ++ size_t size; ++ ++@@ -68,15 +96,14 @@ struct autofs_info { ++ }; ++ ++ #define AUTOFS_INF_EXPIRING (1<<0) /* dentry is in the process of expiring */ +++#define AUTOFS_INF_MOUNTPOINT (1<<1) /* mountpoint status for direct expire */ ++ ++ struct autofs_wait_queue { ++ wait_queue_head_t queue; ++ struct autofs_wait_queue *next; ++ autofs_wqt_t wait_queue_token; ++ /* We use the following to see what we are waiting for */ ++- unsigned int hash; ++- unsigned int len; ++- char *name; +++ struct qstr name; ++ u32 dev; ++ u64 ino; ++ uid_t uid; ++@@ -85,18 +112,13 @@ struct autofs_wait_queue { ++ pid_t tgid; ++ /* This is for status reporting upon return */ ++ int status; ++- atomic_t wait_ctr; +++ unsigned int wait_ctr; ++ }; ++ ++ #define AUTOFS_SBI_MAGIC 0x6d4a556d ++ ++-#define AUTOFS_TYPE_INDIRECT 0x0001 ++-#define AUTOFS_TYPE_DIRECT 0x0002 ++-#define AUTOFS_TYPE_OFFSET 0x0004 ++- ++ struct autofs_sb_info { ++ u32 magic; ++- struct dentry *root; ++ int pipefd; ++ struct file *pipe; ++ pid_t oz_pgrp; ++@@ -113,6 +135,9 @@ struct autofs_sb_info { ++ struct mutex wq_mutex; ++ spinlock_t fs_lock; ++ struct autofs_wait_queue *queues; /* Wait queue pointer */ +++ spinlock_t lookup_lock; +++ struct list_head active_list; +++ struct list_head expiring_list; ++ }; ++ ++ static inline struct autofs_sb_info *autofs4_sbi(struct super_block *sb) ++@@ -137,18 +162,14 @@ static inline int autofs4_oz_mode(struct ++ static inline int autofs4_ispending(struct dentry *dentry) ++ { ++ struct autofs_info *inf = autofs4_dentry_ino(dentry); ++- int pending = 0; ++ ++ if (dentry->d_flags & DCACHE_AUTOFS_PENDING) ++ return 1; ++ ++- if (inf) { ++- spin_lock(&inf->sbi->fs_lock); ++- pending = inf->flags & AUTOFS_INF_EXPIRING; ++- spin_unlock(&inf->sbi->fs_lock); ++- } +++ if (inf->flags & AUTOFS_INF_EXPIRING) +++ return 1; ++ ++- return pending; +++ return 0; ++ } ++ ++ static inline void autofs4_copy_atime(struct file *src, struct file *dst) ++@@ -162,11 +183,23 @@ void autofs4_free_ino(struct autofs_info ++ ++ /* Expiration */ ++ int is_autofs4_dentry(struct dentry *); +++int autofs4_expire_wait(struct dentry *dentry); ++ int autofs4_expire_run(struct super_block *, struct vfsmount *, ++ struct autofs_sb_info *, ++ struct autofs_packet_expire __user *); ++ int autofs4_expire_multi(struct super_block *, struct vfsmount *, ++ struct autofs_sb_info *, int __user *); +++struct dentry *autofs4_expire_direct(struct super_block *sb, +++ struct vfsmount *mnt, +++ struct autofs_sb_info *sbi, int how); +++struct dentry *autofs4_expire_indirect(struct super_block *sb, +++ struct vfsmount *mnt, +++ struct autofs_sb_info *sbi, int how); +++ +++/* Device node initialization */ +++ +++int autofs_dev_ioctl_init(void); +++void autofs_dev_ioctl_exit(void); ++ ++ /* Operations structures */ ++ ++@@ -231,4 +264,4 @@ out: ++ } ++ ++ void autofs4_dentry_release(struct dentry *); ++- +++extern void autofs4_kill_sb(struct super_block *); ++--- linux-2.6.18.orig/fs/autofs4/init.c +++++ linux-2.6.18/fs/autofs4/init.c ++@@ -24,16 +24,25 @@ static struct file_system_type autofs_fs ++ .owner = THIS_MODULE, ++ .name = "autofs", ++ .get_sb = autofs_get_sb, ++- .kill_sb = kill_anon_super, +++ .kill_sb = autofs4_kill_sb, ++ }; ++ ++ static int __init init_autofs4_fs(void) ++ { ++- return register_filesystem(&autofs_fs_type); +++ int err; +++ +++ err = register_filesystem(&autofs_fs_type); +++ if (err) +++ return err; +++ +++ autofs_dev_ioctl_init(); +++ +++ return err; ++ } ++ ++ static void __exit exit_autofs4_fs(void) ++ { +++ autofs_dev_ioctl_exit(); ++ unregister_filesystem(&autofs_fs_type); ++ } ++ ++--- linux-2.6.18.orig/fs/autofs4/inode.c +++++ linux-2.6.18/fs/autofs4/inode.c ++@@ -24,8 +24,10 @@ ++ ++ static void ino_lnkfree(struct autofs_info *ino) ++ { ++- kfree(ino->u.symlink); ++- ino->u.symlink = NULL; +++ if (ino->u.symlink) { +++ kfree(ino->u.symlink); +++ ino->u.symlink = NULL; +++ } ++ } ++ ++ struct autofs_info *autofs4_init_ino(struct autofs_info *ino, ++@@ -41,14 +43,20 @@ struct autofs_info *autofs4_init_ino(str ++ if (ino == NULL) ++ return NULL; ++ ++- ino->flags = 0; ++- ino->mode = mode; ++- ino->inode = NULL; ++- ino->dentry = NULL; ++- ino->size = 0; +++ if (!reinit) { +++ ino->flags = 0; +++ ino->inode = NULL; +++ ino->dentry = NULL; +++ ino->size = 0; +++ INIT_LIST_HEAD(&ino->active); +++ INIT_LIST_HEAD(&ino->expiring); +++ atomic_set(&ino->count, 0); +++ } ++ +++ ino->uid = 0; +++ ino->gid = 0; +++ ino->mode = mode; ++ ino->last_used = jiffies; ++- atomic_set(&ino->count, 0); ++ ++ ino->sbi = sbi; ++ ++@@ -95,9 +103,12 @@ void autofs4_free_ino(struct autofs_info ++ */ ++ static void autofs4_force_release(struct autofs_sb_info *sbi) ++ { ++- struct dentry *this_parent = sbi->root; +++ struct dentry *this_parent = sbi->sb->s_root; ++ struct list_head *next; ++ +++ if (!sbi->sb->s_root) +++ return; +++ ++ spin_lock(&dcache_lock); ++ repeat: ++ next = this_parent->d_subdirs.next; ++@@ -126,7 +137,7 @@ resume: ++ spin_lock(&dcache_lock); ++ } ++ ++- if (this_parent != sbi->root) { +++ if (this_parent != sbi->sb->s_root) { ++ struct dentry *dentry = this_parent; ++ ++ next = this_parent->d_u.d_child.next; ++@@ -139,29 +150,34 @@ resume: ++ goto resume; ++ } ++ spin_unlock(&dcache_lock); ++- ++- dput(sbi->root); ++- sbi->root = NULL; ++ shrink_dcache_sb(sbi->sb); ++- ++- return; ++ } ++ ++-static void autofs4_put_super(struct super_block *sb) +++void autofs4_kill_sb(struct super_block *sb) ++ { ++ struct autofs_sb_info *sbi = autofs4_sbi(sb); ++ ++- sb->s_fs_info = NULL; +++ /* +++ * In the event of a failure in get_sb_nodev the superblock +++ * info is not present so nothing else has been setup, so +++ * just call kill_anon_super when we are called from +++ * deactivate_super. +++ */ +++ if (!sbi) +++ goto out_kill_sb; ++ ++- if ( !sbi->catatonic ) ++- autofs4_catatonic_mode(sbi); /* Free wait queues, close pipe */ +++ /* Free wait queues, close pipe */ +++ autofs4_catatonic_mode(sbi); ++ ++ /* Clean up and release dangling references */ ++ autofs4_force_release(sbi); ++ +++ sb->s_fs_info = NULL; ++ kfree(sbi); ++ +++out_kill_sb: ++ DPRINTK("shutting down"); +++ kill_anon_super(sb); ++ } ++ ++ static int autofs4_show_options(struct seq_file *m, struct vfsmount *mnt) ++@@ -177,9 +193,9 @@ static int autofs4_show_options(struct s ++ seq_printf(m, ",minproto=%d", sbi->min_proto); ++ seq_printf(m, ",maxproto=%d", sbi->max_proto); ++ ++- if (sbi->type & AUTOFS_TYPE_OFFSET) +++ if (autofs_type_offset(sbi->type)) ++ seq_printf(m, ",offset"); ++- else if (sbi->type & AUTOFS_TYPE_DIRECT) +++ else if (autofs_type_direct(sbi->type)) ++ seq_printf(m, ",direct"); ++ else ++ seq_printf(m, ",indirect"); ++@@ -188,7 +204,6 @@ static int autofs4_show_options(struct s ++ } ++ ++ static struct super_operations autofs4_sops = { ++- .put_super = autofs4_put_super, ++ .statfs = simple_statfs, ++ .show_options = autofs4_show_options, ++ }; ++@@ -266,13 +281,13 @@ static int parse_options(char *options, ++ *maxproto = option; ++ break; ++ case Opt_indirect: ++- *type = AUTOFS_TYPE_INDIRECT; +++ set_autofs_type_indirect(type); ++ break; ++ case Opt_direct: ++- *type = AUTOFS_TYPE_DIRECT; +++ set_autofs_type_direct(type); ++ break; ++ case Opt_offset: ++- *type = AUTOFS_TYPE_DIRECT | AUTOFS_TYPE_OFFSET; +++ set_autofs_type_offset(type); ++ break; ++ default: ++ return 1; ++@@ -314,20 +329,23 @@ int autofs4_fill_super(struct super_bloc ++ ++ s->s_fs_info = sbi; ++ sbi->magic = AUTOFS_SBI_MAGIC; ++- sbi->root = NULL; ++ sbi->pipefd = -1; ++- sbi->catatonic = 0; +++ sbi->pipe = NULL; +++ sbi->catatonic = 1; ++ sbi->exp_timeout = 0; ++ sbi->oz_pgrp = process_group(current); ++ sbi->sb = s; ++ sbi->version = 0; ++ sbi->sub_version = 0; ++- sbi->type = 0; +++ set_autofs_type_indirect(&sbi->type); ++ sbi->min_proto = 0; ++ sbi->max_proto = 0; ++ mutex_init(&sbi->wq_mutex); ++ spin_lock_init(&sbi->fs_lock); ++ sbi->queues = NULL; +++ spin_lock_init(&sbi->lookup_lock); +++ INIT_LIST_HEAD(&sbi->active_list); +++ INIT_LIST_HEAD(&sbi->expiring_list); ++ s->s_blocksize = 1024; ++ s->s_blocksize_bits = 10; ++ s->s_magic = AUTOFS_SUPER_MAGIC; ++@@ -362,7 +380,7 @@ int autofs4_fill_super(struct super_bloc ++ } ++ ++ root_inode->i_fop = &autofs4_root_operations; ++- root_inode->i_op = sbi->type & AUTOFS_TYPE_DIRECT ? +++ root_inode->i_op = autofs_type_trigger(sbi->type) ? ++ &autofs4_direct_root_inode_operations : ++ &autofs4_indirect_root_inode_operations; ++ ++@@ -394,13 +412,7 @@ int autofs4_fill_super(struct super_bloc ++ goto fail_fput; ++ sbi->pipe = pipe; ++ sbi->pipefd = pipefd; ++- ++- /* ++- * Take a reference to the root dentry so we get a chance to ++- * clean up the dentry tree on umount. ++- * See autofs4_force_release. ++- */ ++- sbi->root = dget(root); +++ sbi->catatonic = 0; ++ ++ /* ++ * Success! Install the root dentry now to indicate completion. ++@@ -425,6 +437,7 @@ fail_ino: ++ kfree(ino); ++ fail_free: ++ kfree(sbi); +++ s->s_fs_info = NULL; ++ fail_unlock: ++ return -EINVAL; ++ } ++--- linux-2.6.18.orig/fs/autofs4/waitq.c +++++ linux-2.6.18/fs/autofs4/waitq.c ++@@ -28,6 +28,12 @@ void autofs4_catatonic_mode(struct autof ++ { ++ struct autofs_wait_queue *wq, *nwq; ++ +++ mutex_lock(&sbi->wq_mutex); +++ if (sbi->catatonic) { +++ mutex_unlock(&sbi->wq_mutex); +++ return; +++ } +++ ++ DPRINTK("entering catatonic mode"); ++ ++ sbi->catatonic = 1; ++@@ -36,15 +42,17 @@ void autofs4_catatonic_mode(struct autof ++ while (wq) { ++ nwq = wq->next; ++ wq->status = -ENOENT; /* Magic is gone - report failure */ ++- kfree(wq->name); ++- wq->name = NULL; +++ if (wq->name.name) { +++ kfree(wq->name.name); +++ wq->name.name = NULL; +++ } +++ wq->wait_ctr--; ++ wake_up_interruptible(&wq->queue); ++ wq = nwq; ++ } ++- if (sbi->pipe) { ++- fput(sbi->pipe); /* Close the pipe */ ++- sbi->pipe = NULL; ++- } +++ fput(sbi->pipe); /* Close the pipe */ +++ sbi->pipe = NULL; +++ mutex_unlock(&sbi->wq_mutex); ++ shrink_dcache_sb(sbi->sb); ++ } ++ ++@@ -87,11 +95,16 @@ static void autofs4_notify_daemon(struct ++ struct autofs_wait_queue *wq, ++ int type) ++ { ++- union autofs_packet_union pkt; +++ union { +++ struct autofs_packet_hdr hdr; +++ union autofs_packet_union v4_pkt; +++ union autofs_v5_packet_union v5_pkt; +++ } pkt; +++ struct file *pipe = NULL; ++ size_t pktsz; ++ ++ DPRINTK("wait id = 0x%08lx, name = %.*s, type=%d", ++- wq->wait_queue_token, wq->len, wq->name, type); +++ wq->wait_queue_token, wq->name.len, wq->name.name, type); ++ ++ memset(&pkt,0,sizeof pkt); /* For security reasons */ ++ ++@@ -101,26 +114,26 @@ static void autofs4_notify_daemon(struct ++ /* Kernel protocol v4 missing and expire packets */ ++ case autofs_ptype_missing: ++ { ++- struct autofs_packet_missing *mp = &pkt.missing; +++ struct autofs_packet_missing *mp = &pkt.v4_pkt.missing; ++ ++ pktsz = sizeof(*mp); ++ ++ mp->wait_queue_token = wq->wait_queue_token; ++- mp->len = wq->len; ++- memcpy(mp->name, wq->name, wq->len); ++- mp->name[wq->len] = '\0'; +++ mp->len = wq->name.len; +++ memcpy(mp->name, wq->name.name, wq->name.len); +++ mp->name[wq->name.len] = '\0'; ++ break; ++ } ++ case autofs_ptype_expire_multi: ++ { ++- struct autofs_packet_expire_multi *ep = &pkt.expire_multi; +++ struct autofs_packet_expire_multi *ep = &pkt.v4_pkt.expire_multi; ++ ++ pktsz = sizeof(*ep); ++ ++ ep->wait_queue_token = wq->wait_queue_token; ++- ep->len = wq->len; ++- memcpy(ep->name, wq->name, wq->len); ++- ep->name[wq->len] = '\0'; +++ ep->len = wq->name.len; +++ memcpy(ep->name, wq->name.name, wq->name.len); +++ ep->name[wq->name.len] = '\0'; ++ break; ++ } ++ /* ++@@ -132,14 +145,14 @@ static void autofs4_notify_daemon(struct ++ case autofs_ptype_missing_direct: ++ case autofs_ptype_expire_direct: ++ { ++- struct autofs_v5_packet *packet = &pkt.v5_packet; +++ struct autofs_v5_packet *packet = &pkt.v5_pkt.v5_packet; ++ ++ pktsz = sizeof(*packet); ++ ++ packet->wait_queue_token = wq->wait_queue_token; ++- packet->len = wq->len; ++- memcpy(packet->name, wq->name, wq->len); ++- packet->name[wq->len] = '\0'; +++ packet->len = wq->name.len; +++ memcpy(packet->name, wq->name.name, wq->name.len); +++ packet->name[wq->name.len] = '\0'; ++ packet->dev = wq->dev; ++ packet->ino = wq->ino; ++ packet->uid = wq->uid; ++@@ -153,8 +166,19 @@ static void autofs4_notify_daemon(struct ++ return; ++ } ++ ++- if (autofs4_write(sbi->pipe, &pkt, pktsz)) ++- autofs4_catatonic_mode(sbi); +++ /* Check if we have become catatonic */ +++ mutex_lock(&sbi->wq_mutex); +++ if (!sbi->catatonic) { +++ pipe = sbi->pipe; +++ get_file(pipe); +++ } +++ mutex_unlock(&sbi->wq_mutex); +++ +++ if (pipe) { +++ if (autofs4_write(pipe, &pkt, pktsz)) +++ autofs4_catatonic_mode(sbi); +++ fput(pipe); +++ } ++ } ++ ++ static int autofs4_getpath(struct autofs_sb_info *sbi, ++@@ -170,7 +194,7 @@ static int autofs4_getpath(struct autofs ++ for (tmp = dentry ; tmp != root ; tmp = tmp->d_parent) ++ len += tmp->d_name.len + 1; ++ ++- if (--len > NAME_MAX) { +++ if (!len || --len > NAME_MAX) { ++ spin_unlock(&dcache_lock); ++ return 0; ++ } ++@@ -190,58 +214,55 @@ static int autofs4_getpath(struct autofs ++ } ++ ++ static struct autofs_wait_queue * ++-autofs4_find_wait(struct autofs_sb_info *sbi, ++- char *name, unsigned int hash, unsigned int len) +++autofs4_find_wait(struct autofs_sb_info *sbi, struct qstr *qstr) ++ { ++ struct autofs_wait_queue *wq; ++ ++ for (wq = sbi->queues; wq; wq = wq->next) { ++- if (wq->hash == hash && ++- wq->len == len && ++- wq->name && !memcmp(wq->name, name, len)) +++ if (wq->name.hash == qstr->hash && +++ wq->name.len == qstr->len && +++ wq->name.name && +++ !memcmp(wq->name.name, qstr->name, qstr->len)) ++ break; ++ } ++ return wq; ++ } ++ ++-int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry, ++- enum autofs_notify notify) +++/* +++ * Check if we have a valid request. +++ * Returns +++ * 1 if the request should continue. +++ * In this case we can return an autofs_wait_queue entry if one is +++ * found or NULL to idicate a new wait needs to be created. +++ * 0 or a negative errno if the request shouldn't continue. +++ */ +++static int validate_request(struct autofs_wait_queue **wait, +++ struct autofs_sb_info *sbi, +++ struct qstr *qstr, +++ struct dentry*dentry, enum autofs_notify notify) ++ { ++- struct autofs_info *ino; ++ struct autofs_wait_queue *wq; ++- char *name; ++- unsigned int len = 0; ++- unsigned int hash = 0; ++- int status, type; ++- ++- /* In catatonic mode, we don't wait for nobody */ ++- if (sbi->catatonic) ++- return -ENOENT; ++- ++- name = kmalloc(NAME_MAX + 1, GFP_KERNEL); ++- if (!name) ++- return -ENOMEM; +++ struct autofs_info *ino; ++ ++- /* If this is a direct mount request create a dummy name */ ++- if (IS_ROOT(dentry) && (sbi->type & AUTOFS_TYPE_DIRECT)) ++- len = sprintf(name, "%p", dentry); ++- else { ++- len = autofs4_getpath(sbi, dentry, &name); ++- if (!len) { ++- kfree(name); ++- return -ENOENT; ++- } +++ /* Wait in progress, continue; */ +++ wq = autofs4_find_wait(sbi, qstr); +++ if (wq) { +++ *wait = wq; +++ return 1; ++ } ++- hash = full_name_hash(name, len); ++ ++- if (mutex_lock_interruptible(&sbi->wq_mutex)) { ++- kfree(name); ++- return -EINTR; ++- } +++ *wait = NULL; ++ ++- wq = autofs4_find_wait(sbi, name, hash, len); +++ /* If we don't yet have any info this is a new request */ ++ ino = autofs4_dentry_ino(dentry); ++- if (!wq && ino && notify == NFY_NONE) { +++ if (!ino) +++ return 1; +++ +++ /* +++ * If we've been asked to wait on an existing expire (NFY_NONE) +++ * but there is no wait in the queue ... +++ */ +++ if (notify == NFY_NONE) { ++ /* ++ * Either we've betean the pending expire to post it's ++ * wait or it finished while we waited on the mutex. ++@@ -252,13 +273,14 @@ int autofs4_wait(struct autofs_sb_info * ++ while (ino->flags & AUTOFS_INF_EXPIRING) { ++ mutex_unlock(&sbi->wq_mutex); ++ schedule_timeout_interruptible(HZ/10); ++- if (mutex_lock_interruptible(&sbi->wq_mutex)) { ++- kfree(name); +++ if (mutex_lock_interruptible(&sbi->wq_mutex)) ++ return -EINTR; +++ +++ wq = autofs4_find_wait(sbi, qstr); +++ if (wq) { +++ *wait = wq; +++ return 1; ++ } ++- wq = autofs4_find_wait(sbi, name, hash, len); ++- if (wq) ++- break; ++ } ++ ++ /* ++@@ -266,18 +288,90 @@ int autofs4_wait(struct autofs_sb_info * ++ * cases where we wait on NFY_NONE neither depend on the ++ * return status of the wait. ++ */ ++- if (!wq) { ++- kfree(name); ++- mutex_unlock(&sbi->wq_mutex); +++ return 0; +++ } +++ +++ /* +++ * If we've been asked to trigger a mount and the request +++ * completed while we waited on the mutex ... +++ */ +++ if (notify == NFY_MOUNT) { +++ /* +++ * If the dentry was successfully mounted while we slept +++ * on the wait queue mutex we can return success. If it +++ * isn't mounted (doesn't have submounts for the case of +++ * a multi-mount with no mount at it's base) we can +++ * continue on and create a new request. +++ */ +++ if (have_submounts(dentry)) ++ return 0; +++ } +++ +++ return 1; +++} +++ +++int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry, +++ enum autofs_notify notify) +++{ +++ struct autofs_wait_queue *wq; +++ struct qstr qstr; +++ char *name; +++ int status, ret, type; +++ +++ /* In catatonic mode, we don't wait for nobody */ +++ if (sbi->catatonic) +++ return -ENOENT; +++ +++ if (!dentry->d_inode) { +++ /* +++ * A wait for a negative dentry is invalid for certain +++ * cases. A direct or offset mount "always" has its mount +++ * point directory created and so the request dentry must +++ * be positive or the map key doesn't exist. The situation +++ * is very similar for indirect mounts except only dentrys +++ * in the root of the autofs file system may be negative. +++ */ +++ if (autofs_type_trigger(sbi->type)) +++ return -ENOENT; +++ else if (!IS_ROOT(dentry->d_parent)) +++ return -ENOENT; +++ } +++ +++ name = kmalloc(NAME_MAX + 1, GFP_KERNEL); +++ if (!name) +++ return -ENOMEM; +++ +++ /* If this is a direct mount request create a dummy name */ +++ if (IS_ROOT(dentry) && autofs_type_trigger(sbi->type)) +++ qstr.len = sprintf(name, "%p", dentry); +++ else { +++ qstr.len = autofs4_getpath(sbi, dentry, &name); +++ if (!qstr.len) { +++ kfree(name); +++ return -ENOENT; ++ } ++ } +++ qstr.name = name; +++ qstr.hash = full_name_hash(name, qstr.len); +++ +++ if (mutex_lock_interruptible(&sbi->wq_mutex)) { +++ kfree(qstr.name); +++ return -EINTR; +++ } +++ +++ ret = validate_request(&wq, sbi, &qstr, dentry, notify); +++ if (ret <= 0) { +++ if (ret == 0) +++ mutex_unlock(&sbi->wq_mutex); +++ kfree(qstr.name); +++ return ret; +++ } ++ ++ if (!wq) { ++ /* Create a new wait queue */ ++ wq = kmalloc(sizeof(struct autofs_wait_queue),GFP_KERNEL); ++ if (!wq) { ++- kfree(name); +++ kfree(qstr.name); ++ mutex_unlock(&sbi->wq_mutex); ++ return -ENOMEM; ++ } ++@@ -288,9 +382,7 @@ int autofs4_wait(struct autofs_sb_info * ++ wq->next = sbi->queues; ++ sbi->queues = wq; ++ init_waitqueue_head(&wq->queue); ++- wq->hash = hash; ++- wq->name = name; ++- wq->len = len; +++ memcpy(&wq->name, &qstr, sizeof(struct qstr)); ++ wq->dev = autofs4_get_dev(sbi); ++ wq->ino = autofs4_get_ino(sbi); ++ wq->uid = current->uid; ++@@ -298,7 +390,7 @@ int autofs4_wait(struct autofs_sb_info * ++ wq->pid = current->pid; ++ wq->tgid = current->tgid; ++ wq->status = -EINTR; /* Status return if interrupted */ ++- atomic_set(&wq->wait_ctr, 2); +++ wq->wait_ctr = 2; ++ mutex_unlock(&sbi->wq_mutex); ++ ++ if (sbi->version < 5) { ++@@ -308,38 +400,35 @@ int autofs4_wait(struct autofs_sb_info * ++ type = autofs_ptype_expire_multi; ++ } else { ++ if (notify == NFY_MOUNT) ++- type = (sbi->type & AUTOFS_TYPE_DIRECT) ? +++ type = autofs_type_trigger(sbi->type) ? ++ autofs_ptype_missing_direct : ++ autofs_ptype_missing_indirect; ++ else ++- type = (sbi->type & AUTOFS_TYPE_DIRECT) ? +++ type = autofs_type_trigger(sbi->type) ? ++ autofs_ptype_expire_direct : ++ autofs_ptype_expire_indirect; ++ } ++ ++ DPRINTK("new wait id = 0x%08lx, name = %.*s, nfy=%d\n", ++- (unsigned long) wq->wait_queue_token, wq->len, wq->name, notify); +++ (unsigned long) wq->wait_queue_token, wq->name.len, +++ wq->name.name, notify); ++ ++ /* autofs4_notify_daemon() may block */ ++ autofs4_notify_daemon(sbi, wq, type); ++ } else { ++- atomic_inc(&wq->wait_ctr); +++ wq->wait_ctr++; ++ mutex_unlock(&sbi->wq_mutex); ++- kfree(name); +++ kfree(qstr.name); ++ DPRINTK("existing wait id = 0x%08lx, name = %.*s, nfy=%d", ++- (unsigned long) wq->wait_queue_token, wq->len, wq->name, notify); +++ (unsigned long) wq->wait_queue_token, wq->name.len, +++ wq->name.name, notify); ++ } ++ ++- /* wq->name is NULL if and only if the lock is already released */ ++- ++- if (sbi->catatonic) { ++- /* We might have slept, so check again for catatonic mode */ ++- wq->status = -ENOENT; ++- kfree(wq->name); ++- wq->name = NULL; ++- } ++- ++- if (wq->name) { +++ /* +++ * wq->name.name is NULL iff the lock is already released +++ * or the mount has been made catatonic. +++ */ +++ if (wq->name.name) { ++ /* Block all but "shutdown" signals while waiting */ ++ sigset_t oldset; ++ unsigned long irqflags; ++@@ -350,7 +439,7 @@ int autofs4_wait(struct autofs_sb_info * ++ recalc_sigpending(); ++ spin_unlock_irqrestore(¤t->sighand->siglock, irqflags); ++ ++- wait_event_interruptible(wq->queue, wq->name == NULL); +++ wait_event_interruptible(wq->queue, wq->name.name == NULL); ++ ++ spin_lock_irqsave(¤t->sighand->siglock, irqflags); ++ current->blocked = oldset; ++@@ -362,9 +451,45 @@ int autofs4_wait(struct autofs_sb_info * ++ ++ status = wq->status; ++ +++ /* +++ * For direct and offset mounts we need to track the requester's +++ * uid and gid in the dentry info struct. This is so it can be +++ * supplied, on request, by the misc device ioctl interface. +++ * This is needed during daemon resatart when reconnecting +++ * to existing, active, autofs mounts. The uid and gid (and +++ * related string values) may be used for macro substitution +++ * in autofs mount maps. +++ */ +++ if (!status) { +++ struct autofs_info *ino; +++ struct dentry *de = NULL; +++ +++ /* direct mount or browsable map */ +++ ino = autofs4_dentry_ino(dentry); +++ if (!ino) { +++ /* If not lookup actual dentry used */ +++ de = d_lookup(dentry->d_parent, &dentry->d_name); +++ if (de) +++ ino = autofs4_dentry_ino(de); +++ } +++ +++ /* Set mount requester */ +++ if (ino) { +++ spin_lock(&sbi->fs_lock); +++ ino->uid = wq->uid; +++ ino->gid = wq->gid; +++ spin_unlock(&sbi->fs_lock); +++ } +++ +++ if (de) +++ dput(de); +++ } +++ ++ /* Are we the last process to need status? */ ++- if (atomic_dec_and_test(&wq->wait_ctr)) +++ mutex_lock(&sbi->wq_mutex); +++ if (!--wq->wait_ctr) ++ kfree(wq); +++ mutex_unlock(&sbi->wq_mutex); ++ ++ return status; ++ } ++@@ -386,16 +511,13 @@ int autofs4_wait_release(struct autofs_s ++ } ++ ++ *wql = wq->next; /* Unlink from chain */ ++- mutex_unlock(&sbi->wq_mutex); ++- kfree(wq->name); ++- wq->name = NULL; /* Do not wait on this queue */ ++- +++ kfree(wq->name.name); +++ wq->name.name = NULL; /* Do not wait on this queue */ ++ wq->status = status; ++- ++- if (atomic_dec_and_test(&wq->wait_ctr)) /* Is anyone still waiting for this guy? */ +++ wake_up_interruptible(&wq->queue); +++ if (!--wq->wait_ctr) ++ kfree(wq); ++- else ++- wake_up_interruptible(&wq->queue); +++ mutex_unlock(&sbi->wq_mutex); ++ ++ return 0; ++ } ++--- linux-2.6.18.orig/fs/autofs/waitq.c +++++ linux-2.6.18/fs/autofs/waitq.c ++@@ -41,6 +41,7 @@ void autofs_catatonic_mode(struct autofs ++ wq = nwq; ++ } ++ fput(sbi->pipe); /* Close the pipe */ +++ sbi->pipe = NULL; ++ autofs_hash_dputall(&sbi->dirhash); /* Remove all dentry pointers */ ++ } ++ ++--- linux-2.6.18.orig/include/linux/auto_fs4.h +++++ linux-2.6.18/include/linux/auto_fs4.h ++@@ -23,12 +23,71 @@ ++ #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 0U +++#define AUTOFS_TYPE_INDIRECT 1U +++#define AUTOFS_TYPE_DIRECT 2U +++#define AUTOFS_TYPE_OFFSET 4U +++ +++static inline void set_autofs_type_indirect(unsigned int *type) +++{ +++ *type = AUTOFS_TYPE_INDIRECT; +++ return; +++} +++ +++static inline unsigned int autofs_type_indirect(unsigned int type) +++{ +++ return (type == AUTOFS_TYPE_INDIRECT); +++} +++ +++static inline void set_autofs_type_direct(unsigned int *type) +++{ +++ *type = AUTOFS_TYPE_DIRECT; +++ return; +++} +++ +++static inline unsigned int autofs_type_direct(unsigned int type) +++{ +++ return (type == AUTOFS_TYPE_DIRECT); +++} +++ +++static inline void set_autofs_type_offset(unsigned int *type) +++{ +++ *type = AUTOFS_TYPE_OFFSET; +++ return; +++} +++ +++static inline unsigned int autofs_type_offset(unsigned int type) +++{ +++ return (type == AUTOFS_TYPE_OFFSET); +++} +++ +++static inline unsigned int autofs_type_trigger(unsigned int type) +++{ +++ return (type == AUTOFS_TYPE_DIRECT || type == AUTOFS_TYPE_OFFSET); +++} +++ +++/* +++ * This isn't really a type as we use it to say "no type set" to +++ * indicate we want to search for "any" mount in the +++ * autofs_dev_ioctl_ismountpoint() device ioctl function. +++ */ +++static inline void set_autofs_type_any(unsigned int *type) +++{ +++ *type = AUTOFS_TYPE_ANY; +++ return; +++} +++ +++static inline unsigned int autofs_type_any(unsigned int type) +++{ +++ return (type == AUTOFS_TYPE_ANY); +++} +++ ++ /* Daemon notification packet types */ ++ enum autofs_notify { ++ NFY_NONE, ++@@ -59,6 +118,13 @@ struct autofs_packet_expire_multi { ++ char name[NAME_MAX+1]; ++ }; ++ +++union autofs_packet_union { +++ struct autofs_packet_hdr hdr; +++ struct autofs_packet_missing missing; +++ struct autofs_packet_expire expire; +++ struct autofs_packet_expire_multi expire_multi; +++}; +++ ++ /* autofs v5 common packet struct */ ++ struct autofs_v5_packet { ++ struct autofs_packet_hdr hdr; ++@@ -78,20 +144,19 @@ typedef struct autofs_v5_packet autofs_p ++ typedef struct autofs_v5_packet autofs_packet_missing_direct_t; ++ typedef struct autofs_v5_packet autofs_packet_expire_direct_t; ++ ++-union autofs_packet_union { +++union autofs_v5_packet_union { ++ struct autofs_packet_hdr hdr; ++- struct autofs_packet_missing missing; ++- struct autofs_packet_expire expire; ++- struct autofs_packet_expire_multi expire_multi; ++ struct autofs_v5_packet v5_packet; +++ autofs_packet_missing_indirect_t missing_indirect; +++ autofs_packet_expire_indirect_t expire_indirect; +++ autofs_packet_missing_direct_t missing_direct; +++ autofs_packet_expire_direct_t expire_direct; ++ }; ++ ++ #define AUTOFS_IOC_EXPIRE_MULTI _IOW(0x93,0x66,int) ++ #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) ++ ++ ++--- linux-2.6.18.orig/fs/autofs4/expire.c +++++ linux-2.6.18/fs/autofs4/expire.c ++@@ -56,12 +56,25 @@ static int autofs4_mount_busy(struct vfs ++ mntget(mnt); ++ dget(dentry); ++ ++- if (!autofs4_follow_mount(&mnt, &dentry)) +++ if (!follow_down(&mnt, &dentry)) ++ goto done; ++ ++- /* This is an autofs submount, we can't expire it */ ++- if (is_autofs4_dentry(dentry)) ++- goto done; +++ if (is_autofs4_dentry(dentry)) { +++ struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); +++ +++ /* This is an autofs submount, we can't expire it */ +++ if (autofs_type_indirect(sbi->type)) +++ goto done; +++ +++ /* +++ * Otherwise it's an offset mount and we need to check +++ * if we can umount its mount, if there is one. +++ */ +++ if (!d_mountpoint(dentry)) { +++ status = 0; +++ goto done; +++ } +++ } ++ ++ /* Update the expiry counter if fs is busy */ ++ if (!may_umount_tree(mnt)) { ++@@ -73,8 +86,8 @@ static int autofs4_mount_busy(struct vfs ++ status = 0; ++ done: ++ DPRINTK("returning = %d", status); ++- mntput(mnt); ++ dput(dentry); +++ mntput(mnt); ++ return status; ++ } ++ ++@@ -244,10 +257,10 @@ cont: ++ } ++ ++ /* Check if we can expire a direct mount (possibly a tree) */ ++-static struct dentry *autofs4_expire_direct(struct super_block *sb, ++- struct vfsmount *mnt, ++- struct autofs_sb_info *sbi, ++- int how) +++struct dentry *autofs4_expire_direct(struct super_block *sb, +++ struct vfsmount *mnt, +++ struct autofs_sb_info *sbi, +++ int how) ++ { ++ unsigned long timeout; ++ struct dentry *root = dget(sb->s_root); ++@@ -259,13 +272,15 @@ static struct dentry *autofs4_expire_dir ++ now = jiffies; ++ timeout = sbi->exp_timeout; ++ ++- /* Lock the tree as we must expire as a whole */ ++ spin_lock(&sbi->fs_lock); ++ if (!autofs4_direct_busy(mnt, root, timeout, do_now)) { ++ struct autofs_info *ino = autofs4_dentry_ino(root); ++- ++- /* Set this flag early to catch sys_chdir and the like */ +++ if (d_mountpoint(root)) { +++ ino->flags |= AUTOFS_INF_MOUNTPOINT; +++ root->d_mounted--; +++ } ++ ino->flags |= AUTOFS_INF_EXPIRING; +++ init_completion(&ino->expire_complete); ++ spin_unlock(&sbi->fs_lock); ++ return root; ++ } ++@@ -281,10 +296,10 @@ static struct dentry *autofs4_expire_dir ++ * - it is unused by any user process ++ * - it has been unused for exp_timeout time ++ */ ++-static struct dentry *autofs4_expire_indirect(struct super_block *sb, ++- struct vfsmount *mnt, ++- struct autofs_sb_info *sbi, ++- int how) +++struct dentry *autofs4_expire_indirect(struct super_block *sb, +++ struct vfsmount *mnt, +++ struct autofs_sb_info *sbi, +++ int how) ++ { ++ unsigned long timeout; ++ struct dentry *root = sb->s_root; ++@@ -292,6 +307,8 @@ static struct dentry *autofs4_expire_ind ++ struct list_head *next; ++ int do_now = how & AUTOFS_EXP_IMMEDIATE; ++ int exp_leaves = how & AUTOFS_EXP_LEAVES; +++ struct autofs_info *ino; +++ unsigned int ino_count; ++ ++ if ( !sbi->exp_timeout || !root ) ++ return NULL; ++@@ -316,6 +333,9 @@ static struct dentry *autofs4_expire_ind ++ dentry = dget(dentry); ++ spin_unlock(&dcache_lock); ++ +++ spin_lock(&sbi->fs_lock); +++ ino = autofs4_dentry_ino(dentry); +++ ++ /* ++ * Case 1: (i) indirect mount or top level pseudo direct mount ++ * (autofs-4.1). ++@@ -326,6 +346,11 @@ static struct dentry *autofs4_expire_ind ++ DPRINTK("checking mountpoint %p %.*s", ++ dentry, (int)dentry->d_name.len, dentry->d_name.name); ++ +++ /* Path walk currently on this dentry? */ +++ ino_count = atomic_read(&ino->count) + 2; +++ if (atomic_read(&dentry->d_count) > ino_count) +++ goto next; +++ ++ /* Can we umount this guy */ ++ if (autofs4_mount_busy(mnt, dentry)) ++ goto next; ++@@ -333,7 +358,7 @@ static struct dentry *autofs4_expire_ind ++ /* Can we expire this guy */ ++ if (autofs4_can_expire(dentry, timeout, do_now)) { ++ expired = dentry; ++- break; +++ goto found; ++ } ++ goto next; ++ } ++@@ -343,46 +368,80 @@ static struct dentry *autofs4_expire_ind ++ ++ /* Case 2: tree mount, expire iff entire tree is not busy */ ++ if (!exp_leaves) { ++- /* Lock the tree as we must expire as a whole */ ++- spin_lock(&sbi->fs_lock); ++- if (!autofs4_tree_busy(mnt, dentry, timeout, do_now)) { ++- struct autofs_info *inf = autofs4_dentry_ino(dentry); +++ /* Path walk currently on this dentry? */ +++ ino_count = atomic_read(&ino->count) + 1; +++ if (atomic_read(&dentry->d_count) > ino_count) +++ goto next; ++ ++- /* Set this flag early to catch sys_chdir and the like */ ++- inf->flags |= AUTOFS_INF_EXPIRING; ++- spin_unlock(&sbi->fs_lock); +++ if (!autofs4_tree_busy(mnt, dentry, timeout, do_now)) { ++ expired = dentry; ++- break; +++ goto found; ++ } ++- spin_unlock(&sbi->fs_lock); ++ /* ++ * Case 3: pseudo direct mount, expire individual leaves ++ * (autofs-4.1). ++ */ ++ } else { +++ /* Path walk currently on this dentry? */ +++ ino_count = atomic_read(&ino->count) + 1; +++ if (atomic_read(&dentry->d_count) > ino_count) +++ goto next; +++ ++ expired = autofs4_check_leaves(mnt, dentry, timeout, do_now); ++ if (expired) { ++ dput(dentry); ++- break; +++ goto found; ++ } ++ } ++ next: +++ spin_unlock(&sbi->fs_lock); ++ dput(dentry); ++ spin_lock(&dcache_lock); ++ next = next->next; ++ } +++ spin_unlock(&dcache_lock); +++ return NULL; ++ ++- if (expired) { ++- DPRINTK("returning %p %.*s", ++- expired, (int)expired->d_name.len, expired->d_name.name); ++- spin_lock(&dcache_lock); ++- list_move(&expired->d_parent->d_subdirs, &expired->d_u.d_child); ++- spin_unlock(&dcache_lock); ++- return expired; ++- } +++found: +++ DPRINTK("returning %p %.*s", +++ expired, (int)expired->d_name.len, expired->d_name.name); +++ ino = autofs4_dentry_ino(expired); +++ ino->flags |= AUTOFS_INF_EXPIRING; +++ init_completion(&ino->expire_complete); +++ spin_unlock(&sbi->fs_lock); +++ spin_lock(&dcache_lock); +++ list_move(&expired->d_parent->d_subdirs, &expired->d_u.d_child); ++ spin_unlock(&dcache_lock); +++ return expired; +++} ++ ++- return NULL; +++int autofs4_expire_wait(struct dentry *dentry) +++{ +++ struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); +++ struct autofs_info *ino = autofs4_dentry_ino(dentry); +++ int status; +++ +++ /* Block on any pending expire */ +++ spin_lock(&sbi->fs_lock); +++ if (ino->flags & AUTOFS_INF_EXPIRING) { +++ spin_unlock(&sbi->fs_lock); +++ +++ DPRINTK("waiting for expire %p name=%.*s", +++ dentry, dentry->d_name.len, dentry->d_name.name); +++ +++ status = autofs4_wait(sbi, dentry, NFY_NONE); +++ wait_for_completion(&ino->expire_complete); +++ +++ DPRINTK("expire done status=%d", status); +++ +++ if (d_unhashed(dentry)) +++ return -EAGAIN; +++ +++ return status; +++ } +++ spin_unlock(&sbi->fs_lock); +++ +++ return 0; ++ } ++ ++ /* Perform an expiry operation */ ++@@ -392,7 +451,9 @@ int autofs4_expire_run(struct super_bloc ++ struct autofs_packet_expire __user *pkt_p) ++ { ++ struct autofs_packet_expire pkt; +++ struct autofs_info *ino; ++ struct dentry *dentry; +++ int ret = 0; ++ ++ memset(&pkt,0,sizeof pkt); ++ ++@@ -408,9 +469,15 @@ int autofs4_expire_run(struct super_bloc ++ dput(dentry); ++ ++ if ( copy_to_user(pkt_p, &pkt, sizeof(struct autofs_packet_expire)) ) ++- return -EFAULT; +++ ret = -EFAULT; ++ ++- return 0; +++ spin_lock(&sbi->fs_lock); +++ ino = autofs4_dentry_ino(dentry); +++ ino->flags &= ~AUTOFS_INF_EXPIRING; +++ complete_all(&ino->expire_complete); +++ spin_unlock(&sbi->fs_lock); +++ +++ return ret; ++ } ++ ++ /* Call repeatedly until it returns -EAGAIN, meaning there's nothing ++@@ -425,7 +492,7 @@ int autofs4_expire_multi(struct super_bl ++ if (arg && get_user(do_now, arg)) ++ return -EFAULT; ++ ++- if (sbi->type & AUTOFS_TYPE_DIRECT) +++ if (autofs_type_trigger(sbi->type)) ++ dentry = autofs4_expire_direct(sb, mnt, sbi, do_now); ++ else ++ dentry = autofs4_expire_indirect(sb, mnt, sbi, do_now); ++@@ -435,9 +502,16 @@ int autofs4_expire_multi(struct super_bl ++ ++ /* This is synchronous because it makes the daemon a ++ little easier */ ++- ino->flags |= AUTOFS_INF_EXPIRING; ++ ret = autofs4_wait(sbi, dentry, NFY_EXPIRE); +++ +++ spin_lock(&sbi->fs_lock); +++ if (ino->flags & AUTOFS_INF_MOUNTPOINT) { +++ sb->s_root->d_mounted++; +++ ino->flags &= ~AUTOFS_INF_MOUNTPOINT; +++ } ++ ino->flags &= ~AUTOFS_INF_EXPIRING; +++ complete_all(&ino->expire_complete); +++ spin_unlock(&sbi->fs_lock); ++ dput(dentry); ++ } ++ ++--- linux-2.6.18.orig/include/linux/compat_ioctl.h +++++ linux-2.6.18/include/linux/compat_ioctl.h ++@@ -565,8 +565,6 @@ COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOVER) ++ COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE) ++ COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE_MULTI) ++ COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOSUBVER) ++-COMPATIBLE_IOCTL(AUTOFS_IOC_ASKREGHOST) ++-COMPATIBLE_IOCTL(AUTOFS_IOC_TOGGLEREGHOST) ++ COMPATIBLE_IOCTL(AUTOFS_IOC_ASKUMOUNT) ++ /* Raw devices */ ++ COMPATIBLE_IOCTL(RAW_SETBIND) ++--- /dev/null +++++ linux-2.6.18/Documentation/filesystems/autofs4-mount-control.txt ++@@ -0,0 +1,414 @@ +++ +++Miscellaneous Device control operations for the autofs4 kernel module +++==================================================================== +++ +++The problem +++=========== +++ +++There is a problem with active restarts in autofs (that is to say +++restarting autofs when there are busy mounts). +++ +++During normal operation autofs uses a file descriptor opened on the +++directory that is being managed in order to be able to issue control +++operations. Using a file descriptor gives ioctl operations access to +++autofs specific information stored in the super block. The operations +++are things such as setting an autofs mount catatonic, setting the +++expire timeout and requesting expire checks. As is explained below, +++certain types of autofs triggered mounts can end up covering an autofs +++mount itself which prevents us being able to use open(2) to obtain a +++file descriptor for these operations if we don't already have one open. +++ +++Currently autofs uses "umount -l" (lazy umount) to clear active mounts +++at restart. While using lazy umount works for most cases, anything that +++needs to walk back up the mount tree to construct a path, such as +++getcwd(2) and the proc file system /proc//cwd, no longer works +++because the point from which the path is constructed has been detached +++from the mount tree. +++ +++The actual problem with autofs is that it can't reconnect to existing +++mounts. Immediately one thinks of just adding the ability to remount +++autofs file systems would solve it, but alas, that can't work. This is +++because autofs direct mounts and the implementation of "on demand mount +++and expire" of nested mount trees have the file system mounted directly +++on top of the mount trigger directory dentry. +++ +++For example, there are two types of automount maps, direct (in the kernel +++module source you will see a third type called an offset, which is just +++a direct mount in disguise) and indirect. +++ +++Here is a master map with direct and indirect map entries: +++ +++/- /etc/auto.direct +++/test /etc/auto.indirect +++ +++and the corresponding map files: +++ +++/etc/auto.direct: +++ +++/automount/dparse/g6 budgie:/autofs/export1 +++/automount/dparse/g1 shark:/autofs/export1 +++and so on. +++ +++/etc/auto.indirect: +++ +++g1 shark:/autofs/export1 +++g6 budgie:/autofs/export1 +++and so on. +++ +++For the above indirect map an autofs file system is mounted on /test and +++mounts are triggered for each sub-directory key by the inode lookup +++operation. So we see a mount of shark:/autofs/export1 on /test/g1, for +++example. +++ +++The way that direct mounts are handled is by making an autofs mount on +++each full path, such as /automount/dparse/g1, and using it as a mount +++trigger. So when we walk on the path we mount shark:/autofs/export1 "on +++top of this mount point". Since these are always directories we can +++use the follow_link inode operation to trigger the mount. +++ +++But, each entry in direct and indirect maps can have offsets (making +++them multi-mount map entries). +++ +++For example, an indirect mount map entry could also be: +++ +++g1 \ +++ / shark:/autofs/export5/testing/test \ +++ /s1 shark:/autofs/export/testing/test/s1 \ +++ /s2 shark:/autofs/export5/testing/test/s2 \ +++ /s1/ss1 shark:/autofs/export1 \ +++ /s2/ss2 shark:/autofs/export2 +++ +++and a similarly a direct mount map entry could also be: +++ +++/automount/dparse/g1 \ +++ / shark:/autofs/export5/testing/test \ +++ /s1 shark:/autofs/export/testing/test/s1 \ +++ /s2 shark:/autofs/export5/testing/test/s2 \ +++ /s1/ss1 shark:/autofs/export2 \ +++ /s2/ss2 shark:/autofs/export2 +++ +++One of the issues with version 4 of autofs was that, when mounting an +++entry with a large number of offsets, possibly with nesting, we needed +++to mount and umount all of the offsets as a single unit. Not really a +++problem, except for people with a large number of offsets in map entries. +++This mechanism is used for the well known "hosts" map and we have seen +++cases (in 2.4) where the available number of mounts are exhausted or +++where the number of privileged ports available is exhausted. +++ +++In version 5 we mount only as we go down the tree of offsets and +++similarly for expiring them which resolves the above problem. There is +++somewhat more detail to the implementation but it isn't needed for the +++sake of the problem explanation. The one important detail is that these +++offsets are implemented using the same mechanism as the direct mounts +++above and so the mount points can be covered by a mount. +++ +++The current autofs implementation uses an ioctl file descriptor opened +++on the mount point for control operations. The references held by the +++descriptor are accounted for in checks made to determine if a mount is +++in use and is also used to access autofs file system information held +++in the mount super block. So the use of a file handle needs to be +++retained. +++ +++ +++The Solution +++============ +++ +++To be able to restart autofs leaving existing direct, indirect and +++offset mounts in place we need to be able to obtain a file handle +++for these potentially covered autofs mount points. Rather than just +++implement an isolated operation it was decided to re-implement the +++existing ioctl interface and add new operations to provide this +++functionality. +++ +++In addition, to be able to reconstruct a mount tree that has busy mounts, +++the uid and gid of the last user that triggered the mount needs to be +++available because these can be used as macro substitution variables in +++autofs maps. They are recorded at mount request time and an operation +++has been added to retrieve them. +++ +++Since we're re-implementing the control interface, a couple of other +++problems with the existing interface have been addressed. First, when +++a mount or expire operation completes a status is returned to the +++kernel by either a "send ready" or a "send fail" operation. The +++"send fail" operation of the ioctl interface could only ever send +++ENOENT so the re-implementation allows user space to send an actual +++status. Another expensive operation in user space, for those using +++very large maps, is discovering if a mount is present. Usually this +++involves scanning /proc/mounts and since it needs to be done quite +++often it can introduce significant overhead when there are many entries +++in the mount table. An operation to lookup the mount status of a mount +++point dentry (covered or not) has also been added. +++ +++Current kernel development policy recommends avoiding the use of the +++ioctl mechanism in favor of systems such as Netlink. An implementation +++using this system was attempted to evaluate its suitability and it was +++found to be inadequate, in this case. The Generic Netlink system was +++used for this as raw Netlink would lead to a significant increase in +++complexity. There's no question that the Generic Netlink system is an +++elegant solution for common case ioctl functions but it's not a complete +++replacement probably because it's primary purpose in life is to be a +++message bus implementation rather than specifically an ioctl replacement. +++While it would be possible to work around this there is one concern +++that lead to the decision to not use it. This is that the autofs +++expire in the daemon has become far to complex because umount +++candidates are enumerated, almost for no other reason than to "count" +++the number of times to call the expire ioctl. This involves scanning +++the mount table which has proved to be a big overhead for users with +++large maps. The best way to improve this is try and get back to the +++way the expire was done long ago. That is, when an expire request is +++issued for a mount (file handle) we should continually call back to +++the daemon until we can't umount any more mounts, then return the +++appropriate status to the daemon. At the moment we just expire one +++mount at a time. A Generic Netlink implementation would exclude this +++possibility for future development due to the requirements of the +++message bus architecture. +++ +++ +++autofs4 Miscellaneous Device mount control interface +++==================================================== +++ +++The control interface is opening a device node, typically /dev/autofs. +++ +++All the ioctls use a common structure to pass the needed parameter +++information and return operation results: +++ +++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]; +++}; +++ +++The ioctlfd field is a mount point file descriptor of an autofs mount +++point. It is returned by the open call and is used by all calls except +++the check for whether a given path is a mount point, where it may +++optionally be used to check a specific mount corresponding to a given +++mount point file descriptor, and when requesting the uid and gid of the +++last successful mount on a directory within the autofs file system. +++ +++The anonymous union is used to communicate parameters and results of calls +++made as described below. +++ +++The path field is used to pass a path where it is needed and the size field +++is used account for the increased structure length when translating the +++structure sent from user space. +++ +++This structure can be initialized before setting specific fields by using +++the void function call init_autofs_dev_ioctl(struct autofs_dev_ioctl *). +++ +++All of the ioctls perform a copy of this structure from user space to +++kernel space and return -EINVAL if the size parameter is smaller than +++the structure size itself, -ENOMEM if the kernel memory allocation fails +++or -EFAULT if the copy itself fails. Other checks include a version check +++of the compiled in user space version against the module version and a +++mismatch results in a -EINVAL return. If the size field is greater than +++the structure size then a path is assumed to be present and is checked to +++ensure it begins with a "/" and is NULL terminated, otherwise -EINVAL is +++returned. Following these checks, for all ioctl commands except +++AUTOFS_DEV_IOCTL_VERSION_CMD, AUTOFS_DEV_IOCTL_OPENMOUNT_CMD and +++AUTOFS_DEV_IOCTL_CLOSEMOUNT_CMD the ioctlfd is validated and if it is +++not a valid descriptor or doesn't correspond to an autofs mount point +++an error of -EBADF, -ENOTTY or -EINVAL (not an autofs descriptor) is +++returned. +++ +++ +++The ioctls +++========== +++ +++An example of an implementation which uses this interface can be seen +++in autofs version 5.0.4 and later in file lib/dev-ioctl-lib.c of the +++distribution tar available for download from kernel.org in directory +++/pub/linux/daemons/autofs/v5. +++ +++The device node ioctl operations implemented by this interface are: +++ +++ +++AUTOFS_DEV_IOCTL_VERSION +++------------------------ +++ +++Get the major and minor version of the autofs4 device ioctl kernel module +++implementation. It requires an initialized struct autofs_dev_ioctl as an +++input parameter and sets the version information in the passed in structure. +++It returns 0 on success or the error -EINVAL if a version mismatch is +++detected. +++ +++ +++AUTOFS_DEV_IOCTL_PROTOVER_CMD and AUTOFS_DEV_IOCTL_PROTOSUBVER_CMD +++------------------------------------------------------------------ +++ +++Get the major and minor version of the autofs4 protocol version understood +++by loaded module. This call requires an initialized struct autofs_dev_ioctl +++with the ioctlfd field set to a valid autofs mount point descriptor +++and sets the requested version number in structure field protover.version +++and ptotosubver.sub_version respectively. These commands return 0 on +++success or one of the negative error codes if validation fails. +++ +++ +++AUTOFS_DEV_IOCTL_OPENMOUNT_CMD and AUTOFS_DEV_IOCTL_CLOSEMOUNT_CMD +++------------------------------------------------------------------ +++ +++Obtain and release a file descriptor for an autofs managed mount point +++path. The open call requires an initialized struct autofs_dev_ioctl with +++the the path field set and the size field adjusted appropriately as well +++as the openmount.devid field set to the device number of the autofs mount. +++The device number of an autofs mounted filesystem can be obtained by using +++the AUTOFS_DEV_IOCTL_ISMOUNTPOINT ioctl function by providing the path +++and autofs mount type, as described below. The close call requires an +++initialized struct autofs_dev_ioct with the ioctlfd field set to the +++descriptor obtained from the open call. The release of the file descriptor +++can also be done with close(2) so any open descriptors will also be +++closed at process exit. The close call is included in the implemented +++operations largely for completeness and to provide for a consistent +++user space implementation. +++ +++ +++AUTOFS_DEV_IOCTL_READY_CMD and AUTOFS_DEV_IOCTL_FAIL_CMD +++-------------------------------------------------------- +++ +++Return mount and expire result status from user space to the kernel. +++Both of these calls require an initialized struct autofs_dev_ioctl +++with the ioctlfd field set to the descriptor obtained from the open +++call and the ready.token or fail.token field set to the wait queue +++token number, received by user space in the foregoing mount or expire +++request. The fail.status field is set to the status to be returned when +++sending a failure notification with AUTOFS_DEV_IOCTL_FAIL_CMD. +++ +++ +++AUTOFS_DEV_IOCTL_SETPIPEFD_CMD +++------------------------------ +++ +++Set the pipe file descriptor used for kernel communication to the daemon. +++Normally this is set at mount time using an option but when reconnecting +++to a existing mount we need to use this to tell the autofs mount about +++the new kernel pipe descriptor. In order to protect mounts against +++incorrectly setting the pipe descriptor we also require that the autofs +++mount be catatonic (see next call). +++ +++The call requires an initialized struct autofs_dev_ioctl with the +++ioctlfd field set to the descriptor obtained from the open call and +++the setpipefd.pipefd field set to descriptor of the pipe. On success +++the call also sets the process group id used to identify the controlling +++process (eg. the owning automount(8) daemon) to the process group of +++the caller. +++ +++ +++AUTOFS_DEV_IOCTL_CATATONIC_CMD +++------------------------------ +++ +++Make the autofs mount point catatonic. The autofs mount will no longer +++issue mount requests, the kernel communication pipe descriptor is released +++and any remaining waits in the queue released. +++ +++The call requires an initialized struct autofs_dev_ioctl with the +++ioctlfd field set to the descriptor obtained from the open call. +++ +++ +++AUTOFS_DEV_IOCTL_TIMEOUT_CMD +++---------------------------- +++ +++Set the expire timeout for mounts withing an autofs mount point. +++ +++The call requires an initialized struct autofs_dev_ioctl with the +++ioctlfd field set to the descriptor obtained from the open call. +++The timeout.timeout field is set to the desired timeout and this +++field is set to the value of the value of the current timeout of +++the mount upon successful completion. +++ +++ +++AUTOFS_DEV_IOCTL_REQUESTER_CMD +++------------------------------ +++ +++Return the uid and gid of the last process to successfully trigger a the +++mount on the given path dentry. +++ +++The call requires an initialized struct autofs_dev_ioctl with the path +++field set to the mount point in question and the size field adjusted +++appropriately as well as the ioctlfd field set to the descriptor obtained +++from the open call. Upon return the struct fields requester.uid and +++requester.gid contain the uid and gid respectively. +++ +++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. +++This call provides the ability to obtain this uid and gid so they may be +++used by user space for the mount map lookups. +++ +++ +++AUTOFS_DEV_IOCTL_EXPIRE_CMD +++--------------------------- +++ +++Issue an expire request to the kernel for an autofs mount. Typically +++this ioctl is called until no further expire candidates are found. +++ +++The call requires an initialized struct autofs_dev_ioctl with the +++ioctlfd field set to the descriptor obtained from the open call. In +++addition an immediate expire, independent of the mount timeout, can be +++requested by setting the expire.how field to 1. If no expire candidates +++can be found the ioctl returns -1 with errno set to EAGAIN. +++ +++This call causes the kernel module to check the mount corresponding +++to the given ioctlfd for mounts that can be expired, issues an expire +++request back to the daemon and waits for completion. +++ +++AUTOFS_DEV_IOCTL_ASKUMOUNT_CMD +++------------------------------ +++ +++Checks if an autofs mount point is in use. +++ +++The call requires an initialized struct autofs_dev_ioctl with the +++ioctlfd field set to the descriptor obtained from the open call and +++it returns the result in the askumount.may_umount field, 1 for busy +++and 0 otherwise. +++ +++ +++AUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD +++--------------------------------- +++ +++Check if the given path is a mountpoint. +++ +++The call requires an initialized struct autofs_dev_ioctl. There are two +++possible variations. Both use the path field set to the path of the mount +++point to check and the size field must be adjusted appropriately. One uses +++the ioctlfd field to identify a specific mount point to check while the +++other variation uses the path and optionaly the ismountpoint.in.type +++field set to an autofs mount type. The call returns 1 if this is a mount +++point and sets the ismountpoint.out.devid field to the device number of +++the mount and the ismountpoint.out.magic field to the relevant super +++block magic number (described below) or 0 if it isn't a mountpoint. In +++both cases the the device number (as returned by new_encode_dev()) is +++returned in the ismountpoint.out.devid field. +++ +++If supplied with a file descriptor we're looking for a specific mount, +++not necessarily at the top of the mounted stack. In this case the path +++the descriptor corresponds to is considered a mountpoint if it is itself +++a mountpoint or contains a mount, such as a multi-mount without a root +++mount. In this case we return 1 if the descriptor corresponds to a mount +++point and and also returns the super magic of the covering mount if there +++is one or 0 if it isn't a mountpoint. +++ +++If a path is supplied (and the ioctlfd field is set to -1) then the path +++is looked up and is checked to see if it is the root of a mount. If a +++type is also given we are looking for a particular autofs mount and if +++a match isn't found a fail is returned. If the the located path is the +++root of a mount 1 is returned along with the super magic of the mount +++or 0 otherwise. +++ ++--- linux-2.6.18.orig/fs/autofs4/Makefile +++++ linux-2.6.18/fs/autofs4/Makefile ++@@ -4,4 +4,4 @@ ++ ++ obj-$(CONFIG_AUTOFS4_FS) += autofs4.o ++ ++-autofs4-objs := init.o inode.o root.o symlink.o waitq.o expire.o +++autofs4-objs := init.o inode.o root.o symlink.o waitq.o expire.o dev-ioctl.o ++--- /dev/null +++++ linux-2.6.18/fs/autofs4/dev-ioctl.c ++@@ -0,0 +1,867 @@ +++/* +++ * Copyright 2008 Red Hat, Inc. All rights reserved. +++ * Copyright 2008 Ian Kent +++ * +++ * 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. +++ */ +++ +++#include +++#include +++#include +++#include +++#include +++#include +++#include +++#include +++#include +++#include +++#include +++#include +++#include +++#include +++#include +++ +++#include "autofs_i.h" +++ +++/* +++ * This module implements an interface for routing autofs ioctl control +++ * commands via a miscellaneous device file. +++ * +++ * The alternate interface is needed because we need to be able open +++ * an ioctl file descriptor on an autofs mount that may be covered by +++ * another mount. This situation arises when starting automount(8) +++ * or other user space daemon which uses direct mounts or offset +++ * mounts (used for autofs lazy mount/umount of nested mount trees), +++ * which have been left busy at at service shutdown. +++ */ +++ +++#define AUTOFS_DEV_IOCTL_SIZE sizeof(struct autofs_dev_ioctl) +++ +++typedef int (*ioctl_fn)(struct file *, +++struct autofs_sb_info *, struct autofs_dev_ioctl *); +++ +++static int check_name(const char *name) +++{ +++ if (!strchr(name, '/')) +++ return -EINVAL; +++ return 0; +++} +++ +++/* +++ * Check a string doesn't overrun the chunk of +++ * memory we copied from user land. +++ */ +++static int invalid_str(char *str, void *end) +++{ +++ while ((void *) str <= end) +++ if (!*str++) +++ return 0; +++ return -EINVAL; +++} +++ +++/* +++ * Check that the user compiled against correct version of autofs +++ * misc device code. +++ * +++ * As well as checking the version compatibility this always copies +++ * the kernel interface version out. +++ */ +++static int check_dev_ioctl_version(int cmd, struct autofs_dev_ioctl *param) +++{ +++ int err = 0; +++ +++ if ((AUTOFS_DEV_IOCTL_VERSION_MAJOR != param->ver_major) || +++ (AUTOFS_DEV_IOCTL_VERSION_MINOR < param->ver_minor)) { +++ AUTOFS_WARN("ioctl control interface version mismatch: " +++ "kernel(%u.%u), user(%u.%u), cmd(%d)", +++ AUTOFS_DEV_IOCTL_VERSION_MAJOR, +++ AUTOFS_DEV_IOCTL_VERSION_MINOR, +++ param->ver_major, param->ver_minor, cmd); +++ err = -EINVAL; +++ } +++ +++ /* Fill in the kernel version. */ +++ param->ver_major = AUTOFS_DEV_IOCTL_VERSION_MAJOR; +++ param->ver_minor = AUTOFS_DEV_IOCTL_VERSION_MINOR; +++ +++ return err; +++} +++ +++/* +++ * Copy parameter control struct, including a possible path allocated +++ * at the end of the struct. +++ */ +++static struct autofs_dev_ioctl *copy_dev_ioctl(struct autofs_dev_ioctl __user *in) +++{ +++ struct autofs_dev_ioctl tmp, *ads; +++ +++ if (copy_from_user(&tmp, in, sizeof(tmp))) +++ return ERR_PTR(-EFAULT); +++ +++ if (tmp.size < sizeof(tmp)) +++ return ERR_PTR(-EINVAL); +++ +++ ads = kmalloc(tmp.size, GFP_KERNEL); +++ if (!ads) +++ return ERR_PTR(-ENOMEM); +++ +++ if (copy_from_user(ads, in, tmp.size)) { +++ kfree(ads); +++ return ERR_PTR(-EFAULT); +++ } +++ +++ return ads; +++} +++ +++static inline void free_dev_ioctl(struct autofs_dev_ioctl *param) +++{ +++ kfree(param); +++ return; +++} +++ +++/* +++ * Check sanity of parameter control fields and if a path is present +++ * check that it is terminated and contains at least one "/". +++ */ +++static int validate_dev_ioctl(int cmd, struct autofs_dev_ioctl *param) +++{ +++ int err; +++ +++ if ((err = check_dev_ioctl_version(cmd, param))) { +++ AUTOFS_WARN("invalid device control module version " +++ "supplied for cmd(0x%08x)", cmd); +++ goto out; +++ } +++ +++ if (param->size > sizeof(*param)) { +++ err = invalid_str(param->path, +++ (void *) ((size_t) param + param->size)); +++ if (err) { +++ AUTOFS_WARN( +++ "path string terminator missing for cmd(0x%08x)", +++ cmd); +++ goto out; +++ } +++ +++ err = check_name(param->path); +++ if (err) { +++ AUTOFS_WARN("invalid path supplied for cmd(0x%08x)", +++ cmd); +++ goto out; +++ } +++ } +++ +++ err = 0; +++out: +++ return err; +++} +++ +++/* +++ * Get the autofs super block info struct from the file opened on +++ * the autofs mount point. +++ */ +++static struct autofs_sb_info *autofs_dev_ioctl_sbi(struct file *f) +++{ +++ struct autofs_sb_info *sbi = NULL; +++ struct inode *inode; +++ +++ if (f) { +++ inode = f->f_dentry->d_inode; +++ sbi = autofs4_sbi(inode->i_sb); +++ } +++ return sbi; +++} +++ +++/* Return autofs module protocol version */ +++static int autofs_dev_ioctl_protover(struct file *fp, +++ struct autofs_sb_info *sbi, +++ struct autofs_dev_ioctl *param) +++{ +++ param->protover.version = sbi->version; +++ return 0; +++} +++ +++/* Return autofs module protocol sub version */ +++static int autofs_dev_ioctl_protosubver(struct file *fp, +++ struct autofs_sb_info *sbi, +++ struct autofs_dev_ioctl *param) +++{ +++ param->protosubver.sub_version = sbi->sub_version; +++ return 0; +++} +++ +++/* +++ * Walk down the mount stack looking for an autofs mount that +++ * has the requested device number (aka. new_encode_dev(sb->s_dev). +++ */ +++static int autofs_dev_ioctl_find_super(struct nameidata *nd, dev_t devno) +++{ +++ struct dentry *dentry; +++ struct inode *inode; +++ struct super_block *sb; +++ dev_t s_dev; +++ unsigned int err; +++ +++ err = -ENOENT; +++ +++ /* Lookup the dentry name at the base of our mount point */ +++ dentry = d_lookup(nd->dentry, &nd->last); +++ if (!dentry) +++ goto out; +++ +++ dput(nd->dentry); +++ nd->dentry = dentry; +++ +++ /* And follow the mount stack looking for our autofs mount */ +++ while (follow_down(&nd->mnt, &nd->dentry)) { +++ inode = nd->dentry->d_inode; +++ if (!inode) +++ break; +++ +++ sb = inode->i_sb; +++ s_dev = new_encode_dev(sb->s_dev); +++ if (devno == s_dev) { +++ if (sb->s_magic == AUTOFS_SUPER_MAGIC) { +++ err = 0; +++ break; +++ } +++ } +++ } +++out: +++ return err; +++} +++ +++/* +++ * Walk down the mount stack looking for an autofs mount that +++ * has the requested mount type (ie. indirect, direct or offset). +++ */ +++static int autofs_dev_ioctl_find_sbi_type(struct nameidata *nd, unsigned int type) +++{ +++ struct dentry *dentry; +++ struct autofs_info *ino; +++ unsigned int err; +++ +++ err = -ENOENT; +++ +++ /* Lookup the dentry name at the base of our mount point */ +++ dentry = d_lookup(nd->dentry, &nd->last); +++ if (!dentry) +++ goto out; +++ +++ dput(nd->dentry); +++ nd->dentry = dentry; +++ +++ /* And follow the mount stack looking for our autofs mount */ +++ while (follow_down(&nd->mnt, &nd->dentry)) { +++ ino = autofs4_dentry_ino(nd->dentry); +++ if (ino && ino->sbi->type & type) { +++ err = 0; +++ break; +++ } +++ } +++out: +++ return err; +++} +++ +++static void autofs_dev_ioctl_fd_install(unsigned int fd, struct file *file) +++{ +++ struct files_struct *files = current->files; +++ struct fdtable *fdt; +++ +++ spin_lock(&files->file_lock); +++ fdt = files_fdtable(files); +++ BUG_ON(fdt->fd[fd] != NULL); +++ rcu_assign_pointer(fdt->fd[fd], file); +++ FD_SET(fd, fdt->close_on_exec); +++ spin_unlock(&files->file_lock); +++} +++ +++ +++/* +++ * Open a file descriptor on the autofs mount point corresponding +++ * to the given path and device number (aka. new_encode_dev(sb->s_dev)). +++ */ +++static int autofs_dev_ioctl_open_mountpoint(const char *path, dev_t devid) +++{ +++ struct file *filp; +++ struct nameidata nd; +++ int err, fd; +++ +++ fd = get_unused_fd(); +++ if (likely(fd >= 0)) { +++ /* Get nameidata of the parent directory */ +++ err = path_lookup(path, LOOKUP_PARENT, &nd); +++ if (err) +++ goto out; +++ +++ /* +++ * Search down, within the parent, looking for an +++ * autofs super block that has the device number +++ * corresponding to the autofs fs we want to open. +++ */ +++ err = autofs_dev_ioctl_find_super(&nd, devid); +++ if (err) { +++ path_release(&nd); +++ goto out; +++ } +++ +++ filp = dentry_open(nd.dentry, nd.mnt, O_RDONLY); +++ if (IS_ERR(filp)) { +++ err = PTR_ERR(filp); +++ goto out; +++ } +++ +++ autofs_dev_ioctl_fd_install(fd, filp); +++ } +++ +++ return fd; +++ +++out: +++ put_unused_fd(fd); +++ return err; +++} +++ +++/* Open a file descriptor on an autofs mount point */ +++static int autofs_dev_ioctl_openmount(struct file *fp, +++ struct autofs_sb_info *sbi, +++ struct autofs_dev_ioctl *param) +++{ +++ const char *path; +++ dev_t devid; +++ int err, fd; +++ +++ /* param->path has already been checked */ +++ if (!param->openmount.devid) +++ return -EINVAL; +++ +++ param->ioctlfd = -1; +++ +++ path = param->path; +++ devid = param->openmount.devid; +++ +++ err = 0; +++ fd = autofs_dev_ioctl_open_mountpoint(path, devid); +++ if (unlikely(fd < 0)) { +++ err = fd; +++ goto out; +++ } +++ +++ param->ioctlfd = fd; +++out: +++ return err; +++} +++ +++/* Close file descriptor allocated above (user can also use close(2)). */ +++static int autofs_dev_ioctl_closemount(struct file *fp, +++ struct autofs_sb_info *sbi, +++ struct autofs_dev_ioctl *param) +++{ +++ return sys_close(param->ioctlfd); +++} +++ +++/* +++ * Send "ready" status for an existing wait (either a mount or an expire +++ * request). +++ */ +++static int autofs_dev_ioctl_ready(struct file *fp, +++ struct autofs_sb_info *sbi, +++ struct autofs_dev_ioctl *param) +++{ +++ autofs_wqt_t token; +++ +++ token = (autofs_wqt_t) param->ready.token; +++ return autofs4_wait_release(sbi, token, 0); +++} +++ +++/* +++ * Send "fail" status for an existing wait (either a mount or an expire +++ * request). +++ */ +++static int autofs_dev_ioctl_fail(struct file *fp, +++ struct autofs_sb_info *sbi, +++ struct autofs_dev_ioctl *param) +++{ +++ autofs_wqt_t token; +++ int status; +++ +++ token = (autofs_wqt_t) param->fail.token; +++ status = param->fail.status ? param->fail.status : -ENOENT; +++ return autofs4_wait_release(sbi, token, status); +++} +++ +++/* +++ * Set the pipe fd for kernel communication to the daemon. +++ * +++ * 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 mount about the new kernel pipe fd. In +++ * order to protect mounts against incorrectly setting the +++ * pipefd we also require that the autofs mount be catatonic. +++ * +++ * This also sets the process group id used to identify the +++ * controlling process (eg. the owning automount(8) daemon). +++ */ +++static int autofs_dev_ioctl_setpipefd(struct file *fp, +++ struct autofs_sb_info *sbi, +++ struct autofs_dev_ioctl *param) +++{ +++ int pipefd; +++ int err = 0; +++ +++ if (param->setpipefd.pipefd == -1) +++ return -EINVAL; +++ +++ pipefd = param->setpipefd.pipefd; +++ +++ mutex_lock(&sbi->wq_mutex); +++ if (!sbi->catatonic) { +++ mutex_unlock(&sbi->wq_mutex); +++ return -EBUSY; +++ } else { +++ struct file *pipe = fget(pipefd); +++ if (!pipe->f_op || !pipe->f_op->write) { +++ err = -EPIPE; +++ fput(pipe); +++ goto out; +++ } +++ sbi->oz_pgrp = process_group(current); +++ sbi->pipefd = pipefd; +++ sbi->pipe = pipe; +++ sbi->catatonic = 0; +++ } +++out: +++ mutex_unlock(&sbi->wq_mutex); +++ return err; +++} +++ +++/* +++ * Make the autofs mount point catatonic, no longer responsive to +++ * mount requests. Also closes the kernel pipe file descriptor. +++ */ +++static int autofs_dev_ioctl_catatonic(struct file *fp, +++ struct autofs_sb_info *sbi, +++ struct autofs_dev_ioctl *param) +++{ +++ autofs4_catatonic_mode(sbi); +++ return 0; +++} +++ +++/* Set the autofs mount timeout */ +++static int autofs_dev_ioctl_timeout(struct file *fp, +++ struct autofs_sb_info *sbi, +++ struct autofs_dev_ioctl *param) +++{ +++ unsigned long timeout; +++ +++ timeout = param->timeout.timeout; +++ param->timeout.timeout = sbi->exp_timeout / HZ; +++ sbi->exp_timeout = timeout * HZ; +++ return 0; +++} +++ +++/* +++ * Return the uid and gid of the last request for the mount +++ * +++ * 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 autofs_dev_ioctl_requester(struct file *fp, +++ struct autofs_sb_info *sbi, +++ struct autofs_dev_ioctl *param) +++{ +++ struct autofs_info *ino; +++ struct nameidata nd; +++ const char *path; +++ dev_t devid; +++ int err = -ENOENT; +++ +++ if (param->size <= sizeof(*param)) { +++ err = -EINVAL; +++ goto out; +++ } +++ +++ path = param->path; +++ devid = sbi->sb->s_dev; +++ +++ param->requester.uid = param->requester.gid = -1; +++ +++ /* Get nameidata of the parent directory */ +++ err = path_lookup(path, LOOKUP_PARENT, &nd); +++ if (err) +++ goto out; +++ +++ err = autofs_dev_ioctl_find_super(&nd, devid); +++ if (err) +++ goto out_release; +++ +++ ino = autofs4_dentry_ino(nd.dentry); +++ if (ino) { +++ err = 0; +++ autofs4_expire_wait(nd.dentry); +++ spin_lock(&sbi->fs_lock); +++ param->requester.uid = ino->uid; +++ param->requester.gid = ino->gid; +++ spin_unlock(&sbi->fs_lock); +++ } +++ +++out_release: +++ path_release(&nd); +++out: +++ return err; +++} +++ +++/* +++ * Call repeatedly until it returns -EAGAIN, meaning there's nothing +++ * more that can be done. +++ */ +++static int autofs_dev_ioctl_expire(struct file *fp, +++ struct autofs_sb_info *sbi, +++ struct autofs_dev_ioctl *param) +++{ +++ struct dentry *dentry; +++ struct vfsmount *mnt; +++ int err = -EAGAIN; +++ int how; +++ +++ how = param->expire.how; +++ mnt = fp->f_vfsmnt; +++ +++ if (autofs_type_trigger(sbi->type)) +++ dentry = autofs4_expire_direct(sbi->sb, mnt, sbi, how); +++ else +++ dentry = autofs4_expire_indirect(sbi->sb, mnt, sbi, how); +++ +++ if (dentry) { +++ struct autofs_info *ino = autofs4_dentry_ino(dentry); +++ +++ /* +++ * This is synchronous because it makes the daemon a +++ * little easier +++ */ +++ err = autofs4_wait(sbi, dentry, NFY_EXPIRE); +++ +++ spin_lock(&sbi->fs_lock); +++ if (ino->flags & AUTOFS_INF_MOUNTPOINT) { +++ ino->flags &= ~AUTOFS_INF_MOUNTPOINT; +++ sbi->sb->s_root->d_mounted++; +++ } +++ ino->flags &= ~AUTOFS_INF_EXPIRING; +++ complete_all(&ino->expire_complete); +++ spin_unlock(&sbi->fs_lock); +++ dput(dentry); +++ } +++ +++ return err; +++} +++ +++/* Check if autofs mount point is in use */ +++static int autofs_dev_ioctl_askumount(struct file *fp, +++ struct autofs_sb_info *sbi, +++ struct autofs_dev_ioctl *param) +++{ +++ param->askumount.may_umount = 0; +++ if (may_umount(fp->f_vfsmnt)) +++ param->askumount.may_umount = 1; +++ return 0; +++} +++ +++/* +++ * Check if the given path is a mountpoint. +++ * +++ * If we are supplied with the file descriptor of an autofs +++ * mount we're looking for a specific mount. In this case +++ * 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 this case we return 1 if the +++ * path is a mount point and the super magic of the covering +++ * mount if there is one or 0 if it isn't a mountpoint. +++ * +++ * If we aren't supplied with a file descriptor then we +++ * lookup the nameidata of the path and check if it is the +++ * root of a mount. If a type is given we are looking for +++ * a particular autofs mount and if we don't find a match +++ * we return fail. If the located nameidata path is the +++ * root of a mount we return 1 along with the super magic +++ * of the mount or 0 otherwise. +++ * +++ * In both cases the the device number (as returned by +++ * new_encode_dev()) is also returned. +++ */ +++static int autofs_dev_ioctl_ismountpoint(struct file *fp, +++ struct autofs_sb_info *sbi, +++ struct autofs_dev_ioctl *param) +++{ +++ struct nameidata nd; +++ const char *path; +++ unsigned int type; +++ unsigned int devid, magic; +++ int err = -ENOENT; +++ +++ if (param->size <= sizeof(*param)) { +++ err = -EINVAL; +++ goto out; +++ } +++ +++ path = param->path; +++ type = param->ismountpoint.in.type; +++ +++ param->ismountpoint.out.devid = devid = 0; +++ param->ismountpoint.out.magic = magic = 0; +++ +++ if (!fp || param->ioctlfd == -1) { +++ if (autofs_type_any(type)) { +++ struct super_block *sb; +++ +++ err = path_lookup(path, LOOKUP_FOLLOW, &nd); +++ if (err) +++ goto out; +++ +++ sb = nd.dentry->d_sb; +++ devid = new_encode_dev(sb->s_dev); +++ } else { +++ struct autofs_info *ino; +++ +++ err = path_lookup(path, LOOKUP_PARENT, &nd); +++ if (err) +++ goto out; +++ +++ err = autofs_dev_ioctl_find_sbi_type(&nd, type); +++ if (err) +++ goto out_release; +++ +++ ino = autofs4_dentry_ino(nd.dentry); +++ devid = autofs4_get_dev(ino->sbi); +++ } +++ +++ err = 0; +++ if (nd.dentry->d_inode && +++ nd.mnt->mnt_root == nd.dentry) { +++ err = 1; +++ magic = nd.dentry->d_inode->i_sb->s_magic; +++ } +++ } else { +++ dev_t devid = new_encode_dev(sbi->sb->s_dev); +++ +++ err = path_lookup(path, LOOKUP_PARENT, &nd); +++ if (err) +++ goto out; +++ +++ err = autofs_dev_ioctl_find_super(&nd, devid); +++ if (err) +++ goto out_release; +++ +++ devid = autofs4_get_dev(sbi); +++ +++ err = have_submounts(nd.dentry); +++ +++ if (nd.mnt->mnt_mountpoint != nd.mnt->mnt_root) { +++ if (follow_down(&nd.mnt, &nd.dentry)) { +++ struct inode *inode = nd.dentry->d_inode; +++ magic = inode->i_sb->s_magic; +++ } +++ } +++ } +++ +++ param->ismountpoint.out.devid = devid; +++ param->ismountpoint.out.magic = magic; +++ +++out_release: +++ path_release(&nd); +++out: +++ return err; +++} +++ +++/* +++ * Our range of ioctl numbers isn't 0 based so we need to shift +++ * the array index by _IOC_NR(AUTOFS_CTL_IOC_FIRST) for the table +++ * lookup. +++ */ +++#define cmd_idx(cmd) (cmd - _IOC_NR(AUTOFS_DEV_IOCTL_IOC_FIRST)) +++ +++static ioctl_fn lookup_dev_ioctl(unsigned int cmd) +++{ +++ static struct { +++ int cmd; +++ ioctl_fn fn; +++ } _ioctls[] = { +++ {cmd_idx(AUTOFS_DEV_IOCTL_VERSION_CMD), NULL}, +++ {cmd_idx(AUTOFS_DEV_IOCTL_PROTOVER_CMD), +++ autofs_dev_ioctl_protover}, +++ {cmd_idx(AUTOFS_DEV_IOCTL_PROTOSUBVER_CMD), +++ autofs_dev_ioctl_protosubver}, +++ {cmd_idx(AUTOFS_DEV_IOCTL_OPENMOUNT_CMD), +++ autofs_dev_ioctl_openmount}, +++ {cmd_idx(AUTOFS_DEV_IOCTL_CLOSEMOUNT_CMD), +++ autofs_dev_ioctl_closemount}, +++ {cmd_idx(AUTOFS_DEV_IOCTL_READY_CMD), +++ autofs_dev_ioctl_ready}, +++ {cmd_idx(AUTOFS_DEV_IOCTL_FAIL_CMD), +++ autofs_dev_ioctl_fail}, +++ {cmd_idx(AUTOFS_DEV_IOCTL_SETPIPEFD_CMD), +++ autofs_dev_ioctl_setpipefd}, +++ {cmd_idx(AUTOFS_DEV_IOCTL_CATATONIC_CMD), +++ autofs_dev_ioctl_catatonic}, +++ {cmd_idx(AUTOFS_DEV_IOCTL_TIMEOUT_CMD), +++ autofs_dev_ioctl_timeout}, +++ {cmd_idx(AUTOFS_DEV_IOCTL_REQUESTER_CMD), +++ autofs_dev_ioctl_requester}, +++ {cmd_idx(AUTOFS_DEV_IOCTL_EXPIRE_CMD), +++ autofs_dev_ioctl_expire}, +++ {cmd_idx(AUTOFS_DEV_IOCTL_ASKUMOUNT_CMD), +++ autofs_dev_ioctl_askumount}, +++ {cmd_idx(AUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD), +++ autofs_dev_ioctl_ismountpoint} +++ }; +++ unsigned int idx = cmd_idx(cmd); +++ +++ return (idx >= ARRAY_SIZE(_ioctls)) ? NULL : _ioctls[idx].fn; +++} +++ +++/* ioctl dispatcher */ +++static int _autofs_dev_ioctl(unsigned int command, struct autofs_dev_ioctl __user *user) +++{ +++ struct autofs_dev_ioctl *param; +++ struct file *fp; +++ struct autofs_sb_info *sbi; +++ unsigned int cmd_first, cmd; +++ ioctl_fn fn = NULL; +++ int err = 0; +++ +++ /* only root can play with this */ +++ if (!capable(CAP_SYS_ADMIN)) +++ return -EPERM; +++ +++ cmd_first = _IOC_NR(AUTOFS_DEV_IOCTL_IOC_FIRST); +++ cmd = _IOC_NR(command); +++ +++ if (_IOC_TYPE(command) != _IOC_TYPE(AUTOFS_DEV_IOCTL_IOC_FIRST) || +++ cmd - cmd_first >= AUTOFS_DEV_IOCTL_IOC_COUNT) { +++ return -ENOTTY; +++ } +++ +++ /* Copy the parameters into kernel space. */ +++ param = copy_dev_ioctl(user); +++ if (IS_ERR(param)) +++ return PTR_ERR(param); +++ +++ err = validate_dev_ioctl(command, param); +++ if (err) +++ goto out; +++ +++ /* The validate routine above always sets the version */ +++ if (cmd == AUTOFS_DEV_IOCTL_VERSION_CMD) +++ goto done; +++ +++ fn = lookup_dev_ioctl(cmd); +++ if (!fn) { +++ AUTOFS_WARN("unknown command 0x%08x", command); +++ return -ENOTTY; +++ } +++ +++ fp = NULL; +++ sbi = NULL; +++ +++ /* +++ * For obvious reasons the openmount can't have a file +++ * descriptor yet. We don't take a reference to the +++ * file during close to allow for immediate release. +++ */ +++ if (cmd != AUTOFS_DEV_IOCTL_OPENMOUNT_CMD && +++ cmd != AUTOFS_DEV_IOCTL_CLOSEMOUNT_CMD) { +++ fp = fget(param->ioctlfd); +++ if (!fp) { +++ if (cmd == AUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD) +++ goto cont; +++ err = -EBADF; +++ goto out; +++ } +++ +++ if (!fp->f_op) { +++ err = -ENOTTY; +++ fput(fp); +++ goto out; +++ } +++ +++ sbi = autofs_dev_ioctl_sbi(fp); +++ if (!sbi || sbi->magic != AUTOFS_SBI_MAGIC) { +++ err = -EINVAL; +++ fput(fp); +++ goto out; +++ } +++ +++ /* +++ * Admin needs to be able to set the mount catatonic in +++ * order to be able to perform the re-open. +++ */ +++ if (!autofs4_oz_mode(sbi) && +++ cmd != AUTOFS_DEV_IOCTL_CATATONIC_CMD) { +++ err = -EACCES; +++ fput(fp); +++ goto out; +++ } +++ } +++cont: +++ err = fn(fp, sbi, param); +++ +++ if (fp) +++ fput(fp); +++done: +++ if (err >= 0 && copy_to_user(user, param, AUTOFS_DEV_IOCTL_SIZE)) +++ err = -EFAULT; +++out: +++ free_dev_ioctl(param); +++ return err; +++} +++ +++static long autofs_dev_ioctl(struct file *file, uint command, ulong u) +++{ +++ int err; +++ err = _autofs_dev_ioctl(command, (struct autofs_dev_ioctl __user *) u); +++ return (long) err; +++} +++ +++#ifdef CONFIG_COMPAT +++static long autofs_dev_ioctl_compat(struct file *file, uint command, ulong u) +++{ +++ return (long) autofs_dev_ioctl(file, command, (ulong) compat_ptr(u)); +++} +++#else +++#define autofs_dev_ioctl_compat NULL +++#endif +++ +++static const struct file_operations _dev_ioctl_fops = { +++ .unlocked_ioctl = autofs_dev_ioctl, +++ .compat_ioctl = autofs_dev_ioctl_compat, +++ .owner = THIS_MODULE, +++}; +++ +++static struct miscdevice _autofs_dev_ioctl_misc = { +++ .minor = MISC_DYNAMIC_MINOR, +++ .name = AUTOFS_DEVICE_NAME, +++ .fops = &_dev_ioctl_fops +++}; +++ +++/* Register/deregister misc character device */ +++int autofs_dev_ioctl_init(void) +++{ +++ int r; +++ +++ r = misc_register(&_autofs_dev_ioctl_misc); +++ if (r) { +++ AUTOFS_ERROR("misc_register failed for control device"); +++ return r; +++ } +++ +++ return 0; +++} +++ +++void autofs_dev_ioctl_exit(void) +++{ +++ misc_deregister(&_autofs_dev_ioctl_misc); +++ return; +++} +++ ++--- /dev/null +++++ linux-2.6.18/include/linux/auto_dev-ioctl.h ++@@ -0,0 +1,229 @@ +++/* +++ * Copyright 2008 Red Hat, Inc. All rights reserved. +++ * Copyright 2008 Ian Kent +++ * +++ * 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 +++ +++#ifdef __KERNEL__ +++#include +++#else +++#include +++#endif /* __KERNEL__ */ +++ +++#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_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) +++{ +++ memset(in, 0, sizeof(struct autofs_dev_ioctl)); +++ 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 */ ++--- linux-2.6.18.orig/include/linux/auto_fs.h +++++ linux-2.6.18/include/linux/auto_fs.h ++@@ -17,11 +17,13 @@ ++ #ifdef __KERNEL__ ++ #include ++ #include +++#include +++#include +++#else ++ #include +++#include ++ #endif /* __KERNEL__ */ ++ ++-#include ++- ++ /* This file describes autofs v3 */ ++ #define AUTOFS_PROTO_VERSION 3 ++ +diff --git a/patches/autofs4-2.6.19-v5-update-20100114.patch b/patches/autofs4-2.6.19-v5-update-20100114.patch +new file mode 100644 +index 0000000..793aae6 +--- /dev/null ++++ b/patches/autofs4-2.6.19-v5-update-20100114.patch +@@ -0,0 +1,3668 @@ ++--- linux-2.6.19.orig/fs/autofs/inode.c +++++ linux-2.6.19/fs/autofs/inode.c ++@@ -28,10 +28,11 @@ void autofs_kill_sb(struct super_block * ++ /* ++ * In the event of a failure in get_sb_nodev the superblock ++ * info is not present so nothing else has been setup, so ++- * just exit when we are called from deactivate_super. +++ * just call kill_anon_super when we are called from +++ * deactivate_super. ++ */ ++ if (!sbi) ++- return; +++ goto out_kill_sb; ++ ++ if ( !sbi->catatonic ) ++ autofs_catatonic_mode(sbi); /* Free wait queues, close pipe */ ++@@ -44,6 +45,7 @@ void autofs_kill_sb(struct super_block * ++ ++ kfree(sb->s_fs_info); ++ +++out_kill_sb: ++ DPRINTK(("autofs: shutting down\n")); ++ kill_anon_super(sb); ++ } ++@@ -209,7 +211,6 @@ fail_iput: ++ fail_free: ++ kfree(sbi); ++ s->s_fs_info = NULL; ++- kill_anon_super(s); ++ fail_unlock: ++ return -EINVAL; ++ } ++--- linux-2.6.19.orig/fs/autofs4/inode.c +++++ linux-2.6.19/fs/autofs4/inode.c ++@@ -25,8 +25,10 @@ ++ ++ static void ino_lnkfree(struct autofs_info *ino) ++ { ++- kfree(ino->u.symlink); ++- ino->u.symlink = NULL; +++ if (ino->u.symlink) { +++ kfree(ino->u.symlink); +++ ino->u.symlink = NULL; +++ } ++ } ++ ++ struct autofs_info *autofs4_init_ino(struct autofs_info *ino, ++@@ -42,14 +44,20 @@ struct autofs_info *autofs4_init_ino(str ++ if (ino == NULL) ++ return NULL; ++ ++- ino->flags = 0; ++- ino->mode = mode; ++- ino->inode = NULL; ++- ino->dentry = NULL; ++- ino->size = 0; +++ if (!reinit) { +++ ino->flags = 0; +++ ino->inode = NULL; +++ ino->dentry = NULL; +++ ino->size = 0; +++ INIT_LIST_HEAD(&ino->active); +++ INIT_LIST_HEAD(&ino->expiring); +++ atomic_set(&ino->count, 0); +++ } ++ +++ ino->uid = 0; +++ ino->gid = 0; +++ ino->mode = mode; ++ ino->last_used = jiffies; ++- atomic_set(&ino->count, 0); ++ ++ ino->sbi = sbi; ++ ++@@ -152,21 +160,22 @@ void autofs4_kill_sb(struct super_block ++ /* ++ * In the event of a failure in get_sb_nodev the superblock ++ * info is not present so nothing else has been setup, so ++- * just exit when we are called from deactivate_super. +++ * just call kill_anon_super when we are called from +++ * deactivate_super. ++ */ ++ if (!sbi) ++- return; ++- ++- sb->s_fs_info = NULL; +++ goto out_kill_sb; ++ ++- if ( !sbi->catatonic ) ++- autofs4_catatonic_mode(sbi); /* Free wait queues, close pipe */ +++ /* Free wait queues, close pipe */ +++ autofs4_catatonic_mode(sbi); ++ ++ /* Clean up and release dangling references */ ++ autofs4_force_release(sbi); ++ +++ sb->s_fs_info = NULL; ++ kfree(sbi); ++ +++out_kill_sb: ++ DPRINTK("shutting down"); ++ kill_anon_super(sb); ++ } ++@@ -184,9 +193,9 @@ static int autofs4_show_options(struct s ++ seq_printf(m, ",minproto=%d", sbi->min_proto); ++ seq_printf(m, ",maxproto=%d", sbi->max_proto); ++ ++- if (sbi->type & AUTOFS_TYPE_OFFSET) +++ if (autofs_type_offset(sbi->type)) ++ seq_printf(m, ",offset"); ++- else if (sbi->type & AUTOFS_TYPE_DIRECT) +++ else if (autofs_type_direct(sbi->type)) ++ seq_printf(m, ",direct"); ++ else ++ seq_printf(m, ",indirect"); ++@@ -272,13 +281,13 @@ static int parse_options(char *options, ++ *maxproto = option; ++ break; ++ case Opt_indirect: ++- *type = AUTOFS_TYPE_INDIRECT; +++ set_autofs_type_indirect(type); ++ break; ++ case Opt_direct: ++- *type = AUTOFS_TYPE_DIRECT; +++ set_autofs_type_direct(type); ++ break; ++ case Opt_offset: ++- *type = AUTOFS_TYPE_DIRECT | AUTOFS_TYPE_OFFSET; +++ set_autofs_type_offset(type); ++ break; ++ default: ++ return 1; ++@@ -328,12 +337,15 @@ int autofs4_fill_super(struct super_bloc ++ sbi->sb = s; ++ sbi->version = 0; ++ sbi->sub_version = 0; ++- sbi->type = 0; +++ set_autofs_type_indirect(&sbi->type); ++ sbi->min_proto = 0; ++ sbi->max_proto = 0; ++ mutex_init(&sbi->wq_mutex); ++ spin_lock_init(&sbi->fs_lock); ++ sbi->queues = NULL; +++ spin_lock_init(&sbi->lookup_lock); +++ INIT_LIST_HEAD(&sbi->active_list); +++ INIT_LIST_HEAD(&sbi->expiring_list); ++ s->s_blocksize = 1024; ++ s->s_blocksize_bits = 10; ++ s->s_magic = AUTOFS_SUPER_MAGIC; ++@@ -368,7 +380,7 @@ int autofs4_fill_super(struct super_bloc ++ } ++ ++ root_inode->i_fop = &autofs4_root_operations; ++- root_inode->i_op = sbi->type & AUTOFS_TYPE_DIRECT ? +++ root_inode->i_op = autofs_type_trigger(sbi->type) ? ++ &autofs4_direct_root_inode_operations : ++ &autofs4_indirect_root_inode_operations; ++ ++@@ -426,7 +438,6 @@ fail_ino: ++ fail_free: ++ kfree(sbi); ++ s->s_fs_info = NULL; ++- kill_anon_super(s); ++ fail_unlock: ++ return -EINVAL; ++ } ++--- linux-2.6.19.orig/fs/autofs4/waitq.c +++++ linux-2.6.19/fs/autofs4/waitq.c ++@@ -28,6 +28,12 @@ void autofs4_catatonic_mode(struct autof ++ { ++ struct autofs_wait_queue *wq, *nwq; ++ +++ mutex_lock(&sbi->wq_mutex); +++ if (sbi->catatonic) { +++ mutex_unlock(&sbi->wq_mutex); +++ return; +++ } +++ ++ DPRINTK("entering catatonic mode"); ++ ++ sbi->catatonic = 1; ++@@ -36,13 +42,18 @@ void autofs4_catatonic_mode(struct autof ++ while (wq) { ++ nwq = wq->next; ++ wq->status = -ENOENT; /* Magic is gone - report failure */ ++- kfree(wq->name); ++- wq->name = NULL; +++ if (wq->name.name) { +++ kfree(wq->name.name); +++ wq->name.name = NULL; +++ } +++ wq->wait_ctr--; ++ wake_up_interruptible(&wq->queue); ++ wq = nwq; ++ } ++ fput(sbi->pipe); /* Close the pipe */ ++ sbi->pipe = NULL; +++ sbi->pipefd = -1; +++ mutex_unlock(&sbi->wq_mutex); ++ } ++ ++ static int autofs4_write(struct file *file, const void *addr, int bytes) ++@@ -84,11 +95,16 @@ static void autofs4_notify_daemon(struct ++ struct autofs_wait_queue *wq, ++ int type) ++ { ++- union autofs_packet_union pkt; +++ union { +++ struct autofs_packet_hdr hdr; +++ union autofs_packet_union v4_pkt; +++ union autofs_v5_packet_union v5_pkt; +++ } pkt; +++ struct file *pipe = NULL; ++ size_t pktsz; ++ ++ DPRINTK("wait id = 0x%08lx, name = %.*s, type=%d", ++- wq->wait_queue_token, wq->len, wq->name, type); +++ wq->wait_queue_token, wq->name.len, wq->name.name, type); ++ ++ memset(&pkt,0,sizeof pkt); /* For security reasons */ ++ ++@@ -98,26 +114,26 @@ static void autofs4_notify_daemon(struct ++ /* Kernel protocol v4 missing and expire packets */ ++ case autofs_ptype_missing: ++ { ++- struct autofs_packet_missing *mp = &pkt.missing; +++ struct autofs_packet_missing *mp = &pkt.v4_pkt.missing; ++ ++ pktsz = sizeof(*mp); ++ ++ mp->wait_queue_token = wq->wait_queue_token; ++- mp->len = wq->len; ++- memcpy(mp->name, wq->name, wq->len); ++- mp->name[wq->len] = '\0'; +++ mp->len = wq->name.len; +++ memcpy(mp->name, wq->name.name, wq->name.len); +++ mp->name[wq->name.len] = '\0'; ++ break; ++ } ++ case autofs_ptype_expire_multi: ++ { ++- struct autofs_packet_expire_multi *ep = &pkt.expire_multi; +++ struct autofs_packet_expire_multi *ep = &pkt.v4_pkt.expire_multi; ++ ++ pktsz = sizeof(*ep); ++ ++ ep->wait_queue_token = wq->wait_queue_token; ++- ep->len = wq->len; ++- memcpy(ep->name, wq->name, wq->len); ++- ep->name[wq->len] = '\0'; +++ ep->len = wq->name.len; +++ memcpy(ep->name, wq->name.name, wq->name.len); +++ ep->name[wq->name.len] = '\0'; ++ break; ++ } ++ /* ++@@ -129,14 +145,14 @@ static void autofs4_notify_daemon(struct ++ case autofs_ptype_missing_direct: ++ case autofs_ptype_expire_direct: ++ { ++- struct autofs_v5_packet *packet = &pkt.v5_packet; +++ struct autofs_v5_packet *packet = &pkt.v5_pkt.v5_packet; ++ ++ pktsz = sizeof(*packet); ++ ++ packet->wait_queue_token = wq->wait_queue_token; ++- packet->len = wq->len; ++- memcpy(packet->name, wq->name, wq->len); ++- packet->name[wq->len] = '\0'; +++ packet->len = wq->name.len; +++ memcpy(packet->name, wq->name.name, wq->name.len); +++ packet->name[wq->name.len] = '\0'; ++ packet->dev = wq->dev; ++ packet->ino = wq->ino; ++ packet->uid = wq->uid; ++@@ -150,8 +166,19 @@ static void autofs4_notify_daemon(struct ++ return; ++ } ++ ++- if (autofs4_write(sbi->pipe, &pkt, pktsz)) ++- autofs4_catatonic_mode(sbi); +++ /* Check if we have become catatonic */ +++ mutex_lock(&sbi->wq_mutex); +++ if (!sbi->catatonic) { +++ pipe = sbi->pipe; +++ get_file(pipe); +++ } +++ mutex_unlock(&sbi->wq_mutex); +++ +++ if (pipe) { +++ if (autofs4_write(pipe, &pkt, pktsz)) +++ autofs4_catatonic_mode(sbi); +++ fput(pipe); +++ } ++ } ++ ++ static int autofs4_getpath(struct autofs_sb_info *sbi, ++@@ -167,7 +194,7 @@ static int autofs4_getpath(struct autofs ++ for (tmp = dentry ; tmp != root ; tmp = tmp->d_parent) ++ len += tmp->d_name.len + 1; ++ ++- if (--len > NAME_MAX) { +++ if (!len || --len > NAME_MAX) { ++ spin_unlock(&dcache_lock); ++ return 0; ++ } ++@@ -187,58 +214,55 @@ static int autofs4_getpath(struct autofs ++ } ++ ++ static struct autofs_wait_queue * ++-autofs4_find_wait(struct autofs_sb_info *sbi, ++- char *name, unsigned int hash, unsigned int len) +++autofs4_find_wait(struct autofs_sb_info *sbi, struct qstr *qstr) ++ { ++ struct autofs_wait_queue *wq; ++ ++ for (wq = sbi->queues; wq; wq = wq->next) { ++- if (wq->hash == hash && ++- wq->len == len && ++- wq->name && !memcmp(wq->name, name, len)) +++ if (wq->name.hash == qstr->hash && +++ wq->name.len == qstr->len && +++ wq->name.name && +++ !memcmp(wq->name.name, qstr->name, qstr->len)) ++ break; ++ } ++ return wq; ++ } ++ ++-int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry, ++- enum autofs_notify notify) +++/* +++ * Check if we have a valid request. +++ * Returns +++ * 1 if the request should continue. +++ * In this case we can return an autofs_wait_queue entry if one is +++ * found or NULL to idicate a new wait needs to be created. +++ * 0 or a negative errno if the request shouldn't continue. +++ */ +++static int validate_request(struct autofs_wait_queue **wait, +++ struct autofs_sb_info *sbi, +++ struct qstr *qstr, +++ struct dentry*dentry, enum autofs_notify notify) ++ { ++- struct autofs_info *ino; ++ struct autofs_wait_queue *wq; ++- char *name; ++- unsigned int len = 0; ++- unsigned int hash = 0; ++- int status, type; ++- ++- /* In catatonic mode, we don't wait for nobody */ ++- if (sbi->catatonic) ++- return -ENOENT; ++- ++- name = kmalloc(NAME_MAX + 1, GFP_KERNEL); ++- if (!name) ++- return -ENOMEM; +++ struct autofs_info *ino; ++ ++- /* If this is a direct mount request create a dummy name */ ++- if (IS_ROOT(dentry) && (sbi->type & AUTOFS_TYPE_DIRECT)) ++- len = sprintf(name, "%p", dentry); ++- else { ++- len = autofs4_getpath(sbi, dentry, &name); ++- if (!len) { ++- kfree(name); ++- return -ENOENT; ++- } +++ /* Wait in progress, continue; */ +++ wq = autofs4_find_wait(sbi, qstr); +++ if (wq) { +++ *wait = wq; +++ return 1; ++ } ++- hash = full_name_hash(name, len); ++ ++- if (mutex_lock_interruptible(&sbi->wq_mutex)) { ++- kfree(name); ++- return -EINTR; ++- } +++ *wait = NULL; ++ ++- wq = autofs4_find_wait(sbi, name, hash, len); +++ /* If we don't yet have any info this is a new request */ ++ ino = autofs4_dentry_ino(dentry); ++- if (!wq && ino && notify == NFY_NONE) { +++ if (!ino) +++ return 1; +++ +++ /* +++ * If we've been asked to wait on an existing expire (NFY_NONE) +++ * but there is no wait in the queue ... +++ */ +++ if (notify == NFY_NONE) { ++ /* ++ * Either we've betean the pending expire to post it's ++ * wait or it finished while we waited on the mutex. ++@@ -249,13 +273,14 @@ int autofs4_wait(struct autofs_sb_info * ++ while (ino->flags & AUTOFS_INF_EXPIRING) { ++ mutex_unlock(&sbi->wq_mutex); ++ schedule_timeout_interruptible(HZ/10); ++- if (mutex_lock_interruptible(&sbi->wq_mutex)) { ++- kfree(name); +++ if (mutex_lock_interruptible(&sbi->wq_mutex)) ++ return -EINTR; +++ +++ wq = autofs4_find_wait(sbi, qstr); +++ if (wq) { +++ *wait = wq; +++ return 1; ++ } ++- wq = autofs4_find_wait(sbi, name, hash, len); ++- if (wq) ++- break; ++ } ++ ++ /* ++@@ -263,18 +288,90 @@ int autofs4_wait(struct autofs_sb_info * ++ * cases where we wait on NFY_NONE neither depend on the ++ * return status of the wait. ++ */ ++- if (!wq) { ++- kfree(name); ++- mutex_unlock(&sbi->wq_mutex); +++ return 0; +++ } +++ +++ /* +++ * If we've been asked to trigger a mount and the request +++ * completed while we waited on the mutex ... +++ */ +++ if (notify == NFY_MOUNT) { +++ /* +++ * If the dentry was successfully mounted while we slept +++ * on the wait queue mutex we can return success. If it +++ * isn't mounted (doesn't have submounts for the case of +++ * a multi-mount with no mount at it's base) we can +++ * continue on and create a new request. +++ */ +++ if (have_submounts(dentry)) ++ return 0; +++ } +++ +++ return 1; +++} +++ +++int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry, +++ enum autofs_notify notify) +++{ +++ struct autofs_wait_queue *wq; +++ struct qstr qstr; +++ char *name; +++ int status, ret, type; +++ +++ /* In catatonic mode, we don't wait for nobody */ +++ if (sbi->catatonic) +++ return -ENOENT; +++ +++ if (!dentry->d_inode) { +++ /* +++ * A wait for a negative dentry is invalid for certain +++ * cases. A direct or offset mount "always" has its mount +++ * point directory created and so the request dentry must +++ * be positive or the map key doesn't exist. The situation +++ * is very similar for indirect mounts except only dentrys +++ * in the root of the autofs file system may be negative. +++ */ +++ if (autofs_type_trigger(sbi->type)) +++ return -ENOENT; +++ else if (!IS_ROOT(dentry->d_parent)) +++ return -ENOENT; +++ } +++ +++ name = kmalloc(NAME_MAX + 1, GFP_KERNEL); +++ if (!name) +++ return -ENOMEM; +++ +++ /* If this is a direct mount request create a dummy name */ +++ if (IS_ROOT(dentry) && autofs_type_trigger(sbi->type)) +++ qstr.len = sprintf(name, "%p", dentry); +++ else { +++ qstr.len = autofs4_getpath(sbi, dentry, &name); +++ if (!qstr.len) { +++ kfree(name); +++ return -ENOENT; ++ } ++ } +++ qstr.name = name; +++ qstr.hash = full_name_hash(name, qstr.len); +++ +++ if (mutex_lock_interruptible(&sbi->wq_mutex)) { +++ kfree(qstr.name); +++ return -EINTR; +++ } +++ +++ ret = validate_request(&wq, sbi, &qstr, dentry, notify); +++ if (ret <= 0) { +++ if (ret == 0) +++ mutex_unlock(&sbi->wq_mutex); +++ kfree(qstr.name); +++ return ret; +++ } ++ ++ if (!wq) { ++ /* Create a new wait queue */ ++ wq = kmalloc(sizeof(struct autofs_wait_queue),GFP_KERNEL); ++ if (!wq) { ++- kfree(name); +++ kfree(qstr.name); ++ mutex_unlock(&sbi->wq_mutex); ++ return -ENOMEM; ++ } ++@@ -285,9 +382,7 @@ int autofs4_wait(struct autofs_sb_info * ++ wq->next = sbi->queues; ++ sbi->queues = wq; ++ init_waitqueue_head(&wq->queue); ++- wq->hash = hash; ++- wq->name = name; ++- wq->len = len; +++ memcpy(&wq->name, &qstr, sizeof(struct qstr)); ++ wq->dev = autofs4_get_dev(sbi); ++ wq->ino = autofs4_get_ino(sbi); ++ wq->uid = current->uid; ++@@ -295,7 +390,7 @@ int autofs4_wait(struct autofs_sb_info * ++ wq->pid = current->pid; ++ wq->tgid = current->tgid; ++ wq->status = -EINTR; /* Status return if interrupted */ ++- atomic_set(&wq->wait_ctr, 2); +++ wq->wait_ctr = 2; ++ mutex_unlock(&sbi->wq_mutex); ++ ++ if (sbi->version < 5) { ++@@ -305,38 +400,35 @@ int autofs4_wait(struct autofs_sb_info * ++ type = autofs_ptype_expire_multi; ++ } else { ++ if (notify == NFY_MOUNT) ++- type = (sbi->type & AUTOFS_TYPE_DIRECT) ? +++ type = autofs_type_trigger(sbi->type) ? ++ autofs_ptype_missing_direct : ++ autofs_ptype_missing_indirect; ++ else ++- type = (sbi->type & AUTOFS_TYPE_DIRECT) ? +++ type = autofs_type_trigger(sbi->type) ? ++ autofs_ptype_expire_direct : ++ autofs_ptype_expire_indirect; ++ } ++ ++ DPRINTK("new wait id = 0x%08lx, name = %.*s, nfy=%d\n", ++- (unsigned long) wq->wait_queue_token, wq->len, wq->name, notify); +++ (unsigned long) wq->wait_queue_token, wq->name.len, +++ wq->name.name, notify); ++ ++ /* autofs4_notify_daemon() may block */ ++ autofs4_notify_daemon(sbi, wq, type); ++ } else { ++- atomic_inc(&wq->wait_ctr); +++ wq->wait_ctr++; ++ mutex_unlock(&sbi->wq_mutex); ++- kfree(name); +++ kfree(qstr.name); ++ DPRINTK("existing wait id = 0x%08lx, name = %.*s, nfy=%d", ++- (unsigned long) wq->wait_queue_token, wq->len, wq->name, notify); +++ (unsigned long) wq->wait_queue_token, wq->name.len, +++ wq->name.name, notify); ++ } ++ ++- /* wq->name is NULL if and only if the lock is already released */ ++- ++- if (sbi->catatonic) { ++- /* We might have slept, so check again for catatonic mode */ ++- wq->status = -ENOENT; ++- kfree(wq->name); ++- wq->name = NULL; ++- } ++- ++- if (wq->name) { +++ /* +++ * wq->name.name is NULL iff the lock is already released +++ * or the mount has been made catatonic. +++ */ +++ if (wq->name.name) { ++ /* Block all but "shutdown" signals while waiting */ ++ sigset_t oldset; ++ unsigned long irqflags; ++@@ -347,7 +439,7 @@ int autofs4_wait(struct autofs_sb_info * ++ recalc_sigpending(); ++ spin_unlock_irqrestore(¤t->sighand->siglock, irqflags); ++ ++- wait_event_interruptible(wq->queue, wq->name == NULL); +++ wait_event_interruptible(wq->queue, wq->name.name == NULL); ++ ++ spin_lock_irqsave(¤t->sighand->siglock, irqflags); ++ current->blocked = oldset; ++@@ -359,9 +451,45 @@ int autofs4_wait(struct autofs_sb_info * ++ ++ status = wq->status; ++ +++ /* +++ * For direct and offset mounts we need to track the requester's +++ * uid and gid in the dentry info struct. This is so it can be +++ * supplied, on request, by the misc device ioctl interface. +++ * This is needed during daemon resatart when reconnecting +++ * to existing, active, autofs mounts. The uid and gid (and +++ * related string values) may be used for macro substitution +++ * in autofs mount maps. +++ */ +++ if (!status) { +++ struct autofs_info *ino; +++ struct dentry *de = NULL; +++ +++ /* direct mount or browsable map */ +++ ino = autofs4_dentry_ino(dentry); +++ if (!ino) { +++ /* If not lookup actual dentry used */ +++ de = d_lookup(dentry->d_parent, &dentry->d_name); +++ if (de) +++ ino = autofs4_dentry_ino(de); +++ } +++ +++ /* Set mount requester */ +++ if (ino) { +++ spin_lock(&sbi->fs_lock); +++ ino->uid = wq->uid; +++ ino->gid = wq->gid; +++ spin_unlock(&sbi->fs_lock); +++ } +++ +++ if (de) +++ dput(de); +++ } +++ ++ /* Are we the last process to need status? */ ++- if (atomic_dec_and_test(&wq->wait_ctr)) +++ mutex_lock(&sbi->wq_mutex); +++ if (!--wq->wait_ctr) ++ kfree(wq); +++ mutex_unlock(&sbi->wq_mutex); ++ ++ return status; ++ } ++@@ -383,16 +511,13 @@ int autofs4_wait_release(struct autofs_s ++ } ++ ++ *wql = wq->next; /* Unlink from chain */ ++- mutex_unlock(&sbi->wq_mutex); ++- kfree(wq->name); ++- wq->name = NULL; /* Do not wait on this queue */ ++- +++ kfree(wq->name.name); +++ wq->name.name = NULL; /* Do not wait on this queue */ ++ wq->status = status; ++- ++- if (atomic_dec_and_test(&wq->wait_ctr)) /* Is anyone still waiting for this guy? */ +++ wake_up_interruptible(&wq->queue); +++ if (!--wq->wait_ctr) ++ kfree(wq); ++- else ++- wake_up_interruptible(&wq->queue); +++ mutex_unlock(&sbi->wq_mutex); ++ ++ return 0; ++ } ++--- linux-2.6.19.orig/include/linux/auto_fs4.h +++++ linux-2.6.19/include/linux/auto_fs4.h ++@@ -23,12 +23,71 @@ ++ #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 0U +++#define AUTOFS_TYPE_INDIRECT 1U +++#define AUTOFS_TYPE_DIRECT 2U +++#define AUTOFS_TYPE_OFFSET 4U +++ +++static inline void set_autofs_type_indirect(unsigned int *type) +++{ +++ *type = AUTOFS_TYPE_INDIRECT; +++ return; +++} +++ +++static inline unsigned int autofs_type_indirect(unsigned int type) +++{ +++ return (type == AUTOFS_TYPE_INDIRECT); +++} +++ +++static inline void set_autofs_type_direct(unsigned int *type) +++{ +++ *type = AUTOFS_TYPE_DIRECT; +++ return; +++} +++ +++static inline unsigned int autofs_type_direct(unsigned int type) +++{ +++ return (type == AUTOFS_TYPE_DIRECT); +++} +++ +++static inline void set_autofs_type_offset(unsigned int *type) +++{ +++ *type = AUTOFS_TYPE_OFFSET; +++ return; +++} +++ +++static inline unsigned int autofs_type_offset(unsigned int type) +++{ +++ return (type == AUTOFS_TYPE_OFFSET); +++} +++ +++static inline unsigned int autofs_type_trigger(unsigned int type) +++{ +++ return (type == AUTOFS_TYPE_DIRECT || type == AUTOFS_TYPE_OFFSET); +++} +++ +++/* +++ * This isn't really a type as we use it to say "no type set" to +++ * indicate we want to search for "any" mount in the +++ * autofs_dev_ioctl_ismountpoint() device ioctl function. +++ */ +++static inline void set_autofs_type_any(unsigned int *type) +++{ +++ *type = AUTOFS_TYPE_ANY; +++ return; +++} +++ +++static inline unsigned int autofs_type_any(unsigned int type) +++{ +++ return (type == AUTOFS_TYPE_ANY); +++} +++ ++ /* Daemon notification packet types */ ++ enum autofs_notify { ++ NFY_NONE, ++@@ -59,6 +118,13 @@ struct autofs_packet_expire_multi { ++ char name[NAME_MAX+1]; ++ }; ++ +++union autofs_packet_union { +++ struct autofs_packet_hdr hdr; +++ struct autofs_packet_missing missing; +++ struct autofs_packet_expire expire; +++ struct autofs_packet_expire_multi expire_multi; +++}; +++ ++ /* autofs v5 common packet struct */ ++ struct autofs_v5_packet { ++ struct autofs_packet_hdr hdr; ++@@ -78,20 +144,19 @@ typedef struct autofs_v5_packet autofs_p ++ typedef struct autofs_v5_packet autofs_packet_missing_direct_t; ++ typedef struct autofs_v5_packet autofs_packet_expire_direct_t; ++ ++-union autofs_packet_union { +++union autofs_v5_packet_union { ++ struct autofs_packet_hdr hdr; ++- struct autofs_packet_missing missing; ++- struct autofs_packet_expire expire; ++- struct autofs_packet_expire_multi expire_multi; ++ struct autofs_v5_packet v5_packet; +++ autofs_packet_missing_indirect_t missing_indirect; +++ autofs_packet_expire_indirect_t expire_indirect; +++ autofs_packet_missing_direct_t missing_direct; +++ autofs_packet_expire_direct_t expire_direct; ++ }; ++ ++ #define AUTOFS_IOC_EXPIRE_MULTI _IOW(0x93,0x66,int) ++ #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) ++ ++ ++--- linux-2.6.19.orig/fs/autofs4/autofs_i.h +++++ linux-2.6.19/fs/autofs4/autofs_i.h ++@@ -14,6 +14,7 @@ ++ /* Internal header file for autofs */ ++ ++ #include +++#include ++ #include ++ #include ++ ++@@ -21,6 +22,9 @@ ++ #define AUTOFS_IOC_FIRST AUTOFS_IOC_READY ++ #define AUTOFS_IOC_COUNT 32 ++ +++#define AUTOFS_DEV_IOCTL_IOC_FIRST (AUTOFS_DEV_IOCTL_VERSION) +++#define AUTOFS_DEV_IOCTL_IOC_COUNT (AUTOFS_IOC_COUNT - 11) +++ ++ #include ++ #include ++ #include ++@@ -35,11 +39,27 @@ ++ /* #define DEBUG */ ++ ++ #ifdef DEBUG ++-#define DPRINTK(fmt,args...) do { printk(KERN_DEBUG "pid %d: %s: " fmt "\n" , current->pid , __FUNCTION__ , ##args); } while(0) +++#define DPRINTK(fmt, args...) \ +++do { \ +++ printk(KERN_DEBUG "pid %d: %s: " fmt "\n", \ +++ current->pid, __FUNCTION__, ##args); \ +++} while (0) ++ #else ++-#define DPRINTK(fmt,args...) do {} while(0) +++#define DPRINTK(fmt, args...) do {} while (0) ++ #endif ++ +++#define AUTOFS_WARN(fmt, args...) \ +++do { \ +++ printk(KERN_WARNING "pid %d: %s: " fmt "\n", \ +++ current->pid, __FUNCTION__, ##args); \ +++} while (0) +++ +++#define AUTOFS_ERROR(fmt, args...) \ +++do { \ +++ printk(KERN_ERR "pid %d: %s: " fmt "\n", \ +++ current->pid, __FUNCTION__, ##args); \ +++} while (0) +++ ++ /* Unified info structure. This is pointed to by both the dentry and ++ inode structures. Each file in the filesystem has an instance of this ++ structure. It holds a reference to the dentry, so dentries are never ++@@ -52,10 +72,18 @@ struct autofs_info { ++ ++ int flags; ++ +++ struct completion expire_complete; +++ +++ struct list_head active; +++ struct list_head expiring; +++ ++ struct autofs_sb_info *sbi; ++ unsigned long last_used; ++ atomic_t count; ++ +++ uid_t uid; +++ gid_t gid; +++ ++ mode_t mode; ++ size_t size; ++ ++@@ -66,15 +94,14 @@ struct autofs_info { ++ }; ++ ++ #define AUTOFS_INF_EXPIRING (1<<0) /* dentry is in the process of expiring */ +++#define AUTOFS_INF_MOUNTPOINT (1<<1) /* mountpoint status for direct expire */ ++ ++ struct autofs_wait_queue { ++ wait_queue_head_t queue; ++ struct autofs_wait_queue *next; ++ autofs_wqt_t wait_queue_token; ++ /* We use the following to see what we are waiting for */ ++- unsigned int hash; ++- unsigned int len; ++- char *name; +++ struct qstr name; ++ u32 dev; ++ u64 ino; ++ uid_t uid; ++@@ -83,15 +110,11 @@ struct autofs_wait_queue { ++ pid_t tgid; ++ /* This is for status reporting upon return */ ++ int status; ++- atomic_t wait_ctr; +++ unsigned int wait_ctr; ++ }; ++ ++ #define AUTOFS_SBI_MAGIC 0x6d4a556d ++ ++-#define AUTOFS_TYPE_INDIRECT 0x0001 ++-#define AUTOFS_TYPE_DIRECT 0x0002 ++-#define AUTOFS_TYPE_OFFSET 0x0004 ++- ++ struct autofs_sb_info { ++ u32 magic; ++ int pipefd; ++@@ -110,6 +133,9 @@ struct autofs_sb_info { ++ struct mutex wq_mutex; ++ spinlock_t fs_lock; ++ struct autofs_wait_queue *queues; /* Wait queue pointer */ +++ spinlock_t lookup_lock; +++ struct list_head active_list; +++ struct list_head expiring_list; ++ }; ++ ++ static inline struct autofs_sb_info *autofs4_sbi(struct super_block *sb) ++@@ -134,18 +160,14 @@ static inline int autofs4_oz_mode(struct ++ static inline int autofs4_ispending(struct dentry *dentry) ++ { ++ struct autofs_info *inf = autofs4_dentry_ino(dentry); ++- int pending = 0; ++ ++ if (dentry->d_flags & DCACHE_AUTOFS_PENDING) ++ return 1; ++ ++- if (inf) { ++- spin_lock(&inf->sbi->fs_lock); ++- pending = inf->flags & AUTOFS_INF_EXPIRING; ++- spin_unlock(&inf->sbi->fs_lock); ++- } +++ if (inf->flags & AUTOFS_INF_EXPIRING) +++ return 1; ++ ++- return pending; +++ return 0; ++ } ++ ++ static inline void autofs4_copy_atime(struct file *src, struct file *dst) ++@@ -159,11 +181,23 @@ void autofs4_free_ino(struct autofs_info ++ ++ /* Expiration */ ++ int is_autofs4_dentry(struct dentry *); +++int autofs4_expire_wait(struct dentry *dentry); ++ int autofs4_expire_run(struct super_block *, struct vfsmount *, ++ struct autofs_sb_info *, ++ struct autofs_packet_expire __user *); ++ int autofs4_expire_multi(struct super_block *, struct vfsmount *, ++ struct autofs_sb_info *, int __user *); +++struct dentry *autofs4_expire_direct(struct super_block *sb, +++ struct vfsmount *mnt, +++ struct autofs_sb_info *sbi, int how); +++struct dentry *autofs4_expire_indirect(struct super_block *sb, +++ struct vfsmount *mnt, +++ struct autofs_sb_info *sbi, int how); +++ +++/* Device node initialization */ +++ +++int autofs_dev_ioctl_init(void); +++void autofs_dev_ioctl_exit(void); ++ ++ /* Operations structures */ ++ ++--- linux-2.6.19.orig/fs/autofs4/root.c +++++ linux-2.6.19/fs/autofs4/root.c ++@@ -26,25 +26,25 @@ static int autofs4_dir_rmdir(struct inod ++ static int autofs4_dir_mkdir(struct inode *,struct dentry *,int); ++ static int autofs4_root_ioctl(struct inode *, struct file *,unsigned int,unsigned long); ++ static int autofs4_dir_open(struct inode *inode, struct file *file); ++-static int autofs4_dir_close(struct inode *inode, struct file *file); ++-static int autofs4_dir_readdir(struct file * filp, void * dirent, filldir_t filldir); ++-static int autofs4_root_readdir(struct file * filp, void * dirent, filldir_t filldir); ++ static struct dentry *autofs4_lookup(struct inode *,struct dentry *, struct nameidata *); ++ static void *autofs4_follow_link(struct dentry *, struct nameidata *); ++ +++#define TRIGGER_FLAGS (LOOKUP_CONTINUE | LOOKUP_DIRECTORY) +++#define TRIGGER_INTENTS (LOOKUP_OPEN | LOOKUP_CREATE) +++ ++ const struct file_operations autofs4_root_operations = { ++ .open = dcache_dir_open, ++ .release = dcache_dir_close, ++ .read = generic_read_dir, ++- .readdir = autofs4_root_readdir, +++ .readdir = dcache_readdir, ++ .ioctl = autofs4_root_ioctl, ++ }; ++ ++ const struct file_operations autofs4_dir_operations = { ++ .open = autofs4_dir_open, ++- .release = autofs4_dir_close, +++ .release = dcache_dir_close, ++ .read = generic_read_dir, ++- .readdir = autofs4_dir_readdir, +++ .readdir = dcache_readdir, ++ }; ++ ++ struct inode_operations autofs4_indirect_root_inode_operations = { ++@@ -71,42 +71,10 @@ struct inode_operations autofs4_dir_inod ++ .rmdir = autofs4_dir_rmdir, ++ }; ++ ++-static int autofs4_root_readdir(struct file *file, void *dirent, ++- filldir_t filldir) ++-{ ++- struct autofs_sb_info *sbi = autofs4_sbi(file->f_dentry->d_sb); ++- int oz_mode = autofs4_oz_mode(sbi); ++- ++- DPRINTK("called, filp->f_pos = %lld", file->f_pos); ++- ++- /* ++- * Don't set reghost flag if: ++- * 1) f_pos is larger than zero -- we've already been here. ++- * 2) we haven't even enabled reghosting in the 1st place. ++- * 3) this is the daemon doing a readdir ++- */ ++- if (oz_mode && file->f_pos == 0 && sbi->reghost_enabled) ++- sbi->needs_reghost = 1; ++- ++- DPRINTK("needs_reghost = %d", sbi->needs_reghost); ++- ++- return dcache_readdir(file, dirent, filldir); ++-} ++- ++ static int autofs4_dir_open(struct inode *inode, struct file *file) ++ { ++ struct dentry *dentry = file->f_dentry; ++- struct vfsmount *mnt = file->f_vfsmnt; ++ struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); ++- struct dentry *cursor; ++- int status; ++- ++- status = dcache_dir_open(inode, file); ++- if (status) ++- goto out; ++- ++- cursor = file->private_data; ++- cursor->d_fsdata = NULL; ++ ++ DPRINTK("file=%p dentry=%p %.*s", ++ file, dentry, dentry->d_name.len, dentry->d_name.name); ++@@ -114,157 +82,31 @@ static int autofs4_dir_open(struct inode ++ if (autofs4_oz_mode(sbi)) ++ goto out; ++ ++- if (autofs4_ispending(dentry)) { ++- DPRINTK("dentry busy"); ++- dcache_dir_close(inode, file); ++- status = -EBUSY; ++- goto out; ++- } ++- ++- status = -ENOENT; ++- if (!d_mountpoint(dentry) && dentry->d_op && dentry->d_op->d_revalidate) { ++- struct nameidata nd; ++- int empty, ret; ++- ++- /* In case there are stale directory dentrys from a failed mount */ ++- spin_lock(&dcache_lock); ++- empty = list_empty(&dentry->d_subdirs); +++ /* +++ * An empty directory in an autofs file system is always a +++ * mount point. The daemon must have failed to mount this +++ * during lookup so it doesn't exist. This can happen, for +++ * example, if user space returns an incorrect status for a +++ * mount request. Otherwise we're doing a readdir on the +++ * autofs file system so just let the libfs routines handle +++ * it. +++ */ +++ spin_lock(&dcache_lock); +++ if (!d_mountpoint(dentry) && __simple_empty(dentry)) { ++ spin_unlock(&dcache_lock); ++- ++- if (!empty) ++- d_invalidate(dentry); ++- ++- nd.flags = LOOKUP_DIRECTORY; ++- ret = (dentry->d_op->d_revalidate)(dentry, &nd); ++- ++- if (ret <= 0) { ++- if (ret < 0) ++- status = ret; ++- dcache_dir_close(inode, file); ++- goto out; ++- } ++- } ++- ++- if (d_mountpoint(dentry)) { ++- struct file *fp = NULL; ++- struct vfsmount *fp_mnt = mntget(mnt); ++- struct dentry *fp_dentry = dget(dentry); ++- ++- if (!autofs4_follow_mount(&fp_mnt, &fp_dentry)) { ++- dput(fp_dentry); ++- mntput(fp_mnt); ++- dcache_dir_close(inode, file); ++- goto out; ++- } ++- ++- fp = dentry_open(fp_dentry, fp_mnt, file->f_flags); ++- status = PTR_ERR(fp); ++- if (IS_ERR(fp)) { ++- dcache_dir_close(inode, file); ++- goto out; ++- } ++- cursor->d_fsdata = fp; ++- } ++- return 0; ++-out: ++- return status; ++-} ++- ++-static int autofs4_dir_close(struct inode *inode, struct file *file) ++-{ ++- struct dentry *dentry = file->f_dentry; ++- struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); ++- struct dentry *cursor = file->private_data; ++- int status = 0; ++- ++- DPRINTK("file=%p dentry=%p %.*s", ++- file, dentry, dentry->d_name.len, dentry->d_name.name); ++- ++- if (autofs4_oz_mode(sbi)) ++- goto out; ++- ++- if (autofs4_ispending(dentry)) { ++- DPRINTK("dentry busy"); ++- status = -EBUSY; ++- goto out; ++- } ++- ++- if (d_mountpoint(dentry)) { ++- struct file *fp = cursor->d_fsdata; ++- if (!fp) { ++- status = -ENOENT; ++- goto out; ++- } ++- filp_close(fp, current->files); ++- } ++-out: ++- dcache_dir_close(inode, file); ++- return status; ++-} ++- ++-static int autofs4_dir_readdir(struct file *file, void *dirent, filldir_t filldir) ++-{ ++- struct dentry *dentry = file->f_dentry; ++- struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); ++- struct dentry *cursor = file->private_data; ++- int status; ++- ++- DPRINTK("file=%p dentry=%p %.*s", ++- file, dentry, dentry->d_name.len, dentry->d_name.name); ++- ++- if (autofs4_oz_mode(sbi)) ++- goto out; ++- ++- if (autofs4_ispending(dentry)) { ++- DPRINTK("dentry busy"); ++- return -EBUSY; +++ return -ENOENT; ++ } +++ spin_unlock(&dcache_lock); ++ ++- if (d_mountpoint(dentry)) { ++- struct file *fp = cursor->d_fsdata; ++- ++- if (!fp) ++- return -ENOENT; ++- ++- if (!fp->f_op || !fp->f_op->readdir) ++- goto out; ++- ++- status = vfs_readdir(fp, filldir, dirent); ++- file->f_pos = fp->f_pos; ++- if (status) ++- autofs4_copy_atime(file, fp); ++- return status; ++- } ++ out: ++- return dcache_readdir(file, dirent, filldir); +++ return dcache_dir_open(inode, file); ++ } ++ ++ static int try_to_fill_dentry(struct dentry *dentry, int flags) ++ { ++ struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); ++ struct autofs_info *ino = autofs4_dentry_ino(dentry); ++- int status = 0; ++- ++- /* Block on any pending expiry here; invalidate the dentry ++- when expiration is done to trigger mount request with a new ++- dentry */ ++- if (ino && (ino->flags & AUTOFS_INF_EXPIRING)) { ++- DPRINTK("waiting for expire %p name=%.*s", ++- dentry, dentry->d_name.len, dentry->d_name.name); ++- ++- status = autofs4_wait(sbi, dentry, NFY_NONE); ++- ++- DPRINTK("expire done status=%d", status); ++- ++- /* ++- * If the directory still exists the mount request must ++- * continue otherwise it can't be followed at the right ++- * time during the walk. ++- */ ++- status = d_invalidate(dentry); ++- if (status != -EBUSY) ++- return -ENOENT; ++- } +++ int status; ++ ++ DPRINTK("dentry=%p %.*s ino=%p", ++ dentry, dentry->d_name.len, dentry->d_name.name, dentry->d_inode); ++@@ -292,7 +134,8 @@ static int try_to_fill_dentry(struct den ++ return status; ++ } ++ /* Trigger mount for path component or follow link */ ++- } else if (flags & (LOOKUP_CONTINUE | LOOKUP_DIRECTORY) || +++ } else if (dentry->d_flags & DCACHE_AUTOFS_PENDING || +++ flags & (TRIGGER_FLAGS | TRIGGER_INTENTS) || ++ current->link_count) { ++ DPRINTK("waiting for mount name=%.*s", ++ dentry->d_name.len, dentry->d_name.name); ++@@ -319,7 +162,8 @@ static int try_to_fill_dentry(struct den ++ spin_lock(&dentry->d_lock); ++ dentry->d_flags &= ~DCACHE_AUTOFS_PENDING; ++ spin_unlock(&dentry->d_lock); ++- return status; +++ +++ return 0; ++ } ++ ++ /* For autofs direct mounts the follow link triggers the mount */ ++@@ -334,50 +178,62 @@ static void *autofs4_follow_link(struct ++ DPRINTK("dentry=%p %.*s oz_mode=%d nd->flags=%d", ++ dentry, dentry->d_name.len, dentry->d_name.name, oz_mode, ++ nd->flags); ++- ++- /* If it's our master or we shouldn't trigger a mount we're done */ ++- lookup_type = nd->flags & (LOOKUP_CONTINUE | LOOKUP_DIRECTORY); ++- if (oz_mode || !lookup_type) +++ /* +++ * For an expire of a covered direct or offset mount we need +++ * to beeak out of follow_down() at the autofs mount trigger +++ * (d_mounted--), so we can see the expiring flag, and manage +++ * the blocking and following here until the expire is completed. +++ */ +++ if (oz_mode) { +++ spin_lock(&sbi->fs_lock); +++ if (ino->flags & AUTOFS_INF_EXPIRING) { +++ spin_unlock(&sbi->fs_lock); +++ /* Follow down to our covering mount. */ +++ if (!follow_down(&nd->mnt, &nd->dentry)) +++ goto done; +++ goto follow; +++ } +++ spin_unlock(&sbi->fs_lock); ++ goto done; +++ } ++ ++- /* If an expire request is pending wait for it. */ ++- if (ino && (ino->flags & AUTOFS_INF_EXPIRING)) { ++- DPRINTK("waiting for active request %p name=%.*s", ++- dentry, dentry->d_name.len, dentry->d_name.name); +++ /* If an expire request is pending everyone must wait. */ +++ autofs4_expire_wait(dentry); ++ ++- status = autofs4_wait(sbi, dentry, NFY_NONE); ++- ++- DPRINTK("request done status=%d", status); ++- } +++ /* We trigger a mount for almost all flags */ +++ lookup_type = nd->flags & (TRIGGER_FLAGS | TRIGGER_INTENTS); +++ if (!(lookup_type || dentry->d_flags & DCACHE_AUTOFS_PENDING)) +++ goto follow; ++ ++ /* ++- * If the dentry contains directories then it is an ++- * autofs multi-mount with no root mount offset. So ++- * don't try to mount it again. +++ * If the dentry contains directories then it is an autofs +++ * multi-mount with no root mount offset. So don't try to +++ * mount it again. ++ */ ++ spin_lock(&dcache_lock); ++- if (!d_mountpoint(dentry) && __simple_empty(dentry)) { +++ if (dentry->d_flags & DCACHE_AUTOFS_PENDING || +++ (!d_mountpoint(dentry) && __simple_empty(dentry))) { ++ spin_unlock(&dcache_lock); ++ ++ status = try_to_fill_dentry(dentry, 0); ++ if (status) ++ goto out_error; ++ ++- /* ++- * The mount succeeded but if there is no root mount ++- * it must be an autofs multi-mount with no root offset ++- * so we don't need to follow the mount. ++- */ ++- if (d_mountpoint(dentry)) { ++- if (!autofs4_follow_mount(&nd->mnt, &nd->dentry)) { ++- status = -ENOENT; ++- goto out_error; ++- } ++- } ++- ++- goto done; +++ goto follow; ++ } ++ spin_unlock(&dcache_lock); +++follow: +++ /* +++ * If there is no root mount it must be an autofs +++ * multi-mount with no root offset so we don't need +++ * to follow it. +++ */ +++ if (d_mountpoint(dentry)) { +++ if (!autofs4_follow_mount(&nd->mnt, &nd->dentry)) { +++ status = -ENOENT; +++ goto out_error; +++ } +++ } ++ ++ done: ++ return NULL; ++@@ -402,21 +258,33 @@ static int autofs4_revalidate(struct den ++ int status = 1; ++ ++ /* Pending dentry */ +++ spin_lock(&sbi->fs_lock); ++ if (autofs4_ispending(dentry)) { ++ /* The daemon never causes a mount to trigger */ +++ spin_unlock(&sbi->fs_lock); +++ ++ if (oz_mode) ++ return 1; ++ ++ /* +++ * If the directory has gone away due to an expire +++ * we have been called as ->d_revalidate() and so +++ * we need to return false and proceed to ->lookup(). +++ */ +++ if (autofs4_expire_wait(dentry) == -EAGAIN) +++ return 0; +++ +++ /* ++ * A zero status is success otherwise we have a ++ * negative error code. ++ */ ++ status = try_to_fill_dentry(dentry, flags); ++ if (status == 0) ++- return 1; +++ return 1; ++ ++ return status; ++ } +++ spin_unlock(&sbi->fs_lock); ++ ++ /* Negative dentry.. invalidate if "old" */ ++ if (dentry->d_inode == NULL) ++@@ -430,6 +298,7 @@ static int autofs4_revalidate(struct den ++ DPRINTK("dentry=%p %.*s, emptydir", ++ dentry, dentry->d_name.len, dentry->d_name.name); ++ spin_unlock(&dcache_lock); +++ ++ /* The daemon never causes a mount to trigger */ ++ if (oz_mode) ++ return 1; ++@@ -459,6 +328,17 @@ void autofs4_dentry_release(struct dentr ++ de->d_fsdata = NULL; ++ ++ if (inf) { +++ struct autofs_sb_info *sbi = autofs4_sbi(de->d_sb); +++ +++ if (sbi) { +++ spin_lock(&sbi->lookup_lock); +++ if (!list_empty(&inf->active)) +++ list_del(&inf->active); +++ if (!list_empty(&inf->expiring)) +++ list_del(&inf->expiring); +++ spin_unlock(&sbi->lookup_lock); +++ } +++ ++ inf->dentry = NULL; ++ inf->inode = NULL; ++ ++@@ -478,10 +358,116 @@ static struct dentry_operations autofs4_ ++ .d_release = autofs4_dentry_release, ++ }; ++ +++static struct dentry *autofs4_lookup_active(struct autofs_sb_info *sbi, struct dentry *parent, struct qstr *name) +++{ +++ unsigned int len = name->len; +++ unsigned int hash = name->hash; +++ const unsigned char *str = name->name; +++ struct list_head *p, *head; +++ +++ spin_lock(&dcache_lock); +++ spin_lock(&sbi->lookup_lock); +++ head = &sbi->active_list; +++ list_for_each(p, head) { +++ struct autofs_info *ino; +++ struct dentry *dentry; +++ struct qstr *qstr; +++ +++ ino = list_entry(p, struct autofs_info, active); +++ dentry = ino->dentry; +++ +++ spin_lock(&dentry->d_lock); +++ +++ /* Already gone? */ +++ if (atomic_read(&dentry->d_count) == 0) +++ goto next; +++ +++ qstr = &dentry->d_name; +++ +++ if (dentry->d_name.hash != hash) +++ goto next; +++ if (dentry->d_parent != parent) +++ goto next; +++ +++ if (qstr->len != len) +++ goto next; +++ if (memcmp(qstr->name, str, len)) +++ goto next; +++ +++ if (d_unhashed(dentry)) { +++ dget(dentry); +++ spin_unlock(&dentry->d_lock); +++ spin_unlock(&sbi->lookup_lock); +++ spin_unlock(&dcache_lock); +++ return dentry; +++ } +++next: +++ spin_unlock(&dentry->d_lock); +++ } +++ spin_unlock(&sbi->lookup_lock); +++ spin_unlock(&dcache_lock); +++ +++ return NULL; +++} +++ +++static struct dentry *autofs4_lookup_expiring(struct autofs_sb_info *sbi, struct dentry *parent, struct qstr *name) +++{ +++ unsigned int len = name->len; +++ unsigned int hash = name->hash; +++ const unsigned char *str = name->name; +++ struct list_head *p, *head; +++ +++ spin_lock(&dcache_lock); +++ spin_lock(&sbi->lookup_lock); +++ head = &sbi->expiring_list; +++ list_for_each(p, head) { +++ struct autofs_info *ino; +++ struct dentry *dentry; +++ struct qstr *qstr; +++ +++ ino = list_entry(p, struct autofs_info, expiring); +++ dentry = ino->dentry; +++ +++ spin_lock(&dentry->d_lock); +++ +++ /* Bad luck, we've already been dentry_iput */ +++ if (!dentry->d_inode) +++ goto next; +++ +++ qstr = &dentry->d_name; +++ +++ if (dentry->d_name.hash != hash) +++ goto next; +++ if (dentry->d_parent != parent) +++ goto next; +++ +++ if (qstr->len != len) +++ goto next; +++ if (memcmp(qstr->name, str, len)) +++ goto next; +++ +++ if (d_unhashed(dentry)) { +++ dget(dentry); +++ spin_unlock(&dentry->d_lock); +++ spin_unlock(&sbi->lookup_lock); +++ spin_unlock(&dcache_lock); +++ return dentry; +++ } +++next: +++ spin_unlock(&dentry->d_lock); +++ } +++ spin_unlock(&sbi->lookup_lock); +++ spin_unlock(&dcache_lock); +++ +++ return NULL; +++} +++ ++ /* Lookups in the root directory */ ++ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) ++ { ++ struct autofs_sb_info *sbi; +++ struct autofs_info *ino; +++ struct dentry *expiring, *unhashed; ++ int oz_mode; ++ ++ DPRINTK("name = %.*s", ++@@ -497,29 +483,67 @@ static struct dentry *autofs4_lookup(str ++ DPRINTK("pid = %u, pgrp = %u, catatonic = %d, oz_mode = %d", ++ current->pid, process_group(current), sbi->catatonic, oz_mode); ++ ++- /* ++- * Mark the dentry incomplete, but add it. This is needed so ++- * that the VFS layer knows about the dentry, and we can count ++- * on catching any lookups through the revalidate. ++- * ++- * Let all the hard work be done by the revalidate function that ++- * needs to be able to do this anyway.. ++- * ++- * We need to do this before we release the directory semaphore. ++- */ ++- dentry->d_op = &autofs4_root_dentry_operations; +++ unhashed = autofs4_lookup_active(sbi, dentry->d_parent, &dentry->d_name); +++ if (unhashed) +++ dentry = unhashed; +++ else { +++ /* +++ * Mark the dentry incomplete but don't hash it. We do this +++ * to serialize our inode creation operations (symlink and +++ * mkdir) which prevents deadlock during the callback to +++ * the daemon. Subsequent user space lookups for the same +++ * dentry are placed on the wait queue while the daemon +++ * itself is allowed passage unresticted so the create +++ * operation itself can then hash the dentry. Finally, +++ * we check for the hashed dentry and return the newly +++ * hashed dentry. +++ */ +++ dentry->d_op = &autofs4_root_dentry_operations; +++ +++ /* +++ * And we need to ensure that the same dentry is used for +++ * all following lookup calls until it is hashed so that +++ * the dentry flags are persistent throughout the request. +++ */ +++ ino = autofs4_init_ino(NULL, sbi, 0555); +++ if (!ino) +++ return ERR_PTR(-ENOMEM); +++ +++ dentry->d_fsdata = ino; +++ ino->dentry = dentry; +++ +++ spin_lock(&sbi->lookup_lock); +++ list_add(&ino->active, &sbi->active_list); +++ spin_unlock(&sbi->lookup_lock); +++ +++ d_instantiate(dentry, NULL); +++ } ++ ++ if (!oz_mode) { +++ mutex_unlock(&dir->i_mutex); +++ expiring = autofs4_lookup_expiring(sbi, +++ dentry->d_parent, +++ &dentry->d_name); +++ if (expiring) { +++ /* +++ * If we are racing with expire the request might not +++ * be quite complete but the directory has been removed +++ * so it must have been successful, so just wait for it. +++ */ +++ ino = autofs4_dentry_ino(expiring); +++ autofs4_expire_wait(expiring); +++ spin_lock(&sbi->lookup_lock); +++ if (!list_empty(&ino->expiring)) +++ list_del_init(&ino->expiring); +++ spin_unlock(&sbi->lookup_lock); +++ dput(expiring); +++ } +++ ++ spin_lock(&dentry->d_lock); ++ dentry->d_flags |= DCACHE_AUTOFS_PENDING; ++ spin_unlock(&dentry->d_lock); ++- } ++- dentry->d_fsdata = NULL; ++- d_add(dentry, NULL); ++- ++- if (dentry->d_op && dentry->d_op->d_revalidate) { ++- mutex_unlock(&dir->i_mutex); ++- (dentry->d_op->d_revalidate)(dentry, nd); +++ if (dentry->d_op && dentry->d_op->d_revalidate) +++ (dentry->d_op->d_revalidate)(dentry, nd); ++ mutex_lock(&dir->i_mutex); ++ } ++ ++@@ -534,22 +558,47 @@ static struct dentry *autofs4_lookup(str ++ if (sigismember (sigset, SIGKILL) || ++ sigismember (sigset, SIGQUIT) || ++ sigismember (sigset, SIGINT)) { +++ if (unhashed) +++ dput(unhashed); ++ return ERR_PTR(-ERESTARTNOINTR); ++ } ++ } ++- spin_lock(&dentry->d_lock); ++- dentry->d_flags &= ~DCACHE_AUTOFS_PENDING; ++- spin_unlock(&dentry->d_lock); +++ if (!oz_mode) { +++ spin_lock(&dentry->d_lock); +++ dentry->d_flags &= ~DCACHE_AUTOFS_PENDING; +++ spin_unlock(&dentry->d_lock); +++ } ++ } ++ ++ /* ++ * If this dentry is unhashed, then we shouldn't honour this ++- * lookup even if the dentry is positive. Returning ENOENT here ++- * doesn't do the right thing for all system calls, but it should ++- * be OK for the operations we permit from an autofs. +++ * lookup. Returning ENOENT here doesn't do the right thing +++ * for all system calls, but it should be OK for the operations +++ * we permit from an autofs. ++ */ ++- if (dentry->d_inode && d_unhashed(dentry)) ++- return ERR_PTR(-ENOENT); +++ if (!oz_mode && d_unhashed(dentry)) { +++ /* +++ * A user space application can (and has done in the past) +++ * remove and re-create this directory during the callback. +++ * This can leave us with an unhashed dentry, but a +++ * successful mount! So we need to perform another +++ * cached lookup in case the dentry now exists. +++ */ +++ struct dentry *parent = dentry->d_parent; +++ struct dentry *new = d_lookup(parent, &dentry->d_name); +++ if (new != NULL) +++ dentry = new; +++ else +++ dentry = ERR_PTR(-ENOENT); +++ +++ if (unhashed) +++ dput(unhashed); +++ +++ return dentry; +++ } +++ +++ if (unhashed) +++ return unhashed; ++ ++ return NULL; ++ } ++@@ -571,21 +620,32 @@ static int autofs4_dir_symlink(struct in ++ return -EACCES; ++ ++ ino = autofs4_init_ino(ino, sbi, S_IFLNK | 0555); ++- if (ino == NULL) ++- return -ENOSPC; +++ if (!ino) +++ return -ENOMEM; ++ ++- ino->size = strlen(symname); ++- ino->u.symlink = cp = kmalloc(ino->size + 1, GFP_KERNEL); +++ spin_lock(&sbi->lookup_lock); +++ if (!list_empty(&ino->active)) +++ list_del_init(&ino->active); +++ spin_unlock(&sbi->lookup_lock); ++ ++- if (cp == NULL) { ++- kfree(ino); ++- return -ENOSPC; +++ ino->size = strlen(symname); +++ cp = kmalloc(ino->size + 1, GFP_KERNEL); +++ if (!cp) { +++ if (!dentry->d_fsdata) +++ kfree(ino); +++ return -ENOMEM; ++ } ++ ++ strcpy(cp, symname); ++ ++ inode = autofs4_get_inode(dir->i_sb, ino); ++- d_instantiate(dentry, inode); +++ if (!inode) { +++ kfree(cp); +++ if (!dentry->d_fsdata) +++ kfree(ino); +++ return -ENOMEM; +++ } +++ d_add(dentry, inode); ++ ++ if (dir == dir->i_sb->s_root->d_inode) ++ dentry->d_op = &autofs4_root_dentry_operations; ++@@ -600,6 +660,7 @@ static int autofs4_dir_symlink(struct in ++ atomic_inc(&p_ino->count); ++ ino->inode = inode; ++ +++ ino->u.symlink = cp; ++ dir->i_mtime = CURRENT_TIME; ++ ++ return 0; ++@@ -611,9 +672,9 @@ static int autofs4_dir_symlink(struct in ++ * Normal filesystems would do a "d_delete()" to tell the VFS dcache ++ * that the file no longer exists. However, doing that means that the ++ * VFS layer can turn the dentry into a negative dentry. We don't want ++- * this, because since the unlink is probably the result of an expire. ++- * We simply d_drop it, which allows the dentry lookup to remount it ++- * if necessary. +++ * this, because the unlink is probably the result of an expire. +++ * We simply d_drop it and add it to a expiring list in the super block, +++ * which allows the dentry lookup to check for an incomplete expire. ++ * ++ * If a process is blocked on the dentry waiting for the expire to finish, ++ * it will invalidate the dentry and try to mount with a new one. ++@@ -642,7 +703,15 @@ static int autofs4_dir_unlink(struct ino ++ ++ dir->i_mtime = CURRENT_TIME; ++ ++- d_drop(dentry); +++ spin_lock(&dcache_lock); +++ spin_lock(&sbi->lookup_lock); +++ if (list_empty(&ino->expiring)) +++ list_add(&ino->expiring, &sbi->expiring_list); +++ spin_unlock(&sbi->lookup_lock); +++ spin_lock(&dentry->d_lock); +++ __d_drop(dentry); +++ spin_unlock(&dentry->d_lock); +++ spin_unlock(&dcache_lock); ++ ++ return 0; ++ } ++@@ -653,6 +722,9 @@ static int autofs4_dir_rmdir(struct inod ++ struct autofs_info *ino = autofs4_dentry_ino(dentry); ++ struct autofs_info *p_ino; ++ +++ DPRINTK("dentry %p, removing %.*s", +++ dentry, dentry->d_name.len, dentry->d_name.name); +++ ++ if (!autofs4_oz_mode(sbi)) ++ return -EACCES; ++ ++@@ -661,6 +733,10 @@ static int autofs4_dir_rmdir(struct inod ++ spin_unlock(&dcache_lock); ++ return -ENOTEMPTY; ++ } +++ spin_lock(&sbi->lookup_lock); +++ if (list_empty(&ino->expiring)) +++ list_add(&ino->expiring, &sbi->expiring_list); +++ spin_unlock(&sbi->lookup_lock); ++ spin_lock(&dentry->d_lock); ++ __d_drop(dentry); ++ spin_unlock(&dentry->d_lock); ++@@ -695,11 +771,21 @@ static int autofs4_dir_mkdir(struct inod ++ dentry, dentry->d_name.len, dentry->d_name.name); ++ ++ ino = autofs4_init_ino(ino, sbi, S_IFDIR | 0555); ++- if (ino == NULL) ++- return -ENOSPC; +++ if (!ino) +++ return -ENOMEM; +++ +++ spin_lock(&sbi->lookup_lock); +++ if (!list_empty(&ino->active)) +++ list_del_init(&ino->active); +++ spin_unlock(&sbi->lookup_lock); ++ ++ inode = autofs4_get_inode(dir->i_sb, ino); ++- d_instantiate(dentry, inode); +++ if (!inode) { +++ if (!dentry->d_fsdata) +++ kfree(ino); +++ return -ENOMEM; +++ } +++ d_add(dentry, inode); ++ ++ if (dir == dir->i_sb->s_root->d_inode) ++ dentry->d_op = &autofs4_root_dentry_operations; ++@@ -751,44 +837,6 @@ static inline int autofs4_get_protosubve ++ } ++ ++ /* ++- * Tells the daemon whether we need to reghost or not. Also, clears ++- * the reghost_needed flag. ++- */ ++-static inline int autofs4_ask_reghost(struct autofs_sb_info *sbi, int __user *p) ++-{ ++- int status; ++- ++- DPRINTK("returning %d", sbi->needs_reghost); ++- ++- status = put_user(sbi->needs_reghost, p); ++- if ( status ) ++- return status; ++- ++- sbi->needs_reghost = 0; ++- return 0; ++-} ++- ++-/* ++- * Enable / Disable reghosting ioctl() operation ++- */ ++-static inline int autofs4_toggle_reghost(struct autofs_sb_info *sbi, int __user *p) ++-{ ++- int status; ++- int val; ++- ++- status = get_user(val, p); ++- ++- DPRINTK("reghost = %d", val); ++- ++- if (status) ++- return status; ++- ++- /* turn on/off reghosting, with the val */ ++- sbi->reghost_enabled = val; ++- return 0; ++-} ++- ++-/* ++ * Tells the daemon whether it can umount the autofs mount. ++ */ ++ static inline int autofs4_ask_umount(struct vfsmount *mnt, int __user *p) ++@@ -852,11 +900,6 @@ static int autofs4_root_ioctl(struct ino ++ case AUTOFS_IOC_SETTIMEOUT: ++ return autofs4_get_set_timeout(sbi, p); ++ ++- case AUTOFS_IOC_TOGGLEREGHOST: ++- return autofs4_toggle_reghost(sbi, p); ++- case AUTOFS_IOC_ASKREGHOST: ++- return autofs4_ask_reghost(sbi, p); ++- ++ case AUTOFS_IOC_ASKUMOUNT: ++ return autofs4_ask_umount(filp->f_vfsmnt, p); ++ ++--- linux-2.6.19.orig/fs/autofs4/expire.c +++++ linux-2.6.19/fs/autofs4/expire.c ++@@ -56,12 +56,25 @@ static int autofs4_mount_busy(struct vfs ++ mntget(mnt); ++ dget(dentry); ++ ++- if (!autofs4_follow_mount(&mnt, &dentry)) +++ if (!follow_down(&mnt, &dentry)) ++ goto done; ++ ++- /* This is an autofs submount, we can't expire it */ ++- if (is_autofs4_dentry(dentry)) ++- goto done; +++ if (is_autofs4_dentry(dentry)) { +++ struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); +++ +++ /* This is an autofs submount, we can't expire it */ +++ if (autofs_type_indirect(sbi->type)) +++ goto done; +++ +++ /* +++ * Otherwise it's an offset mount and we need to check +++ * if we can umount its mount, if there is one. +++ */ +++ if (!d_mountpoint(dentry)) { +++ status = 0; +++ goto done; +++ } +++ } ++ ++ /* Update the expiry counter if fs is busy */ ++ if (!may_umount_tree(mnt)) { ++@@ -73,8 +86,8 @@ static int autofs4_mount_busy(struct vfs ++ status = 0; ++ done: ++ DPRINTK("returning = %d", status); ++- mntput(mnt); ++ dput(dentry); +++ mntput(mnt); ++ return status; ++ } ++ ++@@ -244,10 +257,10 @@ cont: ++ } ++ ++ /* Check if we can expire a direct mount (possibly a tree) */ ++-static struct dentry *autofs4_expire_direct(struct super_block *sb, ++- struct vfsmount *mnt, ++- struct autofs_sb_info *sbi, ++- int how) +++struct dentry *autofs4_expire_direct(struct super_block *sb, +++ struct vfsmount *mnt, +++ struct autofs_sb_info *sbi, +++ int how) ++ { ++ unsigned long timeout; ++ struct dentry *root = dget(sb->s_root); ++@@ -259,13 +272,15 @@ static struct dentry *autofs4_expire_dir ++ now = jiffies; ++ timeout = sbi->exp_timeout; ++ ++- /* Lock the tree as we must expire as a whole */ ++ spin_lock(&sbi->fs_lock); ++ if (!autofs4_direct_busy(mnt, root, timeout, do_now)) { ++ struct autofs_info *ino = autofs4_dentry_ino(root); ++- ++- /* Set this flag early to catch sys_chdir and the like */ +++ if (d_mountpoint(root)) { +++ ino->flags |= AUTOFS_INF_MOUNTPOINT; +++ root->d_mounted--; +++ } ++ ino->flags |= AUTOFS_INF_EXPIRING; +++ init_completion(&ino->expire_complete); ++ spin_unlock(&sbi->fs_lock); ++ return root; ++ } ++@@ -281,10 +296,10 @@ static struct dentry *autofs4_expire_dir ++ * - it is unused by any user process ++ * - it has been unused for exp_timeout time ++ */ ++-static struct dentry *autofs4_expire_indirect(struct super_block *sb, ++- struct vfsmount *mnt, ++- struct autofs_sb_info *sbi, ++- int how) +++struct dentry *autofs4_expire_indirect(struct super_block *sb, +++ struct vfsmount *mnt, +++ struct autofs_sb_info *sbi, +++ int how) ++ { ++ unsigned long timeout; ++ struct dentry *root = sb->s_root; ++@@ -292,6 +307,8 @@ static struct dentry *autofs4_expire_ind ++ struct list_head *next; ++ int do_now = how & AUTOFS_EXP_IMMEDIATE; ++ int exp_leaves = how & AUTOFS_EXP_LEAVES; +++ struct autofs_info *ino; +++ unsigned int ino_count; ++ ++ if (!root) ++ return NULL; ++@@ -316,6 +333,9 @@ static struct dentry *autofs4_expire_ind ++ dentry = dget(dentry); ++ spin_unlock(&dcache_lock); ++ +++ spin_lock(&sbi->fs_lock); +++ ino = autofs4_dentry_ino(dentry); +++ ++ /* ++ * Case 1: (i) indirect mount or top level pseudo direct mount ++ * (autofs-4.1). ++@@ -326,6 +346,11 @@ static struct dentry *autofs4_expire_ind ++ DPRINTK("checking mountpoint %p %.*s", ++ dentry, (int)dentry->d_name.len, dentry->d_name.name); ++ +++ /* Path walk currently on this dentry? */ +++ ino_count = atomic_read(&ino->count) + 2; +++ if (atomic_read(&dentry->d_count) > ino_count) +++ goto next; +++ ++ /* Can we umount this guy */ ++ if (autofs4_mount_busy(mnt, dentry)) ++ goto next; ++@@ -333,7 +358,7 @@ static struct dentry *autofs4_expire_ind ++ /* Can we expire this guy */ ++ if (autofs4_can_expire(dentry, timeout, do_now)) { ++ expired = dentry; ++- break; +++ goto found; ++ } ++ goto next; ++ } ++@@ -343,46 +368,80 @@ static struct dentry *autofs4_expire_ind ++ ++ /* Case 2: tree mount, expire iff entire tree is not busy */ ++ if (!exp_leaves) { ++- /* Lock the tree as we must expire as a whole */ ++- spin_lock(&sbi->fs_lock); ++- if (!autofs4_tree_busy(mnt, dentry, timeout, do_now)) { ++- struct autofs_info *inf = autofs4_dentry_ino(dentry); +++ /* Path walk currently on this dentry? */ +++ ino_count = atomic_read(&ino->count) + 1; +++ if (atomic_read(&dentry->d_count) > ino_count) +++ goto next; ++ ++- /* Set this flag early to catch sys_chdir and the like */ ++- inf->flags |= AUTOFS_INF_EXPIRING; ++- spin_unlock(&sbi->fs_lock); +++ if (!autofs4_tree_busy(mnt, dentry, timeout, do_now)) { ++ expired = dentry; ++- break; +++ goto found; ++ } ++- spin_unlock(&sbi->fs_lock); ++ /* ++ * Case 3: pseudo direct mount, expire individual leaves ++ * (autofs-4.1). ++ */ ++ } else { +++ /* Path walk currently on this dentry? */ +++ ino_count = atomic_read(&ino->count) + 1; +++ if (atomic_read(&dentry->d_count) > ino_count) +++ goto next; +++ ++ expired = autofs4_check_leaves(mnt, dentry, timeout, do_now); ++ if (expired) { ++ dput(dentry); ++- break; +++ goto found; ++ } ++ } ++ next: +++ spin_unlock(&sbi->fs_lock); ++ dput(dentry); ++ spin_lock(&dcache_lock); ++ next = next->next; ++ } +++ spin_unlock(&dcache_lock); +++ return NULL; ++ ++- if (expired) { ++- DPRINTK("returning %p %.*s", ++- expired, (int)expired->d_name.len, expired->d_name.name); ++- spin_lock(&dcache_lock); ++- list_move(&expired->d_parent->d_subdirs, &expired->d_u.d_child); ++- spin_unlock(&dcache_lock); ++- return expired; ++- } +++found: +++ DPRINTK("returning %p %.*s", +++ expired, (int)expired->d_name.len, expired->d_name.name); +++ ino = autofs4_dentry_ino(expired); +++ ino->flags |= AUTOFS_INF_EXPIRING; +++ init_completion(&ino->expire_complete); +++ spin_unlock(&sbi->fs_lock); +++ spin_lock(&dcache_lock); +++ list_move(&expired->d_parent->d_subdirs, &expired->d_u.d_child); ++ spin_unlock(&dcache_lock); +++ return expired; +++} ++ ++- return NULL; +++int autofs4_expire_wait(struct dentry *dentry) +++{ +++ struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); +++ struct autofs_info *ino = autofs4_dentry_ino(dentry); +++ int status; +++ +++ /* Block on any pending expire */ +++ spin_lock(&sbi->fs_lock); +++ if (ino->flags & AUTOFS_INF_EXPIRING) { +++ spin_unlock(&sbi->fs_lock); +++ +++ DPRINTK("waiting for expire %p name=%.*s", +++ dentry, dentry->d_name.len, dentry->d_name.name); +++ +++ status = autofs4_wait(sbi, dentry, NFY_NONE); +++ wait_for_completion(&ino->expire_complete); +++ +++ DPRINTK("expire done status=%d", status); +++ +++ if (d_unhashed(dentry)) +++ return -EAGAIN; +++ +++ return status; +++ } +++ spin_unlock(&sbi->fs_lock); +++ +++ return 0; ++ } ++ ++ /* Perform an expiry operation */ ++@@ -392,7 +451,9 @@ int autofs4_expire_run(struct super_bloc ++ struct autofs_packet_expire __user *pkt_p) ++ { ++ struct autofs_packet_expire pkt; +++ struct autofs_info *ino; ++ struct dentry *dentry; +++ int ret = 0; ++ ++ memset(&pkt,0,sizeof pkt); ++ ++@@ -408,9 +469,15 @@ int autofs4_expire_run(struct super_bloc ++ dput(dentry); ++ ++ if ( copy_to_user(pkt_p, &pkt, sizeof(struct autofs_packet_expire)) ) ++- return -EFAULT; +++ ret = -EFAULT; ++ ++- return 0; +++ spin_lock(&sbi->fs_lock); +++ ino = autofs4_dentry_ino(dentry); +++ ino->flags &= ~AUTOFS_INF_EXPIRING; +++ complete_all(&ino->expire_complete); +++ spin_unlock(&sbi->fs_lock); +++ +++ return ret; ++ } ++ ++ /* Call repeatedly until it returns -EAGAIN, meaning there's nothing ++@@ -425,7 +492,7 @@ int autofs4_expire_multi(struct super_bl ++ if (arg && get_user(do_now, arg)) ++ return -EFAULT; ++ ++- if (sbi->type & AUTOFS_TYPE_DIRECT) +++ if (autofs_type_trigger(sbi->type)) ++ dentry = autofs4_expire_direct(sb, mnt, sbi, do_now); ++ else ++ dentry = autofs4_expire_indirect(sb, mnt, sbi, do_now); ++@@ -435,9 +502,16 @@ int autofs4_expire_multi(struct super_bl ++ ++ /* This is synchronous because it makes the daemon a ++ little easier */ ++- ino->flags |= AUTOFS_INF_EXPIRING; ++ ret = autofs4_wait(sbi, dentry, NFY_EXPIRE); +++ +++ spin_lock(&sbi->fs_lock); +++ if (ino->flags & AUTOFS_INF_MOUNTPOINT) { +++ sb->s_root->d_mounted++; +++ ino->flags &= ~AUTOFS_INF_MOUNTPOINT; +++ } ++ ino->flags &= ~AUTOFS_INF_EXPIRING; +++ complete_all(&ino->expire_complete); +++ spin_unlock(&sbi->fs_lock); ++ dput(dentry); ++ } ++ ++--- linux-2.6.19.orig/include/linux/compat_ioctl.h +++++ linux-2.6.19/include/linux/compat_ioctl.h ++@@ -568,8 +568,6 @@ COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOVER) ++ COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE) ++ COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE_MULTI) ++ COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOSUBVER) ++-COMPATIBLE_IOCTL(AUTOFS_IOC_ASKREGHOST) ++-COMPATIBLE_IOCTL(AUTOFS_IOC_TOGGLEREGHOST) ++ COMPATIBLE_IOCTL(AUTOFS_IOC_ASKUMOUNT) ++ /* Raw devices */ ++ COMPATIBLE_IOCTL(RAW_SETBIND) ++--- /dev/null +++++ linux-2.6.19/Documentation/filesystems/autofs4-mount-control.txt ++@@ -0,0 +1,414 @@ +++ +++Miscellaneous Device control operations for the autofs4 kernel module +++==================================================================== +++ +++The problem +++=========== +++ +++There is a problem with active restarts in autofs (that is to say +++restarting autofs when there are busy mounts). +++ +++During normal operation autofs uses a file descriptor opened on the +++directory that is being managed in order to be able to issue control +++operations. Using a file descriptor gives ioctl operations access to +++autofs specific information stored in the super block. The operations +++are things such as setting an autofs mount catatonic, setting the +++expire timeout and requesting expire checks. As is explained below, +++certain types of autofs triggered mounts can end up covering an autofs +++mount itself which prevents us being able to use open(2) to obtain a +++file descriptor for these operations if we don't already have one open. +++ +++Currently autofs uses "umount -l" (lazy umount) to clear active mounts +++at restart. While using lazy umount works for most cases, anything that +++needs to walk back up the mount tree to construct a path, such as +++getcwd(2) and the proc file system /proc//cwd, no longer works +++because the point from which the path is constructed has been detached +++from the mount tree. +++ +++The actual problem with autofs is that it can't reconnect to existing +++mounts. Immediately one thinks of just adding the ability to remount +++autofs file systems would solve it, but alas, that can't work. This is +++because autofs direct mounts and the implementation of "on demand mount +++and expire" of nested mount trees have the file system mounted directly +++on top of the mount trigger directory dentry. +++ +++For example, there are two types of automount maps, direct (in the kernel +++module source you will see a third type called an offset, which is just +++a direct mount in disguise) and indirect. +++ +++Here is a master map with direct and indirect map entries: +++ +++/- /etc/auto.direct +++/test /etc/auto.indirect +++ +++and the corresponding map files: +++ +++/etc/auto.direct: +++ +++/automount/dparse/g6 budgie:/autofs/export1 +++/automount/dparse/g1 shark:/autofs/export1 +++and so on. +++ +++/etc/auto.indirect: +++ +++g1 shark:/autofs/export1 +++g6 budgie:/autofs/export1 +++and so on. +++ +++For the above indirect map an autofs file system is mounted on /test and +++mounts are triggered for each sub-directory key by the inode lookup +++operation. So we see a mount of shark:/autofs/export1 on /test/g1, for +++example. +++ +++The way that direct mounts are handled is by making an autofs mount on +++each full path, such as /automount/dparse/g1, and using it as a mount +++trigger. So when we walk on the path we mount shark:/autofs/export1 "on +++top of this mount point". Since these are always directories we can +++use the follow_link inode operation to trigger the mount. +++ +++But, each entry in direct and indirect maps can have offsets (making +++them multi-mount map entries). +++ +++For example, an indirect mount map entry could also be: +++ +++g1 \ +++ / shark:/autofs/export5/testing/test \ +++ /s1 shark:/autofs/export/testing/test/s1 \ +++ /s2 shark:/autofs/export5/testing/test/s2 \ +++ /s1/ss1 shark:/autofs/export1 \ +++ /s2/ss2 shark:/autofs/export2 +++ +++and a similarly a direct mount map entry could also be: +++ +++/automount/dparse/g1 \ +++ / shark:/autofs/export5/testing/test \ +++ /s1 shark:/autofs/export/testing/test/s1 \ +++ /s2 shark:/autofs/export5/testing/test/s2 \ +++ /s1/ss1 shark:/autofs/export2 \ +++ /s2/ss2 shark:/autofs/export2 +++ +++One of the issues with version 4 of autofs was that, when mounting an +++entry with a large number of offsets, possibly with nesting, we needed +++to mount and umount all of the offsets as a single unit. Not really a +++problem, except for people with a large number of offsets in map entries. +++This mechanism is used for the well known "hosts" map and we have seen +++cases (in 2.4) where the available number of mounts are exhausted or +++where the number of privileged ports available is exhausted. +++ +++In version 5 we mount only as we go down the tree of offsets and +++similarly for expiring them which resolves the above problem. There is +++somewhat more detail to the implementation but it isn't needed for the +++sake of the problem explanation. The one important detail is that these +++offsets are implemented using the same mechanism as the direct mounts +++above and so the mount points can be covered by a mount. +++ +++The current autofs implementation uses an ioctl file descriptor opened +++on the mount point for control operations. The references held by the +++descriptor are accounted for in checks made to determine if a mount is +++in use and is also used to access autofs file system information held +++in the mount super block. So the use of a file handle needs to be +++retained. +++ +++ +++The Solution +++============ +++ +++To be able to restart autofs leaving existing direct, indirect and +++offset mounts in place we need to be able to obtain a file handle +++for these potentially covered autofs mount points. Rather than just +++implement an isolated operation it was decided to re-implement the +++existing ioctl interface and add new operations to provide this +++functionality. +++ +++In addition, to be able to reconstruct a mount tree that has busy mounts, +++the uid and gid of the last user that triggered the mount needs to be +++available because these can be used as macro substitution variables in +++autofs maps. They are recorded at mount request time and an operation +++has been added to retrieve them. +++ +++Since we're re-implementing the control interface, a couple of other +++problems with the existing interface have been addressed. First, when +++a mount or expire operation completes a status is returned to the +++kernel by either a "send ready" or a "send fail" operation. The +++"send fail" operation of the ioctl interface could only ever send +++ENOENT so the re-implementation allows user space to send an actual +++status. Another expensive operation in user space, for those using +++very large maps, is discovering if a mount is present. Usually this +++involves scanning /proc/mounts and since it needs to be done quite +++often it can introduce significant overhead when there are many entries +++in the mount table. An operation to lookup the mount status of a mount +++point dentry (covered or not) has also been added. +++ +++Current kernel development policy recommends avoiding the use of the +++ioctl mechanism in favor of systems such as Netlink. An implementation +++using this system was attempted to evaluate its suitability and it was +++found to be inadequate, in this case. The Generic Netlink system was +++used for this as raw Netlink would lead to a significant increase in +++complexity. There's no question that the Generic Netlink system is an +++elegant solution for common case ioctl functions but it's not a complete +++replacement probably because it's primary purpose in life is to be a +++message bus implementation rather than specifically an ioctl replacement. +++While it would be possible to work around this there is one concern +++that lead to the decision to not use it. This is that the autofs +++expire in the daemon has become far to complex because umount +++candidates are enumerated, almost for no other reason than to "count" +++the number of times to call the expire ioctl. This involves scanning +++the mount table which has proved to be a big overhead for users with +++large maps. The best way to improve this is try and get back to the +++way the expire was done long ago. That is, when an expire request is +++issued for a mount (file handle) we should continually call back to +++the daemon until we can't umount any more mounts, then return the +++appropriate status to the daemon. At the moment we just expire one +++mount at a time. A Generic Netlink implementation would exclude this +++possibility for future development due to the requirements of the +++message bus architecture. +++ +++ +++autofs4 Miscellaneous Device mount control interface +++==================================================== +++ +++The control interface is opening a device node, typically /dev/autofs. +++ +++All the ioctls use a common structure to pass the needed parameter +++information and return operation results: +++ +++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]; +++}; +++ +++The ioctlfd field is a mount point file descriptor of an autofs mount +++point. It is returned by the open call and is used by all calls except +++the check for whether a given path is a mount point, where it may +++optionally be used to check a specific mount corresponding to a given +++mount point file descriptor, and when requesting the uid and gid of the +++last successful mount on a directory within the autofs file system. +++ +++The anonymous union is used to communicate parameters and results of calls +++made as described below. +++ +++The path field is used to pass a path where it is needed and the size field +++is used account for the increased structure length when translating the +++structure sent from user space. +++ +++This structure can be initialized before setting specific fields by using +++the void function call init_autofs_dev_ioctl(struct autofs_dev_ioctl *). +++ +++All of the ioctls perform a copy of this structure from user space to +++kernel space and return -EINVAL if the size parameter is smaller than +++the structure size itself, -ENOMEM if the kernel memory allocation fails +++or -EFAULT if the copy itself fails. Other checks include a version check +++of the compiled in user space version against the module version and a +++mismatch results in a -EINVAL return. If the size field is greater than +++the structure size then a path is assumed to be present and is checked to +++ensure it begins with a "/" and is NULL terminated, otherwise -EINVAL is +++returned. Following these checks, for all ioctl commands except +++AUTOFS_DEV_IOCTL_VERSION_CMD, AUTOFS_DEV_IOCTL_OPENMOUNT_CMD and +++AUTOFS_DEV_IOCTL_CLOSEMOUNT_CMD the ioctlfd is validated and if it is +++not a valid descriptor or doesn't correspond to an autofs mount point +++an error of -EBADF, -ENOTTY or -EINVAL (not an autofs descriptor) is +++returned. +++ +++ +++The ioctls +++========== +++ +++An example of an implementation which uses this interface can be seen +++in autofs version 5.0.4 and later in file lib/dev-ioctl-lib.c of the +++distribution tar available for download from kernel.org in directory +++/pub/linux/daemons/autofs/v5. +++ +++The device node ioctl operations implemented by this interface are: +++ +++ +++AUTOFS_DEV_IOCTL_VERSION +++------------------------ +++ +++Get the major and minor version of the autofs4 device ioctl kernel module +++implementation. It requires an initialized struct autofs_dev_ioctl as an +++input parameter and sets the version information in the passed in structure. +++It returns 0 on success or the error -EINVAL if a version mismatch is +++detected. +++ +++ +++AUTOFS_DEV_IOCTL_PROTOVER_CMD and AUTOFS_DEV_IOCTL_PROTOSUBVER_CMD +++------------------------------------------------------------------ +++ +++Get the major and minor version of the autofs4 protocol version understood +++by loaded module. This call requires an initialized struct autofs_dev_ioctl +++with the ioctlfd field set to a valid autofs mount point descriptor +++and sets the requested version number in structure field protover.version +++and ptotosubver.sub_version respectively. These commands return 0 on +++success or one of the negative error codes if validation fails. +++ +++ +++AUTOFS_DEV_IOCTL_OPENMOUNT_CMD and AUTOFS_DEV_IOCTL_CLOSEMOUNT_CMD +++------------------------------------------------------------------ +++ +++Obtain and release a file descriptor for an autofs managed mount point +++path. The open call requires an initialized struct autofs_dev_ioctl with +++the the path field set and the size field adjusted appropriately as well +++as the openmount.devid field set to the device number of the autofs mount. +++The device number of an autofs mounted filesystem can be obtained by using +++the AUTOFS_DEV_IOCTL_ISMOUNTPOINT ioctl function by providing the path +++and autofs mount type, as described below. The close call requires an +++initialized struct autofs_dev_ioct with the ioctlfd field set to the +++descriptor obtained from the open call. The release of the file descriptor +++can also be done with close(2) so any open descriptors will also be +++closed at process exit. The close call is included in the implemented +++operations largely for completeness and to provide for a consistent +++user space implementation. +++ +++ +++AUTOFS_DEV_IOCTL_READY_CMD and AUTOFS_DEV_IOCTL_FAIL_CMD +++-------------------------------------------------------- +++ +++Return mount and expire result status from user space to the kernel. +++Both of these calls require an initialized struct autofs_dev_ioctl +++with the ioctlfd field set to the descriptor obtained from the open +++call and the ready.token or fail.token field set to the wait queue +++token number, received by user space in the foregoing mount or expire +++request. The fail.status field is set to the status to be returned when +++sending a failure notification with AUTOFS_DEV_IOCTL_FAIL_CMD. +++ +++ +++AUTOFS_DEV_IOCTL_SETPIPEFD_CMD +++------------------------------ +++ +++Set the pipe file descriptor used for kernel communication to the daemon. +++Normally this is set at mount time using an option but when reconnecting +++to a existing mount we need to use this to tell the autofs mount about +++the new kernel pipe descriptor. In order to protect mounts against +++incorrectly setting the pipe descriptor we also require that the autofs +++mount be catatonic (see next call). +++ +++The call requires an initialized struct autofs_dev_ioctl with the +++ioctlfd field set to the descriptor obtained from the open call and +++the setpipefd.pipefd field set to descriptor of the pipe. On success +++the call also sets the process group id used to identify the controlling +++process (eg. the owning automount(8) daemon) to the process group of +++the caller. +++ +++ +++AUTOFS_DEV_IOCTL_CATATONIC_CMD +++------------------------------ +++ +++Make the autofs mount point catatonic. The autofs mount will no longer +++issue mount requests, the kernel communication pipe descriptor is released +++and any remaining waits in the queue released. +++ +++The call requires an initialized struct autofs_dev_ioctl with the +++ioctlfd field set to the descriptor obtained from the open call. +++ +++ +++AUTOFS_DEV_IOCTL_TIMEOUT_CMD +++---------------------------- +++ +++Set the expire timeout for mounts withing an autofs mount point. +++ +++The call requires an initialized struct autofs_dev_ioctl with the +++ioctlfd field set to the descriptor obtained from the open call. +++The timeout.timeout field is set to the desired timeout and this +++field is set to the value of the value of the current timeout of +++the mount upon successful completion. +++ +++ +++AUTOFS_DEV_IOCTL_REQUESTER_CMD +++------------------------------ +++ +++Return the uid and gid of the last process to successfully trigger a the +++mount on the given path dentry. +++ +++The call requires an initialized struct autofs_dev_ioctl with the path +++field set to the mount point in question and the size field adjusted +++appropriately as well as the ioctlfd field set to the descriptor obtained +++from the open call. Upon return the struct fields requester.uid and +++requester.gid contain the uid and gid respectively. +++ +++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. +++This call provides the ability to obtain this uid and gid so they may be +++used by user space for the mount map lookups. +++ +++ +++AUTOFS_DEV_IOCTL_EXPIRE_CMD +++--------------------------- +++ +++Issue an expire request to the kernel for an autofs mount. Typically +++this ioctl is called until no further expire candidates are found. +++ +++The call requires an initialized struct autofs_dev_ioctl with the +++ioctlfd field set to the descriptor obtained from the open call. In +++addition an immediate expire, independent of the mount timeout, can be +++requested by setting the expire.how field to 1. If no expire candidates +++can be found the ioctl returns -1 with errno set to EAGAIN. +++ +++This call causes the kernel module to check the mount corresponding +++to the given ioctlfd for mounts that can be expired, issues an expire +++request back to the daemon and waits for completion. +++ +++AUTOFS_DEV_IOCTL_ASKUMOUNT_CMD +++------------------------------ +++ +++Checks if an autofs mount point is in use. +++ +++The call requires an initialized struct autofs_dev_ioctl with the +++ioctlfd field set to the descriptor obtained from the open call and +++it returns the result in the askumount.may_umount field, 1 for busy +++and 0 otherwise. +++ +++ +++AUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD +++--------------------------------- +++ +++Check if the given path is a mountpoint. +++ +++The call requires an initialized struct autofs_dev_ioctl. There are two +++possible variations. Both use the path field set to the path of the mount +++point to check and the size field must be adjusted appropriately. One uses +++the ioctlfd field to identify a specific mount point to check while the +++other variation uses the path and optionaly the ismountpoint.in.type +++field set to an autofs mount type. The call returns 1 if this is a mount +++point and sets the ismountpoint.out.devid field to the device number of +++the mount and the ismountpoint.out.magic field to the relevant super +++block magic number (described below) or 0 if it isn't a mountpoint. In +++both cases the the device number (as returned by new_encode_dev()) is +++returned in the ismountpoint.out.devid field. +++ +++If supplied with a file descriptor we're looking for a specific mount, +++not necessarily at the top of the mounted stack. In this case the path +++the descriptor corresponds to is considered a mountpoint if it is itself +++a mountpoint or contains a mount, such as a multi-mount without a root +++mount. In this case we return 1 if the descriptor corresponds to a mount +++point and and also returns the super magic of the covering mount if there +++is one or 0 if it isn't a mountpoint. +++ +++If a path is supplied (and the ioctlfd field is set to -1) then the path +++is looked up and is checked to see if it is the root of a mount. If a +++type is also given we are looking for a particular autofs mount and if +++a match isn't found a fail is returned. If the the located path is the +++root of a mount 1 is returned along with the super magic of the mount +++or 0 otherwise. +++ ++--- linux-2.6.19.orig/fs/autofs4/Makefile +++++ linux-2.6.19/fs/autofs4/Makefile ++@@ -4,4 +4,4 @@ ++ ++ obj-$(CONFIG_AUTOFS4_FS) += autofs4.o ++ ++-autofs4-objs := init.o inode.o root.o symlink.o waitq.o expire.o +++autofs4-objs := init.o inode.o root.o symlink.o waitq.o expire.o dev-ioctl.o ++--- /dev/null +++++ linux-2.6.19/fs/autofs4/dev-ioctl.c ++@@ -0,0 +1,867 @@ +++/* +++ * Copyright 2008 Red Hat, Inc. All rights reserved. +++ * Copyright 2008 Ian Kent +++ * +++ * 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. +++ */ +++ +++#include +++#include +++#include +++#include +++#include +++#include +++#include +++#include +++#include +++#include +++#include +++#include +++#include +++#include +++#include +++ +++#include "autofs_i.h" +++ +++/* +++ * This module implements an interface for routing autofs ioctl control +++ * commands via a miscellaneous device file. +++ * +++ * The alternate interface is needed because we need to be able open +++ * an ioctl file descriptor on an autofs mount that may be covered by +++ * another mount. This situation arises when starting automount(8) +++ * or other user space daemon which uses direct mounts or offset +++ * mounts (used for autofs lazy mount/umount of nested mount trees), +++ * which have been left busy at at service shutdown. +++ */ +++ +++#define AUTOFS_DEV_IOCTL_SIZE sizeof(struct autofs_dev_ioctl) +++ +++typedef int (*ioctl_fn)(struct file *, +++struct autofs_sb_info *, struct autofs_dev_ioctl *); +++ +++static int check_name(const char *name) +++{ +++ if (!strchr(name, '/')) +++ return -EINVAL; +++ return 0; +++} +++ +++/* +++ * Check a string doesn't overrun the chunk of +++ * memory we copied from user land. +++ */ +++static int invalid_str(char *str, void *end) +++{ +++ while ((void *) str <= end) +++ if (!*str++) +++ return 0; +++ return -EINVAL; +++} +++ +++/* +++ * Check that the user compiled against correct version of autofs +++ * misc device code. +++ * +++ * As well as checking the version compatibility this always copies +++ * the kernel interface version out. +++ */ +++static int check_dev_ioctl_version(int cmd, struct autofs_dev_ioctl *param) +++{ +++ int err = 0; +++ +++ if ((AUTOFS_DEV_IOCTL_VERSION_MAJOR != param->ver_major) || +++ (AUTOFS_DEV_IOCTL_VERSION_MINOR < param->ver_minor)) { +++ AUTOFS_WARN("ioctl control interface version mismatch: " +++ "kernel(%u.%u), user(%u.%u), cmd(%d)", +++ AUTOFS_DEV_IOCTL_VERSION_MAJOR, +++ AUTOFS_DEV_IOCTL_VERSION_MINOR, +++ param->ver_major, param->ver_minor, cmd); +++ err = -EINVAL; +++ } +++ +++ /* Fill in the kernel version. */ +++ param->ver_major = AUTOFS_DEV_IOCTL_VERSION_MAJOR; +++ param->ver_minor = AUTOFS_DEV_IOCTL_VERSION_MINOR; +++ +++ return err; +++} +++ +++/* +++ * Copy parameter control struct, including a possible path allocated +++ * at the end of the struct. +++ */ +++static struct autofs_dev_ioctl *copy_dev_ioctl(struct autofs_dev_ioctl __user *in) +++{ +++ struct autofs_dev_ioctl tmp, *ads; +++ +++ if (copy_from_user(&tmp, in, sizeof(tmp))) +++ return ERR_PTR(-EFAULT); +++ +++ if (tmp.size < sizeof(tmp)) +++ return ERR_PTR(-EINVAL); +++ +++ ads = kmalloc(tmp.size, GFP_KERNEL); +++ if (!ads) +++ return ERR_PTR(-ENOMEM); +++ +++ if (copy_from_user(ads, in, tmp.size)) { +++ kfree(ads); +++ return ERR_PTR(-EFAULT); +++ } +++ +++ return ads; +++} +++ +++static inline void free_dev_ioctl(struct autofs_dev_ioctl *param) +++{ +++ kfree(param); +++ return; +++} +++ +++/* +++ * Check sanity of parameter control fields and if a path is present +++ * check that it is terminated and contains at least one "/". +++ */ +++static int validate_dev_ioctl(int cmd, struct autofs_dev_ioctl *param) +++{ +++ int err; +++ +++ if ((err = check_dev_ioctl_version(cmd, param))) { +++ AUTOFS_WARN("invalid device control module version " +++ "supplied for cmd(0x%08x)", cmd); +++ goto out; +++ } +++ +++ if (param->size > sizeof(*param)) { +++ err = invalid_str(param->path, +++ (void *) ((size_t) param + param->size)); +++ if (err) { +++ AUTOFS_WARN( +++ "path string terminator missing for cmd(0x%08x)", +++ cmd); +++ goto out; +++ } +++ +++ err = check_name(param->path); +++ if (err) { +++ AUTOFS_WARN("invalid path supplied for cmd(0x%08x)", +++ cmd); +++ goto out; +++ } +++ } +++ +++ err = 0; +++out: +++ return err; +++} +++ +++/* +++ * Get the autofs super block info struct from the file opened on +++ * the autofs mount point. +++ */ +++static struct autofs_sb_info *autofs_dev_ioctl_sbi(struct file *f) +++{ +++ struct autofs_sb_info *sbi = NULL; +++ struct inode *inode; +++ +++ if (f) { +++ inode = f->f_dentry->d_inode; +++ sbi = autofs4_sbi(inode->i_sb); +++ } +++ return sbi; +++} +++ +++/* Return autofs module protocol version */ +++static int autofs_dev_ioctl_protover(struct file *fp, +++ struct autofs_sb_info *sbi, +++ struct autofs_dev_ioctl *param) +++{ +++ param->protover.version = sbi->version; +++ return 0; +++} +++ +++/* Return autofs module protocol sub version */ +++static int autofs_dev_ioctl_protosubver(struct file *fp, +++ struct autofs_sb_info *sbi, +++ struct autofs_dev_ioctl *param) +++{ +++ param->protosubver.sub_version = sbi->sub_version; +++ return 0; +++} +++ +++/* +++ * Walk down the mount stack looking for an autofs mount that +++ * has the requested device number (aka. new_encode_dev(sb->s_dev). +++ */ +++static int autofs_dev_ioctl_find_super(struct nameidata *nd, dev_t devno) +++{ +++ struct dentry *dentry; +++ struct inode *inode; +++ struct super_block *sb; +++ dev_t s_dev; +++ unsigned int err; +++ +++ err = -ENOENT; +++ +++ /* Lookup the dentry name at the base of our mount point */ +++ dentry = d_lookup(nd->dentry, &nd->last); +++ if (!dentry) +++ goto out; +++ +++ dput(nd->dentry); +++ nd->dentry = dentry; +++ +++ /* And follow the mount stack looking for our autofs mount */ +++ while (follow_down(&nd->mnt, &nd->dentry)) { +++ inode = nd->dentry->d_inode; +++ if (!inode) +++ break; +++ +++ sb = inode->i_sb; +++ s_dev = new_encode_dev(sb->s_dev); +++ if (devno == s_dev) { +++ if (sb->s_magic == AUTOFS_SUPER_MAGIC) { +++ err = 0; +++ break; +++ } +++ } +++ } +++out: +++ return err; +++} +++ +++/* +++ * Walk down the mount stack looking for an autofs mount that +++ * has the requested mount type (ie. indirect, direct or offset). +++ */ +++static int autofs_dev_ioctl_find_sbi_type(struct nameidata *nd, unsigned int type) +++{ +++ struct dentry *dentry; +++ struct autofs_info *ino; +++ unsigned int err; +++ +++ err = -ENOENT; +++ +++ /* Lookup the dentry name at the base of our mount point */ +++ dentry = d_lookup(nd->dentry, &nd->last); +++ if (!dentry) +++ goto out; +++ +++ dput(nd->dentry); +++ nd->dentry = dentry; +++ +++ /* And follow the mount stack looking for our autofs mount */ +++ while (follow_down(&nd->mnt, &nd->dentry)) { +++ ino = autofs4_dentry_ino(nd->dentry); +++ if (ino && ino->sbi->type & type) { +++ err = 0; +++ break; +++ } +++ } +++out: +++ return err; +++} +++ +++static void autofs_dev_ioctl_fd_install(unsigned int fd, struct file *file) +++{ +++ struct files_struct *files = current->files; +++ struct fdtable *fdt; +++ +++ spin_lock(&files->file_lock); +++ fdt = files_fdtable(files); +++ BUG_ON(fdt->fd[fd] != NULL); +++ rcu_assign_pointer(fdt->fd[fd], file); +++ FD_SET(fd, fdt->close_on_exec); +++ spin_unlock(&files->file_lock); +++} +++ +++ +++/* +++ * Open a file descriptor on the autofs mount point corresponding +++ * to the given path and device number (aka. new_encode_dev(sb->s_dev)). +++ */ +++static int autofs_dev_ioctl_open_mountpoint(const char *path, dev_t devid) +++{ +++ struct file *filp; +++ struct nameidata nd; +++ int err, fd; +++ +++ fd = get_unused_fd(); +++ if (likely(fd >= 0)) { +++ /* Get nameidata of the parent directory */ +++ err = path_lookup(path, LOOKUP_PARENT, &nd); +++ if (err) +++ goto out; +++ +++ /* +++ * Search down, within the parent, looking for an +++ * autofs super block that has the device number +++ * corresponding to the autofs fs we want to open. +++ */ +++ err = autofs_dev_ioctl_find_super(&nd, devid); +++ if (err) { +++ path_release(&nd); +++ goto out; +++ } +++ +++ filp = dentry_open(nd.dentry, nd.mnt, O_RDONLY); +++ if (IS_ERR(filp)) { +++ err = PTR_ERR(filp); +++ goto out; +++ } +++ +++ autofs_dev_ioctl_fd_install(fd, filp); +++ } +++ +++ return fd; +++ +++out: +++ put_unused_fd(fd); +++ return err; +++} +++ +++/* Open a file descriptor on an autofs mount point */ +++static int autofs_dev_ioctl_openmount(struct file *fp, +++ struct autofs_sb_info *sbi, +++ struct autofs_dev_ioctl *param) +++{ +++ const char *path; +++ dev_t devid; +++ int err, fd; +++ +++ /* param->path has already been checked */ +++ if (!param->openmount.devid) +++ return -EINVAL; +++ +++ param->ioctlfd = -1; +++ +++ path = param->path; +++ devid = param->openmount.devid; +++ +++ err = 0; +++ fd = autofs_dev_ioctl_open_mountpoint(path, devid); +++ if (unlikely(fd < 0)) { +++ err = fd; +++ goto out; +++ } +++ +++ param->ioctlfd = fd; +++out: +++ return err; +++} +++ +++/* Close file descriptor allocated above (user can also use close(2)). */ +++static int autofs_dev_ioctl_closemount(struct file *fp, +++ struct autofs_sb_info *sbi, +++ struct autofs_dev_ioctl *param) +++{ +++ return sys_close(param->ioctlfd); +++} +++ +++/* +++ * Send "ready" status for an existing wait (either a mount or an expire +++ * request). +++ */ +++static int autofs_dev_ioctl_ready(struct file *fp, +++ struct autofs_sb_info *sbi, +++ struct autofs_dev_ioctl *param) +++{ +++ autofs_wqt_t token; +++ +++ token = (autofs_wqt_t) param->ready.token; +++ return autofs4_wait_release(sbi, token, 0); +++} +++ +++/* +++ * Send "fail" status for an existing wait (either a mount or an expire +++ * request). +++ */ +++static int autofs_dev_ioctl_fail(struct file *fp, +++ struct autofs_sb_info *sbi, +++ struct autofs_dev_ioctl *param) +++{ +++ autofs_wqt_t token; +++ int status; +++ +++ token = (autofs_wqt_t) param->fail.token; +++ status = param->fail.status ? param->fail.status : -ENOENT; +++ return autofs4_wait_release(sbi, token, status); +++} +++ +++/* +++ * Set the pipe fd for kernel communication to the daemon. +++ * +++ * 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 mount about the new kernel pipe fd. In +++ * order to protect mounts against incorrectly setting the +++ * pipefd we also require that the autofs mount be catatonic. +++ * +++ * This also sets the process group id used to identify the +++ * controlling process (eg. the owning automount(8) daemon). +++ */ +++static int autofs_dev_ioctl_setpipefd(struct file *fp, +++ struct autofs_sb_info *sbi, +++ struct autofs_dev_ioctl *param) +++{ +++ int pipefd; +++ int err = 0; +++ +++ if (param->setpipefd.pipefd == -1) +++ return -EINVAL; +++ +++ pipefd = param->setpipefd.pipefd; +++ +++ mutex_lock(&sbi->wq_mutex); +++ if (!sbi->catatonic) { +++ mutex_unlock(&sbi->wq_mutex); +++ return -EBUSY; +++ } else { +++ struct file *pipe = fget(pipefd); +++ if (!pipe->f_op || !pipe->f_op->write) { +++ err = -EPIPE; +++ fput(pipe); +++ goto out; +++ } +++ sbi->oz_pgrp = process_group(current); +++ sbi->pipefd = pipefd; +++ sbi->pipe = pipe; +++ sbi->catatonic = 0; +++ } +++out: +++ mutex_unlock(&sbi->wq_mutex); +++ return err; +++} +++ +++/* +++ * Make the autofs mount point catatonic, no longer responsive to +++ * mount requests. Also closes the kernel pipe file descriptor. +++ */ +++static int autofs_dev_ioctl_catatonic(struct file *fp, +++ struct autofs_sb_info *sbi, +++ struct autofs_dev_ioctl *param) +++{ +++ autofs4_catatonic_mode(sbi); +++ return 0; +++} +++ +++/* Set the autofs mount timeout */ +++static int autofs_dev_ioctl_timeout(struct file *fp, +++ struct autofs_sb_info *sbi, +++ struct autofs_dev_ioctl *param) +++{ +++ unsigned long timeout; +++ +++ timeout = param->timeout.timeout; +++ param->timeout.timeout = sbi->exp_timeout / HZ; +++ sbi->exp_timeout = timeout * HZ; +++ return 0; +++} +++ +++/* +++ * Return the uid and gid of the last request for the mount +++ * +++ * 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 autofs_dev_ioctl_requester(struct file *fp, +++ struct autofs_sb_info *sbi, +++ struct autofs_dev_ioctl *param) +++{ +++ struct autofs_info *ino; +++ struct nameidata nd; +++ const char *path; +++ dev_t devid; +++ int err = -ENOENT; +++ +++ if (param->size <= sizeof(*param)) { +++ err = -EINVAL; +++ goto out; +++ } +++ +++ path = param->path; +++ devid = sbi->sb->s_dev; +++ +++ param->requester.uid = param->requester.gid = -1; +++ +++ /* Get nameidata of the parent directory */ +++ err = path_lookup(path, LOOKUP_PARENT, &nd); +++ if (err) +++ goto out; +++ +++ err = autofs_dev_ioctl_find_super(&nd, devid); +++ if (err) +++ goto out_release; +++ +++ ino = autofs4_dentry_ino(nd.dentry); +++ if (ino) { +++ err = 0; +++ autofs4_expire_wait(nd.dentry); +++ spin_lock(&sbi->fs_lock); +++ param->requester.uid = ino->uid; +++ param->requester.gid = ino->gid; +++ spin_unlock(&sbi->fs_lock); +++ } +++ +++out_release: +++ path_release(&nd); +++out: +++ return err; +++} +++ +++/* +++ * Call repeatedly until it returns -EAGAIN, meaning there's nothing +++ * more that can be done. +++ */ +++static int autofs_dev_ioctl_expire(struct file *fp, +++ struct autofs_sb_info *sbi, +++ struct autofs_dev_ioctl *param) +++{ +++ struct dentry *dentry; +++ struct vfsmount *mnt; +++ int err = -EAGAIN; +++ int how; +++ +++ how = param->expire.how; +++ mnt = fp->f_vfsmnt; +++ +++ if (autofs_type_trigger(sbi->type)) +++ dentry = autofs4_expire_direct(sbi->sb, mnt, sbi, how); +++ else +++ dentry = autofs4_expire_indirect(sbi->sb, mnt, sbi, how); +++ +++ if (dentry) { +++ struct autofs_info *ino = autofs4_dentry_ino(dentry); +++ +++ /* +++ * This is synchronous because it makes the daemon a +++ * little easier +++ */ +++ err = autofs4_wait(sbi, dentry, NFY_EXPIRE); +++ +++ spin_lock(&sbi->fs_lock); +++ if (ino->flags & AUTOFS_INF_MOUNTPOINT) { +++ ino->flags &= ~AUTOFS_INF_MOUNTPOINT; +++ sbi->sb->s_root->d_mounted++; +++ } +++ ino->flags &= ~AUTOFS_INF_EXPIRING; +++ complete_all(&ino->expire_complete); +++ spin_unlock(&sbi->fs_lock); +++ dput(dentry); +++ } +++ +++ return err; +++} +++ +++/* Check if autofs mount point is in use */ +++static int autofs_dev_ioctl_askumount(struct file *fp, +++ struct autofs_sb_info *sbi, +++ struct autofs_dev_ioctl *param) +++{ +++ param->askumount.may_umount = 0; +++ if (may_umount(fp->f_vfsmnt)) +++ param->askumount.may_umount = 1; +++ return 0; +++} +++ +++/* +++ * Check if the given path is a mountpoint. +++ * +++ * If we are supplied with the file descriptor of an autofs +++ * mount we're looking for a specific mount. In this case +++ * 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 this case we return 1 if the +++ * path is a mount point and the super magic of the covering +++ * mount if there is one or 0 if it isn't a mountpoint. +++ * +++ * If we aren't supplied with a file descriptor then we +++ * lookup the nameidata of the path and check if it is the +++ * root of a mount. If a type is given we are looking for +++ * a particular autofs mount and if we don't find a match +++ * we return fail. If the located nameidata path is the +++ * root of a mount we return 1 along with the super magic +++ * of the mount or 0 otherwise. +++ * +++ * In both cases the the device number (as returned by +++ * new_encode_dev()) is also returned. +++ */ +++static int autofs_dev_ioctl_ismountpoint(struct file *fp, +++ struct autofs_sb_info *sbi, +++ struct autofs_dev_ioctl *param) +++{ +++ struct nameidata nd; +++ const char *path; +++ unsigned int type; +++ unsigned int devid, magic; +++ int err = -ENOENT; +++ +++ if (param->size <= sizeof(*param)) { +++ err = -EINVAL; +++ goto out; +++ } +++ +++ path = param->path; +++ type = param->ismountpoint.in.type; +++ +++ param->ismountpoint.out.devid = devid = 0; +++ param->ismountpoint.out.magic = magic = 0; +++ +++ if (!fp || param->ioctlfd == -1) { +++ if (autofs_type_any(type)) { +++ struct super_block *sb; +++ +++ err = path_lookup(path, LOOKUP_FOLLOW, &nd); +++ if (err) +++ goto out; +++ +++ sb = nd.dentry->d_sb; +++ devid = new_encode_dev(sb->s_dev); +++ } else { +++ struct autofs_info *ino; +++ +++ err = path_lookup(path, LOOKUP_PARENT, &nd); +++ if (err) +++ goto out; +++ +++ err = autofs_dev_ioctl_find_sbi_type(&nd, type); +++ if (err) +++ goto out_release; +++ +++ ino = autofs4_dentry_ino(nd.dentry); +++ devid = autofs4_get_dev(ino->sbi); +++ } +++ +++ err = 0; +++ if (nd.dentry->d_inode && +++ nd.mnt->mnt_root == nd.dentry) { +++ err = 1; +++ magic = nd.dentry->d_inode->i_sb->s_magic; +++ } +++ } else { +++ dev_t devid = new_encode_dev(sbi->sb->s_dev); +++ +++ err = path_lookup(path, LOOKUP_PARENT, &nd); +++ if (err) +++ goto out; +++ +++ err = autofs_dev_ioctl_find_super(&nd, devid); +++ if (err) +++ goto out_release; +++ +++ devid = autofs4_get_dev(sbi); +++ +++ err = have_submounts(nd.dentry); +++ +++ if (nd.mnt->mnt_mountpoint != nd.mnt->mnt_root) { +++ if (follow_down(&nd.mnt, &nd.dentry)) { +++ struct inode *inode = nd.dentry->d_inode; +++ magic = inode->i_sb->s_magic; +++ } +++ } +++ } +++ +++ param->ismountpoint.out.devid = devid; +++ param->ismountpoint.out.magic = magic; +++ +++out_release: +++ path_release(&nd); +++out: +++ return err; +++} +++ +++/* +++ * Our range of ioctl numbers isn't 0 based so we need to shift +++ * the array index by _IOC_NR(AUTOFS_CTL_IOC_FIRST) for the table +++ * lookup. +++ */ +++#define cmd_idx(cmd) (cmd - _IOC_NR(AUTOFS_DEV_IOCTL_IOC_FIRST)) +++ +++static ioctl_fn lookup_dev_ioctl(unsigned int cmd) +++{ +++ static struct { +++ int cmd; +++ ioctl_fn fn; +++ } _ioctls[] = { +++ {cmd_idx(AUTOFS_DEV_IOCTL_VERSION_CMD), NULL}, +++ {cmd_idx(AUTOFS_DEV_IOCTL_PROTOVER_CMD), +++ autofs_dev_ioctl_protover}, +++ {cmd_idx(AUTOFS_DEV_IOCTL_PROTOSUBVER_CMD), +++ autofs_dev_ioctl_protosubver}, +++ {cmd_idx(AUTOFS_DEV_IOCTL_OPENMOUNT_CMD), +++ autofs_dev_ioctl_openmount}, +++ {cmd_idx(AUTOFS_DEV_IOCTL_CLOSEMOUNT_CMD), +++ autofs_dev_ioctl_closemount}, +++ {cmd_idx(AUTOFS_DEV_IOCTL_READY_CMD), +++ autofs_dev_ioctl_ready}, +++ {cmd_idx(AUTOFS_DEV_IOCTL_FAIL_CMD), +++ autofs_dev_ioctl_fail}, +++ {cmd_idx(AUTOFS_DEV_IOCTL_SETPIPEFD_CMD), +++ autofs_dev_ioctl_setpipefd}, +++ {cmd_idx(AUTOFS_DEV_IOCTL_CATATONIC_CMD), +++ autofs_dev_ioctl_catatonic}, +++ {cmd_idx(AUTOFS_DEV_IOCTL_TIMEOUT_CMD), +++ autofs_dev_ioctl_timeout}, +++ {cmd_idx(AUTOFS_DEV_IOCTL_REQUESTER_CMD), +++ autofs_dev_ioctl_requester}, +++ {cmd_idx(AUTOFS_DEV_IOCTL_EXPIRE_CMD), +++ autofs_dev_ioctl_expire}, +++ {cmd_idx(AUTOFS_DEV_IOCTL_ASKUMOUNT_CMD), +++ autofs_dev_ioctl_askumount}, +++ {cmd_idx(AUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD), +++ autofs_dev_ioctl_ismountpoint} +++ }; +++ unsigned int idx = cmd_idx(cmd); +++ +++ return (idx >= ARRAY_SIZE(_ioctls)) ? NULL : _ioctls[idx].fn; +++} +++ +++/* ioctl dispatcher */ +++static int _autofs_dev_ioctl(unsigned int command, struct autofs_dev_ioctl __user *user) +++{ +++ struct autofs_dev_ioctl *param; +++ struct file *fp; +++ struct autofs_sb_info *sbi; +++ unsigned int cmd_first, cmd; +++ ioctl_fn fn = NULL; +++ int err = 0; +++ +++ /* only root can play with this */ +++ if (!capable(CAP_SYS_ADMIN)) +++ return -EPERM; +++ +++ cmd_first = _IOC_NR(AUTOFS_DEV_IOCTL_IOC_FIRST); +++ cmd = _IOC_NR(command); +++ +++ if (_IOC_TYPE(command) != _IOC_TYPE(AUTOFS_DEV_IOCTL_IOC_FIRST) || +++ cmd - cmd_first >= AUTOFS_DEV_IOCTL_IOC_COUNT) { +++ return -ENOTTY; +++ } +++ +++ /* Copy the parameters into kernel space. */ +++ param = copy_dev_ioctl(user); +++ if (IS_ERR(param)) +++ return PTR_ERR(param); +++ +++ err = validate_dev_ioctl(command, param); +++ if (err) +++ goto out; +++ +++ /* The validate routine above always sets the version */ +++ if (cmd == AUTOFS_DEV_IOCTL_VERSION_CMD) +++ goto done; +++ +++ fn = lookup_dev_ioctl(cmd); +++ if (!fn) { +++ AUTOFS_WARN("unknown command 0x%08x", command); +++ return -ENOTTY; +++ } +++ +++ fp = NULL; +++ sbi = NULL; +++ +++ /* +++ * For obvious reasons the openmount can't have a file +++ * descriptor yet. We don't take a reference to the +++ * file during close to allow for immediate release. +++ */ +++ if (cmd != AUTOFS_DEV_IOCTL_OPENMOUNT_CMD && +++ cmd != AUTOFS_DEV_IOCTL_CLOSEMOUNT_CMD) { +++ fp = fget(param->ioctlfd); +++ if (!fp) { +++ if (cmd == AUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD) +++ goto cont; +++ err = -EBADF; +++ goto out; +++ } +++ +++ if (!fp->f_op) { +++ err = -ENOTTY; +++ fput(fp); +++ goto out; +++ } +++ +++ sbi = autofs_dev_ioctl_sbi(fp); +++ if (!sbi || sbi->magic != AUTOFS_SBI_MAGIC) { +++ err = -EINVAL; +++ fput(fp); +++ goto out; +++ } +++ +++ /* +++ * Admin needs to be able to set the mount catatonic in +++ * order to be able to perform the re-open. +++ */ +++ if (!autofs4_oz_mode(sbi) && +++ cmd != AUTOFS_DEV_IOCTL_CATATONIC_CMD) { +++ err = -EACCES; +++ fput(fp); +++ goto out; +++ } +++ } +++cont: +++ err = fn(fp, sbi, param); +++ +++ if (fp) +++ fput(fp); +++done: +++ if (err >= 0 && copy_to_user(user, param, AUTOFS_DEV_IOCTL_SIZE)) +++ err = -EFAULT; +++out: +++ free_dev_ioctl(param); +++ return err; +++} +++ +++static long autofs_dev_ioctl(struct file *file, uint command, ulong u) +++{ +++ int err; +++ err = _autofs_dev_ioctl(command, (struct autofs_dev_ioctl __user *) u); +++ return (long) err; +++} +++ +++#ifdef CONFIG_COMPAT +++static long autofs_dev_ioctl_compat(struct file *file, uint command, ulong u) +++{ +++ return (long) autofs_dev_ioctl(file, command, (ulong) compat_ptr(u)); +++} +++#else +++#define autofs_dev_ioctl_compat NULL +++#endif +++ +++static const struct file_operations _dev_ioctl_fops = { +++ .unlocked_ioctl = autofs_dev_ioctl, +++ .compat_ioctl = autofs_dev_ioctl_compat, +++ .owner = THIS_MODULE, +++}; +++ +++static struct miscdevice _autofs_dev_ioctl_misc = { +++ .minor = MISC_DYNAMIC_MINOR, +++ .name = AUTOFS_DEVICE_NAME, +++ .fops = &_dev_ioctl_fops +++}; +++ +++/* Register/deregister misc character device */ +++int autofs_dev_ioctl_init(void) +++{ +++ int r; +++ +++ r = misc_register(&_autofs_dev_ioctl_misc); +++ if (r) { +++ AUTOFS_ERROR("misc_register failed for control device"); +++ return r; +++ } +++ +++ return 0; +++} +++ +++void autofs_dev_ioctl_exit(void) +++{ +++ misc_deregister(&_autofs_dev_ioctl_misc); +++ return; +++} +++ ++--- linux-2.6.19.orig/fs/autofs4/init.c +++++ linux-2.6.19/fs/autofs4/init.c ++@@ -29,11 +29,20 @@ static struct file_system_type autofs_fs ++ ++ static int __init init_autofs4_fs(void) ++ { ++- return register_filesystem(&autofs_fs_type); +++ int err; +++ +++ err = register_filesystem(&autofs_fs_type); +++ if (err) +++ return err; +++ +++ autofs_dev_ioctl_init(); +++ +++ return err; ++ } ++ ++ static void __exit exit_autofs4_fs(void) ++ { +++ autofs_dev_ioctl_exit(); ++ unregister_filesystem(&autofs_fs_type); ++ } ++ ++--- /dev/null +++++ linux-2.6.19/include/linux/auto_dev-ioctl.h ++@@ -0,0 +1,229 @@ +++/* +++ * Copyright 2008 Red Hat, Inc. All rights reserved. +++ * Copyright 2008 Ian Kent +++ * +++ * 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 +++ +++#ifdef __KERNEL__ +++#include +++#else +++#include +++#endif /* __KERNEL__ */ +++ +++#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_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) +++{ +++ memset(in, 0, sizeof(struct autofs_dev_ioctl)); +++ 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 */ ++--- linux-2.6.19.orig/include/linux/auto_fs.h +++++ linux-2.6.19/include/linux/auto_fs.h ++@@ -17,11 +17,13 @@ ++ #ifdef __KERNEL__ ++ #include ++ #include +++#include +++#include +++#else ++ #include +++#include ++ #endif /* __KERNEL__ */ ++ ++-#include ++- ++ /* This file describes autofs v3 */ ++ #define AUTOFS_PROTO_VERSION 3 ++ --- autofs5-5.0.5.orig/debian/patches/00list +++ autofs5-5.0.5/debian/patches/00list @@ -0,0 +1,76 @@ +01UPSTREAM_autofs-5.0.5-fix-included-map-read-fail-handling +01UPSTREAM_autofs-5.0.5-refactor-ldap-sasl-bind +01UPSTREAM_autofs-5.0.4-add-mount-wait-parameter +01UPSTREAM_autofs-5.0.5-special-case-cifs-escapes +01UPSTREAM_autofs-5.0.5-fix-libxml2-workaround-configure +01UPSTREAM_autofs-5.0.5-more-code-analysis-corrections +01UPSTREAM_autofs-5.0.5-fix-backwards-ifndef-INET6 +01UPSTREAM_autofs-5.0.5-fix-stale-init-for-file-map-instance +01UPSTREAM_autofs-5.0.5-fix-ext4-fsck-at-mount +01UPSTREAM_autofs-5.0.5-dont-use-master_lex_destroy-to-clear-parse-buffer +01UPSTREAM_autofs-5.0.5-make-documentation-for-set-log-priority-clearer +01UPSTREAM_autofs-5.0.5-fix-timeout-in-connect_nb +01UPSTREAM_autofs-5.0.5-fix-pidof-init-script-usage +01UPSTREAM_autofs-5.0.5-check-for-path-mount-location-in-generic-module +01UPSTREAM_autofs-5.0.5-dont-fail-mount-on-access-fail +01UPSTREAM_autofs-5.0.5-fix-rpc-large-export-list +01UPSTREAM_autofs-5.0.5-fix-memory-leak-on-reload +01UPSTREAM_autofs-5.0.5-update-kernel-patches-2.6.18-and-2.6.19 +01UPSTREAM_autofs-5.0.5-dont-connect-at-ldap-lookup-module-init +01UPSTREAM_autofs-5.0.5-fix-random-selection-option +01UPSTREAM_autofs-5.0.5-fix-disable-timeout +01UPSTREAM_autofs-5.0.5-fix-strdup-return-value-check +01UPSTREAM_autofs-5.0.5-fix-reconnect-get-base-dn +01UPSTREAM_autofs-5.0.5-add-sasl-mutex-callbacks +01UPSTREAM_autofs-5.0.5-fix-get-qdn-fail +01UPSTREAM_autofs-5.0.5-fix-ampersand-escape-in-auto-smb +01UPSTREAM_autofs-5.0.5-add-locality-as-valid-ldap-master-map-attribute +01UPSTREAM_autofs-5.0.5-add-locality-as-valid-ldap-master-map-attribute-fix +01UPSTREAM_autofs-5.0.5-make-nfs4-default-for-redhat-replicated-selection +01UPSTREAM_autofs-5.0.5-add-simple-bind-auth +01UPSTREAM_autofs-5.0.5-fix-master-map-source-server-unavialable-handling +01UPSTREAM_autofs-5.0.5-add-autofs_ldap_auth_conf-man-page +01UPSTREAM_autofs-5.0.5-fix-random-selection-for-host-on-different-network +01UPSTREAM_autofs-5.0.5-make-redhat-init-script-more-lsb-compliant +01UPSTREAM_autofs-5.0.5-dont-hold-lock-for-simple-mounts +01UPSTREAM_autofs-5.0.5-fix-remount-locking +01UPSTREAM_autofs-5.0.5-fix-wildcard-map-entry-match +01UPSTREAM_autofs-5.0.5-fix-parse_sun-module-init +01UPSTREAM_autofs-5.0.5-dont-check-null-cache-on-expire +01UPSTREAM_autofs-5.0.5-fix-null-cache-race +01UPSTREAM_autofs-5.0.5-fix-cache_init-on-source-re-read +01UPSTREAM_autofs-5.0.5-mapent-becomes-negative-during-lookup +01UPSTREAM_autofs-5.0.5-check-each-dc-server +01UPSTREAM_autofs-5.0.5-fix-negative-cache-included-map-lookup +01UPSTREAM_autofs-5.0.5-remove-state-machine-timed-wait +01UPSTREAM_autofs-5.0.5-remove-extra-read-master-map-call +01UPSTREAM_autofs-5.0.5-fix-fix-cache_init-on-source-re-read +01UPSTREAM_autofs-5.0.5-fix-error-handing-in-do_mount_indirect +01UPSTREAM_autofs-5.0.5-expire-thread-use-pending-mutex +01UPSTREAM_autofs-5.0.5-include-krb5-library +01UPSTREAM_autofs-5.0.5-make-verbose-mode-a-little-less-verbose +01UPSTREAM_autofs-5.0.5-remove-ERR_remove_state-openssl-call +01UPSTREAM_autofs-5.0.5-fix-restart +01UPSTREAM_autofs-5.0.5-fix-status-privilege-error +01UPSTREAM_autofs-5.0.4-always-read-file-maps-mount-lookup-map-read-fix +01UPSTREAM_autofs-5.0.5-fix-direct-map-not-updating-on-reread +01UPSTREAM_autofs-5.0.5-add-external-bind-method +01UPSTREAM_autofs-5.0.5-fix-add-simple-bind-auth +01UPSTREAM_autofs-5.0.5-add-dump-maps-option +01UPSTREAM_autofs-5.0.5-fix-submount-shutdown-wait +01UPSTREAM_autofs-5.0.5-use-weight-only-for-server-selection +01UPSTREAM_autofs-5.0.5-fix-isspace-wild-card-substition +01UPSTREAM_autofs-5.0.5-auto-adjust-ldap-page-size +01UPSTREAM_autofs-5.0.5-fix-prune-cache-valid-check +01UPSTREAM_autofs-5.0.5-fix-mountd-vers-retry +01UPSTREAM_autofs-5.0.5-fix-expire-race +01UPSTREAM_autofs-5.0.5-add-lsb-force-reload-and-try-restart +01UPSTREAM_autofs-5.0.5-replace-gplv3-code +11default_automaster_location +12disable_default_auto_master +#13ldap_module_linkage +14avoid_sock_cloexec +15auto_net_nfs4 +16group_buffer_size +17ld + --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-fix-expire-race.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-fix-expire-race.dpatch @@ -0,0 +1,50 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-fix-expire-race.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.3 - fix expire race + +From: Ian Kent + +For multi-mounts, if a mount request comes in and does not complete +before a concurrent expire autofs will not recognize that the tree +has become busy which can lead to a partial expire leaving the +multi-mount non-functional. +--- + + CHANGELOG | 1 + + lib/mounts.c | 5 ++++- + 2 files changed, 5 insertions(+), 1 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index e55b873..b9d8299 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -60,6 +60,7 @@ + - auto adjust ldap page size. + - fix prune cache valid check. + - fix mountd vers retry. ++- fix expire race. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/lib/mounts.c b/lib/mounts.c +index 4c44982..f26579e 100644 +--- a/lib/mounts.c ++++ b/lib/mounts.c +@@ -1525,8 +1525,11 @@ int umount_multi_triggers(struct autofs_point *ap, struct mapent *me, char *root + oe_base = oe->key + strlen(root); + left += umount_multi_triggers(ap, oe, root, oe_base); + +- if (oe->ioctlfd != -1) ++ if (oe->ioctlfd != -1 || ++ is_mounted(_PROC_MOUNTS, oe->key, MNTS_REAL)) { + left++; ++ break; ++ } + } + + if (left) --- autofs5-5.0.5.orig/debian/patches/16group_buffer_size.dpatch +++ autofs5-5.0.5/debian/patches/16group_buffer_size.dpatch @@ -0,0 +1,17 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 16group_buffer_size.dpatch by +## +## DP: Increase group buffer geometrically rather than linearly + +@DPATCH@ +--- autofs5-5.0.4.orig/lib/mounts.c 2010-06-09 14:55:15.000000000 -0700 ++++ autofs5-5.0.4/lib/mounts.c 2010-06-09 14:53:11.000000000 -0700 +@@ -1074,7 +1074,7 @@ + status = getgrgid_r(gid, pgr, gr_tmp, tmplen, ppgr); + if (status != ERANGE) + break; +- tmplen += grplen; ++ tmplen *= 2; + } + + if (status || !pgr) { --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-fix-negative-cache-included-map-lookup.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-fix-negative-cache-included-map-lookup.dpatch @@ -0,0 +1,59 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-fix-negative-cache-included-map-lookup.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - fix negative cache included map lookup + +From: Ian Kent + +If we are looking up a mount from multiple included map sources we +can't update the negative cache until we have looked at all sources. +If we don't postpone the negative cache update we will get a false +negative on a subsequent lookups. + +Also clean up "not found" message. +--- + + CHANGELOG | 1 + + daemon/lookup.c | 6 +++++- + 2 files changed, 6 insertions(+), 1 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index 84e3216..f12128c 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -42,6 +42,7 @@ + - fix cache_init() on source re-read. + - fix mapent becomes negative during lookup. + - check each dc server individually. ++- fix negative cache included map lookup. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/daemon/lookup.c b/daemon/lookup.c +index ec979c9..f5d9da8 100644 +--- a/daemon/lookup.c ++++ b/daemon/lookup.c +@@ -813,6 +813,10 @@ static void update_negative_cache(struct autofs_point *ap, struct map_source *so + struct map_source *map; + struct mapent *me; + ++ /* Don't update negative cache for included maps */ ++ if (source && source->depth) ++ return; ++ + /* Have we recorded the lookup fail for negative caching? */ + me = lookup_source_mapent(ap, name, LKP_DISTINCT); + if (me) +@@ -823,7 +827,7 @@ static void update_negative_cache(struct autofs_point *ap, struct map_source *so + cache_unlock(me->mc); + else { + /* Notify only once after fail */ +- error(ap->logopt, "key \"%s\" not found in map.", name); ++ logmsg("key \"%s\" not found in map source(s).", name); + + /* Doesn't exist in any source, just add it somewhere */ + if (source) --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-fix-status-privilege-error.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-fix-status-privilege-error.dpatch @@ -0,0 +1,45 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-fix-status-privilege-error.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - fix status privilege error + +From: Ian Kent + +The recent LSB init init script change prevent normal users from using +the status init script action. Maybe the (very poor) specification is +wrong or I misread it, in either case this behaviour is unacceptable. +--- + + CHANGELOG | 1 + + redhat/autofs.init.in | 2 +- + 2 files changed, 2 insertions(+), 1 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index 02a5e36..577ae41 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -49,6 +49,7 @@ + - expire thread use pending mutex. + - remove ERR_remove_state() openssl call. + - fix init script restart option. ++- fix init script status privilege error. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/redhat/autofs.init.in b/redhat/autofs.init.in +index e2a4b78..05ab145 100644 +--- a/redhat/autofs.init.in ++++ b/redhat/autofs.init.in +@@ -154,7 +154,7 @@ function reload() { + RETVAL=0 + + # Only the root user may change the service status +-if [ `id -u` -ne 0 ]; then ++if [ `id -u` -ne 0 ] && [ "$1" != "status" ]; then + echo "insufficient privilege to change service status" + exit 4 + fi --- autofs5-5.0.5.orig/debian/patches/15auto_net_nfs4.dpatch +++ autofs5-5.0.5/debian/patches/15auto_net_nfs4.dpatch @@ -0,0 +1,19 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 15auto_net_nfs4.dpatch by +## +## DP: Add an example line for nfsv4 environments. + +@DPATCH@ +--- autofs5-5.0.4.orig/samples/auto.net 2008-11-04 02:36:48.000000000 +0100 ++++ autofs5-5.0.4/samples/auto.net 2009-07-25 19:33:33.833528029 +0200 +@@ -9,7 +9,10 @@ + + # add "nosymlink" here if you want to suppress symlinking local filesystems + # add "nonstrict" to make it OK for some filesystems to not mount ++# choose one of the two lines below depending on the NFS version in your ++# environment + opts="-fstype=nfs,hard,intr,nodev,nosuid" ++#opts="-fstype=nfs4,hard,intr,nodev,nosuid,async" + + # Showmount comes in a number of names and varieties. "showmount" is + # typically an older version which accepts the '--no-headers' flag --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-fix-fix-cache_init-on-source-re-read.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-fix-fix-cache_init-on-source-re-read.dpatch @@ -0,0 +1,34 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-fix-fix-cache_init-on-source-re-read.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - fix "fix cache_init() on source re-read" + +From: Ian Kent + +Remove extra cache create call in master_add_map_source(). +--- + + lib/master.c | 6 ------ + 1 files changed, 0 insertions(+), 6 deletions(-) + + +diff --git a/lib/master.c b/lib/master.c +index 03d8f77..12f2d22 100644 +--- a/lib/master.c ++++ b/lib/master.c +@@ -188,12 +188,6 @@ master_add_map_source(struct master_mapent *entry, + source->argc = argc; + source->argv = tmpargv; + +- source->mc = cache_init(entry->ap, source); +- if (!source->mc) { +- master_free_map_source(source, 0); +- return NULL; +- } +- + master_source_writelock(entry); + + if (!entry->maps) { --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-fix-random-selection-for-host-on-different-network.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-fix-random-selection-for-host-on-different-network.dpatch @@ -0,0 +1,151 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-fix-random-selection-for-host-on-different-network.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - fix random selection for host on different network + +From: Ian Kent + +When we select from a list of hosts from which we can mount the list +is ordered by response time within proximity. + +This is intended for normal selection but when using random selection +if any hosts are on another network (and so considered further away) +they will never be at the head of the list and so are unlikely to be +used. This leads to a limited set of hosts being used for mounts which +usually isn't what's required when the random selection option is used. +--- + + CHANGELOG | 1 + + include/replicated.h | 2 +- + modules/mount_nfs.c | 2 +- + modules/replicated.c | 28 ++++++++++++++++++++-------- + 4 files changed, 23 insertions(+), 10 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index e319b4d..470de69 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -31,6 +31,7 @@ + - add simple bind authentication. + - fix master map source server unavailable handling. + - add autofs_ldap_auth.conf man page. ++- fix random selection for host on different network. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/include/replicated.h b/include/replicated.h +index fd87c08..519689d 100644 +--- a/include/replicated.h ++++ b/include/replicated.h +@@ -64,7 +64,7 @@ struct host { + + void seed_random(void); + void free_host_list(struct host **); +-int parse_location(unsigned, struct host **, const char *); ++int parse_location(unsigned, struct host **, const char *, unsigned int); + int prune_host_list(unsigned, struct host **, unsigned int, const char *, unsigned int); + void dump_host_list(struct host *); + +diff --git a/modules/mount_nfs.c b/modules/mount_nfs.c +index 14d3850..21e1929 100644 +--- a/modules/mount_nfs.c ++++ b/modules/mount_nfs.c +@@ -137,7 +137,7 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int + else if (mount_default_proto == 4) + vers = vers | NFS4_VERS_MASK; + +- if (!parse_location(ap->logopt, &hosts, what)) { ++ if (!parse_location(ap->logopt, &hosts, what, random_selection)) { + info(ap->logopt, MODPREFIX "no hosts available"); + return 1; + } +diff --git a/modules/replicated.c b/modules/replicated.c +index 4cd3eb4..9eefb19 100644 +--- a/modules/replicated.c ++++ b/modules/replicated.c +@@ -1041,13 +1041,23 @@ int prune_host_list(unsigned logopt, struct host **list, + + static int add_new_host(struct host **list, + const char *host, unsigned int weight, +- struct addrinfo *host_addr) ++ struct addrinfo *host_addr, ++ unsigned int random_selection) + { + struct host *new; + unsigned int prx; + int addr_len; + +- prx = get_proximity(host_addr->ai_addr); ++ /* ++ * If we are using random selection we pretend all hosts are at ++ * the same proximity so hosts further away don't get excluded. ++ * We can't use PROXIMITY_LOCAL or we won't perform an RPC ping ++ * to remove hosts that may be down. ++ */ ++ if (random_selection) ++ prx = PROXIMITY_SUBNET; ++ else ++ prx = get_proximity(host_addr->ai_addr); + /* + * If we tried to add an IPv6 address and we don't have IPv6 + * support return success in the hope of getting an IPv4 +@@ -1071,7 +1081,8 @@ static int add_new_host(struct host **list, + return 1; + } + +-static int add_host_addrs(struct host **list, const char *host, unsigned int weight) ++static int add_host_addrs(struct host **list, const char *host, ++ unsigned int weight, unsigned int random_selection) + { + struct addrinfo hints, *ni, *this; + int ret; +@@ -1087,7 +1098,7 @@ static int add_host_addrs(struct host **list, const char *host, unsigned int wei + + this = ni; + while (this) { +- ret = add_new_host(list, host, weight, this); ++ ret = add_new_host(list, host, weight, this, random_selection); + if (!ret) + break; + this = this->ai_next; +@@ -1110,7 +1121,7 @@ try_name: + + this = ni; + while (this) { +- ret = add_new_host(list, host, weight, this); ++ ret = add_new_host(list, host, weight, this, random_selection); + if (!ret) + break; + this = this->ai_next; +@@ -1197,7 +1208,8 @@ static char *seek_delim(const char *s) + return NULL; + } + +-int parse_location(unsigned logopt, struct host **hosts, const char *list) ++int parse_location(unsigned logopt, struct host **hosts, ++ const char *list, unsigned int random_selection) + { + char *str, *p, *delim; + unsigned int empty = 1; +@@ -1252,7 +1264,7 @@ int parse_location(unsigned logopt, struct host **hosts, const char *list) + } + + if (p != delim) { +- if (!add_host_addrs(hosts, p, weight)) { ++ if (!add_host_addrs(hosts, p, weight, random_selection)) { + if (empty) { + p = next; + continue; +@@ -1274,7 +1286,7 @@ int parse_location(unsigned logopt, struct host **hosts, const char *list) + *delim = '\0'; + next = delim + 1; + +- if (!add_host_addrs(hosts, p, weight)) { ++ if (!add_host_addrs(hosts, p, weight, random_selection)) { + p = next; + continue; + } --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-fix-get-qdn-fail.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-fix-get-qdn-fail.dpatch @@ -0,0 +1,49 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-fix-get-qdn-fail.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - fix get query dn failure + +From: Ian Kent + +Recent changes to the LDAP connection logic can fail to retrieve a valid +query dn upon LDAP connection. + +If LDAP is being used to store autofs maps, the LDAP schema to be used +for the maps is explicitly defined in the autofs configuration and no +master map entries exist in LDAP autofs fails to try and retrieve a +query dn, returning success instead of failure. +--- + + CHANGELOG | 1 + + modules/lookup_ldap.c | 2 +- + 2 files changed, 2 insertions(+), 1 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index 224a34a..5a921e1 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -24,6 +24,7 @@ + - fix strdup() return value check (Leonardo Chiquitto). + - fix reconnect get base dn. + - add missing sasl mutex callbacks. ++- fix get query dn failure. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c +index e3c0c51..8387951 100644 +--- a/modules/lookup_ldap.c ++++ b/modules/lookup_ldap.c +@@ -556,7 +556,7 @@ static int do_bind(unsigned logopt, LDAP *ldap, const char *uri, struct lookup_c + } + } + +- if (ctxt->schema && !need_base) ++ if (ctxt->schema && ctxt->qdn && !need_base) + return 1; + + /* --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-fix-pidof-init-script-usage.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-fix-pidof-init-script-usage.dpatch @@ -0,0 +1,97 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-fix-pidof-init-script-usage.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - fix pidof init script usage + +From: Ian Kent + +For some reason, following an update, pidof doesn't return the pid +of a running automount daemon when the path is used rather than just +the name, probably to do with the inode of the daemon program changing. + +So we change the init script to use just the program name rather than +the path. +--- + + CHANGELOG | 1 + + redhat/autofs.init.in | 8 ++++---- + samples/rc.autofs.in | 8 ++++---- + 3 files changed, 9 insertions(+), 8 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index dd093e2..cc2efab 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -12,6 +12,7 @@ + - don't use master_lex_destroy() to clear parse buffer. + - make documentation for set-log-priority clearer. + - fix timeout in connect_nb(). ++- fix pidof init script usage. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/redhat/autofs.init.in b/redhat/autofs.init.in +index 806302b..363e824 100644 +--- a/redhat/autofs.init.in ++++ b/redhat/autofs.init.in +@@ -101,14 +101,14 @@ function start() { + function stop() { + echo -n $"Stopping $prog: " + count=0 +- while [ -n "`pidof $DAEMON`" -a $count -lt 15 ] ; do ++ while [ -n "`pidof $prog`" -a $count -lt 15 ] ; do + killproc $prog -TERM >& /dev/null + RETVAL=$? +- [ $RETVAL = 0 -a -z "`pidof $DAEMON`" ] || sleep 3 ++ [ $RETVAL = 0 -a -z "`pidof $prog`" ] || sleep 3 + count=`expr $count + 1` + done + [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/autofs +- if [ -n "`pidof $DAEMON`" ] ; then ++ if [ -n "`pidof $prog`" ] ; then + failure "$prog shutdown" + else + success "$prog shutdown" +@@ -128,7 +128,7 @@ function reload() { + RETVAL=1 + return $RETVAL + fi +- pid=`pidof $DAEMON` ++ pid=`pidof $prog` + if [ -z $pid ]; then + echo $"$prog not running" + RETVAL=1 +diff --git a/samples/rc.autofs.in b/samples/rc.autofs.in +index b193a4e..ae2e907 100644 +--- a/samples/rc.autofs.in ++++ b/samples/rc.autofs.in +@@ -88,13 +88,13 @@ function start() { + function stop() { + echo -n $"Stopping $prog: " + count=0 +- while [ -n "`pidof $DAEMON`" -a $count -lt 15 ] ; do ++ while [ -n "`pidof $prog`" -a $count -lt 15 ] ; do + killall -TERM $prog >& /dev/null + RETVAL=$? +- [ $RETVAL = 0 -a -z "`pidof $DAEMON`" ] || sleep 3 ++ [ $RETVAL = 0 -a -z "`pidof $prog`" ] || sleep 3 + count=`expr $count + 1` + done +- if [ -z "`pidof $DAEMON`" ] ; then ++ if [ -z "`pidof $prog`" ] ; then + echo "done." + else + echo "failed." +@@ -108,7 +108,7 @@ function restart() { + } + + function reload() { +- pid=`pidof $DAEMON` ++ pid=`pidof $prog` + if [ -z $pid ]; then + echo $"$prog not running" + RETVAL=1 --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-fix-add-simple-bind-auth.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-fix-add-simple-bind-auth.dpatch @@ -0,0 +1,86 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-fix-add-simple-bind-auth.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - fix add simple bind auth + +From: Ian Kent + +Simple authentication should not require SASL. +--- + + CHANGELOG | 1 + + include/lookup_ldap.h | 5 +++++ + modules/cyrus-sasl.c | 1 - + modules/lookup_ldap.c | 1 - + 4 files changed, 6 insertions(+), 2 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index b107515..1975369 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -53,6 +53,7 @@ + - always read file maps mount lookup map read fix. + - fix direct map not updating on reread. + - add external bind method. ++- fix add simple bind auth. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/include/lookup_ldap.h b/include/lookup_ldap.h +index 4067ccc..d34c9b8 100644 +--- a/include/lookup_ldap.h ++++ b/include/lookup_ldap.h +@@ -1,6 +1,8 @@ + #ifndef LOOKUP_LDAP_H + #define LOOKUP_LDAP_H + ++#include ++ + #ifdef WITH_SASL + #include + #include +@@ -102,6 +104,8 @@ struct lookup_context { + #define LDAP_AUTH_NOTREQUIRED 0x0001 + #define LDAP_AUTH_REQUIRED 0x0002 + #define LDAP_AUTH_AUTODETECT 0x0004 ++#endif ++ + #define LDAP_AUTH_USESIMPLE 0x0008 + + /* lookup_ldap.c */ +@@ -109,6 +113,7 @@ LDAP *init_ldap_connection(unsigned logopt, const char *uri, struct lookup_conte + int unbind_ldap_connection(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt); + int authtype_requires_creds(const char *authtype); + ++#ifdef WITH_SASL + /* cyrus-sasl.c */ + int autofs_sasl_client_init(unsigned logopt); + int autofs_sasl_init(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt); +diff --git a/modules/cyrus-sasl.c b/modules/cyrus-sasl.c +index 967edc3..b5c87b6 100644 +--- a/modules/cyrus-sasl.c ++++ b/modules/cyrus-sasl.c +@@ -51,7 +51,6 @@ + #include + #include + #include +-#include + #include + + #include "automount.h" +diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c +index 1432056..71aee1b 100644 +--- a/modules/lookup_ldap.c ++++ b/modules/lookup_ldap.c +@@ -28,7 +28,6 @@ + #include + #include + #include +-#include + + #define MODULE_LOOKUP + #include "automount.h" --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-fix-parse_sun-module-init.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-fix-parse_sun-module-init.dpatch @@ -0,0 +1,117 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-fix-parse_sun-module-init.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - fix parse_sun() module init + +From: Ian Kent + +In the parse sun module we pre-open the NFS mount module and cache +the library handle because it is used so often. Since this is shared +amonst all the master map entries multiple threads can race when +accessing the instance counter, especially when there are many +master map entries, leading to a double close on the mount library +handle. +--- + + CHANGELOG | 1 + + modules/parse_sun.c | 37 ++++++++++++++++++++++++++++++------- + 2 files changed, 31 insertions(+), 7 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index 76207c8..334be80 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -36,6 +36,7 @@ + - don't hold lock for simple mounts. + - fix remount locking. + - fix wildcard map entry match. ++- fix parse_sun() module init. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/modules/parse_sun.c b/modules/parse_sun.c +index 34458d0..1f91ad1 100644 +--- a/modules/parse_sun.c ++++ b/modules/parse_sun.c +@@ -45,6 +45,22 @@ int parse_version = AUTOFS_PARSE_VERSION; /* Required by protocol */ + + static struct mount_mod *mount_nfs = NULL; + static int init_ctr = 0; ++static int macro_init_done = 0; ++static pthread_mutex_t instance_mutex = PTHREAD_MUTEX_INITIALIZER; ++ ++static void instance_mutex_lock(void) ++{ ++ int status = pthread_mutex_lock(&instance_mutex); ++ if (status) ++ fatal(status); ++} ++ ++static void instance_mutex_unlock(void) ++{ ++ int status = pthread_mutex_unlock(&instance_mutex); ++ if (status) ++ fatal(status); ++} + + extern const char *global_options; + +@@ -276,9 +292,12 @@ int parse_init(int argc, const char *const *argv, void **context) + unsigned int append_options; + + /* Get processor information for predefined escapes */ +- +- if (!init_ctr) ++ macro_lock(); ++ if (!macro_init_done) { ++ macro_init_done = 1; + macro_init(); ++ } ++ macro_unlock(); + + /* Set up context and escape chain */ + +@@ -434,19 +453,21 @@ options_done: + + /* We only need this once. NFS mounts are so common that we cache + this module. */ +- if (!mount_nfs) { ++ instance_mutex_lock(); ++ if (mount_nfs) ++ init_ctr++; ++ else { + if ((mount_nfs = open_mount("nfs", MODPREFIX))) { + init_ctr++; +- return 0; + } else { + kill_context(ctxt); + *context = NULL; ++ instance_mutex_unlock(); + return 1; + } +- } else { +- init_ctr++; +- return 0; + } ++ instance_mutex_unlock(); ++ return 0; + } + + static const char *parse_options(const char *str, char **ret, unsigned int logopt) +@@ -1734,10 +1755,12 @@ int parse_done(void *context) + int rv = 0; + struct parse_context *ctxt = (struct parse_context *) context; + ++ instance_mutex_lock(); + if (--init_ctr == 0) { + rv = close_mount(mount_nfs); + mount_nfs = NULL; + } ++ instance_mutex_unlock(); + if (ctxt) + kill_context(ctxt); + --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-make-documentation-for-set-log-priority-clearer.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-make-documentation-for-set-log-priority-clearer.dpatch @@ -0,0 +1,49 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-make-documentation-for-set-log-priority-clearer.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - make documentation for set-log-priority clearer + +From: Jeff Moyer + +It is not apparent from the documentation of the --set-log-priority +option that the option can be used to change the log priority of the +damon while it is running. This patch tries to fix that. + +Signed-off-by: Jeff Moyer +--- + + CHANGELOG | 1 + + man/automount.8 | 4 +++- + 2 files changed, 4 insertions(+), 1 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index 329b028..ccf2d32 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -10,6 +10,7 @@ + - fix stale initialization for file map instance. + - add "preen" fsck for ext4 mounts. + - don't use master_lex_destroy() to clear parse buffer. ++- make documentation for set-log-priority clearer. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/man/automount.8 b/man/automount.8 +index 9fcaaf4..d9a45c2 100644 +--- a/man/automount.8 ++++ b/man/automount.8 +@@ -77,7 +77,9 @@ changes. For example, if verbose logging is set in the configuration then + attempting to set logging to basic logging, by using alert, crit, err + or emerg won't stop the verbose logging. However, setting logging to debug + will lead to everything (debug logging) being logged witch can then also +-be disabled, returning the daemon to verbose logging. ++be disabled, returning the daemon to verbose logging. This option can be ++specified to change the logging priority of an already running automount ++process. + .P + The \fIpath\fP argument corresponds to the automounted + path name as specified in the master map. --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-fix-libxml2-workaround-configure.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-fix-libxml2-workaround-configure.dpatch @@ -0,0 +1,85 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-fix-libxml2-workaround-configure.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - fix libxml2 workaround configure + +From: Ian Kent + +The configure logic related to work around the libxml2 library +reload issues is not quite right. The xml code is needed if +ldap is used so it is sufficient to require inclusion of the +workaround code if autofs is being built with LDAP support. +--- + + CHANGELOG | 1 + + daemon/Makefile | 2 -- + daemon/automount.c | 8 +++++--- + 3 files changed, 6 insertions(+), 5 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index 671c979..23351c8 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -4,6 +4,7 @@ + - refactor ldap sasl bind handling. + - add mount wait timeout parameter. + - special case cifs escapes. ++- fix compile fail with when LDAP is excluded. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/daemon/Makefile b/daemon/Makefile +index 371ec72..9e9d635 100644 +--- a/daemon/Makefile ++++ b/daemon/Makefile +@@ -23,10 +23,8 @@ LDFLAGS += -rdynamic + LIBS = -ldl + + ifeq ($(LDAP), 1) +- ifeq ($(SASL), 1) + CFLAGS += $(XML_FLAGS) + LIBS += $(XML_LIBS) +- endif + endif + + all: automount +diff --git a/daemon/automount.c b/daemon/automount.c +index 979ecd6..7c44d4b 100644 +--- a/daemon/automount.c ++++ b/daemon/automount.c +@@ -38,10 +38,12 @@ + #include + + #include "automount.h" +-#ifdef LIBXML2_WORKAROUND ++#if defined(LIBXML2_WORKAROUND) || defined(TIRPC_WORKAROUND) + #include ++#ifdef WITH_LDAP + #include + #endif ++#endif + + const char *program; /* Initialized with argv[0] */ + const char *version = VERSION_STRING; /* Program version */ +@@ -2110,7 +2112,7 @@ int main(int argc, char *argv[]) + exit(1); + } + +-#ifdef LIBXML2_WORKAROUND ++#if defined(WITH_LDAP) && defined(LIBXML2_WORKAROUND) + void *dh_xml2 = dlopen("libxml2.so", RTLD_NOW); + if (!dh_xml2) + dh_xml2 = dlopen("libxml2.so.2", RTLD_NOW); +@@ -2158,7 +2160,7 @@ int main(int argc, char *argv[]) + if (dh_tirpc) + dlclose(dh_tirpc); + #endif +-#ifdef LIBXML2_WORKAROUND ++#if defined(WITH_LDAP) && defined( LIBXML2_WORKAROUND) + if (dh_xml2) { + xmlCleanupParser(); + dlclose(dh_xml2); --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-dont-check-null-cache-on-expire.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-dont-check-null-cache-on-expire.dpatch @@ -0,0 +1,58 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-dont-check-null-cache-on-expire.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - dont check null cache on expire + +From: Ian Kent + +When expiring an entry there is no need to check the null map +entry cache. If we have a mount then it must have been done at +some point when the entry was not a nulled so it still needs +to be expired. Remove this check. +--- + + CHANGELOG | 1 + + daemon/automount.c | 9 --------- + 2 files changed, 1 insertions(+), 9 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index 334be80..5d673ea 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -37,6 +37,7 @@ + - fix remount locking. + - fix wildcard map entry match. + - fix parse_sun() module init. ++- dont check null cache on expire. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/daemon/automount.c b/daemon/automount.c +index 915928b..5a1f189 100644 +--- a/daemon/automount.c ++++ b/daemon/automount.c +@@ -526,20 +526,11 @@ static int umount_subtree_mounts(struct autofs_point *ap, const char *path, unsi + it also tries to umount path itself */ + int umount_multi(struct autofs_point *ap, const char *path, int incl) + { +- struct mapent_cache *nc; + int is_autofs_fs; + int left; + + debug(ap->logopt, "path %s incl %d", path, incl); + +- nc = ap->entry->master->nc; +- cache_readlock(nc); +- if (cache_lookup_distinct(nc, path)) { +- cache_unlock(nc); +- return 0; +- } +- cache_unlock(nc); +- + is_autofs_fs = 0; + if (master_find_submount(ap, path)) + is_autofs_fs = 1; --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-fix-remount-locking.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-fix-remount-locking.dpatch @@ -0,0 +1,386 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-fix-remount-locking.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - fix remount locking + +From: Ian Kent + +When autofs is restarted with active mounts it is possible, due +to possible recursion when mounting multi-mount map entries, that +a lookup module will take a write lock on the map entry cache +when a read lock is alreay held. + +Since, during the re-mount, we are still essentially running +single threaded we need only take care to ensure we don't take +the write lock. +--- + + CHANGELOG | 1 + + modules/lookup_file.c | 27 +++++++++++++++++---------- + modules/lookup_hosts.c | 26 ++++++++++++++++---------- + modules/lookup_ldap.c | 24 ++++++++++++++++-------- + modules/lookup_nisplus.c | 29 ++++++++++++++++++----------- + modules/lookup_program.c | 29 +++++++++++++++++++++-------- + modules/lookup_yp.c | 27 +++++++++++++++++---------- + 7 files changed, 106 insertions(+), 57 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index 488cd2e..6ef2d5a 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -34,6 +34,7 @@ + - fix random selection for host on different network. + - make redhat init script more lsb compliant. + - don't hold lock for simple mounts. ++- fix remount locking. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/modules/lookup_file.c b/modules/lookup_file.c +index 6104d0c..676be9e 100644 +--- a/modules/lookup_file.c ++++ b/modules/lookup_file.c +@@ -871,7 +871,6 @@ static int check_map_indirect(struct autofs_point *ap, + if (ret == CHE_FAIL) + return NSS_STATUS_NOTFOUND; + +- pthread_cleanup_push(cache_lock_cleanup, mc); + cache_writelock(mc); + exists = cache_lookup_distinct(mc, key); + /* Not found in the map but found in the cache */ +@@ -882,7 +881,7 @@ static int check_map_indirect(struct autofs_point *ap, + exists->status = 0; + } + } +- pthread_cleanup_pop(1); ++ cache_unlock(mc); + + if (ret == CHE_MISSING) { + struct mapent *we; +@@ -896,7 +895,6 @@ static int check_map_indirect(struct autofs_point *ap, + * Check for map change and update as needed for + * following cache lookup. + */ +- pthread_cleanup_push(cache_lock_cleanup, mc); + cache_writelock(mc); + we = cache_lookup_distinct(mc, "*"); + if (we) { +@@ -904,7 +902,7 @@ static int check_map_indirect(struct autofs_point *ap, + if (we->source == source && (wild & CHE_MISSING)) + cache_delete(mc, "*"); + } +- pthread_cleanup_pop(1); ++ cache_unlock(mc); + + if (wild & (CHE_OK | CHE_UPDATED)) + return NSS_STATUS_SUCCESS; +@@ -957,13 +955,22 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void * + if (me->status >= time(NULL)) { + cache_unlock(me->mc); + return NSS_STATUS_NOTFOUND; +- } +- +- /* Negative timeout expired for non-existent entry. */ +- if (!me->mapent) +- cache_delete(me->mc, key); ++ } else { ++ struct mapent_cache *smc = me->mc; ++ struct mapent *sme; + +- cache_unlock(me->mc); ++ if (me->mapent) ++ cache_unlock(smc); ++ else { ++ cache_unlock(smc); ++ cache_writelock(smc); ++ sme = cache_lookup_distinct(smc, key); ++ /* Negative timeout expired for non-existent entry. */ ++ if (sme && !sme->mapent) ++ cache_delete(smc, key); ++ cache_unlock(smc); ++ } ++ } + } + + /* +diff --git a/modules/lookup_hosts.c b/modules/lookup_hosts.c +index a213780..cc259b2 100644 +--- a/modules/lookup_hosts.c ++++ b/modules/lookup_hosts.c +@@ -146,19 +146,25 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void * + /* Check if we recorded a mount fail for this key anywhere */ + me = lookup_source_mapent(ap, name, LKP_DISTINCT); + if (me) { +- struct mapent_cache *fmc = me->mc; +- + if (me->status >= time(NULL)) { +- cache_unlock(fmc); ++ cache_unlock(me->mc); + return NSS_STATUS_NOTFOUND; ++ } else { ++ struct mapent_cache *smc = me->mc; ++ struct mapent *sme; ++ ++ if (me->mapent) ++ cache_unlock(smc); ++ else { ++ cache_unlock(smc); ++ cache_writelock(smc); ++ sme = cache_lookup_distinct(smc, name); ++ /* Negative timeout expired for non-existent entry. */ ++ if (sme && !sme->mapent) ++ cache_delete(smc, name); ++ cache_unlock(smc); ++ } + } +- +- if (!me->mapent) { +- cache_delete(fmc, name); +- me = NULL; +- } +- +- cache_unlock(fmc); + } + + cache_readlock(mc); +diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c +index d7d4f71..f02d0dc 100644 +--- a/modules/lookup_ldap.c ++++ b/modules/lookup_ldap.c +@@ -2681,7 +2681,6 @@ next: + unbind_ldap_connection(ap->logopt, ldap, ctxt); + + /* Failed to find wild entry, update cache if needed */ +- pthread_cleanup_push(cache_lock_cleanup, mc); + cache_writelock(mc); + we = cache_lookup_distinct(mc, "*"); + if (we) { +@@ -2707,7 +2706,7 @@ next: + } + } + } +- pthread_cleanup_pop(1); ++ cache_unlock(mc); + free(query); + + return ret; +@@ -2817,13 +2816,22 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void * + if (me->status >= time(NULL)) { + cache_unlock(me->mc); + return NSS_STATUS_NOTFOUND; +- } +- +- /* Negative timeout expired for non-existent entry. */ +- if (!me->mapent) +- cache_delete(me->mc, key); ++ } else { ++ struct mapent_cache *smc = me->mc; ++ struct mapent *sme; + +- cache_unlock(me->mc); ++ if (me->mapent) ++ cache_unlock(smc); ++ else { ++ cache_unlock(smc); ++ cache_writelock(smc); ++ sme = cache_lookup_distinct(smc, key); ++ /* Negative timeout expired for non-existent entry. */ ++ if (sme && !sme->mapent) ++ cache_delete(smc, key); ++ cache_unlock(smc); ++ } ++ } + } + + /* +diff --git a/modules/lookup_nisplus.c b/modules/lookup_nisplus.c +index ae53481..9b7941a 100644 +--- a/modules/lookup_nisplus.c ++++ b/modules/lookup_nisplus.c +@@ -421,7 +421,6 @@ static int check_map_indirect(struct autofs_point *ap, + return NSS_STATUS_UNAVAIL; + } + +- pthread_cleanup_push(cache_lock_cleanup, mc); + cache_writelock(mc); + t_last_read = ap->exp_runfreq + 1; + me = cache_lookup_first(mc); +@@ -442,8 +441,8 @@ static int check_map_indirect(struct autofs_point *ap, + exists->status = 0; + } + } +- pthread_cleanup_pop(1); +- ++ cache_unlock(mc); ++ + if (t_last_read > ap->exp_runfreq && ret & CHE_UPDATED) + source->stale = 1; + +@@ -459,7 +458,6 @@ static int check_map_indirect(struct autofs_point *ap, + * Check for map change and update as needed for + * following cache lookup. + */ +- pthread_cleanup_push(cache_lock_cleanup, mc); + cache_writelock(mc); + we = cache_lookup_distinct(mc, "*"); + if (we) { +@@ -473,7 +471,7 @@ static int check_map_indirect(struct autofs_point *ap, + if (wild & (CHE_OK | CHE_UPDATED)) + source->stale = 1; + } +- pthread_cleanup_pop(1); ++ cache_unlock(mc); + + if (wild & (CHE_UPDATED | CHE_OK)) + return NSS_STATUS_SUCCESS; +@@ -516,13 +514,22 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void * + if (me->status >= time(NULL)) { + cache_unlock(me->mc); + return NSS_STATUS_NOTFOUND; ++ } else { ++ struct mapent_cache *smc = me->mc; ++ struct mapent *sme; ++ ++ if (me->mapent) ++ cache_unlock(smc); ++ else { ++ cache_unlock(smc); ++ cache_writelock(smc); ++ sme = cache_lookup_distinct(smc, key); ++ /* Negative timeout expired for non-existent entry. */ ++ if (sme && !sme->mapent) ++ cache_delete(smc, key); ++ cache_unlock(smc); ++ } + } +- +- /* Negative timeout expired for non-existent entry. */ +- if (!me->mapent) +- cache_delete(me->mc, key); +- +- cache_unlock(me->mc); + } + + /* +diff --git a/modules/lookup_program.c b/modules/lookup_program.c +index 5b295a5..2457108 100644 +--- a/modules/lookup_program.c ++++ b/modules/lookup_program.c +@@ -135,17 +135,26 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void * + if (me->status >= time(NULL)) { + cache_unlock(me->mc); + return NSS_STATUS_NOTFOUND; ++ } else { ++ struct mapent_cache *smc = me->mc; ++ struct mapent *sme; ++ ++ if (me->mapent) ++ cache_unlock(smc); ++ else { ++ cache_unlock(smc); ++ cache_writelock(smc); ++ sme = cache_lookup_distinct(smc, name); ++ /* Negative timeout expired for non-existent entry. */ ++ if (sme && !sme->mapent) ++ cache_delete(smc, name); ++ cache_unlock(smc); ++ } + } +- +- /* Negative timeout expired for non-existent entry. */ +- if (!me->mapent) +- cache_delete(me->mc, name); +- +- cache_unlock(me->mc); + } + + /* Catch installed direct offset triggers */ +- cache_writelock(mc); ++ cache_readlock(mc); + me = cache_lookup_distinct(mc, name); + if (!me) { + cache_unlock(mc); +@@ -191,7 +200,11 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void * + " key %s, returning fail", name); + return NSS_STATUS_UNAVAIL; + } +- cache_delete(mc, name); ++ cache_unlock(mc); ++ cache_writelock(mc); ++ me = cache_lookup_distinct(mc, name); ++ if (me) ++ cache_delete(mc, name); + cache_unlock(mc); + } + } +diff --git a/modules/lookup_yp.c b/modules/lookup_yp.c +index 208f95e..fb0ae9f 100644 +--- a/modules/lookup_yp.c ++++ b/modules/lookup_yp.c +@@ -533,7 +533,6 @@ static int check_map_indirect(struct autofs_point *ap, + source->stale = 1; + } + +- pthread_cleanup_push(cache_lock_cleanup, mc); + cache_writelock(mc); + exists = cache_lookup_distinct(mc, key); + /* Not found in the map but found in the cache */ +@@ -545,7 +544,7 @@ static int check_map_indirect(struct autofs_point *ap, + exists->status = 0; + } + } +- pthread_cleanup_pop(1); ++ cache_unlock(mc); + + if (ret == CHE_MISSING) { + struct mapent *we; +@@ -559,7 +558,6 @@ static int check_map_indirect(struct autofs_point *ap, + * Check for map change and update as needed for + * following cache lookup. + */ +- pthread_cleanup_push(cache_lock_cleanup, mc); + cache_writelock(mc); + we = cache_lookup_distinct(mc, "*"); + if (we) { +@@ -573,7 +571,7 @@ static int check_map_indirect(struct autofs_point *ap, + if (wild & (CHE_OK | CHE_UPDATED)) + source->stale = 1; + } +- pthread_cleanup_pop(1); ++ cache_unlock(mc); + + if (wild & (CHE_OK | CHE_UPDATED)) + return NSS_STATUS_SUCCESS; +@@ -616,13 +614,22 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void * + if (me->status >= time(NULL)) { + cache_unlock(me->mc); + return NSS_STATUS_NOTFOUND; ++ } else { ++ struct mapent_cache *smc = me->mc; ++ struct mapent *sme; ++ ++ if (me->mapent) ++ cache_unlock(smc); ++ else { ++ cache_unlock(smc); ++ cache_writelock(smc); ++ sme = cache_lookup_distinct(smc, key); ++ /* Negative timeout expired for non-existent entry. */ ++ if (sme && !sme->mapent) ++ cache_delete(smc, key); ++ cache_unlock(smc); ++ } + } +- +- /* Negative timeout expired for non-existent entry. */ +- if (!me->mapent) +- cache_delete(me->mc, key); +- +- cache_unlock(me->mc); + } + + /* --- autofs5-5.0.5.orig/debian/patches/14avoid_sock_cloexec.dpatch +++ autofs5-5.0.5/debian/patches/14avoid_sock_cloexec.dpatch @@ -0,0 +1,21 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 14avoid_sock_cloexec.dpatch by +## +## DP: Don't use SOCK_CLOEXEC yet because 2.6.27 is not well-established +## DP: and all upstream does is a compile-team test against the glibc. + +@DPATCH@ +--- autofs5-5.0.4.orig/include/automount.h 2009-03-11 22:04:56.356896234 +0100 ++++ autofs5-5.0.4/include/automount.h 2009-03-11 22:08:58.381860088 +0100 +@@ -40,6 +40,11 @@ + #include + #endif + ++/* Avoid using SOCK_CLOEXEC as long as 2.6.27 is still young */ ++#ifdef SOCK_CLOEXEC ++# undef SOCK_CLOEXEC ++#endif ++ + #define ENABLE_CORES 1 + + /* We MUST have the paths to mount(8) and umount(8) */ --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-fix-submount-shutdown-wait.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-fix-submount-shutdown-wait.dpatch @@ -0,0 +1,49 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-fix-submount-shutdown-wait.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - fix submount shutdown wait + +From: Ian Kent + +When expiring a mount that has submounts we determine if a submount is +still in use by its state being other than ST_SHUTDOWN. But a submount +that is in the process of exiting could also be in one of the states +ST_SHUTDOWN_PENDING or ST_SHUTDOWN_FORCE, in which case we should also +continue to wait for the submount entry to be removed from the list or +for it to reach another state. +--- + + lib/master.c | 9 ++++++--- + 1 files changed, 6 insertions(+), 3 deletions(-) + + +diff --git a/lib/master.c b/lib/master.c +index ad3aa77..95bd3fb 100644 +--- a/lib/master.c ++++ b/lib/master.c +@@ -905,8 +905,9 @@ int master_notify_submount(struct autofs_point *ap, const char *path, enum state + st_wait_task(this, state, 0); + + /* +- * If our submount gets to state ST_SHUTDOWN we need to +- * wait until it goes away or changes to ST_READY. ++ * If our submount gets to state ST_SHUTDOWN, ST_SHUTDOWN_PENDING or ++ * ST_SHUTDOWN_FORCE we need to wait until it goes away or changes ++ * to ST_READY. + */ + mounts_mutex_lock(ap); + st_mutex_lock(); +@@ -914,7 +915,9 @@ int master_notify_submount(struct autofs_point *ap, const char *path, enum state + struct timespec t = { 0, 300000000 }; + struct timespec r; + +- if (this->state != ST_SHUTDOWN) { ++ if (this->state != ST_SHUTDOWN && ++ this->state != ST_SHUTDOWN_PENDING && ++ this->state != ST_SHUTDOWN_FORCE) { + ret = 0; + break; + } --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-dont-hold-lock-for-simple-mounts.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-dont-hold-lock-for-simple-mounts.dpatch @@ -0,0 +1,127 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-dont-hold-lock-for-simple-mounts.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - don't hold lock for simple mounts + +From: Ian Kent + +A map entry that depends on another map entry in the "same" map cannot +be allowed in all cases. In particular, multi-mount entries must not +change during mount operations so the internal map entry cache must +remain locked during the mount. This is because, during the mount, we +must consult the map and possibly update the internal cache entry to +ensure we are using the most up to date mount information. + +This isn't the case for non multi-mount map entries but autofs didn't +allow for this, which is the issue this patch addresses. +--- + + CHANGELOG | 1 + + modules/parse_sun.c | 41 +++++++++++++++++------------------------ + 2 files changed, 18 insertions(+), 24 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index 8a9611b..488cd2e 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -33,6 +33,7 @@ + - add autofs_ldap_auth.conf man page. + - fix random selection for host on different network. + - make redhat init script more lsb compliant. ++- don't hold lock for simple mounts. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/modules/parse_sun.c b/modules/parse_sun.c +index 921daf4..34458d0 100644 +--- a/modules/parse_sun.c ++++ b/modules/parse_sun.c +@@ -1136,19 +1136,6 @@ static int mount_subtree(struct autofs_point *ap, struct mapent *me, + + rv = 0; + +- if (!me || !me->multi) { +- int loclen = strlen(loc); +- int namelen = strlen(name); +- const char *root = ap->path; +- +- if (!strcmp(ap->path, "/-")) +- root = name; +- +- rv = sun_mount(ap, root, name, namelen, loc, loclen, options, ctxt); +- +- goto done; +- } +- + mm = me->multi; + mm_key = mm->key; + move = MOUNT_MOVE_NONE; +@@ -1294,7 +1281,6 @@ static int mount_subtree(struct autofs_point *ap, struct mapent *me, + if (rv > 0) + return rv; + +-done: + /* + * Convert fail on nonstrict, non-empty multi-mount + * to success +@@ -1622,17 +1608,25 @@ int parse_mount(struct autofs_point *ap, const char *name, + * it's already been parsed (above) and any option string + * has already been stripped so just use the remainder. + */ ++ cache_readlock(mc); + if (*name == '/' && + (me = cache_lookup_distinct(mc, name)) && me->multi) { + loc = strdup(p); + if (!loc) { + free(options); ++ cache_unlock(mc); + warn(ap->logopt, MODPREFIX "out of memory"); + return 1; + } +- loclen = strlen(p); +- goto mount_it; ++ cache_multi_writelock(me); ++ rv = mount_subtree(ap, me, name, loc, options, ctxt); ++ cache_multi_unlock(me); ++ cache_unlock(mc); ++ free(loc); ++ free(options); ++ return rv; + } ++ cache_unlock(mc); + + l = chunklen(p, check_colon(p)); + loc = dequote(p, l, ap->logopt); +@@ -1716,21 +1710,20 @@ int parse_mount(struct autofs_point *ap, const char *name, + MODPREFIX "entry %s is empty!", name); + return 1; + } +-mount_it: ++ + debug(ap->logopt, + MODPREFIX "core of entry: options=%s, loc=%.*s", + options, loclen, loc); + +- cache_readlock(mc); +- cache_multi_writelock(me); +- +- rv = mount_subtree(ap, me, name, loc, options, ctxt); ++ if (!strcmp(ap->path, "/-")) ++ rv = sun_mount(ap, name, name, name_len, ++ loc, loclen, options, ctxt); ++ else ++ rv = sun_mount(ap, ap->path, name, name_len, ++ loc, loclen, options, ctxt); + + free(loc); + free(options); +- +- cache_multi_unlock(me); +- cache_unlock(mc); + pthread_setcancelstate(cur_state, NULL); + } + return rv; --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-check-each-dc-server.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-check-each-dc-server.dpatch @@ -0,0 +1,209 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-check-each-dc-server.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - check each dc server + +From: Ian Kent + +We return a space separated list of dc servers from get_dc_list() but the +GSSAPI code needs an individual server in the uri to function correctly. + +Change the logic in find_server() and do_reconnect() to attempt a connection +to each dc server individually. +--- + + CHANGELOG | 1 + modules/lookup_ldap.c | 103 +++++++++++++++++++++++++++++-------------------- + 2 files changed, 62 insertions(+), 42 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index 4788f44..84e3216 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -41,6 +41,7 @@ + - fix null cache race. + - fix cache_init() on source re-read. + - fix mapent becomes negative during lookup. ++- check each dc server individually. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c +index 9aac960..e9d1fa2 100644 +--- a/modules/lookup_ldap.c ++++ b/modules/lookup_ldap.c +@@ -615,23 +615,43 @@ static LDAP *connect_to_server(unsigned logopt, const char *uri, struct lookup_c + return ldap; + } + ++static LDAP *find_dc_server(unsigned logopt, const char *uri, struct lookup_context *ctxt) ++{ ++ char *str, *tok, *ptr = NULL; ++ LDAP *ldap = NULL; ++ ++ str = strdup(uri); ++ if (!str) ++ return NULL; ++ ++ tok = strtok_r(str, " ", &ptr); ++ while (tok) { ++ const char *this = (const char *) tok; ++ debug(logopt, "trying server uri %s", this); ++ ldap = connect_to_server(logopt, this, ctxt); ++ if (ldap) { ++ info(logopt, "connected to uri %s", this); ++ free(str); ++ return ldap; ++ } ++ tok = strtok_r(NULL, " ", &ptr); ++ } ++ ++ free(str); ++ ++ return NULL; ++} ++ + static LDAP *find_server(unsigned logopt, struct lookup_context *ctxt) + { + LDAP *ldap = NULL; + struct ldap_uri *this; + struct list_head *p, *first; +- struct dclist *dclist = NULL; ++ struct dclist *dclist; + char *uri = NULL; + + uris_mutex_lock(ctxt); +- if (ctxt->dclist) { +- dclist = ctxt->dclist; +- if (ctxt->dclist->expire < time(NULL)) { +- free_dclist(ctxt->dclist); +- ctxt->dclist = NULL; +- dclist = NULL; +- } +- } ++ dclist = ctxt->dclist; + if (!ctxt->uri) + first = ctxt->uris; + else +@@ -648,9 +668,16 @@ static LDAP *find_server(unsigned logopt, struct lookup_context *ctxt) + continue; + } + this = list_entry(p, struct ldap_uri, list); +- if (!strstr(this->uri, ":///")) ++ if (!strstr(this->uri, ":///")) { + uri = strdup(this->uri); +- else { ++ debug(logopt, "trying server uri %s", uri); ++ ldap = connect_to_server(logopt, uri, ctxt); ++ if (ldap) { ++ info(logopt, "connected to uri %s", uri); ++ free(uri); ++ break; ++ } ++ } else { + if (dclist) + uri = strdup(dclist->uri); + else { +@@ -663,21 +690,11 @@ static LDAP *find_server(unsigned logopt, struct lookup_context *ctxt) + dclist = tmp; + uri = strdup(dclist->uri); + } +- } +- if (!uri) { +- if (dclist) { +- free_dclist(dclist); +- dclist = NULL; ++ ldap = find_dc_server(logopt, uri, ctxt); ++ if (ldap) { ++ free(uri); ++ break; + } +- p = p->next; +- continue; +- } +- debug(logopt, "trying server uri %s", uri); +- ldap = connect_to_server(logopt, uri, ctxt); +- if (ldap) { +- info(logopt, "connected to uri %s", uri); +- free(uri); +- break; + } + free(uri); + uri = NULL; +@@ -708,7 +725,7 @@ static LDAP *find_server(unsigned logopt, struct lookup_context *ctxt) + + static LDAP *do_reconnect(unsigned logopt, struct lookup_context *ctxt) + { +- LDAP *ldap; ++ LDAP *ldap = NULL; + char *uri; + + if (ctxt->server || !ctxt->uris) { +@@ -723,25 +740,29 @@ static LDAP *do_reconnect(unsigned logopt, struct lookup_context *ctxt) + return ldap; + } + ++ if (ctxt->dclist) { ++ ldap = find_dc_server(logopt, ctxt->dclist->uri, ctxt); ++ if (ldap) ++ return ldap; ++ } ++ + uris_mutex_lock(ctxt); +- if (ctxt->dclist) +- uri = strdup(ctxt->dclist->uri); +- else if (ctxt->uri) +- uri = strdup(ctxt->uri->uri); +- else { ++ if (ctxt->dclist) { ++ if (!ldap || ctxt->dclist->expire < time(NULL)) { ++ free_dclist(ctxt->dclist); ++ ctxt->dclist = NULL; ++ } ++ /* Make sure we don't skip the domain spec */ ++ ctxt->uri = NULL; + uris_mutex_unlock(ctxt); + goto find_server; + } + uris_mutex_unlock(ctxt); + +- if (!uri) { +- char buf[MAX_ERR_BUF]; +- char *estr = strerror_r(errno, buf, sizeof(buf)); +- crit(logopt, MODPREFIX "strdup: %s", estr); +- return NULL; +- } ++ if (!ctxt->uri) ++ goto find_server; + +- ldap = do_connect(logopt, uri, ctxt); ++ ldap = do_connect(logopt, ctxt->uri->uri, ctxt); + #ifdef WITH_SASL + /* + * Dispose of the sasl authentication connection and try the +@@ -752,19 +773,17 @@ static LDAP *do_reconnect(unsigned logopt, struct lookup_context *ctxt) + ldap = connect_to_server(logopt, uri, ctxt); + } + #endif +- free(uri); +- + if (ldap) + return ldap; + + /* Failed to connect, try to find a new server */ + ++find_server: + #ifdef WITH_SASL + autofs_sasl_dispose(ctxt); + #endif + +-find_server: +- /* Current server failed connect, try the rest */ ++ /* Current server failed, try the rest or dc connection */ + ldap = find_server(logopt, ctxt); + if (!ldap) + error(logopt, MODPREFIX "failed to find available server"); --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-fix-error-handing-in-do_mount_indirect.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-fix-error-handing-in-do_mount_indirect.dpatch @@ -0,0 +1,53 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-fix-error-handing-in-do_mount_indirect.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - fix error handing in do_mount_indirect() + +From: Ian Kent + +A couple of error returns in do_mount_indirect() fail to notify +the kernel of request status before terminating. +--- + + CHANGELOG | 1 + + daemon/indirect.c | 4 ++++ + 2 files changed, 5 insertions(+), 0 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index e5d743b..5f6465a 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -45,6 +45,7 @@ + - fix negative cache included map lookup. + - remove state machine timed wait. + - remove extra read master map call. ++- fix error handing in do_mount_indirect(). + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/daemon/indirect.c b/daemon/indirect.c +index 8025ee4..09d784b 100644 +--- a/daemon/indirect.c ++++ b/daemon/indirect.c +@@ -792,6 +792,9 @@ static void *do_mount_indirect(void *arg) + len = ncat_path(buf, sizeof(buf), ap->path, mt.name, mt.len); + if (!len) { + crit(ap->logopt, "path to be mounted is to long"); ++ ops->send_fail(ap->logopt, ++ ap->ioctlfd, mt.wait_queue_token, ++ -ENAMETOOLONG); + pthread_setcancelstate(state, NULL); + pthread_exit(NULL); + } +@@ -800,6 +803,7 @@ static void *do_mount_indirect(void *arg) + if (status != -1 && !(S_ISDIR(st.st_mode) && st.st_dev == mt.dev)) { + error(ap->logopt, + "indirect trigger not valid or already mounted %s", buf); ++ ops->send_ready(ap->logopt, ap->ioctlfd, mt.wait_queue_token); + pthread_setcancelstate(state, NULL); + pthread_exit(NULL); + } --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-make-redhat-init-script-more-lsb-compliant.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-make-redhat-init-script-more-lsb-compliant.dpatch @@ -0,0 +1,122 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-make-redhat-init-script-more-lsb-compliant.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - make redhat init script more lsb compliant + +From: Ian Kent + + +--- + + CHANGELOG | 1 + + redhat/autofs.init.in | 39 ++++++++++++++++++++++++++++++++------- + 2 files changed, 33 insertions(+), 7 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index 470de69..8a9611b 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -32,6 +32,7 @@ + - fix master map source server unavailable handling. + - add autofs_ldap_auth.conf man page. + - fix random selection for host on different network. ++- make redhat init script more lsb compliant. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/redhat/autofs.init.in b/redhat/autofs.init.in +index 363e824..1e926ce 100644 +--- a/redhat/autofs.init.in ++++ b/redhat/autofs.init.in +@@ -86,14 +86,18 @@ function start() { + fi + + echo -n $"Starting $prog: " +- $prog $OPTIONS ++ $prog $OPTIONS --pid-file /var/run/autofs.pid + RETVAL=$? + if [ $RETVAL -eq 0 ] ; then + success "$prog startup" + else + failure "$prog startup" + fi +- [ $RETVAL -eq 0 ] && touch /var/lock/subsys/autofs ++ if [ $RETVAL -eq 0 ]; then ++ touch /var/lock/subsys/autofs ++ else ++ RETVAL=1 ++ fi + echo + return $RETVAL + } +@@ -107,7 +111,11 @@ function stop() { + [ $RETVAL = 0 -a -z "`pidof $prog`" ] || sleep 3 + count=`expr $count + 1` + done +- [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/autofs ++ if [ $RETVAL -eq 0 ]; then ++ rm -f /var/lock/subsys/autofs ++ else ++ RETVAL=1 ++ fi + if [ -n "`pidof $prog`" ] ; then + failure "$prog shutdown" + else +@@ -118,7 +126,10 @@ function stop() { + } + + function restart() { +- stop ++ status > /dev/null 2>&1 ++ if [ $? -eq 0 ]; then ++ stop ++ fi + start + } + +@@ -142,6 +153,12 @@ function reload() { + + RETVAL=0 + ++# Only the root user may change the service status ++if [ `id -u` -ne 0 ]; then ++ echo "insufficient privilege to change service status" ++ exit 4 ++fi ++ + case "$1" in + start) + start +@@ -154,7 +171,7 @@ case "$1" in + stop + ;; + status) +- status $prog ++ status -p /var/run/autofs.pid -l autofs $prog + ;; + restart) + restart +@@ -171,9 +188,17 @@ case "$1" in + restart + fi + ;; +- *) ++ usage) + echo $"Usage: $0 {start|forcestart|stop|status|restart|forcerestart|reload|condrestart}" +- exit 1; ++ exit 0 ++ ;; ++ try-restart|force-reload) ++ echo "$1 service action not supported" ++ exit 3 ++ ;; ++ *) ++ echo "unknown, invalid or excess argument(s)" ++ exit 2 + ;; + esac + --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-dont-connect-at-ldap-lookup-module-init.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-dont-connect-at-ldap-lookup-module-init.dpatch @@ -0,0 +1,208 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-dont-connect-at-ldap-lookup-module-init.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - dont connect at ldap lookup module init + +From: Ian Kent + +When using LDAP as a map source and no server is available at +startup autofs will fiail to mount autofs mounts because it +cannot read the mount maps. + +For the case were the master map is available (for example as +a file map) indirect autofs mounts should still be able to +continue but the LDAP lookup module unnecessarily tryes to +connect a an LDAP server and returns a fail if it can't +connect causing the autofs mount to not complete. + +If no server is available to obtain the mount information and +an entry for a requested mount has not been seen before then +mount requests will fail. But, if an entry has previously been +seen autofs will use that while the server is unavailable. + +If an autofs indirect mount uses the browse option and no +server is available at startup the map cannot be read so no +mount point directories will be created (and the mount will +behave as though the browse option was not present). A HUP +signal can be issued to make autofs read the map and create +the map mount point directores. Or the next access to a mount +point that isn't already in the cache but in the map on the +server will trigger a map re-read. +--- + + CHANGELOG | 1 + + daemon/lookup.c | 7 +++++- + modules/lookup_ldap.c | 61 +++++++++++++++++-------------------------------- + 3 files changed, 28 insertions(+), 41 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index a2569aa..f38fc3f 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -18,6 +18,7 @@ + - fix rpc fail on large export list. + - fix memory leak on reload. + - update kernel patches for 2.6.18 and 2.6.19. ++- dont connect at ldap lookup module init. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/daemon/lookup.c b/daemon/lookup.c +index 665ada0..a4b9a80 100644 +--- a/daemon/lookup.c ++++ b/daemon/lookup.c +@@ -292,8 +292,13 @@ static int do_read_map(struct autofs_point *ap, struct map_source *map, time_t a + * For maps that don't support enumeration return success + * and do whatever we must to have autofs function with an + * empty map entry cache. ++ * ++ * For indirect maps that use the browse option, when the ++ * server is unavailable continue as best we can with ++ * whatever we have in the cache, if anything. + */ +- if (status == NSS_STATUS_UNKNOWN) ++ if (status == NSS_STATUS_UNKNOWN || ++ (ap->type == LKP_INDIRECT && status == NSS_STATUS_UNAVAIL)) + return NSS_STATUS_SUCCESS; + + return status; +diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c +index d8bd169..079ded1 100644 +--- a/modules/lookup_ldap.c ++++ b/modules/lookup_ldap.c +@@ -724,8 +724,12 @@ static LDAP *do_reconnect(unsigned logopt, struct lookup_context *ctxt) + uris_mutex_lock(ctxt); + if (ctxt->dclist) + uri = strdup(ctxt->dclist->uri); +- else ++ else if (ctxt->uri) + uri = strdup(ctxt->uri->uri); ++ else { ++ uris_mutex_unlock(ctxt); ++ goto find_server; ++ } + uris_mutex_unlock(ctxt); + + if (!uri) { +@@ -757,6 +761,7 @@ static LDAP *do_reconnect(unsigned logopt, struct lookup_context *ctxt) + autofs_sasl_dispose(ctxt); + #endif + ++find_server: + /* Current server failed connect, try the rest */ + ldap = find_server(logopt, ctxt); + if (!ldap) +@@ -1342,7 +1347,6 @@ int lookup_init(const char *mapfmt, int argc, const char *const *argv, void **co + { + struct lookup_context *ctxt; + char buf[MAX_ERR_BUF]; +- LDAP *ldap = NULL; + int ret; + + *context = NULL; +@@ -1416,23 +1420,6 @@ int lookup_init(const char *mapfmt, int argc, const char *const *argv, void **co + } + #endif + +- if (ctxt->server || !ctxt->uris) { +- ldap = connect_to_server(LOGOPT_NONE, ctxt->server, ctxt); +- if (!ldap) { +- free_context(ctxt); +- return 1; +- } +- } else { +- ldap = find_server(LOGOPT_NONE, ctxt); +- if (!ldap) { +- free_context(ctxt); +- error(LOGOPT_ANY, MODPREFIX +- "failed to find available server"); +- return 1; +- } +- } +- unbind_ldap_connection(LOGOPT_ANY, ldap, ctxt); +- + /* Open the parser, if we can. */ + ctxt->parse = open_parse(mapfmt, MODPREFIX, argc - 1, argv + 1); + if (!ctxt->parse) { +@@ -1463,6 +1450,11 @@ int lookup_read_master(struct master *master, time_t age, void *context) + int scope = LDAP_SCOPE_SUBTREE; + LDAP *ldap; + ++ /* Initialize the LDAP context. */ ++ ldap = do_reconnect(logopt, ctxt); ++ if (!ldap) ++ return NSS_STATUS_UNAVAIL; ++ + class = ctxt->schema->entry_class; + entry = ctxt->schema->entry_attr; + info = ctxt->schema->value_attr; +@@ -1486,13 +1478,6 @@ int lookup_read_master(struct master *master, time_t age, void *context) + return NSS_STATUS_UNAVAIL; + } + +- /* Initialize the LDAP context. */ +- ldap = do_reconnect(logopt, ctxt); +- if (!ldap) { +- free(query); +- return NSS_STATUS_UNAVAIL; +- } +- + /* Look around. */ + debug(logopt, + MODPREFIX "searching for \"%s\" under \"%s\"", query, ctxt->qdn); +@@ -2264,6 +2249,11 @@ static int read_one_map(struct autofs_point *ap, + sp.ap = ap; + sp.age = age; + ++ /* Initialize the LDAP context. */ ++ sp.ldap = do_reconnect(ap->logopt, ctxt); ++ if (!sp.ldap) ++ return NSS_STATUS_UNAVAIL; ++ + class = ctxt->schema->entry_class; + entry = ctxt->schema->entry_attr; + info = ctxt->schema->value_attr; +@@ -2289,13 +2279,6 @@ static int read_one_map(struct autofs_point *ap, + return NSS_STATUS_UNAVAIL; + } + +- /* Initialize the LDAP context. */ +- sp.ldap = do_reconnect(ap->logopt, ctxt); +- if (!sp.ldap) { +- free(sp.query); +- return NSS_STATUS_UNAVAIL; +- } +- + /* Look around. */ + debug(ap->logopt, + MODPREFIX "searching for \"%s\" under \"%s\"", sp.query, ctxt->qdn); +@@ -2401,6 +2384,11 @@ static int lookup_one(struct autofs_point *ap, + return CHE_FAIL; + } + ++ /* Initialize the LDAP context. */ ++ ldap = do_reconnect(ap->logopt, ctxt); ++ if (!ldap) ++ return CHE_UNAVAIL; ++ + class = ctxt->schema->entry_class; + entry = ctxt->schema->entry_attr; + info = ctxt->schema->value_attr; +@@ -2479,13 +2467,6 @@ static int lookup_one(struct autofs_point *ap, + return CHE_FAIL; + } + +- /* Initialize the LDAP context. */ +- ldap = do_reconnect(ap->logopt, ctxt); +- if (!ldap) { +- free(query); +- return CHE_UNAVAIL; +- } +- + debug(ap->logopt, + MODPREFIX "searching for \"%s\" under \"%s\"", query, ctxt->qdn); + --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-fix-cache_init-on-source-re-read.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-fix-cache_init-on-source-re-read.dpatch @@ -0,0 +1,104 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-fix-cache_init-on-source-re-read.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - fix cache_init() on source re-read + +From: Ian Kent + +The master map entry cache is released and re-allocated for each +map source upon master map re-read. This is done without holding +the master map entry write lock and, when there are many master +map entries, could lead to a race because other activities can be +underway concurrently. In this case then we must either use +additional expensive exclusive locking or not do the cache +re-recreate. + +So the question really becomes what do we have to gain by releasing +and re-creating the cache since we spend a fairly significant amount +of effort on pruning stale entries during ongoing operation already. + +This patch moves the allocation of the map entry cache (belonging to +the map source) into the function used to add the map source to the +master map entry and does not release and re-create the cache if the +source already exists for the given master map entry. +--- + + CHANGELOG | 1 + + lib/master.c | 6 ++++++ + lib/master_parse.y | 10 ---------- + modules/mount_autofs.c | 8 -------- + 4 files changed, 7 insertions(+), 18 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index f022893..bfee5de 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -39,6 +39,7 @@ + - fix parse_sun() module init. + - dont check null cache on expire. + - fix null cache race. ++- fix cache_init() on source re-read. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/lib/master.c b/lib/master.c +index 61f671c..62d6fc0 100644 +--- a/lib/master.c ++++ b/lib/master.c +@@ -188,6 +188,12 @@ master_add_map_source(struct master_mapent *entry, + source->argc = argc; + source->argv = tmpargv; + ++ source->mc = cache_init(entry->ap, source); ++ if (!source->mc) { ++ master_free_map_source(source, 0); ++ return NULL; ++ } ++ + master_source_writelock(entry); + + if (!entry->maps) { +diff --git a/lib/master_parse.y b/lib/master_parse.y +index 8b86810..b82129f 100644 +--- a/lib/master_parse.y ++++ b/lib/master_parse.y +@@ -830,16 +830,6 @@ int master_parse_entry(const char *buffer, unsigned int default_timeout, unsigne + return 0; + } + +- if (!source->mc) { +- source->mc = cache_init(entry->ap, source); +- if (!source->mc) { +- error(m_logopt, "failed to init source cache"); +- if (new) +- master_free_mapent(new); +- local_free_vars(); +- return 0; +- } +- } + source->master_line = lineno; + + entry->age = age; +diff --git a/modules/mount_autofs.c b/modules/mount_autofs.c +index 2a5d860..ec75111 100644 +--- a/modules/mount_autofs.c ++++ b/modules/mount_autofs.c +@@ -200,14 +200,6 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, + } + free_map_type_info(info); + +- source->mc = cache_init(entry->ap, source); +- if (!source->mc) { +- error(ap->logopt, MODPREFIX "failed to init source cache"); +- master_free_map_source(source, 0); +- master_free_mapent(entry); +- return 1; +- } +- + mounts_mutex_lock(ap); + + if (handle_mounts_startup_cond_init(&suc)) { --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-refactor-ldap-sasl-bind.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-refactor-ldap-sasl-bind.dpatch @@ -0,0 +1,229 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-refactor-ldap-sasl-bind.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - refactor ldap sasl bind + +From: Ian Kent + +During the sasl authentication (and possible authentication method +selection) we establish a connection and then dispose of it and then +authenticate again. This is a little inefficient but some servers +don't like a second authentication using the same LDAP handle and +authentication fails when it should succeed. We should use the +authentication connection once we get it and not perform another +later. + +Also fixed with this patch. If a server returns a set of +authentication mechanisms that all require authentication, then the +connection pointer is returned to the caller uninitialized (reported +and fix provided by Jeff Moyer). +--- + + CHANGELOG | 1 + + modules/cyrus-sasl.c | 55 ++++++++++++++++++--------------------------- + modules/lookup_ldap.c | 60 ------------------------------------------------- + 3 files changed, 23 insertions(+), 93 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index 674a48b..5adcca5 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -1,6 +1,7 @@ + ??/??/20?? autofs-5.0.6 + ----------------------- + - fix included map read fail handling. ++- refactor ldap sasl bind handling. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/modules/cyrus-sasl.c b/modules/cyrus-sasl.c +index 04001d0..828143e 100644 +--- a/modules/cyrus-sasl.c ++++ b/modules/cyrus-sasl.c +@@ -87,8 +87,8 @@ static sasl_callback_t callbacks[] = { + { SASL_CB_LIST_END, NULL, NULL }, + }; + +-static char *sasl_auth_id, *sasl_auth_secret; +-sasl_secret_t *sasl_secret; ++static char *sasl_auth_id = NULL; ++static char *sasl_auth_secret = NULL; + + static int + sasl_log_func(void *context, int level, const char *message) +@@ -798,7 +798,7 @@ sasl_bind_mech(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt, const c + sasl_conn_t * + sasl_choose_mech(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt) + { +- sasl_conn_t *conn; ++ sasl_conn_t *conn = NULL; + int authenticated; + int i; + char **mechanisms; +@@ -845,22 +845,6 @@ sasl_choose_mech(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt) + return conn; + } + +-int +-autofs_sasl_bind(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt) +-{ +- sasl_conn_t *conn; +- +- if (!ctxt->sasl_mech) +- return -1; +- +- conn = sasl_bind_mech(logopt, ldap, ctxt, ctxt->sasl_mech); +- if (!conn) +- return -1; +- +- ctxt->sasl_conn = conn; +- return 0; +-} +- + /* + * Routine called when unbinding an ldap connection. + */ +@@ -883,35 +867,40 @@ autofs_sasl_unbind(struct lookup_context *ctxt) + * -1 - Failure + */ + int +-autofs_sasl_init(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt) ++autofs_sasl_bind(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt) + { +- sasl_conn_t *conn; ++ sasl_conn_t *conn = NULL; ++ ++ /* If we already have a connection use it */ ++ if (ctxt->sasl_conn) ++ return 0; + + sasl_auth_id = ctxt->user; + sasl_auth_secret = ctxt->secret; + ++ if (ctxt->auth_required & LDAP_AUTH_AUTODETECT) { ++ if (ctxt->sasl_mech) { ++ free(ctxt->sasl_mech); ++ ctxt->sasl_mech = NULL; ++ } ++ } ++ + /* + * If LDAP_AUTH_AUTODETECT is set, it means that there was no + * mechanism specified in the configuration file or auto + * selection has been requested, so try to auto-select an + * auth mechanism. + */ +- if (!(ctxt->auth_required & LDAP_AUTH_AUTODETECT)) ++ if (ctxt->sasl_mech) + conn = sasl_bind_mech(logopt, ldap, ctxt, ctxt->sasl_mech); +- else { +- if (ctxt->sasl_mech) { +- free(ctxt->sasl_mech); +- ctxt->sasl_mech = NULL; +- } ++ else + conn = sasl_choose_mech(logopt, ldap, ctxt); +- } + +- if (conn) { +- sasl_dispose(&conn); +- return 0; +- } ++ if (!conn) ++ return -1; + +- return -1; ++ ctxt->sasl_conn = conn; ++ return 0; + } + + /* +diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c +index 2ecf5fe..f1fb9ce 100644 +--- a/modules/lookup_ldap.c ++++ b/modules/lookup_ldap.c +@@ -59,7 +59,6 @@ struct ldap_search_params { + time_t age; + }; + +-static LDAP *auth_init(unsigned logopt, const char *, struct lookup_context *); + static int decode_percent_hack(const char *, char **); + + #ifndef HAVE_LDAP_CREATE_PAGE_CONTROL +@@ -600,33 +599,6 @@ static LDAP *connect_to_server(unsigned logopt, const char *uri, struct lookup_c + { + LDAP *ldap; + +-#ifdef WITH_SASL +- /* +- * Determine which authentication mechanism to use if we require +- * authentication. +- */ +- if (ctxt->auth_required & (LDAP_AUTH_REQUIRED|LDAP_AUTH_AUTODETECT)) { +- ldap = auth_init(logopt, uri, ctxt); +- if (!ldap && ctxt->auth_required & LDAP_AUTH_AUTODETECT) +- info(logopt, +- "no authentication mechanisms auto detected."); +- if (!ldap) { +- error(logopt, MODPREFIX +- "cannot initialize authentication setup"); +- return NULL; +- } +- +- if (!do_bind(logopt, ldap, uri, ctxt)) { +- unbind_ldap_connection(logopt, ldap, ctxt); +- autofs_sasl_dispose(ctxt); +- error(logopt, MODPREFIX "cannot bind to server"); +- return NULL; +- } +- +- return ldap; +- } +-#endif +- + ldap = do_connect(logopt, uri, ctxt); + if (!ldap) { + warn(logopt, +@@ -1074,38 +1046,6 @@ out: + + return ret; + } +- +-/* +- * Reads in the xml configuration file and parses out the relevant +- * information. If there is no configuration file, then we fall back to +- * trying all supported authentication mechanisms until one works. +- * +- * Returns ldap connection on success, with authtype, user and secret +- * filled in as appropriate. Returns NULL on failre. +- */ +-static LDAP *auth_init(unsigned logopt, const char *uri, struct lookup_context *ctxt) +-{ +- int ret; +- LDAP *ldap; +- +- ldap = init_ldap_connection(logopt, uri, ctxt); +- if (!ldap) +- return NULL; +- +- /* +- * Initialize the sasl library. It is okay if user and secret +- * are NULL, here. +- * +- * The autofs_sasl_init routine will figure out which mechamism +- * to use. If kerberos is used, it will also take care to initialize +- * the credential cache and the client and service principals. +- */ +- ret = autofs_sasl_init(logopt, ldap, ctxt); +- if (ret) +- return NULL; +- +- return ldap; +-} + #endif + + /* --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-add-dump-maps-option.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-add-dump-maps-option.dpatch @@ -0,0 +1,374 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-add-dump-maps-option.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - add dump maps option + +From: Ondrej Valousek + +Modified by Ian Kent +--- + + CHANGELOG | 1 + daemon/automount.c | 52 ++++++++++++++++----- + include/log.h | 1 + include/master.h | 1 + lib/log.c | 14 ++++-- + lib/master.c | 126 ++++++++++++++++++++++++++++++++++++++++++++++++++++ + man/automount.8 | 3 + + 7 files changed, 180 insertions(+), 18 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index 1975369..11054da 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -54,6 +54,7 @@ + - fix direct map not updating on reread. + - add external bind method. + - fix add simple bind auth. ++- add option to dump configured automount maps. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/daemon/automount.c b/daemon/automount.c +index 9939a25..1b1007d 100644 +--- a/daemon/automount.c ++++ b/daemon/automount.c +@@ -1664,6 +1664,7 @@ static void usage(void) + " -f --foreground do not fork into background\n" + " -r --random-multimount-selection\n" + " use ramdom replicated server selection\n" ++ " -m --dumpmaps dump automounter maps and exit\n" + " -n --negative-timeout n\n" + " set the timeout for failed key lookups.\n" + " -O --global-options\n" +@@ -1813,7 +1814,7 @@ int main(int argc, char *argv[]) + int res, opt, status; + int logpri = -1; + unsigned ghost, logging, daemon_check; +- unsigned foreground, have_global_options; ++ unsigned dumpmaps, foreground, have_global_options; + time_t timeout; + time_t age = time(NULL); + struct rlimit rlim; +@@ -1827,6 +1828,7 @@ int main(int argc, char *argv[]) + {"foreground", 0, 0, 'f'}, + {"random-multimount-selection", 0, 0, 'r'}, + {"negative-timeout", 1, 0, 'n'}, ++ {"dumpmaps", 0, 0, 'm'}, + {"global-options", 1, 0, 'O'}, + {"version", 0, 0, 'V'}, + {"set-log-priority", 1, 0, 'l'}, +@@ -1857,10 +1859,11 @@ int main(int argc, char *argv[]) + global_options = NULL; + have_global_options = 0; + foreground = 0; ++ dumpmaps = 0; + daemon_check = 1; + + opterr = 0; +- while ((opt = getopt_long(argc, argv, "+hp:t:vdD:fVrO:l:n:CF", long_options, NULL)) != EOF) { ++ while ((opt = getopt_long(argc, argv, "+hp:t:vmdD:fVrO:l:n:CF", long_options, NULL)) != EOF) { + switch (opt) { + case 'h': + usage(); +@@ -1902,6 +1905,10 @@ int main(int argc, char *argv[]) + global_negative_timeout = getnumopt(optarg, opt); + break; + ++ case 'm': ++ dumpmaps = 1; ++ break; ++ + case 'O': + if (!have_global_options) { + global_options = strdup(optarg); +@@ -1988,7 +1995,8 @@ int main(int argc, char *argv[]) + } + #endif + +- if (!query_kproto_ver() || get_kver_major() < 5) { ++ /* Don't need the kernel module just to look at the configured maps */ ++ if (!dumpmaps && (!query_kproto_ver() || get_kver_major() < 5)) { + fprintf(stderr, + "%s: test mount forbidden or " + "incorrect kernel protocol version, " +@@ -2001,34 +2009,50 @@ int main(int argc, char *argv[]) + rlim.rlim_max = MAX_OPEN_FILES; + res = setrlimit(RLIMIT_NOFILE, &rlim); + if (res) +- warn(logging, +- "can't increase open file limit - continuing"); ++ printf("%s: can't increase open file limit - continuing", ++ argv[0]); + + #if ENABLE_CORES + rlim.rlim_cur = RLIM_INFINITY; + rlim.rlim_max = RLIM_INFINITY; + res = setrlimit(RLIMIT_CORE, &rlim); + if (res) +- warn(logging, +- "can't increase core file limit - continuing"); ++ printf("%s: can't increase core file limit - continuing", ++ argv[0]); + #endif + +- become_daemon(foreground, daemon_check); +- + if (argc == 0) + master_list = master_new(NULL, timeout, ghost); + else + master_list = master_new(argv[0], timeout, ghost); + + if (!master_list) { +- logerr("%s: can't create master map %s", +- program, argv[0]); +- res = write(start_pipefd[1], pst_stat, sizeof(*pst_stat)); +- close(start_pipefd[1]); +- release_flag_file(); ++ printf("%s: can't create master map %s", program, argv[0]); + exit(1); + } + ++ if (dumpmaps) { ++ struct mapent_cache *nc; ++ ++ open_log(); ++ ++ master_init_scan(); ++ ++ nc = cache_init_null_cache(master_list); ++ if (!nc) { ++ printf("%s: failed to init null map cache for %s", ++ master_list->name, argv[0]); ++ exit(1); ++ } ++ master_list->nc = nc; ++ ++ lookup_nss_read_master(master_list, 0); ++ master_show_mounts(master_list); ++ exit(0); ++ } ++ ++ become_daemon(foreground, daemon_check); ++ + if (pthread_attr_init(&th_attr)) { + logerr("%s: failed to init thread attribute struct!", + program); +diff --git a/include/log.h b/include/log.h +index 6a4a942..7a394cb 100644 +--- a/include/log.h ++++ b/include/log.h +@@ -35,6 +35,7 @@ extern void set_log_verbose_ap(struct autofs_point *ap); + extern void set_log_debug_ap(struct autofs_point *ap); + extern void set_mnt_logging(unsigned global_logopt); + ++extern void open_log(void); + extern void log_to_syslog(void); + extern void log_to_stderr(void); + +diff --git a/include/master.h b/include/master.h +index 0d6aa82..bef59d3 100644 +--- a/include/master.h ++++ b/include/master.h +@@ -110,6 +110,7 @@ int master_submount_list_empty(struct autofs_point *ap); + int master_notify_submount(struct autofs_point *, const char *path, enum states); + void master_notify_state_change(struct master *, int); + int master_mount_mounts(struct master *, time_t, int); ++int master_show_mounts(struct master *); + extern inline unsigned int master_get_logopt(void); + int master_list_empty(struct master *); + int master_done(struct master *); +diff --git a/lib/log.c b/lib/log.c +index 46220fd..832add7 100644 +--- a/lib/log.c ++++ b/lib/log.c +@@ -193,17 +193,23 @@ void logmsg(const char *msg, ...) + return; + } + +-void log_to_syslog(void) ++void open_log(void) + { +- char buf[MAX_ERR_BUF]; +- int nullfd; +- + if (!syslog_open) { + syslog_open = 1; + openlog("automount", LOG_PID, LOG_DAEMON); + } + + logging_to_syslog = 1; ++ return; ++} ++ ++void log_to_syslog(void) ++{ ++ char buf[MAX_ERR_BUF]; ++ int nullfd; ++ ++ open_log(); + + /* Redirect all our file descriptors to /dev/null */ + nullfd = open("/dev/null", O_RDWR); +diff --git a/lib/master.c b/lib/master.c +index ebeccce..ad3aa77 100644 +--- a/lib/master.c ++++ b/lib/master.c +@@ -30,6 +30,7 @@ + /* The root of the map entry tree */ + struct master *master_list = NULL; + ++extern const char *global_options; + extern long global_negative_timeout; + + /* Attribute to create a joinable thread */ +@@ -1189,6 +1190,131 @@ int master_mount_mounts(struct master *master, time_t age, int readall) + return 1; + } + ++/* The nss source instances end up in reverse order. */ ++static void list_source_instances(struct map_source *source, struct map_source *instance) ++{ ++ if (!source || !instance) { ++ printf("none"); ++ return; ++ } ++ ++ if (instance->next) ++ list_source_instances(source, instance->next); ++ ++ /* ++ * For convienience we map nss instance type "files" to "file". ++ * Check for that and report corrected instance type. ++ */ ++ if (strcmp(instance->type, "file")) ++ printf("%s ", instance->type); ++ else { ++ if (source->argv && *(source->argv[0]) != '/') ++ printf("files "); ++ else ++ printf("%s ", instance->type); ++ } ++ ++ return; ++} ++ ++int master_show_mounts(struct master *master) ++{ ++ struct list_head *p, *head; ++ ++ printf("\nautofs dump map information\n" ++ "===========================\n\n"); ++ ++ printf("global options: "); ++ if (!global_options) ++ printf("none configured\n"); ++ else { ++ printf("%s\n", global_options); ++ unsigned int append_options = defaults_get_append_options(); ++ const char *append = append_options ? "will" : "will not"; ++ printf("global options %s be appended to map entries\n", append); ++ } ++ ++ if (list_empty(&master->mounts)) { ++ printf("no master map entries found\n\n"); ++ return 1; ++ } ++ ++ head = &master->mounts; ++ p = head->next; ++ while (p != head) { ++ struct map_source *source; ++ struct master_mapent *this; ++ struct autofs_point *ap; ++ time_t now = time(NULL); ++ int i; ++ ++ this = list_entry(p, struct master_mapent, list); ++ p = p->next; ++ ++ ap = this->ap; ++ ++ printf("\nMount point: %s\n", ap->path); ++ printf("\nsource(s):\n"); ++ ++ /* Read the map content into the cache */ ++ if (lookup_nss_read_map(ap, NULL, now)) ++ lookup_prune_cache(ap, now); ++ else { ++ printf(" failed to read map\n\n"); ++ continue; ++ } ++ ++ if (!this->maps) { ++ printf(" no map sources found\n\n"); ++ continue; ++ } ++ ++ source = this->maps; ++ while (source) { ++ struct mapent *me; ++ ++ if (source->type) ++ printf("\n type: %s\n", source->type); ++ else { ++ printf("\n instance type(s): "); ++ list_source_instances(source, source->instance); ++ printf("\n"); ++ } ++ ++ if (source->argc >= 1) { ++ i = 0; ++ if (source->argv[0] && *source->argv[0] != '-') { ++ printf(" map: %s\n", source->argv[0]); ++ i = 1; ++ } ++ if (source->argc > 1) { ++ printf(" arguments: "); ++ for (; i < source->argc; i++) ++ printf("%s ", source->argv[i]); ++ printf("\n"); ++ } ++ } ++ ++ printf("\n"); ++ ++ me = cache_lookup_first(source->mc); ++ if (!me) ++ printf(" no keys found in map\n"); ++ else { ++ do { ++ printf(" %s | %s\n", me->key, me->mapent); ++ } while ((me = cache_lookup_next(source->mc, me))); ++ } ++ ++ source = source->next; ++ } ++ ++ printf("\n"); ++ } ++ ++ return 1; ++} ++ + int master_list_empty(struct master *master) + { + int res = 0; +diff --git a/man/automount.8 b/man/automount.8 +index 18f74bf..d57ecba 100644 +--- a/man/automount.8 ++++ b/man/automount.8 +@@ -57,6 +57,9 @@ Run the daemon in the forground and log to stderr instead of syslog." + Enables the use of ramdom selection when choosing a host from a + list of replicated servers. + .TP ++.I "\-m, \-\-dumpmaps" ++Dump configured automounter maps, then exit. ++.TP + .I "\-O, \-\-global-options" + Allows the specification of global mount options used for all master + map entries. These options will either replace or be appened to options --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-make-nfs4-default-for-redhat-replicated-selection.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-make-nfs4-default-for-redhat-replicated-selection.dpatch @@ -0,0 +1,31 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-make-nfs4-default-for-redhat-replicated-selection.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - make nfs4 default for RedHat replicated selection configuration + +From: Ian Kent + +We know for sure that RHEL-6 and later is set to mount NFSv4 as default and +fall back to earlier NFS versions if it can't mount as NFSv4. So set our +default for replicated mount probing to start at NFSv4 instead of v3. +--- + + redhat/autofs.sysconfig.in | 1 + + 1 files changed, 1 insertions(+), 0 deletions(-) + + +diff --git a/redhat/autofs.sysconfig.in b/redhat/autofs.sysconfig.in +index c72cd2b..a46335d 100644 +--- a/redhat/autofs.sysconfig.in ++++ b/redhat/autofs.sysconfig.in +@@ -40,6 +40,7 @@ BROWSE_MODE="no" + # used for single host map entries. + # + #MOUNT_NFS_DEFAULT_PROTOCOL=3 ++MOUNT_NFS_DEFAULT_PROTOCOL=4 + # + # APPEND_OPTIONS - append to global options instead of replace. + # --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.5-remove-ERR_remove_state-openssl-call.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.5-remove-ERR_remove_state-openssl-call.dpatch @@ -0,0 +1,54 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01UPSTREAM_autofs-5.0.5-remove-ERR_remove_state-openssl-call.dpatch +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.5 - remove ERR_remove_state() openssl call + +From: Ian Kent + +autofs should never have had to use ERR_remove_state() so remove that call. +--- + + CHANGELOG | 1 + + modules/lookup_ldap.c | 12 +----------- + 2 files changed, 2 insertions(+), 11 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index e9deabf..ce9c385 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -47,6 +47,7 @@ + - remove extra read master map call. + - fix error handing in do_mount_indirect(). + - expire thread use pending mutex. ++- remove ERR_remove_state() openssl call. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c +index e9d1fa2..3d47048 100644 +--- a/modules/lookup_ldap.c ++++ b/modules/lookup_ldap.c +@@ -169,18 +169,8 @@ int unbind_ldap_connection(unsigned logopt, LDAP *ldap, struct lookup_context *c + int rv; + + #ifdef WITH_SASL +- /* +- * The OpenSSL library can't handle having its message and error +- * string database loaded multiple times and segfaults if the +- * TLS environment is not reset at the right times. As there +- * is no ldap_stop_tls call in the openldap library we have +- * to do the job ourselves, here and in lookup_done when the +- * module is closed. +- */ +- if (ctxt->use_tls == LDAP_TLS_RELEASE) { +- ERR_remove_state(0); ++ if (ctxt->use_tls == LDAP_TLS_RELEASE) + ctxt->use_tls = LDAP_TLS_INIT; +- } + autofs_sasl_unbind(ctxt); + #endif + --- autofs5-5.0.5.orig/debian/patches/01UPSTREAM_autofs-5.0.4-add-mount-wait-parameter.dpatch +++ autofs5-5.0.5/debian/patches/01UPSTREAM_autofs-5.0.4-add-mount-wait-parameter.dpatch @@ -0,0 +1,177 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## +## DP: Upstream patch on top of 5.0.5 + +@DPATCH@ +autofs-5.0.4 - add mount wait parameter + +From: Ian Kent + +Often delays when trying to mount from a server that is not reponding +for some reason are undesirable. To try and prevent these delays we +provide a configuration setting to limit the time that we wait for +our spawned mount(8) process to complete before sending it a SIGTERM +signal. This patch adds a configuration parameter to allow us to +request we limit the time we wait for mount(8) to complete before +send it a TERM signal. +--- + + CHANGELOG | 1 + + daemon/spawn.c | 3 ++- + include/defaults.h | 2 ++ + lib/defaults.c | 13 +++++++++++++ + man/auto.master.5.in | 7 +++++++ + redhat/autofs.sysconfig.in | 9 +++++++++ + samples/autofs.conf.default.in | 9 +++++++++ + 7 files changed, 43 insertions(+), 1 deletions(-) + + +diff --git a/CHANGELOG b/CHANGELOG +index 5adcca5..fadb229 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -2,6 +2,7 @@ + ----------------------- + - fix included map read fail handling. + - refactor ldap sasl bind handling. ++- add mount wait timeout parameter. + + 03/09/2009 autofs-5.0.5 + ----------------------- +diff --git a/daemon/spawn.c b/daemon/spawn.c +index e02d926..db356d4 100644 +--- a/daemon/spawn.c ++++ b/daemon/spawn.c +@@ -305,6 +305,7 @@ int spawn_mount(unsigned logopt, ...) + unsigned int options; + unsigned int retries = MTAB_LOCK_RETRIES; + int update_mtab = 1, ret, printed = 0; ++ unsigned int wait = defaults_get_mount_wait(); + char buf[PATH_MAX]; + + /* If we use mount locking we can't validate the location */ +@@ -355,7 +356,7 @@ int spawn_mount(unsigned logopt, ...) + va_end(arg); + + while (retries--) { +- ret = do_spawn(logopt, -1, options, prog, (const char **) argv); ++ ret = do_spawn(logopt, wait, options, prog, (const char **) argv); + if (ret & MTAB_NOTUPDATED) { + struct timespec tm = {3, 0}; + +diff --git a/include/defaults.h b/include/defaults.h +index 9bf16e5..cda2174 100644 +--- a/include/defaults.h ++++ b/include/defaults.h +@@ -24,6 +24,7 @@ + + #define DEFAULT_TIMEOUT 600 + #define DEFAULT_NEGATIVE_TIMEOUT 60 ++#define DEFAULT_MOUNT_WAIT -1 + #define DEFAULT_UMOUNT_WAIT 12 + #define DEFAULT_BROWSE_MODE 1 + #define DEFAULT_LOGGING 0 +@@ -64,6 +65,7 @@ struct ldap_searchdn *defaults_get_searchdns(void); + void defaults_free_searchdns(struct ldap_searchdn *); + unsigned int defaults_get_mount_nfs_default_proto(void); + unsigned int defaults_get_append_options(void); ++unsigned int defaults_get_mount_wait(void); + unsigned int defaults_get_umount_wait(void); + const char *defaults_get_auth_conf_file(void); + unsigned int defaults_get_map_hash_table_size(void); +diff --git a/lib/defaults.c b/lib/defaults.c +index 17164bd..2204b18 100644 +--- a/lib/defaults.c ++++ b/lib/defaults.c +@@ -47,6 +47,7 @@ + + #define ENV_MOUNT_NFS_DEFAULT_PROTOCOL "MOUNT_NFS_DEFAULT_PROTOCOL" + #define ENV_APPEND_OPTIONS "APPEND_OPTIONS" ++#define ENV_MOUNT_WAIT "MOUNT_WAIT" + #define ENV_UMOUNT_WAIT "UMOUNT_WAIT" + #define ENV_AUTH_CONF_FILE "AUTH_CONF_FILE" + +@@ -325,6 +326,7 @@ unsigned int defaults_read_config(unsigned int to_syslog) + check_set_config_value(key, ENV_NAME_ENTRY_ATTR, value, to_syslog) || + check_set_config_value(key, ENV_NAME_VALUE_ATTR, value, to_syslog) || + check_set_config_value(key, ENV_APPEND_OPTIONS, value, to_syslog) || ++ check_set_config_value(key, ENV_MOUNT_WAIT, value, to_syslog) || + check_set_config_value(key, ENV_UMOUNT_WAIT, value, to_syslog) || + check_set_config_value(key, ENV_AUTH_CONF_FILE, value, to_syslog) || + check_set_config_value(key, ENV_MAP_HASH_TABLE_SIZE, value, to_syslog) || +@@ -667,6 +669,17 @@ unsigned int defaults_get_append_options(void) + return res; + } + ++unsigned int defaults_get_mount_wait(void) ++{ ++ long wait; ++ ++ wait = get_env_number(ENV_MOUNT_WAIT); ++ if (wait < 0) ++ wait = DEFAULT_MOUNT_WAIT; ++ ++ return (unsigned int) wait; ++} ++ + unsigned int defaults_get_umount_wait(void) + { + long wait; +diff --git a/man/auto.master.5.in b/man/auto.master.5.in +index 71c4402..792035f 100644 +--- a/man/auto.master.5.in ++++ b/man/auto.master.5.in +@@ -174,6 +174,13 @@ Set the default timeout for caching failed key lookups (program default + 60). If the equivalent command line option is given it will override this + setting. + .TP ++.B MOUNT_WAIT ++Set the default time to wait for a response from a spawned mount(8) ++before sending it a SIGTERM. Note that we still need to wait for the ++RPC layer to timeout before the sub-process exits so this isn't ideal ++but it is the best we can do. The default is to wait until mount(8) ++returns without intervention. ++.TP + .B UMOUNT_WAIT + Set the default time to wait for a response from a spawned umount(8) + before sending it a SIGTERM. Note that we still need to wait for the +diff --git a/redhat/autofs.sysconfig.in b/redhat/autofs.sysconfig.in +index 37448ea..c72cd2b 100644 +--- a/redhat/autofs.sysconfig.in ++++ b/redhat/autofs.sysconfig.in +@@ -14,6 +14,15 @@ TIMEOUT=300 + # + #NEGATIVE_TIMEOUT=60 + # ++# MOUNT_WAIT - time to wait for a response from umount(8). ++# Setting this timeout can cause problems when ++# mount would otherwise wait for a server that ++# is temporarily unavailable, such as when it's ++# restarting. The defailt of waiting for mount(8) ++# usually results in a wait of around 3 minutes. ++# ++#MOUNT_WAIT=-1 ++# + # UMOUNT_WAIT - time to wait for a response from umount(8). + # + #UMOUNT_WAIT=12 +diff --git a/samples/autofs.conf.default.in b/samples/autofs.conf.default.in +index 7dee5fd..b87c4d0 100644 +--- a/samples/autofs.conf.default.in ++++ b/samples/autofs.conf.default.in +@@ -14,6 +14,15 @@ TIMEOUT=300 + # + #NEGATIVE_TIMEOUT=60 + # ++# MOUNT_WAIT - time to wait for a response from umount(8). ++# Setting this timeout can cause problems when ++# mount would otherwise wait for a server that ++# is temporarily unavailable, such as when it's ++# restarting. The defailt of waiting for mount(8) ++# usually results in a wait of around 3 minutes. ++# ++#MOUNT_WAIT=-1 ++# + # UMOUNT_WAIT - time to wait for a response from umount(8). + # + #UMOUNT_WAIT=12