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