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