14bff34e3Sthurlow /*
24bff34e3Sthurlow  * Copyright (c) 2000-2001 Boris Popov
34bff34e3Sthurlow  * All rights reserved.
44bff34e3Sthurlow  *
54bff34e3Sthurlow  * Redistribution and use in source and binary forms, with or without
64bff34e3Sthurlow  * modification, are permitted provided that the following conditions
74bff34e3Sthurlow  * are met:
84bff34e3Sthurlow  * 1. Redistributions of source code must retain the above copyright
94bff34e3Sthurlow  *    notice, this list of conditions and the following disclaimer.
104bff34e3Sthurlow  * 2. Redistributions in binary form must reproduce the above copyright
114bff34e3Sthurlow  *    notice, this list of conditions and the following disclaimer in the
124bff34e3Sthurlow  *    documentation and/or other materials provided with the distribution.
134bff34e3Sthurlow  * 3. All advertising materials mentioning features or use of this software
144bff34e3Sthurlow  *    must display the following acknowledgement:
154bff34e3Sthurlow  *    This product includes software developed by Boris Popov.
164bff34e3Sthurlow  * 4. Neither the name of the author nor the names of any co-contributors
174bff34e3Sthurlow  *    may be used to endorse or promote products derived from this software
184bff34e3Sthurlow  *    without specific prior written permission.
194bff34e3Sthurlow  *
204bff34e3Sthurlow  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
214bff34e3Sthurlow  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
224bff34e3Sthurlow  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
234bff34e3Sthurlow  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
244bff34e3Sthurlow  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
254bff34e3Sthurlow  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
264bff34e3Sthurlow  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
274bff34e3Sthurlow  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
284bff34e3Sthurlow  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
294bff34e3Sthurlow  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
304bff34e3Sthurlow  * SUCH DAMAGE.
314bff34e3Sthurlow  *
324bff34e3Sthurlow  * $Id: smbfs_vnops.c,v 1.128.36.1 2005/05/27 02:35:28 lindak Exp $
334bff34e3Sthurlow  */
344bff34e3Sthurlow 
354bff34e3Sthurlow /*
36134a1f4eSCasper H.S. Dik  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
37*168091e5SGordon Ross  * Copyright 2021 Tintri by DDN, Inc.  All rights reserved.
384bff34e3Sthurlow  */
394bff34e3Sthurlow 
405f4fc069Sjilinxpd /*
415f4fc069Sjilinxpd  * Vnode operations
425f4fc069Sjilinxpd  *
435f4fc069Sjilinxpd  * This file is similar to nfs3_vnops.c
445f4fc069Sjilinxpd  */
455f4fc069Sjilinxpd 
465f4fc069Sjilinxpd #include <sys/param.h>
474bff34e3Sthurlow #include <sys/systm.h>
484bff34e3Sthurlow #include <sys/cred.h>
494bff34e3Sthurlow #include <sys/vnode.h>
504bff34e3Sthurlow #include <sys/vfs.h>
517568150aSgwr #include <sys/filio.h>
524bff34e3Sthurlow #include <sys/uio.h>
534bff34e3Sthurlow #include <sys/dirent.h>
544bff34e3Sthurlow #include <sys/errno.h>
55613a2f6bSGordon Ross #include <sys/sunddi.h>
564bff34e3Sthurlow #include <sys/sysmacros.h>
574bff34e3Sthurlow #include <sys/kmem.h>
584bff34e3Sthurlow #include <sys/cmn_err.h>
594bff34e3Sthurlow #include <sys/vfs_opreg.h>
604bff34e3Sthurlow #include <sys/policy.h>
615f4fc069Sjilinxpd #include <sys/sdt.h>
624e72ade1SGordon Ross #include <sys/taskq_impl.h>
635f4fc069Sjilinxpd #include <sys/zone.h>
645f4fc069Sjilinxpd 
658329232eSGordon Ross #ifdef	_KERNEL
668329232eSGordon Ross #include <sys/vmsystm.h>	// for desfree
675f4fc069Sjilinxpd #include <vm/hat.h>
685f4fc069Sjilinxpd #include <vm/as.h>
695f4fc069Sjilinxpd #include <vm/page.h>
705f4fc069Sjilinxpd #include <vm/pvn.h>
715f4fc069Sjilinxpd #include <vm/seg.h>
725f4fc069Sjilinxpd #include <vm/seg_map.h>
735f4fc069Sjilinxpd #include <vm/seg_kpm.h>
745f4fc069Sjilinxpd #include <vm/seg_vn.h>
758329232eSGordon Ross #endif	// _KERNEL
764bff34e3Sthurlow 
774bff34e3Sthurlow #include <netsmb/smb_osdep.h>
784bff34e3Sthurlow #include <netsmb/smb.h>
794bff34e3Sthurlow #include <netsmb/smb_conn.h>
804bff34e3Sthurlow #include <netsmb/smb_subr.h>
814bff34e3Sthurlow 
824bff34e3Sthurlow #include <smbfs/smbfs.h>
834bff34e3Sthurlow #include <smbfs/smbfs_node.h>
844bff34e3Sthurlow #include <smbfs/smbfs_subr.h>
854bff34e3Sthurlow 
867568150aSgwr #include <sys/fs/smbfs_ioctl.h>
874bff34e3Sthurlow #include <fs/fs_subr.h>
884bff34e3Sthurlow 
898329232eSGordon Ross #ifndef	MAXOFF32_T
908329232eSGordon Ross #define	MAXOFF32_T	0x7fffffff
918329232eSGordon Ross #endif
928329232eSGordon Ross 
935ecede33SGordon Ross /*
945ecede33SGordon Ross  * We assign directory offsets like the NFS client, where the
955ecede33SGordon Ross  * offset increments by _one_ after each directory entry.
965ecede33SGordon Ross  * Further, the entries "." and ".." are always at offsets
975ecede33SGordon Ross  * zero and one (respectively) and the "real" entries from
985ecede33SGordon Ross  * the server appear at offsets starting with two.  This
995ecede33SGordon Ross  * macro is used to initialize the n_dirofs field after
1005ecede33SGordon Ross  * setting n_dirseq with a _findopen call.
1015ecede33SGordon Ross  */
1025ecede33SGordon Ross #define	FIRST_DIROFS	2
1035ecede33SGordon Ross 
1044bff34e3Sthurlow /*
1054bff34e3Sthurlow  * These characters are illegal in NTFS file names.
1064bff34e3Sthurlow  * ref: http://support.microsoft.com/kb/147438
10791d632c8Sgwr  *
10891d632c8Sgwr  * Careful!  The check in the XATTR case skips the
10991d632c8Sgwr  * first character to allow colon in XATTR names.
1104bff34e3Sthurlow  */
1114bff34e3Sthurlow static const char illegal_chars[] = {
11291d632c8Sgwr 	':',	/* colon - keep this first! */
1134bff34e3Sthurlow 	'\\',	/* back slash */
1144bff34e3Sthurlow 	'/',	/* slash */
1154bff34e3Sthurlow 	'*',	/* asterisk */
1164bff34e3Sthurlow 	'?',	/* question mark */
1174bff34e3Sthurlow 	'"',	/* double quote */
1184bff34e3Sthurlow 	'<',	/* less than sign */
1194bff34e3Sthurlow 	'>',	/* greater than sign */
1204bff34e3Sthurlow 	'|',	/* vertical bar */
1214bff34e3Sthurlow 	0
1224bff34e3Sthurlow };
1234bff34e3Sthurlow 
1244bff34e3Sthurlow /*
1254bff34e3Sthurlow  * Turning this on causes nodes to be created in the cache
12602d09e03SGordon Ross  * during directory listings, normally avoiding a second
12702d09e03SGordon Ross  * OtW attribute fetch just after a readdir.
1284bff34e3Sthurlow  */
12902d09e03SGordon Ross int smbfs_fastlookup = 1;
1304bff34e3Sthurlow 
1315f4fc069Sjilinxpd struct vnodeops *smbfs_vnodeops = NULL;
1325f4fc069Sjilinxpd 
1334bff34e3Sthurlow /* local static function defines */
1344bff34e3Sthurlow 
13502d09e03SGordon Ross static int	smbfslookup_cache(vnode_t *, char *, int, vnode_t **,
13602d09e03SGordon Ross 			cred_t *);
1374bff34e3Sthurlow static int	smbfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr,
13802d09e03SGordon Ross 			int cache_ok, caller_context_t *);
139ff1e230cSjilinxpd static int	smbfsremove(vnode_t *dvp, vnode_t *vp, struct smb_cred *scred,
140ff1e230cSjilinxpd 			int flags);
141ff1e230cSjilinxpd static int	smbfsrename(vnode_t *odvp, vnode_t *ovp, vnode_t *ndvp,
142ff1e230cSjilinxpd 			char *nnm, struct smb_cred *scred, int flags);
1434bff34e3Sthurlow static int	smbfssetattr(vnode_t *, struct vattr *, int, cred_t *);
1444bff34e3Sthurlow static int	smbfs_accessx(void *, int, cred_t *);
1454bff34e3Sthurlow static int	smbfs_readvdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp,
1464bff34e3Sthurlow 			caller_context_t *);
147adee6784SGordon Ross static int	smbfsflush(smbnode_t *, struct smb_cred *);
14842d15982SGordon Ross static void	smbfs_rele_fid(smbnode_t *, struct smb_cred *);
14928162916SGordon Ross static uint32_t xvattr_to_dosattr(smbnode_t *, struct vattr *);
15042d15982SGordon Ross 
1515f4fc069Sjilinxpd static int	smbfs_fsync(vnode_t *, int, cred_t *, caller_context_t *);
1528329232eSGordon Ross 
1535f4fc069Sjilinxpd static int	smbfs_putpage(vnode_t *, offset_t, size_t, int, cred_t *,
1545f4fc069Sjilinxpd 			caller_context_t *);
1558329232eSGordon Ross #ifdef	_KERNEL
1565f4fc069Sjilinxpd static int	smbfs_getapage(vnode_t *, u_offset_t, size_t, uint_t *,
1575f4fc069Sjilinxpd 			page_t *[], size_t, struct seg *, caddr_t,
1585f4fc069Sjilinxpd 			enum seg_rw, cred_t *);
1595f4fc069Sjilinxpd static int	smbfs_putapage(vnode_t *, page_t *, u_offset_t *, size_t *,
1605f4fc069Sjilinxpd 			int, cred_t *);
1614e72ade1SGordon Ross static void	smbfs_delmap_async(void *);
1625f4fc069Sjilinxpd 
1638329232eSGordon Ross static int	smbfs_rdwrlbn(vnode_t *, page_t *, u_offset_t, size_t, int,
1648329232eSGordon Ross 			cred_t *);
1658329232eSGordon Ross static int	smbfs_bio(struct buf *, int, cred_t *);
1668329232eSGordon Ross static int	smbfs_writenp(smbnode_t *np, caddr_t base, int tcount,
1678329232eSGordon Ross 			struct uio *uiop, int pgcreated);
1688329232eSGordon Ross #endif	// _KERNEL
1698329232eSGordon Ross 
1705f4fc069Sjilinxpd /*
1715f4fc069Sjilinxpd  * Error flags used to pass information about certain special errors
1725f4fc069Sjilinxpd  * which need to be handled specially.
1735f4fc069Sjilinxpd  */
1745f4fc069Sjilinxpd #define	SMBFS_EOF			-98
1755f4fc069Sjilinxpd 
1765f4fc069Sjilinxpd /* When implementing OtW locks, make this a real function. */
1775f4fc069Sjilinxpd #define	smbfs_lm_has_sleep(vp) 0
1785f4fc069Sjilinxpd 
1794bff34e3Sthurlow /*
1804bff34e3Sthurlow  * These are the vnode ops routines which implement the vnode interface to
1814bff34e3Sthurlow  * the networked file system.  These routines just take their parameters,
1824bff34e3Sthurlow  * make them look networkish by putting the right info into interface structs,
1834bff34e3Sthurlow  * and then calling the appropriate remote routine(s) to do the work.
1844bff34e3Sthurlow  *
1854bff34e3Sthurlow  * Note on directory name lookup cacheing:  If we detect a stale fhandle,
1864bff34e3Sthurlow  * we purge the directory cache relative to that vnode.  This way, the
1874bff34e3Sthurlow  * user won't get burned by the cache repeatedly.  See <smbfs/smbnode.h> for
1884bff34e3Sthurlow  * more details on smbnode locking.
1894bff34e3Sthurlow  */
1904bff34e3Sthurlow 
1914bff34e3Sthurlow 
1924bff34e3Sthurlow /*
1934bff34e3Sthurlow  * XXX
1944bff34e3Sthurlow  * When new and relevant functionality is enabled, we should be
1954bff34e3Sthurlow  * calling vfs_set_feature() to inform callers that pieces of
1969660e5cbSJanice Chang  * functionality are available, per PSARC 2007/227.
1974bff34e3Sthurlow  */
1984bff34e3Sthurlow /* ARGSUSED */
1994bff34e3Sthurlow static int
smbfs_open(vnode_t ** vpp,int flag,cred_t * cr,caller_context_t * ct)2004bff34e3Sthurlow smbfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
2014bff34e3Sthurlow {
2024bff34e3Sthurlow 	smbnode_t	*np;
2034bff34e3Sthurlow 	vnode_t		*vp;
20402d09e03SGordon Ross 	smbfattr_t	fa;
205adee6784SGordon Ross 	smb_fh_t	*fid = NULL;
206adee6784SGordon Ross 	smb_fh_t	*oldfid;
207adee6784SGordon Ross 	uint32_t	rights;
2084bff34e3Sthurlow 	struct smb_cred scred;
2094bff34e3Sthurlow 	smbmntinfo_t	*smi;
210613a2f6bSGordon Ross 	smb_share_t	*ssp;
2114bff34e3Sthurlow 	cred_t		*oldcr;
2124bff34e3Sthurlow 	int		error = 0;
2134bff34e3Sthurlow 
2144bff34e3Sthurlow 	vp = *vpp;
2154bff34e3Sthurlow 	np = VTOSMB(vp);
2164bff34e3Sthurlow 	smi = VTOSMI(vp);
217613a2f6bSGordon Ross 	ssp = smi->smi_share;
2184bff34e3Sthurlow 
219a19609f8Sjv 	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
2204bff34e3Sthurlow 		return (EIO);
2214bff34e3Sthurlow 
2224bff34e3Sthurlow 	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2234bff34e3Sthurlow 		return (EIO);
2244bff34e3Sthurlow 
2254bff34e3Sthurlow 	if (vp->v_type != VREG && vp->v_type != VDIR) { /* XXX VLNK? */
2264bff34e3Sthurlow 		SMBVDEBUG("open eacces vtype=%d\n", vp->v_type);
2274bff34e3Sthurlow 		return (EACCES);
2284bff34e3Sthurlow 	}
2294bff34e3Sthurlow 
2304bff34e3Sthurlow 	/*
2314bff34e3Sthurlow 	 * Get exclusive access to n_fid and related stuff.
2324bff34e3Sthurlow 	 * No returns after this until out.
2334bff34e3Sthurlow 	 */
2344bff34e3Sthurlow 	if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, SMBINTR(vp)))
2354bff34e3Sthurlow 		return (EINTR);
236613a2f6bSGordon Ross 	smb_credinit(&scred, cr);
2374bff34e3Sthurlow 
23891d632c8Sgwr 	/*
23991d632c8Sgwr 	 * Keep track of the vnode type at first open.
24091d632c8Sgwr 	 * It may change later, and we need close to do
24191d632c8Sgwr 	 * cleanup for the type we opened.  Also deny
24291d632c8Sgwr 	 * open of new types until old type is closed.
24391d632c8Sgwr 	 */
24491d632c8Sgwr 	if (np->n_ovtype == VNON) {
24591d632c8Sgwr 		ASSERT(np->n_dirrefs == 0);
24691d632c8Sgwr 		ASSERT(np->n_fidrefs == 0);
24791d632c8Sgwr 	} else if (np->n_ovtype != vp->v_type) {
24891d632c8Sgwr 		SMBVDEBUG("open n_ovtype=%d v_type=%d\n",
24991d632c8Sgwr 		    np->n_ovtype, vp->v_type);
25091d632c8Sgwr 		error = EACCES;
25191d632c8Sgwr 		goto out;
25291d632c8Sgwr 	}
25391d632c8Sgwr 
2544bff34e3Sthurlow 	/*
2555ecede33SGordon Ross 	 * Directory open.  See smbfs_readvdir()
2564bff34e3Sthurlow 	 */
2574bff34e3Sthurlow 	if (vp->v_type == VDIR) {
2585ecede33SGordon Ross 		if (np->n_dirseq == NULL) {
2595ecede33SGordon Ross 			/* first open */
2605ecede33SGordon Ross 			error = smbfs_smb_findopen(np, "*", 1,
2615ecede33SGordon Ross 			    SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR,
2625ecede33SGordon Ross 			    &scred, &np->n_dirseq);
2635ecede33SGordon Ross 			if (error != 0)
2645ecede33SGordon Ross 				goto out;
2655ecede33SGordon Ross 		}
2665ecede33SGordon Ross 		np->n_dirofs = FIRST_DIROFS;
2674bff34e3Sthurlow 		np->n_dirrefs++;
2684bff34e3Sthurlow 		goto have_fid;
2694bff34e3Sthurlow 	}
2704bff34e3Sthurlow 
2714bff34e3Sthurlow 	/*
2724bff34e3Sthurlow 	 * If caller specified O_TRUNC/FTRUNC, then be sure to set
2734bff34e3Sthurlow 	 * FWRITE (to drive successful setattr(size=0) after open)
2744bff34e3Sthurlow 	 */
2754bff34e3Sthurlow 	if (flag & FTRUNC)
2764bff34e3Sthurlow 		flag |= FWRITE;
2774bff34e3Sthurlow 
2784bff34e3Sthurlow 	/*
279613a2f6bSGordon Ross 	 * If we already have it open, and the FID is still valid,
280613a2f6bSGordon Ross 	 * check whether the rights are sufficient for FID reuse.
2814bff34e3Sthurlow 	 */
282613a2f6bSGordon Ross 	if (np->n_fidrefs > 0 &&
283adee6784SGordon Ross 	    (fid = np->n_fid) != NULL &&
284adee6784SGordon Ross 	    fid->fh_vcgenid == ssp->ss_vcgenid) {
2854bff34e3Sthurlow 		int upgrade = 0;
2864bff34e3Sthurlow 
2874bff34e3Sthurlow 		if ((flag & FWRITE) &&
288adee6784SGordon Ross 		    !(fid->fh_rights & SA_RIGHT_FILE_WRITE_DATA))
2894bff34e3Sthurlow 			upgrade = 1;
2904bff34e3Sthurlow 		if ((flag & FREAD) &&
291adee6784SGordon Ross 		    !(fid->fh_rights & SA_RIGHT_FILE_READ_DATA))
2924bff34e3Sthurlow 			upgrade = 1;
2934bff34e3Sthurlow 		if (!upgrade) {
2944bff34e3Sthurlow 			/*
2954bff34e3Sthurlow 			 *  the existing open is good enough
2964bff34e3Sthurlow 			 */
2974bff34e3Sthurlow 			np->n_fidrefs++;
2984bff34e3Sthurlow 			goto have_fid;
2994bff34e3Sthurlow 		}
300adee6784SGordon Ross 		fid = NULL;
3014bff34e3Sthurlow 	}
302adee6784SGordon Ross 	rights = (fid != NULL) ? fid->fh_rights : 0;
3034bff34e3Sthurlow 
3044bff34e3Sthurlow 	/*
3054bff34e3Sthurlow 	 * we always ask for READ_CONTROL so we can always get the
30691d632c8Sgwr 	 * owner/group IDs to satisfy a stat.  Ditto attributes.
3074bff34e3Sthurlow 	 */
30891d632c8Sgwr 	rights |= (STD_RIGHT_READ_CONTROL_ACCESS |
30991d632c8Sgwr 	    SA_RIGHT_FILE_READ_ATTRIBUTES);
3104bff34e3Sthurlow 	if ((flag & FREAD))
3114bff34e3Sthurlow 		rights |= SA_RIGHT_FILE_READ_DATA;
3124bff34e3Sthurlow 	if ((flag & FWRITE))
31302d09e03SGordon Ross 		rights |= SA_RIGHT_FILE_WRITE_DATA |
31402d09e03SGordon Ross 		    SA_RIGHT_FILE_APPEND_DATA |
31502d09e03SGordon Ross 		    SA_RIGHT_FILE_WRITE_ATTRIBUTES;
31602d09e03SGordon Ross 
31702d09e03SGordon Ross 	bzero(&fa, sizeof (fa));
31802d09e03SGordon Ross 	error = smbfs_smb_open(np,
31902d09e03SGordon Ross 	    NULL, 0, 0, /* name nmlen xattr */
32002d09e03SGordon Ross 	    rights, &scred,
321adee6784SGordon Ross 	    &fid, &fa);
3224bff34e3Sthurlow 	if (error)
3234bff34e3Sthurlow 		goto out;
32402d09e03SGordon Ross 	smbfs_attrcache_fa(vp, &fa);
3254bff34e3Sthurlow 
3264bff34e3Sthurlow 	/*
3274bff34e3Sthurlow 	 * We have a new FID and access rights.
3284bff34e3Sthurlow 	 */
329*168091e5SGordon Ross 	VERIFY(fid != NULL);
3304bff34e3Sthurlow 	oldfid = np->n_fid;
3314bff34e3Sthurlow 	np->n_fid = fid;
3324bff34e3Sthurlow 	np->n_fidrefs++;
333adee6784SGordon Ross 	if (oldfid != NULL)
334adee6784SGordon Ross 		smb_fh_rele(oldfid);
3354bff34e3Sthurlow 
3364bff34e3Sthurlow 	/*
3374bff34e3Sthurlow 	 * This thread did the open.
3384bff34e3Sthurlow 	 * Save our credentials too.
3394bff34e3Sthurlow 	 */
3404bff34e3Sthurlow 	mutex_enter(&np->r_statelock);
3414bff34e3Sthurlow 	oldcr = np->r_cred;
3424bff34e3Sthurlow 	np->r_cred = cr;
3434bff34e3Sthurlow 	crhold(cr);
3444bff34e3Sthurlow 	if (oldcr)
3454bff34e3Sthurlow 		crfree(oldcr);
3464bff34e3Sthurlow 	mutex_exit(&np->r_statelock);
3474bff34e3Sthurlow 
3484bff34e3Sthurlow have_fid:
34991d632c8Sgwr 	/*
35091d632c8Sgwr 	 * Keep track of the vnode type at first open.
35191d632c8Sgwr 	 * (see comments above)
35291d632c8Sgwr 	 */
35391d632c8Sgwr 	if (np->n_ovtype == VNON)
35491d632c8Sgwr 		np->n_ovtype = vp->v_type;
3554bff34e3Sthurlow 
3564bff34e3Sthurlow out:
3574bff34e3Sthurlow 	smb_credrele(&scred);
3584bff34e3Sthurlow 	smbfs_rw_exit(&np->r_lkserlock);
3594bff34e3Sthurlow 	return (error);
3604bff34e3Sthurlow }
3614bff34e3Sthurlow 
3624bff34e3Sthurlow /*ARGSUSED*/
3634bff34e3Sthurlow static int
smbfs_close(vnode_t * vp,int flag,int count,offset_t offset,cred_t * cr,caller_context_t * ct)3644bff34e3Sthurlow smbfs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
3654bff34e3Sthurlow 	caller_context_t *ct)
3664bff34e3Sthurlow {
3674bff34e3Sthurlow 	smbnode_t	*np;
368613a2f6bSGordon Ross 	smbmntinfo_t	*smi;
3694bff34e3Sthurlow 	struct smb_cred scred;
3705f4fc069Sjilinxpd 	int error = 0;
3714bff34e3Sthurlow 
3724bff34e3Sthurlow 	np = VTOSMB(vp);
373613a2f6bSGordon Ross 	smi = VTOSMI(vp);
3744bff34e3Sthurlow 
3754bff34e3Sthurlow 	/*
3764bff34e3Sthurlow 	 * Don't "bail out" for VFS_UNMOUNTED here,
3774bff34e3Sthurlow 	 * as we want to do cleanup, etc.
3784bff34e3Sthurlow 	 */
3794bff34e3Sthurlow 
3804bff34e3Sthurlow 	/*
3814bff34e3Sthurlow 	 * zone_enter(2) prevents processes from changing zones with SMBFS files
3824bff34e3Sthurlow 	 * open; if we happen to get here from the wrong zone we can't do
3834bff34e3Sthurlow 	 * anything over the wire.
3844bff34e3Sthurlow 	 */
385a19609f8Sjv 	if (smi->smi_zone_ref.zref_zone != curproc->p_zone) {
3864bff34e3Sthurlow 		/*
3874bff34e3Sthurlow 		 * We could attempt to clean up locks, except we're sure
3884bff34e3Sthurlow 		 * that the current process didn't acquire any locks on
3894bff34e3Sthurlow 		 * the file: any attempt to lock a file belong to another zone
3904bff34e3Sthurlow 		 * will fail, and one can't lock an SMBFS file and then change
3914bff34e3Sthurlow 		 * zones, as that fails too.
3924bff34e3Sthurlow 		 *
3934bff34e3Sthurlow 		 * Returning an error here is the sane thing to do.  A
3944bff34e3Sthurlow 		 * subsequent call to VN_RELE() which translates to a
3954bff34e3Sthurlow 		 * smbfs_inactive() will clean up state: if the zone of the
3964bff34e3Sthurlow 		 * vnode's origin is still alive and kicking, an async worker
3974bff34e3Sthurlow 		 * thread will handle the request (from the correct zone), and
3984bff34e3Sthurlow 		 * everything (minus the final smbfs_getattr_otw() call) should
3994bff34e3Sthurlow 		 * be OK. If the zone is going away smbfs_async_inactive() will
4004bff34e3Sthurlow 		 * throw away cached pages inline.
4014bff34e3Sthurlow 		 */
4024bff34e3Sthurlow 		return (EIO);
4034bff34e3Sthurlow 	}
4044bff34e3Sthurlow 
4054bff34e3Sthurlow 	/*
4064bff34e3Sthurlow 	 * If we are using local locking for this filesystem, then
4074bff34e3Sthurlow 	 * release all of the SYSV style record locks.  Otherwise,
4084bff34e3Sthurlow 	 * we are doing network locking and we need to release all
4094bff34e3Sthurlow 	 * of the network locks.  All of the locks held by this
4104bff34e3Sthurlow 	 * process on this file are released no matter what the
4114bff34e3Sthurlow 	 * incoming reference count is.
4124bff34e3Sthurlow 	 */
41342d15982SGordon Ross 	if (smi->smi_flags & SMI_LLOCK) {
414613a2f6bSGordon Ross 		pid_t pid = ddi_get_pid();
415613a2f6bSGordon Ross 		cleanlocks(vp, pid, 0);
416613a2f6bSGordon Ross 		cleanshares(vp, pid);
4174bff34e3Sthurlow 	}
4185f4fc069Sjilinxpd 	/*
4195f4fc069Sjilinxpd 	 * else doing OtW locking.  SMB servers drop all locks
4205f4fc069Sjilinxpd 	 * on the file ID we close here, so no _lockrelease()
4215f4fc069Sjilinxpd 	 */
4224bff34e3Sthurlow 
4234bff34e3Sthurlow 	/*
42402d09e03SGordon Ross 	 * This (passed in) count is the ref. count from the
42502d09e03SGordon Ross 	 * user's file_t before the closef call (fio.c).
4265f4fc069Sjilinxpd 	 * The rest happens only on last close.
4274bff34e3Sthurlow 	 */
42802d09e03SGordon Ross 	if (count > 1)
42902d09e03SGordon Ross 		return (0);
4304bff34e3Sthurlow 
4315f4fc069Sjilinxpd 	/* NFS has DNLC purge here. */
4325f4fc069Sjilinxpd 
4335f4fc069Sjilinxpd 	/*
4345f4fc069Sjilinxpd 	 * If the file was open for write and there are pages,
4355f4fc069Sjilinxpd 	 * then make sure dirty pages written back.
4365f4fc069Sjilinxpd 	 *
4375f4fc069Sjilinxpd 	 * NFS does this async when "close-to-open" is off
4385f4fc069Sjilinxpd 	 * (MI_NOCTO flag is set) to avoid blocking the caller.
4395f4fc069Sjilinxpd 	 * For now, always do this synchronously (no B_ASYNC).
4405f4fc069Sjilinxpd 	 */
4415f4fc069Sjilinxpd 	if ((flag & FWRITE) && vn_has_cached_data(vp)) {
4425f4fc069Sjilinxpd 		error = smbfs_putpage(vp, (offset_t)0, 0, 0, cr, ct);
4435f4fc069Sjilinxpd 		if (error == EAGAIN)
4445f4fc069Sjilinxpd 			error = 0;
4455f4fc069Sjilinxpd 	}
4465f4fc069Sjilinxpd 	if (error == 0) {
4475f4fc069Sjilinxpd 		mutex_enter(&np->r_statelock);
4485f4fc069Sjilinxpd 		np->r_flags &= ~RSTALE;
4495f4fc069Sjilinxpd 		np->r_error = 0;
4505f4fc069Sjilinxpd 		mutex_exit(&np->r_statelock);
4515f4fc069Sjilinxpd 	}
4525f4fc069Sjilinxpd 
4534bff34e3Sthurlow 	/*
45442d15982SGordon Ross 	 * Decrement the reference count for the FID
45542d15982SGordon Ross 	 * and possibly do the OtW close.
45642d15982SGordon Ross 	 *
4574bff34e3Sthurlow 	 * Exclusive lock for modifying n_fid stuff.
4584bff34e3Sthurlow 	 * Don't want this one ever interruptible.
4594bff34e3Sthurlow 	 */
4604bff34e3Sthurlow 	(void) smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, 0);
461613a2f6bSGordon Ross 	smb_credinit(&scred, cr);
4624bff34e3Sthurlow 
46342d15982SGordon Ross 	smbfs_rele_fid(np, &scred);
46442d15982SGordon Ross 
46542d15982SGordon Ross 	smb_credrele(&scred);
46642d15982SGordon Ross 	smbfs_rw_exit(&np->r_lkserlock);
46742d15982SGordon Ross 
46842d15982SGordon Ross 	return (0);
46942d15982SGordon Ross }
47042d15982SGordon Ross 
47142d15982SGordon Ross /*
47242d15982SGordon Ross  * Helper for smbfs_close.  Decrement the reference count
47342d15982SGordon Ross  * for an SMB-level file or directory ID, and when the last
47442d15982SGordon Ross  * reference for the fid goes away, do the OtW close.
47542d15982SGordon Ross  * Also called in smbfs_inactive (defensive cleanup).
47642d15982SGordon Ross  */
47742d15982SGordon Ross static void
smbfs_rele_fid(smbnode_t * np,struct smb_cred * scred)47842d15982SGordon Ross smbfs_rele_fid(smbnode_t *np, struct smb_cred *scred)
47942d15982SGordon Ross {
48042d15982SGordon Ross 	cred_t		*oldcr;
48142d15982SGordon Ross 	struct smbfs_fctx *fctx;
48242d15982SGordon Ross 	int		error;
483adee6784SGordon Ross 	smb_fh_t	*ofid;
48442d15982SGordon Ross 
4854bff34e3Sthurlow 	error = 0;
48691d632c8Sgwr 
48742d15982SGordon Ross 	/* Make sure we serialize for n_dirseq use. */
48842d15982SGordon Ross 	ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_WRITER));
48942d15982SGordon Ross 
49091d632c8Sgwr 	/*
49191d632c8Sgwr 	 * Note that vp->v_type may change if a remote node
49291d632c8Sgwr 	 * is deleted and recreated as a different type, and
49391d632c8Sgwr 	 * our getattr may change v_type accordingly.
49491d632c8Sgwr 	 * Now use n_ovtype to keep track of the v_type
49591d632c8Sgwr 	 * we had during open (see comments above).
49691d632c8Sgwr 	 */
49742d15982SGordon Ross 	switch (np->n_ovtype) {
49842d15982SGordon Ross 	case VDIR:
4994bff34e3Sthurlow 		ASSERT(np->n_dirrefs > 0);
5004bff34e3Sthurlow 		if (--np->n_dirrefs)
50142d15982SGordon Ross 			return;
5024bff34e3Sthurlow 		if ((fctx = np->n_dirseq) != NULL) {
5034bff34e3Sthurlow 			np->n_dirseq = NULL;
5045ecede33SGordon Ross 			np->n_dirofs = 0;
50542d15982SGordon Ross 			error = smbfs_smb_findclose(fctx, scred);
5064bff34e3Sthurlow 		}
50742d15982SGordon Ross 		break;
50842d15982SGordon Ross 
50942d15982SGordon Ross 	case VREG:
5104bff34e3Sthurlow 		ASSERT(np->n_fidrefs > 0);
5114bff34e3Sthurlow 		if (--np->n_fidrefs)
51242d15982SGordon Ross 			return;
513adee6784SGordon Ross 		if ((ofid = np->n_fid) != NULL) {
514adee6784SGordon Ross 			np->n_fid = NULL;
515adee6784SGordon Ross 			smb_fh_rele(ofid);
5164bff34e3Sthurlow 		}
51742d15982SGordon Ross 		break;
51842d15982SGordon Ross 
51942d15982SGordon Ross 	default:
52042d15982SGordon Ross 		SMBVDEBUG("bad n_ovtype %d\n", np->n_ovtype);
52142d15982SGordon Ross 		break;
5224bff34e3Sthurlow 	}
5234bff34e3Sthurlow 	if (error) {
52402d09e03SGordon Ross 		SMBVDEBUG("error %d closing %s\n",
5254bff34e3Sthurlow 		    error, np->n_rpath);
5264bff34e3Sthurlow 	}
5274bff34e3Sthurlow 
52891d632c8Sgwr 	/* Allow next open to use any v_type. */
52991d632c8Sgwr 	np->n_ovtype = VNON;
53091d632c8Sgwr 
53102d09e03SGordon Ross 	/*
53202d09e03SGordon Ross 	 * Other "last close" stuff.
53302d09e03SGordon Ross 	 */
53402d09e03SGordon Ross 	mutex_enter(&np->r_statelock);
5354bff34e3Sthurlow 	if (np->n_flag & NATTRCHANGED)
53602d09e03SGordon Ross 		smbfs_attrcache_rm_locked(np);
53702d09e03SGordon Ross 	oldcr = np->r_cred;
53802d09e03SGordon Ross 	np->r_cred = NULL;
53902d09e03SGordon Ross 	mutex_exit(&np->r_statelock);
54002d09e03SGordon Ross 	if (oldcr != NULL)
54102d09e03SGordon Ross 		crfree(oldcr);
5424bff34e3Sthurlow }
5434bff34e3Sthurlow 
5444bff34e3Sthurlow /* ARGSUSED */
5454bff34e3Sthurlow static int
smbfs_read(vnode_t * vp,struct uio * uiop,int ioflag,cred_t * cr,caller_context_t * ct)5464bff34e3Sthurlow smbfs_read(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
5474bff34e3Sthurlow 	caller_context_t *ct)
5484bff34e3Sthurlow {
5499c9af259SGordon Ross 	struct smb_cred scred;
5509c9af259SGordon Ross 	struct vattr	va;
551613a2f6bSGordon Ross 	smbnode_t	*np;
552613a2f6bSGordon Ross 	smbmntinfo_t	*smi;
5539c9af259SGordon Ross 	offset_t	endoff;
5549c9af259SGordon Ross 	ssize_t		past_eof;
5559c9af259SGordon Ross 	int		error;
5564bff34e3Sthurlow 
5574bff34e3Sthurlow 	np = VTOSMB(vp);
5584bff34e3Sthurlow 	smi = VTOSMI(vp);
5594bff34e3Sthurlow 
560a19609f8Sjv 	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
5614bff34e3Sthurlow 		return (EIO);
5624bff34e3Sthurlow 
5634bff34e3Sthurlow 	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
5644bff34e3Sthurlow 		return (EIO);
5654bff34e3Sthurlow 
566*168091e5SGordon Ross 	/* Sanity check: should have a valid open */
567*168091e5SGordon Ross 	if (np->n_fid == NULL)
568*168091e5SGordon Ross 		return (EIO);
569*168091e5SGordon Ross 
5704bff34e3Sthurlow 	ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_READER));
5714bff34e3Sthurlow 
5724bff34e3Sthurlow 	if (vp->v_type != VREG)
5734bff34e3Sthurlow 		return (EISDIR);
5744bff34e3Sthurlow 
5754bff34e3Sthurlow 	if (uiop->uio_resid == 0)
5764bff34e3Sthurlow 		return (0);
5774bff34e3Sthurlow 
5784bff34e3Sthurlow 	/*
5794bff34e3Sthurlow 	 * Like NFS3, just check for 63-bit overflow.
5804bff34e3Sthurlow 	 * Our SMB layer takes care to return EFBIG
5814bff34e3Sthurlow 	 * when it has to fallback to a 32-bit call.
5824bff34e3Sthurlow 	 */
583613a2f6bSGordon Ross 	endoff = uiop->uio_loffset + uiop->uio_resid;
584613a2f6bSGordon Ross 	if (uiop->uio_loffset < 0 || endoff < 0)
5854bff34e3Sthurlow 		return (EINVAL);
5864bff34e3Sthurlow 
5874bff34e3Sthurlow 	/* get vnode attributes from server */
5884bff34e3Sthurlow 	va.va_mask = AT_SIZE | AT_MTIME;
5894bff34e3Sthurlow 	if (error = smbfsgetattr(vp, &va, cr))
5909c9af259SGordon Ross 		return (error);
5914bff34e3Sthurlow 
5929c9af259SGordon Ross 	/* Update mtime with mtime from server here? */
5939c9af259SGordon Ross 
5949c9af259SGordon Ross 	/* if offset is beyond EOF, read nothing */
5959c9af259SGordon Ross 	if (uiop->uio_loffset >= va.va_size)
5969c9af259SGordon Ross 		return (0);
5974bff34e3Sthurlow 
5984bff34e3Sthurlow 	/*
5999c9af259SGordon Ross 	 * Limit the read to the remaining file size.
6009c9af259SGordon Ross 	 * Do this by temporarily reducing uio_resid
6019c9af259SGordon Ross 	 * by the amount the lies beyoned the EOF.
6024bff34e3Sthurlow 	 */
6039c9af259SGordon Ross 	if (endoff > va.va_size) {
6049c9af259SGordon Ross 		past_eof = (ssize_t)(endoff - va.va_size);
6059c9af259SGordon Ross 		uiop->uio_resid -= past_eof;
6069c9af259SGordon Ross 	} else
6079c9af259SGordon Ross 		past_eof = 0;
6089c9af259SGordon Ross 
6095f4fc069Sjilinxpd 	/*
6105f4fc069Sjilinxpd 	 * Bypass VM if caching has been disabled (e.g., locking) or if
6115f4fc069Sjilinxpd 	 * using client-side direct I/O and the file is not mmap'd and
6125f4fc069Sjilinxpd 	 * there are no cached pages.
6135f4fc069Sjilinxpd 	 */
6145f4fc069Sjilinxpd 	if ((vp->v_flag & VNOCACHE) ||
6155f4fc069Sjilinxpd 	    (((np->r_flags & RDIRECTIO) || (smi->smi_flags & SMI_DIRECTIO)) &&
6165f4fc069Sjilinxpd 	    np->r_mapcnt == 0 && np->r_inmap == 0 &&
6175f4fc069Sjilinxpd 	    !vn_has_cached_data(vp))) {
6184bff34e3Sthurlow 
6195f4fc069Sjilinxpd 		/* Shared lock for n_fid use in smb_rwuio */
6205f4fc069Sjilinxpd 		if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
6215f4fc069Sjilinxpd 			return (EINTR);
6225f4fc069Sjilinxpd 		smb_credinit(&scred, cr);
6239c9af259SGordon Ross 
624adee6784SGordon Ross 		error = smb_rwuio(np->n_fid, UIO_READ,
625adee6784SGordon Ross 		    uiop, &scred, smb_timo_read);
6265f4fc069Sjilinxpd 
6275f4fc069Sjilinxpd 		smb_credrele(&scred);
6285f4fc069Sjilinxpd 		smbfs_rw_exit(&np->r_lkserlock);
6295f4fc069Sjilinxpd 
6305f4fc069Sjilinxpd 		/* undo adjustment of resid */
6315f4fc069Sjilinxpd 		uiop->uio_resid += past_eof;
6325f4fc069Sjilinxpd 
6335f4fc069Sjilinxpd 		return (error);
6345f4fc069Sjilinxpd 	}
6355f4fc069Sjilinxpd 
6368329232eSGordon Ross #ifdef	_KERNEL
6375f4fc069Sjilinxpd 	/* (else) Do I/O through segmap. */
6385f4fc069Sjilinxpd 	do {
6398329232eSGordon Ross 		caddr_t		base;
6408329232eSGordon Ross 		u_offset_t	off;
6418329232eSGordon Ross 		size_t		n;
6428329232eSGordon Ross 		int		on;
6438329232eSGordon Ross 		uint_t		flags;
6448329232eSGordon Ross 
6455f4fc069Sjilinxpd 		off = uiop->uio_loffset & MAXBMASK; /* mapping offset */
6465f4fc069Sjilinxpd 		on = uiop->uio_loffset & MAXBOFFSET; /* Relative offset */
6475f4fc069Sjilinxpd 		n = MIN(MAXBSIZE - on, uiop->uio_resid);
6485f4fc069Sjilinxpd 
6495f4fc069Sjilinxpd 		error = smbfs_validate_caches(vp, cr);
6505f4fc069Sjilinxpd 		if (error)
6515f4fc069Sjilinxpd 			break;
6525f4fc069Sjilinxpd 
6535f4fc069Sjilinxpd 		/* NFS waits for RINCACHEPURGE here. */
6545f4fc069Sjilinxpd 
6555f4fc069Sjilinxpd 		if (vpm_enable) {
6565f4fc069Sjilinxpd 			/*
6575f4fc069Sjilinxpd 			 * Copy data.
6585f4fc069Sjilinxpd 			 */
6595f4fc069Sjilinxpd 			error = vpm_data_copy(vp, off + on, n, uiop,
6605f4fc069Sjilinxpd 			    1, NULL, 0, S_READ);
6615f4fc069Sjilinxpd 		} else {
6625f4fc069Sjilinxpd 			base = segmap_getmapflt(segkmap, vp, off + on, n, 1,
6635f4fc069Sjilinxpd 			    S_READ);
6645f4fc069Sjilinxpd 
6655f4fc069Sjilinxpd 			error = uiomove(base + on, n, UIO_READ, uiop);
6665f4fc069Sjilinxpd 		}
6675f4fc069Sjilinxpd 
6685f4fc069Sjilinxpd 		if (!error) {
6695f4fc069Sjilinxpd 			/*
6705f4fc069Sjilinxpd 			 * If read a whole block or read to eof,
6715f4fc069Sjilinxpd 			 * won't need this buffer again soon.
6725f4fc069Sjilinxpd 			 */
6735f4fc069Sjilinxpd 			mutex_enter(&np->r_statelock);
6745f4fc069Sjilinxpd 			if (n + on == MAXBSIZE ||
6755f4fc069Sjilinxpd 			    uiop->uio_loffset == np->r_size)
6765f4fc069Sjilinxpd 				flags = SM_DONTNEED;
6775f4fc069Sjilinxpd 			else
6785f4fc069Sjilinxpd 				flags = 0;
6795f4fc069Sjilinxpd 			mutex_exit(&np->r_statelock);
6805f4fc069Sjilinxpd 			if (vpm_enable) {
6815f4fc069Sjilinxpd 				error = vpm_sync_pages(vp, off, n, flags);
6825f4fc069Sjilinxpd 			} else {
6835f4fc069Sjilinxpd 				error = segmap_release(segkmap, base, flags);
6845f4fc069Sjilinxpd 			}
6855f4fc069Sjilinxpd 		} else {
6865f4fc069Sjilinxpd 			if (vpm_enable) {
6875f4fc069Sjilinxpd 				(void) vpm_sync_pages(vp, off, n, 0);
6885f4fc069Sjilinxpd 			} else {
6895f4fc069Sjilinxpd 				(void) segmap_release(segkmap, base, 0);
6905f4fc069Sjilinxpd 			}
6915f4fc069Sjilinxpd 		}
6925f4fc069Sjilinxpd 	} while (!error && uiop->uio_resid > 0);
6938329232eSGordon Ross #else	// _KERNEL
6948329232eSGordon Ross 	error = ENOSYS;
6958329232eSGordon Ross #endif	// _KERNEL
6964bff34e3Sthurlow 
6979c9af259SGordon Ross 	/* undo adjustment of resid */
6989c9af259SGordon Ross 	uiop->uio_resid += past_eof;
6999c9af259SGordon Ross 
7009c9af259SGordon Ross 	return (error);
7014bff34e3Sthurlow }
7024bff34e3Sthurlow 
7034bff34e3Sthurlow 
7044bff34e3Sthurlow /* ARGSUSED */
7054bff34e3Sthurlow static int
smbfs_write(vnode_t * vp,struct uio * uiop,int ioflag,cred_t * cr,caller_context_t * ct)7064bff34e3Sthurlow smbfs_write(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
7074bff34e3Sthurlow 	caller_context_t *ct)
7084bff34e3Sthurlow {
7099c9af259SGordon Ross 	struct smb_cred scred;
7105f4fc069Sjilinxpd 	struct vattr    va;
711613a2f6bSGordon Ross 	smbnode_t	*np;
712613a2f6bSGordon Ross 	smbmntinfo_t	*smi;
7139c9af259SGordon Ross 	offset_t	endoff, limit;
7149c9af259SGordon Ross 	ssize_t		past_limit;
7159c9af259SGordon Ross 	int		error, timo;
7165f4fc069Sjilinxpd 	u_offset_t	last_off;
7175f4fc069Sjilinxpd 	size_t		last_resid;
7188329232eSGordon Ross #ifdef	_KERNEL
7195f4fc069Sjilinxpd 	uint_t		bsize;
7208329232eSGordon Ross #endif
7214bff34e3Sthurlow 
7224bff34e3Sthurlow 	np = VTOSMB(vp);
7234bff34e3Sthurlow 	smi = VTOSMI(vp);
7244bff34e3Sthurlow 
725a19609f8Sjv 	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
7264bff34e3Sthurlow 		return (EIO);
7274bff34e3Sthurlow 
7284bff34e3Sthurlow 	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
7294bff34e3Sthurlow 		return (EIO);
7304bff34e3Sthurlow 
731*168091e5SGordon Ross 	/* Sanity check: should have a valid open */
732*168091e5SGordon Ross 	if (np->n_fid == NULL)
733*168091e5SGordon Ross 		return (EIO);
734*168091e5SGordon Ross 
7354bff34e3Sthurlow 	ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_WRITER));
7364bff34e3Sthurlow 
7374bff34e3Sthurlow 	if (vp->v_type != VREG)
7384bff34e3Sthurlow 		return (EISDIR);
7394bff34e3Sthurlow 
7404bff34e3Sthurlow 	if (uiop->uio_resid == 0)
7414bff34e3Sthurlow 		return (0);
7424bff34e3Sthurlow 
7439c9af259SGordon Ross 	/*
7449c9af259SGordon Ross 	 * Handle ioflag bits: (FAPPEND|FSYNC|FDSYNC)
7459c9af259SGordon Ross 	 */
7469c9af259SGordon Ross 	if (ioflag & (FAPPEND | FSYNC)) {
7479c9af259SGordon Ross 		if (np->n_flag & NMODIFIED) {
74802d09e03SGordon Ross 			smbfs_attrcache_remove(np);
7499c9af259SGordon Ross 		}
7509c9af259SGordon Ross 	}
7519c9af259SGordon Ross 	if (ioflag & FAPPEND) {
7529c9af259SGordon Ross 		/*
7539c9af259SGordon Ross 		 * File size can be changed by another client
7545f4fc069Sjilinxpd 		 *
7555f4fc069Sjilinxpd 		 * Todo: Consider redesigning this to use a
7565f4fc069Sjilinxpd 		 * handle opened for append instead.
7579c9af259SGordon Ross 		 */
7589c9af259SGordon Ross 		va.va_mask = AT_SIZE;
7599c9af259SGordon Ross 		if (error = smbfsgetattr(vp, &va, cr))
7609c9af259SGordon Ross 			return (error);
7619c9af259SGordon Ross 		uiop->uio_loffset = va.va_size;
7629c9af259SGordon Ross 	}
7634bff34e3Sthurlow 
7649c9af259SGordon Ross 	/*
7659c9af259SGordon Ross 	 * Like NFS3, just check for 63-bit overflow.
7669c9af259SGordon Ross 	 */
7679c9af259SGordon Ross 	endoff = uiop->uio_loffset + uiop->uio_resid;
7689c9af259SGordon Ross 	if (uiop->uio_loffset < 0 || endoff < 0)
7699c9af259SGordon Ross 		return (EINVAL);
7704bff34e3Sthurlow 
7714bff34e3Sthurlow 	/*
7729c9af259SGordon Ross 	 * Check to make sure that the process will not exceed
7739c9af259SGordon Ross 	 * its limit on file size.  It is okay to write up to
7749c9af259SGordon Ross 	 * the limit, but not beyond.  Thus, the write which
7759c9af259SGordon Ross 	 * reaches the limit will be short and the next write
7769c9af259SGordon Ross 	 * will return an error.
7779c9af259SGordon Ross 	 *
7789c9af259SGordon Ross 	 * So if we're starting at or beyond the limit, EFBIG.
7799c9af259SGordon Ross 	 * Otherwise, temporarily reduce resid to the amount
7805f4fc069Sjilinxpd 	 * that is after the limit.
7814bff34e3Sthurlow 	 */
7829c9af259SGordon Ross 	limit = uiop->uio_llimit;
7839c9af259SGordon Ross 	if (limit == RLIM64_INFINITY || limit > MAXOFFSET_T)
7849c9af259SGordon Ross 		limit = MAXOFFSET_T;
7855f4fc069Sjilinxpd 	if (uiop->uio_loffset >= limit) {
7868329232eSGordon Ross #ifdef	_KERNEL
7875f4fc069Sjilinxpd 		proc_t *p = ttoproc(curthread);
7885f4fc069Sjilinxpd 
7895f4fc069Sjilinxpd 		mutex_enter(&p->p_lock);
7905f4fc069Sjilinxpd 		(void) rctl_action(rctlproc_legacy[RLIMIT_FSIZE],
7915f4fc069Sjilinxpd 		    p->p_rctls, p, RCA_UNSAFE_SIGINFO);
7925f4fc069Sjilinxpd 		mutex_exit(&p->p_lock);
7938329232eSGordon Ross #endif	// _KERNEL
7949c9af259SGordon Ross 		return (EFBIG);
7955f4fc069Sjilinxpd 	}
7969c9af259SGordon Ross 	if (endoff > limit) {
7979c9af259SGordon Ross 		past_limit = (ssize_t)(endoff - limit);
7989c9af259SGordon Ross 		uiop->uio_resid -= past_limit;
7999c9af259SGordon Ross 	} else
8009c9af259SGordon Ross 		past_limit = 0;
8019c9af259SGordon Ross 
8025f4fc069Sjilinxpd 	/*
8035f4fc069Sjilinxpd 	 * Bypass VM if caching has been disabled (e.g., locking) or if
8045f4fc069Sjilinxpd 	 * using client-side direct I/O and the file is not mmap'd and
8055f4fc069Sjilinxpd 	 * there are no cached pages.
8065f4fc069Sjilinxpd 	 */
8075f4fc069Sjilinxpd 	if ((vp->v_flag & VNOCACHE) ||
8085f4fc069Sjilinxpd 	    (((np->r_flags & RDIRECTIO) || (smi->smi_flags & SMI_DIRECTIO)) &&
8095f4fc069Sjilinxpd 	    np->r_mapcnt == 0 && np->r_inmap == 0 &&
8105f4fc069Sjilinxpd 	    !vn_has_cached_data(vp))) {
8115f4fc069Sjilinxpd 
8128329232eSGordon Ross #ifdef	_KERNEL
8135f4fc069Sjilinxpd smbfs_fwrite:
8148329232eSGordon Ross #endif	// _KERNEL
8155f4fc069Sjilinxpd 		if (np->r_flags & RSTALE) {
8165f4fc069Sjilinxpd 			last_resid = uiop->uio_resid;
8175f4fc069Sjilinxpd 			last_off = uiop->uio_loffset;
8185f4fc069Sjilinxpd 			error = np->r_error;
8195f4fc069Sjilinxpd 			/*
8205f4fc069Sjilinxpd 			 * A close may have cleared r_error, if so,
8215f4fc069Sjilinxpd 			 * propagate ESTALE error return properly
8225f4fc069Sjilinxpd 			 */
8235f4fc069Sjilinxpd 			if (error == 0)
8245f4fc069Sjilinxpd 				error = ESTALE;
8255f4fc069Sjilinxpd 			goto bottom;
8265f4fc069Sjilinxpd 		}
8275f4fc069Sjilinxpd 
8285f4fc069Sjilinxpd 		/* Timeout: longer for append. */
8295f4fc069Sjilinxpd 		timo = smb_timo_write;
8305f4fc069Sjilinxpd 		if (endoff > np->r_size)
8315f4fc069Sjilinxpd 			timo = smb_timo_append;
8329c9af259SGordon Ross 
8335f4fc069Sjilinxpd 		/* Shared lock for n_fid use in smb_rwuio */
8345f4fc069Sjilinxpd 		if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
8355f4fc069Sjilinxpd 			return (EINTR);
8365f4fc069Sjilinxpd 		smb_credinit(&scred, cr);
8374bff34e3Sthurlow 
838adee6784SGordon Ross 		error = smb_rwuio(np->n_fid, UIO_WRITE,
839adee6784SGordon Ross 		    uiop, &scred, timo);
8409c9af259SGordon Ross 
8415f4fc069Sjilinxpd 		if (error == 0) {
8425f4fc069Sjilinxpd 			mutex_enter(&np->r_statelock);
8435f4fc069Sjilinxpd 			np->n_flag |= (NFLUSHWIRE | NATTRCHANGED);
8445f4fc069Sjilinxpd 			if (uiop->uio_loffset > (offset_t)np->r_size)
8455f4fc069Sjilinxpd 				np->r_size = (len_t)uiop->uio_loffset;
8465f4fc069Sjilinxpd 			mutex_exit(&np->r_statelock);
8475f4fc069Sjilinxpd 			if (ioflag & (FSYNC | FDSYNC)) {
8485f4fc069Sjilinxpd 				/* Don't error the I/O if this fails. */
849adee6784SGordon Ross 				(void) smbfsflush(np, &scred);
8505f4fc069Sjilinxpd 			}
8515f4fc069Sjilinxpd 		}
8525f4fc069Sjilinxpd 
8535f4fc069Sjilinxpd 		smb_credrele(&scred);
8545f4fc069Sjilinxpd 		smbfs_rw_exit(&np->r_lkserlock);
8555f4fc069Sjilinxpd 
8565f4fc069Sjilinxpd 		/* undo adjustment of resid */
8575f4fc069Sjilinxpd 		uiop->uio_resid += past_limit;
8585f4fc069Sjilinxpd 
8595f4fc069Sjilinxpd 		return (error);
8605f4fc069Sjilinxpd 	}
8615f4fc069Sjilinxpd 
8628329232eSGordon Ross #ifdef	_KERNEL
8635f4fc069Sjilinxpd 	/* (else) Do I/O through segmap. */
8645f4fc069Sjilinxpd 	bsize = vp->v_vfsp->vfs_bsize;
8655f4fc069Sjilinxpd 
8665f4fc069Sjilinxpd 	do {
8678329232eSGordon Ross 		caddr_t		base;
8688329232eSGordon Ross 		u_offset_t	off;
8698329232eSGordon Ross 		size_t		n;
8708329232eSGordon Ross 		int		on;
8718329232eSGordon Ross 		uint_t		flags;
8728329232eSGordon Ross 
8735f4fc069Sjilinxpd 		off = uiop->uio_loffset & MAXBMASK; /* mapping offset */
8745f4fc069Sjilinxpd 		on = uiop->uio_loffset & MAXBOFFSET; /* Relative offset */
8755f4fc069Sjilinxpd 		n = MIN(MAXBSIZE - on, uiop->uio_resid);
8765f4fc069Sjilinxpd 
8775f4fc069Sjilinxpd 		last_resid = uiop->uio_resid;
8785f4fc069Sjilinxpd 		last_off = uiop->uio_loffset;
8795f4fc069Sjilinxpd 
8805f4fc069Sjilinxpd 		if (np->r_flags & RSTALE) {
8815f4fc069Sjilinxpd 			error = np->r_error;
8825f4fc069Sjilinxpd 			/*
8835f4fc069Sjilinxpd 			 * A close may have cleared r_error, if so,
8845f4fc069Sjilinxpd 			 * propagate ESTALE error return properly
8855f4fc069Sjilinxpd 			 */
8865f4fc069Sjilinxpd 			if (error == 0)
8875f4fc069Sjilinxpd 				error = ESTALE;
8885f4fc069Sjilinxpd 			break;
8895f4fc069Sjilinxpd 		}
8905f4fc069Sjilinxpd 
8915f4fc069Sjilinxpd 		/*
8925f4fc069Sjilinxpd 		 * From NFS: Don't create dirty pages faster than they
8935f4fc069Sjilinxpd 		 * can be cleaned.
8945f4fc069Sjilinxpd 		 *
8955f4fc069Sjilinxpd 		 * Here NFS also checks for async writes (np->r_awcount)
8965f4fc069Sjilinxpd 		 */
8979c9af259SGordon Ross 		mutex_enter(&np->r_statelock);
8985f4fc069Sjilinxpd 		while (np->r_gcount > 0) {
8995f4fc069Sjilinxpd 			if (SMBINTR(vp)) {
9005f4fc069Sjilinxpd 				klwp_t *lwp = ttolwp(curthread);
9015f4fc069Sjilinxpd 
9025f4fc069Sjilinxpd 				if (lwp != NULL)
9035f4fc069Sjilinxpd 					lwp->lwp_nostop++;
9045f4fc069Sjilinxpd 				if (!cv_wait_sig(&np->r_cv, &np->r_statelock)) {
9055f4fc069Sjilinxpd 					mutex_exit(&np->r_statelock);
9065f4fc069Sjilinxpd 					if (lwp != NULL)
9075f4fc069Sjilinxpd 						lwp->lwp_nostop--;
9085f4fc069Sjilinxpd 					error = EINTR;
9095f4fc069Sjilinxpd 					goto bottom;
9105f4fc069Sjilinxpd 				}
9115f4fc069Sjilinxpd 				if (lwp != NULL)
9125f4fc069Sjilinxpd 					lwp->lwp_nostop--;
9135f4fc069Sjilinxpd 			} else
9145f4fc069Sjilinxpd 				cv_wait(&np->r_cv, &np->r_statelock);
9155f4fc069Sjilinxpd 		}
9169c9af259SGordon Ross 		mutex_exit(&np->r_statelock);
9175f4fc069Sjilinxpd 
9185f4fc069Sjilinxpd 		/*
9195f4fc069Sjilinxpd 		 * Touch the page and fault it in if it is not in core
9205f4fc069Sjilinxpd 		 * before segmap_getmapflt or vpm_data_copy can lock it.
9215f4fc069Sjilinxpd 		 * This is to avoid the deadlock if the buffer is mapped
9225f4fc069Sjilinxpd 		 * to the same file through mmap which we want to write.
9235f4fc069Sjilinxpd 		 */
9245f4fc069Sjilinxpd 		uio_prefaultpages((long)n, uiop);
9255f4fc069Sjilinxpd 
9265f4fc069Sjilinxpd 		if (vpm_enable) {
9275f4fc069Sjilinxpd 			/*
9285f4fc069Sjilinxpd 			 * It will use kpm mappings, so no need to
9295f4fc069Sjilinxpd 			 * pass an address.
9305f4fc069Sjilinxpd 			 */
9315f4fc069Sjilinxpd 			error = smbfs_writenp(np, NULL, n, uiop, 0);
9325f4fc069Sjilinxpd 		} else {
9335f4fc069Sjilinxpd 			if (segmap_kpm) {
9345f4fc069Sjilinxpd 				int pon = uiop->uio_loffset & PAGEOFFSET;
9355f4fc069Sjilinxpd 				size_t pn = MIN(PAGESIZE - pon,
9365f4fc069Sjilinxpd 				    uiop->uio_resid);
9375f4fc069Sjilinxpd 				int pagecreate;
9385f4fc069Sjilinxpd 
9395f4fc069Sjilinxpd 				mutex_enter(&np->r_statelock);
9405f4fc069Sjilinxpd 				pagecreate = (pon == 0) && (pn == PAGESIZE ||
9415f4fc069Sjilinxpd 				    uiop->uio_loffset + pn >= np->r_size);
9425f4fc069Sjilinxpd 				mutex_exit(&np->r_statelock);
9435f4fc069Sjilinxpd 
9445f4fc069Sjilinxpd 				base = segmap_getmapflt(segkmap, vp, off + on,
9455f4fc069Sjilinxpd 				    pn, !pagecreate, S_WRITE);
9465f4fc069Sjilinxpd 
9475f4fc069Sjilinxpd 				error = smbfs_writenp(np, base + pon, n, uiop,
9485f4fc069Sjilinxpd 				    pagecreate);
9495f4fc069Sjilinxpd 
9505f4fc069Sjilinxpd 			} else {
9515f4fc069Sjilinxpd 				base = segmap_getmapflt(segkmap, vp, off + on,
9525f4fc069Sjilinxpd 				    n, 0, S_READ);
9535f4fc069Sjilinxpd 				error = smbfs_writenp(np, base + on, n, uiop, 0);
9545f4fc069Sjilinxpd 			}
9559c9af259SGordon Ross 		}
9569c9af259SGordon Ross 
9575f4fc069Sjilinxpd 		if (!error) {
9585f4fc069Sjilinxpd 			if (smi->smi_flags & SMI_NOAC)
9595f4fc069Sjilinxpd 				flags = SM_WRITE;
9605f4fc069Sjilinxpd 			else if ((uiop->uio_loffset % bsize) == 0 ||
9615f4fc069Sjilinxpd 			    IS_SWAPVP(vp)) {
9625f4fc069Sjilinxpd 				/*
9635f4fc069Sjilinxpd 				 * Have written a whole block.
9645f4fc069Sjilinxpd 				 * Start an asynchronous write
9655f4fc069Sjilinxpd 				 * and mark the buffer to
9665f4fc069Sjilinxpd 				 * indicate that it won't be
9675f4fc069Sjilinxpd 				 * needed again soon.
9685f4fc069Sjilinxpd 				 */
9695f4fc069Sjilinxpd 				flags = SM_WRITE | SM_ASYNC | SM_DONTNEED;
9705f4fc069Sjilinxpd 			} else
9715f4fc069Sjilinxpd 				flags = 0;
9725f4fc069Sjilinxpd 			if ((ioflag & (FSYNC|FDSYNC)) ||
9735f4fc069Sjilinxpd 			    (np->r_flags & ROUTOFSPACE)) {
9745f4fc069Sjilinxpd 				flags &= ~SM_ASYNC;
9755f4fc069Sjilinxpd 				flags |= SM_WRITE;
9765f4fc069Sjilinxpd 			}
9775f4fc069Sjilinxpd 			if (vpm_enable) {
9785f4fc069Sjilinxpd 				error = vpm_sync_pages(vp, off, n, flags);
9795f4fc069Sjilinxpd 			} else {
9805f4fc069Sjilinxpd 				error = segmap_release(segkmap, base, flags);
9815f4fc069Sjilinxpd 			}
9825f4fc069Sjilinxpd 		} else {
9835f4fc069Sjilinxpd 			if (vpm_enable) {
9845f4fc069Sjilinxpd 				(void) vpm_sync_pages(vp, off, n, 0);
9855f4fc069Sjilinxpd 			} else {
9865f4fc069Sjilinxpd 				(void) segmap_release(segkmap, base, 0);
9875f4fc069Sjilinxpd 			}
9885f4fc069Sjilinxpd 			/*
9895f4fc069Sjilinxpd 			 * In the event that we got an access error while
9905f4fc069Sjilinxpd 			 * faulting in a page for a write-only file just
9915f4fc069Sjilinxpd 			 * force a write.
9925f4fc069Sjilinxpd 			 */
9935f4fc069Sjilinxpd 			if (error == EACCES)
9945f4fc069Sjilinxpd 				goto smbfs_fwrite;
9955f4fc069Sjilinxpd 		}
9965f4fc069Sjilinxpd 	} while (!error && uiop->uio_resid > 0);
9978329232eSGordon Ross #else	// _KERNEL
9988329232eSGordon Ross 	last_resid = uiop->uio_resid;
9998329232eSGordon Ross 	last_off = uiop->uio_loffset;
10008329232eSGordon Ross 	error = ENOSYS;
10018329232eSGordon Ross #endif	// _KERNEL
10024bff34e3Sthurlow 
10035f4fc069Sjilinxpd bottom:
10049c9af259SGordon Ross 	/* undo adjustment of resid */
10055f4fc069Sjilinxpd 	if (error) {
10065f4fc069Sjilinxpd 		uiop->uio_resid = last_resid + past_limit;
10075f4fc069Sjilinxpd 		uiop->uio_loffset = last_off;
10085f4fc069Sjilinxpd 	} else {
10095f4fc069Sjilinxpd 		uiop->uio_resid += past_limit;
10105f4fc069Sjilinxpd 	}
10119c9af259SGordon Ross 
10129c9af259SGordon Ross 	return (error);
10134bff34e3Sthurlow }
10144bff34e3Sthurlow 
10158329232eSGordon Ross #ifdef	_KERNEL
10168329232eSGordon Ross 
10175f4fc069Sjilinxpd /*
10185f4fc069Sjilinxpd  * Like nfs_client.c: writerp()
10195f4fc069Sjilinxpd  *
10205f4fc069Sjilinxpd  * Write by creating pages and uiomove data onto them.
10215f4fc069Sjilinxpd  */
10224bff34e3Sthurlow 
10235f4fc069Sjilinxpd int
smbfs_writenp(smbnode_t * np,caddr_t base,int tcount,struct uio * uio,int pgcreated)10245f4fc069Sjilinxpd smbfs_writenp(smbnode_t *np, caddr_t base, int tcount, struct uio *uio,
10255f4fc069Sjilinxpd     int pgcreated)
10267568150aSgwr {
10275f4fc069Sjilinxpd 	int		pagecreate;
10285f4fc069Sjilinxpd 	int		n;
10295f4fc069Sjilinxpd 	int		saved_n;
10305f4fc069Sjilinxpd 	caddr_t		saved_base;
10315f4fc069Sjilinxpd 	u_offset_t	offset;
10327568150aSgwr 	int		error;
10335f4fc069Sjilinxpd 	int		sm_error;
10345f4fc069Sjilinxpd 	vnode_t		*vp = SMBTOV(np);
10357568150aSgwr 
10365f4fc069Sjilinxpd 	ASSERT(tcount <= MAXBSIZE && tcount <= uio->uio_resid);
10375f4fc069Sjilinxpd 	ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_WRITER));
10385f4fc069Sjilinxpd 	if (!vpm_enable) {
10395f4fc069Sjilinxpd 		ASSERT(((uintptr_t)base & MAXBOFFSET) + tcount <= MAXBSIZE);
10405f4fc069Sjilinxpd 	}
10417568150aSgwr 
10425f4fc069Sjilinxpd 	/*
10435f4fc069Sjilinxpd 	 * Move bytes in at most PAGESIZE chunks. We must avoid
10445f4fc069Sjilinxpd 	 * spanning pages in uiomove() because page faults may cause
10455f4fc069Sjilinxpd 	 * the cache to be invalidated out from under us. The r_size is not
10465f4fc069Sjilinxpd 	 * updated until after the uiomove. If we push the last page of a
10475f4fc069Sjilinxpd 	 * file before r_size is correct, we will lose the data written past
10485f4fc069Sjilinxpd 	 * the current (and invalid) r_size.
10495f4fc069Sjilinxpd 	 */
10505f4fc069Sjilinxpd 	do {
10515f4fc069Sjilinxpd 		offset = uio->uio_loffset;
10525f4fc069Sjilinxpd 		pagecreate = 0;
10537568150aSgwr 
10545f4fc069Sjilinxpd 		/*
10555f4fc069Sjilinxpd 		 * n is the number of bytes required to satisfy the request
10565f4fc069Sjilinxpd 		 *   or the number of bytes to fill out the page.
10575f4fc069Sjilinxpd 		 */
10585f4fc069Sjilinxpd 		n = (int)MIN((PAGESIZE - (offset & PAGEOFFSET)), tcount);
10597568150aSgwr 
10605f4fc069Sjilinxpd 		/*
10615f4fc069Sjilinxpd 		 * Check to see if we can skip reading in the page
10625f4fc069Sjilinxpd 		 * and just allocate the memory.  We can do this
10635f4fc069Sjilinxpd 		 * if we are going to rewrite the entire mapping
10645f4fc069Sjilinxpd 		 * or if we are going to write to or beyond the current
10655f4fc069Sjilinxpd 		 * end of file from the beginning of the mapping.
10665f4fc069Sjilinxpd 		 *
10675f4fc069Sjilinxpd 		 * The read of r_size is now protected by r_statelock.
10685f4fc069Sjilinxpd 		 */
10695f4fc069Sjilinxpd 		mutex_enter(&np->r_statelock);
10705f4fc069Sjilinxpd 		/*
10715f4fc069Sjilinxpd 		 * When pgcreated is nonzero the caller has already done
10725f4fc069Sjilinxpd 		 * a segmap_getmapflt with forcefault 0 and S_WRITE. With
10735f4fc069Sjilinxpd 		 * segkpm this means we already have at least one page
10745f4fc069Sjilinxpd 		 * created and mapped at base.
10755f4fc069Sjilinxpd 		 */
10765f4fc069Sjilinxpd 		pagecreate = pgcreated ||
10775f4fc069Sjilinxpd 		    ((offset & PAGEOFFSET) == 0 &&
10785f4fc069Sjilinxpd 		    (n == PAGESIZE || ((offset + n) >= np->r_size)));
10797568150aSgwr 
10805f4fc069Sjilinxpd 		mutex_exit(&np->r_statelock);
10815f4fc069Sjilinxpd 		if (!vpm_enable && pagecreate) {
10825f4fc069Sjilinxpd 			/*
10835f4fc069Sjilinxpd 			 * The last argument tells segmap_pagecreate() to
10845f4fc069Sjilinxpd 			 * always lock the page, as opposed to sometimes
10855f4fc069Sjilinxpd 			 * returning with the page locked. This way we avoid a
10865f4fc069Sjilinxpd 			 * fault on the ensuing uiomove(), but also
10875f4fc069Sjilinxpd 			 * more importantly (to fix bug 1094402) we can
10885f4fc069Sjilinxpd 			 * call segmap_fault() to unlock the page in all
10895f4fc069Sjilinxpd 			 * cases. An alternative would be to modify
10905f4fc069Sjilinxpd 			 * segmap_pagecreate() to tell us when it is
10915f4fc069Sjilinxpd 			 * locking a page, but that's a fairly major
10925f4fc069Sjilinxpd 			 * interface change.
10935f4fc069Sjilinxpd 			 */
10945f4fc069Sjilinxpd 			if (pgcreated == 0)
10955f4fc069Sjilinxpd 				(void) segmap_pagecreate(segkmap, base,
10965f4fc069Sjilinxpd 				    (uint_t)n, 1);
10975f4fc069Sjilinxpd 			saved_base = base;
10985f4fc069Sjilinxpd 			saved_n = n;
10995f4fc069Sjilinxpd 		}
11007568150aSgwr 
11017568150aSgwr 		/*
11025f4fc069Sjilinxpd 		 * The number of bytes of data in the last page can not
11035f4fc069Sjilinxpd 		 * be accurately be determined while page is being
11045f4fc069Sjilinxpd 		 * uiomove'd to and the size of the file being updated.
11055f4fc069Sjilinxpd 		 * Thus, inform threads which need to know accurately
11065f4fc069Sjilinxpd 		 * how much data is in the last page of the file.  They
11075f4fc069Sjilinxpd 		 * will not do the i/o immediately, but will arrange for
11085f4fc069Sjilinxpd 		 * the i/o to happen later when this modify operation
11095f4fc069Sjilinxpd 		 * will have finished.
11107568150aSgwr 		 */
11115f4fc069Sjilinxpd 		ASSERT(!(np->r_flags & RMODINPROGRESS));
11125f4fc069Sjilinxpd 		mutex_enter(&np->r_statelock);
11135f4fc069Sjilinxpd 		np->r_flags |= RMODINPROGRESS;
11145f4fc069Sjilinxpd 		np->r_modaddr = (offset & MAXBMASK);
11155f4fc069Sjilinxpd 		mutex_exit(&np->r_statelock);
11167568150aSgwr 
11175f4fc069Sjilinxpd 		if (vpm_enable) {
11185f4fc069Sjilinxpd 			/*
11195f4fc069Sjilinxpd 			 * Copy data. If new pages are created, part of
11205f4fc069Sjilinxpd 			 * the page that is not written will be initizliazed
11215f4fc069Sjilinxpd 			 * with zeros.
11225f4fc069Sjilinxpd 			 */
11235f4fc069Sjilinxpd 			error = vpm_data_copy(vp, offset, n, uio,
11245f4fc069Sjilinxpd 			    !pagecreate, NULL, 0, S_WRITE);
11255f4fc069Sjilinxpd 		} else {
11265f4fc069Sjilinxpd 			error = uiomove(base, n, UIO_WRITE, uio);
11275f4fc069Sjilinxpd 		}
11287568150aSgwr 
11297568150aSgwr 		/*
11305f4fc069Sjilinxpd 		 * r_size is the maximum number of
11315f4fc069Sjilinxpd 		 * bytes known to be in the file.
11325f4fc069Sjilinxpd 		 * Make sure it is at least as high as the
11335f4fc069Sjilinxpd 		 * first unwritten byte pointed to by uio_loffset.
11347568150aSgwr 		 */
11355f4fc069Sjilinxpd 		mutex_enter(&np->r_statelock);
11365f4fc069Sjilinxpd 		if (np->r_size < uio->uio_loffset)
11375f4fc069Sjilinxpd 			np->r_size = uio->uio_loffset;
11385f4fc069Sjilinxpd 		np->r_flags &= ~RMODINPROGRESS;
11395f4fc069Sjilinxpd 		np->r_flags |= RDIRTY;
11405f4fc069Sjilinxpd 		mutex_exit(&np->r_statelock);
11417568150aSgwr 
11425f4fc069Sjilinxpd 		/* n = # of bytes written */
11435f4fc069Sjilinxpd 		n = (int)(uio->uio_loffset - offset);
11447568150aSgwr 
11455f4fc069Sjilinxpd 		if (!vpm_enable) {
11465f4fc069Sjilinxpd 			base += n;
11475f4fc069Sjilinxpd 		}
11485f4fc069Sjilinxpd 		tcount -= n;
11495f4fc069Sjilinxpd 		/*
11505f4fc069Sjilinxpd 		 * If we created pages w/o initializing them completely,
11515f4fc069Sjilinxpd 		 * we need to zero the part that wasn't set up.
11525f4fc069Sjilinxpd 		 * This happens on a most EOF write cases and if
11535f4fc069Sjilinxpd 		 * we had some sort of error during the uiomove.
11545f4fc069Sjilinxpd 		 */
11555f4fc069Sjilinxpd 		if (!vpm_enable && pagecreate) {
11565f4fc069Sjilinxpd 			if ((uio->uio_loffset & PAGEOFFSET) || n == 0)
11575f4fc069Sjilinxpd 				(void) kzero(base, PAGESIZE - n);
11585f4fc069Sjilinxpd 
11595f4fc069Sjilinxpd 			if (pgcreated) {
11605f4fc069Sjilinxpd 				/*
11615f4fc069Sjilinxpd 				 * Caller is responsible for this page,
11625f4fc069Sjilinxpd 				 * it was not created in this loop.
11635f4fc069Sjilinxpd 				 */
11645f4fc069Sjilinxpd 				pgcreated = 0;
11655f4fc069Sjilinxpd 			} else {
11665f4fc069Sjilinxpd 				/*
11675f4fc069Sjilinxpd 				 * For bug 1094402: segmap_pagecreate locks
11685f4fc069Sjilinxpd 				 * page. Unlock it. This also unlocks the
11695f4fc069Sjilinxpd 				 * pages allocated by page_create_va() in
11705f4fc069Sjilinxpd 				 * segmap_pagecreate().
11715f4fc069Sjilinxpd 				 */
11725f4fc069Sjilinxpd 				sm_error = segmap_fault(kas.a_hat, segkmap,
11735f4fc069Sjilinxpd 				    saved_base, saved_n,
11745f4fc069Sjilinxpd 				    F_SOFTUNLOCK, S_WRITE);
11755f4fc069Sjilinxpd 				if (error == 0)
11765f4fc069Sjilinxpd 					error = sm_error;
11775f4fc069Sjilinxpd 			}
11785f4fc069Sjilinxpd 		}
11795f4fc069Sjilinxpd 	} while (tcount > 0 && error == 0);
11807568150aSgwr 
11817568150aSgwr 	return (error);
11827568150aSgwr }
11837568150aSgwr 
11844bff34e3Sthurlow /*
11855f4fc069Sjilinxpd  * Flags are composed of {B_ASYNC, B_INVAL, B_FREE, B_DONTNEED}
11865f4fc069Sjilinxpd  * Like nfs3_rdwrlbn()
11874bff34e3Sthurlow  */
11884bff34e3Sthurlow static int
smbfs_rdwrlbn(vnode_t * vp,page_t * pp,u_offset_t off,size_t len,int flags,cred_t * cr)11895f4fc069Sjilinxpd smbfs_rdwrlbn(vnode_t *vp, page_t *pp, u_offset_t off, size_t len,
11905f4fc069Sjilinxpd 	int flags, cred_t *cr)
11914bff34e3Sthurlow {
11925f4fc069Sjilinxpd 	smbmntinfo_t	*smi = VTOSMI(vp);
11935f4fc069Sjilinxpd 	struct buf *bp;
11945f4fc069Sjilinxpd 	int error;
11955f4fc069Sjilinxpd 	int sync;
11964bff34e3Sthurlow 
1197a19609f8Sjv 	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
11984bff34e3Sthurlow 		return (EIO);
11994bff34e3Sthurlow 
12004bff34e3Sthurlow 	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
12014bff34e3Sthurlow 		return (EIO);
12024bff34e3Sthurlow 
12035f4fc069Sjilinxpd 	bp = pageio_setup(pp, len, vp, flags);
12045f4fc069Sjilinxpd 	ASSERT(bp != NULL);
12055f4fc069Sjilinxpd 
12064bff34e3Sthurlow 	/*
12075f4fc069Sjilinxpd 	 * pageio_setup should have set b_addr to 0.  This
12085f4fc069Sjilinxpd 	 * is correct since we want to do I/O on a page
12095f4fc069Sjilinxpd 	 * boundary.  bp_mapin will use this addr to calculate
12105f4fc069Sjilinxpd 	 * an offset, and then set b_addr to the kernel virtual
12115f4fc069Sjilinxpd 	 * address it allocated for us.
12124bff34e3Sthurlow 	 */
12135f4fc069Sjilinxpd 	ASSERT(bp->b_un.b_addr == 0);
12144bff34e3Sthurlow 
12155f4fc069Sjilinxpd 	bp->b_edev = 0;
12165f4fc069Sjilinxpd 	bp->b_dev = 0;
12175f4fc069Sjilinxpd 	bp->b_lblkno = lbtodb(off);
12185f4fc069Sjilinxpd 	bp->b_file = vp;
12195f4fc069Sjilinxpd 	bp->b_offset = (offset_t)off;
12205f4fc069Sjilinxpd 	bp_mapin(bp);
12215f4fc069Sjilinxpd 
12225f4fc069Sjilinxpd 	/*
12235f4fc069Sjilinxpd 	 * Calculate the desired level of stability to write data.
12245f4fc069Sjilinxpd 	 */
12255f4fc069Sjilinxpd 	if ((flags & (B_WRITE|B_ASYNC)) == (B_WRITE|B_ASYNC) &&
12265f4fc069Sjilinxpd 	    freemem > desfree) {
12275f4fc069Sjilinxpd 		sync = 0;
12285f4fc069Sjilinxpd 	} else {
12295f4fc069Sjilinxpd 		sync = 1;
12305f4fc069Sjilinxpd 	}
12315f4fc069Sjilinxpd 
12325f4fc069Sjilinxpd 	error = smbfs_bio(bp, sync, cr);
12335f4fc069Sjilinxpd 
12345f4fc069Sjilinxpd 	bp_mapout(bp);
12355f4fc069Sjilinxpd 	pageio_done(bp);
12365f4fc069Sjilinxpd 
12375f4fc069Sjilinxpd 	return (error);
12385f4fc069Sjilinxpd }
12395f4fc069Sjilinxpd 
12405f4fc069Sjilinxpd 
12415f4fc069Sjilinxpd /*
12425f4fc069Sjilinxpd  * Corresponds to nfs3_vnopc.c : nfs3_bio(), though the NFS code
12435f4fc069Sjilinxpd  * uses nfs3read()/nfs3write() where we use smb_rwuio().  Also,
12445f4fc069Sjilinxpd  * NFS has this later in the file.  Move it up here closer to
12455f4fc069Sjilinxpd  * the one call site just above.
12465f4fc069Sjilinxpd  */
12475f4fc069Sjilinxpd 
12485f4fc069Sjilinxpd static int
smbfs_bio(struct buf * bp,int sync,cred_t * cr)12495f4fc069Sjilinxpd smbfs_bio(struct buf *bp, int sync, cred_t *cr)
12505f4fc069Sjilinxpd {
12515f4fc069Sjilinxpd 	struct iovec aiov[1];
12525f4fc069Sjilinxpd 	struct uio  auio;
12535f4fc069Sjilinxpd 	struct smb_cred scred;
12545f4fc069Sjilinxpd 	smbnode_t *np = VTOSMB(bp->b_vp);
12555f4fc069Sjilinxpd 	smbmntinfo_t *smi = np->n_mount;
12565f4fc069Sjilinxpd 	offset_t offset;
12575f4fc069Sjilinxpd 	offset_t endoff;
12585f4fc069Sjilinxpd 	size_t count;
12595f4fc069Sjilinxpd 	size_t past_eof;
12605f4fc069Sjilinxpd 	int error;
12615f4fc069Sjilinxpd 
12625f4fc069Sjilinxpd 	ASSERT(curproc->p_zone == smi->smi_zone_ref.zref_zone);
12635f4fc069Sjilinxpd 
12645f4fc069Sjilinxpd 	offset = ldbtob(bp->b_lblkno);
12655f4fc069Sjilinxpd 	count = bp->b_bcount;
12665f4fc069Sjilinxpd 	endoff = offset + count;
12675f4fc069Sjilinxpd 	if (offset < 0 || endoff < 0)
12685f4fc069Sjilinxpd 		return (EINVAL);
12695f4fc069Sjilinxpd 
12705f4fc069Sjilinxpd 	/*
12715f4fc069Sjilinxpd 	 * Limit file I/O to the remaining file size, but see
12725f4fc069Sjilinxpd 	 * the notes in smbfs_getpage about SMBFS_EOF.
12735f4fc069Sjilinxpd 	 */
12745f4fc069Sjilinxpd 	mutex_enter(&np->r_statelock);
12755f4fc069Sjilinxpd 	if (offset >= np->r_size) {
12765f4fc069Sjilinxpd 		mutex_exit(&np->r_statelock);
12775f4fc069Sjilinxpd 		if (bp->b_flags & B_READ) {
12785f4fc069Sjilinxpd 			return (SMBFS_EOF);
12795f4fc069Sjilinxpd 		} else {
12805f4fc069Sjilinxpd 			return (EINVAL);
12815f4fc069Sjilinxpd 		}
12825f4fc069Sjilinxpd 	}
12835f4fc069Sjilinxpd 	if (endoff > np->r_size) {
12845f4fc069Sjilinxpd 		past_eof = (size_t)(endoff - np->r_size);
12855f4fc069Sjilinxpd 		count -= past_eof;
12865f4fc069Sjilinxpd 	} else
12875f4fc069Sjilinxpd 		past_eof = 0;
12885f4fc069Sjilinxpd 	mutex_exit(&np->r_statelock);
12895f4fc069Sjilinxpd 	ASSERT(count > 0);
12905f4fc069Sjilinxpd 
12915f4fc069Sjilinxpd 	/* Caller did bpmapin().  Mapped address is... */
12925f4fc069Sjilinxpd 	aiov[0].iov_base = bp->b_un.b_addr;
12935f4fc069Sjilinxpd 	aiov[0].iov_len = count;
12945f4fc069Sjilinxpd 	auio.uio_iov = aiov;
12955f4fc069Sjilinxpd 	auio.uio_iovcnt = 1;
12965f4fc069Sjilinxpd 	auio.uio_loffset = offset;
12975f4fc069Sjilinxpd 	auio.uio_segflg = UIO_SYSSPACE;
12985f4fc069Sjilinxpd 	auio.uio_fmode = 0;
12995f4fc069Sjilinxpd 	auio.uio_resid = count;
13005f4fc069Sjilinxpd 
13015f4fc069Sjilinxpd 	/* Shared lock for n_fid use in smb_rwuio */
13025f4fc069Sjilinxpd 	if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER,
13035f4fc069Sjilinxpd 	    smi->smi_flags & SMI_INT))
13045f4fc069Sjilinxpd 		return (EINTR);
13055f4fc069Sjilinxpd 	smb_credinit(&scred, cr);
13065f4fc069Sjilinxpd 
13075f4fc069Sjilinxpd 	DTRACE_IO1(start, struct buf *, bp);
13085f4fc069Sjilinxpd 
13095f4fc069Sjilinxpd 	if (bp->b_flags & B_READ) {
13105f4fc069Sjilinxpd 
1311adee6784SGordon Ross 		error = smb_rwuio(np->n_fid, UIO_READ,
1312adee6784SGordon Ross 		    &auio, &scred, smb_timo_read);
13135f4fc069Sjilinxpd 
13145f4fc069Sjilinxpd 		/* Like NFS, only set b_error here. */
13155f4fc069Sjilinxpd 		bp->b_error = error;
13165f4fc069Sjilinxpd 		bp->b_resid = auio.uio_resid;
13175f4fc069Sjilinxpd 
13185f4fc069Sjilinxpd 		if (!error && auio.uio_resid != 0)
13195f4fc069Sjilinxpd 			error = EIO;
13205f4fc069Sjilinxpd 		if (!error && past_eof != 0) {
13215f4fc069Sjilinxpd 			/* Zero the memory beyond EOF. */
13225f4fc069Sjilinxpd 			bzero(bp->b_un.b_addr + count, past_eof);
13235f4fc069Sjilinxpd 		}
13245f4fc069Sjilinxpd 	} else {
13255f4fc069Sjilinxpd 
1326adee6784SGordon Ross 		error = smb_rwuio(np->n_fid, UIO_WRITE,
1327adee6784SGordon Ross 		    &auio, &scred, smb_timo_write);
13285f4fc069Sjilinxpd 
13295f4fc069Sjilinxpd 		/* Like NFS, only set b_error here. */
13305f4fc069Sjilinxpd 		bp->b_error = error;
13315f4fc069Sjilinxpd 		bp->b_resid = auio.uio_resid;
13325f4fc069Sjilinxpd 
13335f4fc069Sjilinxpd 		if (!error && auio.uio_resid != 0)
13345f4fc069Sjilinxpd 			error = EIO;
13355f4fc069Sjilinxpd 		if (!error && sync) {
1336adee6784SGordon Ross 			(void) smbfsflush(np, &scred);
13375f4fc069Sjilinxpd 		}
13385f4fc069Sjilinxpd 	}
13395f4fc069Sjilinxpd 
13405f4fc069Sjilinxpd 	/*
13415f4fc069Sjilinxpd 	 * This comes from nfs3_commit()
13425f4fc069Sjilinxpd 	 */
13435f4fc069Sjilinxpd 	if (error != 0) {
13445f4fc069Sjilinxpd 		mutex_enter(&np->r_statelock);
13455f4fc069Sjilinxpd 		if (error == ESTALE)
13465f4fc069Sjilinxpd 			np->r_flags |= RSTALE;
13475f4fc069Sjilinxpd 		if (!np->r_error)
13485f4fc069Sjilinxpd 			np->r_error = error;
13495f4fc069Sjilinxpd 		mutex_exit(&np->r_statelock);
13505f4fc069Sjilinxpd 		bp->b_flags |= B_ERROR;
13515f4fc069Sjilinxpd 	}
13525f4fc069Sjilinxpd 
13535f4fc069Sjilinxpd 	DTRACE_IO1(done, struct buf *, bp);
13545f4fc069Sjilinxpd 
13555f4fc069Sjilinxpd 	smb_credrele(&scred);
13565f4fc069Sjilinxpd 	smbfs_rw_exit(&np->r_lkserlock);
13575f4fc069Sjilinxpd 
13585f4fc069Sjilinxpd 	if (error == ESTALE)
13595f4fc069Sjilinxpd 		smbfs_attrcache_remove(np);
13605f4fc069Sjilinxpd 
13615f4fc069Sjilinxpd 	return (error);
13625f4fc069Sjilinxpd }
13638329232eSGordon Ross #endif	// _KERNEL
13645f4fc069Sjilinxpd 
13655f4fc069Sjilinxpd /*
13665f4fc069Sjilinxpd  * Here NFS has: nfs3write, nfs3read
13675f4fc069Sjilinxpd  * We use smb_rwuio instead.
13685f4fc069Sjilinxpd  */
13695f4fc069Sjilinxpd 
13705f4fc069Sjilinxpd /* ARGSUSED */
13715f4fc069Sjilinxpd static int
smbfs_ioctl(vnode_t * vp,int cmd,intptr_t arg,int flag,cred_t * cr,int * rvalp,caller_context_t * ct)13725f4fc069Sjilinxpd smbfs_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag,
13735f4fc069Sjilinxpd 	cred_t *cr, int *rvalp,	caller_context_t *ct)
13745f4fc069Sjilinxpd {
13755f4fc069Sjilinxpd 	int		error;
13765f4fc069Sjilinxpd 	smbmntinfo_t	*smi;
13775f4fc069Sjilinxpd 
13785f4fc069Sjilinxpd 	smi = VTOSMI(vp);
13795f4fc069Sjilinxpd 
13805f4fc069Sjilinxpd 	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
13815f4fc069Sjilinxpd 		return (EIO);
13825f4fc069Sjilinxpd 
13835f4fc069Sjilinxpd 	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
13845f4fc069Sjilinxpd 		return (EIO);
13855f4fc069Sjilinxpd 
13865f4fc069Sjilinxpd 	switch (cmd) {
13875f4fc069Sjilinxpd 
13885f4fc069Sjilinxpd 	case _FIOFFS:
13895f4fc069Sjilinxpd 		error = smbfs_fsync(vp, 0, cr, ct);
13905f4fc069Sjilinxpd 		break;
13915f4fc069Sjilinxpd 
13925f4fc069Sjilinxpd 		/*
13935f4fc069Sjilinxpd 		 * The following two ioctls are used by bfu.
13945f4fc069Sjilinxpd 		 * Silently ignore to avoid bfu errors.
13955f4fc069Sjilinxpd 		 */
13965f4fc069Sjilinxpd 	case _FIOGDIO:
13975f4fc069Sjilinxpd 	case _FIOSDIO:
13985f4fc069Sjilinxpd 		error = 0;
13995f4fc069Sjilinxpd 		break;
14005f4fc069Sjilinxpd 
14015f4fc069Sjilinxpd #if 0	/* Todo - SMB ioctl query regions */
14025f4fc069Sjilinxpd 	case _FIO_SEEK_DATA:
14035f4fc069Sjilinxpd 	case _FIO_SEEK_HOLE:
14045f4fc069Sjilinxpd #endif
14055f4fc069Sjilinxpd 
14065f4fc069Sjilinxpd 	case _FIODIRECTIO:
14075f4fc069Sjilinxpd 		error = smbfs_directio(vp, (int)arg, cr);
14085f4fc069Sjilinxpd 		break;
14095f4fc069Sjilinxpd 
14105f4fc069Sjilinxpd 		/*
14115f4fc069Sjilinxpd 		 * Allow get/set with "raw" security descriptor (SD) data.
14125f4fc069Sjilinxpd 		 * Useful for testing, diagnosing idmap problems, etc.
14135f4fc069Sjilinxpd 		 */
14145f4fc069Sjilinxpd 	case SMBFSIO_GETSD:
14155f4fc069Sjilinxpd 		error = smbfs_acl_iocget(vp, arg, flag, cr);
14165f4fc069Sjilinxpd 		break;
14175f4fc069Sjilinxpd 
14185f4fc069Sjilinxpd 	case SMBFSIO_SETSD:
14195f4fc069Sjilinxpd 		error = smbfs_acl_iocset(vp, arg, flag, cr);
14205f4fc069Sjilinxpd 		break;
14215f4fc069Sjilinxpd 
14225f4fc069Sjilinxpd 	default:
14235f4fc069Sjilinxpd 		error = ENOTTY;
14245f4fc069Sjilinxpd 		break;
14255f4fc069Sjilinxpd 	}
14265f4fc069Sjilinxpd 
14275f4fc069Sjilinxpd 	return (error);
14285f4fc069Sjilinxpd }
14295f4fc069Sjilinxpd 
14305f4fc069Sjilinxpd 
14315f4fc069Sjilinxpd /*
14325f4fc069Sjilinxpd  * Return either cached or remote attributes. If get remote attr
14335f4fc069Sjilinxpd  * use them to check and invalidate caches, then cache the new attributes.
14345f4fc069Sjilinxpd  */
14355f4fc069Sjilinxpd /* ARGSUSED */
14365f4fc069Sjilinxpd static int
smbfs_getattr(vnode_t * vp,struct vattr * vap,int flags,cred_t * cr,caller_context_t * ct)14375f4fc069Sjilinxpd smbfs_getattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr,
14385f4fc069Sjilinxpd 	caller_context_t *ct)
14395f4fc069Sjilinxpd {
14405f4fc069Sjilinxpd 	smbnode_t *np;
14415f4fc069Sjilinxpd 	smbmntinfo_t *smi;
14425f4fc069Sjilinxpd 	int error;
14435f4fc069Sjilinxpd 
14445f4fc069Sjilinxpd 	smi = VTOSMI(vp);
14455f4fc069Sjilinxpd 
14465f4fc069Sjilinxpd 	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
14475f4fc069Sjilinxpd 		return (EIO);
14485f4fc069Sjilinxpd 
14495f4fc069Sjilinxpd 	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
14505f4fc069Sjilinxpd 		return (EIO);
14515f4fc069Sjilinxpd 
14525f4fc069Sjilinxpd 	/*
14535f4fc069Sjilinxpd 	 * If it has been specified that the return value will
14545f4fc069Sjilinxpd 	 * just be used as a hint, and we are only being asked
14555f4fc069Sjilinxpd 	 * for size, fsid or rdevid, then return the client's
14565f4fc069Sjilinxpd 	 * notion of these values without checking to make sure
14575f4fc069Sjilinxpd 	 * that the attribute cache is up to date.
14585f4fc069Sjilinxpd 	 * The whole point is to avoid an over the wire GETATTR
14595f4fc069Sjilinxpd 	 * call.
14605f4fc069Sjilinxpd 	 */
14615f4fc069Sjilinxpd 	np = VTOSMB(vp);
14625f4fc069Sjilinxpd 	if (flags & ATTR_HINT) {
14635f4fc069Sjilinxpd 		if (vap->va_mask ==
14645f4fc069Sjilinxpd 		    (vap->va_mask & (AT_SIZE | AT_FSID | AT_RDEV))) {
14655f4fc069Sjilinxpd 			mutex_enter(&np->r_statelock);
14665f4fc069Sjilinxpd 			if (vap->va_mask | AT_SIZE)
14675f4fc069Sjilinxpd 				vap->va_size = np->r_size;
14685f4fc069Sjilinxpd 			if (vap->va_mask | AT_FSID)
14695f4fc069Sjilinxpd 				vap->va_fsid = vp->v_vfsp->vfs_dev;
14705f4fc069Sjilinxpd 			if (vap->va_mask | AT_RDEV)
14715f4fc069Sjilinxpd 				vap->va_rdev = vp->v_rdev;
14725f4fc069Sjilinxpd 			mutex_exit(&np->r_statelock);
14735f4fc069Sjilinxpd 			return (0);
14745f4fc069Sjilinxpd 		}
14755f4fc069Sjilinxpd 	}
14765f4fc069Sjilinxpd 
14775f4fc069Sjilinxpd 	/*
14785f4fc069Sjilinxpd 	 * Only need to flush pages if asking for the mtime
14795f4fc069Sjilinxpd 	 * and if there any dirty pages.
14805f4fc069Sjilinxpd 	 *
14815f4fc069Sjilinxpd 	 * Here NFS also checks for async writes (np->r_awcount)
14825f4fc069Sjilinxpd 	 */
14835f4fc069Sjilinxpd 	if (vap->va_mask & AT_MTIME) {
14845f4fc069Sjilinxpd 		if (vn_has_cached_data(vp) &&
14855f4fc069Sjilinxpd 		    ((np->r_flags & RDIRTY) != 0)) {
14865f4fc069Sjilinxpd 			mutex_enter(&np->r_statelock);
14875f4fc069Sjilinxpd 			np->r_gcount++;
14885f4fc069Sjilinxpd 			mutex_exit(&np->r_statelock);
14895f4fc069Sjilinxpd 			error = smbfs_putpage(vp, (offset_t)0, 0, 0, cr, ct);
14905f4fc069Sjilinxpd 			mutex_enter(&np->r_statelock);
14915f4fc069Sjilinxpd 			if (error && (error == ENOSPC || error == EDQUOT)) {
14925f4fc069Sjilinxpd 				if (!np->r_error)
14935f4fc069Sjilinxpd 					np->r_error = error;
14945f4fc069Sjilinxpd 			}
14955f4fc069Sjilinxpd 			if (--np->r_gcount == 0)
14965f4fc069Sjilinxpd 				cv_broadcast(&np->r_cv);
14975f4fc069Sjilinxpd 			mutex_exit(&np->r_statelock);
14985f4fc069Sjilinxpd 		}
14995f4fc069Sjilinxpd 	}
15005f4fc069Sjilinxpd 
15015f4fc069Sjilinxpd 	return (smbfsgetattr(vp, vap, cr));
15025f4fc069Sjilinxpd }
15034bff34e3Sthurlow 
150402d09e03SGordon Ross /* smbfsgetattr() in smbfs_client.c */
15054bff34e3Sthurlow 
15064bff34e3Sthurlow /*ARGSUSED4*/
15074bff34e3Sthurlow static int
smbfs_setattr(vnode_t * vp,struct vattr * vap,int flags,cred_t * cr,caller_context_t * ct)15084bff34e3Sthurlow smbfs_setattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr,
15094bff34e3Sthurlow 		caller_context_t *ct)
15104bff34e3Sthurlow {
151102d09e03SGordon Ross 	vfs_t		*vfsp;
151202d09e03SGordon Ross 	smbmntinfo_t	*smi;
15134bff34e3Sthurlow 	int		error;
15144bff34e3Sthurlow 	uint_t		mask;
15154bff34e3Sthurlow 	struct vattr	oldva;
15164bff34e3Sthurlow 
151702d09e03SGordon Ross 	vfsp = vp->v_vfsp;
151802d09e03SGordon Ross 	smi = VFTOSMI(vfsp);
15194bff34e3Sthurlow 
1520a19609f8Sjv 	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
15214bff34e3Sthurlow 		return (EIO);
15224bff34e3Sthurlow 
152302d09e03SGordon Ross 	if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
15244bff34e3Sthurlow 		return (EIO);
15254bff34e3Sthurlow 
15264bff34e3Sthurlow 	mask = vap->va_mask;
15274bff34e3Sthurlow 	if (mask & AT_NOSET)
15284bff34e3Sthurlow 		return (EINVAL);
15294bff34e3Sthurlow 
153002d09e03SGordon Ross 	if (vfsp->vfs_flag & VFS_RDONLY)
153102d09e03SGordon Ross 		return (EROFS);
153202d09e03SGordon Ross 
1533bd7c6f51SGordon Ross 	/*
1534bd7c6f51SGordon Ross 	 * This is a _local_ access check so that only the owner of
1535bd7c6f51SGordon Ross 	 * this mount can set attributes.  With ACLs enabled, the
1536bd7c6f51SGordon Ross 	 * file owner can be different from the mount owner, and we
1537bd7c6f51SGordon Ross 	 * need to check the _mount_ owner here.  See _access_rwx
1538bd7c6f51SGordon Ross 	 */
153902d09e03SGordon Ross 	bzero(&oldva, sizeof (oldva));
1540bd7c6f51SGordon Ross 	oldva.va_mask = AT_TYPE | AT_MODE;
15414bff34e3Sthurlow 	error = smbfsgetattr(vp, &oldva, cr);
15424bff34e3Sthurlow 	if (error)
15434bff34e3Sthurlow 		return (error);
1544bd7c6f51SGordon Ross 	oldva.va_mask |= AT_UID | AT_GID;
1545bd7c6f51SGordon Ross 	oldva.va_uid = smi->smi_uid;
1546bd7c6f51SGordon Ross 	oldva.va_gid = smi->smi_gid;
15474bff34e3Sthurlow 
15484bff34e3Sthurlow 	error = secpolicy_vnode_setattr(cr, vp, vap, &oldva, flags,
15494bff34e3Sthurlow 	    smbfs_accessx, vp);
15504bff34e3Sthurlow 	if (error)
15514bff34e3Sthurlow 		return (error);
15524bff34e3Sthurlow 
1553bd7c6f51SGordon Ross 	if (mask & (AT_UID | AT_GID)) {
1554bd7c6f51SGordon Ross 		if (smi->smi_flags & SMI_ACL)
1555bd7c6f51SGordon Ross 			error = smbfs_acl_setids(vp, vap, cr);
1556bd7c6f51SGordon Ross 		else
1557bd7c6f51SGordon Ross 			error = ENOSYS;
1558bd7c6f51SGordon Ross 		if (error != 0) {
1559bd7c6f51SGordon Ross 			SMBVDEBUG("error %d seting UID/GID on %s",
1560bd7c6f51SGordon Ross 			    error, VTOSMB(vp)->n_rpath);
1561bd7c6f51SGordon Ross 			/*
1562bd7c6f51SGordon Ross 			 * It might be more correct to return the
1563bd7c6f51SGordon Ross 			 * error here, but that causes complaints
1564bd7c6f51SGordon Ross 			 * when root extracts a cpio archive, etc.
1565bd7c6f51SGordon Ross 			 * So ignore this error, and go ahead with
1566bd7c6f51SGordon Ross 			 * the rest of the setattr work.
1567bd7c6f51SGordon Ross 			 */
1568bd7c6f51SGordon Ross 		}
1569bd7c6f51SGordon Ross 	}
1570bd7c6f51SGordon Ross 
15715f4fc069Sjilinxpd 	error = smbfssetattr(vp, vap, flags, cr);
15725f4fc069Sjilinxpd 
15735f4fc069Sjilinxpd #ifdef	SMBFS_VNEVENT
15745f4fc069Sjilinxpd 	if (error == 0 && (vap->va_mask & AT_SIZE) && vap->va_size == 0)
15755f4fc069Sjilinxpd 		vnevent_truncate(vp, ct);
15765f4fc069Sjilinxpd #endif
15775f4fc069Sjilinxpd 
15785f4fc069Sjilinxpd 	return (error);
15794bff34e3Sthurlow }
15804bff34e3Sthurlow 
15814bff34e3Sthurlow /*
15824bff34e3Sthurlow  * Mostly from Darwin smbfs_setattr()
15834bff34e3Sthurlow  * but then modified a lot.
15844bff34e3Sthurlow  */
15854bff34e3Sthurlow /* ARGSUSED */
15864bff34e3Sthurlow static int
smbfssetattr(vnode_t * vp,struct vattr * vap,int flags,cred_t * cr)15874bff34e3Sthurlow smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
15884bff34e3Sthurlow {
15894bff34e3Sthurlow 	int		error = 0;
15904bff34e3Sthurlow 	smbnode_t	*np = VTOSMB(vp);
1591adee6784SGordon Ross 	smbmntinfo_t	*smi = np->n_mount;
15924bff34e3Sthurlow 	uint_t		mask = vap->va_mask;
15934bff34e3Sthurlow 	struct timespec	*mtime, *atime;
15944bff34e3Sthurlow 	struct smb_cred	scred;
1595adee6784SGordon Ross 	int		modified = 0;
1596adee6784SGordon Ross 	smb_fh_t	*fid = NULL;
15974bff34e3Sthurlow 	uint32_t rights = 0;
159828162916SGordon Ross 	uint32_t dosattr = 0;
15994bff34e3Sthurlow 
1600a19609f8Sjv 	ASSERT(curproc->p_zone == VTOSMI(vp)->smi_zone_ref.zref_zone);
16014bff34e3Sthurlow 
160291d632c8Sgwr 	/*
160391d632c8Sgwr 	 * There are no settable attributes on the XATTR dir,
160491d632c8Sgwr 	 * so just silently ignore these.  On XATTR files,
160591d632c8Sgwr 	 * you can set the size but nothing else.
160691d632c8Sgwr 	 */
160791d632c8Sgwr 	if (vp->v_flag & V_XATTRDIR)
160891d632c8Sgwr 		return (0);
160991d632c8Sgwr 	if (np->n_flag & N_XATTR) {
161091d632c8Sgwr 		if (mask & AT_TIMES)
161191d632c8Sgwr 			SMBVDEBUG("ignore set time on xattr\n");
161291d632c8Sgwr 		mask &= AT_SIZE;
161391d632c8Sgwr 	}
161491d632c8Sgwr 
16155f4fc069Sjilinxpd 	/*
16165f4fc069Sjilinxpd 	 * Only need to flush pages if there are any pages and
16175f4fc069Sjilinxpd 	 * if the file is marked as dirty in some fashion.  The
16185f4fc069Sjilinxpd 	 * file must be flushed so that we can accurately
16195f4fc069Sjilinxpd 	 * determine the size of the file and the cached data
16205f4fc069Sjilinxpd 	 * after the SETATTR returns.  A file is considered to
16215f4fc069Sjilinxpd 	 * be dirty if it is either marked with RDIRTY, has
16225f4fc069Sjilinxpd 	 * outstanding i/o's active, or is mmap'd.  In this
16235f4fc069Sjilinxpd 	 * last case, we can't tell whether there are dirty
16245f4fc069Sjilinxpd 	 * pages, so we flush just to be sure.
16255f4fc069Sjilinxpd 	 */
16265f4fc069Sjilinxpd 	if (vn_has_cached_data(vp) &&
16275f4fc069Sjilinxpd 	    ((np->r_flags & RDIRTY) ||
16285f4fc069Sjilinxpd 	    np->r_count > 0 ||
16295f4fc069Sjilinxpd 	    np->r_mapcnt > 0)) {
16305f4fc069Sjilinxpd 		ASSERT(vp->v_type != VCHR);
16315f4fc069Sjilinxpd 		error = smbfs_putpage(vp, (offset_t)0, 0, 0, cr, NULL);
16325f4fc069Sjilinxpd 		if (error && (error == ENOSPC || error == EDQUOT)) {
16335f4fc069Sjilinxpd 			mutex_enter(&np->r_statelock);
16345f4fc069Sjilinxpd 			if (!np->r_error)
16355f4fc069Sjilinxpd 				np->r_error = error;
16365f4fc069Sjilinxpd 			mutex_exit(&np->r_statelock);
16375f4fc069Sjilinxpd 		}
16385f4fc069Sjilinxpd 	}
16395f4fc069Sjilinxpd 
16404bff34e3Sthurlow 	/*
16414bff34e3Sthurlow 	 * If our caller is trying to set multiple attributes, they
16424bff34e3Sthurlow 	 * can make no assumption about what order they are done in.
16434bff34e3Sthurlow 	 * Here we try to do them in order of decreasing likelihood
16444bff34e3Sthurlow 	 * of failure, just to minimize the chance we'll wind up
16454bff34e3Sthurlow 	 * with a partially complete request.
16464bff34e3Sthurlow 	 */
16474bff34e3Sthurlow 
1648613a2f6bSGordon Ross 	smb_credinit(&scred, cr);
16494bff34e3Sthurlow 
165028162916SGordon Ross 	/*
165128162916SGordon Ross 	 * If the caller has provided extensible attributes,
165228162916SGordon Ross 	 * map those into DOS attributes supported by SMB.
165328162916SGordon Ross 	 * Note: zero means "no change".
165428162916SGordon Ross 	 */
165528162916SGordon Ross 	if (mask & AT_XVATTR)
165628162916SGordon Ross 		dosattr = xvattr_to_dosattr(np, vap);
165728162916SGordon Ross 
16584bff34e3Sthurlow 	/*
16594bff34e3Sthurlow 	 * Will we need an open handle for this setattr?
16604bff34e3Sthurlow 	 * If so, what rights will we need?
16614bff34e3Sthurlow 	 */
166228162916SGordon Ross 	if (dosattr || (mask & (AT_ATIME | AT_MTIME))) {
16634bff34e3Sthurlow 		rights |=
166402d09e03SGordon Ross 		    SA_RIGHT_FILE_WRITE_ATTRIBUTES;
16654bff34e3Sthurlow 	}
16664bff34e3Sthurlow 	if (mask & AT_SIZE) {
16674bff34e3Sthurlow 		rights |=
16684bff34e3Sthurlow 		    SA_RIGHT_FILE_WRITE_DATA |
16694bff34e3Sthurlow 		    SA_RIGHT_FILE_APPEND_DATA;
167002d09e03SGordon Ross 	}
167102d09e03SGordon Ross 
167202d09e03SGordon Ross 	/*
167302d09e03SGordon Ross 	 * Only SIZE really requires a handle, but it's
167402d09e03SGordon Ross 	 * simpler and more reliable to set via a handle.
167502d09e03SGordon Ross 	 * Some servers like NT4 won't set times by path.
167602d09e03SGordon Ross 	 * Also, we're usually setting everything anyway.
167702d09e03SGordon Ross 	 */
167828162916SGordon Ross 	if (rights != 0) {
16794bff34e3Sthurlow 		error = smbfs_smb_tmpopen(np, rights, &scred, &fid);
16804bff34e3Sthurlow 		if (error) {
16814bff34e3Sthurlow 			SMBVDEBUG("error %d opening %s\n",
16824bff34e3Sthurlow 			    error, np->n_rpath);
16834bff34e3Sthurlow 			goto out;
16844bff34e3Sthurlow 		}
1685adee6784SGordon Ross 		ASSERT(fid != NULL);
16864bff34e3Sthurlow 	}
16874bff34e3Sthurlow 
16884bff34e3Sthurlow 	/*
16894bff34e3Sthurlow 	 * If the server supports the UNIX extensions, right here is where
16904bff34e3Sthurlow 	 * we'd support changes to uid, gid, mode, and possibly va_flags.
16914bff34e3Sthurlow 	 * For now we claim to have made any such changes.
16924bff34e3Sthurlow 	 */
16934bff34e3Sthurlow 
16944bff34e3Sthurlow 	if (mask & AT_SIZE) {
16954bff34e3Sthurlow 		/*
16964bff34e3Sthurlow 		 * If the new file size is less than what the client sees as
16974bff34e3Sthurlow 		 * the file size, then just change the size and invalidate
16984bff34e3Sthurlow 		 * the pages.
16994bff34e3Sthurlow 		 */
17004bff34e3Sthurlow 
17014bff34e3Sthurlow 		/*
17024bff34e3Sthurlow 		 * Set the file size to vap->va_size.
17034bff34e3Sthurlow 		 */
1704adee6784SGordon Ross 		ASSERT(fid != NULL);
1705adee6784SGordon Ross 		error = smbfs_smb_setfsize(smi->smi_share, fid,
1706adee6784SGordon Ross 		    vap->va_size, &scred);
17074bff34e3Sthurlow 		if (error) {
17084bff34e3Sthurlow 			SMBVDEBUG("setsize error %d file %s\n",
17094bff34e3Sthurlow 			    error, np->n_rpath);
17104bff34e3Sthurlow 		} else {
17114bff34e3Sthurlow 			/*
17124bff34e3Sthurlow 			 * Darwin had code here to zero-extend.
17134bff34e3Sthurlow 			 * Tests indicate the server will zero-fill,
17145f4fc069Sjilinxpd 			 * so looks like we don't need to do that.
17154bff34e3Sthurlow 			 */
17164bff34e3Sthurlow 			mutex_enter(&np->r_statelock);
17174bff34e3Sthurlow 			np->r_size = vap->va_size;
1718adee6784SGordon Ross 			np->n_flag |= (NFLUSHWIRE | NATTRCHANGED);
17194bff34e3Sthurlow 			mutex_exit(&np->r_statelock);
17204bff34e3Sthurlow 			modified = 1;
17214bff34e3Sthurlow 		}
17224bff34e3Sthurlow 	}
17234bff34e3Sthurlow 
17244bff34e3Sthurlow 	/*
17255f4fc069Sjilinxpd 	 * Todo: Implement setting create_time (which is
17265f4fc069Sjilinxpd 	 * different from ctime).
17274bff34e3Sthurlow 	 */
17284bff34e3Sthurlow 	mtime = ((mask & AT_MTIME) ? &vap->va_mtime : 0);
17294bff34e3Sthurlow 	atime = ((mask & AT_ATIME) ? &vap->va_atime : 0);
17304bff34e3Sthurlow 
173128162916SGordon Ross 	if (dosattr || mtime || atime) {
17324bff34e3Sthurlow 		/*
173302d09e03SGordon Ross 		 * Always use the handle-based set attr call now.
17344bff34e3Sthurlow 		 */
1735adee6784SGordon Ross 		ASSERT(fid != NULL);
1736adee6784SGordon Ross 		error = smbfs_smb_setfattr(smi->smi_share, fid,
173728162916SGordon Ross 		    dosattr, mtime, atime, &scred);
17384bff34e3Sthurlow 		if (error) {
17394bff34e3Sthurlow 			SMBVDEBUG("set times error %d file %s\n",
17404bff34e3Sthurlow 			    error, np->n_rpath);
17414bff34e3Sthurlow 		} else {
17424bff34e3Sthurlow 			modified = 1;
17434bff34e3Sthurlow 		}
17444bff34e3Sthurlow 	}
17454bff34e3Sthurlow 
17464bff34e3Sthurlow out:
1747adee6784SGordon Ross 	if (fid != NULL)
1748adee6784SGordon Ross 		smbfs_smb_tmpclose(np, fid);
17494bff34e3Sthurlow 
17504bff34e3Sthurlow 	smb_credrele(&scred);
17514bff34e3Sthurlow 
17525f4fc069Sjilinxpd 	if (modified) {
17535f4fc069Sjilinxpd 		/*
17545f4fc069Sjilinxpd 		 * Invalidate attribute cache in case the server
17555f4fc069Sjilinxpd 		 * doesn't set exactly the attributes we asked.
17565f4fc069Sjilinxpd 		 */
17575f4fc069Sjilinxpd 		smbfs_attrcache_remove(np);
17585f4fc069Sjilinxpd 
17595f4fc069Sjilinxpd 		/*
17605f4fc069Sjilinxpd 		 * If changing the size of the file, invalidate
17615f4fc069Sjilinxpd 		 * any local cached data which is no longer part
17625f4fc069Sjilinxpd 		 * of the file.  We also possibly invalidate the
17635f4fc069Sjilinxpd 		 * last page in the file.  We could use
17645f4fc069Sjilinxpd 		 * pvn_vpzero(), but this would mark the page as
17655f4fc069Sjilinxpd 		 * modified and require it to be written back to
17665f4fc069Sjilinxpd 		 * the server for no particularly good reason.
17675f4fc069Sjilinxpd 		 * This way, if we access it, then we bring it
17685f4fc069Sjilinxpd 		 * back in.  A read should be cheaper than a
17695f4fc069Sjilinxpd 		 * write.
17705f4fc069Sjilinxpd 		 */
17715f4fc069Sjilinxpd 		if (mask & AT_SIZE) {
17725f4fc069Sjilinxpd 			smbfs_invalidate_pages(vp,
17735f4fc069Sjilinxpd 			    (vap->va_size & PAGEMASK), cr);
17745f4fc069Sjilinxpd 		}
17755f4fc069Sjilinxpd 	}
17765f4fc069Sjilinxpd 
17774bff34e3Sthurlow 	return (error);
17784bff34e3Sthurlow }
17794bff34e3Sthurlow 
178028162916SGordon Ross /*
178128162916SGordon Ross  * Helper function for extensible system attributes (PSARC 2007/315)
178228162916SGordon Ross  * Compute the DOS attribute word to pass to _setfattr (see above).
178328162916SGordon Ross  * This returns zero IFF no change is being made to attributes.
178428162916SGordon Ross  * Otherwise return the new attributes or SMB_EFA_NORMAL.
178528162916SGordon Ross  */
178628162916SGordon Ross static uint32_t
xvattr_to_dosattr(smbnode_t * np,struct vattr * vap)178728162916SGordon Ross xvattr_to_dosattr(smbnode_t *np, struct vattr *vap)
178828162916SGordon Ross {
178928162916SGordon Ross 	xvattr_t *xvap = (xvattr_t *)vap;
179028162916SGordon Ross 	xoptattr_t *xoap = NULL;
179128162916SGordon Ross 	uint32_t attr = np->r_attr.fa_attr;
179228162916SGordon Ross 	boolean_t anyset = B_FALSE;
179328162916SGordon Ross 
179428162916SGordon Ross 	if ((xoap = xva_getxoptattr(xvap)) == NULL)
179528162916SGordon Ross 		return (0);
179628162916SGordon Ross 
179728162916SGordon Ross 	if (XVA_ISSET_REQ(xvap, XAT_ARCHIVE)) {
179828162916SGordon Ross 		if (xoap->xoa_archive)
179928162916SGordon Ross 			attr |= SMB_FA_ARCHIVE;
180028162916SGordon Ross 		else
180128162916SGordon Ross 			attr &= ~SMB_FA_ARCHIVE;
180228162916SGordon Ross 		XVA_SET_RTN(xvap, XAT_ARCHIVE);
180328162916SGordon Ross 		anyset = B_TRUE;
180428162916SGordon Ross 	}
180528162916SGordon Ross 	if (XVA_ISSET_REQ(xvap, XAT_SYSTEM)) {
180628162916SGordon Ross 		if (xoap->xoa_system)
180728162916SGordon Ross 			attr |= SMB_FA_SYSTEM;
180828162916SGordon Ross 		else
180928162916SGordon Ross 			attr &= ~SMB_FA_SYSTEM;
181028162916SGordon Ross 		XVA_SET_RTN(xvap, XAT_SYSTEM);
181128162916SGordon Ross 		anyset = B_TRUE;
181228162916SGordon Ross 	}
181328162916SGordon Ross 	if (XVA_ISSET_REQ(xvap, XAT_READONLY)) {
181428162916SGordon Ross 		if (xoap->xoa_readonly)
181528162916SGordon Ross 			attr |= SMB_FA_RDONLY;
181628162916SGordon Ross 		else
181728162916SGordon Ross 			attr &= ~SMB_FA_RDONLY;
181828162916SGordon Ross 		XVA_SET_RTN(xvap, XAT_READONLY);
181928162916SGordon Ross 		anyset = B_TRUE;
182028162916SGordon Ross 	}
182128162916SGordon Ross 	if (XVA_ISSET_REQ(xvap, XAT_HIDDEN)) {
182228162916SGordon Ross 		if (xoap->xoa_hidden)
182328162916SGordon Ross 			attr |= SMB_FA_HIDDEN;
182428162916SGordon Ross 		else
182528162916SGordon Ross 			attr &= ~SMB_FA_HIDDEN;
182628162916SGordon Ross 		XVA_SET_RTN(xvap, XAT_HIDDEN);
182728162916SGordon Ross 		anyset = B_TRUE;
182828162916SGordon Ross 	}
182928162916SGordon Ross 
183028162916SGordon Ross 	if (anyset == B_FALSE)
183128162916SGordon Ross 		return (0);	/* no change */
183228162916SGordon Ross 	if (attr == 0)
183328162916SGordon Ross 		attr = SMB_EFA_NORMAL;
183428162916SGordon Ross 
183528162916SGordon Ross 	return (attr);
183628162916SGordon Ross }
183728162916SGordon Ross 
18384bff34e3Sthurlow /*
18394bff34e3Sthurlow  * smbfs_access_rwx()
18404bff34e3Sthurlow  * Common function for smbfs_access, etc.
18414bff34e3Sthurlow  *
18424bff34e3Sthurlow  * The security model implemented by the FS is unusual
1843bd7c6f51SGordon Ross  * due to the current "single user mounts" restriction:
18444bff34e3Sthurlow  * All access under a given mount point uses the CIFS
18454bff34e3Sthurlow  * credentials established by the owner of the mount.
18464bff34e3Sthurlow  *
18474bff34e3Sthurlow  * Most access checking is handled by the CIFS server,
18484bff34e3Sthurlow  * but we need sufficient Unix access checks here to
18494bff34e3Sthurlow  * prevent other local Unix users from having access
18504bff34e3Sthurlow  * to objects under this mount that the uid/gid/mode
18514bff34e3Sthurlow  * settings in the mount would not allow.
18524bff34e3Sthurlow  *
18534bff34e3Sthurlow  * With this model, there is a case where we need the
18544bff34e3Sthurlow  * ability to do an access check before we have the
18554bff34e3Sthurlow  * vnode for an object.  This function takes advantage
18564bff34e3Sthurlow  * of the fact that the uid/gid/mode is per mount, and
18574bff34e3Sthurlow  * avoids the need for a vnode.
18584bff34e3Sthurlow  *
18594bff34e3Sthurlow  * We still (sort of) need a vnode when we call
18604bff34e3Sthurlow  * secpolicy_vnode_access, but that only uses
18614bff34e3Sthurlow  * the vtype field, so we can use a pair of fake
18624bff34e3Sthurlow  * vnodes that have only v_type filled in.
18634bff34e3Sthurlow  */
18644bff34e3Sthurlow static int
smbfs_access_rwx(vfs_t * vfsp,int vtype,int mode,cred_t * cr)18654bff34e3Sthurlow smbfs_access_rwx(vfs_t *vfsp, int vtype, int mode, cred_t *cr)
18664bff34e3Sthurlow {
18674bff34e3Sthurlow 	/* See the secpolicy call below. */
18684bff34e3Sthurlow 	static const vnode_t tmpl_vdir = { .v_type = VDIR };
18694bff34e3Sthurlow 	static const vnode_t tmpl_vreg = { .v_type = VREG };
18704bff34e3Sthurlow 	vattr_t		va;
18714bff34e3Sthurlow 	vnode_t		*tvp;
18724bff34e3Sthurlow 	struct smbmntinfo *smi = VFTOSMI(vfsp);
18734bff34e3Sthurlow 	int shift = 0;
18744bff34e3Sthurlow 
18754bff34e3Sthurlow 	/*
18764bff34e3Sthurlow 	 * Build our (fabricated) vnode attributes.
18774bff34e3Sthurlow 	 */
18784bff34e3Sthurlow 	bzero(&va, sizeof (va));
18794bff34e3Sthurlow 	va.va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID;
18804bff34e3Sthurlow 	va.va_type = vtype;
18814bff34e3Sthurlow 	va.va_mode = (vtype == VDIR) ?
188202d09e03SGordon Ross 	    smi->smi_dmode : smi->smi_fmode;
188302d09e03SGordon Ross 	va.va_uid = smi->smi_uid;
188402d09e03SGordon Ross 	va.va_gid = smi->smi_gid;
18854bff34e3Sthurlow 
18864bff34e3Sthurlow 	/*
18874bff34e3Sthurlow 	 * Disallow write attempts on read-only file systems,
18884bff34e3Sthurlow 	 * unless the file is a device or fifo node.  Note:
18894bff34e3Sthurlow 	 * Inline vn_is_readonly and IS_DEVVP here because
18904bff34e3Sthurlow 	 * we may not have a vnode ptr.  Original expr. was:
18914bff34e3Sthurlow 	 * (mode & VWRITE) && vn_is_readonly(vp) && !IS_DEVVP(vp))
18924bff34e3Sthurlow 	 */
18934bff34e3Sthurlow 	if ((mode & VWRITE) &&
18944bff34e3Sthurlow 	    (vfsp->vfs_flag & VFS_RDONLY) &&
18954bff34e3Sthurlow 	    !(vtype == VCHR || vtype == VBLK || vtype == VFIFO))
18964bff34e3Sthurlow 		return (EROFS);
18974bff34e3Sthurlow 
18984bff34e3Sthurlow 	/*
18994bff34e3Sthurlow 	 * Disallow attempts to access mandatory lock files.
19004bff34e3Sthurlow 	 * Similarly, expand MANDLOCK here.
19014bff34e3Sthurlow 	 */
19024bff34e3Sthurlow 	if ((mode & (VWRITE | VREAD | VEXEC)) &&
19034bff34e3Sthurlow 	    va.va_type == VREG && MANDMODE(va.va_mode))
19044bff34e3Sthurlow 		return (EACCES);
19054bff34e3Sthurlow 
19064bff34e3Sthurlow 	/*
19074bff34e3Sthurlow 	 * Access check is based on only
19084bff34e3Sthurlow 	 * one of owner, group, public.
19094bff34e3Sthurlow 	 * If not owner, then check group.
19104bff34e3Sthurlow 	 * If not a member of the group,
19114bff34e3Sthurlow 	 * then check public access.
19124bff34e3Sthurlow 	 */
19134bff34e3Sthurlow 	if (crgetuid(cr) != va.va_uid) {
19144bff34e3Sthurlow 		shift += 3;
19154bff34e3Sthurlow 		if (!groupmember(va.va_gid, cr))
19164bff34e3Sthurlow 			shift += 3;
19174bff34e3Sthurlow 	}
19184bff34e3Sthurlow 
19194bff34e3Sthurlow 	/*
19204bff34e3Sthurlow 	 * We need a vnode for secpolicy_vnode_access,
19214bff34e3Sthurlow 	 * but the only thing it looks at is v_type,
19224bff34e3Sthurlow 	 * so pass one of the templates above.
19234bff34e3Sthurlow 	 */
19244bff34e3Sthurlow 	tvp = (va.va_type == VDIR) ?
19254bff34e3Sthurlow 	    (vnode_t *)&tmpl_vdir :
19264bff34e3Sthurlow 	    (vnode_t *)&tmpl_vreg;
1927134a1f4eSCasper H.S. Dik 
1928134a1f4eSCasper H.S. Dik 	return (secpolicy_vnode_access2(cr, tvp, va.va_uid,
1929134a1f4eSCasper H.S. Dik 	    va.va_mode << shift, mode));
19304bff34e3Sthurlow }
19314bff34e3Sthurlow 
19324bff34e3Sthurlow /*
19334bff34e3Sthurlow  * See smbfs_setattr
19344bff34e3Sthurlow  */
19354bff34e3Sthurlow static int
smbfs_accessx(void * arg,int mode,cred_t * cr)19364bff34e3Sthurlow smbfs_accessx(void *arg, int mode, cred_t *cr)
19374bff34e3Sthurlow {
19384bff34e3Sthurlow 	vnode_t *vp = arg;
19394bff34e3Sthurlow 	/*
19404bff34e3Sthurlow 	 * Note: The caller has checked the current zone,
19414bff34e3Sthurlow 	 * the SMI_DEAD and VFS_UNMOUNTED flags, etc.
19424bff34e3Sthurlow 	 */
19434bff34e3Sthurlow 	return (smbfs_access_rwx(vp->v_vfsp, vp->v_type, mode, cr));
19444bff34e3Sthurlow }
19454bff34e3Sthurlow 
19464bff34e3Sthurlow /*
19474bff34e3Sthurlow  * XXX
19484bff34e3Sthurlow  * This op should support PSARC 2007/403, Modified Access Checks for CIFS
19494bff34e3Sthurlow  */
19504bff34e3Sthurlow /* ARGSUSED */
19514bff34e3Sthurlow static int
smbfs_access(vnode_t * vp,int mode,int flags,cred_t * cr,caller_context_t * ct)19524bff34e3Sthurlow smbfs_access(vnode_t *vp, int mode, int flags, cred_t *cr, caller_context_t *ct)
19534bff34e3Sthurlow {
19544bff34e3Sthurlow 	vfs_t		*vfsp;
19554bff34e3Sthurlow 	smbmntinfo_t	*smi;
19564bff34e3Sthurlow 
19574bff34e3Sthurlow 	vfsp = vp->v_vfsp;
19584bff34e3Sthurlow 	smi = VFTOSMI(vfsp);
19594bff34e3Sthurlow 
1960a19609f8Sjv 	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
19614bff34e3Sthurlow 		return (EIO);
19624bff34e3Sthurlow 
19634bff34e3Sthurlow 	if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
19644bff34e3Sthurlow 		return (EIO);
19654bff34e3Sthurlow 
19664bff34e3Sthurlow 	return (smbfs_access_rwx(vfsp, vp->v_type, mode, cr));
19674bff34e3Sthurlow }
19684bff34e3Sthurlow 
19694bff34e3Sthurlow 
19705f4fc069Sjilinxpd /* ARGSUSED */
19715f4fc069Sjilinxpd static int
smbfs_readlink(vnode_t * vp,struct uio * uiop,cred_t * cr,caller_context_t * ct)19725f4fc069Sjilinxpd smbfs_readlink(vnode_t *vp, struct uio *uiop, cred_t *cr, caller_context_t *ct)
19735f4fc069Sjilinxpd {
19745f4fc069Sjilinxpd 	/* Not yet... */
19755f4fc069Sjilinxpd 	return (ENOSYS);
19765f4fc069Sjilinxpd }
19775f4fc069Sjilinxpd 
19785f4fc069Sjilinxpd 
19794bff34e3Sthurlow /*
19804bff34e3Sthurlow  * Flush local dirty pages to stable storage on the server.
19814bff34e3Sthurlow  *
19824bff34e3Sthurlow  * If FNODSYNC is specified, then there is nothing to do because
19834bff34e3Sthurlow  * metadata changes are not cached on the client before being
19844bff34e3Sthurlow  * sent to the server.
19854bff34e3Sthurlow  */
19864bff34e3Sthurlow /* ARGSUSED */
19874bff34e3Sthurlow static int
smbfs_fsync(vnode_t * vp,int syncflag,cred_t * cr,caller_context_t * ct)19884bff34e3Sthurlow smbfs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct)
19894bff34e3Sthurlow {
19904bff34e3Sthurlow 	int		error = 0;
19914bff34e3Sthurlow 	smbmntinfo_t	*smi;
19925f4fc069Sjilinxpd 	smbnode_t	*np;
19932f5e3e91SGordon Ross 	struct smb_cred scred;
19944bff34e3Sthurlow 
19952f5e3e91SGordon Ross 	np = VTOSMB(vp);
19964bff34e3Sthurlow 	smi = VTOSMI(vp);
19974bff34e3Sthurlow 
1998a19609f8Sjv 	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
19994bff34e3Sthurlow 		return (EIO);
20004bff34e3Sthurlow 
20014bff34e3Sthurlow 	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
20024bff34e3Sthurlow 		return (EIO);
20034bff34e3Sthurlow 
20044bff34e3Sthurlow 	if ((syncflag & FNODSYNC) || IS_SWAPVP(vp))
20054bff34e3Sthurlow 		return (0);
20064bff34e3Sthurlow 
20072f5e3e91SGordon Ross 	if ((syncflag & (FSYNC|FDSYNC)) == 0)
20082f5e3e91SGordon Ross 		return (0);
20092f5e3e91SGordon Ross 
20105f4fc069Sjilinxpd 	error = smbfs_putpage(vp, (offset_t)0, 0, 0, cr, ct);
20115f4fc069Sjilinxpd 	if (error)
20125f4fc069Sjilinxpd 		return (error);
20135f4fc069Sjilinxpd 
20142f5e3e91SGordon Ross 	/* Shared lock for n_fid use in _flush */
20152f5e3e91SGordon Ross 	if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
20162f5e3e91SGordon Ross 		return (EINTR);
2017613a2f6bSGordon Ross 	smb_credinit(&scred, cr);
20182f5e3e91SGordon Ross 
2019adee6784SGordon Ross 	error = smbfsflush(np, &scred);
20202f5e3e91SGordon Ross 
20212f5e3e91SGordon Ross 	smb_credrele(&scred);
20222f5e3e91SGordon Ross 	smbfs_rw_exit(&np->r_lkserlock);
20232f5e3e91SGordon Ross 
20244bff34e3Sthurlow 	return (error);
20254bff34e3Sthurlow }
20264bff34e3Sthurlow 
2027adee6784SGordon Ross static int
smbfsflush(smbnode_t * np,struct smb_cred * scrp)2028adee6784SGordon Ross smbfsflush(smbnode_t *np, struct smb_cred *scrp)
2029adee6784SGordon Ross {
2030adee6784SGordon Ross 	struct smb_share *ssp = np->n_mount->smi_share;
2031adee6784SGordon Ross 	smb_fh_t *fhp;
2032adee6784SGordon Ross 	int error;
2033adee6784SGordon Ross 
2034adee6784SGordon Ross 	/* Shared lock for n_fid use below. */
2035adee6784SGordon Ross 	ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
2036adee6784SGordon Ross 
2037adee6784SGordon Ross 	if (!(np->n_flag & NFLUSHWIRE))
2038adee6784SGordon Ross 		return (0);
2039adee6784SGordon Ross 	if (np->n_fidrefs == 0)
2040adee6784SGordon Ross 		return (0); /* not open */
2041adee6784SGordon Ross 	if ((fhp = np->n_fid) == NULL)
2042adee6784SGordon Ross 		return (0);
2043adee6784SGordon Ross 
2044adee6784SGordon Ross 	/* After reconnect, n_fid is invalid */
2045adee6784SGordon Ross 	if (fhp->fh_vcgenid != ssp->ss_vcgenid)
2046adee6784SGordon Ross 		return (ESTALE);
2047adee6784SGordon Ross 
2048adee6784SGordon Ross 	error = smbfs_smb_flush(ssp, fhp, scrp);
2049adee6784SGordon Ross 
2050adee6784SGordon Ross 	if (!error) {
2051adee6784SGordon Ross 		mutex_enter(&np->r_statelock);
2052adee6784SGordon Ross 		np->n_flag &= ~NFLUSHWIRE;
2053adee6784SGordon Ross 		mutex_exit(&np->r_statelock);
2054adee6784SGordon Ross 	}
2055adee6784SGordon Ross 	return (error);
2056adee6784SGordon Ross }
2057adee6784SGordon Ross 
20584bff34e3Sthurlow /*
20594bff34e3Sthurlow  * Last reference to vnode went away.
20604bff34e3Sthurlow  */
20614bff34e3Sthurlow /* ARGSUSED */
20624bff34e3Sthurlow static void
smbfs_inactive(vnode_t * vp,cred_t * cr,caller_context_t * ct)20634bff34e3Sthurlow smbfs_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
20644bff34e3Sthurlow {
206542d15982SGordon Ross 	struct smb_cred scred;
20665f4fc069Sjilinxpd 	smbnode_t	*np = VTOSMB(vp);
20675f4fc069Sjilinxpd 	int error;
20684bff34e3Sthurlow 
20694bff34e3Sthurlow 	/*
20704bff34e3Sthurlow 	 * Don't "bail out" for VFS_UNMOUNTED here,
20714bff34e3Sthurlow 	 * as we want to do cleanup, etc.
20724bff34e3Sthurlow 	 * See also pcfs_inactive
20734bff34e3Sthurlow 	 */
20744bff34e3Sthurlow 
20754bff34e3Sthurlow 	/*
20764bff34e3Sthurlow 	 * If this is coming from the wrong zone, we let someone in the right
20774bff34e3Sthurlow 	 * zone take care of it asynchronously.  We can get here due to
20784bff34e3Sthurlow 	 * VN_RELE() being called from pageout() or fsflush().  This call may
20794bff34e3Sthurlow 	 * potentially turn into an expensive no-op if, for instance, v_count
20804bff34e3Sthurlow 	 * gets incremented in the meantime, but it's still correct.
20814bff34e3Sthurlow 	 */
20824bff34e3Sthurlow 
20835f4fc069Sjilinxpd 	/*
20845f4fc069Sjilinxpd 	 * From NFS:rinactive()
20855f4fc069Sjilinxpd 	 *
20865f4fc069Sjilinxpd 	 * Before freeing anything, wait until all asynchronous
20875f4fc069Sjilinxpd 	 * activity is done on this rnode.  This will allow all
20885f4fc069Sjilinxpd 	 * asynchronous read ahead and write behind i/o's to
20895f4fc069Sjilinxpd 	 * finish.
20905f4fc069Sjilinxpd 	 */
20915f4fc069Sjilinxpd 	mutex_enter(&np->r_statelock);
20925f4fc069Sjilinxpd 	while (np->r_count > 0)
20935f4fc069Sjilinxpd 		cv_wait(&np->r_cv, &np->r_statelock);
20945f4fc069Sjilinxpd 	mutex_exit(&np->r_statelock);
20955f4fc069Sjilinxpd 
20965f4fc069Sjilinxpd 	/*
20975f4fc069Sjilinxpd 	 * Flush and invalidate all pages associated with the vnode.
20985f4fc069Sjilinxpd 	 */
20995f4fc069Sjilinxpd 	if (vn_has_cached_data(vp)) {
21005f4fc069Sjilinxpd 		if ((np->r_flags & RDIRTY) && !np->r_error) {
21015f4fc069Sjilinxpd 			error = smbfs_putpage(vp, (u_offset_t)0, 0, 0, cr, ct);
21025f4fc069Sjilinxpd 			if (error && (error == ENOSPC || error == EDQUOT)) {
21035f4fc069Sjilinxpd 				mutex_enter(&np->r_statelock);
21045f4fc069Sjilinxpd 				if (!np->r_error)
21055f4fc069Sjilinxpd 					np->r_error = error;
21065f4fc069Sjilinxpd 				mutex_exit(&np->r_statelock);
21075f4fc069Sjilinxpd 			}
21085f4fc069Sjilinxpd 		}
21095f4fc069Sjilinxpd 		smbfs_invalidate_pages(vp, (u_offset_t)0, cr);
21105f4fc069Sjilinxpd 	}
21115f4fc069Sjilinxpd 	/*
21125f4fc069Sjilinxpd 	 * This vnode should have lost all cached data.
21135f4fc069Sjilinxpd 	 */
21145f4fc069Sjilinxpd 	ASSERT(vn_has_cached_data(vp) == 0);
21155f4fc069Sjilinxpd 
21164bff34e3Sthurlow 	/*
211742d15982SGordon Ross 	 * Defend against the possibility that higher-level callers
211842d15982SGordon Ross 	 * might not correctly balance open and close calls.  If we
211942d15982SGordon Ross 	 * get here with open references remaining, it means there
212042d15982SGordon Ross 	 * was a missing VOP_CLOSE somewhere.  If that happens, do
212142d15982SGordon Ross 	 * the close here so we don't "leak" FIDs on the server.
21224bff34e3Sthurlow 	 *
212342d15982SGordon Ross 	 * Exclusive lock for modifying n_fid stuff.
212442d15982SGordon Ross 	 * Don't want this one ever interruptible.
21254bff34e3Sthurlow 	 */
212642d15982SGordon Ross 	(void) smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, 0);
212742d15982SGordon Ross 	smb_credinit(&scred, cr);
212842d15982SGordon Ross 
212942d15982SGordon Ross 	switch (np->n_ovtype) {
213042d15982SGordon Ross 	case VNON:
213142d15982SGordon Ross 		/* not open (OK) */
213242d15982SGordon Ross 		break;
213342d15982SGordon Ross 
213442d15982SGordon Ross 	case VDIR:
213542d15982SGordon Ross 		if (np->n_dirrefs == 0)
213642d15982SGordon Ross 			break;
213742d15982SGordon Ross 		SMBVDEBUG("open dir: refs %d path %s\n",
213842d15982SGordon Ross 		    np->n_dirrefs, np->n_rpath);
213942d15982SGordon Ross 		/* Force last close. */
214042d15982SGordon Ross 		np->n_dirrefs = 1;
214142d15982SGordon Ross 		smbfs_rele_fid(np, &scred);
214242d15982SGordon Ross 		break;
214342d15982SGordon Ross 
214442d15982SGordon Ross 	case VREG:
214542d15982SGordon Ross 		if (np->n_fidrefs == 0)
214642d15982SGordon Ross 			break;
2147adee6784SGordon Ross 		SMBVDEBUG("open file: refs %d path %s\n",
2148adee6784SGordon Ross 		    np->n_fidrefs, np->n_rpath);
214942d15982SGordon Ross 		/* Force last close. */
215042d15982SGordon Ross 		np->n_fidrefs = 1;
215142d15982SGordon Ross 		smbfs_rele_fid(np, &scred);
215242d15982SGordon Ross 		break;
215342d15982SGordon Ross 
215442d15982SGordon Ross 	default:
215542d15982SGordon Ross 		SMBVDEBUG("bad n_ovtype %d\n", np->n_ovtype);
215642d15982SGordon Ross 		np->n_ovtype = VNON;
215742d15982SGordon Ross 		break;
21584bff34e3Sthurlow 	}
215942d15982SGordon Ross 
216042d15982SGordon Ross 	smb_credrele(&scred);
216142d15982SGordon Ross 	smbfs_rw_exit(&np->r_lkserlock);
21624bff34e3Sthurlow 
2163ff1e230cSjilinxpd 	/*
2164ff1e230cSjilinxpd 	 * XATTR directories (and the files under them) have
2165ff1e230cSjilinxpd 	 * little value for reclaim, so just remove them from
2166ff1e230cSjilinxpd 	 * the "hash" (AVL) as soon as they go inactive.
2167ff1e230cSjilinxpd 	 * Note that the node may already have been removed
2168ff1e230cSjilinxpd 	 * from the hash by smbfsremove.
2169ff1e230cSjilinxpd 	 */
2170ff1e230cSjilinxpd 	if ((np->n_flag & N_XATTR) != 0 &&
2171ff1e230cSjilinxpd 	    (np->r_flags & RHASHED) != 0)
2172ff1e230cSjilinxpd 		smbfs_rmhash(np);
2173ff1e230cSjilinxpd 
217402d09e03SGordon Ross 	smbfs_addfree(np);
21754bff34e3Sthurlow }
21764bff34e3Sthurlow 
21774bff34e3Sthurlow /*
21784bff34e3Sthurlow  * Remote file system operations having to do with directory manipulation.
21794bff34e3Sthurlow  */
21804bff34e3Sthurlow /* ARGSUSED */
21814bff34e3Sthurlow static int
smbfs_lookup(vnode_t * dvp,char * nm,vnode_t ** vpp,struct pathname * pnp,int flags,vnode_t * rdir,cred_t * cr,caller_context_t * ct,int * direntflags,pathname_t * realpnp)21824bff34e3Sthurlow smbfs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
21834bff34e3Sthurlow 	int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
21844bff34e3Sthurlow 	int *direntflags, pathname_t *realpnp)
21854bff34e3Sthurlow {
218691d632c8Sgwr 	vfs_t		*vfs;
21874bff34e3Sthurlow 	smbmntinfo_t	*smi;
218891d632c8Sgwr 	smbnode_t	*dnp;
218991d632c8Sgwr 	int		error;
21904bff34e3Sthurlow 
219191d632c8Sgwr 	vfs = dvp->v_vfsp;
219291d632c8Sgwr 	smi = VFTOSMI(vfs);
21934bff34e3Sthurlow 
2194a19609f8Sjv 	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
21954bff34e3Sthurlow 		return (EPERM);
21964bff34e3Sthurlow 
219791d632c8Sgwr 	if (smi->smi_flags & SMI_DEAD || vfs->vfs_flag & VFS_UNMOUNTED)
21984bff34e3Sthurlow 		return (EIO);
21994bff34e3Sthurlow 
22004bff34e3Sthurlow 	dnp = VTOSMB(dvp);
220191d632c8Sgwr 
220291d632c8Sgwr 	/*
220391d632c8Sgwr 	 * Are we looking up extended attributes?  If so, "dvp" is
220491d632c8Sgwr 	 * the file or directory for which we want attributes, and
220591d632c8Sgwr 	 * we need a lookup of the (faked up) attribute directory
220691d632c8Sgwr 	 * before we lookup the rest of the path.
220791d632c8Sgwr 	 */
220891d632c8Sgwr 	if (flags & LOOKUP_XATTR) {
220991d632c8Sgwr 		/*
221091d632c8Sgwr 		 * Require the xattr mount option.
221191d632c8Sgwr 		 */
221291d632c8Sgwr 		if ((vfs->vfs_flag & VFS_XATTR) == 0)
221391d632c8Sgwr 			return (EINVAL);
221491d632c8Sgwr 
221591d632c8Sgwr 		error = smbfs_get_xattrdir(dvp, vpp, cr, flags);
221691d632c8Sgwr 		return (error);
221791d632c8Sgwr 	}
221891d632c8Sgwr 
221902d09e03SGordon Ross 	if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_READER, SMBINTR(dvp)))
222002d09e03SGordon Ross 		return (EINTR);
22214bff34e3Sthurlow 
22224bff34e3Sthurlow 	error = smbfslookup(dvp, nm, vpp, cr, 1, ct);
22234bff34e3Sthurlow 
22244bff34e3Sthurlow 	smbfs_rw_exit(&dnp->r_rwlock);
22254bff34e3Sthurlow 
2226adee6784SGordon Ross 	/*
2227adee6784SGordon Ross 	 * If the caller passes an invalid name here, we'll have
2228adee6784SGordon Ross 	 * error == EINVAL but want to return ENOENT.  This is
2229adee6784SGordon Ross 	 * common with things like "ls foo*" with no matches.
2230adee6784SGordon Ross 	 */
2231adee6784SGordon Ross 	if (error == EINVAL)
2232adee6784SGordon Ross 		error = ENOENT;
2233adee6784SGordon Ross 
22344bff34e3Sthurlow 	return (error);
22354bff34e3Sthurlow }
22364bff34e3Sthurlow 
22374bff34e3Sthurlow /* ARGSUSED */
22384bff34e3Sthurlow static int
smbfslookup(vnode_t * dvp,char * nm,vnode_t ** vpp,cred_t * cr,int cache_ok,caller_context_t * ct)223902d09e03SGordon Ross smbfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr,
224002d09e03SGordon Ross 	int cache_ok, caller_context_t *ct)
22414bff34e3Sthurlow {
22424bff34e3Sthurlow 	int		error;
22434bff34e3Sthurlow 	int		supplen; /* supported length */
22444bff34e3Sthurlow 	vnode_t		*vp;
224502d09e03SGordon Ross 	smbnode_t	*np;
22464bff34e3Sthurlow 	smbnode_t	*dnp;
22474bff34e3Sthurlow 	smbmntinfo_t	*smi;
22484bff34e3Sthurlow 	/* struct smb_vc	*vcp; */
224991d632c8Sgwr 	const char	*ill;
22504bff34e3Sthurlow 	const char	*name = (const char *)nm;
22515f4fc069Sjilinxpd 	int		nmlen = strlen(nm);
22525f4fc069Sjilinxpd 	int		rplen;
22534bff34e3Sthurlow 	struct smb_cred scred;
22544bff34e3Sthurlow 	struct smbfattr fa;
22554bff34e3Sthurlow 
22564bff34e3Sthurlow 	smi = VTOSMI(dvp);
22574bff34e3Sthurlow 	dnp = VTOSMB(dvp);
22584bff34e3Sthurlow 
2259a19609f8Sjv 	ASSERT(curproc->p_zone == smi->smi_zone_ref.zref_zone);
22604bff34e3Sthurlow 
22614bff34e3Sthurlow 	supplen = 255;
22624bff34e3Sthurlow 
22634bff34e3Sthurlow 	/*
22644bff34e3Sthurlow 	 * RWlock must be held, either reader or writer.
22654bff34e3Sthurlow 	 */
22664bff34e3Sthurlow 	ASSERT(dnp->r_rwlock.count != 0);
22674bff34e3Sthurlow 
22684bff34e3Sthurlow 	/*
226902d09e03SGordon Ross 	 * If lookup is for "", just return dvp.
227002d09e03SGordon Ross 	 * No need to perform any access checks.
22714bff34e3Sthurlow 	 */
22724bff34e3Sthurlow 	if (nmlen == 0) {
22734bff34e3Sthurlow 		VN_HOLD(dvp);
22744bff34e3Sthurlow 		*vpp = dvp;
22754bff34e3Sthurlow 		return (0);
22764bff34e3Sthurlow 	}
22774bff34e3Sthurlow 
22784bff34e3Sthurlow 	/*
227991d632c8Sgwr 	 * Can't do lookups in non-directories.
22804bff34e3Sthurlow 	 */
22814bff34e3Sthurlow 	if (dvp->v_type != VDIR)
22824bff34e3Sthurlow 		return (ENOTDIR);
22834bff34e3Sthurlow 
228491d632c8Sgwr 	/*
228591d632c8Sgwr 	 * Need search permission in the directory.
228691d632c8Sgwr 	 */
22874bff34e3Sthurlow 	error = smbfs_access(dvp, VEXEC, 0, cr, ct);
22884bff34e3Sthurlow 	if (error)
22894bff34e3Sthurlow 		return (error);
22904bff34e3Sthurlow 
22914bff34e3Sthurlow 	/*
229202d09e03SGordon Ross 	 * If lookup is for ".", just return dvp.
229302d09e03SGordon Ross 	 * Access check was done above.
22944bff34e3Sthurlow 	 */
22954bff34e3Sthurlow 	if (nmlen == 1 && name[0] == '.') {
22964bff34e3Sthurlow 		VN_HOLD(dvp);
22974bff34e3Sthurlow 		*vpp = dvp;
22984bff34e3Sthurlow 		return (0);
22994bff34e3Sthurlow 	}
23004bff34e3Sthurlow 
23014bff34e3Sthurlow 	/*
230291d632c8Sgwr 	 * Now some sanity checks on the name.
230391d632c8Sgwr 	 * First check the length.
23044bff34e3Sthurlow 	 */
230591d632c8Sgwr 	if (nmlen > supplen)
230691d632c8Sgwr 		return (ENAMETOOLONG);
230791d632c8Sgwr 
230891d632c8Sgwr 	/*
230991d632c8Sgwr 	 * Avoid surprises with characters that are
231091d632c8Sgwr 	 * illegal in Windows file names.
23115f4fc069Sjilinxpd 	 * Todo: CATIA mappings?
231291d632c8Sgwr 	 */
231391d632c8Sgwr 	ill = illegal_chars;
231491d632c8Sgwr 	if (dnp->n_flag & N_XATTR)
231591d632c8Sgwr 		ill++; /* allow colon */
231691d632c8Sgwr 	if (strpbrk(nm, ill))
231791d632c8Sgwr 		return (EINVAL);
231891d632c8Sgwr 
23194bff34e3Sthurlow 	/*
232002d09e03SGordon Ross 	 * Special handling for lookup of ".."
23214bff34e3Sthurlow 	 *
23224bff34e3Sthurlow 	 * We keep full pathnames (as seen on the server)
23234bff34e3Sthurlow 	 * so we can just trim off the last component to
23244bff34e3Sthurlow 	 * get the full pathname of the parent.  Note:
23254bff34e3Sthurlow 	 * We don't actually copy and modify, but just
23264bff34e3Sthurlow 	 * compute the trimmed length and pass that with
23274bff34e3Sthurlow 	 * the current dir path (not null terminated).
23284bff34e3Sthurlow 	 *
23294bff34e3Sthurlow 	 * We don't go over-the-wire to get attributes
23304bff34e3Sthurlow 	 * for ".." because we know it's a directory,
23314bff34e3Sthurlow 	 * and we can just leave the rest "stale"
23324bff34e3Sthurlow 	 * until someone does a getattr.
23334bff34e3Sthurlow 	 */
23344bff34e3Sthurlow 	if (nmlen == 2 && name[0] == '.' && name[1] == '.') {
23354bff34e3Sthurlow 		if (dvp->v_flag & VROOT) {
23364bff34e3Sthurlow 			/*
23374bff34e3Sthurlow 			 * Already at the root.  This can happen
23384bff34e3Sthurlow 			 * with directory listings at the root,
23394bff34e3Sthurlow 			 * which lookup "." and ".." to get the
23404bff34e3Sthurlow 			 * inode numbers.  Let ".." be the same
23414bff34e3Sthurlow 			 * as "." in the FS root.
23424bff34e3Sthurlow 			 */
23434bff34e3Sthurlow 			VN_HOLD(dvp);
23444bff34e3Sthurlow 			*vpp = dvp;
23454bff34e3Sthurlow 			return (0);
23464bff34e3Sthurlow 		}
23474bff34e3Sthurlow 
234891d632c8Sgwr 		/*
234991d632c8Sgwr 		 * Special case for XATTR directory
235091d632c8Sgwr 		 */
235191d632c8Sgwr 		if (dvp->v_flag & V_XATTRDIR) {
235291d632c8Sgwr 			error = smbfs_xa_parent(dvp, vpp);
235391d632c8Sgwr 			return (error);
235491d632c8Sgwr 		}
235591d632c8Sgwr 
23564bff34e3Sthurlow 		/*
23574bff34e3Sthurlow 		 * Find the parent path length.
23584bff34e3Sthurlow 		 */
23594bff34e3Sthurlow 		rplen = dnp->n_rplen;
23604bff34e3Sthurlow 		ASSERT(rplen > 0);
23614bff34e3Sthurlow 		while (--rplen >= 0) {
23624bff34e3Sthurlow 			if (dnp->n_rpath[rplen] == '\\')
23634bff34e3Sthurlow 				break;
23644bff34e3Sthurlow 		}
236502d09e03SGordon Ross 		if (rplen <= 0) {
23664bff34e3Sthurlow 			/* Found our way to the root. */
23674bff34e3Sthurlow 			vp = SMBTOV(smi->smi_root);
23684bff34e3Sthurlow 			VN_HOLD(vp);
23694bff34e3Sthurlow 			*vpp = vp;
23704bff34e3Sthurlow 			return (0);
23714bff34e3Sthurlow 		}
237202d09e03SGordon Ross 		np = smbfs_node_findcreate(smi,
237302d09e03SGordon Ross 		    dnp->n_rpath, rplen, NULL, 0, 0,
237402d09e03SGordon Ross 		    &smbfs_fattr0); /* force create */
237502d09e03SGordon Ross 		ASSERT(np != NULL);
237602d09e03SGordon Ross 		vp = SMBTOV(np);
23774bff34e3Sthurlow 		vp->v_type = VDIR;
23784bff34e3Sthurlow 
23794bff34e3Sthurlow 		/* Success! */
23804bff34e3Sthurlow 		*vpp = vp;
23814bff34e3Sthurlow 		return (0);
23824bff34e3Sthurlow 	}
23834bff34e3Sthurlow 
23844bff34e3Sthurlow 	/*
238502d09e03SGordon Ross 	 * Normal lookup of a name under this directory.
238602d09e03SGordon Ross 	 * Note we handled "", ".", ".." above.
238702d09e03SGordon Ross 	 */
238802d09e03SGordon Ross 	if (cache_ok) {
238902d09e03SGordon Ross 		/*
239002d09e03SGordon Ross 		 * The caller indicated that it's OK to use a
239102d09e03SGordon Ross 		 * cached result for this lookup, so try to
239202d09e03SGordon Ross 		 * reclaim a node from the smbfs node cache.
239302d09e03SGordon Ross 		 */
239402d09e03SGordon Ross 		error = smbfslookup_cache(dvp, nm, nmlen, &vp, cr);
239502d09e03SGordon Ross 		if (error)
239602d09e03SGordon Ross 			return (error);
239702d09e03SGordon Ross 		if (vp != NULL) {
239802d09e03SGordon Ross 			/* hold taken in lookup_cache */
239902d09e03SGordon Ross 			*vpp = vp;
240002d09e03SGordon Ross 			return (0);
240102d09e03SGordon Ross 		}
240202d09e03SGordon Ross 	}
240302d09e03SGordon Ross 
240402d09e03SGordon Ross 	/*
240502d09e03SGordon Ross 	 * OK, go over-the-wire to get the attributes,
240602d09e03SGordon Ross 	 * then create the node.
24074bff34e3Sthurlow 	 */
2408613a2f6bSGordon Ross 	smb_credinit(&scred, cr);
24094bff34e3Sthurlow 	/* Note: this can allocate a new "name" */
24104bff34e3Sthurlow 	error = smbfs_smb_lookup(dnp, &name, &nmlen, &fa, &scred);
24114bff34e3Sthurlow 	smb_credrele(&scred);
241202d09e03SGordon Ross 	if (error == ENOTDIR) {
241302d09e03SGordon Ross 		/*
241402d09e03SGordon Ross 		 * Lookup failed because this directory was
241502d09e03SGordon Ross 		 * removed or renamed by another client.
241602d09e03SGordon Ross 		 * Remove any cached attributes under it.
241702d09e03SGordon Ross 		 */
241802d09e03SGordon Ross 		smbfs_attrcache_remove(dnp);
241902d09e03SGordon Ross 		smbfs_attrcache_prune(dnp);
242002d09e03SGordon Ross 	}
24214bff34e3Sthurlow 	if (error)
24224bff34e3Sthurlow 		goto out;
24234bff34e3Sthurlow 
24244bff34e3Sthurlow 	error = smbfs_nget(dvp, name, nmlen, &fa, &vp);
24254bff34e3Sthurlow 	if (error)
24264bff34e3Sthurlow 		goto out;
24274bff34e3Sthurlow 
24284bff34e3Sthurlow 	/* Success! */
24294bff34e3Sthurlow 	*vpp = vp;
24304bff34e3Sthurlow 
24314bff34e3Sthurlow out:
24324bff34e3Sthurlow 	/* smbfs_smb_lookup may have allocated name. */
24334bff34e3Sthurlow 	if (name != nm)
24344bff34e3Sthurlow 		smbfs_name_free(name, nmlen);
24354bff34e3Sthurlow 
24364bff34e3Sthurlow 	return (error);
24374bff34e3Sthurlow }
24384bff34e3Sthurlow 
243902d09e03SGordon Ross /*
244002d09e03SGordon Ross  * smbfslookup_cache
244102d09e03SGordon Ross  *
244202d09e03SGordon Ross  * Try to reclaim a node from the smbfs node cache.
244302d09e03SGordon Ross  * Some statistics for DEBUG.
244402d09e03SGordon Ross  *
244502d09e03SGordon Ross  * This mechanism lets us avoid many of the five (or more)
244602d09e03SGordon Ross  * OtW lookup calls per file seen with "ls -l" if we search
244702d09e03SGordon Ross  * the smbfs node cache for recently inactive(ated) nodes.
244802d09e03SGordon Ross  */
244991d632c8Sgwr #ifdef DEBUG
245002d09e03SGordon Ross int smbfs_lookup_cache_calls = 0;
245102d09e03SGordon Ross int smbfs_lookup_cache_error = 0;
245202d09e03SGordon Ross int smbfs_lookup_cache_miss = 0;
245302d09e03SGordon Ross int smbfs_lookup_cache_stale = 0;
245402d09e03SGordon Ross int smbfs_lookup_cache_hits = 0;
245502d09e03SGordon Ross #endif /* DEBUG */
245691d632c8Sgwr 
245791d632c8Sgwr /* ARGSUSED */
245891d632c8Sgwr static int
smbfslookup_cache(vnode_t * dvp,char * nm,int nmlen,vnode_t ** vpp,cred_t * cr)245902d09e03SGordon Ross smbfslookup_cache(vnode_t *dvp, char *nm, int nmlen,
246002d09e03SGordon Ross 	vnode_t **vpp, cred_t *cr)
246191d632c8Sgwr {
246291d632c8Sgwr 	struct vattr va;
246391d632c8Sgwr 	smbnode_t *dnp;
246402d09e03SGordon Ross 	smbnode_t *np;
246502d09e03SGordon Ross 	vnode_t *vp;
246602d09e03SGordon Ross 	int error;
246702d09e03SGordon Ross 	char sep;
246891d632c8Sgwr 
246991d632c8Sgwr 	dnp = VTOSMB(dvp);
247002d09e03SGordon Ross 	*vpp = NULL;
247191d632c8Sgwr 
247202d09e03SGordon Ross #ifdef DEBUG
247302d09e03SGordon Ross 	smbfs_lookup_cache_calls++;
247402d09e03SGordon Ross #endif
247591d632c8Sgwr 
247691d632c8Sgwr 	/*
247702d09e03SGordon Ross 	 * First make sure we can get attributes for the
247802d09e03SGordon Ross 	 * directory.  Cached attributes are OK here.
247902d09e03SGordon Ross 	 * If we removed or renamed the directory, this
248002d09e03SGordon Ross 	 * will return ENOENT.  If someone else removed
248102d09e03SGordon Ross 	 * this directory or file, we'll find out when we
248202d09e03SGordon Ross 	 * try to open or get attributes.
248391d632c8Sgwr 	 */
248402d09e03SGordon Ross 	va.va_mask = AT_TYPE | AT_MODE;
248502d09e03SGordon Ross 	error = smbfsgetattr(dvp, &va, cr);
248602d09e03SGordon Ross 	if (error) {
248791d632c8Sgwr #ifdef DEBUG
248802d09e03SGordon Ross 		smbfs_lookup_cache_error++;
248991d632c8Sgwr #endif
249002d09e03SGordon Ross 		return (error);
249102d09e03SGordon Ross 	}
249202d09e03SGordon Ross 
249302d09e03SGordon Ross 	/*
249402d09e03SGordon Ross 	 * Passing NULL smbfattr here so we will
249502d09e03SGordon Ross 	 * just look, not create.
249602d09e03SGordon Ross 	 */
249702d09e03SGordon Ross 	sep = SMBFS_DNP_SEP(dnp);
249802d09e03SGordon Ross 	np = smbfs_node_findcreate(dnp->n_mount,
249902d09e03SGordon Ross 	    dnp->n_rpath, dnp->n_rplen,
250002d09e03SGordon Ross 	    nm, nmlen, sep, NULL);
250102d09e03SGordon Ross 	if (np == NULL) {
250291d632c8Sgwr #ifdef DEBUG
250302d09e03SGordon Ross 		smbfs_lookup_cache_miss++;
250491d632c8Sgwr #endif
250502d09e03SGordon Ross 		return (0);
250602d09e03SGordon Ross 	}
250702d09e03SGordon Ross 
250802d09e03SGordon Ross 	/*
250902d09e03SGordon Ross 	 * Found it.  Attributes still valid?
251002d09e03SGordon Ross 	 */
251102d09e03SGordon Ross 	vp = SMBTOV(np);
251202d09e03SGordon Ross 	if (np->r_attrtime <= gethrtime()) {
251302d09e03SGordon Ross 		/* stale */
251491d632c8Sgwr #ifdef DEBUG
251502d09e03SGordon Ross 		smbfs_lookup_cache_stale++;
251691d632c8Sgwr #endif
251702d09e03SGordon Ross 		VN_RELE(vp);
251802d09e03SGordon Ross 		return (0);
251991d632c8Sgwr 	}
252002d09e03SGordon Ross 
252102d09e03SGordon Ross 	/*
252202d09e03SGordon Ross 	 * Success!
252302d09e03SGordon Ross 	 * Caller gets hold from smbfs_node_findcreate
252402d09e03SGordon Ross 	 */
252591d632c8Sgwr #ifdef DEBUG
252602d09e03SGordon Ross 	smbfs_lookup_cache_hits++;
252791d632c8Sgwr #endif
252802d09e03SGordon Ross 	*vpp = vp;
252991d632c8Sgwr 	return (0);
253091d632c8Sgwr }
253191d632c8Sgwr 
25325f4fc069Sjilinxpd 
25334bff34e3Sthurlow /*
25344bff34e3Sthurlow  * XXX
25354bff34e3Sthurlow  * vsecattr_t is new to build 77, and we need to eventually support
25364bff34e3Sthurlow  * it in order to create an ACL when an object is created.
25374bff34e3Sthurlow  *
25384bff34e3Sthurlow  * This op should support the new FIGNORECASE flag for case-insensitive
25394bff34e3Sthurlow  * lookups, per PSARC 2007/244.
25404bff34e3Sthurlow  */
25414bff34e3Sthurlow /* ARGSUSED */
25424bff34e3Sthurlow static int
smbfs_create(vnode_t * dvp,char * nm,struct vattr * va,enum vcexcl exclusive,int mode,vnode_t ** vpp,cred_t * cr,int lfaware,caller_context_t * ct,vsecattr_t * vsecp)25434bff34e3Sthurlow smbfs_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive,
25444bff34e3Sthurlow 	int mode, vnode_t **vpp, cred_t *cr, int lfaware, caller_context_t *ct,
25454bff34e3Sthurlow 	vsecattr_t *vsecp)
25464bff34e3Sthurlow {
25474bff34e3Sthurlow 	int		error;
25484bff34e3Sthurlow 	vfs_t		*vfsp;
25494bff34e3Sthurlow 	vnode_t		*vp;
25504bff34e3Sthurlow 	smbnode_t	*np;
25514bff34e3Sthurlow 	smbnode_t	*dnp;
25524bff34e3Sthurlow 	smbmntinfo_t	*smi;
25534bff34e3Sthurlow 	struct vattr	vattr;
25544bff34e3Sthurlow 	struct smbfattr	fattr;
25554bff34e3Sthurlow 	struct smb_cred	scred;
25564bff34e3Sthurlow 	const char *name = (const char *)nm;
25574bff34e3Sthurlow 	int		nmlen = strlen(nm);
25584bff34e3Sthurlow 	uint32_t	disp;
2559adee6784SGordon Ross 	smb_fh_t	*fid = NULL;
256091d632c8Sgwr 	int		xattr;
25614bff34e3Sthurlow 
25624bff34e3Sthurlow 	vfsp = dvp->v_vfsp;
25634bff34e3Sthurlow 	smi = VFTOSMI(vfsp);
25644bff34e3Sthurlow 	dnp = VTOSMB(dvp);
25654bff34e3Sthurlow 	vp = NULL;
25664bff34e3Sthurlow 
2567a19609f8Sjv 	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
25684bff34e3Sthurlow 		return (EPERM);
25694bff34e3Sthurlow 
25704bff34e3Sthurlow 	if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
25714bff34e3Sthurlow 		return (EIO);
25724bff34e3Sthurlow 
25734bff34e3Sthurlow 	/*
25744bff34e3Sthurlow 	 * Note: this may break mknod(2) calls to create a directory,
25754bff34e3Sthurlow 	 * but that's obscure use.  Some other filesystems do this.
25765f4fc069Sjilinxpd 	 * Todo: redirect VDIR type here to _mkdir.
25774bff34e3Sthurlow 	 */
25784bff34e3Sthurlow 	if (va->va_type != VREG)
25794bff34e3Sthurlow 		return (EINVAL);
25804bff34e3Sthurlow 
25814bff34e3Sthurlow 	/*
25824bff34e3Sthurlow 	 * If the pathname is "", just use dvp, no checks.
25834bff34e3Sthurlow 	 * Do this outside of the rwlock (like zfs).
25844bff34e3Sthurlow 	 */
25854bff34e3Sthurlow 	if (nmlen == 0) {
25864bff34e3Sthurlow 		VN_HOLD(dvp);
25874bff34e3Sthurlow 		*vpp = dvp;
25884bff34e3Sthurlow 		return (0);
25894bff34e3Sthurlow 	}
25904bff34e3Sthurlow 
25914bff34e3Sthurlow 	/* Don't allow "." or ".." through here. */
25924bff34e3Sthurlow 	if ((nmlen == 1 && name[0] == '.') ||
25934bff34e3Sthurlow 	    (nmlen == 2 && name[0] == '.' && name[1] == '.'))
25944bff34e3Sthurlow 		return (EISDIR);
25954bff34e3Sthurlow 
25964bff34e3Sthurlow 	/*
25974bff34e3Sthurlow 	 * We make a copy of the attributes because the caller does not
25984bff34e3Sthurlow 	 * expect us to change what va points to.
25994bff34e3Sthurlow 	 */
26004bff34e3Sthurlow 	vattr = *va;
26014bff34e3Sthurlow 
26024bff34e3Sthurlow 	if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
26034bff34e3Sthurlow 		return (EINTR);
2604613a2f6bSGordon Ross 	smb_credinit(&scred, cr);
26054bff34e3Sthurlow 
26064bff34e3Sthurlow 	/*
26074bff34e3Sthurlow 	 * NFS needs to go over the wire, just to be sure whether the
260802d09e03SGordon Ross 	 * file exists or not.  Using a cached result is dangerous in
26094bff34e3Sthurlow 	 * this case when making a decision regarding existence.
26104bff34e3Sthurlow 	 *
26114bff34e3Sthurlow 	 * The SMB protocol does NOT really need to go OTW here
26124bff34e3Sthurlow 	 * thanks to the expressive NTCREATE disposition values.
26134bff34e3Sthurlow 	 * Unfortunately, to do Unix access checks correctly,
26144bff34e3Sthurlow 	 * we need to know if the object already exists.
26154bff34e3Sthurlow 	 * When the object does not exist, we need VWRITE on
26164bff34e3Sthurlow 	 * the directory.  Note: smbfslookup() checks VEXEC.
26174bff34e3Sthurlow 	 */
26184bff34e3Sthurlow 	error = smbfslookup(dvp, nm, &vp, cr, 0, ct);
26194bff34e3Sthurlow 	if (error == 0) {
26204bff34e3Sthurlow 		/*
262142645588SGordon Ross 		 * The file already exists.  Error?
262242645588SGordon Ross 		 * NB: have a hold from smbfslookup
26234bff34e3Sthurlow 		 */
26244bff34e3Sthurlow 		if (exclusive == EXCL) {
26254bff34e3Sthurlow 			error = EEXIST;
262642645588SGordon Ross 			VN_RELE(vp);
26274bff34e3Sthurlow 			goto out;
26284bff34e3Sthurlow 		}
26294bff34e3Sthurlow 		/*
26304bff34e3Sthurlow 		 * Verify requested access.
26314bff34e3Sthurlow 		 */
26324bff34e3Sthurlow 		error = smbfs_access(vp, mode, 0, cr, ct);
263342645588SGordon Ross 		if (error) {
263442645588SGordon Ross 			VN_RELE(vp);
26354bff34e3Sthurlow 			goto out;
263642645588SGordon Ross 		}
26374bff34e3Sthurlow 
26384bff34e3Sthurlow 		/*
26394bff34e3Sthurlow 		 * Truncate (if requested).
26404bff34e3Sthurlow 		 */
26415f4fc069Sjilinxpd 		if ((vattr.va_mask & AT_SIZE) && vp->v_type == VREG) {
26425f4fc069Sjilinxpd 			np = VTOSMB(vp);
26435f4fc069Sjilinxpd 			/*
26445f4fc069Sjilinxpd 			 * Check here for large file truncation by
26455f4fc069Sjilinxpd 			 * LF-unaware process, like ufs_create().
26465f4fc069Sjilinxpd 			 */
26475f4fc069Sjilinxpd 			if (!(lfaware & FOFFMAX)) {
26485f4fc069Sjilinxpd 				mutex_enter(&np->r_statelock);
26495f4fc069Sjilinxpd 				if (np->r_size > MAXOFF32_T)
26505f4fc069Sjilinxpd 					error = EOVERFLOW;
26515f4fc069Sjilinxpd 				mutex_exit(&np->r_statelock);
26525f4fc069Sjilinxpd 			}
26535f4fc069Sjilinxpd 			if (error) {
26545f4fc069Sjilinxpd 				VN_RELE(vp);
26555f4fc069Sjilinxpd 				goto out;
26565f4fc069Sjilinxpd 			}
26575f4fc069Sjilinxpd 			vattr.va_mask = AT_SIZE;
26585f4fc069Sjilinxpd 			error = smbfssetattr(vp, &vattr, 0, cr);
265942645588SGordon Ross 			if (error) {
266042645588SGordon Ross 				VN_RELE(vp);
26614bff34e3Sthurlow 				goto out;
266242645588SGordon Ross 			}
26635f4fc069Sjilinxpd #ifdef	SMBFS_VNEVENT
26645f4fc069Sjilinxpd 			/* Existing file was truncated */
26655f4fc069Sjilinxpd 			vnevent_create(vp, ct);
26665f4fc069Sjilinxpd #endif
26675f4fc069Sjilinxpd 			/* invalidate pages done in smbfssetattr() */
26684bff34e3Sthurlow 		}
26694bff34e3Sthurlow 		/* Success! */
26704bff34e3Sthurlow 		*vpp = vp;
26714bff34e3Sthurlow 		goto out;
26724bff34e3Sthurlow 	}
26734bff34e3Sthurlow 
26744bff34e3Sthurlow 	/*
26754bff34e3Sthurlow 	 * The file did not exist.  Need VWRITE in the directory.
26764bff34e3Sthurlow 	 */
26774bff34e3Sthurlow 	error = smbfs_access(dvp, VWRITE, 0, cr, ct);
26784bff34e3Sthurlow 	if (error)
26794bff34e3Sthurlow 		goto out;
26804bff34e3Sthurlow 
26814bff34e3Sthurlow 	/*
26824bff34e3Sthurlow 	 * Now things get tricky.  We also need to check the
26834bff34e3Sthurlow 	 * requested open mode against the file we may create.
26844bff34e3Sthurlow 	 * See comments at smbfs_access_rwx
26854bff34e3Sthurlow 	 */
26864bff34e3Sthurlow 	error = smbfs_access_rwx(vfsp, VREG, mode, cr);
26874bff34e3Sthurlow 	if (error)
26884bff34e3Sthurlow 		goto out;
26894bff34e3Sthurlow 
26904bff34e3Sthurlow 	/*
26914bff34e3Sthurlow 	 * Now the code derived from Darwin,
26924bff34e3Sthurlow 	 * but with greater use of NT_CREATE
26934bff34e3Sthurlow 	 * disposition options.  Much changed.
26944bff34e3Sthurlow 	 *
26954bff34e3Sthurlow 	 * Create (or open) a new child node.
26964bff34e3Sthurlow 	 * Note we handled "." and ".." above.
26974bff34e3Sthurlow 	 */
26984bff34e3Sthurlow 
26994bff34e3Sthurlow 	if (exclusive == EXCL)
27004bff34e3Sthurlow 		disp = NTCREATEX_DISP_CREATE;
27014bff34e3Sthurlow 	else {
27024bff34e3Sthurlow 		/* Truncate regular files if requested. */
27034bff34e3Sthurlow 		if ((va->va_type == VREG) &&
27044bff34e3Sthurlow 		    (va->va_mask & AT_SIZE) &&
27054bff34e3Sthurlow 		    (va->va_size == 0))
27064bff34e3Sthurlow 			disp = NTCREATEX_DISP_OVERWRITE_IF;
27074bff34e3Sthurlow 		else
27084bff34e3Sthurlow 			disp = NTCREATEX_DISP_OPEN_IF;
27094bff34e3Sthurlow 	}
271091d632c8Sgwr 	xattr = (dnp->n_flag & N_XATTR) ? 1 : 0;
271102d09e03SGordon Ross 	error = smbfs_smb_create(dnp,
271202d09e03SGordon Ross 	    name, nmlen, xattr,
271302d09e03SGordon Ross 	    disp, &scred, &fid);
27144bff34e3Sthurlow 	if (error)
27154bff34e3Sthurlow 		goto out;
27164bff34e3Sthurlow 
27174bff34e3Sthurlow 	/*
27184bff34e3Sthurlow 	 * Should use the fid to get/set the size
27194bff34e3Sthurlow 	 * while we have it opened here.  See above.
27204bff34e3Sthurlow 	 */
2721adee6784SGordon Ross 	smbfs_smb_close(fid);
27224bff34e3Sthurlow 
27234bff34e3Sthurlow 	/*
27244bff34e3Sthurlow 	 * In the open case, the name may differ a little
27254bff34e3Sthurlow 	 * from what we passed to create (case, etc.)
27264bff34e3Sthurlow 	 * so call lookup to get the (opened) name.
27274bff34e3Sthurlow 	 *
27284bff34e3Sthurlow 	 * XXX: Could avoid this extra lookup if the
27294bff34e3Sthurlow 	 * "createact" result from NT_CREATE says we
27304bff34e3Sthurlow 	 * created the object.
27314bff34e3Sthurlow 	 */
27324bff34e3Sthurlow 	error = smbfs_smb_lookup(dnp, &name, &nmlen, &fattr, &scred);
27334bff34e3Sthurlow 	if (error)
27344bff34e3Sthurlow 		goto out;
27354bff34e3Sthurlow 
27364bff34e3Sthurlow 	/* update attr and directory cache */
27374bff34e3Sthurlow 	smbfs_attr_touchdir(dnp);
27384bff34e3Sthurlow 
27394bff34e3Sthurlow 	error = smbfs_nget(dvp, name, nmlen, &fattr, &vp);
27404bff34e3Sthurlow 	if (error)
27414bff34e3Sthurlow 		goto out;
27424bff34e3Sthurlow 
27434bff34e3Sthurlow 	/* Success! */
27444bff34e3Sthurlow 	*vpp = vp;
27454bff34e3Sthurlow 	error = 0;
27464bff34e3Sthurlow 
27474bff34e3Sthurlow out:
27484bff34e3Sthurlow 	smb_credrele(&scred);
274902d09e03SGordon Ross 	smbfs_rw_exit(&dnp->r_rwlock);
27504bff34e3Sthurlow 	if (name != nm)
27514bff34e3Sthurlow 		smbfs_name_free(name, nmlen);
27524bff34e3Sthurlow 	return (error);
27534bff34e3Sthurlow }
27544bff34e3Sthurlow 
27554bff34e3Sthurlow /*
27564bff34e3Sthurlow  * XXX
27574bff34e3Sthurlow  * This op should support the new FIGNORECASE flag for case-insensitive
27584bff34e3Sthurlow  * lookups, per PSARC 2007/244.
27594bff34e3Sthurlow  */
27604bff34e3Sthurlow /* ARGSUSED */
27614bff34e3Sthurlow static int
smbfs_remove(vnode_t * dvp,char * nm,cred_t * cr,caller_context_t * ct,int flags)27624bff34e3Sthurlow smbfs_remove(vnode_t *dvp, char *nm, cred_t *cr, caller_context_t *ct,
27634bff34e3Sthurlow 	int flags)
27644bff34e3Sthurlow {
27654bff34e3Sthurlow 	struct smb_cred	scred;
2766ff1e230cSjilinxpd 	vnode_t		*vp = NULL;
2767ff1e230cSjilinxpd 	smbnode_t	*dnp = VTOSMB(dvp);
2768ff1e230cSjilinxpd 	smbmntinfo_t	*smi = VTOSMI(dvp);
2769ff1e230cSjilinxpd 	int		error;
27704bff34e3Sthurlow 
2771a19609f8Sjv 	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
27724bff34e3Sthurlow 		return (EPERM);
27734bff34e3Sthurlow 
27744bff34e3Sthurlow 	if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
27754bff34e3Sthurlow 		return (EIO);
27764bff34e3Sthurlow 
27774bff34e3Sthurlow 	/*
27784bff34e3Sthurlow 	 * Verify access to the dirctory.
27794bff34e3Sthurlow 	 */
27804bff34e3Sthurlow 	error = smbfs_access(dvp, VWRITE|VEXEC, 0, cr, ct);
27814bff34e3Sthurlow 	if (error)
2782ff1e230cSjilinxpd 		return (error);
2783ff1e230cSjilinxpd 
2784ff1e230cSjilinxpd 	if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
2785ff1e230cSjilinxpd 		return (EINTR);
2786ff1e230cSjilinxpd 	smb_credinit(&scred, cr);
2787ff1e230cSjilinxpd 
2788ff1e230cSjilinxpd 	/* Lookup the file to remove. */
2789ff1e230cSjilinxpd 	error = smbfslookup(dvp, nm, &vp, cr, 0, ct);
2790adee6784SGordon Ross 	if (error != 0)
2791adee6784SGordon Ross 		goto out;
2792adee6784SGordon Ross 
2793adee6784SGordon Ross 	/* Don't allow unlink of a directory. */
2794adee6784SGordon Ross 	if (vp->v_type == VDIR) {
2795adee6784SGordon Ross 		error = EPERM;
2796adee6784SGordon Ross 		goto out;
2797ff1e230cSjilinxpd 	}
2798ff1e230cSjilinxpd 
2799adee6784SGordon Ross 	/*
2800adee6784SGordon Ross 	 * Do the real remove work
2801adee6784SGordon Ross 	 */
2802adee6784SGordon Ross 	error = smbfsremove(dvp, vp, &scred, flags);
2803adee6784SGordon Ross 	if (error != 0)
2804adee6784SGordon Ross 		goto out;
2805adee6784SGordon Ross 
2806adee6784SGordon Ross #ifdef	SMBFS_VNEVENT
2807adee6784SGordon Ross 	vnevent_remove(vp, dvp, nm, ct);
2808adee6784SGordon Ross #endif
2809adee6784SGordon Ross 
2810adee6784SGordon Ross out:
2811adee6784SGordon Ross 	if (vp != NULL)
2812adee6784SGordon Ross 		VN_RELE(vp);
2813adee6784SGordon Ross 
2814ff1e230cSjilinxpd 	smb_credrele(&scred);
2815ff1e230cSjilinxpd 	smbfs_rw_exit(&dnp->r_rwlock);
2816ff1e230cSjilinxpd 
2817ff1e230cSjilinxpd 	return (error);
2818ff1e230cSjilinxpd }
2819ff1e230cSjilinxpd 
2820ff1e230cSjilinxpd /*
2821ff1e230cSjilinxpd  * smbfsremove does the real work of removing in SMBFS
2822ff1e230cSjilinxpd  * Caller has done dir access checks etc.
2823ff1e230cSjilinxpd  *
2824ff1e230cSjilinxpd  * The normal way to delete a file over SMB is open it (with DELETE access),
2825ff1e230cSjilinxpd  * set the "delete-on-close" flag, and close the file.  The problem for Unix
2826ff1e230cSjilinxpd  * applications is that they expect the file name to be gone once the unlink
2827ff1e230cSjilinxpd  * completes, and the SMB server does not actually delete the file until ALL
2828ff1e230cSjilinxpd  * opens of that file are closed.  We can't assume our open handles are the
2829ff1e230cSjilinxpd  * only open handles on a file we're deleting, so to be safe we'll try to
2830ff1e230cSjilinxpd  * rename the file to a temporary name and then set delete-on-close.  If we
2831ff1e230cSjilinxpd  * fail to set delete-on-close (i.e. because other opens prevent it) then
2832ff1e230cSjilinxpd  * undo the changes we made and give up with EBUSY.  Note that we might have
2833ff1e230cSjilinxpd  * permission to delete a file but lack permission to rename, so we want to
2834ff1e230cSjilinxpd  * continue in cases where rename fails.  As an optimization, only do the
2835ff1e230cSjilinxpd  * rename when we have the file open.
2836ff1e230cSjilinxpd  *
2837ff1e230cSjilinxpd  * This is similar to what NFS does when deleting a file that has local opens,
2838ff1e230cSjilinxpd  * but thanks to SMB delete-on-close, we don't need to keep track of when the
2839ff1e230cSjilinxpd  * last local open goes away and send a delete.  The server does that for us.
2840ff1e230cSjilinxpd  */
2841ff1e230cSjilinxpd /* ARGSUSED */
2842ff1e230cSjilinxpd static int
smbfsremove(vnode_t * dvp,vnode_t * vp,struct smb_cred * scred,int flags)2843ff1e230cSjilinxpd smbfsremove(vnode_t *dvp, vnode_t *vp, struct smb_cred *scred,
2844ff1e230cSjilinxpd     int flags)
2845ff1e230cSjilinxpd {
2846ff1e230cSjilinxpd 	smbnode_t	*dnp = VTOSMB(dvp);
2847ff1e230cSjilinxpd 	smbnode_t	*np = VTOSMB(vp);
2848adee6784SGordon Ross 	smbmntinfo_t	*smi = np->n_mount;
2849ff1e230cSjilinxpd 	char		*tmpname = NULL;
2850ff1e230cSjilinxpd 	int		tnlen;
2851ff1e230cSjilinxpd 	int		error;
2852adee6784SGordon Ross 	smb_fh_t	*fid = NULL;
2853ff1e230cSjilinxpd 	boolean_t	renamed = B_FALSE;
28544bff34e3Sthurlow 
28554bff34e3Sthurlow 	/*
2856ff1e230cSjilinxpd 	 * The dvp RWlock must be held as writer.
28574bff34e3Sthurlow 	 */
2858ff1e230cSjilinxpd 	ASSERT(dnp->r_rwlock.owner == curthread);
28594bff34e3Sthurlow 
28605f4fc069Sjilinxpd 	/*
28615f4fc069Sjilinxpd 	 * We need to flush any dirty pages which happen to
28625f4fc069Sjilinxpd 	 * be hanging around before removing the file.  This
28635f4fc069Sjilinxpd 	 * shouldn't happen very often and mostly on file
28645f4fc069Sjilinxpd 	 * systems mounted "nocto".
28655f4fc069Sjilinxpd 	 */
28665f4fc069Sjilinxpd 	if (vn_has_cached_data(vp) &&
28675f4fc069Sjilinxpd 	    ((np->r_flags & RDIRTY) || np->r_count > 0)) {
28685f4fc069Sjilinxpd 		error = smbfs_putpage(vp, (offset_t)0, 0, 0,
28695f4fc069Sjilinxpd 		    scred->scr_cred, NULL);
28705f4fc069Sjilinxpd 		if (error && (error == ENOSPC || error == EDQUOT)) {
28715f4fc069Sjilinxpd 			mutex_enter(&np->r_statelock);
28725f4fc069Sjilinxpd 			if (!np->r_error)
28735f4fc069Sjilinxpd 				np->r_error = error;
28745f4fc069Sjilinxpd 			mutex_exit(&np->r_statelock);
28755f4fc069Sjilinxpd 		}
28765f4fc069Sjilinxpd 	}
28775f4fc069Sjilinxpd 
2878ff1e230cSjilinxpd 	/*
2879ff1e230cSjilinxpd 	 * Get a file handle with delete access.
2880ff1e230cSjilinxpd 	 * Close this FID before return.
2881ff1e230cSjilinxpd 	 */
2882ff1e230cSjilinxpd 	error = smbfs_smb_tmpopen(np, STD_RIGHT_DELETE_ACCESS,
2883ff1e230cSjilinxpd 	    scred, &fid);
2884ff1e230cSjilinxpd 	if (error) {
2885ff1e230cSjilinxpd 		SMBVDEBUG("error %d opening %s\n",
2886ff1e230cSjilinxpd 		    error, np->n_rpath);
28874bff34e3Sthurlow 		goto out;
28884bff34e3Sthurlow 	}
2889adee6784SGordon Ross 	ASSERT(fid != NULL);
28904bff34e3Sthurlow 
28914bff34e3Sthurlow 	/*
2892ff1e230cSjilinxpd 	 * If we have the file open, try to rename it to a temporary name.
2893ff1e230cSjilinxpd 	 * If we can't rename, continue on and try setting DoC anyway.
2894adee6784SGordon Ross 	 * Unnecessary for directories.
28954bff34e3Sthurlow 	 */
2896adee6784SGordon Ross 	if (vp->v_type != VDIR && vp->v_count > 1 && np->n_fidrefs > 0) {
2897ff1e230cSjilinxpd 		tmpname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
2898ff1e230cSjilinxpd 		tnlen = smbfs_newname(tmpname, MAXNAMELEN);
2899adee6784SGordon Ross 		error = smbfs_smb_rename(dnp, np, dnp, tmpname, tnlen,
2900adee6784SGordon Ross 		    fid, scred);
2901ff1e230cSjilinxpd 		if (error != 0) {
2902ff1e230cSjilinxpd 			SMBVDEBUG("error %d renaming %s -> %s\n",
29035f4fc069Sjilinxpd 			    error, np->n_rpath, tmpname);
2904ff1e230cSjilinxpd 			/* Keep going without the rename. */
2905ff1e230cSjilinxpd 		} else {
2906ff1e230cSjilinxpd 			renamed = B_TRUE;
2907ff1e230cSjilinxpd 		}
2908ff1e230cSjilinxpd 	}
29094bff34e3Sthurlow 
2910ff1e230cSjilinxpd 	/*
2911ff1e230cSjilinxpd 	 * Mark the file as delete-on-close.  If we can't,
2912ff1e230cSjilinxpd 	 * undo what we did and err out.
2913ff1e230cSjilinxpd 	 */
2914adee6784SGordon Ross 	error = smbfs_smb_setdisp(smi->smi_share, fid, 1, scred);
2915ff1e230cSjilinxpd 	if (error != 0) {
2916ff1e230cSjilinxpd 		SMBVDEBUG("error %d setting DoC on %s\n",
2917ff1e230cSjilinxpd 		    error, np->n_rpath);
291802d09e03SGordon Ross 		/*
2919ff1e230cSjilinxpd 		 * Failed to set DoC. If we renamed, undo that.
2920ff1e230cSjilinxpd 		 * Need np->n_rpath relative to parent (dnp).
2921ff1e230cSjilinxpd 		 * Use parent path name length plus one for
2922ff1e230cSjilinxpd 		 * the separator ('/' or ':')
292302d09e03SGordon Ross 		 */
2924ff1e230cSjilinxpd 		if (renamed) {
2925ff1e230cSjilinxpd 			char *oldname;
2926ff1e230cSjilinxpd 			int oldnlen;
2927ff1e230cSjilinxpd 			int err2;
2928ff1e230cSjilinxpd 
2929ff1e230cSjilinxpd 			oldname = np->n_rpath + (dnp->n_rplen + 1);
2930ff1e230cSjilinxpd 			oldnlen = np->n_rplen - (dnp->n_rplen + 1);
2931adee6784SGordon Ross 			err2 = smbfs_smb_rename(dnp, np, dnp, oldname, oldnlen,
2932adee6784SGordon Ross 			    fid, scred);
2933ff1e230cSjilinxpd 			SMBVDEBUG("error %d un-renaming %s -> %s\n",
29345f4fc069Sjilinxpd 			    err2, tmpname, np->n_rpath);
293502d09e03SGordon Ross 		}
2936ff1e230cSjilinxpd 		error = EBUSY;
2937ff1e230cSjilinxpd 		goto out;
29384bff34e3Sthurlow 	}
2939ff1e230cSjilinxpd 	/* Done! */
2940adee6784SGordon Ross 	smbfs_attrcache_remove(np);
2941ff1e230cSjilinxpd 	smbfs_attrcache_prune(np);
29424bff34e3Sthurlow 
29434bff34e3Sthurlow out:
2944ff1e230cSjilinxpd 	if (tmpname != NULL)
2945ff1e230cSjilinxpd 		kmem_free(tmpname, MAXNAMELEN);
2946adee6784SGordon Ross 	if (fid != NULL)
2947adee6784SGordon Ross 		smbfs_smb_tmpclose(np, fid);
2948ff1e230cSjilinxpd 
2949ff1e230cSjilinxpd 	if (error == 0) {
2950ff1e230cSjilinxpd 		/* Keep lookup from finding this node anymore. */
2951ff1e230cSjilinxpd 		smbfs_rmhash(np);
2952ff1e230cSjilinxpd 	}
29534bff34e3Sthurlow 
29544bff34e3Sthurlow 	return (error);
29554bff34e3Sthurlow }
29564bff34e3Sthurlow 
29574bff34e3Sthurlow 
29585f4fc069Sjilinxpd /* ARGSUSED */
29595f4fc069Sjilinxpd static int
smbfs_link(vnode_t * tdvp,vnode_t * svp,char * tnm,cred_t * cr,caller_context_t * ct,int flags)29605f4fc069Sjilinxpd smbfs_link(vnode_t *tdvp, vnode_t *svp, char *tnm, cred_t *cr,
29615f4fc069Sjilinxpd 	caller_context_t *ct, int flags)
29625f4fc069Sjilinxpd {
29635f4fc069Sjilinxpd 	/* Not yet... */
29645f4fc069Sjilinxpd 	return (ENOSYS);
29655f4fc069Sjilinxpd }
29665f4fc069Sjilinxpd 
29675f4fc069Sjilinxpd 
29684bff34e3Sthurlow /*
29694bff34e3Sthurlow  * XXX
29704bff34e3Sthurlow  * This op should support the new FIGNORECASE flag for case-insensitive
29714bff34e3Sthurlow  * lookups, per PSARC 2007/244.
29724bff34e3Sthurlow  */
29734bff34e3Sthurlow /* ARGSUSED */
29744bff34e3Sthurlow static int
smbfs_rename(vnode_t * odvp,char * onm,vnode_t * ndvp,char * nnm,cred_t * cr,caller_context_t * ct,int flags)29754bff34e3Sthurlow smbfs_rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr,
29764bff34e3Sthurlow 	caller_context_t *ct, int flags)
29774bff34e3Sthurlow {
2978ff1e230cSjilinxpd 	struct smb_cred	scred;
2979ff1e230cSjilinxpd 	smbnode_t	*odnp = VTOSMB(odvp);
2980ff1e230cSjilinxpd 	smbnode_t	*ndnp = VTOSMB(ndvp);
2981ff1e230cSjilinxpd 	vnode_t		*ovp;
2982ff1e230cSjilinxpd 	int error;
29834bff34e3Sthurlow 
2984a19609f8Sjv 	if (curproc->p_zone != VTOSMI(odvp)->smi_zone_ref.zref_zone ||
2985a19609f8Sjv 	    curproc->p_zone != VTOSMI(ndvp)->smi_zone_ref.zref_zone)
29864bff34e3Sthurlow 		return (EPERM);
29874bff34e3Sthurlow 
29884bff34e3Sthurlow 	if (VTOSMI(odvp)->smi_flags & SMI_DEAD ||
29894bff34e3Sthurlow 	    VTOSMI(ndvp)->smi_flags & SMI_DEAD ||
29904bff34e3Sthurlow 	    odvp->v_vfsp->vfs_flag & VFS_UNMOUNTED ||
29914bff34e3Sthurlow 	    ndvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
29924bff34e3Sthurlow 		return (EIO);
29934bff34e3Sthurlow 
29944bff34e3Sthurlow 	if (strcmp(onm, ".") == 0 || strcmp(onm, "..") == 0 ||
29954bff34e3Sthurlow 	    strcmp(nnm, ".") == 0 || strcmp(nnm, "..") == 0)
29964bff34e3Sthurlow 		return (EINVAL);
29974bff34e3Sthurlow 
29984bff34e3Sthurlow 	/*
29994bff34e3Sthurlow 	 * Check that everything is on the same filesystem.
30004bff34e3Sthurlow 	 * vn_rename checks the fsid's, but in case we don't
30014bff34e3Sthurlow 	 * fill those in correctly, check here too.
30024bff34e3Sthurlow 	 */
30034bff34e3Sthurlow 	if (odvp->v_vfsp != ndvp->v_vfsp)
30044bff34e3Sthurlow 		return (EXDEV);
30054bff34e3Sthurlow 
3006ff1e230cSjilinxpd 	/*
3007ff1e230cSjilinxpd 	 * Need write access on source and target.
3008ff1e230cSjilinxpd 	 * Server takes care of most checks.
3009ff1e230cSjilinxpd 	 */
3010ff1e230cSjilinxpd 	error = smbfs_access(odvp, VWRITE|VEXEC, 0, cr, ct);
3011ff1e230cSjilinxpd 	if (error)
3012ff1e230cSjilinxpd 		return (error);
3013ff1e230cSjilinxpd 	if (odvp != ndvp) {
3014ff1e230cSjilinxpd 		error = smbfs_access(ndvp, VWRITE, 0, cr, ct);
3015ff1e230cSjilinxpd 		if (error)
3016ff1e230cSjilinxpd 			return (error);
3017ff1e230cSjilinxpd 	}
30184bff34e3Sthurlow 
30194bff34e3Sthurlow 	/*
3020ff1e230cSjilinxpd 	 * Need to lock both old/new dirs as writer.
3021ff1e230cSjilinxpd 	 *
30224bff34e3Sthurlow 	 * Avoid deadlock here on old vs new directory nodes
30234bff34e3Sthurlow 	 * by always taking the locks in order of address.
30244bff34e3Sthurlow 	 * The order is arbitrary, but must be consistent.
30254bff34e3Sthurlow 	 */
30264bff34e3Sthurlow 	if (odnp < ndnp) {
30274bff34e3Sthurlow 		if (smbfs_rw_enter_sig(&odnp->r_rwlock, RW_WRITER,
30284bff34e3Sthurlow 		    SMBINTR(odvp)))
30294bff34e3Sthurlow 			return (EINTR);
30304bff34e3Sthurlow 		if (smbfs_rw_enter_sig(&ndnp->r_rwlock, RW_WRITER,
30314bff34e3Sthurlow 		    SMBINTR(ndvp))) {
30324bff34e3Sthurlow 			smbfs_rw_exit(&odnp->r_rwlock);
30334bff34e3Sthurlow 			return (EINTR);
30344bff34e3Sthurlow 		}
30354bff34e3Sthurlow 	} else {
30364bff34e3Sthurlow 		if (smbfs_rw_enter_sig(&ndnp->r_rwlock, RW_WRITER,
30374bff34e3Sthurlow 		    SMBINTR(ndvp)))
30384bff34e3Sthurlow 			return (EINTR);
30394bff34e3Sthurlow 		if (smbfs_rw_enter_sig(&odnp->r_rwlock, RW_WRITER,
30404bff34e3Sthurlow 		    SMBINTR(odvp))) {
30414bff34e3Sthurlow 			smbfs_rw_exit(&ndnp->r_rwlock);
30424bff34e3Sthurlow 			return (EINTR);
30434bff34e3Sthurlow 		}
30444bff34e3Sthurlow 	}
304502d09e03SGordon Ross 	smb_credinit(&scred, cr);
30464bff34e3Sthurlow 
3047ff1e230cSjilinxpd 	/* Lookup the "old" name */
3048ff1e230cSjilinxpd 	error = smbfslookup(odvp, onm, &ovp, cr, 0, ct);
3049ff1e230cSjilinxpd 	if (error == 0) {
3050ff1e230cSjilinxpd 		/*
3051ff1e230cSjilinxpd 		 * Do the real rename work
3052ff1e230cSjilinxpd 		 */
3053ff1e230cSjilinxpd 		error = smbfsrename(odvp, ovp, ndvp, nnm, &scred, flags);
3054ff1e230cSjilinxpd 		VN_RELE(ovp);
30554bff34e3Sthurlow 	}
30564bff34e3Sthurlow 
3057ff1e230cSjilinxpd 	smb_credrele(&scred);
3058ff1e230cSjilinxpd 	smbfs_rw_exit(&odnp->r_rwlock);
3059ff1e230cSjilinxpd 	smbfs_rw_exit(&ndnp->r_rwlock);
3060ff1e230cSjilinxpd 
3061ff1e230cSjilinxpd 	return (error);
3062ff1e230cSjilinxpd }
3063ff1e230cSjilinxpd 
3064ff1e230cSjilinxpd /*
3065ff1e230cSjilinxpd  * smbfsrename does the real work of renaming in SMBFS
3066ff1e230cSjilinxpd  * Caller has done dir access checks etc.
3067ff1e230cSjilinxpd  */
3068ff1e230cSjilinxpd /* ARGSUSED */
3069ff1e230cSjilinxpd static int
smbfsrename(vnode_t * odvp,vnode_t * ovp,vnode_t * ndvp,char * nnm,struct smb_cred * scred,int flags)3070ff1e230cSjilinxpd smbfsrename(vnode_t *odvp, vnode_t *ovp, vnode_t *ndvp, char *nnm,
3071ff1e230cSjilinxpd     struct smb_cred *scred, int flags)
3072ff1e230cSjilinxpd {
3073ff1e230cSjilinxpd 	smbnode_t	*odnp = VTOSMB(odvp);
3074ff1e230cSjilinxpd 	smbnode_t	*onp = VTOSMB(ovp);
3075ff1e230cSjilinxpd 	smbnode_t	*ndnp = VTOSMB(ndvp);
3076ff1e230cSjilinxpd 	vnode_t		*nvp = NULL;
3077ff1e230cSjilinxpd 	int		error;
3078ff1e230cSjilinxpd 	int		nvp_locked = 0;
3079adee6784SGordon Ross 	smb_fh_t	*fid = NULL;
3080ff1e230cSjilinxpd 
3081ff1e230cSjilinxpd 	/* Things our caller should have checked. */
3082ff1e230cSjilinxpd 	ASSERT(curproc->p_zone == VTOSMI(odvp)->smi_zone_ref.zref_zone);
3083ff1e230cSjilinxpd 	ASSERT(odvp->v_vfsp == ndvp->v_vfsp);
3084ff1e230cSjilinxpd 	ASSERT(odnp->r_rwlock.owner == curthread);
3085ff1e230cSjilinxpd 	ASSERT(ndnp->r_rwlock.owner == curthread);
30864bff34e3Sthurlow 
30874bff34e3Sthurlow 	/*
30884bff34e3Sthurlow 	 * Lookup the target file.  If it exists, it needs to be
30894bff34e3Sthurlow 	 * checked to see whether it is a mount point and whether
30904bff34e3Sthurlow 	 * it is active (open).
30914bff34e3Sthurlow 	 */
3092ff1e230cSjilinxpd 	error = smbfslookup(ndvp, nnm, &nvp, scred->scr_cred, 0, NULL);
30934bff34e3Sthurlow 	if (!error) {
30944bff34e3Sthurlow 		/*
30954bff34e3Sthurlow 		 * Target (nvp) already exists.  Check that it
30964bff34e3Sthurlow 		 * has the same type as the source.  The server
30974bff34e3Sthurlow 		 * will check this also, (and more reliably) but
30984bff34e3Sthurlow 		 * this lets us return the correct error codes.
30994bff34e3Sthurlow 		 */
31004bff34e3Sthurlow 		if (ovp->v_type == VDIR) {
31014bff34e3Sthurlow 			if (nvp->v_type != VDIR) {
31024bff34e3Sthurlow 				error = ENOTDIR;
31034bff34e3Sthurlow 				goto out;
31044bff34e3Sthurlow 			}
31054bff34e3Sthurlow 		} else {
31064bff34e3Sthurlow 			if (nvp->v_type == VDIR) {
31074bff34e3Sthurlow 				error = EISDIR;
31084bff34e3Sthurlow 				goto out;
31094bff34e3Sthurlow 			}
31104bff34e3Sthurlow 		}
31114bff34e3Sthurlow 
31124bff34e3Sthurlow 		/*
31134bff34e3Sthurlow 		 * POSIX dictates that when the source and target
31144bff34e3Sthurlow 		 * entries refer to the same file object, rename
31154bff34e3Sthurlow 		 * must do nothing and exit without error.
31164bff34e3Sthurlow 		 */
31174bff34e3Sthurlow 		if (ovp == nvp) {
31184bff34e3Sthurlow 			error = 0;
31194bff34e3Sthurlow 			goto out;
31204bff34e3Sthurlow 		}
31214bff34e3Sthurlow 
31224bff34e3Sthurlow 		/*
31234bff34e3Sthurlow 		 * Also must ensure the target is not a mount point,
31244bff34e3Sthurlow 		 * and keep mount/umount away until we're done.
31254bff34e3Sthurlow 		 */
31264bff34e3Sthurlow 		if (vn_vfsrlock(nvp)) {
31274bff34e3Sthurlow 			error = EBUSY;
31284bff34e3Sthurlow 			goto out;
31294bff34e3Sthurlow 		}
31304bff34e3Sthurlow 		nvp_locked = 1;
31314bff34e3Sthurlow 		if (vn_mountedvfs(nvp) != NULL) {
31324bff34e3Sthurlow 			error = EBUSY;
31334bff34e3Sthurlow 			goto out;
31344bff34e3Sthurlow 		}
31354bff34e3Sthurlow 
313691d632c8Sgwr 		/*
3137ff1e230cSjilinxpd 		 * CIFS may give a SHARING_VIOLATION error when
313891d632c8Sgwr 		 * trying to rename onto an exising object,
313991d632c8Sgwr 		 * so try to remove the target first.
314091d632c8Sgwr 		 * (Only for files, not directories.)
314191d632c8Sgwr 		 */
314291d632c8Sgwr 		if (nvp->v_type == VDIR) {
314391d632c8Sgwr 			error = EEXIST;
314491d632c8Sgwr 			goto out;
314591d632c8Sgwr 		}
3146ff1e230cSjilinxpd 		error = smbfsremove(ndvp, nvp, scred, flags);
3147ff1e230cSjilinxpd 		if (error != 0)
31484bff34e3Sthurlow 			goto out;
314902d09e03SGordon Ross 
315091d632c8Sgwr 		/*
315191d632c8Sgwr 		 * OK, removed the target file.  Continue as if
315291d632c8Sgwr 		 * lookup target had failed (nvp == NULL).
315391d632c8Sgwr 		 */
315491d632c8Sgwr 		vn_vfsunlock(nvp);
315591d632c8Sgwr 		nvp_locked = 0;
315691d632c8Sgwr 		VN_RELE(nvp);
315791d632c8Sgwr 		nvp = NULL;
31584bff34e3Sthurlow 	} /* nvp */
31594bff34e3Sthurlow 
3160adee6784SGordon Ross 	/*
3161adee6784SGordon Ross 	 * Get a file handle with delete access.
3162adee6784SGordon Ross 	 * Close this FID before return.
3163adee6784SGordon Ross 	 */
3164adee6784SGordon Ross 	error = smbfs_smb_tmpopen(onp, STD_RIGHT_DELETE_ACCESS,
3165adee6784SGordon Ross 	    scred, &fid);
3166adee6784SGordon Ross 	if (error) {
3167adee6784SGordon Ross 		SMBVDEBUG("error %d opening %s\n",
3168adee6784SGordon Ross 		    error, onp->n_rpath);
3169adee6784SGordon Ross 		goto out;
3170adee6784SGordon Ross 	}
3171adee6784SGordon Ross 
317202d09e03SGordon Ross 	smbfs_attrcache_remove(onp);
3173adee6784SGordon Ross 	error = smbfs_smb_rename(odnp, onp, ndnp, nnm, strlen(nnm),
3174adee6784SGordon Ross 	    fid, scred);
3175adee6784SGordon Ross 
3176adee6784SGordon Ross 	smbfs_smb_tmpclose(onp, fid);
31774bff34e3Sthurlow 
317802d09e03SGordon Ross 	/*
317902d09e03SGordon Ross 	 * If the old name should no longer exist,
318002d09e03SGordon Ross 	 * discard any cached attributes under it.
318102d09e03SGordon Ross 	 */
31825f4fc069Sjilinxpd 	if (error == 0) {
318302d09e03SGordon Ross 		smbfs_attrcache_prune(onp);
31845f4fc069Sjilinxpd 		/* SMBFS_VNEVENT... */
31855f4fc069Sjilinxpd 	}
31864bff34e3Sthurlow 
31874bff34e3Sthurlow out:
31884bff34e3Sthurlow 	if (nvp) {
31894bff34e3Sthurlow 		if (nvp_locked)
31904bff34e3Sthurlow 			vn_vfsunlock(nvp);
31914bff34e3Sthurlow 		VN_RELE(nvp);
31924bff34e3Sthurlow 	}
31934bff34e3Sthurlow 
31944bff34e3Sthurlow 	return (error);
31954bff34e3Sthurlow }
31964bff34e3Sthurlow 
31974bff34e3Sthurlow /*
31984bff34e3Sthurlow  * XXX
31994bff34e3Sthurlow  * vsecattr_t is new to build 77, and we need to eventually support
32004bff34e3Sthurlow  * it in order to create an ACL when an object is created.
32014bff34e3Sthurlow  *
32024bff34e3Sthurlow  * This op should support the new FIGNORECASE flag for case-insensitive
32034bff34e3Sthurlow  * lookups, per PSARC 2007/244.
32044bff34e3Sthurlow  */
32054bff34e3Sthurlow /* ARGSUSED */
32064bff34e3Sthurlow static int
smbfs_mkdir(vnode_t * dvp,char * nm,struct vattr * va,vnode_t ** vpp,cred_t * cr,caller_context_t * ct,int flags,vsecattr_t * vsecp)32074bff34e3Sthurlow smbfs_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp,
32084bff34e3Sthurlow 	cred_t *cr, caller_context_t *ct, int flags, vsecattr_t *vsecp)
32094bff34e3Sthurlow {
32104bff34e3Sthurlow 	vnode_t		*vp;
32114bff34e3Sthurlow 	struct smbnode	*dnp = VTOSMB(dvp);
32124bff34e3Sthurlow 	struct smbmntinfo *smi = VTOSMI(dvp);
32134bff34e3Sthurlow 	struct smb_cred	scred;
32144bff34e3Sthurlow 	struct smbfattr	fattr;
32154bff34e3Sthurlow 	const char		*name = (const char *) nm;
32164bff34e3Sthurlow 	int		nmlen = strlen(name);
3217adee6784SGordon Ross 	int		error;
32184bff34e3Sthurlow 
3219a19609f8Sjv 	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
32204bff34e3Sthurlow 		return (EPERM);
32214bff34e3Sthurlow 
32224bff34e3Sthurlow 	if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
32234bff34e3Sthurlow 		return (EIO);
32244bff34e3Sthurlow 
32254bff34e3Sthurlow 	if ((nmlen == 1 && name[0] == '.') ||
32264bff34e3Sthurlow 	    (nmlen == 2 && name[0] == '.' && name[1] == '.'))
32274bff34e3Sthurlow 		return (EEXIST);
32284bff34e3Sthurlow 
322991d632c8Sgwr 	/* Only plain files are allowed in V_XATTRDIR. */
323091d632c8Sgwr 	if (dvp->v_flag & V_XATTRDIR)
323191d632c8Sgwr 		return (EINVAL);
323291d632c8Sgwr 
32334bff34e3Sthurlow 	if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
32344bff34e3Sthurlow 		return (EINTR);
3235613a2f6bSGordon Ross 	smb_credinit(&scred, cr);
32364bff34e3Sthurlow 
32374bff34e3Sthurlow 	/*
32384bff34e3Sthurlow 	 * Require write access in the containing directory.
32394bff34e3Sthurlow 	 */
32404bff34e3Sthurlow 	error = smbfs_access(dvp, VWRITE, 0, cr, ct);
32414bff34e3Sthurlow 	if (error)
32424bff34e3Sthurlow 		goto out;
32434bff34e3Sthurlow 
32444bff34e3Sthurlow 	error = smbfs_smb_mkdir(dnp, name, nmlen, &scred);
32454bff34e3Sthurlow 	if (error)
32464bff34e3Sthurlow 		goto out;
32474bff34e3Sthurlow 
32484bff34e3Sthurlow 	error = smbfs_smb_lookup(dnp, &name, &nmlen, &fattr, &scred);
32494bff34e3Sthurlow 	if (error)
32504bff34e3Sthurlow 		goto out;
32514bff34e3Sthurlow 
32524bff34e3Sthurlow 	smbfs_attr_touchdir(dnp);
32534bff34e3Sthurlow 
32544bff34e3Sthurlow 	error = smbfs_nget(dvp, name, nmlen, &fattr, &vp);
32554bff34e3Sthurlow 	if (error)
32564bff34e3Sthurlow 		goto out;
32574bff34e3Sthurlow 
32584bff34e3Sthurlow 	/* Success! */
32594bff34e3Sthurlow 	*vpp = vp;
32604bff34e3Sthurlow 	error = 0;
32614bff34e3Sthurlow out:
32624bff34e3Sthurlow 	smb_credrele(&scred);
32634bff34e3Sthurlow 	smbfs_rw_exit(&dnp->r_rwlock);
32644bff34e3Sthurlow 
32654bff34e3Sthurlow 	if (name != nm)
32664bff34e3Sthurlow 		smbfs_name_free(name, nmlen);
32674bff34e3Sthurlow 
32684bff34e3Sthurlow 	return (error);
32694bff34e3Sthurlow }
32704bff34e3Sthurlow 
32714bff34e3Sthurlow /*
32724bff34e3Sthurlow  * XXX
32734bff34e3Sthurlow  * This op should support the new FIGNORECASE flag for case-insensitive
32744bff34e3Sthurlow  * lookups, per PSARC 2007/244.
32754bff34e3Sthurlow  */
32764bff34e3Sthurlow /* ARGSUSED */
32774bff34e3Sthurlow static int
smbfs_rmdir(vnode_t * dvp,char * nm,vnode_t * cdir,cred_t * cr,caller_context_t * ct,int flags)32784bff34e3Sthurlow smbfs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr,
32794bff34e3Sthurlow 	caller_context_t *ct, int flags)
32804bff34e3Sthurlow {
3281adee6784SGordon Ross 	struct smb_cred	scred;
32824bff34e3Sthurlow 	vnode_t		*vp = NULL;
32834bff34e3Sthurlow 	int		vp_locked = 0;
32844bff34e3Sthurlow 	struct smbmntinfo *smi = VTOSMI(dvp);
32854bff34e3Sthurlow 	struct smbnode	*dnp = VTOSMB(dvp);
32864bff34e3Sthurlow 	struct smbnode	*np;
32874bff34e3Sthurlow 	int		error;
32884bff34e3Sthurlow 
3289a19609f8Sjv 	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
32904bff34e3Sthurlow 		return (EPERM);
32914bff34e3Sthurlow 
32924bff34e3Sthurlow 	if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
32934bff34e3Sthurlow 		return (EIO);
32944bff34e3Sthurlow 
32954bff34e3Sthurlow 	/*
3296adee6784SGordon Ross 	 * Verify access to the dirctory.
32974bff34e3Sthurlow 	 */
3298adee6784SGordon Ross 	error = smbfs_access(dvp, VWRITE|VEXEC, 0, cr, ct);
32994bff34e3Sthurlow 	if (error)
3300adee6784SGordon Ross 		return (error);
3301adee6784SGordon Ross 
3302adee6784SGordon Ross 	if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
3303adee6784SGordon Ross 		return (EINTR);
3304adee6784SGordon Ross 	smb_credinit(&scred, cr);
33054bff34e3Sthurlow 
33064bff34e3Sthurlow 	/*
33074bff34e3Sthurlow 	 * First lookup the entry to be removed.
33084bff34e3Sthurlow 	 */
33094bff34e3Sthurlow 	error = smbfslookup(dvp, nm, &vp, cr, 0, ct);
33104bff34e3Sthurlow 	if (error)
33114bff34e3Sthurlow 		goto out;
33124bff34e3Sthurlow 	np = VTOSMB(vp);
33134bff34e3Sthurlow 
33144bff34e3Sthurlow 	/*
33154bff34e3Sthurlow 	 * Disallow rmdir of "." or current dir, or the FS root.
33164bff34e3Sthurlow 	 * Also make sure it's a directory, not a mount point,
33174bff34e3Sthurlow 	 * and lock to keep mount/umount away until we're done.
33184bff34e3Sthurlow 	 */
33194bff34e3Sthurlow 	if ((vp == dvp) || (vp == cdir) || (vp->v_flag & VROOT)) {
33204bff34e3Sthurlow 		error = EINVAL;
33214bff34e3Sthurlow 		goto out;
33224bff34e3Sthurlow 	}
33234bff34e3Sthurlow 	if (vp->v_type != VDIR) {
33244bff34e3Sthurlow 		error = ENOTDIR;
33254bff34e3Sthurlow 		goto out;
33264bff34e3Sthurlow 	}
33274bff34e3Sthurlow 	if (vn_vfsrlock(vp)) {
33284bff34e3Sthurlow 		error = EBUSY;
33294bff34e3Sthurlow 		goto out;
33304bff34e3Sthurlow 	}
33314bff34e3Sthurlow 	vp_locked = 1;
33324bff34e3Sthurlow 	if (vn_mountedvfs(vp) != NULL) {
33334bff34e3Sthurlow 		error = EBUSY;
33344bff34e3Sthurlow 		goto out;
33354bff34e3Sthurlow 	}
33364bff34e3Sthurlow 
333791d632c8Sgwr 	/*
3338adee6784SGordon Ross 	 * Do the real rmdir work
333991d632c8Sgwr 	 */
3340adee6784SGordon Ross 	error = smbfsremove(dvp, vp, &scred, flags);
33414bff34e3Sthurlow 	if (error)
33424bff34e3Sthurlow 		goto out;
33434bff34e3Sthurlow 
3344adee6784SGordon Ross #ifdef	SMBFS_VNEVENT
3345adee6784SGordon Ross 	vnevent_rmdir(vp, dvp, nm, ct);
3346adee6784SGordon Ross #endif
3347adee6784SGordon Ross 
33484bff34e3Sthurlow 	mutex_enter(&np->r_statelock);
33494bff34e3Sthurlow 	dnp->n_flag |= NMODIFIED;
33504bff34e3Sthurlow 	mutex_exit(&np->r_statelock);
33514bff34e3Sthurlow 	smbfs_attr_touchdir(dnp);
335202d09e03SGordon Ross 	smbfs_rmhash(np);
33534bff34e3Sthurlow 
33544bff34e3Sthurlow out:
33554bff34e3Sthurlow 	if (vp) {
33564bff34e3Sthurlow 		if (vp_locked)
33574bff34e3Sthurlow 			vn_vfsunlock(vp);
33584bff34e3Sthurlow 		VN_RELE(vp);
33594bff34e3Sthurlow 	}
33604bff34e3Sthurlow 	smb_credrele(&scred);
33614bff34e3Sthurlow 	smbfs_rw_exit(&dnp->r_rwlock);
33624bff34e3Sthurlow 
33634bff34e3Sthurlow 	return (error);
33644bff34e3Sthurlow }
33654bff34e3Sthurlow 
33664bff34e3Sthurlow 
33675f4fc069Sjilinxpd /* ARGSUSED */
33685f4fc069Sjilinxpd static int
smbfs_symlink(vnode_t * dvp,char * lnm,struct vattr * tva,char * tnm,cred_t * cr,caller_context_t * ct,int flags)33695f4fc069Sjilinxpd smbfs_symlink(vnode_t *dvp, char *lnm, struct vattr *tva, char *tnm, cred_t *cr,
33705f4fc069Sjilinxpd 	caller_context_t *ct, int flags)
33715f4fc069Sjilinxpd {
33725f4fc069Sjilinxpd 	/* Not yet... */
33735f4fc069Sjilinxpd 	return (ENOSYS);
33745f4fc069Sjilinxpd }
33755f4fc069Sjilinxpd 
33765f4fc069Sjilinxpd 
33774bff34e3Sthurlow /* ARGSUSED */
33784bff34e3Sthurlow static int
smbfs_readdir(vnode_t * vp,struct uio * uiop,cred_t * cr,int * eofp,caller_context_t * ct,int flags)33794bff34e3Sthurlow smbfs_readdir(vnode_t *vp, struct uio *uiop, cred_t *cr, int *eofp,
33804bff34e3Sthurlow 	caller_context_t *ct, int flags)
33814bff34e3Sthurlow {
33824bff34e3Sthurlow 	struct smbnode	*np = VTOSMB(vp);
33834bff34e3Sthurlow 	int		error = 0;
33844bff34e3Sthurlow 	smbmntinfo_t	*smi;
33854bff34e3Sthurlow 
33864bff34e3Sthurlow 	smi = VTOSMI(vp);
33874bff34e3Sthurlow 
3388a19609f8Sjv 	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
33894bff34e3Sthurlow 		return (EIO);
33904bff34e3Sthurlow 
33914bff34e3Sthurlow 	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
33924bff34e3Sthurlow 		return (EIO);
33934bff34e3Sthurlow 
33944bff34e3Sthurlow 	/*
33954bff34e3Sthurlow 	 * Require read access in the directory.
33964bff34e3Sthurlow 	 */
33974bff34e3Sthurlow 	error = smbfs_access(vp, VREAD, 0, cr, ct);
33984bff34e3Sthurlow 	if (error)
33994bff34e3Sthurlow 		return (error);
34004bff34e3Sthurlow 
34014bff34e3Sthurlow 	ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_READER));
34024bff34e3Sthurlow 
34034bff34e3Sthurlow 	/*
34045f4fc069Sjilinxpd 	 * Todo readdir cache here
34054bff34e3Sthurlow 	 *
34064bff34e3Sthurlow 	 * I am serializing the entire readdir opreation
34074bff34e3Sthurlow 	 * now since we have not yet implemented readdir
34084bff34e3Sthurlow 	 * cache. This fix needs to be revisited once
34094bff34e3Sthurlow 	 * we implement readdir cache.
34104bff34e3Sthurlow 	 */
34114bff34e3Sthurlow 	if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, SMBINTR(vp)))
34124bff34e3Sthurlow 		return (EINTR);
34134bff34e3Sthurlow 
34144bff34e3Sthurlow 	error = smbfs_readvdir(vp, uiop, cr, eofp, ct);
34154bff34e3Sthurlow 
34164bff34e3Sthurlow 	smbfs_rw_exit(&np->r_lkserlock);
34174bff34e3Sthurlow 
34184bff34e3Sthurlow 	return (error);
34194bff34e3Sthurlow }
34204bff34e3Sthurlow 
34214bff34e3Sthurlow /* ARGSUSED */
34224bff34e3Sthurlow static int
smbfs_readvdir(vnode_t * vp,uio_t * uio,cred_t * cr,int * eofp,caller_context_t * ct)34234bff34e3Sthurlow smbfs_readvdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp,
34244bff34e3Sthurlow 	caller_context_t *ct)
34254bff34e3Sthurlow {
34265ecede33SGordon Ross 	/*
34275ecede33SGordon Ross 	 * Note: "limit" tells the SMB-level FindFirst/FindNext
34285ecede33SGordon Ross 	 * functions how many directory entries to request in
34295ecede33SGordon Ross 	 * each OtW call.  It needs to be large enough so that
34305ecede33SGordon Ross 	 * we don't make lots of tiny OtW requests, but there's
34315ecede33SGordon Ross 	 * no point making it larger than the maximum number of
34325ecede33SGordon Ross 	 * OtW entries that would fit in a maximum sized trans2
34335ecede33SGordon Ross 	 * response (64k / 48).  Beyond that, it's just tuning.
34345ecede33SGordon Ross 	 * WinNT used 512, Win2k used 1366.  We use 1000.
34355ecede33SGordon Ross 	 */
34365ecede33SGordon Ross 	static const int limit = 1000;
34375ecede33SGordon Ross 	/* Largest possible dirent size. */
34385ecede33SGordon Ross 	static const size_t dbufsiz = DIRENT64_RECLEN(SMB_MAXFNAMELEN);
34394bff34e3Sthurlow 	struct smb_cred scred;
34404bff34e3Sthurlow 	vnode_t		*newvp;
34414bff34e3Sthurlow 	struct smbnode	*np = VTOSMB(vp);
34424bff34e3Sthurlow 	struct smbfs_fctx *ctx;
34435ecede33SGordon Ross 	struct dirent64 *dp;
34445ecede33SGordon Ross 	ssize_t		save_resid;
34455ecede33SGordon Ross 	offset_t	save_offset; /* 64 bits */
34465ecede33SGordon Ross 	int		offset; /* yes, 32 bits */
34475ecede33SGordon Ross 	int		nmlen, error;
34485ecede33SGordon Ross 	ushort_t	reclen;
34494bff34e3Sthurlow 
3450a19609f8Sjv 	ASSERT(curproc->p_zone == VTOSMI(vp)->smi_zone_ref.zref_zone);
34514bff34e3Sthurlow 
34524bff34e3Sthurlow 	/* Make sure we serialize for n_dirseq use. */
34534bff34e3Sthurlow 	ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_WRITER));
34544bff34e3Sthurlow 
34555ecede33SGordon Ross 	/*
34565ecede33SGordon Ross 	 * Make sure smbfs_open filled in n_dirseq
34575ecede33SGordon Ross 	 */
34585ecede33SGordon Ross 	if (np->n_dirseq == NULL)
34595ecede33SGordon Ross 		return (EBADF);
34605ecede33SGordon Ross 
34615ecede33SGordon Ross 	/* Check for overflow of (32-bit) directory offset. */
34625ecede33SGordon Ross 	if (uio->uio_loffset < 0 || uio->uio_loffset > INT32_MAX ||
34635ecede33SGordon Ross 	    (uio->uio_loffset + uio->uio_resid) > INT32_MAX)
34645ecede33SGordon Ross 		return (EINVAL);
34655ecede33SGordon Ross 
34665ecede33SGordon Ross 	/* Require space for at least one dirent. */
34675ecede33SGordon Ross 	if (uio->uio_resid < dbufsiz)
34684bff34e3Sthurlow 		return (EINVAL);
34694bff34e3Sthurlow 
34704bff34e3Sthurlow 	SMBVDEBUG("dirname='%s'\n", np->n_rpath);
3471613a2f6bSGordon Ross 	smb_credinit(&scred, cr);
34724bff34e3Sthurlow 	dp = kmem_alloc(dbufsiz, KM_SLEEP);
34734bff34e3Sthurlow 
34745ecede33SGordon Ross 	save_resid = uio->uio_resid;
34755ecede33SGordon Ross 	save_offset = uio->uio_loffset;
34765ecede33SGordon Ross 	offset = uio->uio_offset;
34775ecede33SGordon Ross 	SMBVDEBUG("in: offset=%d, resid=%d\n",
34785ecede33SGordon Ross 	    (int)uio->uio_offset, (int)uio->uio_resid);
34795ecede33SGordon Ross 	error = 0;
34804bff34e3Sthurlow 
34814bff34e3Sthurlow 	/*
34824bff34e3Sthurlow 	 * Generate the "." and ".." entries here so we can
34834bff34e3Sthurlow 	 * (1) make sure they appear (but only once), and
34844bff34e3Sthurlow 	 * (2) deal with getting their I numbers which the
34854bff34e3Sthurlow 	 * findnext below does only for normal names.
34864bff34e3Sthurlow 	 */
34875ecede33SGordon Ross 	while (offset < FIRST_DIROFS) {
34885ecede33SGordon Ross 		/*
34895ecede33SGordon Ross 		 * Tricky bit filling in the first two:
34905ecede33SGordon Ross 		 * offset 0 is ".", offset 1 is ".."
34915ecede33SGordon Ross 		 * so strlen of these is offset+1.
34925ecede33SGordon Ross 		 */
34934bff34e3Sthurlow 		reclen = DIRENT64_RECLEN(offset + 1);
34945ecede33SGordon Ross 		if (uio->uio_resid < reclen)
34955ecede33SGordon Ross 			goto out;
34964bff34e3Sthurlow 		bzero(dp, reclen);
34974bff34e3Sthurlow 		dp->d_reclen = reclen;
34984bff34e3Sthurlow 		dp->d_name[0] = '.';
34994bff34e3Sthurlow 		dp->d_name[1] = '.';
35004bff34e3Sthurlow 		dp->d_name[offset + 1] = '\0';
35014bff34e3Sthurlow 		/*
35024bff34e3Sthurlow 		 * Want the real I-numbers for the "." and ".."
35034bff34e3Sthurlow 		 * entries.  For these two names, we know that
35045ecede33SGordon Ross 		 * smbfslookup can get the nodes efficiently.
35054bff34e3Sthurlow 		 */
35064bff34e3Sthurlow 		error = smbfslookup(vp, dp->d_name, &newvp, cr, 1, ct);
35074bff34e3Sthurlow 		if (error) {
35084bff34e3Sthurlow 			dp->d_ino = np->n_ino + offset; /* fiction */
35094bff34e3Sthurlow 		} else {
35104bff34e3Sthurlow 			dp->d_ino = VTOSMB(newvp)->n_ino;
35114bff34e3Sthurlow 			VN_RELE(newvp);
35124bff34e3Sthurlow 		}
35135ecede33SGordon Ross 		/*
35145ecede33SGordon Ross 		 * Note: d_off is the offset that a user-level program
35155ecede33SGordon Ross 		 * should seek to for reading the NEXT directory entry.
35165ecede33SGordon Ross 		 * See libc: readdir, telldir, seekdir
35175ecede33SGordon Ross 		 */
35185ecede33SGordon Ross 		dp->d_off = offset + 1;
35195ecede33SGordon Ross 		error = uiomove(dp, reclen, UIO_READ, uio);
35204bff34e3Sthurlow 		if (error)
35214bff34e3Sthurlow 			goto out;
35225ecede33SGordon Ross 		/*
35235ecede33SGordon Ross 		 * Note: uiomove updates uio->uio_offset,
35245ecede33SGordon Ross 		 * but we want it to be our "cookie" value,
35255ecede33SGordon Ross 		 * which just counts dirents ignoring size.
35265ecede33SGordon Ross 		 */
35274bff34e3Sthurlow 		uio->uio_offset = ++offset;
35284bff34e3Sthurlow 	}
35295ecede33SGordon Ross 
35305ecede33SGordon Ross 	/*
35315ecede33SGordon Ross 	 * If there was a backward seek, we have to reopen.
35325ecede33SGordon Ross 	 */
35335ecede33SGordon Ross 	if (offset < np->n_dirofs) {
35345ecede33SGordon Ross 		SMBVDEBUG("Reopening search %d:%d\n",
35355ecede33SGordon Ross 		    offset, np->n_dirofs);
35364bff34e3Sthurlow 		error = smbfs_smb_findopen(np, "*", 1,
35374bff34e3Sthurlow 		    SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR,
35384bff34e3Sthurlow 		    &scred, &ctx);
35394bff34e3Sthurlow 		if (error) {
35404bff34e3Sthurlow 			SMBVDEBUG("can not open search, error = %d", error);
35414bff34e3Sthurlow 			goto out;
35424bff34e3Sthurlow 		}
35435ecede33SGordon Ross 		/* free the old one */
35445ecede33SGordon Ross 		(void) smbfs_smb_findclose(np->n_dirseq, &scred);
35455ecede33SGordon Ross 		/* save the new one */
35464bff34e3Sthurlow 		np->n_dirseq = ctx;
35475ecede33SGordon Ross 		np->n_dirofs = FIRST_DIROFS;
35485ecede33SGordon Ross 	} else {
35494bff34e3Sthurlow 		ctx = np->n_dirseq;
35505ecede33SGordon Ross 	}
35515ecede33SGordon Ross 
35525ecede33SGordon Ross 	/*
35535ecede33SGordon Ross 	 * Skip entries before the requested offset.
35545ecede33SGordon Ross 	 */
35554bff34e3Sthurlow 	while (np->n_dirofs < offset) {
35565ecede33SGordon Ross 		error = smbfs_smb_findnext(ctx, limit, &scred);
35575ecede33SGordon Ross 		if (error != 0)
35584bff34e3Sthurlow 			goto out;
35595ecede33SGordon Ross 		np->n_dirofs++;
35604bff34e3Sthurlow 	}
35615ecede33SGordon Ross 
35625ecede33SGordon Ross 	/*
35635ecede33SGordon Ross 	 * While there's room in the caller's buffer:
35645ecede33SGordon Ross 	 *	get a directory entry from SMB,
35655ecede33SGordon Ross 	 *	convert to a dirent, copyout.
35665ecede33SGordon Ross 	 * We stop when there is no longer room for a
35675ecede33SGordon Ross 	 * maximum sized dirent because we must decide
35685ecede33SGordon Ross 	 * before we know anything about the next entry.
35695ecede33SGordon Ross 	 */
35705ecede33SGordon Ross 	while (uio->uio_resid >= dbufsiz) {
35714bff34e3Sthurlow 		error = smbfs_smb_findnext(ctx, limit, &scred);
35725ecede33SGordon Ross 		if (error != 0)
35735ecede33SGordon Ross 			goto out;
35744bff34e3Sthurlow 		np->n_dirofs++;
35755ecede33SGordon Ross 
35764bff34e3Sthurlow 		/* Sanity check the name length. */
35774bff34e3Sthurlow 		nmlen = ctx->f_nmlen;
3578613a2f6bSGordon Ross 		if (nmlen > SMB_MAXFNAMELEN) {
3579613a2f6bSGordon Ross 			nmlen = SMB_MAXFNAMELEN;
35804bff34e3Sthurlow 			SMBVDEBUG("Truncating name: %s\n", ctx->f_name);
35814bff34e3Sthurlow 		}
35824bff34e3Sthurlow 		if (smbfs_fastlookup) {
358302d09e03SGordon Ross 			/* See comment at smbfs_fastlookup above. */
35845ecede33SGordon Ross 			if (smbfs_nget(vp, ctx->f_name, nmlen,
35855ecede33SGordon Ross 			    &ctx->f_attr, &newvp) == 0)
35864bff34e3Sthurlow 				VN_RELE(newvp);
35874bff34e3Sthurlow 		}
35885ecede33SGordon Ross 
35895ecede33SGordon Ross 		reclen = DIRENT64_RECLEN(nmlen);
35905ecede33SGordon Ross 		bzero(dp, reclen);
35915ecede33SGordon Ross 		dp->d_reclen = reclen;
35925ecede33SGordon Ross 		bcopy(ctx->f_name, dp->d_name, nmlen);
35935ecede33SGordon Ross 		dp->d_name[nmlen] = '\0';
359402d09e03SGordon Ross 		dp->d_ino = ctx->f_inum;
35955ecede33SGordon Ross 		dp->d_off = offset + 1;	/* See d_off comment above */
35965ecede33SGordon Ross 		error = uiomove(dp, reclen, UIO_READ, uio);
35974bff34e3Sthurlow 		if (error)
35985ecede33SGordon Ross 			goto out;
35995ecede33SGordon Ross 		/* See comment re. uio_offset above. */
36004bff34e3Sthurlow 		uio->uio_offset = ++offset;
36014bff34e3Sthurlow 	}
36025ecede33SGordon Ross 
36034bff34e3Sthurlow out:
36045ecede33SGordon Ross 	/*
36055ecede33SGordon Ross 	 * When we come to the end of a directory, the
36065ecede33SGordon Ross 	 * SMB-level functions return ENOENT, but the
36075ecede33SGordon Ross 	 * caller is not expecting an error return.
36085ecede33SGordon Ross 	 *
36095ecede33SGordon Ross 	 * Also note that we must delay the call to
36105ecede33SGordon Ross 	 * smbfs_smb_findclose(np->n_dirseq, ...)
36115ecede33SGordon Ross 	 * until smbfs_close so that all reads at the
36125ecede33SGordon Ross 	 * end of the directory will return no data.
36135ecede33SGordon Ross 	 */
36145ecede33SGordon Ross 	if (error == ENOENT) {
36155ecede33SGordon Ross 		error = 0;
36165ecede33SGordon Ross 		if (eofp)
36175ecede33SGordon Ross 			*eofp = 1;
36185ecede33SGordon Ross 	}
36195ecede33SGordon Ross 	/*
36205ecede33SGordon Ross 	 * If we encountered an error (i.e. "access denied")
36215ecede33SGordon Ross 	 * from the FindFirst call, we will have copied out
36225ecede33SGordon Ross 	 * the "." and ".." entries leaving offset == 2.
36235ecede33SGordon Ross 	 * In that case, restore the original offset/resid
36245ecede33SGordon Ross 	 * so the caller gets no data with the error.
36255ecede33SGordon Ross 	 */
36265ecede33SGordon Ross 	if (error != 0 && offset == FIRST_DIROFS) {
36275ecede33SGordon Ross 		uio->uio_loffset = save_offset;
36285ecede33SGordon Ross 		uio->uio_resid = save_resid;
36295ecede33SGordon Ross 	}
36305ecede33SGordon Ross 	SMBVDEBUG("out: offset=%d, resid=%d\n",
36315ecede33SGordon Ross 	    (int)uio->uio_offset, (int)uio->uio_resid);
36325ecede33SGordon Ross 
36334bff34e3Sthurlow 	kmem_free(dp, dbufsiz);
36344bff34e3Sthurlow 	smb_credrele(&scred);
36354bff34e3Sthurlow 	return (error);
36364bff34e3Sthurlow }
36374bff34e3Sthurlow 
36385f4fc069Sjilinxpd /*
36395f4fc069Sjilinxpd  * Here NFS has: nfs3_bio
36405f4fc069Sjilinxpd  * See smbfs_bio above.
36415f4fc069Sjilinxpd  */
36425f4fc069Sjilinxpd 
36435f4fc069Sjilinxpd /* ARGSUSED */
36445f4fc069Sjilinxpd static int
smbfs_fid(vnode_t * vp,fid_t * fidp,caller_context_t * ct)36455f4fc069Sjilinxpd smbfs_fid(vnode_t *vp, fid_t *fidp, caller_context_t *ct)
36465f4fc069Sjilinxpd {
36475f4fc069Sjilinxpd 	return (ENOSYS);
36485f4fc069Sjilinxpd }
36495f4fc069Sjilinxpd 
36504bff34e3Sthurlow 
36514bff34e3Sthurlow /*
36524bff34e3Sthurlow  * The pair of functions VOP_RWLOCK, VOP_RWUNLOCK
36534bff34e3Sthurlow  * are optional functions that are called by:
36544bff34e3Sthurlow  *    getdents, before/after VOP_READDIR
36554bff34e3Sthurlow  *    pread, before/after ... VOP_READ
36564bff34e3Sthurlow  *    pwrite, before/after ... VOP_WRITE
36574bff34e3Sthurlow  *    (other places)
36584bff34e3Sthurlow  *
36594bff34e3Sthurlow  * Careful here: None of the above check for any
36604bff34e3Sthurlow  * error returns from VOP_RWLOCK / VOP_RWUNLOCK!
36614bff34e3Sthurlow  * In fact, the return value from _rwlock is NOT
36624bff34e3Sthurlow  * an error code, but V_WRITELOCK_TRUE / _FALSE.
36634bff34e3Sthurlow  *
36644bff34e3Sthurlow  * Therefore, it's up to _this_ code to make sure
36654bff34e3Sthurlow  * the lock state remains balanced, which means
36664bff34e3Sthurlow  * we can't "bail out" on interrupts, etc.
36674bff34e3Sthurlow  */
36684bff34e3Sthurlow 
36694bff34e3Sthurlow /* ARGSUSED2 */
36704bff34e3Sthurlow static int
smbfs_rwlock(vnode_t * vp,int write_lock,caller_context_t * ctp)36714bff34e3Sthurlow smbfs_rwlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
36724bff34e3Sthurlow {
36734bff34e3Sthurlow 	smbnode_t	*np = VTOSMB(vp);
36744bff34e3Sthurlow 
36754bff34e3Sthurlow 	if (!write_lock) {
36764bff34e3Sthurlow 		(void) smbfs_rw_enter_sig(&np->r_rwlock, RW_READER, FALSE);
36774bff34e3Sthurlow 		return (V_WRITELOCK_FALSE);
36784bff34e3Sthurlow 	}
36794bff34e3Sthurlow 
36804bff34e3Sthurlow 
36814bff34e3Sthurlow 	(void) smbfs_rw_enter_sig(&np->r_rwlock, RW_WRITER, FALSE);
36824bff34e3Sthurlow 	return (V_WRITELOCK_TRUE);
36834bff34e3Sthurlow }
36844bff34e3Sthurlow 
36854bff34e3Sthurlow /* ARGSUSED */
36864bff34e3Sthurlow static void
smbfs_rwunlock(vnode_t * vp,int write_lock,caller_context_t * ctp)36874bff34e3Sthurlow smbfs_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
36884bff34e3Sthurlow {
36894bff34e3Sthurlow 	smbnode_t	*np = VTOSMB(vp);
36904bff34e3Sthurlow 
36914bff34e3Sthurlow 	smbfs_rw_exit(&np->r_rwlock);
36924bff34e3Sthurlow }
36934bff34e3Sthurlow 
36944bff34e3Sthurlow 
36954bff34e3Sthurlow /* ARGSUSED */
36964bff34e3Sthurlow static int
smbfs_seek(vnode_t * vp,offset_t ooff,offset_t * noffp,caller_context_t * ct)36974bff34e3Sthurlow smbfs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
36984bff34e3Sthurlow {
36994bff34e3Sthurlow 	smbmntinfo_t	*smi;
37004bff34e3Sthurlow 
37014bff34e3Sthurlow 	smi = VTOSMI(vp);
37024bff34e3Sthurlow 
3703a19609f8Sjv 	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
37044bff34e3Sthurlow 		return (EPERM);
37054bff34e3Sthurlow 
37064bff34e3Sthurlow 	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
37074bff34e3Sthurlow 		return (EIO);
37084bff34e3Sthurlow 
37094bff34e3Sthurlow 	/*
37104bff34e3Sthurlow 	 * Because we stuff the readdir cookie into the offset field
37114bff34e3Sthurlow 	 * someone may attempt to do an lseek with the cookie which
37124bff34e3Sthurlow 	 * we want to succeed.
37134bff34e3Sthurlow 	 */
37144bff34e3Sthurlow 	if (vp->v_type == VDIR)
37154bff34e3Sthurlow 		return (0);
37164bff34e3Sthurlow 
37174bff34e3Sthurlow 	/* Like NFS3, just check for 63-bit overflow. */
37184bff34e3Sthurlow 	if (*noffp < 0)
37194bff34e3Sthurlow 		return (EINVAL);
37204bff34e3Sthurlow 
37214bff34e3Sthurlow 	return (0);
37224bff34e3Sthurlow }
37234bff34e3Sthurlow 
37245f4fc069Sjilinxpd /* mmap support ******************************************************** */
37255f4fc069Sjilinxpd 
37268329232eSGordon Ross #ifdef	_KERNEL
37278329232eSGordon Ross 
37285f4fc069Sjilinxpd #ifdef DEBUG
37295f4fc069Sjilinxpd static int smbfs_lostpage = 0;	/* number of times we lost original page */
37305f4fc069Sjilinxpd #endif
37315f4fc069Sjilinxpd 
37325f4fc069Sjilinxpd /*
37335f4fc069Sjilinxpd  * Return all the pages from [off..off+len) in file
37345f4fc069Sjilinxpd  * Like nfs3_getpage
37355f4fc069Sjilinxpd  */
37365f4fc069Sjilinxpd /* ARGSUSED */
37375f4fc069Sjilinxpd static int
smbfs_getpage(vnode_t * vp,offset_t off,size_t len,uint_t * protp,page_t * pl[],size_t plsz,struct seg * seg,caddr_t addr,enum seg_rw rw,cred_t * cr,caller_context_t * ct)37385f4fc069Sjilinxpd smbfs_getpage(vnode_t *vp, offset_t off, size_t len, uint_t *protp,
37395f4fc069Sjilinxpd 	page_t *pl[], size_t plsz, struct seg *seg, caddr_t addr,
37405f4fc069Sjilinxpd 	enum seg_rw rw, cred_t *cr, caller_context_t *ct)
37415f4fc069Sjilinxpd {
37425f4fc069Sjilinxpd 	smbnode_t	*np;
37435f4fc069Sjilinxpd 	smbmntinfo_t	*smi;
37445f4fc069Sjilinxpd 	int		error;
37455f4fc069Sjilinxpd 
37465f4fc069Sjilinxpd 	np = VTOSMB(vp);
37475f4fc069Sjilinxpd 	smi = VTOSMI(vp);
37485f4fc069Sjilinxpd 
37495f4fc069Sjilinxpd 	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
37505f4fc069Sjilinxpd 		return (EIO);
37515f4fc069Sjilinxpd 
37525f4fc069Sjilinxpd 	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
37535f4fc069Sjilinxpd 		return (EIO);
37545f4fc069Sjilinxpd 
37555f4fc069Sjilinxpd 	if (vp->v_flag & VNOMAP)
37565f4fc069Sjilinxpd 		return (ENOSYS);
37575f4fc069Sjilinxpd 
37585f4fc069Sjilinxpd 	if (protp != NULL)
37595f4fc069Sjilinxpd 		*protp = PROT_ALL;
37605f4fc069Sjilinxpd 
37615f4fc069Sjilinxpd 	/*
37625f4fc069Sjilinxpd 	 * Now valididate that the caches are up to date.
37635f4fc069Sjilinxpd 	 */
37645f4fc069Sjilinxpd 	error = smbfs_validate_caches(vp, cr);
37655f4fc069Sjilinxpd 	if (error)
37665f4fc069Sjilinxpd 		return (error);
37675f4fc069Sjilinxpd 
37685f4fc069Sjilinxpd retry:
37695f4fc069Sjilinxpd 	mutex_enter(&np->r_statelock);
37705f4fc069Sjilinxpd 
37715f4fc069Sjilinxpd 	/*
37725f4fc069Sjilinxpd 	 * Don't create dirty pages faster than they
37735f4fc069Sjilinxpd 	 * can be cleaned ... (etc. see nfs)
37745f4fc069Sjilinxpd 	 *
37755f4fc069Sjilinxpd 	 * Here NFS also tests:
37765f4fc069Sjilinxpd 	 *  (mi->mi_max_threads != 0 &&
37775f4fc069Sjilinxpd 	 *  rp->r_awcount > 2 * mi->mi_max_threads)
37785f4fc069Sjilinxpd 	 */
37795f4fc069Sjilinxpd 	if (rw == S_CREATE) {
37805f4fc069Sjilinxpd 		while (np->r_gcount > 0)
37815f4fc069Sjilinxpd 			cv_wait(&np->r_cv, &np->r_statelock);
37825f4fc069Sjilinxpd 	}
37835f4fc069Sjilinxpd 
37845f4fc069Sjilinxpd 	/*
37855f4fc069Sjilinxpd 	 * If we are getting called as a side effect of a write
37865f4fc069Sjilinxpd 	 * operation the local file size might not be extended yet.
37875f4fc069Sjilinxpd 	 * In this case we want to be able to return pages of zeroes.
37885f4fc069Sjilinxpd 	 */
37895f4fc069Sjilinxpd 	if (off + len > np->r_size + PAGEOFFSET && seg != segkmap) {
37905f4fc069Sjilinxpd 		mutex_exit(&np->r_statelock);
37915f4fc069Sjilinxpd 		return (EFAULT);		/* beyond EOF */
37925f4fc069Sjilinxpd 	}
37935f4fc069Sjilinxpd 
37945f4fc069Sjilinxpd 	mutex_exit(&np->r_statelock);
37955f4fc069Sjilinxpd 
37965f4fc069Sjilinxpd 	error = pvn_getpages(smbfs_getapage, vp, off, len, protp,
37975f4fc069Sjilinxpd 	    pl, plsz, seg, addr, rw, cr);
37985f4fc069Sjilinxpd 
37995f4fc069Sjilinxpd 	switch (error) {
38005f4fc069Sjilinxpd 	case SMBFS_EOF:
38015f4fc069Sjilinxpd 		smbfs_purge_caches(vp, cr);
38025f4fc069Sjilinxpd 		goto retry;
38035f4fc069Sjilinxpd 	case ESTALE:
38045f4fc069Sjilinxpd 		/*
38055f4fc069Sjilinxpd 		 * Here NFS has: PURGE_STALE_FH(error, vp, cr);
38065f4fc069Sjilinxpd 		 * In-line here as we only use it once.
38075f4fc069Sjilinxpd 		 */
38085f4fc069Sjilinxpd 		mutex_enter(&np->r_statelock);
38095f4fc069Sjilinxpd 		np->r_flags |= RSTALE;
38105f4fc069Sjilinxpd 		if (!np->r_error)
38115f4fc069Sjilinxpd 			np->r_error = (error);
38125f4fc069Sjilinxpd 		mutex_exit(&np->r_statelock);
38135f4fc069Sjilinxpd 		if (vn_has_cached_data(vp))
38145f4fc069Sjilinxpd 			smbfs_invalidate_pages(vp, (u_offset_t)0, cr);
38155f4fc069Sjilinxpd 		smbfs_purge_caches(vp, cr);
38165f4fc069Sjilinxpd 		break;
38175f4fc069Sjilinxpd 	default:
38185f4fc069Sjilinxpd 		break;
38195f4fc069Sjilinxpd 	}
38205f4fc069Sjilinxpd 
38215f4fc069Sjilinxpd 	return (error);
38225f4fc069Sjilinxpd }
38235f4fc069Sjilinxpd 
38245f4fc069Sjilinxpd /*
38255f4fc069Sjilinxpd  * Called from pvn_getpages to get a particular page.
38265f4fc069Sjilinxpd  * Like nfs3_getapage
38275f4fc069Sjilinxpd  */
38285f4fc069Sjilinxpd /* ARGSUSED */
38295f4fc069Sjilinxpd static int
smbfs_getapage(vnode_t * vp,u_offset_t off,size_t len,uint_t * protp,page_t * pl[],size_t plsz,struct seg * seg,caddr_t addr,enum seg_rw rw,cred_t * cr)38305f4fc069Sjilinxpd smbfs_getapage(vnode_t *vp, u_offset_t off, size_t len, uint_t *protp,
38315f4fc069Sjilinxpd 	page_t *pl[], size_t plsz, struct seg *seg, caddr_t addr,
38325f4fc069Sjilinxpd 	enum seg_rw rw, cred_t *cr)
38335f4fc069Sjilinxpd {
38345f4fc069Sjilinxpd 	smbnode_t	*np;
38355f4fc069Sjilinxpd 	smbmntinfo_t   *smi;
38365f4fc069Sjilinxpd 
38375f4fc069Sjilinxpd 	uint_t		bsize;
38385f4fc069Sjilinxpd 	struct buf	*bp;
38395f4fc069Sjilinxpd 	page_t		*pp;
38405f4fc069Sjilinxpd 	u_offset_t	lbn;
38415f4fc069Sjilinxpd 	u_offset_t	io_off;
38425f4fc069Sjilinxpd 	u_offset_t	blkoff;
38435f4fc069Sjilinxpd 	size_t		io_len;
38445f4fc069Sjilinxpd 	uint_t blksize;
38455f4fc069Sjilinxpd 	int error;
38465f4fc069Sjilinxpd 	/* int readahead; */
38475f4fc069Sjilinxpd 	int readahead_issued = 0;
38485f4fc069Sjilinxpd 	/* int ra_window; * readahead window */
38495f4fc069Sjilinxpd 	page_t *pagefound;
38505f4fc069Sjilinxpd 
38515f4fc069Sjilinxpd 	np = VTOSMB(vp);
38525f4fc069Sjilinxpd 	smi = VTOSMI(vp);
38535f4fc069Sjilinxpd 
38545f4fc069Sjilinxpd 	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
38555f4fc069Sjilinxpd 		return (EIO);
38565f4fc069Sjilinxpd 
38575f4fc069Sjilinxpd 	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
38585f4fc069Sjilinxpd 		return (EIO);
38595f4fc069Sjilinxpd 
38605f4fc069Sjilinxpd 	bsize = MAX(vp->v_vfsp->vfs_bsize, PAGESIZE);
38615f4fc069Sjilinxpd 
38625f4fc069Sjilinxpd reread:
38635f4fc069Sjilinxpd 	bp = NULL;
38645f4fc069Sjilinxpd 	pp = NULL;
38655f4fc069Sjilinxpd 	pagefound = NULL;
38665f4fc069Sjilinxpd 
38675f4fc069Sjilinxpd 	if (pl != NULL)
38685f4fc069Sjilinxpd 		pl[0] = NULL;
38695f4fc069Sjilinxpd 
38705f4fc069Sjilinxpd 	error = 0;
38715f4fc069Sjilinxpd 	lbn = off / bsize;
38725f4fc069Sjilinxpd 	blkoff = lbn * bsize;
38735f4fc069Sjilinxpd 
38745f4fc069Sjilinxpd 	/*
38755f4fc069Sjilinxpd 	 * NFS queues up readahead work here.
38765f4fc069Sjilinxpd 	 */
38775f4fc069Sjilinxpd 
38785f4fc069Sjilinxpd again:
38795f4fc069Sjilinxpd 	if ((pagefound = page_exists(vp, off)) == NULL) {
38805f4fc069Sjilinxpd 		if (pl == NULL) {
38815f4fc069Sjilinxpd 			(void) 0; /* Todo: smbfs_async_readahead(); */
38825f4fc069Sjilinxpd 		} else if (rw == S_CREATE) {
38835f4fc069Sjilinxpd 			/*
38845f4fc069Sjilinxpd 			 * Block for this page is not allocated, or the offset
38855f4fc069Sjilinxpd 			 * is beyond the current allocation size, or we're
38865f4fc069Sjilinxpd 			 * allocating a swap slot and the page was not found,
38875f4fc069Sjilinxpd 			 * so allocate it and return a zero page.
38885f4fc069Sjilinxpd 			 */
38895f4fc069Sjilinxpd 			if ((pp = page_create_va(vp, off,
38905f4fc069Sjilinxpd 			    PAGESIZE, PG_WAIT, seg, addr)) == NULL)
38915f4fc069Sjilinxpd 				cmn_err(CE_PANIC, "smbfs_getapage: page_create");
38925f4fc069Sjilinxpd 			io_len = PAGESIZE;
38935f4fc069Sjilinxpd 			mutex_enter(&np->r_statelock);
38945f4fc069Sjilinxpd 			np->r_nextr = off + PAGESIZE;
38955f4fc069Sjilinxpd 			mutex_exit(&np->r_statelock);
38965f4fc069Sjilinxpd 		} else {
38975f4fc069Sjilinxpd 			/*
38985f4fc069Sjilinxpd 			 * Need to go to server to get a BLOCK, exception to
38995f4fc069Sjilinxpd 			 * that being while reading at offset = 0 or doing
39005f4fc069Sjilinxpd 			 * random i/o, in that case read only a PAGE.
39015f4fc069Sjilinxpd 			 */
39025f4fc069Sjilinxpd 			mutex_enter(&np->r_statelock);
39035f4fc069Sjilinxpd 			if (blkoff < np->r_size &&
39045f4fc069Sjilinxpd 			    blkoff + bsize >= np->r_size) {
39055f4fc069Sjilinxpd 				/*
39065f4fc069Sjilinxpd 				 * If only a block or less is left in
39075f4fc069Sjilinxpd 				 * the file, read all that is remaining.
39085f4fc069Sjilinxpd 				 */
39095f4fc069Sjilinxpd 				if (np->r_size <= off) {
39105f4fc069Sjilinxpd 					/*
39115f4fc069Sjilinxpd 					 * Trying to access beyond EOF,
39125f4fc069Sjilinxpd 					 * set up to get at least one page.
39135f4fc069Sjilinxpd 					 */
39145f4fc069Sjilinxpd 					blksize = off + PAGESIZE - blkoff;
39155f4fc069Sjilinxpd 				} else
39165f4fc069Sjilinxpd 					blksize = np->r_size - blkoff;
39175f4fc069Sjilinxpd 			} else if ((off == 0) ||
39185f4fc069Sjilinxpd 			    (off != np->r_nextr && !readahead_issued)) {
39195f4fc069Sjilinxpd 				blksize = PAGESIZE;
39205f4fc069Sjilinxpd 				blkoff = off; /* block = page here */
39215f4fc069Sjilinxpd 			} else
39225f4fc069Sjilinxpd 				blksize = bsize;
39235f4fc069Sjilinxpd 			mutex_exit(&np->r_statelock);
39245f4fc069Sjilinxpd 
39255f4fc069Sjilinxpd 			pp = pvn_read_kluster(vp, off, seg, addr, &io_off,
39265f4fc069Sjilinxpd 			    &io_len, blkoff, blksize, 0);
39275f4fc069Sjilinxpd 
39285f4fc069Sjilinxpd 			/*
39295f4fc069Sjilinxpd 			 * Some other thread has entered the page,
39305f4fc069Sjilinxpd 			 * so just use it.
39315f4fc069Sjilinxpd 			 */
39325f4fc069Sjilinxpd 			if (pp == NULL)
39335f4fc069Sjilinxpd 				goto again;
39345f4fc069Sjilinxpd 
39355f4fc069Sjilinxpd 			/*
39365f4fc069Sjilinxpd 			 * Now round the request size up to page boundaries.
39375f4fc069Sjilinxpd 			 * This ensures that the entire page will be
39385f4fc069Sjilinxpd 			 * initialized to zeroes if EOF is encountered.
39395f4fc069Sjilinxpd 			 */
39405f4fc069Sjilinxpd 			io_len = ptob(btopr(io_len));
39415f4fc069Sjilinxpd 
39425f4fc069Sjilinxpd 			bp = pageio_setup(pp, io_len, vp, B_READ);
39435f4fc069Sjilinxpd 			ASSERT(bp != NULL);
39445f4fc069Sjilinxpd 
39455f4fc069Sjilinxpd 			/*
39465f4fc069Sjilinxpd 			 * pageio_setup should have set b_addr to 0.  This
39475f4fc069Sjilinxpd 			 * is correct since we want to do I/O on a page
39485f4fc069Sjilinxpd 			 * boundary.  bp_mapin will use this addr to calculate
39495f4fc069Sjilinxpd 			 * an offset, and then set b_addr to the kernel virtual
39505f4fc069Sjilinxpd 			 * address it allocated for us.
39515f4fc069Sjilinxpd 			 */
39525f4fc069Sjilinxpd 			ASSERT(bp->b_un.b_addr == 0);
39535f4fc069Sjilinxpd 
39545f4fc069Sjilinxpd 			bp->b_edev = 0;
39555f4fc069Sjilinxpd 			bp->b_dev = 0;
39565f4fc069Sjilinxpd 			bp->b_lblkno = lbtodb(io_off);
39575f4fc069Sjilinxpd 			bp->b_file = vp;
39585f4fc069Sjilinxpd 			bp->b_offset = (offset_t)off;
39595f4fc069Sjilinxpd 			bp_mapin(bp);
39605f4fc069Sjilinxpd 
39615f4fc069Sjilinxpd 			/*
39625f4fc069Sjilinxpd 			 * If doing a write beyond what we believe is EOF,
39635f4fc069Sjilinxpd 			 * don't bother trying to read the pages from the
39645f4fc069Sjilinxpd 			 * server, we'll just zero the pages here.  We
39655f4fc069Sjilinxpd 			 * don't check that the rw flag is S_WRITE here
39665f4fc069Sjilinxpd 			 * because some implementations may attempt a
39675f4fc069Sjilinxpd 			 * read access to the buffer before copying data.
39685f4fc069Sjilinxpd 			 */
39695f4fc069Sjilinxpd 			mutex_enter(&np->r_statelock);
39705f4fc069Sjilinxpd 			if (io_off >= np->r_size && seg == segkmap) {
39715f4fc069Sjilinxpd 				mutex_exit(&np->r_statelock);
39725f4fc069Sjilinxpd 				bzero(bp->b_un.b_addr, io_len);
39735f4fc069Sjilinxpd 			} else {
39745f4fc069Sjilinxpd 				mutex_exit(&np->r_statelock);
39755f4fc069Sjilinxpd 				error = smbfs_bio(bp, 0, cr);
39765f4fc069Sjilinxpd 			}
39775f4fc069Sjilinxpd 
39785f4fc069Sjilinxpd 			/*
39795f4fc069Sjilinxpd 			 * Unmap the buffer before freeing it.
39805f4fc069Sjilinxpd 			 */
39815f4fc069Sjilinxpd 			bp_mapout(bp);
39825f4fc069Sjilinxpd 			pageio_done(bp);
39835f4fc069Sjilinxpd 
39845f4fc069Sjilinxpd 			/* Here NFS3 updates all pp->p_fsdata */
39855f4fc069Sjilinxpd 
39865f4fc069Sjilinxpd 			if (error == SMBFS_EOF) {
39875f4fc069Sjilinxpd 				/*
39885f4fc069Sjilinxpd 				 * If doing a write system call just return
39895f4fc069Sjilinxpd 				 * zeroed pages, else user tried to get pages
39905f4fc069Sjilinxpd 				 * beyond EOF, return error.  We don't check
39915f4fc069Sjilinxpd 				 * that the rw flag is S_WRITE here because
39925f4fc069Sjilinxpd 				 * some implementations may attempt a read
39935f4fc069Sjilinxpd 				 * access to the buffer before copying data.
39945f4fc069Sjilinxpd 				 */
39955f4fc069Sjilinxpd 				if (seg == segkmap)
39965f4fc069Sjilinxpd 					error = 0;
39975f4fc069Sjilinxpd 				else
39985f4fc069Sjilinxpd 					error = EFAULT;
39995f4fc069Sjilinxpd 			}
40005f4fc069Sjilinxpd 
40015f4fc069Sjilinxpd 			if (!readahead_issued && !error) {
40025f4fc069Sjilinxpd 				mutex_enter(&np->r_statelock);
40035f4fc069Sjilinxpd 				np->r_nextr = io_off + io_len;
40045f4fc069Sjilinxpd 				mutex_exit(&np->r_statelock);
40055f4fc069Sjilinxpd 			}
40065f4fc069Sjilinxpd 		}
40075f4fc069Sjilinxpd 	}
40085f4fc069Sjilinxpd 
40095f4fc069Sjilinxpd 	if (pl == NULL)
40105f4fc069Sjilinxpd 		return (error);
40115f4fc069Sjilinxpd 
40125f4fc069Sjilinxpd 	if (error) {
40135f4fc069Sjilinxpd 		if (pp != NULL)
40145f4fc069Sjilinxpd 			pvn_read_done(pp, B_ERROR);
40155f4fc069Sjilinxpd 		return (error);
40165f4fc069Sjilinxpd 	}
40175f4fc069Sjilinxpd 
40185f4fc069Sjilinxpd 	if (pagefound) {
40195f4fc069Sjilinxpd 		se_t se = (rw == S_CREATE ? SE_EXCL : SE_SHARED);
40205f4fc069Sjilinxpd 
40215f4fc069Sjilinxpd 		/*
40225f4fc069Sjilinxpd 		 * Page exists in the cache, acquire the appropriate lock.
40235f4fc069Sjilinxpd 		 * If this fails, start all over again.
40245f4fc069Sjilinxpd 		 */
40255f4fc069Sjilinxpd 		if ((pp = page_lookup(vp, off, se)) == NULL) {
40265f4fc069Sjilinxpd #ifdef DEBUG
40275f4fc069Sjilinxpd 			smbfs_lostpage++;
40285f4fc069Sjilinxpd #endif
40295f4fc069Sjilinxpd 			goto reread;
40305f4fc069Sjilinxpd 		}
40315f4fc069Sjilinxpd 		pl[0] = pp;
40325f4fc069Sjilinxpd 		pl[1] = NULL;
40335f4fc069Sjilinxpd 		return (0);
40345f4fc069Sjilinxpd 	}
40355f4fc069Sjilinxpd 
40365f4fc069Sjilinxpd 	if (pp != NULL)
40375f4fc069Sjilinxpd 		pvn_plist_init(pp, pl, plsz, off, io_len, rw);
40385f4fc069Sjilinxpd 
40395f4fc069Sjilinxpd 	return (error);
40405f4fc069Sjilinxpd }
40415f4fc069Sjilinxpd 
40425f4fc069Sjilinxpd /*
40435f4fc069Sjilinxpd  * Here NFS has: nfs3_readahead
40445f4fc069Sjilinxpd  * No read-ahead in smbfs yet.
40455f4fc069Sjilinxpd  */
40465f4fc069Sjilinxpd 
40478329232eSGordon Ross #endif	// _KERNEL
40488329232eSGordon Ross 
40495f4fc069Sjilinxpd /*
40505f4fc069Sjilinxpd  * Flags are composed of {B_INVAL, B_FREE, B_DONTNEED, B_FORCE}
40515f4fc069Sjilinxpd  * If len == 0, do from off to EOF.
40525f4fc069Sjilinxpd  *
40535f4fc069Sjilinxpd  * The normal cases should be len == 0 && off == 0 (entire vp list),
40545f4fc069Sjilinxpd  * len == MAXBSIZE (from segmap_release actions), and len == PAGESIZE
40555f4fc069Sjilinxpd  * (from pageout).
40565f4fc069Sjilinxpd  *
40575f4fc069Sjilinxpd  * Like nfs3_putpage + nfs_putpages
40585f4fc069Sjilinxpd  */
40595f4fc069Sjilinxpd /* ARGSUSED */
40605f4fc069Sjilinxpd static int
smbfs_putpage(vnode_t * vp,offset_t off,size_t len,int flags,cred_t * cr,caller_context_t * ct)40615f4fc069Sjilinxpd smbfs_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr,
40625f4fc069Sjilinxpd 	caller_context_t *ct)
40635f4fc069Sjilinxpd {
40648329232eSGordon Ross #ifdef	_KERNEL
40655f4fc069Sjilinxpd 	smbnode_t *np;
40665f4fc069Sjilinxpd 	smbmntinfo_t *smi;
40675f4fc069Sjilinxpd 	page_t *pp;
40685f4fc069Sjilinxpd 	u_offset_t eoff;
40695f4fc069Sjilinxpd 	u_offset_t io_off;
40705f4fc069Sjilinxpd 	size_t io_len;
40715f4fc069Sjilinxpd 	int error;
40725f4fc069Sjilinxpd 	int rdirty;
40735f4fc069Sjilinxpd 	int err;
40745f4fc069Sjilinxpd 
40755f4fc069Sjilinxpd 	np = VTOSMB(vp);
40765f4fc069Sjilinxpd 	smi = VTOSMI(vp);
40775f4fc069Sjilinxpd 
40785f4fc069Sjilinxpd 	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
40795f4fc069Sjilinxpd 		return (EIO);
40805f4fc069Sjilinxpd 
40815f4fc069Sjilinxpd 	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
40825f4fc069Sjilinxpd 		return (EIO);
40835f4fc069Sjilinxpd 
40845f4fc069Sjilinxpd 	if (vp->v_flag & VNOMAP)
40855f4fc069Sjilinxpd 		return (ENOSYS);
40865f4fc069Sjilinxpd 
40875f4fc069Sjilinxpd 	/* Here NFS does rp->r_count (++/--) stuff. */
40885f4fc069Sjilinxpd 
40895f4fc069Sjilinxpd 	/* Beginning of code from nfs_putpages. */
40905f4fc069Sjilinxpd 
40915f4fc069Sjilinxpd 	if (!vn_has_cached_data(vp))
40925f4fc069Sjilinxpd 		return (0);
40935f4fc069Sjilinxpd 
40945f4fc069Sjilinxpd 	/*
40955f4fc069Sjilinxpd 	 * If ROUTOFSPACE is set, then all writes turn into B_INVAL
40965f4fc069Sjilinxpd 	 * writes.  B_FORCE is set to force the VM system to actually
40975f4fc069Sjilinxpd 	 * invalidate the pages, even if the i/o failed.  The pages
40985f4fc069Sjilinxpd 	 * need to get invalidated because they can't be written out
40995f4fc069Sjilinxpd 	 * because there isn't any space left on either the server's
41005f4fc069Sjilinxpd 	 * file system or in the user's disk quota.  The B_FREE bit
41015f4fc069Sjilinxpd 	 * is cleared to avoid confusion as to whether this is a
41025f4fc069Sjilinxpd 	 * request to place the page on the freelist or to destroy
41035f4fc069Sjilinxpd 	 * it.
41045f4fc069Sjilinxpd 	 */
41055f4fc069Sjilinxpd 	if ((np->r_flags & ROUTOFSPACE) ||
41065f4fc069Sjilinxpd 	    (vp->v_vfsp->vfs_flag & VFS_UNMOUNTED))
41075f4fc069Sjilinxpd 		flags = (flags & ~B_FREE) | B_INVAL | B_FORCE;
41085f4fc069Sjilinxpd 
41095f4fc069Sjilinxpd 	if (len == 0) {
41105f4fc069Sjilinxpd 		/*
41115f4fc069Sjilinxpd 		 * If doing a full file synchronous operation, then clear
41125f4fc069Sjilinxpd 		 * the RDIRTY bit.  If a page gets dirtied while the flush
41135f4fc069Sjilinxpd 		 * is happening, then RDIRTY will get set again.  The
41145f4fc069Sjilinxpd 		 * RDIRTY bit must get cleared before the flush so that
41155f4fc069Sjilinxpd 		 * we don't lose this information.
41165f4fc069Sjilinxpd 		 *
41175f4fc069Sjilinxpd 		 * NFS has B_ASYNC vs sync stuff here.
41185f4fc069Sjilinxpd 		 */
41195f4fc069Sjilinxpd 		if (off == (u_offset_t)0 &&
41205f4fc069Sjilinxpd 		    (np->r_flags & RDIRTY)) {
41215f4fc069Sjilinxpd 			mutex_enter(&np->r_statelock);
41225f4fc069Sjilinxpd 			rdirty = (np->r_flags & RDIRTY);
41235f4fc069Sjilinxpd 			np->r_flags &= ~RDIRTY;
41245f4fc069Sjilinxpd 			mutex_exit(&np->r_statelock);
41255f4fc069Sjilinxpd 		} else
41265f4fc069Sjilinxpd 			rdirty = 0;
41275f4fc069Sjilinxpd 
41285f4fc069Sjilinxpd 		/*
41295f4fc069Sjilinxpd 		 * Search the entire vp list for pages >= off, and flush
41305f4fc069Sjilinxpd 		 * the dirty pages.
41315f4fc069Sjilinxpd 		 */
41325f4fc069Sjilinxpd 		error = pvn_vplist_dirty(vp, off, smbfs_putapage,
41335f4fc069Sjilinxpd 		    flags, cr);
41345f4fc069Sjilinxpd 
41355f4fc069Sjilinxpd 		/*
41365f4fc069Sjilinxpd 		 * If an error occurred and the file was marked as dirty
41375f4fc069Sjilinxpd 		 * before and we aren't forcibly invalidating pages, then
41385f4fc069Sjilinxpd 		 * reset the RDIRTY flag.
41395f4fc069Sjilinxpd 		 */
41405f4fc069Sjilinxpd 		if (error && rdirty &&
41415f4fc069Sjilinxpd 		    (flags & (B_INVAL | B_FORCE)) != (B_INVAL | B_FORCE)) {
41425f4fc069Sjilinxpd 			mutex_enter(&np->r_statelock);
41435f4fc069Sjilinxpd 			np->r_flags |= RDIRTY;
41445f4fc069Sjilinxpd 			mutex_exit(&np->r_statelock);
41455f4fc069Sjilinxpd 		}
41465f4fc069Sjilinxpd 	} else {
41475f4fc069Sjilinxpd 		/*
41485f4fc069Sjilinxpd 		 * Do a range from [off...off + len) looking for pages
41495f4fc069Sjilinxpd 		 * to deal with.
41505f4fc069Sjilinxpd 		 */
41515f4fc069Sjilinxpd 		error = 0;
41525f4fc069Sjilinxpd 		io_len = 1; /* quiet warnings */
41535f4fc069Sjilinxpd 		eoff = off + len;
41545f4fc069Sjilinxpd 
41555f4fc069Sjilinxpd 		for (io_off = off; io_off < eoff; io_off += io_len) {
41565f4fc069Sjilinxpd 			mutex_enter(&np->r_statelock);
41575f4fc069Sjilinxpd 			if (io_off >= np->r_size) {
41585f4fc069Sjilinxpd 				mutex_exit(&np->r_statelock);
41595f4fc069Sjilinxpd 				break;
41605f4fc069Sjilinxpd 			}
41615f4fc069Sjilinxpd 			mutex_exit(&np->r_statelock);
41625f4fc069Sjilinxpd 			/*
41635f4fc069Sjilinxpd 			 * If we are not invalidating, synchronously
41645f4fc069Sjilinxpd 			 * freeing or writing pages use the routine
41655f4fc069Sjilinxpd 			 * page_lookup_nowait() to prevent reclaiming
41665f4fc069Sjilinxpd 			 * them from the free list.
41675f4fc069Sjilinxpd 			 */
41685f4fc069Sjilinxpd 			if ((flags & B_INVAL) || !(flags & B_ASYNC)) {
41695f4fc069Sjilinxpd 				pp = page_lookup(vp, io_off,
41705f4fc069Sjilinxpd 				    (flags & (B_INVAL | B_FREE)) ?
41715f4fc069Sjilinxpd 				    SE_EXCL : SE_SHARED);
41725f4fc069Sjilinxpd 			} else {
41735f4fc069Sjilinxpd 				pp = page_lookup_nowait(vp, io_off,
41745f4fc069Sjilinxpd 				    (flags & B_FREE) ? SE_EXCL : SE_SHARED);
41755f4fc069Sjilinxpd 			}
41765f4fc069Sjilinxpd 
41775f4fc069Sjilinxpd 			if (pp == NULL || !pvn_getdirty(pp, flags))
41785f4fc069Sjilinxpd 				io_len = PAGESIZE;
41795f4fc069Sjilinxpd 			else {
41805f4fc069Sjilinxpd 				err = smbfs_putapage(vp, pp, &io_off,
41815f4fc069Sjilinxpd 				    &io_len, flags, cr);
41825f4fc069Sjilinxpd 				if (!error)
41835f4fc069Sjilinxpd 					error = err;
41845f4fc069Sjilinxpd 				/*
41855f4fc069Sjilinxpd 				 * "io_off" and "io_len" are returned as
41865f4fc069Sjilinxpd 				 * the range of pages we actually wrote.
41875f4fc069Sjilinxpd 				 * This allows us to skip ahead more quickly
41885f4fc069Sjilinxpd 				 * since several pages may've been dealt
41895f4fc069Sjilinxpd 				 * with by this iteration of the loop.
41905f4fc069Sjilinxpd 				 */
41915f4fc069Sjilinxpd 			}
41925f4fc069Sjilinxpd 		}
41935f4fc069Sjilinxpd 	}
41945f4fc069Sjilinxpd 
41955f4fc069Sjilinxpd 	return (error);
41968329232eSGordon Ross 
41978329232eSGordon Ross #else	// _KERNEL
41988329232eSGordon Ross 	return (ENOSYS);
41998329232eSGordon Ross #endif	// _KERNEL
42005f4fc069Sjilinxpd }
42015f4fc069Sjilinxpd 
42028329232eSGordon Ross #ifdef	_KERNEL
42038329232eSGordon Ross 
42045f4fc069Sjilinxpd /*
42055f4fc069Sjilinxpd  * Write out a single page, possibly klustering adjacent dirty pages.
42065f4fc069Sjilinxpd  *
42075f4fc069Sjilinxpd  * Like nfs3_putapage / nfs3_sync_putapage
42085f4fc069Sjilinxpd  */
42095f4fc069Sjilinxpd static int
smbfs_putapage(vnode_t * vp,page_t * pp,u_offset_t * offp,size_t * lenp,int flags,cred_t * cr)42105f4fc069Sjilinxpd smbfs_putapage(vnode_t *vp, page_t *pp, u_offset_t *offp, size_t *lenp,
42115f4fc069Sjilinxpd 	int flags, cred_t *cr)
42125f4fc069Sjilinxpd {
42135f4fc069Sjilinxpd 	smbnode_t *np;
42145f4fc069Sjilinxpd 	u_offset_t io_off;
42155f4fc069Sjilinxpd 	u_offset_t lbn_off;
42165f4fc069Sjilinxpd 	u_offset_t lbn;
42175f4fc069Sjilinxpd 	size_t io_len;
42185f4fc069Sjilinxpd 	uint_t bsize;
42195f4fc069Sjilinxpd 	int error;
42205f4fc069Sjilinxpd 
42215f4fc069Sjilinxpd 	np = VTOSMB(vp);
42225f4fc069Sjilinxpd 
42235f4fc069Sjilinxpd 	ASSERT(!vn_is_readonly(vp));
42245f4fc069Sjilinxpd 
42255f4fc069Sjilinxpd 	bsize = MAX(vp->v_vfsp->vfs_bsize, PAGESIZE);
42265f4fc069Sjilinxpd 	lbn = pp->p_offset / bsize;
42275f4fc069Sjilinxpd 	lbn_off = lbn * bsize;
42285f4fc069Sjilinxpd 
42295f4fc069Sjilinxpd 	/*
42305f4fc069Sjilinxpd 	 * Find a kluster that fits in one block, or in
42315f4fc069Sjilinxpd 	 * one page if pages are bigger than blocks.  If
42325f4fc069Sjilinxpd 	 * there is less file space allocated than a whole
42335f4fc069Sjilinxpd 	 * page, we'll shorten the i/o request below.
42345f4fc069Sjilinxpd 	 */
42355f4fc069Sjilinxpd 	pp = pvn_write_kluster(vp, pp, &io_off, &io_len, lbn_off,
42365f4fc069Sjilinxpd 	    roundup(bsize, PAGESIZE), flags);
42375f4fc069Sjilinxpd 
42385f4fc069Sjilinxpd 	/*
42395f4fc069Sjilinxpd 	 * pvn_write_kluster shouldn't have returned a page with offset
42405f4fc069Sjilinxpd 	 * behind the original page we were given.  Verify that.
42415f4fc069Sjilinxpd 	 */
42425f4fc069Sjilinxpd 	ASSERT((pp->p_offset / bsize) >= lbn);
42435f4fc069Sjilinxpd 
42445f4fc069Sjilinxpd 	/*
42455f4fc069Sjilinxpd 	 * Now pp will have the list of kept dirty pages marked for
42465f4fc069Sjilinxpd 	 * write back.  It will also handle invalidation and freeing
42475f4fc069Sjilinxpd 	 * of pages that are not dirty.  Check for page length rounding
42485f4fc069Sjilinxpd 	 * problems.
42495f4fc069Sjilinxpd 	 */
42505f4fc069Sjilinxpd 	if (io_off + io_len > lbn_off + bsize) {
42515f4fc069Sjilinxpd 		ASSERT((io_off + io_len) - (lbn_off + bsize) < PAGESIZE);
42525f4fc069Sjilinxpd 		io_len = lbn_off + bsize - io_off;
42535f4fc069Sjilinxpd 	}
42545f4fc069Sjilinxpd 	/*
42555f4fc069Sjilinxpd 	 * The RMODINPROGRESS flag makes sure that smbfs_bio() sees a
42565f4fc069Sjilinxpd 	 * consistent value of r_size. RMODINPROGRESS is set in writerp().
42575f4fc069Sjilinxpd 	 * When RMODINPROGRESS is set it indicates that a uiomove() is in
42585f4fc069Sjilinxpd 	 * progress and the r_size has not been made consistent with the
42595f4fc069Sjilinxpd 	 * new size of the file. When the uiomove() completes the r_size is
42605f4fc069Sjilinxpd 	 * updated and the RMODINPROGRESS flag is cleared.
42615f4fc069Sjilinxpd 	 *
42625f4fc069Sjilinxpd 	 * The RMODINPROGRESS flag makes sure that smbfs_bio() sees a
42635f4fc069Sjilinxpd 	 * consistent value of r_size. Without this handshaking, it is
42645f4fc069Sjilinxpd 	 * possible that smbfs_bio() picks  up the old value of r_size
42655f4fc069Sjilinxpd 	 * before the uiomove() in writerp() completes. This will result
42665f4fc069Sjilinxpd 	 * in the write through smbfs_bio() being dropped.
42675f4fc069Sjilinxpd 	 *
42685f4fc069Sjilinxpd 	 * More precisely, there is a window between the time the uiomove()
42695f4fc069Sjilinxpd 	 * completes and the time the r_size is updated. If a VOP_PUTPAGE()
42705f4fc069Sjilinxpd 	 * operation intervenes in this window, the page will be picked up,
42715f4fc069Sjilinxpd 	 * because it is dirty (it will be unlocked, unless it was
42725f4fc069Sjilinxpd 	 * pagecreate'd). When the page is picked up as dirty, the dirty
42735f4fc069Sjilinxpd 	 * bit is reset (pvn_getdirty()). In smbfs_write(), r_size is
42745f4fc069Sjilinxpd 	 * checked. This will still be the old size. Therefore the page will
42755f4fc069Sjilinxpd 	 * not be written out. When segmap_release() calls VOP_PUTPAGE(),
42765f4fc069Sjilinxpd 	 * the page will be found to be clean and the write will be dropped.
42775f4fc069Sjilinxpd 	 */
42785f4fc069Sjilinxpd 	if (np->r_flags & RMODINPROGRESS) {
42795f4fc069Sjilinxpd 		mutex_enter(&np->r_statelock);
42805f4fc069Sjilinxpd 		if ((np->r_flags & RMODINPROGRESS) &&
42815f4fc069Sjilinxpd 		    np->r_modaddr + MAXBSIZE > io_off &&
42825f4fc069Sjilinxpd 		    np->r_modaddr < io_off + io_len) {
42835f4fc069Sjilinxpd 			page_t *plist;
42845f4fc069Sjilinxpd 			/*
42855f4fc069Sjilinxpd 			 * A write is in progress for this region of the file.
42865f4fc069Sjilinxpd 			 * If we did not detect RMODINPROGRESS here then this
42875f4fc069Sjilinxpd 			 * path through smbfs_putapage() would eventually go to
42885f4fc069Sjilinxpd 			 * smbfs_bio() and may not write out all of the data
42895f4fc069Sjilinxpd 			 * in the pages. We end up losing data. So we decide
42905f4fc069Sjilinxpd 			 * to set the modified bit on each page in the page
42915f4fc069Sjilinxpd 			 * list and mark the rnode with RDIRTY. This write
42925f4fc069Sjilinxpd 			 * will be restarted at some later time.
42935f4fc069Sjilinxpd 			 */
42945f4fc069Sjilinxpd 			plist = pp;
42955f4fc069Sjilinxpd 			while (plist != NULL) {
42965f4fc069Sjilinxpd 				pp = plist;
42975f4fc069Sjilinxpd 				page_sub(&plist, pp);
42985f4fc069Sjilinxpd 				hat_setmod(pp);
42995f4fc069Sjilinxpd 				page_io_unlock(pp);
43005f4fc069Sjilinxpd 				page_unlock(pp);
43015f4fc069Sjilinxpd 			}
43025f4fc069Sjilinxpd 			np->r_flags |= RDIRTY;
43035f4fc069Sjilinxpd 			mutex_exit(&np->r_statelock);
43045f4fc069Sjilinxpd 			if (offp)
43055f4fc069Sjilinxpd 				*offp = io_off;
43065f4fc069Sjilinxpd 			if (lenp)
43075f4fc069Sjilinxpd 				*lenp = io_len;
43085f4fc069Sjilinxpd 			return (0);
43095f4fc069Sjilinxpd 		}
43105f4fc069Sjilinxpd 		mutex_exit(&np->r_statelock);
43115f4fc069Sjilinxpd 	}
43125f4fc069Sjilinxpd 
43135f4fc069Sjilinxpd 	/*
43145f4fc069Sjilinxpd 	 * NFS handles (flags & B_ASYNC) here...
43155f4fc069Sjilinxpd 	 * (See nfs_async_putapage())
43165f4fc069Sjilinxpd 	 *
43175f4fc069Sjilinxpd 	 * This code section from: nfs3_sync_putapage()
43185f4fc069Sjilinxpd 	 */
43195f4fc069Sjilinxpd 
43205f4fc069Sjilinxpd 	flags |= B_WRITE;
43215f4fc069Sjilinxpd 
43225f4fc069Sjilinxpd 	error = smbfs_rdwrlbn(vp, pp, io_off, io_len, flags, cr);
43235f4fc069Sjilinxpd 
43245f4fc069Sjilinxpd 	if ((error == ENOSPC || error == EDQUOT || error == EFBIG ||
43255f4fc069Sjilinxpd 	    error == EACCES) &&
43265f4fc069Sjilinxpd 	    (flags & (B_INVAL|B_FORCE)) != (B_INVAL|B_FORCE)) {
43275f4fc069Sjilinxpd 		if (!(np->r_flags & ROUTOFSPACE)) {
43285f4fc069Sjilinxpd 			mutex_enter(&np->r_statelock);
43295f4fc069Sjilinxpd 			np->r_flags |= ROUTOFSPACE;
43305f4fc069Sjilinxpd 			mutex_exit(&np->r_statelock);
43315f4fc069Sjilinxpd 		}
43325f4fc069Sjilinxpd 		flags |= B_ERROR;
43335f4fc069Sjilinxpd 		pvn_write_done(pp, flags);
43345f4fc069Sjilinxpd 		/*
43355f4fc069Sjilinxpd 		 * If this was not an async thread, then try again to
43365f4fc069Sjilinxpd 		 * write out the pages, but this time, also destroy
43375f4fc069Sjilinxpd 		 * them whether or not the write is successful.  This
43385f4fc069Sjilinxpd 		 * will prevent memory from filling up with these
43395f4fc069Sjilinxpd 		 * pages and destroying them is the only alternative
43405f4fc069Sjilinxpd 		 * if they can't be written out.
43415f4fc069Sjilinxpd 		 *
43425f4fc069Sjilinxpd 		 * Don't do this if this is an async thread because
43435f4fc069Sjilinxpd 		 * when the pages are unlocked in pvn_write_done,
43445f4fc069Sjilinxpd 		 * some other thread could have come along, locked
43455f4fc069Sjilinxpd 		 * them, and queued for an async thread.  It would be
43465f4fc069Sjilinxpd 		 * possible for all of the async threads to be tied
43475f4fc069Sjilinxpd 		 * up waiting to lock the pages again and they would
43485f4fc069Sjilinxpd 		 * all already be locked and waiting for an async
43495f4fc069Sjilinxpd 		 * thread to handle them.  Deadlock.
43505f4fc069Sjilinxpd 		 */
43515f4fc069Sjilinxpd 		if (!(flags & B_ASYNC)) {
43525f4fc069Sjilinxpd 			error = smbfs_putpage(vp, io_off, io_len,
43535f4fc069Sjilinxpd 			    B_INVAL | B_FORCE, cr, NULL);
43545f4fc069Sjilinxpd 		}
43555f4fc069Sjilinxpd 	} else {
43565f4fc069Sjilinxpd 		if (error)
43575f4fc069Sjilinxpd 			flags |= B_ERROR;
43585f4fc069Sjilinxpd 		else if (np->r_flags & ROUTOFSPACE) {
43595f4fc069Sjilinxpd 			mutex_enter(&np->r_statelock);
43605f4fc069Sjilinxpd 			np->r_flags &= ~ROUTOFSPACE;
43615f4fc069Sjilinxpd 			mutex_exit(&np->r_statelock);
43625f4fc069Sjilinxpd 		}
43635f4fc069Sjilinxpd 		pvn_write_done(pp, flags);
43645f4fc069Sjilinxpd 	}
43655f4fc069Sjilinxpd 
43665f4fc069Sjilinxpd 	/* Now more code from: nfs3_putapage */
43675f4fc069Sjilinxpd 
43685f4fc069Sjilinxpd 	if (offp)
43695f4fc069Sjilinxpd 		*offp = io_off;
43705f4fc069Sjilinxpd 	if (lenp)
43715f4fc069Sjilinxpd 		*lenp = io_len;
43725f4fc069Sjilinxpd 
43735f4fc069Sjilinxpd 	return (error);
43745f4fc069Sjilinxpd }
43755f4fc069Sjilinxpd 
43768329232eSGordon Ross #endif	// _KERNEL
43778329232eSGordon Ross 
43788329232eSGordon Ross 
43795f4fc069Sjilinxpd /*
43805f4fc069Sjilinxpd  * NFS has this in nfs_client.c (shared by v2,v3,...)
43815f4fc069Sjilinxpd  * We have it here so smbfs_putapage can be file scope.
43825f4fc069Sjilinxpd  */
43835f4fc069Sjilinxpd void
smbfs_invalidate_pages(vnode_t * vp,u_offset_t off,cred_t * cr)43845f4fc069Sjilinxpd smbfs_invalidate_pages(vnode_t *vp, u_offset_t off, cred_t *cr)
43855f4fc069Sjilinxpd {
43865f4fc069Sjilinxpd 	smbnode_t *np;
43875f4fc069Sjilinxpd 
43885f4fc069Sjilinxpd 	np = VTOSMB(vp);
43895f4fc069Sjilinxpd 
43905f4fc069Sjilinxpd 	mutex_enter(&np->r_statelock);
43915f4fc069Sjilinxpd 	while (np->r_flags & RTRUNCATE)
43925f4fc069Sjilinxpd 		cv_wait(&np->r_cv, &np->r_statelock);
43935f4fc069Sjilinxpd 	np->r_flags |= RTRUNCATE;
43945f4fc069Sjilinxpd 
43955f4fc069Sjilinxpd 	if (off == (u_offset_t)0) {
43965f4fc069Sjilinxpd 		np->r_flags &= ~RDIRTY;
43975f4fc069Sjilinxpd 		if (!(np->r_flags & RSTALE))
43985f4fc069Sjilinxpd 			np->r_error = 0;
43995f4fc069Sjilinxpd 	}
44005f4fc069Sjilinxpd 	/* Here NFSv3 has np->r_truncaddr = off; */
44015f4fc069Sjilinxpd 	mutex_exit(&np->r_statelock);
44025f4fc069Sjilinxpd 
44038329232eSGordon Ross #ifdef	_KERNEL
44045f4fc069Sjilinxpd 	(void) pvn_vplist_dirty(vp, off, smbfs_putapage,
44055f4fc069Sjilinxpd 	    B_INVAL | B_TRUNC, cr);
44068329232eSGordon Ross #endif	// _KERNEL
44075f4fc069Sjilinxpd 
44085f4fc069Sjilinxpd 	mutex_enter(&np->r_statelock);
44095f4fc069Sjilinxpd 	np->r_flags &= ~RTRUNCATE;
44105f4fc069Sjilinxpd 	cv_broadcast(&np->r_cv);
44115f4fc069Sjilinxpd 	mutex_exit(&np->r_statelock);
44125f4fc069Sjilinxpd }
44135f4fc069Sjilinxpd 
44148329232eSGordon Ross #ifdef	_KERNEL
44158329232eSGordon Ross 
44165f4fc069Sjilinxpd /* Like nfs3_map */
44175f4fc069Sjilinxpd 
44185f4fc069Sjilinxpd /* ARGSUSED */
44195f4fc069Sjilinxpd static int
smbfs_map(vnode_t * vp,offset_t off,struct as * as,caddr_t * addrp,size_t len,uchar_t prot,uchar_t maxprot,uint_t flags,cred_t * cr,caller_context_t * ct)44205f4fc069Sjilinxpd smbfs_map(vnode_t *vp, offset_t off, struct as *as, caddr_t *addrp,
44215f4fc069Sjilinxpd 	size_t len, uchar_t prot, uchar_t maxprot, uint_t flags,
44225f4fc069Sjilinxpd 	cred_t *cr, caller_context_t *ct)
44235f4fc069Sjilinxpd {
44245f4fc069Sjilinxpd 	segvn_crargs_t	vn_a;
44255f4fc069Sjilinxpd 	struct vattr	va;
44265f4fc069Sjilinxpd 	smbnode_t	*np;
44275f4fc069Sjilinxpd 	smbmntinfo_t	*smi;
44285f4fc069Sjilinxpd 	int		error;
44295f4fc069Sjilinxpd 
44305f4fc069Sjilinxpd 	np = VTOSMB(vp);
44315f4fc069Sjilinxpd 	smi = VTOSMI(vp);
44325f4fc069Sjilinxpd 
44335f4fc069Sjilinxpd 	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
44345f4fc069Sjilinxpd 		return (EIO);
44355f4fc069Sjilinxpd 
44365f4fc069Sjilinxpd 	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
44375f4fc069Sjilinxpd 		return (EIO);
44385f4fc069Sjilinxpd 
4439*168091e5SGordon Ross 	/* Sanity check: should have a valid open */
4440*168091e5SGordon Ross 	if (np->n_fid == NULL)
4441*168091e5SGordon Ross 		return (EIO);
4442*168091e5SGordon Ross 
44435f4fc069Sjilinxpd 	if (vp->v_flag & VNOMAP)
44445f4fc069Sjilinxpd 		return (ENOSYS);
44455f4fc069Sjilinxpd 
44465f4fc069Sjilinxpd 	if (off < 0 || off + (ssize_t)len < 0)
44475f4fc069Sjilinxpd 		return (ENXIO);
44485f4fc069Sjilinxpd 
44495f4fc069Sjilinxpd 	if (vp->v_type != VREG)
44505f4fc069Sjilinxpd 		return (ENODEV);
44515f4fc069Sjilinxpd 
44525f4fc069Sjilinxpd 	/*
44535f4fc069Sjilinxpd 	 * NFS does close-to-open consistency stuff here.
44545f4fc069Sjilinxpd 	 * Just get (possibly cached) attributes.
44555f4fc069Sjilinxpd 	 */
44565f4fc069Sjilinxpd 	va.va_mask = AT_ALL;
44575f4fc069Sjilinxpd 	if ((error = smbfsgetattr(vp, &va, cr)) != 0)
44585f4fc069Sjilinxpd 		return (error);
44595f4fc069Sjilinxpd 
44605f4fc069Sjilinxpd 	/*
44615f4fc069Sjilinxpd 	 * Check to see if the vnode is currently marked as not cachable.
44625f4fc069Sjilinxpd 	 * This means portions of the file are locked (through VOP_FRLOCK).
44635f4fc069Sjilinxpd 	 * In this case the map request must be refused.  We use
44645f4fc069Sjilinxpd 	 * rp->r_lkserlock to avoid a race with concurrent lock requests.
44655f4fc069Sjilinxpd 	 */
44665f4fc069Sjilinxpd 	/*
44675f4fc069Sjilinxpd 	 * Atomically increment r_inmap after acquiring r_rwlock. The
44685f4fc069Sjilinxpd 	 * idea here is to acquire r_rwlock to block read/write and
44695f4fc069Sjilinxpd 	 * not to protect r_inmap. r_inmap will inform smbfs_read/write()
44705f4fc069Sjilinxpd 	 * that we are in smbfs_map(). Now, r_rwlock is acquired in order
44715f4fc069Sjilinxpd 	 * and we can prevent the deadlock that would have occurred
44725f4fc069Sjilinxpd 	 * when smbfs_addmap() would have acquired it out of order.
44735f4fc069Sjilinxpd 	 *
44745f4fc069Sjilinxpd 	 * Since we are not protecting r_inmap by any lock, we do not
44755f4fc069Sjilinxpd 	 * hold any lock when we decrement it. We atomically decrement
44765f4fc069Sjilinxpd 	 * r_inmap after we release r_lkserlock.  Note that rwlock is
44775f4fc069Sjilinxpd 	 * re-entered as writer in smbfs_addmap (called via as_map).
44785f4fc069Sjilinxpd 	 */
44795f4fc069Sjilinxpd 
44805f4fc069Sjilinxpd 	if (smbfs_rw_enter_sig(&np->r_rwlock, RW_WRITER, SMBINTR(vp)))
44815f4fc069Sjilinxpd 		return (EINTR);
44825f4fc069Sjilinxpd 	atomic_inc_uint(&np->r_inmap);
44835f4fc069Sjilinxpd 	smbfs_rw_exit(&np->r_rwlock);
44845f4fc069Sjilinxpd 
44855f4fc069Sjilinxpd 	if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, SMBINTR(vp))) {
44865f4fc069Sjilinxpd 		atomic_dec_uint(&np->r_inmap);
44875f4fc069Sjilinxpd 		return (EINTR);
44885f4fc069Sjilinxpd 	}
44895f4fc069Sjilinxpd 
44905f4fc069Sjilinxpd 	if (vp->v_flag & VNOCACHE) {
44915f4fc069Sjilinxpd 		error = EAGAIN;
44925f4fc069Sjilinxpd 		goto done;
44935f4fc069Sjilinxpd 	}
44945f4fc069Sjilinxpd 
44955f4fc069Sjilinxpd 	/*
44965f4fc069Sjilinxpd 	 * Don't allow concurrent locks and mapping if mandatory locking is
44975f4fc069Sjilinxpd 	 * enabled.
44985f4fc069Sjilinxpd 	 */
44995f4fc069Sjilinxpd 	if ((flk_has_remote_locks(vp) || smbfs_lm_has_sleep(vp)) &&
45005f4fc069Sjilinxpd 	    MANDLOCK(vp, va.va_mode)) {
45015f4fc069Sjilinxpd 		error = EAGAIN;
45025f4fc069Sjilinxpd 		goto done;
45035f4fc069Sjilinxpd 	}
45045f4fc069Sjilinxpd 
45055f4fc069Sjilinxpd 	as_rangelock(as);
45065f4fc069Sjilinxpd 	error = choose_addr(as, addrp, len, off, ADDR_VACALIGN, flags);
45075f4fc069Sjilinxpd 	if (error != 0) {
45085f4fc069Sjilinxpd 		as_rangeunlock(as);
45095f4fc069Sjilinxpd 		goto done;
45105f4fc069Sjilinxpd 	}
45115f4fc069Sjilinxpd 
45125f4fc069Sjilinxpd 	vn_a.vp = vp;
45135f4fc069Sjilinxpd 	vn_a.offset = off;
45145f4fc069Sjilinxpd 	vn_a.type = (flags & MAP_TYPE);
45155f4fc069Sjilinxpd 	vn_a.prot = (uchar_t)prot;
45165f4fc069Sjilinxpd 	vn_a.maxprot = (uchar_t)maxprot;
45175f4fc069Sjilinxpd 	vn_a.flags = (flags & ~MAP_TYPE);
45185f4fc069Sjilinxpd 	vn_a.cred = cr;
45195f4fc069Sjilinxpd 	vn_a.amp = NULL;
45205f4fc069Sjilinxpd 	vn_a.szc = 0;
45215f4fc069Sjilinxpd 	vn_a.lgrp_mem_policy_flags = 0;
45225f4fc069Sjilinxpd 
45235f4fc069Sjilinxpd 	error = as_map(as, *addrp, len, segvn_create, &vn_a);
45245f4fc069Sjilinxpd 	as_rangeunlock(as);
45255f4fc069Sjilinxpd 
45265f4fc069Sjilinxpd done:
45275f4fc069Sjilinxpd 	smbfs_rw_exit(&np->r_lkserlock);
45285f4fc069Sjilinxpd 	atomic_dec_uint(&np->r_inmap);
45295f4fc069Sjilinxpd 	return (error);
45305f4fc069Sjilinxpd }
45315f4fc069Sjilinxpd 
45324e72ade1SGordon Ross /*
45334e72ade1SGordon Ross  * This uses addmap/delmap functions to hold the SMB FID open as long as
45344e72ade1SGordon Ross  * there are pages mapped in this as/seg.  Increment the FID refs. when
45354e72ade1SGordon Ross  * the maping count goes from zero to non-zero, and release the FID ref
45364e72ade1SGordon Ross  * when the maping count goes from non-zero to zero.
45374e72ade1SGordon Ross  */
45384e72ade1SGordon Ross 
45395f4fc069Sjilinxpd /* ARGSUSED */
45405f4fc069Sjilinxpd static int
smbfs_addmap(vnode_t * vp,offset_t off,struct as * as,caddr_t addr,size_t len,uchar_t prot,uchar_t maxprot,uint_t flags,cred_t * cr,caller_context_t * ct)45415f4fc069Sjilinxpd smbfs_addmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
45425f4fc069Sjilinxpd 	size_t len, uchar_t prot, uchar_t maxprot, uint_t flags,
45435f4fc069Sjilinxpd 	cred_t *cr, caller_context_t *ct)
45445f4fc069Sjilinxpd {
45455f4fc069Sjilinxpd 	smbnode_t *np = VTOSMB(vp);
45465f4fc069Sjilinxpd 	boolean_t inc_fidrefs = B_FALSE;
45475f4fc069Sjilinxpd 
45485f4fc069Sjilinxpd 	/*
45495f4fc069Sjilinxpd 	 * When r_mapcnt goes from zero to non-zero,
45505f4fc069Sjilinxpd 	 * increment n_fidrefs
45515f4fc069Sjilinxpd 	 */
45525f4fc069Sjilinxpd 	mutex_enter(&np->r_statelock);
45535f4fc069Sjilinxpd 	if (np->r_mapcnt == 0)
45545f4fc069Sjilinxpd 		inc_fidrefs = B_TRUE;
45555f4fc069Sjilinxpd 	np->r_mapcnt += btopr(len);
45565f4fc069Sjilinxpd 	mutex_exit(&np->r_statelock);
45575f4fc069Sjilinxpd 
45585f4fc069Sjilinxpd 	if (inc_fidrefs) {
45595f4fc069Sjilinxpd 		(void) smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, 0);
45605f4fc069Sjilinxpd 		np->n_fidrefs++;
45615f4fc069Sjilinxpd 		smbfs_rw_exit(&np->r_lkserlock);
45625f4fc069Sjilinxpd 	}
45635f4fc069Sjilinxpd 
45645f4fc069Sjilinxpd 	return (0);
45655f4fc069Sjilinxpd }
45665f4fc069Sjilinxpd 
45675f4fc069Sjilinxpd /*
45684e72ade1SGordon Ross  * Args passed to smbfs_delmap_async
45695f4fc069Sjilinxpd  */
45705f4fc069Sjilinxpd typedef struct smbfs_delmap_args {
45714e72ade1SGordon Ross 	taskq_ent_t		dm_tqent;
45724e72ade1SGordon Ross 	cred_t			*dm_cr;
45734e72ade1SGordon Ross 	vnode_t			*dm_vp;
45744e72ade1SGordon Ross 	offset_t		dm_off;
45754e72ade1SGordon Ross 	caddr_t			dm_addr;
45764e72ade1SGordon Ross 	size_t			dm_len;
45774e72ade1SGordon Ross 	uint_t			dm_prot;
45784e72ade1SGordon Ross 	uint_t			dm_maxprot;
45794e72ade1SGordon Ross 	uint_t			dm_flags;
45804e72ade1SGordon Ross 	boolean_t		dm_rele_fid;
45815f4fc069Sjilinxpd } smbfs_delmap_args_t;
45825f4fc069Sjilinxpd 
45834e72ade1SGordon Ross /*
45844e72ade1SGordon Ross  * Using delmap not only to release the SMB FID (as described above)
45854e72ade1SGordon Ross  * but to flush dirty pages as needed.  Both of those do the actual
45864e72ade1SGordon Ross  * work in an async taskq job to avoid interfering with locks held
45874e72ade1SGordon Ross  * in the VM layer when this is called.
45884e72ade1SGordon Ross  */
45894e72ade1SGordon Ross 
45905f4fc069Sjilinxpd /* ARGSUSED */
45915f4fc069Sjilinxpd static int
smbfs_delmap(vnode_t * vp,offset_t off,struct as * as,caddr_t addr,size_t len,uint_t prot,uint_t maxprot,uint_t flags,cred_t * cr,caller_context_t * ct)45925f4fc069Sjilinxpd smbfs_delmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
45935f4fc069Sjilinxpd 	size_t len, uint_t prot, uint_t maxprot, uint_t flags,
45945f4fc069Sjilinxpd 	cred_t *cr, caller_context_t *ct)
45955f4fc069Sjilinxpd {
45964e72ade1SGordon Ross 	smbnode_t		*np = VTOSMB(vp);
45974e72ade1SGordon Ross 	smbmntinfo_t		*smi = VTOSMI(vp);
45985f4fc069Sjilinxpd 	smbfs_delmap_args_t	*dmapp;
45995f4fc069Sjilinxpd 
46005f4fc069Sjilinxpd 	dmapp = kmem_zalloc(sizeof (*dmapp), KM_SLEEP);
46015f4fc069Sjilinxpd 
46024e72ade1SGordon Ross 	/*
46034e72ade1SGordon Ross 	 * The VM layer may segvn_free the seg holding this vnode
46044e72ade1SGordon Ross 	 * before our callback has a chance run, so take a hold on
46054e72ade1SGordon Ross 	 * the vnode here and release it in the callback.
46064e72ade1SGordon Ross 	 * (same for the cred)
46074e72ade1SGordon Ross 	 */
46084e72ade1SGordon Ross 	crhold(cr);
46094e72ade1SGordon Ross 	VN_HOLD(vp);
46104e72ade1SGordon Ross 
46114e72ade1SGordon Ross 	dmapp->dm_vp = vp;
46124e72ade1SGordon Ross 	dmapp->dm_cr = cr;
46134e72ade1SGordon Ross 	dmapp->dm_off = off;
46144e72ade1SGordon Ross 	dmapp->dm_addr = addr;
46154e72ade1SGordon Ross 	dmapp->dm_len = len;
46164e72ade1SGordon Ross 	dmapp->dm_prot = prot;
46174e72ade1SGordon Ross 	dmapp->dm_maxprot = maxprot;
46184e72ade1SGordon Ross 	dmapp->dm_flags = flags;
46194e72ade1SGordon Ross 	dmapp->dm_rele_fid = B_FALSE;
46205f4fc069Sjilinxpd 
46215f4fc069Sjilinxpd 	/*
46224e72ade1SGordon Ross 	 * Go ahead and decrement r_mapcount now, which is
46234e72ade1SGordon Ross 	 * the primary purpose of this function.
46244e72ade1SGordon Ross 	 *
46254e72ade1SGordon Ross 	 * When r_mapcnt goes to zero, we need to call
46264e72ade1SGordon Ross 	 * smbfs_rele_fid, but can't do that here, so
46274e72ade1SGordon Ross 	 * set a flag telling the async task to do it.
46285f4fc069Sjilinxpd 	 */
46295f4fc069Sjilinxpd 	mutex_enter(&np->r_statelock);
46305f4fc069Sjilinxpd 	np->r_mapcnt -= btopr(len);
46315f4fc069Sjilinxpd 	ASSERT(np->r_mapcnt >= 0);
46325f4fc069Sjilinxpd 	if (np->r_mapcnt == 0)
46334e72ade1SGordon Ross 		dmapp->dm_rele_fid = B_TRUE;
46345f4fc069Sjilinxpd 	mutex_exit(&np->r_statelock);
46355f4fc069Sjilinxpd 
46364e72ade1SGordon Ross 	taskq_dispatch_ent(smi->smi_taskq, smbfs_delmap_async, dmapp, 0,
46374e72ade1SGordon Ross 	    &dmapp->dm_tqent);
46385f4fc069Sjilinxpd 
46395f4fc069Sjilinxpd 	return (0);
46405f4fc069Sjilinxpd }
46415f4fc069Sjilinxpd 
46425f4fc069Sjilinxpd /*
46435f4fc069Sjilinxpd  * Remove some pages from an mmap'd vnode.  Flush any
46445f4fc069Sjilinxpd  * dirty pages in the unmapped range.
46455f4fc069Sjilinxpd  */
46465f4fc069Sjilinxpd /* ARGSUSED */
46475f4fc069Sjilinxpd static void
smbfs_delmap_async(void * varg)46484e72ade1SGordon Ross smbfs_delmap_async(void *varg)
46495f4fc069Sjilinxpd {
46504e72ade1SGordon Ross 	smbfs_delmap_args_t	*dmapp = varg;
46514e72ade1SGordon Ross 	cred_t			*cr;
46525f4fc069Sjilinxpd 	vnode_t			*vp;
46535f4fc069Sjilinxpd 	smbnode_t		*np;
46545f4fc069Sjilinxpd 	smbmntinfo_t		*smi;
46555f4fc069Sjilinxpd 
46564e72ade1SGordon Ross 	cr = dmapp->dm_cr;
46574e72ade1SGordon Ross 	vp = dmapp->dm_vp;
46585f4fc069Sjilinxpd 	np = VTOSMB(vp);
46595f4fc069Sjilinxpd 	smi = VTOSMI(vp);
46605f4fc069Sjilinxpd 
46615f4fc069Sjilinxpd 	/* Decremented r_mapcnt in smbfs_delmap */
46625f4fc069Sjilinxpd 
46635f4fc069Sjilinxpd 	/*
46645f4fc069Sjilinxpd 	 * Initiate a page flush and potential commit if there are
46655f4fc069Sjilinxpd 	 * pages, the file system was not mounted readonly, the segment
46665f4fc069Sjilinxpd 	 * was mapped shared, and the pages themselves were writeable.
46675f4fc069Sjilinxpd 	 *
46685f4fc069Sjilinxpd 	 * mark RDIRTY here, will be used to check if a file is dirty when
46695f4fc069Sjilinxpd 	 * unmount smbfs
46705f4fc069Sjilinxpd 	 */
46715f4fc069Sjilinxpd 	if (vn_has_cached_data(vp) && !vn_is_readonly(vp) &&
46724e72ade1SGordon Ross 	    dmapp->dm_flags == MAP_SHARED &&
46734e72ade1SGordon Ross 	    (dmapp->dm_maxprot & PROT_WRITE) != 0) {
46745f4fc069Sjilinxpd 		mutex_enter(&np->r_statelock);
46755f4fc069Sjilinxpd 		np->r_flags |= RDIRTY;
46765f4fc069Sjilinxpd 		mutex_exit(&np->r_statelock);
46775f4fc069Sjilinxpd 
46785f4fc069Sjilinxpd 		/*
46795f4fc069Sjilinxpd 		 * Need to finish the putpage before we
46805f4fc069Sjilinxpd 		 * close the OtW FID needed for I/O.
46815f4fc069Sjilinxpd 		 */
46824e72ade1SGordon Ross 		(void) smbfs_putpage(vp, dmapp->dm_off, dmapp->dm_len, 0,
46834e72ade1SGordon Ross 		    dmapp->dm_cr, NULL);
46845f4fc069Sjilinxpd 	}
46855f4fc069Sjilinxpd 
46865f4fc069Sjilinxpd 	if ((np->r_flags & RDIRECTIO) || (smi->smi_flags & SMI_DIRECTIO))
46874e72ade1SGordon Ross 		(void) smbfs_putpage(vp, dmapp->dm_off, dmapp->dm_len,
46884e72ade1SGordon Ross 		    B_INVAL, dmapp->dm_cr, NULL);
46895f4fc069Sjilinxpd 
46905f4fc069Sjilinxpd 	/*
46915f4fc069Sjilinxpd 	 * If r_mapcnt went to zero, drop our FID ref now.
46925f4fc069Sjilinxpd 	 * On the last fidref, this does an OtW close.
46935f4fc069Sjilinxpd 	 */
46944e72ade1SGordon Ross 	if (dmapp->dm_rele_fid) {
46955f4fc069Sjilinxpd 		struct smb_cred scred;
46965f4fc069Sjilinxpd 
46975f4fc069Sjilinxpd 		(void) smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, 0);
46984e72ade1SGordon Ross 		smb_credinit(&scred, dmapp->dm_cr);
46995f4fc069Sjilinxpd 
47005f4fc069Sjilinxpd 		smbfs_rele_fid(np, &scred);
47015f4fc069Sjilinxpd 
47025f4fc069Sjilinxpd 		smb_credrele(&scred);
47035f4fc069Sjilinxpd 		smbfs_rw_exit(&np->r_lkserlock);
47045f4fc069Sjilinxpd 	}
47055f4fc069Sjilinxpd 
47064e72ade1SGordon Ross 	/* Release holds taken in smbfs_delmap */
47074e72ade1SGordon Ross 	VN_RELE(vp);
47084e72ade1SGordon Ross 	crfree(cr);
47094e72ade1SGordon Ross 
47105f4fc069Sjilinxpd 	kmem_free(dmapp, sizeof (*dmapp));
47115f4fc069Sjilinxpd }
47125f4fc069Sjilinxpd 
47135f4fc069Sjilinxpd /* No smbfs_pageio() or smbfs_dispose() ops. */
47145f4fc069Sjilinxpd 
47158329232eSGordon Ross #endif	// _KERNEL
47168329232eSGordon Ross 
47175f4fc069Sjilinxpd /* misc. ******************************************************** */
47185f4fc069Sjilinxpd 
47194bff34e3Sthurlow 
47204bff34e3Sthurlow /*
47214bff34e3Sthurlow  * XXX
47224bff34e3Sthurlow  * This op may need to support PSARC 2007/440, nbmand changes for CIFS Service.
47234bff34e3Sthurlow  */
47244bff34e3Sthurlow static int
smbfs_frlock(vnode_t * vp,int cmd,struct flock64 * bfp,int flag,offset_t offset,struct flk_callback * flk_cbp,cred_t * cr,caller_context_t * ct)47254bff34e3Sthurlow smbfs_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
47264bff34e3Sthurlow 	offset_t offset, struct flk_callback *flk_cbp, cred_t *cr,
47274bff34e3Sthurlow 	caller_context_t *ct)
47284bff34e3Sthurlow {
4729a19609f8Sjv 	if (curproc->p_zone != VTOSMI(vp)->smi_zone_ref.zref_zone)
47304bff34e3Sthurlow 		return (EIO);
47314bff34e3Sthurlow 
47324bff34e3Sthurlow 	if (VTOSMI(vp)->smi_flags & SMI_LLOCK)
47334bff34e3Sthurlow 		return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr, ct));
47344bff34e3Sthurlow 	else
47354bff34e3Sthurlow 		return (ENOSYS);
47364bff34e3Sthurlow }
47374bff34e3Sthurlow 
47384bff34e3Sthurlow /*
47394bff34e3Sthurlow  * Free storage space associated with the specified vnode.  The portion
47404bff34e3Sthurlow  * to be freed is specified by bfp->l_start and bfp->l_len (already
47414bff34e3Sthurlow  * normalized to a "whence" of 0).
47424bff34e3Sthurlow  *
47434bff34e3Sthurlow  * Called by fcntl(fd, F_FREESP, lkp) for libc:ftruncate, etc.
47444bff34e3Sthurlow  */
47454bff34e3Sthurlow /* ARGSUSED */
47464bff34e3Sthurlow static int
smbfs_space(vnode_t * vp,int cmd,struct flock64 * bfp,int flag,offset_t offset,cred_t * cr,caller_context_t * ct)47474bff34e3Sthurlow smbfs_space(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
47484bff34e3Sthurlow 	offset_t offset, cred_t *cr, caller_context_t *ct)
47494bff34e3Sthurlow {
47504bff34e3Sthurlow 	int		error;
47514bff34e3Sthurlow 	smbmntinfo_t	*smi;
47524bff34e3Sthurlow 
47534bff34e3Sthurlow 	smi = VTOSMI(vp);
47544bff34e3Sthurlow 
4755a19609f8Sjv 	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
47564bff34e3Sthurlow 		return (EIO);
47574bff34e3Sthurlow 
47584bff34e3Sthurlow 	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
47594bff34e3Sthurlow 		return (EIO);
47604bff34e3Sthurlow 
476191d632c8Sgwr 	/* Caller (fcntl) has checked v_type */
47624bff34e3Sthurlow 	ASSERT(vp->v_type == VREG);
47634bff34e3Sthurlow 	if (cmd != F_FREESP)
47644bff34e3Sthurlow 		return (EINVAL);
47654bff34e3Sthurlow 
47664bff34e3Sthurlow 	/*
47674bff34e3Sthurlow 	 * Like NFS3, no 32-bit offset checks here.
47684bff34e3Sthurlow 	 * Our SMB layer takes care to return EFBIG
47694bff34e3Sthurlow 	 * when it has to fallback to a 32-bit call.
47704bff34e3Sthurlow 	 */
47714bff34e3Sthurlow 
47724bff34e3Sthurlow 	error = convoff(vp, bfp, 0, offset);
47734bff34e3Sthurlow 	if (!error) {
47744bff34e3Sthurlow 		ASSERT(bfp->l_start >= 0);
47754bff34e3Sthurlow 		if (bfp->l_len == 0) {
47764bff34e3Sthurlow 			struct vattr va;
47774bff34e3Sthurlow 
47784bff34e3Sthurlow 			/*
47794bff34e3Sthurlow 			 * ftruncate should not change the ctime and
47804bff34e3Sthurlow 			 * mtime if we truncate the file to its
47814bff34e3Sthurlow 			 * previous size.
47824bff34e3Sthurlow 			 */
47834bff34e3Sthurlow 			va.va_mask = AT_SIZE;
47844bff34e3Sthurlow 			error = smbfsgetattr(vp, &va, cr);
47854bff34e3Sthurlow 			if (error || va.va_size == bfp->l_start)
47864bff34e3Sthurlow 				return (error);
47874bff34e3Sthurlow 			va.va_mask = AT_SIZE;
47884bff34e3Sthurlow 			va.va_size = bfp->l_start;
47894bff34e3Sthurlow 			error = smbfssetattr(vp, &va, 0, cr);
47905f4fc069Sjilinxpd 			/* SMBFS_VNEVENT... */
47914bff34e3Sthurlow 		} else
47924bff34e3Sthurlow 			error = EINVAL;
47934bff34e3Sthurlow 	}
47944bff34e3Sthurlow 
47954bff34e3Sthurlow 	return (error);
47964bff34e3Sthurlow }
47974bff34e3Sthurlow 
47985f4fc069Sjilinxpd 
47995f4fc069Sjilinxpd /* ARGSUSED */
48005f4fc069Sjilinxpd static int
smbfs_realvp(vnode_t * vp,vnode_t ** vpp,caller_context_t * ct)48015f4fc069Sjilinxpd smbfs_realvp(vnode_t *vp, vnode_t **vpp, caller_context_t *ct)
48025f4fc069Sjilinxpd {
48035f4fc069Sjilinxpd 
48045f4fc069Sjilinxpd 	return (ENOSYS);
48055f4fc069Sjilinxpd }
48065f4fc069Sjilinxpd 
48075f4fc069Sjilinxpd 
48084bff34e3Sthurlow /* ARGSUSED */
48094bff34e3Sthurlow static int
smbfs_pathconf(vnode_t * vp,int cmd,ulong_t * valp,cred_t * cr,caller_context_t * ct)48104bff34e3Sthurlow smbfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
48114bff34e3Sthurlow 	caller_context_t *ct)
48124bff34e3Sthurlow {
481391d632c8Sgwr 	vfs_t *vfs;
48144bff34e3Sthurlow 	smbmntinfo_t *smi;
48154bff34e3Sthurlow 	struct smb_share *ssp;
48164bff34e3Sthurlow 
481791d632c8Sgwr 	vfs = vp->v_vfsp;
481891d632c8Sgwr 	smi = VFTOSMI(vfs);
48194bff34e3Sthurlow 
4820a19609f8Sjv 	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
48214bff34e3Sthurlow 		return (EIO);
48224bff34e3Sthurlow 
48234bff34e3Sthurlow 	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
48244bff34e3Sthurlow 		return (EIO);
48254bff34e3Sthurlow 
48264bff34e3Sthurlow 	switch (cmd) {
48274bff34e3Sthurlow 	case _PC_FILESIZEBITS:
48284bff34e3Sthurlow 		ssp = smi->smi_share;
48294bff34e3Sthurlow 		if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES)
48304bff34e3Sthurlow 			*valp = 64;
48314bff34e3Sthurlow 		else
48324bff34e3Sthurlow 			*valp = 32;
48334bff34e3Sthurlow 		break;
48344bff34e3Sthurlow 
48354bff34e3Sthurlow 	case _PC_LINK_MAX:
48364bff34e3Sthurlow 		/* We only ever report one link to an object */
48374bff34e3Sthurlow 		*valp = 1;
48384bff34e3Sthurlow 		break;
48394bff34e3Sthurlow 
48407568150aSgwr 	case _PC_ACL_ENABLED:
48417568150aSgwr 		/*
484202d09e03SGordon Ross 		 * Always indicate that ACLs are enabled and
484302d09e03SGordon Ross 		 * that we support ACE_T format, otherwise
484402d09e03SGordon Ross 		 * libsec will ask for ACLENT_T format data
484502d09e03SGordon Ross 		 * which we don't support.
48467568150aSgwr 		 */
48477568150aSgwr 		*valp = _ACL_ACE_ENABLED;
48487568150aSgwr 		break;
48497568150aSgwr 
48504bff34e3Sthurlow 	case _PC_SYMLINK_MAX:	/* No symlinks until we do Unix extensions */
48514bff34e3Sthurlow 		*valp = 0;
48524bff34e3Sthurlow 		break;
48534bff34e3Sthurlow 
485491d632c8Sgwr 	case _PC_XATTR_EXISTS:
485591d632c8Sgwr 		if (vfs->vfs_flag & VFS_XATTR) {
485691d632c8Sgwr 			*valp = smbfs_xa_exists(vp, cr);
485791d632c8Sgwr 			break;
485891d632c8Sgwr 		}
485991d632c8Sgwr 		return (EINVAL);
486091d632c8Sgwr 
486128162916SGordon Ross 	case _PC_SATTR_ENABLED:
486228162916SGordon Ross 	case _PC_SATTR_EXISTS:
486328162916SGordon Ross 		*valp = 1;
486428162916SGordon Ross 		break;
486528162916SGordon Ross 
48663b862e9aSRoger A. Faulkner 	case _PC_TIMESTAMP_RESOLUTION:
486702d09e03SGordon Ross 		/*
486802d09e03SGordon Ross 		 * Windows times are tenths of microseconds
486902d09e03SGordon Ross 		 * (multiples of 100 nanoseconds).
487002d09e03SGordon Ross 		 */
487102d09e03SGordon Ross 		*valp = 100L;
48723b862e9aSRoger A. Faulkner 		break;
48733b862e9aSRoger A. Faulkner 
48744bff34e3Sthurlow 	default:
48754bff34e3Sthurlow 		return (fs_pathconf(vp, cmd, valp, cr, ct));
48764bff34e3Sthurlow 	}
48774bff34e3Sthurlow 	return (0);
48784bff34e3Sthurlow }
48794bff34e3Sthurlow 
48807568150aSgwr /* ARGSUSED */
48817568150aSgwr static int
smbfs_getsecattr(vnode_t * vp,vsecattr_t * vsa,int flag,cred_t * cr,caller_context_t * ct)48827568150aSgwr smbfs_getsecattr(vnode_t *vp, vsecattr_t *vsa, int flag, cred_t *cr,
48837568150aSgwr 	caller_context_t *ct)
48847568150aSgwr {
48857568150aSgwr 	vfs_t *vfsp;
48867568150aSgwr 	smbmntinfo_t *smi;
488702d09e03SGordon Ross 	int	error;
48887568150aSgwr 	uint_t	mask;
48897568150aSgwr 
48907568150aSgwr 	vfsp = vp->v_vfsp;
48917568150aSgwr 	smi = VFTOSMI(vfsp);
48927568150aSgwr 
4893a19609f8Sjv 	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
48947568150aSgwr 		return (EIO);
48957568150aSgwr 
48967568150aSgwr 	if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
48977568150aSgwr 		return (EIO);
48987568150aSgwr 
48997568150aSgwr 	/*
49007568150aSgwr 	 * Our _pathconf indicates _ACL_ACE_ENABLED,
49017568150aSgwr 	 * so we should only see VSA_ACE, etc here.
49027568150aSgwr 	 * Note: vn_create asks for VSA_DFACLCNT,
49037568150aSgwr 	 * and it expects ENOSYS and empty data.
49047568150aSgwr 	 */
49057568150aSgwr 	mask = vsa->vsa_mask & (VSA_ACE | VSA_ACECNT |
49067568150aSgwr 	    VSA_ACE_ACLFLAGS | VSA_ACE_ALLTYPES);
49077568150aSgwr 	if (mask == 0)
49087568150aSgwr 		return (ENOSYS);
49097568150aSgwr 
491002d09e03SGordon Ross 	if (smi->smi_flags & SMI_ACL)
4911bd7c6f51SGordon Ross 		error = smbfs_acl_getvsa(vp, vsa, flag, cr);
491202d09e03SGordon Ross 	else
49137568150aSgwr 		error = ENOSYS;
49147568150aSgwr 
49157568150aSgwr 	if (error == ENOSYS)
49167568150aSgwr 		error = fs_fab_acl(vp, vsa, flag, cr, ct);
49177568150aSgwr 
49187568150aSgwr 	return (error);
49197568150aSgwr }
49207568150aSgwr 
49217568150aSgwr /* ARGSUSED */
49227568150aSgwr static int
smbfs_setsecattr(vnode_t * vp,vsecattr_t * vsa,int flag,cred_t * cr,caller_context_t * ct)49237568150aSgwr smbfs_setsecattr(vnode_t *vp, vsecattr_t *vsa, int flag, cred_t *cr,
49247568150aSgwr 	caller_context_t *ct)
49257568150aSgwr {
49267568150aSgwr 	vfs_t *vfsp;
49277568150aSgwr 	smbmntinfo_t *smi;
49287568150aSgwr 	int	error;
49297568150aSgwr 	uint_t	mask;
49307568150aSgwr 
49317568150aSgwr 	vfsp = vp->v_vfsp;
49327568150aSgwr 	smi = VFTOSMI(vfsp);
49337568150aSgwr 
4934a19609f8Sjv 	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
49357568150aSgwr 		return (EIO);
49367568150aSgwr 
49377568150aSgwr 	if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
49387568150aSgwr 		return (EIO);
49397568150aSgwr 
49407568150aSgwr 	/*
49417568150aSgwr 	 * Our _pathconf indicates _ACL_ACE_ENABLED,
49427568150aSgwr 	 * so we should only see VSA_ACE, etc here.
49437568150aSgwr 	 */
49447568150aSgwr 	mask = vsa->vsa_mask & (VSA_ACE | VSA_ACECNT);
49457568150aSgwr 	if (mask == 0)
49467568150aSgwr 		return (ENOSYS);
49477568150aSgwr 
49487568150aSgwr 	if (vfsp->vfs_flag & VFS_RDONLY)
49497568150aSgwr 		return (EROFS);
49507568150aSgwr 
495102d09e03SGordon Ross 	/*
495202d09e03SGordon Ross 	 * Allow only the mount owner to do this.
495302d09e03SGordon Ross 	 * See comments at smbfs_access_rwx.
495402d09e03SGordon Ross 	 */
495502d09e03SGordon Ross 	error = secpolicy_vnode_setdac(cr, smi->smi_uid);
495602d09e03SGordon Ross 	if (error != 0)
495702d09e03SGordon Ross 		return (error);
495802d09e03SGordon Ross 
495902d09e03SGordon Ross 	if (smi->smi_flags & SMI_ACL)
4960bd7c6f51SGordon Ross 		error = smbfs_acl_setvsa(vp, vsa, flag, cr);
496102d09e03SGordon Ross 	else
49627568150aSgwr 		error = ENOSYS;
49637568150aSgwr 
49647568150aSgwr 	return (error);
49657568150aSgwr }
49664bff34e3Sthurlow 
49674bff34e3Sthurlow 
49684bff34e3Sthurlow /*
49694bff34e3Sthurlow  * XXX
49704bff34e3Sthurlow  * This op should eventually support PSARC 2007/268.
49714bff34e3Sthurlow  */
49724bff34e3Sthurlow static int
smbfs_shrlock(vnode_t * vp,int cmd,struct shrlock * shr,int flag,cred_t * cr,caller_context_t * ct)49734bff34e3Sthurlow smbfs_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr,
49744bff34e3Sthurlow 	caller_context_t *ct)
49754bff34e3Sthurlow {
4976a19609f8Sjv 	if (curproc->p_zone != VTOSMI(vp)->smi_zone_ref.zref_zone)
49774bff34e3Sthurlow 		return (EIO);
49784bff34e3Sthurlow 
49794bff34e3Sthurlow 	if (VTOSMI(vp)->smi_flags & SMI_LLOCK)
49804bff34e3Sthurlow 		return (fs_shrlock(vp, cmd, shr, flag, cr, ct));
49814bff34e3Sthurlow 	else
49824bff34e3Sthurlow 		return (ENOSYS);
49834bff34e3Sthurlow }
49845f4fc069Sjilinxpd 
49855f4fc069Sjilinxpd 
49865f4fc069Sjilinxpd /*
49875f4fc069Sjilinxpd  * Most unimplemented ops will return ENOSYS because of fs_nosys().
49885f4fc069Sjilinxpd  * The only ops where that won't work are ACCESS (due to open(2)
49895f4fc069Sjilinxpd  * failures) and ... (anything else left?)
49905f4fc069Sjilinxpd  */
49915f4fc069Sjilinxpd const fs_operation_def_t smbfs_vnodeops_template[] = {
49925f4fc069Sjilinxpd 	VOPNAME_OPEN,		{ .vop_open = smbfs_open },
49935f4fc069Sjilinxpd 	VOPNAME_CLOSE,		{ .vop_close = smbfs_close },
49945f4fc069Sjilinxpd 	VOPNAME_READ,		{ .vop_read = smbfs_read },
49955f4fc069Sjilinxpd 	VOPNAME_WRITE,		{ .vop_write = smbfs_write },
49965f4fc069Sjilinxpd 	VOPNAME_IOCTL,		{ .vop_ioctl = smbfs_ioctl },
49975f4fc069Sjilinxpd 	VOPNAME_GETATTR,	{ .vop_getattr = smbfs_getattr },
49985f4fc069Sjilinxpd 	VOPNAME_SETATTR,	{ .vop_setattr = smbfs_setattr },
49995f4fc069Sjilinxpd 	VOPNAME_ACCESS,		{ .vop_access = smbfs_access },
50005f4fc069Sjilinxpd 	VOPNAME_LOOKUP,		{ .vop_lookup = smbfs_lookup },
50015f4fc069Sjilinxpd 	VOPNAME_CREATE,		{ .vop_create = smbfs_create },
50025f4fc069Sjilinxpd 	VOPNAME_REMOVE,		{ .vop_remove = smbfs_remove },
50035f4fc069Sjilinxpd 	VOPNAME_LINK,		{ .vop_link = smbfs_link },
50045f4fc069Sjilinxpd 	VOPNAME_RENAME,		{ .vop_rename = smbfs_rename },
50055f4fc069Sjilinxpd 	VOPNAME_MKDIR,		{ .vop_mkdir = smbfs_mkdir },
50065f4fc069Sjilinxpd 	VOPNAME_RMDIR,		{ .vop_rmdir = smbfs_rmdir },
50075f4fc069Sjilinxpd 	VOPNAME_READDIR,	{ .vop_readdir = smbfs_readdir },
50085f4fc069Sjilinxpd 	VOPNAME_SYMLINK,	{ .vop_symlink = smbfs_symlink },
50095f4fc069Sjilinxpd 	VOPNAME_READLINK,	{ .vop_readlink = smbfs_readlink },
50105f4fc069Sjilinxpd 	VOPNAME_FSYNC,		{ .vop_fsync = smbfs_fsync },
50115f4fc069Sjilinxpd 	VOPNAME_INACTIVE,	{ .vop_inactive = smbfs_inactive },
50125f4fc069Sjilinxpd 	VOPNAME_FID,		{ .vop_fid = smbfs_fid },
50135f4fc069Sjilinxpd 	VOPNAME_RWLOCK,		{ .vop_rwlock = smbfs_rwlock },
50145f4fc069Sjilinxpd 	VOPNAME_RWUNLOCK,	{ .vop_rwunlock = smbfs_rwunlock },
50155f4fc069Sjilinxpd 	VOPNAME_SEEK,		{ .vop_seek = smbfs_seek },
50165f4fc069Sjilinxpd 	VOPNAME_FRLOCK,		{ .vop_frlock = smbfs_frlock },
50175f4fc069Sjilinxpd 	VOPNAME_SPACE,		{ .vop_space = smbfs_space },
50185f4fc069Sjilinxpd 	VOPNAME_REALVP,		{ .vop_realvp = smbfs_realvp },
50198329232eSGordon Ross #ifdef	_KERNEL
50205f4fc069Sjilinxpd 	VOPNAME_GETPAGE,	{ .vop_getpage = smbfs_getpage },
50215f4fc069Sjilinxpd 	VOPNAME_PUTPAGE,	{ .vop_putpage = smbfs_putpage },
50225f4fc069Sjilinxpd 	VOPNAME_MAP,		{ .vop_map = smbfs_map },
50235f4fc069Sjilinxpd 	VOPNAME_ADDMAP,		{ .vop_addmap = smbfs_addmap },
50245f4fc069Sjilinxpd 	VOPNAME_DELMAP,		{ .vop_delmap = smbfs_delmap },
50258329232eSGordon Ross #endif	// _KERNEL
50265f4fc069Sjilinxpd 	VOPNAME_PATHCONF,	{ .vop_pathconf = smbfs_pathconf },
50275f4fc069Sjilinxpd 	VOPNAME_SETSECATTR,	{ .vop_setsecattr = smbfs_setsecattr },
50285f4fc069Sjilinxpd 	VOPNAME_GETSECATTR,	{ .vop_getsecattr = smbfs_getsecattr },
50295f4fc069Sjilinxpd 	VOPNAME_SHRLOCK,	{ .vop_shrlock = smbfs_shrlock },
50305f4fc069Sjilinxpd #ifdef	SMBFS_VNEVENT
50315f4fc069Sjilinxpd 	VOPNAME_VNEVENT,	{ .vop_vnevent = fs_vnevent_support },
50325f4fc069Sjilinxpd #endif
50335f4fc069Sjilinxpd 	{ NULL, NULL }
50345f4fc069Sjilinxpd };
5035