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