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