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