1/*
2 * Copyright (c) 2000-2001 Boris Popov
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *    This product includes software developed by Boris Popov.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 * $Id: smbfs_vnops.c,v 1.128.36.1 2005/05/27 02:35:28 lindak Exp $
33 */
34
35/*
36 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
37 */
38
39#include <sys/systm.h>
40#include <sys/cred.h>
41#include <sys/vnode.h>
42#include <sys/vfs.h>
43#include <sys/filio.h>
44#include <sys/uio.h>
45#include <sys/dirent.h>
46#include <sys/errno.h>
47#include <sys/sunddi.h>
48#include <sys/sysmacros.h>
49#include <sys/kmem.h>
50#include <sys/cmn_err.h>
51#include <sys/vfs_opreg.h>
52#include <sys/policy.h>
53
54#include <netsmb/smb_osdep.h>
55#include <netsmb/smb.h>
56#include <netsmb/smb_conn.h>
57#include <netsmb/smb_subr.h>
58
59#include <smbfs/smbfs.h>
60#include <smbfs/smbfs_node.h>
61#include <smbfs/smbfs_subr.h>
62
63#include <sys/fs/smbfs_ioctl.h>
64#include <fs/fs_subr.h>
65
66/*
67 * We assign directory offsets like the NFS client, where the
68 * offset increments by _one_ after each directory entry.
69 * Further, the entries "." and ".." are always at offsets
70 * zero and one (respectively) and the "real" entries from
71 * the server appear at offsets starting with two.  This
72 * macro is used to initialize the n_dirofs field after
73 * setting n_dirseq with a _findopen call.
74 */
75#define	FIRST_DIROFS	2
76
77/*
78 * These characters are illegal in NTFS file names.
79 * ref: http://support.microsoft.com/kb/147438
80 *
81 * Careful!  The check in the XATTR case skips the
82 * first character to allow colon in XATTR names.
83 */
84static const char illegal_chars[] = {
85	':',	/* colon - keep this first! */
86	'\\',	/* back slash */
87	'/',	/* slash */
88	'*',	/* asterisk */
89	'?',	/* question mark */
90	'"',	/* double quote */
91	'<',	/* less than sign */
92	'>',	/* greater than sign */
93	'|',	/* vertical bar */
94	0
95};
96
97/*
98 * Turning this on causes nodes to be created in the cache
99 * during directory listings, normally avoiding a second
100 * OtW attribute fetch just after a readdir.
101 */
102int smbfs_fastlookup = 1;
103
104/* local static function defines */
105
106static int	smbfslookup_cache(vnode_t *, char *, int, vnode_t **,
107			cred_t *);
108static int	smbfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr,
109			int cache_ok, caller_context_t *);
110static int	smbfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm,
111			cred_t *cr, caller_context_t *);
112static int	smbfssetattr(vnode_t *, struct vattr *, int, cred_t *);
113static int	smbfs_accessx(void *, int, cred_t *);
114static int	smbfs_readvdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp,
115			caller_context_t *);
116static void	smbfs_rele_fid(smbnode_t *, struct smb_cred *);
117
118/*
119 * These are the vnode ops routines which implement the vnode interface to
120 * the networked file system.  These routines just take their parameters,
121 * make them look networkish by putting the right info into interface structs,
122 * and then calling the appropriate remote routine(s) to do the work.
123 *
124 * Note on directory name lookup cacheing:  If we detect a stale fhandle,
125 * we purge the directory cache relative to that vnode.  This way, the
126 * user won't get burned by the cache repeatedly.  See <smbfs/smbnode.h> for
127 * more details on smbnode locking.
128 */
129
130static int	smbfs_open(vnode_t **, int, cred_t *, caller_context_t *);
131static int	smbfs_close(vnode_t *, int, int, offset_t, cred_t *,
132			caller_context_t *);
133static int	smbfs_read(vnode_t *, struct uio *, int, cred_t *,
134			caller_context_t *);
135static int	smbfs_write(vnode_t *, struct uio *, int, cred_t *,
136			caller_context_t *);
137static int	smbfs_ioctl(vnode_t *, int, intptr_t, int, cred_t *, int *,
138			caller_context_t *);
139static int	smbfs_getattr(vnode_t *, struct vattr *, int, cred_t *,
140			caller_context_t *);
141static int	smbfs_setattr(vnode_t *, struct vattr *, int, cred_t *,
142			caller_context_t *);
143static int	smbfs_access(vnode_t *, int, int, cred_t *, caller_context_t *);
144static int	smbfs_fsync(vnode_t *, int, cred_t *, caller_context_t *);
145static void	smbfs_inactive(vnode_t *, cred_t *, caller_context_t *);
146static int	smbfs_lookup(vnode_t *, char *, vnode_t **, struct pathname *,
147			int, vnode_t *, cred_t *, caller_context_t *,
148			int *, pathname_t *);
149static int	smbfs_create(vnode_t *, char *, struct vattr *, enum vcexcl,
150			int, vnode_t **, cred_t *, int, caller_context_t *,
151			vsecattr_t *);
152static int	smbfs_remove(vnode_t *, char *, cred_t *, caller_context_t *,
153			int);
154static int	smbfs_rename(vnode_t *, char *, vnode_t *, char *, cred_t *,
155			caller_context_t *, int);
156static int	smbfs_mkdir(vnode_t *, char *, struct vattr *, vnode_t **,
157			cred_t *, caller_context_t *, int, vsecattr_t *);
158static int	smbfs_rmdir(vnode_t *, char *, vnode_t *, cred_t *,
159			caller_context_t *, int);
160static int	smbfs_readdir(vnode_t *, struct uio *, cred_t *, int *,
161			caller_context_t *, int);
162static int	smbfs_rwlock(vnode_t *, int, caller_context_t *);
163static void	smbfs_rwunlock(vnode_t *, int, caller_context_t *);
164static int	smbfs_seek(vnode_t *, offset_t, offset_t *, caller_context_t *);
165static int	smbfs_frlock(vnode_t *, int, struct flock64 *, int, offset_t,
166			struct flk_callback *, cred_t *, caller_context_t *);
167static int	smbfs_space(vnode_t *, int, struct flock64 *, int, offset_t,
168			cred_t *, caller_context_t *);
169static int	smbfs_pathconf(vnode_t *, int, ulong_t *, cred_t *,
170			caller_context_t *);
171static int	smbfs_setsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
172			caller_context_t *);
173static int	smbfs_getsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
174			caller_context_t *);
175static int	smbfs_shrlock(vnode_t *, int, struct shrlock *, int, cred_t *,
176			caller_context_t *);
177
178/* Dummy function to use until correct function is ported in */
179int noop_vnodeop() {
180	return (0);
181}
182
183struct vnodeops *smbfs_vnodeops = NULL;
184
185/*
186 * Most unimplemented ops will return ENOSYS because of fs_nosys().
187 * The only ops where that won't work are ACCESS (due to open(2)
188 * failures) and ... (anything else left?)
189 */
190const fs_operation_def_t smbfs_vnodeops_template[] = {
191	{ VOPNAME_OPEN,		{ .vop_open = smbfs_open } },
192	{ VOPNAME_CLOSE,	{ .vop_close = smbfs_close } },
193	{ VOPNAME_READ,		{ .vop_read = smbfs_read } },
194	{ VOPNAME_WRITE,	{ .vop_write = smbfs_write } },
195	{ VOPNAME_IOCTL,	{ .vop_ioctl = smbfs_ioctl } },
196	{ VOPNAME_GETATTR,	{ .vop_getattr = smbfs_getattr } },
197	{ VOPNAME_SETATTR,	{ .vop_setattr = smbfs_setattr } },
198	{ VOPNAME_ACCESS,	{ .vop_access = smbfs_access } },
199	{ VOPNAME_LOOKUP,	{ .vop_lookup = smbfs_lookup } },
200	{ VOPNAME_CREATE,	{ .vop_create = smbfs_create } },
201	{ VOPNAME_REMOVE,	{ .vop_remove = smbfs_remove } },
202	{ VOPNAME_LINK,		{ .error = fs_nosys } }, /* smbfs_link, */
203	{ VOPNAME_RENAME,	{ .vop_rename = smbfs_rename } },
204	{ VOPNAME_MKDIR,	{ .vop_mkdir = smbfs_mkdir } },
205	{ VOPNAME_RMDIR,	{ .vop_rmdir = smbfs_rmdir } },
206	{ VOPNAME_READDIR,	{ .vop_readdir = smbfs_readdir } },
207	{ VOPNAME_SYMLINK,	{ .error = fs_nosys } }, /* smbfs_symlink, */
208	{ VOPNAME_READLINK,	{ .error = fs_nosys } }, /* smbfs_readlink, */
209	{ VOPNAME_FSYNC,	{ .vop_fsync = smbfs_fsync } },
210	{ VOPNAME_INACTIVE,	{ .vop_inactive = smbfs_inactive } },
211	{ VOPNAME_FID,		{ .error = fs_nosys } }, /* smbfs_fid, */
212	{ VOPNAME_RWLOCK,	{ .vop_rwlock = smbfs_rwlock } },
213	{ VOPNAME_RWUNLOCK,	{ .vop_rwunlock = smbfs_rwunlock } },
214	{ VOPNAME_SEEK,		{ .vop_seek = smbfs_seek } },
215	{ VOPNAME_FRLOCK,	{ .vop_frlock = smbfs_frlock } },
216	{ VOPNAME_SPACE,	{ .vop_space = smbfs_space } },
217	{ VOPNAME_REALVP,	{ .error = fs_nosys } }, /* smbfs_realvp, */
218	{ VOPNAME_GETPAGE,	{ .error = fs_nosys } }, /* smbfs_getpage, */
219	{ VOPNAME_PUTPAGE,	{ .error = fs_nosys } }, /* smbfs_putpage, */
220	{ VOPNAME_MAP,		{ .error = fs_nosys } }, /* smbfs_map, */
221	{ VOPNAME_ADDMAP,	{ .error = fs_nosys } }, /* smbfs_addmap, */
222	{ VOPNAME_DELMAP,	{ .error = fs_nosys } }, /* smbfs_delmap, */
223	{ VOPNAME_DUMP,		{ .error = fs_nosys } }, /* smbfs_dump, */
224	{ VOPNAME_PATHCONF,	{ .vop_pathconf = smbfs_pathconf } },
225	{ VOPNAME_PAGEIO,	{ .error = fs_nosys } }, /* smbfs_pageio, */
226	{ VOPNAME_SETSECATTR,	{ .vop_setsecattr = smbfs_setsecattr } },
227	{ VOPNAME_GETSECATTR,	{ .vop_getsecattr = smbfs_getsecattr } },
228	{ VOPNAME_SHRLOCK,	{ .vop_shrlock = smbfs_shrlock } },
229	{ NULL, NULL }
230};
231
232/*
233 * XXX
234 * When new and relevant functionality is enabled, we should be
235 * calling vfs_set_feature() to inform callers that pieces of
236 * functionality are available, per PSARC 2007/227.
237 */
238/* ARGSUSED */
239static int
240smbfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
241{
242	smbnode_t	*np;
243	vnode_t		*vp;
244	smbfattr_t	fa;
245	u_int32_t	rights, rightsrcvd;
246	u_int16_t	fid, oldfid;
247	int		oldgenid;
248	struct smb_cred scred;
249	smbmntinfo_t	*smi;
250	smb_share_t	*ssp;
251	cred_t		*oldcr;
252	int		tmperror;
253	int		error = 0;
254
255	vp = *vpp;
256	np = VTOSMB(vp);
257	smi = VTOSMI(vp);
258	ssp = smi->smi_share;
259
260	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
261		return (EIO);
262
263	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
264		return (EIO);
265
266	if (vp->v_type != VREG && vp->v_type != VDIR) { /* XXX VLNK? */
267		SMBVDEBUG("open eacces vtype=%d\n", vp->v_type);
268		return (EACCES);
269	}
270
271	/*
272	 * Get exclusive access to n_fid and related stuff.
273	 * No returns after this until out.
274	 */
275	if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, SMBINTR(vp)))
276		return (EINTR);
277	smb_credinit(&scred, cr);
278
279	/*
280	 * Keep track of the vnode type at first open.
281	 * It may change later, and we need close to do
282	 * cleanup for the type we opened.  Also deny
283	 * open of new types until old type is closed.
284	 * XXX: Per-open instance nodes whould help.
285	 */
286	if (np->n_ovtype == VNON) {
287		ASSERT(np->n_dirrefs == 0);
288		ASSERT(np->n_fidrefs == 0);
289	} else if (np->n_ovtype != vp->v_type) {
290		SMBVDEBUG("open n_ovtype=%d v_type=%d\n",
291		    np->n_ovtype, vp->v_type);
292		error = EACCES;
293		goto out;
294	}
295
296	/*
297	 * Directory open.  See smbfs_readvdir()
298	 */
299	if (vp->v_type == VDIR) {
300		if (np->n_dirseq == NULL) {
301			/* first open */
302			error = smbfs_smb_findopen(np, "*", 1,
303			    SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR,
304			    &scred, &np->n_dirseq);
305			if (error != 0)
306				goto out;
307		}
308		np->n_dirofs = FIRST_DIROFS;
309		np->n_dirrefs++;
310		goto have_fid;
311	}
312
313	/*
314	 * If caller specified O_TRUNC/FTRUNC, then be sure to set
315	 * FWRITE (to drive successful setattr(size=0) after open)
316	 */
317	if (flag & FTRUNC)
318		flag |= FWRITE;
319
320	/*
321	 * If we already have it open, and the FID is still valid,
322	 * check whether the rights are sufficient for FID reuse.
323	 */
324	if (np->n_fidrefs > 0 &&
325	    np->n_vcgenid == ssp->ss_vcgenid) {
326		int upgrade = 0;
327
328		if ((flag & FWRITE) &&
329		    !(np->n_rights & SA_RIGHT_FILE_WRITE_DATA))
330			upgrade = 1;
331		if ((flag & FREAD) &&
332		    !(np->n_rights & SA_RIGHT_FILE_READ_DATA))
333			upgrade = 1;
334		if (!upgrade) {
335			/*
336			 *  the existing open is good enough
337			 */
338			np->n_fidrefs++;
339			goto have_fid;
340		}
341	}
342	rights = np->n_fidrefs ? np->n_rights : 0;
343
344	/*
345	 * we always ask for READ_CONTROL so we can always get the
346	 * owner/group IDs to satisfy a stat.  Ditto attributes.
347	 */
348	rights |= (STD_RIGHT_READ_CONTROL_ACCESS |
349	    SA_RIGHT_FILE_READ_ATTRIBUTES);
350	if ((flag & FREAD))
351		rights |= SA_RIGHT_FILE_READ_DATA;
352	if ((flag & FWRITE))
353		rights |= SA_RIGHT_FILE_WRITE_DATA |
354		    SA_RIGHT_FILE_APPEND_DATA |
355		    SA_RIGHT_FILE_WRITE_ATTRIBUTES;
356
357	bzero(&fa, sizeof (fa));
358	error = smbfs_smb_open(np,
359	    NULL, 0, 0, /* name nmlen xattr */
360	    rights, &scred,
361	    &fid, &rightsrcvd, &fa);
362	if (error)
363		goto out;
364	smbfs_attrcache_fa(vp, &fa);
365
366	/*
367	 * We have a new FID and access rights.
368	 */
369	oldfid = np->n_fid;
370	oldgenid = np->n_vcgenid;
371	np->n_fid = fid;
372	np->n_vcgenid = ssp->ss_vcgenid;
373	np->n_rights = rightsrcvd;
374	np->n_fidrefs++;
375	if (np->n_fidrefs > 1 &&
376	    oldgenid == ssp->ss_vcgenid) {
377		/*
378		 * We already had it open (presumably because
379		 * it was open with insufficient rights.)
380		 * Close old wire-open.
381		 */
382		tmperror = smbfs_smb_close(ssp,
383		    oldfid, NULL, &scred);
384		if (tmperror)
385			SMBVDEBUG("error %d closing %s\n",
386			    tmperror, np->n_rpath);
387	}
388
389	/*
390	 * This thread did the open.
391	 * Save our credentials too.
392	 */
393	mutex_enter(&np->r_statelock);
394	oldcr = np->r_cred;
395	np->r_cred = cr;
396	crhold(cr);
397	if (oldcr)
398		crfree(oldcr);
399	mutex_exit(&np->r_statelock);
400
401have_fid:
402	/*
403	 * Keep track of the vnode type at first open.
404	 * (see comments above)
405	 */
406	if (np->n_ovtype == VNON)
407		np->n_ovtype = vp->v_type;
408
409out:
410	smb_credrele(&scred);
411	smbfs_rw_exit(&np->r_lkserlock);
412	return (error);
413}
414
415/*ARGSUSED*/
416static int
417smbfs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
418	caller_context_t *ct)
419{
420	smbnode_t	*np;
421	smbmntinfo_t	*smi;
422	struct smb_cred scred;
423
424	np = VTOSMB(vp);
425	smi = VTOSMI(vp);
426
427	/*
428	 * Don't "bail out" for VFS_UNMOUNTED here,
429	 * as we want to do cleanup, etc.
430	 */
431
432	/*
433	 * zone_enter(2) prevents processes from changing zones with SMBFS files
434	 * open; if we happen to get here from the wrong zone we can't do
435	 * anything over the wire.
436	 */
437	if (smi->smi_zone_ref.zref_zone != curproc->p_zone) {
438		/*
439		 * We could attempt to clean up locks, except we're sure
440		 * that the current process didn't acquire any locks on
441		 * the file: any attempt to lock a file belong to another zone
442		 * will fail, and one can't lock an SMBFS file and then change
443		 * zones, as that fails too.
444		 *
445		 * Returning an error here is the sane thing to do.  A
446		 * subsequent call to VN_RELE() which translates to a
447		 * smbfs_inactive() will clean up state: if the zone of the
448		 * vnode's origin is still alive and kicking, an async worker
449		 * thread will handle the request (from the correct zone), and
450		 * everything (minus the final smbfs_getattr_otw() call) should
451		 * be OK. If the zone is going away smbfs_async_inactive() will
452		 * throw away cached pages inline.
453		 */
454		return (EIO);
455	}
456
457	/*
458	 * If we are using local locking for this filesystem, then
459	 * release all of the SYSV style record locks.  Otherwise,
460	 * we are doing network locking and we need to release all
461	 * of the network locks.  All of the locks held by this
462	 * process on this file are released no matter what the
463	 * incoming reference count is.
464	 */
465	if (smi->smi_flags & SMI_LLOCK) {
466		pid_t pid = ddi_get_pid();
467		cleanlocks(vp, pid, 0);
468		cleanshares(vp, pid);
469	}
470
471	/*
472	 * This (passed in) count is the ref. count from the
473	 * user's file_t before the closef call (fio.c).
474	 * We only care when the reference goes away.
475	 */
476	if (count > 1)
477		return (0);
478
479	/*
480	 * Decrement the reference count for the FID
481	 * and possibly do the OtW close.
482	 *
483	 * Exclusive lock for modifying n_fid stuff.
484	 * Don't want this one ever interruptible.
485	 */
486	(void) smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, 0);
487	smb_credinit(&scred, cr);
488
489	smbfs_rele_fid(np, &scred);
490
491	smb_credrele(&scred);
492	smbfs_rw_exit(&np->r_lkserlock);
493
494	return (0);
495}
496
497/*
498 * Helper for smbfs_close.  Decrement the reference count
499 * for an SMB-level file or directory ID, and when the last
500 * reference for the fid goes away, do the OtW close.
501 * Also called in smbfs_inactive (defensive cleanup).
502 */
503static void
504smbfs_rele_fid(smbnode_t *np, struct smb_cred *scred)
505{
506	smb_share_t	*ssp;
507	cred_t		*oldcr;
508	struct smbfs_fctx *fctx;
509	int		error;
510	uint16_t ofid;
511
512	ssp = np->n_mount->smi_share;
513	error = 0;
514
515	/* Make sure we serialize for n_dirseq use. */
516	ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_WRITER));
517
518	/*
519	 * Note that vp->v_type may change if a remote node
520	 * is deleted and recreated as a different type, and
521	 * our getattr may change v_type accordingly.
522	 * Now use n_ovtype to keep track of the v_type
523	 * we had during open (see comments above).
524	 */
525	switch (np->n_ovtype) {
526	case VDIR:
527		ASSERT(np->n_dirrefs > 0);
528		if (--np->n_dirrefs)
529			return;
530		if ((fctx = np->n_dirseq) != NULL) {
531			np->n_dirseq = NULL;
532			np->n_dirofs = 0;
533			error = smbfs_smb_findclose(fctx, scred);
534		}
535		break;
536
537	case VREG:
538		ASSERT(np->n_fidrefs > 0);
539		if (--np->n_fidrefs)
540			return;
541		if ((ofid = np->n_fid) != SMB_FID_UNUSED) {
542			np->n_fid = SMB_FID_UNUSED;
543			/* After reconnect, n_fid is invalid */
544			if (np->n_vcgenid == ssp->ss_vcgenid) {
545				error = smbfs_smb_close(
546				    ssp, ofid, NULL, scred);
547			}
548		}
549		break;
550
551	default:
552		SMBVDEBUG("bad n_ovtype %d\n", np->n_ovtype);
553		break;
554	}
555	if (error) {
556		SMBVDEBUG("error %d closing %s\n",
557		    error, np->n_rpath);
558	}
559
560	/* Allow next open to use any v_type. */
561	np->n_ovtype = VNON;
562
563	/*
564	 * Other "last close" stuff.
565	 */
566	mutex_enter(&np->r_statelock);
567	if (np->n_flag & NATTRCHANGED)
568		smbfs_attrcache_rm_locked(np);
569	oldcr = np->r_cred;
570	np->r_cred = NULL;
571	mutex_exit(&np->r_statelock);
572	if (oldcr != NULL)
573		crfree(oldcr);
574}
575
576/* ARGSUSED */
577static int
578smbfs_read(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
579	caller_context_t *ct)
580{
581	struct smb_cred scred;
582	struct vattr	va;
583	smbnode_t	*np;
584	smbmntinfo_t	*smi;
585	smb_share_t	*ssp;
586	offset_t	endoff;
587	ssize_t		past_eof;
588	int		error;
589
590	np = VTOSMB(vp);
591	smi = VTOSMI(vp);
592	ssp = smi->smi_share;
593
594	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
595		return (EIO);
596
597	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
598		return (EIO);
599
600	ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_READER));
601
602	if (vp->v_type != VREG)
603		return (EISDIR);
604
605	if (uiop->uio_resid == 0)
606		return (0);
607
608	/*
609	 * Like NFS3, just check for 63-bit overflow.
610	 * Our SMB layer takes care to return EFBIG
611	 * when it has to fallback to a 32-bit call.
612	 */
613	endoff = uiop->uio_loffset + uiop->uio_resid;
614	if (uiop->uio_loffset < 0 || endoff < 0)
615		return (EINVAL);
616
617	/* get vnode attributes from server */
618	va.va_mask = AT_SIZE | AT_MTIME;
619	if (error = smbfsgetattr(vp, &va, cr))
620		return (error);
621
622	/* Update mtime with mtime from server here? */
623
624	/* if offset is beyond EOF, read nothing */
625	if (uiop->uio_loffset >= va.va_size)
626		return (0);
627
628	/*
629	 * Limit the read to the remaining file size.
630	 * Do this by temporarily reducing uio_resid
631	 * by the amount the lies beyoned the EOF.
632	 */
633	if (endoff > va.va_size) {
634		past_eof = (ssize_t)(endoff - va.va_size);
635		uiop->uio_resid -= past_eof;
636	} else
637		past_eof = 0;
638
639	/* Shared lock for n_fid use in smb_rwuio */
640	if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
641		return (EINTR);
642	smb_credinit(&scred, cr);
643
644	/* After reconnect, n_fid is invalid */
645	if (np->n_vcgenid != ssp->ss_vcgenid)
646		error = ESTALE;
647	else
648		error = smb_rwuio(ssp, np->n_fid, UIO_READ,
649		    uiop, &scred, smb_timo_read);
650
651	smb_credrele(&scred);
652	smbfs_rw_exit(&np->r_lkserlock);
653
654	/* undo adjustment of resid */
655	uiop->uio_resid += past_eof;
656
657	return (error);
658}
659
660
661/* ARGSUSED */
662static int
663smbfs_write(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
664	caller_context_t *ct)
665{
666	struct smb_cred scred;
667	struct vattr	va;
668	smbnode_t	*np;
669	smbmntinfo_t	*smi;
670	smb_share_t	*ssp;
671	offset_t	endoff, limit;
672	ssize_t		past_limit;
673	int		error, timo;
674
675	np = VTOSMB(vp);
676	smi = VTOSMI(vp);
677	ssp = smi->smi_share;
678
679	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
680		return (EIO);
681
682	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
683		return (EIO);
684
685	ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_WRITER));
686
687	if (vp->v_type != VREG)
688		return (EISDIR);
689
690	if (uiop->uio_resid == 0)
691		return (0);
692
693	/*
694	 * Handle ioflag bits: (FAPPEND|FSYNC|FDSYNC)
695	 */
696	if (ioflag & (FAPPEND | FSYNC)) {
697		if (np->n_flag & NMODIFIED) {
698			smbfs_attrcache_remove(np);
699			/* XXX: smbfs_vinvalbuf? */
700		}
701	}
702	if (ioflag & FAPPEND) {
703		/*
704		 * File size can be changed by another client
705		 */
706		va.va_mask = AT_SIZE;
707		if (error = smbfsgetattr(vp, &va, cr))
708			return (error);
709		uiop->uio_loffset = va.va_size;
710	}
711
712	/*
713	 * Like NFS3, just check for 63-bit overflow.
714	 */
715	endoff = uiop->uio_loffset + uiop->uio_resid;
716	if (uiop->uio_loffset < 0 || endoff < 0)
717		return (EINVAL);
718
719	/*
720	 * Check to make sure that the process will not exceed
721	 * its limit on file size.  It is okay to write up to
722	 * the limit, but not beyond.  Thus, the write which
723	 * reaches the limit will be short and the next write
724	 * will return an error.
725	 *
726	 * So if we're starting at or beyond the limit, EFBIG.
727	 * Otherwise, temporarily reduce resid to the amount
728	 * the falls after the limit.
729	 */
730	limit = uiop->uio_llimit;
731	if (limit == RLIM64_INFINITY || limit > MAXOFFSET_T)
732		limit = MAXOFFSET_T;
733	if (uiop->uio_loffset >= limit)
734		return (EFBIG);
735	if (endoff > limit) {
736		past_limit = (ssize_t)(endoff - limit);
737		uiop->uio_resid -= past_limit;
738	} else
739		past_limit = 0;
740
741	/* Timeout: longer for append. */
742	timo = smb_timo_write;
743	if (endoff > np->r_size)
744		timo = smb_timo_append;
745
746	/* Shared lock for n_fid use in smb_rwuio */
747	if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
748		return (EINTR);
749	smb_credinit(&scred, cr);
750
751	/* After reconnect, n_fid is invalid */
752	if (np->n_vcgenid != ssp->ss_vcgenid)
753		error = ESTALE;
754	else
755		error = smb_rwuio(ssp, np->n_fid, UIO_WRITE,
756		    uiop, &scred, timo);
757
758	if (error == 0) {
759		mutex_enter(&np->r_statelock);
760		np->n_flag |= (NFLUSHWIRE | NATTRCHANGED);
761		if (uiop->uio_loffset > (offset_t)np->r_size)
762			np->r_size = (len_t)uiop->uio_loffset;
763		mutex_exit(&np->r_statelock);
764		if (ioflag & (FSYNC|FDSYNC)) {
765			/* Don't error the I/O if this fails. */
766			(void) smbfs_smb_flush(np, &scred);
767		}
768	}
769
770	smb_credrele(&scred);
771	smbfs_rw_exit(&np->r_lkserlock);
772
773	/* undo adjustment of resid */
774	uiop->uio_resid += past_limit;
775
776	return (error);
777}
778
779
780/* ARGSUSED */
781static int
782smbfs_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag,
783	cred_t *cr, int *rvalp,	caller_context_t *ct)
784{
785	int		error;
786	smbmntinfo_t 	*smi;
787
788	smi = VTOSMI(vp);
789
790	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
791		return (EIO);
792
793	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
794		return (EIO);
795
796	switch (cmd) {
797		/* First three from ZFS. XXX - need these? */
798
799	case _FIOFFS:
800		error = smbfs_fsync(vp, 0, cr, ct);
801		break;
802
803		/*
804		 * The following two ioctls are used by bfu.
805		 * Silently ignore to avoid bfu errors.
806		 */
807	case _FIOGDIO:
808	case _FIOSDIO:
809		error = 0;
810		break;
811
812#ifdef NOT_YET	/* XXX - from the NFS code. */
813	case _FIODIRECTIO:
814		error = smbfs_directio(vp, (int)arg, cr);
815#endif
816
817		/*
818		 * Allow get/set with "raw" security descriptor (SD) data.
819		 * Useful for testing, diagnosing idmap problems, etc.
820		 */
821	case SMBFSIO_GETSD:
822		error = smbfs_acl_iocget(vp, arg, flag, cr);
823		break;
824
825	case SMBFSIO_SETSD:
826		error = smbfs_acl_iocset(vp, arg, flag, cr);
827		break;
828
829	default:
830		error = ENOTTY;
831		break;
832	}
833
834	return (error);
835}
836
837
838/*
839 * Return either cached or remote attributes. If get remote attr
840 * use them to check and invalidate caches, then cache the new attributes.
841 *
842 * XXX
843 * This op should eventually support PSARC 2007/315, Extensible Attribute
844 * Interfaces, for richer metadata.
845 */
846/* ARGSUSED */
847static int
848smbfs_getattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr,
849	caller_context_t *ct)
850{
851	smbnode_t *np;
852	smbmntinfo_t *smi;
853
854	smi = VTOSMI(vp);
855
856	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
857		return (EIO);
858
859	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
860		return (EIO);
861
862	/*
863	 * If it has been specified that the return value will
864	 * just be used as a hint, and we are only being asked
865	 * for size, fsid or rdevid, then return the client's
866	 * notion of these values without checking to make sure
867	 * that the attribute cache is up to date.
868	 * The whole point is to avoid an over the wire GETATTR
869	 * call.
870	 */
871	np = VTOSMB(vp);
872	if (flags & ATTR_HINT) {
873		if (vap->va_mask ==
874		    (vap->va_mask & (AT_SIZE | AT_FSID | AT_RDEV))) {
875			mutex_enter(&np->r_statelock);
876			if (vap->va_mask | AT_SIZE)
877				vap->va_size = np->r_size;
878			if (vap->va_mask | AT_FSID)
879				vap->va_fsid = vp->v_vfsp->vfs_dev;
880			if (vap->va_mask | AT_RDEV)
881				vap->va_rdev = vp->v_rdev;
882			mutex_exit(&np->r_statelock);
883			return (0);
884		}
885	}
886
887	return (smbfsgetattr(vp, vap, cr));
888}
889
890/* smbfsgetattr() in smbfs_client.c */
891
892/*
893 * XXX
894 * This op should eventually support PSARC 2007/315, Extensible Attribute
895 * Interfaces, for richer metadata.
896 */
897/*ARGSUSED4*/
898static int
899smbfs_setattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr,
900		caller_context_t *ct)
901{
902	vfs_t		*vfsp;
903	smbmntinfo_t	*smi;
904	int		error;
905	uint_t		mask;
906	struct vattr	oldva;
907
908	vfsp = vp->v_vfsp;
909	smi = VFTOSMI(vfsp);
910
911	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
912		return (EIO);
913
914	if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
915		return (EIO);
916
917	mask = vap->va_mask;
918	if (mask & AT_NOSET)
919		return (EINVAL);
920
921	if (vfsp->vfs_flag & VFS_RDONLY)
922		return (EROFS);
923
924	/*
925	 * This is a _local_ access check so that only the owner of
926	 * this mount can set attributes.  With ACLs enabled, the
927	 * file owner can be different from the mount owner, and we
928	 * need to check the _mount_ owner here.  See _access_rwx
929	 */
930	bzero(&oldva, sizeof (oldva));
931	oldva.va_mask = AT_TYPE | AT_MODE;
932	error = smbfsgetattr(vp, &oldva, cr);
933	if (error)
934		return (error);
935	oldva.va_mask |= AT_UID | AT_GID;
936	oldva.va_uid = smi->smi_uid;
937	oldva.va_gid = smi->smi_gid;
938
939	error = secpolicy_vnode_setattr(cr, vp, vap, &oldva, flags,
940	    smbfs_accessx, vp);
941	if (error)
942		return (error);
943
944	if (mask & (AT_UID | AT_GID)) {
945		if (smi->smi_flags & SMI_ACL)
946			error = smbfs_acl_setids(vp, vap, cr);
947		else
948			error = ENOSYS;
949		if (error != 0) {
950			SMBVDEBUG("error %d seting UID/GID on %s",
951			    error, VTOSMB(vp)->n_rpath);
952			/*
953			 * It might be more correct to return the
954			 * error here, but that causes complaints
955			 * when root extracts a cpio archive, etc.
956			 * So ignore this error, and go ahead with
957			 * the rest of the setattr work.
958			 */
959		}
960	}
961
962	return (smbfssetattr(vp, vap, flags, cr));
963}
964
965/*
966 * Mostly from Darwin smbfs_setattr()
967 * but then modified a lot.
968 */
969/* ARGSUSED */
970static int
971smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
972{
973	int		error = 0;
974	smbnode_t	*np = VTOSMB(vp);
975	uint_t		mask = vap->va_mask;
976	struct timespec	*mtime, *atime;
977	struct smb_cred	scred;
978	int		cerror, modified = 0;
979	unsigned short	fid;
980	int have_fid = 0;
981	uint32_t rights = 0;
982
983	ASSERT(curproc->p_zone == VTOSMI(vp)->smi_zone_ref.zref_zone);
984
985	/*
986	 * There are no settable attributes on the XATTR dir,
987	 * so just silently ignore these.  On XATTR files,
988	 * you can set the size but nothing else.
989	 */
990	if (vp->v_flag & V_XATTRDIR)
991		return (0);
992	if (np->n_flag & N_XATTR) {
993		if (mask & AT_TIMES)
994			SMBVDEBUG("ignore set time on xattr\n");
995		mask &= AT_SIZE;
996	}
997
998	/*
999	 * If our caller is trying to set multiple attributes, they
1000	 * can make no assumption about what order they are done in.
1001	 * Here we try to do them in order of decreasing likelihood
1002	 * of failure, just to minimize the chance we'll wind up
1003	 * with a partially complete request.
1004	 */
1005
1006	/* Shared lock for (possible) n_fid use. */
1007	if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
1008		return (EINTR);
1009	smb_credinit(&scred, cr);
1010
1011	/*
1012	 * Will we need an open handle for this setattr?
1013	 * If so, what rights will we need?
1014	 */
1015	if (mask & (AT_ATIME | AT_MTIME)) {
1016		rights |=
1017		    SA_RIGHT_FILE_WRITE_ATTRIBUTES;
1018	}
1019	if (mask & AT_SIZE) {
1020		rights |=
1021		    SA_RIGHT_FILE_WRITE_DATA |
1022		    SA_RIGHT_FILE_APPEND_DATA;
1023	}
1024
1025	/*
1026	 * Only SIZE really requires a handle, but it's
1027	 * simpler and more reliable to set via a handle.
1028	 * Some servers like NT4 won't set times by path.
1029	 * Also, we're usually setting everything anyway.
1030	 */
1031	if (mask & (AT_SIZE | AT_ATIME | AT_MTIME)) {
1032		error = smbfs_smb_tmpopen(np, rights, &scred, &fid);
1033		if (error) {
1034			SMBVDEBUG("error %d opening %s\n",
1035			    error, np->n_rpath);
1036			goto out;
1037		}
1038		have_fid = 1;
1039	}
1040
1041	/*
1042	 * If the server supports the UNIX extensions, right here is where
1043	 * we'd support changes to uid, gid, mode, and possibly va_flags.
1044	 * For now we claim to have made any such changes.
1045	 */
1046
1047	if (mask & AT_SIZE) {
1048		/*
1049		 * If the new file size is less than what the client sees as
1050		 * the file size, then just change the size and invalidate
1051		 * the pages.
1052		 * I am commenting this code at present because the function
1053		 * smbfs_putapage() is not yet implemented.
1054		 */
1055
1056		/*
1057		 * Set the file size to vap->va_size.
1058		 */
1059		ASSERT(have_fid);
1060		error = smbfs_smb_setfsize(np, fid, vap->va_size, &scred);
1061		if (error) {
1062			SMBVDEBUG("setsize error %d file %s\n",
1063			    error, np->n_rpath);
1064		} else {
1065			/*
1066			 * Darwin had code here to zero-extend.
1067			 * Tests indicate the server will zero-fill,
1068			 * so looks like we don't need to do this.
1069			 * Good thing, as this could take forever.
1070			 *
1071			 * XXX: Reportedly, writing one byte of zero
1072			 * at the end offset avoids problems here.
1073			 */
1074			mutex_enter(&np->r_statelock);
1075			np->r_size = vap->va_size;
1076			mutex_exit(&np->r_statelock);
1077			modified = 1;
1078		}
1079	}
1080
1081	/*
1082	 * XXX: When Solaris has create_time, set that too.
1083	 * Note: create_time is different from ctime.
1084	 */
1085	mtime = ((mask & AT_MTIME) ? &vap->va_mtime : 0);
1086	atime = ((mask & AT_ATIME) ? &vap->va_atime : 0);
1087
1088	if (mtime || atime) {
1089		/*
1090		 * Always use the handle-based set attr call now.
1091		 * Not trying to set DOS attributes here so pass zero.
1092		 */
1093		ASSERT(have_fid);
1094		error = smbfs_smb_setfattr(np, fid,
1095		    0, mtime, atime, &scred);
1096		if (error) {
1097			SMBVDEBUG("set times error %d file %s\n",
1098			    error, np->n_rpath);
1099		} else {
1100			modified = 1;
1101		}
1102	}
1103
1104out:
1105	if (modified) {
1106		/*
1107		 * Invalidate attribute cache in case the server
1108		 * doesn't set exactly the attributes we asked.
1109		 */
1110		smbfs_attrcache_remove(np);
1111	}
1112
1113	if (have_fid) {
1114		cerror = smbfs_smb_tmpclose(np, fid, &scred);
1115		if (cerror)
1116			SMBVDEBUG("error %d closing %s\n",
1117			    cerror, np->n_rpath);
1118	}
1119
1120	smb_credrele(&scred);
1121	smbfs_rw_exit(&np->r_lkserlock);
1122
1123	return (error);
1124}
1125
1126/*
1127 * smbfs_access_rwx()
1128 * Common function for smbfs_access, etc.
1129 *
1130 * The security model implemented by the FS is unusual
1131 * due to the current "single user mounts" restriction:
1132 * All access under a given mount point uses the CIFS
1133 * credentials established by the owner of the mount.
1134 *
1135 * Most access checking is handled by the CIFS server,
1136 * but we need sufficient Unix access checks here to
1137 * prevent other local Unix users from having access
1138 * to objects under this mount that the uid/gid/mode
1139 * settings in the mount would not allow.
1140 *
1141 * With this model, there is a case where we need the
1142 * ability to do an access check before we have the
1143 * vnode for an object.  This function takes advantage
1144 * of the fact that the uid/gid/mode is per mount, and
1145 * avoids the need for a vnode.
1146 *
1147 * We still (sort of) need a vnode when we call
1148 * secpolicy_vnode_access, but that only uses
1149 * the vtype field, so we can use a pair of fake
1150 * vnodes that have only v_type filled in.
1151 *
1152 * XXX: Later, add a new secpolicy_vtype_access()
1153 * that takes the vtype instead of a vnode, and
1154 * get rid of the tmpl_vxxx fake vnodes below.
1155 */
1156static int
1157smbfs_access_rwx(vfs_t *vfsp, int vtype, int mode, cred_t *cr)
1158{
1159	/* See the secpolicy call below. */
1160	static const vnode_t tmpl_vdir = { .v_type = VDIR };
1161	static const vnode_t tmpl_vreg = { .v_type = VREG };
1162	vattr_t		va;
1163	vnode_t		*tvp;
1164	struct smbmntinfo *smi = VFTOSMI(vfsp);
1165	int shift = 0;
1166
1167	/*
1168	 * Build our (fabricated) vnode attributes.
1169	 * XXX: Could make these templates in the
1170	 * per-mount struct and use them here.
1171	 */
1172	bzero(&va, sizeof (va));
1173	va.va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID;
1174	va.va_type = vtype;
1175	va.va_mode = (vtype == VDIR) ?
1176	    smi->smi_dmode : smi->smi_fmode;
1177	va.va_uid = smi->smi_uid;
1178	va.va_gid = smi->smi_gid;
1179
1180	/*
1181	 * Disallow write attempts on read-only file systems,
1182	 * unless the file is a device or fifo node.  Note:
1183	 * Inline vn_is_readonly and IS_DEVVP here because
1184	 * we may not have a vnode ptr.  Original expr. was:
1185	 * (mode & VWRITE) && vn_is_readonly(vp) && !IS_DEVVP(vp))
1186	 */
1187	if ((mode & VWRITE) &&
1188	    (vfsp->vfs_flag & VFS_RDONLY) &&
1189	    !(vtype == VCHR || vtype == VBLK || vtype == VFIFO))
1190		return (EROFS);
1191
1192	/*
1193	 * Disallow attempts to access mandatory lock files.
1194	 * Similarly, expand MANDLOCK here.
1195	 * XXX: not sure we need this.
1196	 */
1197	if ((mode & (VWRITE | VREAD | VEXEC)) &&
1198	    va.va_type == VREG && MANDMODE(va.va_mode))
1199		return (EACCES);
1200
1201	/*
1202	 * Access check is based on only
1203	 * one of owner, group, public.
1204	 * If not owner, then check group.
1205	 * If not a member of the group,
1206	 * then check public access.
1207	 */
1208	if (crgetuid(cr) != va.va_uid) {
1209		shift += 3;
1210		if (!groupmember(va.va_gid, cr))
1211			shift += 3;
1212	}
1213
1214	/*
1215	 * We need a vnode for secpolicy_vnode_access,
1216	 * but the only thing it looks at is v_type,
1217	 * so pass one of the templates above.
1218	 */
1219	tvp = (va.va_type == VDIR) ?
1220	    (vnode_t *)&tmpl_vdir :
1221	    (vnode_t *)&tmpl_vreg;
1222
1223	return (secpolicy_vnode_access2(cr, tvp, va.va_uid,
1224	    va.va_mode << shift, mode));
1225}
1226
1227/*
1228 * See smbfs_setattr
1229 */
1230static int
1231smbfs_accessx(void *arg, int mode, cred_t *cr)
1232{
1233	vnode_t *vp = arg;
1234	/*
1235	 * Note: The caller has checked the current zone,
1236	 * the SMI_DEAD and VFS_UNMOUNTED flags, etc.
1237	 */
1238	return (smbfs_access_rwx(vp->v_vfsp, vp->v_type, mode, cr));
1239}
1240
1241/*
1242 * XXX
1243 * This op should support PSARC 2007/403, Modified Access Checks for CIFS
1244 */
1245/* ARGSUSED */
1246static int
1247smbfs_access(vnode_t *vp, int mode, int flags, cred_t *cr, caller_context_t *ct)
1248{
1249	vfs_t		*vfsp;
1250	smbmntinfo_t	*smi;
1251
1252	vfsp = vp->v_vfsp;
1253	smi = VFTOSMI(vfsp);
1254
1255	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
1256		return (EIO);
1257
1258	if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
1259		return (EIO);
1260
1261	return (smbfs_access_rwx(vfsp, vp->v_type, mode, cr));
1262}
1263
1264
1265/*
1266 * Flush local dirty pages to stable storage on the server.
1267 *
1268 * If FNODSYNC is specified, then there is nothing to do because
1269 * metadata changes are not cached on the client before being
1270 * sent to the server.
1271 */
1272/* ARGSUSED */
1273static int
1274smbfs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct)
1275{
1276	int		error = 0;
1277	smbmntinfo_t	*smi;
1278	smbnode_t 	*np;
1279	struct smb_cred scred;
1280
1281	np = VTOSMB(vp);
1282	smi = VTOSMI(vp);
1283
1284	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
1285		return (EIO);
1286
1287	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
1288		return (EIO);
1289
1290	if ((syncflag & FNODSYNC) || IS_SWAPVP(vp))
1291		return (0);
1292
1293	if ((syncflag & (FSYNC|FDSYNC)) == 0)
1294		return (0);
1295
1296	/* Shared lock for n_fid use in _flush */
1297	if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
1298		return (EINTR);
1299	smb_credinit(&scred, cr);
1300
1301	error = smbfs_smb_flush(np, &scred);
1302
1303	smb_credrele(&scred);
1304	smbfs_rw_exit(&np->r_lkserlock);
1305
1306	return (error);
1307}
1308
1309/*
1310 * Last reference to vnode went away.
1311 */
1312/* ARGSUSED */
1313static void
1314smbfs_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
1315{
1316	smbnode_t	*np;
1317	struct smb_cred scred;
1318
1319	/*
1320	 * Don't "bail out" for VFS_UNMOUNTED here,
1321	 * as we want to do cleanup, etc.
1322	 * See also pcfs_inactive
1323	 */
1324
1325	np = VTOSMB(vp);
1326
1327	/*
1328	 * If this is coming from the wrong zone, we let someone in the right
1329	 * zone take care of it asynchronously.  We can get here due to
1330	 * VN_RELE() being called from pageout() or fsflush().  This call may
1331	 * potentially turn into an expensive no-op if, for instance, v_count
1332	 * gets incremented in the meantime, but it's still correct.
1333	 */
1334
1335	/*
1336	 * Defend against the possibility that higher-level callers
1337	 * might not correctly balance open and close calls.  If we
1338	 * get here with open references remaining, it means there
1339	 * was a missing VOP_CLOSE somewhere.  If that happens, do
1340	 * the close here so we don't "leak" FIDs on the server.
1341	 *
1342	 * Exclusive lock for modifying n_fid stuff.
1343	 * Don't want this one ever interruptible.
1344	 */
1345	(void) smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, 0);
1346	smb_credinit(&scred, cr);
1347
1348	switch (np->n_ovtype) {
1349	case VNON:
1350		/* not open (OK) */
1351		break;
1352
1353	case VDIR:
1354		if (np->n_dirrefs == 0)
1355			break;
1356		SMBVDEBUG("open dir: refs %d path %s\n",
1357		    np->n_dirrefs, np->n_rpath);
1358		/* Force last close. */
1359		np->n_dirrefs = 1;
1360		smbfs_rele_fid(np, &scred);
1361		break;
1362
1363	case VREG:
1364		if (np->n_fidrefs == 0)
1365			break;
1366		SMBVDEBUG("open file: refs %d id 0x%x path %s\n",
1367		    np->n_fidrefs, np->n_fid, np->n_rpath);
1368		/* Force last close. */
1369		np->n_fidrefs = 1;
1370		smbfs_rele_fid(np, &scred);
1371		break;
1372
1373	default:
1374		SMBVDEBUG("bad n_ovtype %d\n", np->n_ovtype);
1375		np->n_ovtype = VNON;
1376		break;
1377	}
1378
1379	smb_credrele(&scred);
1380	smbfs_rw_exit(&np->r_lkserlock);
1381
1382	smbfs_addfree(np);
1383}
1384
1385/*
1386 * Remote file system operations having to do with directory manipulation.
1387 */
1388/* ARGSUSED */
1389static int
1390smbfs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
1391	int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
1392	int *direntflags, pathname_t *realpnp)
1393{
1394	vfs_t		*vfs;
1395	smbmntinfo_t	*smi;
1396	smbnode_t	*dnp;
1397	int		error;
1398
1399	vfs = dvp->v_vfsp;
1400	smi = VFTOSMI(vfs);
1401
1402	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
1403		return (EPERM);
1404
1405	if (smi->smi_flags & SMI_DEAD || vfs->vfs_flag & VFS_UNMOUNTED)
1406		return (EIO);
1407
1408	dnp = VTOSMB(dvp);
1409
1410	/*
1411	 * Are we looking up extended attributes?  If so, "dvp" is
1412	 * the file or directory for which we want attributes, and
1413	 * we need a lookup of the (faked up) attribute directory
1414	 * before we lookup the rest of the path.
1415	 */
1416	if (flags & LOOKUP_XATTR) {
1417		/*
1418		 * Require the xattr mount option.
1419		 */
1420		if ((vfs->vfs_flag & VFS_XATTR) == 0)
1421			return (EINVAL);
1422
1423		error = smbfs_get_xattrdir(dvp, vpp, cr, flags);
1424		return (error);
1425	}
1426
1427	if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_READER, SMBINTR(dvp)))
1428		return (EINTR);
1429
1430	error = smbfslookup(dvp, nm, vpp, cr, 1, ct);
1431
1432	smbfs_rw_exit(&dnp->r_rwlock);
1433
1434	return (error);
1435}
1436
1437/* ARGSUSED */
1438static int
1439smbfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr,
1440	int cache_ok, caller_context_t *ct)
1441{
1442	int		error;
1443	int		supplen; /* supported length */
1444	vnode_t		*vp;
1445	smbnode_t	*np;
1446	smbnode_t	*dnp;
1447	smbmntinfo_t	*smi;
1448	/* struct smb_vc	*vcp; */
1449	const char	*ill;
1450	const char	*name = (const char *)nm;
1451	int 		nmlen = strlen(nm);
1452	int 		rplen;
1453	struct smb_cred scred;
1454	struct smbfattr fa;
1455
1456	smi = VTOSMI(dvp);
1457	dnp = VTOSMB(dvp);
1458
1459	ASSERT(curproc->p_zone == smi->smi_zone_ref.zref_zone);
1460
1461#ifdef NOT_YET
1462	vcp = SSTOVC(smi->smi_share);
1463
1464	/* XXX: Should compute this once and store it in smbmntinfo_t */
1465	supplen = (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN2_0) ? 255 : 12;
1466#else
1467	supplen = 255;
1468#endif
1469
1470	/*
1471	 * RWlock must be held, either reader or writer.
1472	 * XXX: Can we check without looking directly
1473	 * inside the struct smbfs_rwlock_t?
1474	 */
1475	ASSERT(dnp->r_rwlock.count != 0);
1476
1477	/*
1478	 * If lookup is for "", just return dvp.
1479	 * No need to perform any access checks.
1480	 */
1481	if (nmlen == 0) {
1482		VN_HOLD(dvp);
1483		*vpp = dvp;
1484		return (0);
1485	}
1486
1487	/*
1488	 * Can't do lookups in non-directories.
1489	 */
1490	if (dvp->v_type != VDIR)
1491		return (ENOTDIR);
1492
1493	/*
1494	 * Need search permission in the directory.
1495	 */
1496	error = smbfs_access(dvp, VEXEC, 0, cr, ct);
1497	if (error)
1498		return (error);
1499
1500	/*
1501	 * If lookup is for ".", just return dvp.
1502	 * Access check was done above.
1503	 */
1504	if (nmlen == 1 && name[0] == '.') {
1505		VN_HOLD(dvp);
1506		*vpp = dvp;
1507		return (0);
1508	}
1509
1510	/*
1511	 * Now some sanity checks on the name.
1512	 * First check the length.
1513	 */
1514	if (nmlen > supplen)
1515		return (ENAMETOOLONG);
1516
1517	/*
1518	 * Avoid surprises with characters that are
1519	 * illegal in Windows file names.
1520	 * Todo: CATIA mappings  XXX
1521	 */
1522	ill = illegal_chars;
1523	if (dnp->n_flag & N_XATTR)
1524		ill++; /* allow colon */
1525	if (strpbrk(nm, ill))
1526		return (EINVAL);
1527
1528	/*
1529	 * Special handling for lookup of ".."
1530	 *
1531	 * We keep full pathnames (as seen on the server)
1532	 * so we can just trim off the last component to
1533	 * get the full pathname of the parent.  Note:
1534	 * We don't actually copy and modify, but just
1535	 * compute the trimmed length and pass that with
1536	 * the current dir path (not null terminated).
1537	 *
1538	 * We don't go over-the-wire to get attributes
1539	 * for ".." because we know it's a directory,
1540	 * and we can just leave the rest "stale"
1541	 * until someone does a getattr.
1542	 */
1543	if (nmlen == 2 && name[0] == '.' && name[1] == '.') {
1544		if (dvp->v_flag & VROOT) {
1545			/*
1546			 * Already at the root.  This can happen
1547			 * with directory listings at the root,
1548			 * which lookup "." and ".." to get the
1549			 * inode numbers.  Let ".." be the same
1550			 * as "." in the FS root.
1551			 */
1552			VN_HOLD(dvp);
1553			*vpp = dvp;
1554			return (0);
1555		}
1556
1557		/*
1558		 * Special case for XATTR directory
1559		 */
1560		if (dvp->v_flag & V_XATTRDIR) {
1561			error = smbfs_xa_parent(dvp, vpp);
1562			return (error);
1563		}
1564
1565		/*
1566		 * Find the parent path length.
1567		 */
1568		rplen = dnp->n_rplen;
1569		ASSERT(rplen > 0);
1570		while (--rplen >= 0) {
1571			if (dnp->n_rpath[rplen] == '\\')
1572				break;
1573		}
1574		if (rplen <= 0) {
1575			/* Found our way to the root. */
1576			vp = SMBTOV(smi->smi_root);
1577			VN_HOLD(vp);
1578			*vpp = vp;
1579			return (0);
1580		}
1581		np = smbfs_node_findcreate(smi,
1582		    dnp->n_rpath, rplen, NULL, 0, 0,
1583		    &smbfs_fattr0); /* force create */
1584		ASSERT(np != NULL);
1585		vp = SMBTOV(np);
1586		vp->v_type = VDIR;
1587
1588		/* Success! */
1589		*vpp = vp;
1590		return (0);
1591	}
1592
1593	/*
1594	 * Normal lookup of a name under this directory.
1595	 * Note we handled "", ".", ".." above.
1596	 */
1597	if (cache_ok) {
1598		/*
1599		 * The caller indicated that it's OK to use a
1600		 * cached result for this lookup, so try to
1601		 * reclaim a node from the smbfs node cache.
1602		 */
1603		error = smbfslookup_cache(dvp, nm, nmlen, &vp, cr);
1604		if (error)
1605			return (error);
1606		if (vp != NULL) {
1607			/* hold taken in lookup_cache */
1608			*vpp = vp;
1609			return (0);
1610		}
1611	}
1612
1613	/*
1614	 * OK, go over-the-wire to get the attributes,
1615	 * then create the node.
1616	 */
1617	smb_credinit(&scred, cr);
1618	/* Note: this can allocate a new "name" */
1619	error = smbfs_smb_lookup(dnp, &name, &nmlen, &fa, &scred);
1620	smb_credrele(&scred);
1621	if (error == ENOTDIR) {
1622		/*
1623		 * Lookup failed because this directory was
1624		 * removed or renamed by another client.
1625		 * Remove any cached attributes under it.
1626		 */
1627		smbfs_attrcache_remove(dnp);
1628		smbfs_attrcache_prune(dnp);
1629	}
1630	if (error)
1631		goto out;
1632
1633	error = smbfs_nget(dvp, name, nmlen, &fa, &vp);
1634	if (error)
1635		goto out;
1636
1637	/* Success! */
1638	*vpp = vp;
1639
1640out:
1641	/* smbfs_smb_lookup may have allocated name. */
1642	if (name != nm)
1643		smbfs_name_free(name, nmlen);
1644
1645	return (error);
1646}
1647
1648/*
1649 * smbfslookup_cache
1650 *
1651 * Try to reclaim a node from the smbfs node cache.
1652 * Some statistics for DEBUG.
1653 *
1654 * This mechanism lets us avoid many of the five (or more)
1655 * OtW lookup calls per file seen with "ls -l" if we search
1656 * the smbfs node cache for recently inactive(ated) nodes.
1657 */
1658#ifdef DEBUG
1659int smbfs_lookup_cache_calls = 0;
1660int smbfs_lookup_cache_error = 0;
1661int smbfs_lookup_cache_miss = 0;
1662int smbfs_lookup_cache_stale = 0;
1663int smbfs_lookup_cache_hits = 0;
1664#endif /* DEBUG */
1665
1666/* ARGSUSED */
1667static int
1668smbfslookup_cache(vnode_t *dvp, char *nm, int nmlen,
1669	vnode_t **vpp, cred_t *cr)
1670{
1671	struct vattr va;
1672	smbnode_t *dnp;
1673	smbnode_t *np;
1674	vnode_t *vp;
1675	int error;
1676	char sep;
1677
1678	dnp = VTOSMB(dvp);
1679	*vpp = NULL;
1680
1681#ifdef DEBUG
1682	smbfs_lookup_cache_calls++;
1683#endif
1684
1685	/*
1686	 * First make sure we can get attributes for the
1687	 * directory.  Cached attributes are OK here.
1688	 * If we removed or renamed the directory, this
1689	 * will return ENOENT.  If someone else removed
1690	 * this directory or file, we'll find out when we
1691	 * try to open or get attributes.
1692	 */
1693	va.va_mask = AT_TYPE | AT_MODE;
1694	error = smbfsgetattr(dvp, &va, cr);
1695	if (error) {
1696#ifdef DEBUG
1697		smbfs_lookup_cache_error++;
1698#endif
1699		return (error);
1700	}
1701
1702	/*
1703	 * Passing NULL smbfattr here so we will
1704	 * just look, not create.
1705	 */
1706	sep = SMBFS_DNP_SEP(dnp);
1707	np = smbfs_node_findcreate(dnp->n_mount,
1708	    dnp->n_rpath, dnp->n_rplen,
1709	    nm, nmlen, sep, NULL);
1710	if (np == NULL) {
1711#ifdef DEBUG
1712		smbfs_lookup_cache_miss++;
1713#endif
1714		return (0);
1715	}
1716
1717	/*
1718	 * Found it.  Attributes still valid?
1719	 */
1720	vp = SMBTOV(np);
1721	if (np->r_attrtime <= gethrtime()) {
1722		/* stale */
1723#ifdef DEBUG
1724		smbfs_lookup_cache_stale++;
1725#endif
1726		VN_RELE(vp);
1727		return (0);
1728	}
1729
1730	/*
1731	 * Success!
1732	 * Caller gets hold from smbfs_node_findcreate
1733	 */
1734#ifdef DEBUG
1735	smbfs_lookup_cache_hits++;
1736#endif
1737	*vpp = vp;
1738	return (0);
1739}
1740
1741/*
1742 * XXX
1743 * vsecattr_t is new to build 77, and we need to eventually support
1744 * it in order to create an ACL when an object is created.
1745 *
1746 * This op should support the new FIGNORECASE flag for case-insensitive
1747 * lookups, per PSARC 2007/244.
1748 */
1749/* ARGSUSED */
1750static int
1751smbfs_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive,
1752	int mode, vnode_t **vpp, cred_t *cr, int lfaware, caller_context_t *ct,
1753	vsecattr_t *vsecp)
1754{
1755	int		error;
1756	int		cerror;
1757	vfs_t		*vfsp;
1758	vnode_t		*vp;
1759#ifdef NOT_YET
1760	smbnode_t	*np;
1761#endif
1762	smbnode_t	*dnp;
1763	smbmntinfo_t	*smi;
1764	struct vattr	vattr;
1765	struct smbfattr	fattr;
1766	struct smb_cred	scred;
1767	const char *name = (const char *)nm;
1768	int		nmlen = strlen(nm);
1769	uint32_t	disp;
1770	uint16_t	fid;
1771	int		xattr;
1772
1773	vfsp = dvp->v_vfsp;
1774	smi = VFTOSMI(vfsp);
1775	dnp = VTOSMB(dvp);
1776	vp = NULL;
1777
1778	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
1779		return (EPERM);
1780
1781	if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
1782		return (EIO);
1783
1784	/*
1785	 * Note: this may break mknod(2) calls to create a directory,
1786	 * but that's obscure use.  Some other filesystems do this.
1787	 * XXX: Later, redirect VDIR type here to _mkdir.
1788	 */
1789	if (va->va_type != VREG)
1790		return (EINVAL);
1791
1792	/*
1793	 * If the pathname is "", just use dvp, no checks.
1794	 * Do this outside of the rwlock (like zfs).
1795	 */
1796	if (nmlen == 0) {
1797		VN_HOLD(dvp);
1798		*vpp = dvp;
1799		return (0);
1800	}
1801
1802	/* Don't allow "." or ".." through here. */
1803	if ((nmlen == 1 && name[0] == '.') ||
1804	    (nmlen == 2 && name[0] == '.' && name[1] == '.'))
1805		return (EISDIR);
1806
1807	/*
1808	 * We make a copy of the attributes because the caller does not
1809	 * expect us to change what va points to.
1810	 */
1811	vattr = *va;
1812
1813	if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
1814		return (EINTR);
1815	smb_credinit(&scred, cr);
1816
1817	/*
1818	 * XXX: Do we need r_lkserlock too?
1819	 * No use of any shared fid or fctx...
1820	 */
1821
1822	/*
1823	 * NFS needs to go over the wire, just to be sure whether the
1824	 * file exists or not.  Using a cached result is dangerous in
1825	 * this case when making a decision regarding existence.
1826	 *
1827	 * The SMB protocol does NOT really need to go OTW here
1828	 * thanks to the expressive NTCREATE disposition values.
1829	 * Unfortunately, to do Unix access checks correctly,
1830	 * we need to know if the object already exists.
1831	 * When the object does not exist, we need VWRITE on
1832	 * the directory.  Note: smbfslookup() checks VEXEC.
1833	 */
1834	error = smbfslookup(dvp, nm, &vp, cr, 0, ct);
1835	if (error == 0) {
1836		/*
1837		 * The file already exists.  Error?
1838		 * NB: have a hold from smbfslookup
1839		 */
1840		if (exclusive == EXCL) {
1841			error = EEXIST;
1842			VN_RELE(vp);
1843			goto out;
1844		}
1845		/*
1846		 * Verify requested access.
1847		 */
1848		error = smbfs_access(vp, mode, 0, cr, ct);
1849		if (error) {
1850			VN_RELE(vp);
1851			goto out;
1852		}
1853
1854		/*
1855		 * Truncate (if requested).
1856		 */
1857		if ((vattr.va_mask & AT_SIZE) && vattr.va_size == 0) {
1858			vattr.va_mask = AT_SIZE;
1859			error = smbfssetattr(vp, &vattr, 0, cr);
1860			if (error) {
1861				VN_RELE(vp);
1862				goto out;
1863			}
1864		}
1865		/* Success! */
1866#ifdef NOT_YET
1867		vnevent_create(vp, ct);
1868#endif
1869		*vpp = vp;
1870		goto out;
1871	}
1872
1873	/*
1874	 * The file did not exist.  Need VWRITE in the directory.
1875	 */
1876	error = smbfs_access(dvp, VWRITE, 0, cr, ct);
1877	if (error)
1878		goto out;
1879
1880	/*
1881	 * Now things get tricky.  We also need to check the
1882	 * requested open mode against the file we may create.
1883	 * See comments at smbfs_access_rwx
1884	 */
1885	error = smbfs_access_rwx(vfsp, VREG, mode, cr);
1886	if (error)
1887		goto out;
1888
1889	/*
1890	 * Now the code derived from Darwin,
1891	 * but with greater use of NT_CREATE
1892	 * disposition options.  Much changed.
1893	 *
1894	 * Create (or open) a new child node.
1895	 * Note we handled "." and ".." above.
1896	 */
1897
1898	if (exclusive == EXCL)
1899		disp = NTCREATEX_DISP_CREATE;
1900	else {
1901		/* Truncate regular files if requested. */
1902		if ((va->va_type == VREG) &&
1903		    (va->va_mask & AT_SIZE) &&
1904		    (va->va_size == 0))
1905			disp = NTCREATEX_DISP_OVERWRITE_IF;
1906		else
1907			disp = NTCREATEX_DISP_OPEN_IF;
1908	}
1909	xattr = (dnp->n_flag & N_XATTR) ? 1 : 0;
1910	error = smbfs_smb_create(dnp,
1911	    name, nmlen, xattr,
1912	    disp, &scred, &fid);
1913	if (error)
1914		goto out;
1915
1916	/*
1917	 * XXX: Missing some code here to deal with
1918	 * the case where we opened an existing file,
1919	 * it's size is larger than 32-bits, and we're
1920	 * setting the size from a process that's not
1921	 * aware of large file offsets.  i.e.
1922	 * from the NFS3 code:
1923	 */
1924#if NOT_YET /* XXX */
1925	if ((vattr.va_mask & AT_SIZE) &&
1926	    vp->v_type == VREG) {
1927		np = VTOSMB(vp);
1928		/*
1929		 * Check here for large file handled
1930		 * by LF-unaware process (as
1931		 * ufs_create() does)
1932		 */
1933		if (!(lfaware & FOFFMAX)) {
1934			mutex_enter(&np->r_statelock);
1935			if (np->r_size > MAXOFF32_T)
1936				error = EOVERFLOW;
1937			mutex_exit(&np->r_statelock);
1938		}
1939		if (!error) {
1940			vattr.va_mask = AT_SIZE;
1941			error = smbfssetattr(vp,
1942			    &vattr, 0, cr);
1943		}
1944	}
1945#endif /* XXX */
1946	/*
1947	 * Should use the fid to get/set the size
1948	 * while we have it opened here.  See above.
1949	 */
1950
1951	cerror = smbfs_smb_close(smi->smi_share, fid, NULL, &scred);
1952	if (cerror)
1953		SMBVDEBUG("error %d closing %s\\%s\n",
1954		    cerror, dnp->n_rpath, name);
1955
1956	/*
1957	 * In the open case, the name may differ a little
1958	 * from what we passed to create (case, etc.)
1959	 * so call lookup to get the (opened) name.
1960	 *
1961	 * XXX: Could avoid this extra lookup if the
1962	 * "createact" result from NT_CREATE says we
1963	 * created the object.
1964	 */
1965	error = smbfs_smb_lookup(dnp, &name, &nmlen, &fattr, &scred);
1966	if (error)
1967		goto out;
1968
1969	/* update attr and directory cache */
1970	smbfs_attr_touchdir(dnp);
1971
1972	error = smbfs_nget(dvp, name, nmlen, &fattr, &vp);
1973	if (error)
1974		goto out;
1975
1976	/* XXX invalidate pages if we truncated? */
1977
1978	/* Success! */
1979	*vpp = vp;
1980	error = 0;
1981
1982out:
1983	smb_credrele(&scred);
1984	smbfs_rw_exit(&dnp->r_rwlock);
1985	if (name != nm)
1986		smbfs_name_free(name, nmlen);
1987	return (error);
1988}
1989
1990/*
1991 * XXX
1992 * This op should support the new FIGNORECASE flag for case-insensitive
1993 * lookups, per PSARC 2007/244.
1994 */
1995/* ARGSUSED */
1996static int
1997smbfs_remove(vnode_t *dvp, char *nm, cred_t *cr, caller_context_t *ct,
1998	int flags)
1999{
2000	int		error;
2001	vnode_t		*vp;
2002	smbnode_t	*np;
2003	smbnode_t	*dnp;
2004	struct smb_cred	scred;
2005	/* enum smbfsstat status; */
2006	smbmntinfo_t	*smi;
2007
2008	smi = VTOSMI(dvp);
2009
2010	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
2011		return (EPERM);
2012
2013	if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2014		return (EIO);
2015
2016	dnp = VTOSMB(dvp);
2017	if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
2018		return (EINTR);
2019	smb_credinit(&scred, cr);
2020
2021	/*
2022	 * Verify access to the dirctory.
2023	 */
2024	error = smbfs_access(dvp, VWRITE|VEXEC, 0, cr, ct);
2025	if (error)
2026		goto out;
2027
2028	/*
2029	 * NOTE:  the darwin code gets the "vp" passed in so it looks
2030	 * like the "vp" has probably been "lookup"ed by the VFS layer.
2031	 * It looks like we will need to lookup the vp to check the
2032	 * caches and check if the object being deleted is a directory.
2033	 */
2034	error = smbfslookup(dvp, nm, &vp, cr, 0, ct);
2035	if (error)
2036		goto out;
2037
2038	/* Never allow link/unlink directories on CIFS. */
2039	if (vp->v_type == VDIR) {
2040		VN_RELE(vp);
2041		error = EPERM;
2042		goto out;
2043	}
2044
2045	/*
2046	 * Now we have the real reference count on the vnode
2047	 * Do we have the file open?
2048	 */
2049	np = VTOSMB(vp);
2050	mutex_enter(&np->r_statelock);
2051	if ((vp->v_count > 1) && (np->n_fidrefs > 0)) {
2052		/*
2053		 * NFS does a rename on remove here.
2054		 * Probably not applicable for SMB.
2055		 * Like Darwin, just return EBUSY.
2056		 *
2057		 * XXX: Todo - Use Trans2rename, and
2058		 * if that fails, ask the server to
2059		 * set the delete-on-close flag.
2060		 */
2061		mutex_exit(&np->r_statelock);
2062		error = EBUSY;
2063	} else {
2064		smbfs_attrcache_rm_locked(np);
2065		mutex_exit(&np->r_statelock);
2066
2067		error = smbfs_smb_delete(np, &scred, NULL, 0, 0);
2068
2069		/*
2070		 * If the file should no longer exist, discard
2071		 * any cached attributes under this node.
2072		 */
2073		switch (error) {
2074		case 0:
2075		case ENOENT:
2076		case ENOTDIR:
2077			smbfs_attrcache_prune(np);
2078			break;
2079		}
2080	}
2081
2082	VN_RELE(vp);
2083
2084out:
2085	smb_credrele(&scred);
2086	smbfs_rw_exit(&dnp->r_rwlock);
2087
2088	return (error);
2089}
2090
2091
2092/*
2093 * XXX
2094 * This op should support the new FIGNORECASE flag for case-insensitive
2095 * lookups, per PSARC 2007/244.
2096 */
2097/* ARGSUSED */
2098static int
2099smbfs_rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr,
2100	caller_context_t *ct, int flags)
2101{
2102	/* vnode_t		*realvp; */
2103
2104	if (curproc->p_zone != VTOSMI(odvp)->smi_zone_ref.zref_zone ||
2105	    curproc->p_zone != VTOSMI(ndvp)->smi_zone_ref.zref_zone)
2106		return (EPERM);
2107
2108	if (VTOSMI(odvp)->smi_flags & SMI_DEAD ||
2109	    VTOSMI(ndvp)->smi_flags & SMI_DEAD ||
2110	    odvp->v_vfsp->vfs_flag & VFS_UNMOUNTED ||
2111	    ndvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2112		return (EIO);
2113
2114	return (smbfsrename(odvp, onm, ndvp, nnm, cr, ct));
2115}
2116
2117/*
2118 * smbfsrename does the real work of renaming in SMBFS
2119 */
2120/* ARGSUSED */
2121static int
2122smbfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr,
2123	caller_context_t *ct)
2124{
2125	int		error;
2126	int		nvp_locked = 0;
2127	vnode_t		*nvp = NULL;
2128	vnode_t		*ovp = NULL;
2129	smbnode_t	*onp;
2130	smbnode_t	*nnp;
2131	smbnode_t	*odnp;
2132	smbnode_t	*ndnp;
2133	struct smb_cred	scred;
2134	/* enum smbfsstat	status; */
2135
2136	ASSERT(curproc->p_zone == VTOSMI(odvp)->smi_zone_ref.zref_zone);
2137
2138	if (strcmp(onm, ".") == 0 || strcmp(onm, "..") == 0 ||
2139	    strcmp(nnm, ".") == 0 || strcmp(nnm, "..") == 0)
2140		return (EINVAL);
2141
2142	/*
2143	 * Check that everything is on the same filesystem.
2144	 * vn_rename checks the fsid's, but in case we don't
2145	 * fill those in correctly, check here too.
2146	 */
2147	if (odvp->v_vfsp != ndvp->v_vfsp)
2148		return (EXDEV);
2149
2150	odnp = VTOSMB(odvp);
2151	ndnp = VTOSMB(ndvp);
2152
2153	/*
2154	 * Avoid deadlock here on old vs new directory nodes
2155	 * by always taking the locks in order of address.
2156	 * The order is arbitrary, but must be consistent.
2157	 */
2158	if (odnp < ndnp) {
2159		if (smbfs_rw_enter_sig(&odnp->r_rwlock, RW_WRITER,
2160		    SMBINTR(odvp)))
2161			return (EINTR);
2162		if (smbfs_rw_enter_sig(&ndnp->r_rwlock, RW_WRITER,
2163		    SMBINTR(ndvp))) {
2164			smbfs_rw_exit(&odnp->r_rwlock);
2165			return (EINTR);
2166		}
2167	} else {
2168		if (smbfs_rw_enter_sig(&ndnp->r_rwlock, RW_WRITER,
2169		    SMBINTR(ndvp)))
2170			return (EINTR);
2171		if (smbfs_rw_enter_sig(&odnp->r_rwlock, RW_WRITER,
2172		    SMBINTR(odvp))) {
2173			smbfs_rw_exit(&ndnp->r_rwlock);
2174			return (EINTR);
2175		}
2176	}
2177	smb_credinit(&scred, cr);
2178	/*
2179	 * No returns after this point (goto out)
2180	 */
2181
2182	/*
2183	 * Need write access on source and target.
2184	 * Server takes care of most checks.
2185	 */
2186	error = smbfs_access(odvp, VWRITE|VEXEC, 0, cr, ct);
2187	if (error)
2188		goto out;
2189	if (odvp != ndvp) {
2190		error = smbfs_access(ndvp, VWRITE, 0, cr, ct);
2191		if (error)
2192			goto out;
2193	}
2194
2195	/*
2196	 * Lookup the source name.  Must already exist.
2197	 */
2198	error = smbfslookup(odvp, onm, &ovp, cr, 0, ct);
2199	if (error)
2200		goto out;
2201
2202	/*
2203	 * Lookup the target file.  If it exists, it needs to be
2204	 * checked to see whether it is a mount point and whether
2205	 * it is active (open).
2206	 */
2207	error = smbfslookup(ndvp, nnm, &nvp, cr, 0, ct);
2208	if (!error) {
2209		/*
2210		 * Target (nvp) already exists.  Check that it
2211		 * has the same type as the source.  The server
2212		 * will check this also, (and more reliably) but
2213		 * this lets us return the correct error codes.
2214		 */
2215		if (ovp->v_type == VDIR) {
2216			if (nvp->v_type != VDIR) {
2217				error = ENOTDIR;
2218				goto out;
2219			}
2220		} else {
2221			if (nvp->v_type == VDIR) {
2222				error = EISDIR;
2223				goto out;
2224			}
2225		}
2226
2227		/*
2228		 * POSIX dictates that when the source and target
2229		 * entries refer to the same file object, rename
2230		 * must do nothing and exit without error.
2231		 */
2232		if (ovp == nvp) {
2233			error = 0;
2234			goto out;
2235		}
2236
2237		/*
2238		 * Also must ensure the target is not a mount point,
2239		 * and keep mount/umount away until we're done.
2240		 */
2241		if (vn_vfsrlock(nvp)) {
2242			error = EBUSY;
2243			goto out;
2244		}
2245		nvp_locked = 1;
2246		if (vn_mountedvfs(nvp) != NULL) {
2247			error = EBUSY;
2248			goto out;
2249		}
2250
2251		/*
2252		 * CIFS gives a SHARING_VIOLATION error when
2253		 * trying to rename onto an exising object,
2254		 * so try to remove the target first.
2255		 * (Only for files, not directories.)
2256		 */
2257		if (nvp->v_type == VDIR) {
2258			error = EEXIST;
2259			goto out;
2260		}
2261
2262		/*
2263		 * Nodes that are "not active" here have v_count=2
2264		 * because vn_renameat (our caller) did a lookup on
2265		 * both the source and target before this call.
2266		 * Otherwise this similar to smbfs_remove.
2267		 */
2268		nnp = VTOSMB(nvp);
2269		mutex_enter(&nnp->r_statelock);
2270		if ((nvp->v_count > 2) && (nnp->n_fidrefs > 0)) {
2271			/*
2272			 * The target file exists, is not the same as
2273			 * the source file, and is active.  Other FS
2274			 * implementations unlink the target here.
2275			 * For SMB, we don't assume we can remove an
2276			 * open file.  Return an error instead.
2277			 */
2278			mutex_exit(&nnp->r_statelock);
2279			error = EBUSY;
2280			goto out;
2281		}
2282
2283		/*
2284		 * Target file is not active. Try to remove it.
2285		 */
2286		smbfs_attrcache_rm_locked(nnp);
2287		mutex_exit(&nnp->r_statelock);
2288
2289		error = smbfs_smb_delete(nnp, &scred, NULL, 0, 0);
2290
2291		/*
2292		 * Similar to smbfs_remove
2293		 */
2294		switch (error) {
2295		case 0:
2296		case ENOENT:
2297		case ENOTDIR:
2298			smbfs_attrcache_prune(nnp);
2299			break;
2300		}
2301
2302		if (error)
2303			goto out;
2304		/*
2305		 * OK, removed the target file.  Continue as if
2306		 * lookup target had failed (nvp == NULL).
2307		 */
2308		vn_vfsunlock(nvp);
2309		nvp_locked = 0;
2310		VN_RELE(nvp);
2311		nvp = NULL;
2312	} /* nvp */
2313
2314	onp = VTOSMB(ovp);
2315	smbfs_attrcache_remove(onp);
2316
2317	error = smbfs_smb_rename(onp, ndnp, nnm, strlen(nnm), &scred);
2318
2319	/*
2320	 * If the old name should no longer exist,
2321	 * discard any cached attributes under it.
2322	 */
2323	if (error == 0)
2324		smbfs_attrcache_prune(onp);
2325
2326out:
2327	if (nvp) {
2328		if (nvp_locked)
2329			vn_vfsunlock(nvp);
2330		VN_RELE(nvp);
2331	}
2332	if (ovp)
2333		VN_RELE(ovp);
2334
2335	smb_credrele(&scred);
2336	smbfs_rw_exit(&odnp->r_rwlock);
2337	smbfs_rw_exit(&ndnp->r_rwlock);
2338
2339	return (error);
2340}
2341
2342/*
2343 * XXX
2344 * vsecattr_t is new to build 77, and we need to eventually support
2345 * it in order to create an ACL when an object is created.
2346 *
2347 * This op should support the new FIGNORECASE flag for case-insensitive
2348 * lookups, per PSARC 2007/244.
2349 */
2350/* ARGSUSED */
2351static int
2352smbfs_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp,
2353	cred_t *cr, caller_context_t *ct, int flags, vsecattr_t *vsecp)
2354{
2355	vnode_t		*vp;
2356	struct smbnode	*dnp = VTOSMB(dvp);
2357	struct smbmntinfo *smi = VTOSMI(dvp);
2358	struct smb_cred	scred;
2359	struct smbfattr	fattr;
2360	const char		*name = (const char *) nm;
2361	int		nmlen = strlen(name);
2362	int		error, hiderr;
2363
2364	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
2365		return (EPERM);
2366
2367	if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2368		return (EIO);
2369
2370	if ((nmlen == 1 && name[0] == '.') ||
2371	    (nmlen == 2 && name[0] == '.' && name[1] == '.'))
2372		return (EEXIST);
2373
2374	/* Only plain files are allowed in V_XATTRDIR. */
2375	if (dvp->v_flag & V_XATTRDIR)
2376		return (EINVAL);
2377
2378	if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
2379		return (EINTR);
2380	smb_credinit(&scred, cr);
2381
2382	/*
2383	 * XXX: Do we need r_lkserlock too?
2384	 * No use of any shared fid or fctx...
2385	 */
2386
2387	/*
2388	 * Require write access in the containing directory.
2389	 */
2390	error = smbfs_access(dvp, VWRITE, 0, cr, ct);
2391	if (error)
2392		goto out;
2393
2394	error = smbfs_smb_mkdir(dnp, name, nmlen, &scred);
2395	if (error)
2396		goto out;
2397
2398	error = smbfs_smb_lookup(dnp, &name, &nmlen, &fattr, &scred);
2399	if (error)
2400		goto out;
2401
2402	smbfs_attr_touchdir(dnp);
2403
2404	error = smbfs_nget(dvp, name, nmlen, &fattr, &vp);
2405	if (error)
2406		goto out;
2407
2408	if (name[0] == '.')
2409		if ((hiderr = smbfs_smb_hideit(VTOSMB(vp), NULL, 0, &scred)))
2410			SMBVDEBUG("hide failure %d\n", hiderr);
2411
2412	/* Success! */
2413	*vpp = vp;
2414	error = 0;
2415out:
2416	smb_credrele(&scred);
2417	smbfs_rw_exit(&dnp->r_rwlock);
2418
2419	if (name != nm)
2420		smbfs_name_free(name, nmlen);
2421
2422	return (error);
2423}
2424
2425/*
2426 * XXX
2427 * This op should support the new FIGNORECASE flag for case-insensitive
2428 * lookups, per PSARC 2007/244.
2429 */
2430/* ARGSUSED */
2431static int
2432smbfs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr,
2433	caller_context_t *ct, int flags)
2434{
2435	vnode_t		*vp = NULL;
2436	int		vp_locked = 0;
2437	struct smbmntinfo *smi = VTOSMI(dvp);
2438	struct smbnode	*dnp = VTOSMB(dvp);
2439	struct smbnode	*np;
2440	struct smb_cred	scred;
2441	int		error;
2442
2443	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
2444		return (EPERM);
2445
2446	if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2447		return (EIO);
2448
2449	if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
2450		return (EINTR);
2451	smb_credinit(&scred, cr);
2452
2453	/*
2454	 * Require w/x access in the containing directory.
2455	 * Server handles all other access checks.
2456	 */
2457	error = smbfs_access(dvp, VEXEC|VWRITE, 0, cr, ct);
2458	if (error)
2459		goto out;
2460
2461	/*
2462	 * First lookup the entry to be removed.
2463	 */
2464	error = smbfslookup(dvp, nm, &vp, cr, 0, ct);
2465	if (error)
2466		goto out;
2467	np = VTOSMB(vp);
2468
2469	/*
2470	 * Disallow rmdir of "." or current dir, or the FS root.
2471	 * Also make sure it's a directory, not a mount point,
2472	 * and lock to keep mount/umount away until we're done.
2473	 */
2474	if ((vp == dvp) || (vp == cdir) || (vp->v_flag & VROOT)) {
2475		error = EINVAL;
2476		goto out;
2477	}
2478	if (vp->v_type != VDIR) {
2479		error = ENOTDIR;
2480		goto out;
2481	}
2482	if (vn_vfsrlock(vp)) {
2483		error = EBUSY;
2484		goto out;
2485	}
2486	vp_locked = 1;
2487	if (vn_mountedvfs(vp) != NULL) {
2488		error = EBUSY;
2489		goto out;
2490	}
2491
2492	smbfs_attrcache_remove(np);
2493	error = smbfs_smb_rmdir(np, &scred);
2494
2495	/*
2496	 * Similar to smbfs_remove
2497	 */
2498	switch (error) {
2499	case 0:
2500	case ENOENT:
2501	case ENOTDIR:
2502		smbfs_attrcache_prune(np);
2503		break;
2504	}
2505
2506	if (error)
2507		goto out;
2508
2509	mutex_enter(&np->r_statelock);
2510	dnp->n_flag |= NMODIFIED;
2511	mutex_exit(&np->r_statelock);
2512	smbfs_attr_touchdir(dnp);
2513	smbfs_rmhash(np);
2514
2515out:
2516	if (vp) {
2517		if (vp_locked)
2518			vn_vfsunlock(vp);
2519		VN_RELE(vp);
2520	}
2521	smb_credrele(&scred);
2522	smbfs_rw_exit(&dnp->r_rwlock);
2523
2524	return (error);
2525}
2526
2527
2528/* ARGSUSED */
2529static int
2530smbfs_readdir(vnode_t *vp, struct uio *uiop, cred_t *cr, int *eofp,
2531	caller_context_t *ct, int flags)
2532{
2533	struct smbnode	*np = VTOSMB(vp);
2534	int		error = 0;
2535	smbmntinfo_t	*smi;
2536
2537	smi = VTOSMI(vp);
2538
2539	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
2540		return (EIO);
2541
2542	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2543		return (EIO);
2544
2545	/*
2546	 * Require read access in the directory.
2547	 */
2548	error = smbfs_access(vp, VREAD, 0, cr, ct);
2549	if (error)
2550		return (error);
2551
2552	ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_READER));
2553
2554	/*
2555	 * XXX: Todo readdir cache here
2556	 * Note: NFS code is just below this.
2557	 *
2558	 * I am serializing the entire readdir opreation
2559	 * now since we have not yet implemented readdir
2560	 * cache. This fix needs to be revisited once
2561	 * we implement readdir cache.
2562	 */
2563	if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, SMBINTR(vp)))
2564		return (EINTR);
2565
2566	error = smbfs_readvdir(vp, uiop, cr, eofp, ct);
2567
2568	smbfs_rw_exit(&np->r_lkserlock);
2569
2570	return (error);
2571}
2572
2573/* ARGSUSED */
2574static int
2575smbfs_readvdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp,
2576	caller_context_t *ct)
2577{
2578	/*
2579	 * Note: "limit" tells the SMB-level FindFirst/FindNext
2580	 * functions how many directory entries to request in
2581	 * each OtW call.  It needs to be large enough so that
2582	 * we don't make lots of tiny OtW requests, but there's
2583	 * no point making it larger than the maximum number of
2584	 * OtW entries that would fit in a maximum sized trans2
2585	 * response (64k / 48).  Beyond that, it's just tuning.
2586	 * WinNT used 512, Win2k used 1366.  We use 1000.
2587	 */
2588	static const int limit = 1000;
2589	/* Largest possible dirent size. */
2590	static const size_t dbufsiz = DIRENT64_RECLEN(SMB_MAXFNAMELEN);
2591	struct smb_cred scred;
2592	vnode_t		*newvp;
2593	struct smbnode	*np = VTOSMB(vp);
2594	struct smbfs_fctx *ctx;
2595	struct dirent64 *dp;
2596	ssize_t		save_resid;
2597	offset_t	save_offset; /* 64 bits */
2598	int		offset; /* yes, 32 bits */
2599	int		nmlen, error;
2600	ushort_t	reclen;
2601
2602	ASSERT(curproc->p_zone == VTOSMI(vp)->smi_zone_ref.zref_zone);
2603
2604	/* Make sure we serialize for n_dirseq use. */
2605	ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_WRITER));
2606
2607	/*
2608	 * Make sure smbfs_open filled in n_dirseq
2609	 */
2610	if (np->n_dirseq == NULL)
2611		return (EBADF);
2612
2613	/* Check for overflow of (32-bit) directory offset. */
2614	if (uio->uio_loffset < 0 || uio->uio_loffset > INT32_MAX ||
2615	    (uio->uio_loffset + uio->uio_resid) > INT32_MAX)
2616		return (EINVAL);
2617
2618	/* Require space for at least one dirent. */
2619	if (uio->uio_resid < dbufsiz)
2620		return (EINVAL);
2621
2622	SMBVDEBUG("dirname='%s'\n", np->n_rpath);
2623	smb_credinit(&scred, cr);
2624	dp = kmem_alloc(dbufsiz, KM_SLEEP);
2625
2626	save_resid = uio->uio_resid;
2627	save_offset = uio->uio_loffset;
2628	offset = uio->uio_offset;
2629	SMBVDEBUG("in: offset=%d, resid=%d\n",
2630	    (int)uio->uio_offset, (int)uio->uio_resid);
2631	error = 0;
2632
2633	/*
2634	 * Generate the "." and ".." entries here so we can
2635	 * (1) make sure they appear (but only once), and
2636	 * (2) deal with getting their I numbers which the
2637	 * findnext below does only for normal names.
2638	 */
2639	while (offset < FIRST_DIROFS) {
2640		/*
2641		 * Tricky bit filling in the first two:
2642		 * offset 0 is ".", offset 1 is ".."
2643		 * so strlen of these is offset+1.
2644		 */
2645		reclen = DIRENT64_RECLEN(offset + 1);
2646		if (uio->uio_resid < reclen)
2647			goto out;
2648		bzero(dp, reclen);
2649		dp->d_reclen = reclen;
2650		dp->d_name[0] = '.';
2651		dp->d_name[1] = '.';
2652		dp->d_name[offset + 1] = '\0';
2653		/*
2654		 * Want the real I-numbers for the "." and ".."
2655		 * entries.  For these two names, we know that
2656		 * smbfslookup can get the nodes efficiently.
2657		 */
2658		error = smbfslookup(vp, dp->d_name, &newvp, cr, 1, ct);
2659		if (error) {
2660			dp->d_ino = np->n_ino + offset; /* fiction */
2661		} else {
2662			dp->d_ino = VTOSMB(newvp)->n_ino;
2663			VN_RELE(newvp);
2664		}
2665		/*
2666		 * Note: d_off is the offset that a user-level program
2667		 * should seek to for reading the NEXT directory entry.
2668		 * See libc: readdir, telldir, seekdir
2669		 */
2670		dp->d_off = offset + 1;
2671		error = uiomove(dp, reclen, UIO_READ, uio);
2672		if (error)
2673			goto out;
2674		/*
2675		 * Note: uiomove updates uio->uio_offset,
2676		 * but we want it to be our "cookie" value,
2677		 * which just counts dirents ignoring size.
2678		 */
2679		uio->uio_offset = ++offset;
2680	}
2681
2682	/*
2683	 * If there was a backward seek, we have to reopen.
2684	 */
2685	if (offset < np->n_dirofs) {
2686		SMBVDEBUG("Reopening search %d:%d\n",
2687		    offset, np->n_dirofs);
2688		error = smbfs_smb_findopen(np, "*", 1,
2689		    SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR,
2690		    &scred, &ctx);
2691		if (error) {
2692			SMBVDEBUG("can not open search, error = %d", error);
2693			goto out;
2694		}
2695		/* free the old one */
2696		(void) smbfs_smb_findclose(np->n_dirseq, &scred);
2697		/* save the new one */
2698		np->n_dirseq = ctx;
2699		np->n_dirofs = FIRST_DIROFS;
2700	} else {
2701		ctx = np->n_dirseq;
2702	}
2703
2704	/*
2705	 * Skip entries before the requested offset.
2706	 */
2707	while (np->n_dirofs < offset) {
2708		error = smbfs_smb_findnext(ctx, limit, &scred);
2709		if (error != 0)
2710			goto out;
2711		np->n_dirofs++;
2712	}
2713
2714	/*
2715	 * While there's room in the caller's buffer:
2716	 *	get a directory entry from SMB,
2717	 *	convert to a dirent, copyout.
2718	 * We stop when there is no longer room for a
2719	 * maximum sized dirent because we must decide
2720	 * before we know anything about the next entry.
2721	 */
2722	while (uio->uio_resid >= dbufsiz) {
2723		error = smbfs_smb_findnext(ctx, limit, &scred);
2724		if (error != 0)
2725			goto out;
2726		np->n_dirofs++;
2727
2728		/* Sanity check the name length. */
2729		nmlen = ctx->f_nmlen;
2730		if (nmlen > SMB_MAXFNAMELEN) {
2731			nmlen = SMB_MAXFNAMELEN;
2732			SMBVDEBUG("Truncating name: %s\n", ctx->f_name);
2733		}
2734		if (smbfs_fastlookup) {
2735			/* See comment at smbfs_fastlookup above. */
2736			if (smbfs_nget(vp, ctx->f_name, nmlen,
2737			    &ctx->f_attr, &newvp) == 0)
2738				VN_RELE(newvp);
2739		}
2740
2741		reclen = DIRENT64_RECLEN(nmlen);
2742		bzero(dp, reclen);
2743		dp->d_reclen = reclen;
2744		bcopy(ctx->f_name, dp->d_name, nmlen);
2745		dp->d_name[nmlen] = '\0';
2746		dp->d_ino = ctx->f_inum;
2747		dp->d_off = offset + 1;	/* See d_off comment above */
2748		error = uiomove(dp, reclen, UIO_READ, uio);
2749		if (error)
2750			goto out;
2751		/* See comment re. uio_offset above. */
2752		uio->uio_offset = ++offset;
2753	}
2754
2755out:
2756	/*
2757	 * When we come to the end of a directory, the
2758	 * SMB-level functions return ENOENT, but the
2759	 * caller is not expecting an error return.
2760	 *
2761	 * Also note that we must delay the call to
2762	 * smbfs_smb_findclose(np->n_dirseq, ...)
2763	 * until smbfs_close so that all reads at the
2764	 * end of the directory will return no data.
2765	 */
2766	if (error == ENOENT) {
2767		error = 0;
2768		if (eofp)
2769			*eofp = 1;
2770	}
2771	/*
2772	 * If we encountered an error (i.e. "access denied")
2773	 * from the FindFirst call, we will have copied out
2774	 * the "." and ".." entries leaving offset == 2.
2775	 * In that case, restore the original offset/resid
2776	 * so the caller gets no data with the error.
2777	 */
2778	if (error != 0 && offset == FIRST_DIROFS) {
2779		uio->uio_loffset = save_offset;
2780		uio->uio_resid = save_resid;
2781	}
2782	SMBVDEBUG("out: offset=%d, resid=%d\n",
2783	    (int)uio->uio_offset, (int)uio->uio_resid);
2784
2785	kmem_free(dp, dbufsiz);
2786	smb_credrele(&scred);
2787	return (error);
2788}
2789
2790
2791/*
2792 * The pair of functions VOP_RWLOCK, VOP_RWUNLOCK
2793 * are optional functions that are called by:
2794 *    getdents, before/after VOP_READDIR
2795 *    pread, before/after ... VOP_READ
2796 *    pwrite, before/after ... VOP_WRITE
2797 *    (other places)
2798 *
2799 * Careful here: None of the above check for any
2800 * error returns from VOP_RWLOCK / VOP_RWUNLOCK!
2801 * In fact, the return value from _rwlock is NOT
2802 * an error code, but V_WRITELOCK_TRUE / _FALSE.
2803 *
2804 * Therefore, it's up to _this_ code to make sure
2805 * the lock state remains balanced, which means
2806 * we can't "bail out" on interrupts, etc.
2807 */
2808
2809/* ARGSUSED2 */
2810static int
2811smbfs_rwlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
2812{
2813	smbnode_t	*np = VTOSMB(vp);
2814
2815	if (!write_lock) {
2816		(void) smbfs_rw_enter_sig(&np->r_rwlock, RW_READER, FALSE);
2817		return (V_WRITELOCK_FALSE);
2818	}
2819
2820
2821	(void) smbfs_rw_enter_sig(&np->r_rwlock, RW_WRITER, FALSE);
2822	return (V_WRITELOCK_TRUE);
2823}
2824
2825/* ARGSUSED */
2826static void
2827smbfs_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
2828{
2829	smbnode_t	*np = VTOSMB(vp);
2830
2831	smbfs_rw_exit(&np->r_rwlock);
2832}
2833
2834
2835/* ARGSUSED */
2836static int
2837smbfs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
2838{
2839	smbmntinfo_t	*smi;
2840
2841	smi = VTOSMI(vp);
2842
2843	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
2844		return (EPERM);
2845
2846	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2847		return (EIO);
2848
2849	/*
2850	 * Because we stuff the readdir cookie into the offset field
2851	 * someone may attempt to do an lseek with the cookie which
2852	 * we want to succeed.
2853	 */
2854	if (vp->v_type == VDIR)
2855		return (0);
2856
2857	/* Like NFS3, just check for 63-bit overflow. */
2858	if (*noffp < 0)
2859		return (EINVAL);
2860
2861	return (0);
2862}
2863
2864
2865/*
2866 * XXX
2867 * This op may need to support PSARC 2007/440, nbmand changes for CIFS Service.
2868 */
2869static int
2870smbfs_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
2871	offset_t offset, struct flk_callback *flk_cbp, cred_t *cr,
2872	caller_context_t *ct)
2873{
2874	if (curproc->p_zone != VTOSMI(vp)->smi_zone_ref.zref_zone)
2875		return (EIO);
2876
2877	if (VTOSMI(vp)->smi_flags & SMI_LLOCK)
2878		return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr, ct));
2879	else
2880		return (ENOSYS);
2881}
2882
2883/*
2884 * Free storage space associated with the specified vnode.  The portion
2885 * to be freed is specified by bfp->l_start and bfp->l_len (already
2886 * normalized to a "whence" of 0).
2887 *
2888 * Called by fcntl(fd, F_FREESP, lkp) for libc:ftruncate, etc.
2889 */
2890/* ARGSUSED */
2891static int
2892smbfs_space(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
2893	offset_t offset, cred_t *cr, caller_context_t *ct)
2894{
2895	int		error;
2896	smbmntinfo_t	*smi;
2897
2898	smi = VTOSMI(vp);
2899
2900	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
2901		return (EIO);
2902
2903	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2904		return (EIO);
2905
2906	/* Caller (fcntl) has checked v_type */
2907	ASSERT(vp->v_type == VREG);
2908	if (cmd != F_FREESP)
2909		return (EINVAL);
2910
2911	/*
2912	 * Like NFS3, no 32-bit offset checks here.
2913	 * Our SMB layer takes care to return EFBIG
2914	 * when it has to fallback to a 32-bit call.
2915	 */
2916
2917	error = convoff(vp, bfp, 0, offset);
2918	if (!error) {
2919		ASSERT(bfp->l_start >= 0);
2920		if (bfp->l_len == 0) {
2921			struct vattr va;
2922
2923			/*
2924			 * ftruncate should not change the ctime and
2925			 * mtime if we truncate the file to its
2926			 * previous size.
2927			 */
2928			va.va_mask = AT_SIZE;
2929			error = smbfsgetattr(vp, &va, cr);
2930			if (error || va.va_size == bfp->l_start)
2931				return (error);
2932			va.va_mask = AT_SIZE;
2933			va.va_size = bfp->l_start;
2934			error = smbfssetattr(vp, &va, 0, cr);
2935		} else
2936			error = EINVAL;
2937	}
2938
2939	return (error);
2940}
2941
2942/* ARGSUSED */
2943static int
2944smbfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
2945	caller_context_t *ct)
2946{
2947	vfs_t *vfs;
2948	smbmntinfo_t *smi;
2949	struct smb_share *ssp;
2950
2951	vfs = vp->v_vfsp;
2952	smi = VFTOSMI(vfs);
2953
2954	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
2955		return (EIO);
2956
2957	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2958		return (EIO);
2959
2960	switch (cmd) {
2961	case _PC_FILESIZEBITS:
2962		ssp = smi->smi_share;
2963		if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES)
2964			*valp = 64;
2965		else
2966			*valp = 32;
2967		break;
2968
2969	case _PC_LINK_MAX:
2970		/* We only ever report one link to an object */
2971		*valp = 1;
2972		break;
2973
2974	case _PC_ACL_ENABLED:
2975		/*
2976		 * Always indicate that ACLs are enabled and
2977		 * that we support ACE_T format, otherwise
2978		 * libsec will ask for ACLENT_T format data
2979		 * which we don't support.
2980		 */
2981		*valp = _ACL_ACE_ENABLED;
2982		break;
2983
2984	case _PC_SYMLINK_MAX:	/* No symlinks until we do Unix extensions */
2985		*valp = 0;
2986		break;
2987
2988	case _PC_XATTR_EXISTS:
2989		if (vfs->vfs_flag & VFS_XATTR) {
2990			*valp = smbfs_xa_exists(vp, cr);
2991			break;
2992		}
2993		return (EINVAL);
2994
2995	case _PC_TIMESTAMP_RESOLUTION:
2996		/*
2997		 * Windows times are tenths of microseconds
2998		 * (multiples of 100 nanoseconds).
2999		 */
3000		*valp = 100L;
3001		break;
3002
3003	default:
3004		return (fs_pathconf(vp, cmd, valp, cr, ct));
3005	}
3006	return (0);
3007}
3008
3009/* ARGSUSED */
3010static int
3011smbfs_getsecattr(vnode_t *vp, vsecattr_t *vsa, int flag, cred_t *cr,
3012	caller_context_t *ct)
3013{
3014	vfs_t *vfsp;
3015	smbmntinfo_t *smi;
3016	int	error;
3017	uint_t	mask;
3018
3019	vfsp = vp->v_vfsp;
3020	smi = VFTOSMI(vfsp);
3021
3022	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
3023		return (EIO);
3024
3025	if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
3026		return (EIO);
3027
3028	/*
3029	 * Our _pathconf indicates _ACL_ACE_ENABLED,
3030	 * so we should only see VSA_ACE, etc here.
3031	 * Note: vn_create asks for VSA_DFACLCNT,
3032	 * and it expects ENOSYS and empty data.
3033	 */
3034	mask = vsa->vsa_mask & (VSA_ACE | VSA_ACECNT |
3035	    VSA_ACE_ACLFLAGS | VSA_ACE_ALLTYPES);
3036	if (mask == 0)
3037		return (ENOSYS);
3038
3039	if (smi->smi_flags & SMI_ACL)
3040		error = smbfs_acl_getvsa(vp, vsa, flag, cr);
3041	else
3042		error = ENOSYS;
3043
3044	if (error == ENOSYS)
3045		error = fs_fab_acl(vp, vsa, flag, cr, ct);
3046
3047	return (error);
3048}
3049
3050/* ARGSUSED */
3051static int
3052smbfs_setsecattr(vnode_t *vp, vsecattr_t *vsa, int flag, cred_t *cr,
3053	caller_context_t *ct)
3054{
3055	vfs_t *vfsp;
3056	smbmntinfo_t *smi;
3057	int	error;
3058	uint_t	mask;
3059
3060	vfsp = vp->v_vfsp;
3061	smi = VFTOSMI(vfsp);
3062
3063	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
3064		return (EIO);
3065
3066	if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
3067		return (EIO);
3068
3069	/*
3070	 * Our _pathconf indicates _ACL_ACE_ENABLED,
3071	 * so we should only see VSA_ACE, etc here.
3072	 */
3073	mask = vsa->vsa_mask & (VSA_ACE | VSA_ACECNT);
3074	if (mask == 0)
3075		return (ENOSYS);
3076
3077	if (vfsp->vfs_flag & VFS_RDONLY)
3078		return (EROFS);
3079
3080	/*
3081	 * Allow only the mount owner to do this.
3082	 * See comments at smbfs_access_rwx.
3083	 */
3084	error = secpolicy_vnode_setdac(cr, smi->smi_uid);
3085	if (error != 0)
3086		return (error);
3087
3088	if (smi->smi_flags & SMI_ACL)
3089		error = smbfs_acl_setvsa(vp, vsa, flag, cr);
3090	else
3091		error = ENOSYS;
3092
3093	return (error);
3094}
3095
3096
3097/*
3098 * XXX
3099 * This op should eventually support PSARC 2007/268.
3100 */
3101static int
3102smbfs_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr,
3103	caller_context_t *ct)
3104{
3105	if (curproc->p_zone != VTOSMI(vp)->smi_zone_ref.zref_zone)
3106		return (EIO);
3107
3108	if (VTOSMI(vp)->smi_flags & SMI_LLOCK)
3109		return (fs_shrlock(vp, cmd, shr, flag, cr, ct));
3110	else
3111		return (ENOSYS);
3112}
3113