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