1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27/*
28 * Portions Copyright 2007-2013 Apple Inc.
29 */
30
31#pragma ident	"@(#)auto_vnops.c	1.70	05/12/19 SMI"
32
33#include <mach/mach_types.h>
34#include <mach/machine/boolean.h>
35#include <mach/host_priv.h>
36#include <mach/host_special_ports.h>
37#include <mach/vm_map.h>
38#include <vm/vm_map.h>
39#include <vm/vm_kern.h>
40
41#include <sys/param.h>
42#include <sys/systm.h>
43#include <sys/kernel.h>
44#include <sys/file.h>
45#include <sys/stat.h>
46#include <sys/buf.h>
47#include <sys/proc.h>
48#include <sys/conf.h>
49#include <sys/mount.h>
50#include <sys/vnode.h>
51#include <sys/malloc.h>
52#include <sys/dirent.h>
53#include <sys/namei.h>
54#include <sys/kauth.h>
55#include <sys/attr.h>
56#include <sys/vnode_if.h>
57#include <sys/vfs_context.h>
58#include <sys/vm.h>
59#include <sys/errno.h>
60#include <vfs/vfs_support.h>
61#include <sys/uio.h>
62
63#include <kern/assert.h>
64#include <kern/host.h>
65
66#include <IOKit/IOLib.h>
67
68#include "autofs.h"
69#include "triggers.h"
70#include "triggers_priv.h"
71#include "autofs_kern.h"
72#include "autofs_protUser.h"
73
74/*
75 *  Vnode ops for autofs
76 */
77static int auto_getattr(struct vnop_getattr_args *);
78static int auto_setattr(struct vnop_setattr_args *);
79static int auto_lookup(struct vnop_lookup_args *);
80static int auto_readdir(struct vnop_readdir_args *);
81static int auto_readlink(struct vnop_readlink_args *);
82static int auto_pathconf(struct vnop_pathconf_args *);
83static int auto_fsctl(struct vnop_ioctl_args *);
84static int auto_getxattr(struct vnop_getxattr_args *);
85static int auto_listxattr(struct vnop_listxattr_args *);
86static int auto_inactive(struct vnop_inactive_args *);
87static int auto_reclaim(struct vnop_reclaim_args *);
88
89int (**autofs_vnodeop_p)(void *);
90
91#define VOPFUNC int (*)(void *)
92
93struct vnodeopv_entry_desc autofs_vnodeop_entries[] = {
94	{&vnop_default_desc, (VOPFUNC)vn_default_error},
95	{&vnop_lookup_desc, (VOPFUNC)auto_lookup},		/* lookup */
96	{&vnop_open_desc, (VOPFUNC)nop_open},			/* open	- NOP */
97	{&vnop_close_desc, (VOPFUNC)nop_close},			/* close - NOP */
98	{&vnop_getattr_desc, (VOPFUNC)auto_getattr},		/* getattr */
99	{&vnop_setattr_desc, (VOPFUNC)auto_setattr},		/* setattr */
100	{&vnop_fsync_desc, (VOPFUNC)nop_fsync},			/* fsync - NOP */
101	{&vnop_readdir_desc, (VOPFUNC)auto_readdir},		/* readdir */
102	{&vnop_readlink_desc, (VOPFUNC)auto_readlink},		/* readlink */
103	{&vnop_pathconf_desc, (VOPFUNC)auto_pathconf},		/* pathconf */
104	{&vnop_ioctl_desc, (VOPFUNC)auto_fsctl},		/* ioctl (really fsctl) */
105	{&vnop_getxattr_desc, (VOPFUNC)auto_getxattr},		/* getxattr */
106	{&vnop_listxattr_desc, (VOPFUNC)auto_listxattr},	/* listxattr */
107	{&vnop_inactive_desc, (VOPFUNC)auto_inactive},		/* inactive */
108	{&vnop_reclaim_desc, (VOPFUNC)auto_reclaim},		/* reclaim */
109	{NULL, NULL}
110};
111
112struct vnodeopv_desc autofsfs_vnodeop_opv_desc =
113	{ &autofs_vnodeop_p, autofs_vnodeop_entries };
114
115static int autofs_nobrowse = 0;
116
117/*
118 * Returns 1 if a readdir on the vnode will only return names for the
119 * vnodes we have, 0 otherwise.
120 *
121 * XXX - come up with a better name.
122 */
123int
124auto_nobrowse(vnode_t vp)
125{
126	fnnode_t *fnp = vntofn(vp);
127	fninfo_t *fnip = vfstofni(vnode_mount(vp));
128
129	if (fnp == vntofn(fnip->fi_rootvp)) {
130		/*
131		 * This is the root directory of the mount, so a
132		 * readdir on the vnode will only return names for
133		 * the vnodes we already have if we've globally
134		 * disabled browsing or the map was mounted with
135		 * "nobrowse".
136		 */
137		return (autofs_nobrowse ||
138		    (fnip->fi_mntflags & AUTOFS_MNT_NOBROWSE));
139	} else {
140		/*
141		 * This is a subdirectory of the mount; a readdir
142		 * on the vnode will always make an upcall, as
143		 * we need to enumerate all the subdirectories
144		 * generated by the submounts.
145		 */
146		return (0);
147	}
148}
149
150static int
151auto_getattr(ap)
152	struct vnop_getattr_args /* {
153		struct vnodeop_desc *a_desc;
154		vnode_t a_vp;
155		struct vnode_attr *a_vap;
156		vfs_context_t a_context;
157	} */ *ap;
158{
159	vnode_t vp = ap->a_vp;
160	struct vnode_attr *vap = ap->a_vap;
161
162	AUTOFS_DPRINT((4, "auto_getattr vp %p\n", (void *)vp));
163
164	/* XXX - lock the fnnode? */
165
166	auto_get_attributes(vp, vap);
167
168	return (0);
169}
170
171void
172auto_get_attributes(vnode_t vp, struct vnode_attr *vap)
173{
174	fnnode_t *fnp = vntofn(vp);
175
176	VATTR_RETURN(vap, va_rdev, 0);
177	switch (vnode_vtype(vp)) {
178	case VDIR:
179		/*
180		 * fn_linkcnt doesn't count the "." link, as we're using it
181		 * as a count of references to the fnnode from other vnnodes
182		 * (so that if it goes to 0, we know no other fnnode refers
183		 * to it).
184		 */
185		VATTR_RETURN(vap, va_nlink, fnp->fn_linkcnt + 1);
186
187		/*
188		 * The "size" of a directory is the number of entries
189		 * in its list of directory entries, plus 1.
190		 * (Solaris added 1 for some reason.)
191		 */
192		VATTR_RETURN(vap, va_data_size, fnp->fn_direntcnt + 1);
193		break;
194	case VLNK:
195		VATTR_RETURN(vap, va_nlink, fnp->fn_linkcnt);
196		VATTR_RETURN(vap, va_data_size, fnp->fn_symlinklen);
197		break;
198	default:
199		VATTR_RETURN(vap, va_nlink, fnp->fn_linkcnt);
200		VATTR_RETURN(vap, va_data_size, 0);
201		break;
202	}
203	VATTR_RETURN(vap, va_total_size, roundup(vap->va_data_size, AUTOFS_BLOCKSIZE));
204	VATTR_RETURN(vap, va_iosize, AUTOFS_BLOCKSIZE);
205
206	VATTR_RETURN(vap, va_uid, fnp->fn_uid);
207	VATTR_RETURN(vap, va_gid, 0);
208	VATTR_RETURN(vap, va_mode, fnp->fn_mode);
209	/*
210	 * Does our caller want the BSD flags?
211	 */
212	if (VATTR_IS_ACTIVE(vap, va_flags)) {
213		/*
214		 * If this is the root of a mount, and if the "hide this
215		 * from the Finder" mount option is set on that mount,
216		 * return the hidden bit, so the Finder won't show it.
217		 */
218		if (vnode_isvroot(vp)) {
219			fninfo_t *fnip = vfstofni(vnode_mount(vp));
220
221			if (fnip->fi_mntflags & AUTOFS_MNT_HIDEFROMFINDER)
222				VATTR_RETURN(vap, va_flags, UF_HIDDEN);
223			else
224				VATTR_RETURN(vap, va_flags, 0);
225		} else
226			VATTR_RETURN(vap, va_flags, 0);
227	}
228	vap->va_access_time.tv_sec = fnp->fn_atime.tv_sec;
229	vap->va_access_time.tv_nsec = fnp->fn_atime.tv_usec * 1000;
230	VATTR_SET_SUPPORTED(vap, va_access_time);
231	vap->va_modify_time.tv_sec = fnp->fn_mtime.tv_sec;
232	vap->va_modify_time.tv_nsec = fnp->fn_mtime.tv_usec * 1000;
233	VATTR_SET_SUPPORTED(vap, va_modify_time);
234	vap->va_change_time.tv_sec = fnp->fn_ctime.tv_sec;
235	vap->va_change_time.tv_nsec = fnp->fn_ctime.tv_usec * 1000;
236	VATTR_SET_SUPPORTED(vap, va_change_time);
237	VATTR_RETURN(vap, va_fileid, fnp->fn_nodeid);
238	VATTR_RETURN(vap, va_fsid, vfs_statfs(vnode_mount(vp))->f_fsid.val[0]);
239	VATTR_RETURN(vap, va_filerev, 0);
240	VATTR_RETURN(vap, va_type, vnode_vtype(vp));
241}
242
243static int
244auto_setattr(ap)
245	struct vnop_setattr_args /* {
246		struct vnodeop_desc *a_desc;
247		vnode_t a_vp;
248		struct vnode_attr *a_vap;
249		vfs_context_t a_context;
250	} */ *ap;
251{
252	vnode_t vp = ap->a_vp;
253	struct vnode_attr *vap = ap->a_vap;
254	fnnode_t *fnp = vntofn(vp);
255
256	AUTOFS_DPRINT((4, "auto_setattr vp %p\n", (void *)vp));
257
258	/*
259	 * Only root can change the attributes.
260	 */
261	if (!kauth_cred_issuser(vfs_context_ucred(ap->a_context)))
262		return (EPERM);
263
264	/*
265	 * All you can set are the UID and the permissions; that's to
266	 * allow the automounter to give the mount point to the user
267	 * on whose behalf we're doing the mount, and make it writable
268	 * by them, so we can do AFP and SMB mounts as that user (so
269	 * the connection can be authenticated as them).
270	 *
271	 * We pretend to allow the GID to be set, but we don't actually
272	 * set it.
273	 */
274	VATTR_SET_SUPPORTED(vap, va_uid);
275	if (VATTR_IS_ACTIVE(vap, va_uid))
276		fnp->fn_uid = vap->va_uid;
277	VATTR_SET_SUPPORTED(vap, va_gid);
278	VATTR_SET_SUPPORTED(vap, va_mode);
279	if (VATTR_IS_ACTIVE(vap, va_mode))
280		fnp->fn_mode = vap->va_mode & ALLPERMS;
281	return (0);
282}
283
284static int
285auto_lookup(ap)
286	struct vnop_lookup_args /* {
287		struct vnodeop_desc *a_desc;
288		vnode_t a_dvp;
289		vnode_t *a_vpp;
290		struct componentname *a_cnp;
291		vfs_context_t a_context;
292	} */ *ap;
293{
294	vnode_t dvp = ap->a_dvp;
295	vnode_t *vpp = ap->a_vpp;
296	struct componentname *cnp = ap->a_cnp;
297	u_long nameiop = cnp->cn_nameiop;
298	u_long flags = cnp->cn_flags;
299	int namelen = cnp->cn_namelen;
300	vfs_context_t context = ap->a_context;
301	int pid = vfs_context_pid(context);
302	int error = 0;
303	fninfo_t *dfnip;
304	fnnode_t *dfnp = NULL;
305	fnnode_t *fnp = NULL;
306	vnode_t vp;
307	uint32_t vid;
308	char *searchnm;
309	int searchnmlen;
310	int do_notify = 0;
311	struct vnode_attr vattr;
312	int node_type;
313
314	dfnip = vfstofni(vnode_mount(dvp));
315	AUTOFS_DPRINT((3, "auto_lookup: dvp=%p (%s) name=%.*s\n",
316	    (void *)dvp, dfnip->fi_map, namelen, cnp->cn_nameptr));
317
318	/* This must be a directory. */
319	if (!vnode_isdir(dvp))
320		return (ENOTDIR);
321
322	/*
323	 * XXX - is this necessary?
324	 */
325	if (namelen == 0) {
326		error = vnode_get(dvp);
327		if (error)
328			return (error);
329		*vpp = dvp;
330		return (0);
331	}
332
333	/* first check for "." and ".." */
334	if (cnp->cn_nameptr[0] == '.') {
335		if (namelen == 1) {
336			/*
337			 * "." requested
338			 */
339
340			/*
341			 * Thou shalt not rename ".".
342			 * (No, the VFS layer doesn't catch this for us.)
343			 */
344			if ((nameiop == RENAME) && (flags & WANTPARENT) &&
345			    (flags & ISLASTCN))
346				return (EISDIR);
347
348			error = vnode_get(dvp);
349			if (error)
350				return (error);
351			*vpp = dvp;
352			return (0);
353		} else if ((namelen == 2) && (cnp->cn_nameptr[1] == '.')) {
354			fnnode_t *pdfnp;
355
356			pdfnp = (vntofn(dvp))->fn_parent;
357			assert(pdfnp != NULL);
358
359			/*
360			 * Since it is legitimate to have the VROOT flag set for the
361			 * subdirectories of the indirect map in autofs filesystem,
362			 * rootfnnodep is checked against fnnode of dvp instead of
363			 * just checking whether VROOT flag is set in dvp
364			 */
365
366#if 0
367			if (pdfnp == pdfnp->fn_globals->fng_rootfnnodep) {
368				vnode_t vp;
369
370				vfs_lock_wait(vnode_mount(dvp));
371				if (vnode_mount(dvp)->vfs_flag & VFS_UNMOUNTED) {
372					vfs_unlock(vnode_mount(dvp));
373					return (EIO);
374				}
375				vp = vnode_mount(dvp)->mnt_vnodecovered;
376				error = vnode_get(vp);	/* XXX - what if it fails? */
377				vfs_unlock(vnode_mount(dvp));
378				error = VNOP_LOOKUP(vp, nm, vpp, pnp, flags, rdir, cred);
379				vnode_put(vp);
380				return (error);
381			} else {
382#else
383			{
384#endif
385				*vpp = fntovn(pdfnp);
386				return (vnode_get(*vpp));
387			}
388		}
389	}
390
391	dfnp = vntofn(dvp);
392	searchnm = cnp->cn_nameptr;
393	searchnmlen = namelen;
394
395	AUTOFS_DPRINT((3, "auto_lookup: dvp=%p dfnp=%p\n", (void *)dvp,
396	    (void *)dfnp));
397
398	auto_fninfo_lock_shared(dfnip, pid);
399
400top:
401	/*
402	 * If this vnode is a trigger, then something should
403	 * be mounted atop it, and there should be nothing
404	 * in this file system below it.  (We shouldn't
405	 * normally get here, as we should have resolved
406	 * the trigger, but some special processes don't
407	 * trigger mounts.)
408	 */
409	if (dfnp->fn_trigger_info != NULL) {
410		error = ENOENT;
411		goto fail;
412	}
413
414	/*
415	 * See if we have done something with this name already, so we
416	 * already have it.
417	 */
418	lck_rw_lock_shared(dfnp->fn_rwlock);
419	fnp = auto_search(dfnp, cnp->cn_nameptr, cnp->cn_namelen);
420	if (fnp == NULL) {
421		/*
422		 * No, we don't, so we need to make an upcall to see
423		 * if something with that name should exist.
424		 *
425		 * Drop the writer lock on the directory, so
426		 * that we don't block reclaims of autofs
427		 * vnodes in that directory while we're
428		 * waiting for automountd to respond
429		 * (automountd, or some process on which
430		 * it depends, might be doing something
431		 * that requires the allocation of a
432		 * vnode, and that might involve reclaiming
433		 * an autofs vnode) or while we're trying
434		 * to allocate a vnode for the file or
435		 * directory we're looking up.
436		 */
437		lck_rw_unlock_shared(dfnp->fn_rwlock);
438
439		/*
440		 * Check whether this map is in the process of being
441		 * unmounted.  If so, return ENOENT; see auto_control_ioctl()
442		 * for the reason why this is done.
443		 */
444		if (dfnip->fi_flags & MF_UNMOUNTING) {
445			error = ENOENT;
446			goto fail;
447		}
448
449		/*
450		 * Ask automountd whether something with this
451		 * name exists.
452		 */
453		error = auto_lookup_aux(dfnip, dfnp, searchnm,
454		    searchnmlen, context, &node_type);
455		if (error != 0)
456			goto fail;	/* nope */
457
458		/*
459		 * OK, it exists.  We need to create the
460		 * fnnode for it, and enter it into the
461		 * directory.
462		 *
463		 * Create the fnnode first, as we must
464		 * not grab the writer lock on the
465		 * directory, as per the above.
466		 */
467		error = auto_makefnnode(&fnp, node_type,
468		    vnode_mount(dvp), cnp, NULL, dvp, 0,
469		    dfnp->fn_globals);
470		if (error)
471			goto fail;
472
473		/*
474		 * Now enter the fnnode in the directory.
475		 *
476		 * Note that somebody might have created the
477		 * name while we weren't holding the lock;
478		 * if so, then auto_enter() will return
479		 * EEXIST, and will have discarded the
480		 * vnode we created and handed us back
481		 * an fnnode referring to what they'd
482		 * already created.
483		 */
484		error = auto_enter(dfnp, cnp, &fnp);
485		if (error) {
486			if (error == EEXIST) {
487				/*
488				 * We found the name.  Act as if
489				 * the auto_search() above succeeded.
490				 */
491				error = 0;
492			} else {
493				/*
494				 * We found the name, but couldn't
495				 * get an iocount on the vnode for
496				 * its fnnode.  That's probably
497				 * because it was in the process
498				 * of being recycled.  Redo the search,
499				 * as the directory might have changed.
500				 */
501				error = 0;
502				goto top;
503			}
504		} else {
505			/*
506			 * We added an entry to the directory,
507			 * so we might want to notify
508			 * interested parties about that.
509			 * XXX
510			 */
511			do_notify = 1;
512		}
513	} else {
514		/*
515		 * Yes, we did.
516		 *
517		 * We're holding a read lock on that directory, so this
518		 * won't be released out from under us.  We'll have to
519		 * drop the read lock when we do a vnode_getwithvid() to
520		 * allow in-progress reclaims to finish, but that means
521		 * such a reclaim could free the fnnode.
522		 *
523		 * We get the vnode for the fnnode - which will remain
524		 * a vnode even if it's reclaimed - and the vnode ID it
525		 * had when we created the fnnode.
526		 */
527		vp = fntovn(fnp);
528		vid = fnp->fn_vid;
529
530		/*
531		 * Now we can, and must, drop the rwlock to allow
532		 * in-progress reclaims to finish.
533		 */
534		lck_rw_unlock_shared(dfnp->fn_rwlock);
535
536	    	/*
537	    	 * Now let's try to get an iocount on the fnnode, so it
538		 * doesn't vanish out from under us; this also checks
539		 * whether the vnode has been reclaimed out from under
540		 * us, and, thus, whether the fnnode has already vanished
541		 * out from under us.
542	    	 */
543		if (vnode_getwithvid(vp, vid) != 0) {
544			/*
545			 * We failed; the vnode was reclaimed.  The fnnode
546			 * is gone; redo the search.
547			 */
548			error = 0;
549			goto top;
550		}
551
552		/*
553		 * OK, that succeeded, and the vnode is still what it
554		 * was when we created the fnnode, so the fnnode is
555		 * still there - and, as we're holding an iocount
556		 * on the vnode, it's not going away.
557		 */
558	}
559
560fail:
561	auto_fninfo_unlock_shared(dfnip, pid);
562
563	if (error) {
564		/*
565		 * If this is a CREATE operation, and this is the last
566		 * component, and the error is ENOENT, make it ENOTSUP,
567		 * instead, so that somebody trying to create a file or
568		 * directory gets told "sorry, we don't support that".
569		 * Do the same for RENAME operations, so somebody trying
570		 * to rename a file or directory gets told that.
571		 */
572		if (error == ENOENT &&
573		    (nameiop == CREATE || nameiop == RENAME) &&
574		    (flags & ISLASTCN))
575			error = ENOTSUP;
576		goto done;
577	}
578
579	/*
580	 * We now have the actual fnnode we're interested in.
581	 */
582	*vpp = fntovn(fnp);
583
584	/*
585	 * If the directory in which we created this is one on which a
586	 * readdir will only return names corresponding to the vnodes
587	 * we have for it, and somebody cares whether something was
588	 * created in it, notify them.
589	 *
590	 * XXX - defer until we trigger a mount atop it?
591	 */
592	if (do_notify && vnode_ismonitored(dvp) && auto_nobrowse(dvp)) {
593		vfs_get_notify_attributes(&vattr);
594		auto_get_attributes(dvp, &vattr);
595		vnode_notify(dvp, VNODE_EVENT_WRITE, &vattr);
596	}
597
598done:
599	AUTOFS_DPRINT((5, "auto_lookup: name=%s *vpp=%p return=%d\n",
600	    cnp->cn_nameptr, (void *)*vpp, error));
601
602	return (error);
603}
604
605/*
606#% readdir	vp	L L L
607#
608vnop_readdir {
609	IN vnode_t vp;
610	INOUT struct uio *uio;
611	INOUT int *eofflag;
612	OUT int *ncookies;
613	INOUT u_long **cookies;
614	IN vfs_context_t context;
615*/
616
617#define MAXDIRBUFSIZE	65536
618
619/*
620 * "Transient" fnnodes are fnnodes that don't have anything mounted on
621 * them and don't have subdirectories.
622 * Those are subject to evaporating in the near term, so we don't
623 * return them from a readdir - and don't filter them out from names
624 * we get from automountd.
625 */
626#define IS_TRANSIENT(fnp) \
627	 (!vnode_mountedhere(fntovn(fnp)) && (fnp)->fn_direntcnt == 0)
628
629int
630auto_readdir(ap)
631	struct vnop_readdir_args /* {
632		vnode_t a_vp;
633		struct uio *a_uio;
634		int a_flags;
635		int *a_eofflag;
636		int *a_numdirent;
637		vfs_context_t a_context;
638	} */ *ap;
639{
640	vnode_t vp = ap->a_vp;
641	struct uio *uiop = ap->a_uio;
642	int pid = vfs_context_pid(ap->a_context);
643	int64_t return_offset;
644	boolean_t return_eof;
645	byte_buffer return_buffer;
646	mach_msg_type_number_t return_bufcount;
647	vm_map_offset_t map_data;
648	vm_offset_t data;
649	fnnode_t *fnp = vntofn(vp);
650	fnnode_t *cfnp, *nfnp;
651	struct dirent *dp;
652	off_t offset;
653	u_int outcount = 0;
654	mach_msg_type_number_t count;
655        void *outbuf;
656	user_ssize_t user_alloc_count;
657	u_int alloc_count;
658	fninfo_t *fnip = vfstofni(vnode_mount(vp));
659	kern_return_t ret;
660	int error = 0;
661	int reached_max = 0;
662	int myeof = 0;
663	u_int this_reclen;
664
665        AUTOFS_DPRINT((4, "auto_readdir vp=%p offset=%lld\n",
666            (void *)vp, uio_offset(uiop)));
667
668	if (ap->a_numdirent != NULL)
669		*ap->a_numdirent = 0;
670
671	if (ap->a_flags & (VNODE_READDIR_EXTENDED | VNODE_READDIR_REQSEEKOFF))
672		return (EINVAL);
673
674	if (ap->a_eofflag != NULL)
675		*ap->a_eofflag = 0;
676
677	user_alloc_count = uio_resid(uiop);
678	/*
679	 * Reject too-small user requests.
680	 */
681	if (user_alloc_count < (user_ssize_t) DIRENT_RECLEN(1))
682		return (EINVAL);
683	/*
684	 * Trim too-large user requests.
685	 */
686	if (user_alloc_count > (user_ssize_t) MAXDIRBUFSIZE)
687		user_alloc_count = MAXDIRBUFSIZE;
688	alloc_count = (u_int)user_alloc_count;
689
690	/*
691	 * Make sure the mounted map won't change out from under us.
692	 */
693	auto_fninfo_lock_shared(fnip, pid);
694
695	/*
696	 * Make sure the directory we're reading won't change out from
697	 * under us while we're scanning it.
698	 */
699	lck_rw_lock_shared(fnp->fn_rwlock);
700
701	if (uio_offset(uiop) >= AUTOFS_DAEMONCOOKIE) {
702		/*
703		 * If we're in the middle of unmounting the map, we won't
704		 * create anything under it in a lookup, so we should
705		 * only return directory entries for things that are
706		 * already there.
707		 */
708		if (fnip->fi_flags & MF_UNMOUNTING) {
709			myeof = 1;
710			if (ap->a_eofflag != NULL)
711				*ap->a_eofflag = 1;
712			goto done;
713		}
714
715again:
716		/*
717		 * Do readdir of daemon contents only
718		 * Drop readers lock and reacquire after reply.
719		 */
720		lck_rw_unlock_shared(fnp->fn_rwlock);
721
722		count = 0;
723		error = auto_readdir_aux(fnip, fnp,
724		    uio_offset(uiop), alloc_count,
725		    &return_offset, &return_eof, &return_buffer,
726		    &return_bufcount);
727
728		/*
729		 * reacquire previously dropped lock
730		 */
731		lck_rw_lock_shared(fnp->fn_rwlock);
732
733		if (error)
734			goto done;
735
736		ret = vm_map_copyout(kernel_map, &map_data,
737		    (vm_map_copy_t)return_buffer);
738		if (ret != KERN_SUCCESS) {
739			IOLog("autofs: vm_map_copyout failed, status 0x%08x\n",
740			    ret);
741			/* XXX - deal with Mach errors */
742			error = EIO;
743			goto done;
744		}
745		data = CAST_DOWN(vm_offset_t, map_data);
746
747		if (return_bufcount != 0) {
748			struct dirent *odp;	/* next in output buffer */
749			struct dirent *cdp;	/* current examined entry */
750
751			/*
752			 * Check for duplicates of entries that have
753			 * fnnodes, and for illegal values (".", "..",
754			 * and anything with a "/" in it), here.
755			 */
756			dp = (struct dirent *)data;
757			odp = dp;
758			cdp = dp;
759			do {
760				this_reclen = RECLEN(cdp);
761				cfnp = auto_search(fnp, cdp->d_name,
762				    cdp->d_namlen);
763				if (cfnp == NULL || IS_TRANSIENT(cfnp)) {
764					/*
765					 * entry not found in kernel list,
766					 * or found but is transient, so
767					 * include it in readdir output.
768					 *
769					 * If we are skipping entries. then
770					 * we need to copy this entry to the
771					 * correct position in the buffer
772					 * to be copied out.
773					 */
774					if (cdp != odp)
775						bcopy(cdp, odp,
776						    (size_t)this_reclen);
777					odp = nextdp(odp);
778					outcount += this_reclen;
779					if (ap->a_numdirent)
780						++(*ap->a_numdirent);
781				} else {
782					/*
783					 * Entry was found in the kernel
784					 * list. If it is the first entry
785					 * in this buffer, then just skip it
786					 */
787					if (odp == dp) {
788						dp = nextdp(dp);
789						odp = dp;
790					}
791				}
792				count += this_reclen;
793				cdp = (struct dirent *)
794				    ((char *)cdp + this_reclen);
795			} while (count < return_bufcount);
796
797			if (outcount)
798				error = uiomove((caddr_t)dp, outcount, uiop);
799			uio_setoffset(uiop, return_offset);
800		} else {
801			if (return_eof == 0) {
802				/*
803				 * alloc_count not large enough for one
804				 * directory entry
805				 */
806				error = EINVAL;
807			}
808		}
809		vm_deallocate(kernel_map, data, return_bufcount);
810		if (return_eof && !error) {
811			myeof = 1;
812			if (ap->a_eofflag != NULL)
813				*ap->a_eofflag = 1;
814		}
815		if (!error && !myeof && outcount == 0) {
816			/*
817			 * call daemon with new cookie, all previous
818			 * elements happened to be duplicates
819			 */
820			goto again;
821		}
822		goto done;
823	}
824
825	/*
826	 * Not past the "magic" offset, so we return only the entries
827	 * we get without talking to the daemon.
828	 */
829	MALLOC(outbuf, void *, alloc_count, M_AUTOFS, M_WAITOK);
830	dp = outbuf;
831	if (uio_offset(uiop) == 0) {
832		/*
833		 * first time: so fudge the . and ..
834		 */
835		this_reclen = DIRENT_RECLEN(1);
836		if (alloc_count < this_reclen) {
837			error = EINVAL;
838			goto done;
839		}
840		dp->d_ino = (ino_t)fnp->fn_nodeid;
841		dp->d_reclen = (uint16_t)this_reclen;
842#if 0
843		dp->d_type = DT_DIR;
844#else
845		dp->d_type = DT_UNKNOWN;
846#endif
847		dp->d_namlen = 1;
848
849		/* use strncpy() to zero out uninitialized bytes */
850
851		(void) strncpy(dp->d_name, ".", DIRENT_NAMELEN(this_reclen));
852		outcount += dp->d_reclen;
853		dp = nextdp(dp);
854
855		if (ap->a_numdirent)
856			++(*ap->a_numdirent);
857
858		this_reclen = DIRENT_RECLEN(2);
859		if (alloc_count < outcount + this_reclen) {
860			error = EINVAL;
861			FREE(outbuf, M_AUTOFS);
862			goto done;
863		}
864		dp->d_reclen = (uint16_t)this_reclen;
865		dp->d_ino = (ino_t)fnp->fn_parent->fn_nodeid;
866#if 0
867		dp->d_type = DT_DIR;
868#else
869		dp->d_type = DT_UNKNOWN;
870#endif
871		dp->d_namlen = 2;
872
873		/* use strncpy() to zero out uninitialized bytes */
874
875		(void) strncpy(dp->d_name, "..",
876		    DIRENT_NAMELEN(this_reclen));
877		outcount += dp->d_reclen;
878		dp = nextdp(dp);
879
880		if (ap->a_numdirent)
881			++(*ap->a_numdirent);
882	}
883
884	offset = 2;
885	cfnp = fnp->fn_dirents;
886	while (cfnp != NULL) {
887		nfnp = cfnp->fn_next;
888		offset = cfnp->fn_offset;
889		/*
890		 * XXX - what is this lock protecting against?  We're
891		 * holding a read lock on the directory we're reading,
892		 * which should keep its fn_dirents list from changing
893		 * and thus keep fnnodes in that list from being freed.
894		 */
895		lck_rw_lock_shared(cfnp->fn_rwlock);
896		if ((offset >= uio_offset(uiop)) && !IS_TRANSIENT(cfnp)) {
897			int reclen;
898
899			lck_rw_unlock_shared(cfnp->fn_rwlock);
900
901			/*
902			 * include node only if its offset is greater or
903			 * equal to the one required and isn't
904			 * transient
905			 */
906			reclen = (int)DIRENT_RECLEN(cfnp->fn_namelen);
907			if (outcount + reclen > alloc_count) {
908				reached_max = 1;
909				break;
910			}
911			dp->d_reclen = (uint16_t)reclen;
912			dp->d_ino = (ino_t)cfnp->fn_nodeid;
913#if 0
914			dp->d_type = vnode_isdir(fntovn(cfnp)) ? DT_DIR : DT_LNK;
915#else
916			dp->d_type = DT_UNKNOWN;
917#endif
918			dp->d_namlen = cfnp->fn_namelen;
919
920			/* use strncpy() to zero out uninitialized bytes */
921
922			(void) strncpy(dp->d_name, cfnp->fn_name,
923			    DIRENT_NAMELEN(reclen));
924			outcount += dp->d_reclen;
925			dp = nextdp(dp);
926
927			if (ap->a_numdirent)
928				++(*ap->a_numdirent);
929		} else
930			lck_rw_unlock_shared(cfnp->fn_rwlock);
931		cfnp = nfnp;
932	}
933
934	if (outcount)
935		error = uiomove(outbuf, outcount, uiop);
936	if (!error) {
937		if (reached_max) {
938			/*
939			 * This entry did not get added to the buffer on this,
940			 * call. We need to add it on the next call therefore
941			 * set uio_offset to this entry's offset.  If there
942			 * wasn't enough space for one dirent, return EINVAL.
943			 */
944			uio_setoffset(uiop, offset);
945			if (outcount == 0)
946				error = EINVAL;
947		} else if (auto_nobrowse(vp)) {
948			/*
949			 * done reading directory entries
950			 */
951			uio_setoffset(uiop, offset + 1);
952			if (ap->a_eofflag != NULL)
953				*ap->a_eofflag = 1;
954		} else {
955			/*
956			 * Need to get the rest of the entries from the daemon.
957			 */
958			uio_setoffset(uiop, AUTOFS_DAEMONCOOKIE);
959		}
960	}
961	FREE(outbuf, M_AUTOFS);
962
963done:
964	lck_rw_unlock_shared(fnp->fn_rwlock);
965	auto_fninfo_unlock_shared(fnip, pid);
966	AUTOFS_DPRINT((5, "auto_readdir vp=%p offset=%lld eof=%d\n",
967	    (void *)vp, uio_offset(uiop), myeof));
968	return (error);
969}
970
971static int
972auto_readlink(ap)
973	struct vnop_readlink_args /* {
974		struct vnodeop_desc *a_desc;
975		vnode_t a_vp;
976		struct uio *a_uio;
977		vfs_context_t a_context;
978	} */ *ap;
979{
980	vnode_t vp = ap->a_vp;
981	uio_t uiop = ap->a_uio;
982	fnnode_t *fnp = vntofn(vp);
983	struct timeval now;
984	int error;
985
986	AUTOFS_DPRINT((4, "auto_readlink: vp=%p\n", (void *)vp));
987
988	if (!vnode_islnk(vp))
989		error = EINVAL;
990	else {
991		microtime(&now);
992		fnp->fn_atime = now;
993		error = uiomove(fnp->fn_symlink, MIN(fnp->fn_symlinklen,
994		    (int)uio_resid(uiop)), uiop);
995	}
996
997	AUTOFS_DPRINT((5, "auto_readlink: error=%d\n", error));
998	return (error);
999}
1000
1001static int
1002auto_pathconf(ap)
1003	struct vnop_pathconf_args /* {
1004		struct vnode *a_vp;
1005		int a_name;
1006		int *a_retval;
1007		vfs_context_t a_context;
1008	} */ *ap;
1009{
1010	switch (ap->a_name) {
1011	case _PC_LINK_MAX:
1012		/* arbitrary limit matching HFS; autofs has no hard limit */
1013		*ap->a_retval = 32767;
1014		break;
1015	case _PC_NAME_MAX:
1016		*ap->a_retval = NAME_MAX;
1017		break;
1018	case _PC_PATH_MAX:
1019		*ap->a_retval = PATH_MAX;
1020		break;
1021	case _PC_CHOWN_RESTRICTED:
1022		*ap->a_retval = 200112;		/* _POSIX_CHOWN_RESTRICTED */
1023		break;
1024	case _PC_NO_TRUNC:
1025		*ap->a_retval = 0;
1026		break;
1027	case _PC_CASE_SENSITIVE:
1028		*ap->a_retval = 1;
1029		break;
1030	case _PC_CASE_PRESERVING:
1031		*ap->a_retval = 1;
1032		break;
1033	default:
1034		return (EINVAL);
1035	}
1036
1037	return (0);
1038}
1039
1040static int
1041auto_fsctl(ap)
1042	struct vnop_ioctl_args /* {
1043		struct vnodeop_desc *a_desc;
1044		vnode_t a_vp;
1045		int32_t a_command;
1046		caddr_t a_data;
1047		int32_t a_fflag;
1048		vfs_context_t a_context;
1049	}; */ *ap;
1050{
1051	vnode_t vp = ap->a_vp;
1052
1053	/*
1054	 * The only operation we support is "mark this as having a home
1055	 * directory mount in progress".
1056	 */
1057	if (ap->a_command != IOCBASECMD(AUTOFS_MARK_HOMEDIRMOUNT))
1058		return (EINVAL);
1059
1060        /*
1061         * <13595777> homedirmounter getting ready to do a mount so we
1062         * want to take the mutex
1063         */
1064	return (auto_mark_vnode_homedirmount(vp,
1065                                             vfs_context_pid(ap->a_context),
1066                                             1));
1067}
1068
1069static int
1070auto_getxattr(ap)
1071 	struct vnop_getxattr_args /* {
1072		struct vnodeop_desc *a_desc;
1073		vnode_t a_vp;
1074		char * a_name;
1075		uio_t a_uio;
1076		size_t *a_size;
1077		int a_options;
1078		vfs_context_t a_context;
1079	}; */ *ap;
1080{
1081	struct uio *uio = ap->a_uio;
1082
1083	/* do not support position argument */
1084	if (uio_offset(uio) != 0)
1085		return (EINVAL);
1086
1087	/*
1088	 * We don't actually offer any extended attributes; we just say
1089	 * we do, so that nobody wastes our time - or any server's time,
1090	 * with wildcard maps - looking for ._ files.
1091	 */
1092	return (ENOATTR);
1093}
1094
1095static int
1096auto_listxattr(ap)
1097	struct vnop_listxattr_args /* {
1098		struct vnodeop_desc *a_desc;
1099		vnode_t a_vp;
1100		uio_t a_uio;
1101		size_t *a_size;
1102		int a_options;
1103		vfs_context_t a_context;
1104	}; */ *ap;
1105{
1106	*ap->a_size = 0;
1107
1108	/* we have no extended attributes, so just return 0 */
1109	return (0);
1110}
1111
1112/*
1113 * Called when the I/O count (in-progress vnops) is 0, and either
1114 * the use count (long-term references) is 0 or the vnode is being
1115 * forcibly disconnected from us (e.g., on a forced unmount, in which
1116 * case the vnode will be reassociated with deadfs).
1117 *
1118 * We just recycle the vnode, which encourages its reclamation; we
1119 * can't disconnect it until it's actually reclaimed.
1120 */
1121static int
1122auto_inactive(ap)
1123	struct vnop_inactive_args /* {
1124		struct vnodeop_desc *a_desc;
1125		vnode_t a_vp;
1126		vfs_context_t a_context;
1127	} */ *ap;
1128{
1129	AUTOFS_DPRINT((4, "auto_inactive: vp=%p\n", (void *)vp));
1130
1131	vnode_recycle(ap->a_vp);
1132
1133	AUTOFS_DPRINT((5, "auto_inactive: (exit) vp=%p\n", (void *)vp));
1134	return (0);
1135}
1136
1137static int
1138auto_reclaim(ap)
1139	struct vnop_reclaim_args /* {
1140		struct vnodeop_desc *a_desc;
1141		vnode_t a_vp;
1142		vfs_context_t a_context;
1143	} */ *ap;
1144{
1145	vnode_t vp = ap->a_vp;
1146	fnnode_t *fnp = vntofn(vp);
1147	fnnode_t *dfnp = fnp->fn_parent;
1148
1149	AUTOFS_DPRINT((4, "auto_reclaim: vp=%p fn_link=%d\n",
1150	    (void *)vp, fnp->fn_linkcnt));
1151
1152	/*
1153	 * There are no filesystem calls in progress on this vnode, and
1154	 * none will be made until we're done.
1155	 *
1156	 * Thus, it's safe to disconnect this from its parent directory,
1157	 * if it has one.
1158	 */
1159	if (dfnp != NULL) {
1160		lck_rw_lock_exclusive(dfnp->fn_rwlock);
1161		/*
1162		 * There are no active references to this.
1163		 * If there's only one link to this, namely the link to it
1164		 * from its parent, get rid of it by removing it from
1165		 * its parent's list of child fnnodes and recycle it;
1166		 * a subsequent reference to it will recreate it if
1167		 * the name is still there in the map.
1168		 */
1169		if (fnp->fn_linkcnt == 1) {
1170			/*
1171			 * This will drop the write lock on dfnp.
1172			 */
1173			auto_disconnect(dfnp, fnp);
1174		} else if (fnp->fn_linkcnt == 0) {
1175			/*
1176			 * Root vnode; we've already removed it from the
1177			 * "parent" (the master node for all autofs file
1178			 * systems) - just null out the parent pointer, so
1179			 * that we don't trip any assertions
1180			 * in auto_freefnnode().
1181			 */
1182			fnp->fn_parent = NULL;
1183			lck_rw_unlock_exclusive(dfnp->fn_rwlock);
1184		} else {
1185			/*
1186			 * This should not happen.
1187			 */
1188			IOLog("auto_reclaim: reclaiming fnnode with linkcnt %u > 1\n",
1189			    fnp->fn_linkcnt);
1190			lck_rw_unlock_exclusive(dfnp->fn_rwlock);
1191		}
1192	}
1193	auto_freefnnode(fnp);
1194	vnode_clearfsnode(vp);
1195	AUTOFS_DPRINT((5, "auto_reclaim: (exit) vp=%p freed\n",
1196	    (void *)vp));
1197	return (0);
1198}
1199