10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
51610Sthurlow * Common Development and Distribution License (the "License").
61610Sthurlow * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*13002SKaren.Rochford@Sun.COM * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate */
240Sstevel@tonic-gate
250Sstevel@tonic-gate /*
260Sstevel@tonic-gate * Copyright (c) 1983,1984,1985,1986,1987,1988,1989 AT&T.
270Sstevel@tonic-gate * All rights reserved.
280Sstevel@tonic-gate */
290Sstevel@tonic-gate
300Sstevel@tonic-gate #include <sys/param.h>
310Sstevel@tonic-gate #include <sys/types.h>
320Sstevel@tonic-gate #include <sys/systm.h>
330Sstevel@tonic-gate #include <sys/cred.h>
340Sstevel@tonic-gate #include <sys/buf.h>
350Sstevel@tonic-gate #include <sys/vfs.h>
360Sstevel@tonic-gate #include <sys/vnode.h>
370Sstevel@tonic-gate #include <sys/uio.h>
380Sstevel@tonic-gate #include <sys/stat.h>
390Sstevel@tonic-gate #include <sys/errno.h>
400Sstevel@tonic-gate #include <sys/sysmacros.h>
410Sstevel@tonic-gate #include <sys/statvfs.h>
420Sstevel@tonic-gate #include <sys/kmem.h>
430Sstevel@tonic-gate #include <sys/kstat.h>
440Sstevel@tonic-gate #include <sys/dirent.h>
450Sstevel@tonic-gate #include <sys/cmn_err.h>
460Sstevel@tonic-gate #include <sys/debug.h>
470Sstevel@tonic-gate #include <sys/vtrace.h>
480Sstevel@tonic-gate #include <sys/mode.h>
490Sstevel@tonic-gate #include <sys/acl.h>
500Sstevel@tonic-gate #include <sys/nbmlock.h>
510Sstevel@tonic-gate #include <sys/policy.h>
527387SRobert.Gordon@Sun.COM #include <sys/sdt.h>
530Sstevel@tonic-gate
540Sstevel@tonic-gate #include <rpc/types.h>
550Sstevel@tonic-gate #include <rpc/auth.h>
560Sstevel@tonic-gate #include <rpc/svc.h>
570Sstevel@tonic-gate
580Sstevel@tonic-gate #include <nfs/nfs.h>
590Sstevel@tonic-gate #include <nfs/export.h>
607961SNatalie.Li@Sun.COM #include <nfs/nfs_cmd.h>
610Sstevel@tonic-gate
620Sstevel@tonic-gate #include <vm/hat.h>
630Sstevel@tonic-gate #include <vm/as.h>
640Sstevel@tonic-gate #include <vm/seg.h>
650Sstevel@tonic-gate #include <vm/seg_map.h>
660Sstevel@tonic-gate #include <vm/seg_kmem.h>
670Sstevel@tonic-gate
680Sstevel@tonic-gate #include <sys/strsubr.h>
690Sstevel@tonic-gate
700Sstevel@tonic-gate /*
710Sstevel@tonic-gate * These are the interface routines for the server side of the
720Sstevel@tonic-gate * Network File System. See the NFS version 2 protocol specification
730Sstevel@tonic-gate * for a description of this interface.
740Sstevel@tonic-gate */
750Sstevel@tonic-gate
760Sstevel@tonic-gate static int sattr_to_vattr(struct nfssattr *, struct vattr *);
770Sstevel@tonic-gate static void acl_perm(struct vnode *, struct exportinfo *, struct vattr *,
780Sstevel@tonic-gate cred_t *);
790Sstevel@tonic-gate
800Sstevel@tonic-gate /*
810Sstevel@tonic-gate * Some "over the wire" UNIX file types. These are encoded
820Sstevel@tonic-gate * into the mode. This needs to be fixed in the next rev.
830Sstevel@tonic-gate */
840Sstevel@tonic-gate #define IFMT 0170000 /* type of file */
850Sstevel@tonic-gate #define IFCHR 0020000 /* character special */
860Sstevel@tonic-gate #define IFBLK 0060000 /* block special */
870Sstevel@tonic-gate #define IFSOCK 0140000 /* socket */
880Sstevel@tonic-gate
895599Sjwahlig u_longlong_t nfs2_srv_caller_id;
905599Sjwahlig
910Sstevel@tonic-gate /*
920Sstevel@tonic-gate * Get file attributes.
930Sstevel@tonic-gate * Returns the current attributes of the file with the given fhandle.
940Sstevel@tonic-gate */
950Sstevel@tonic-gate /* ARGSUSED */
960Sstevel@tonic-gate void
rfs_getattr(fhandle_t * fhp,struct nfsattrstat * ns,struct exportinfo * exi,struct svc_req * req,cred_t * cr)970Sstevel@tonic-gate rfs_getattr(fhandle_t *fhp, struct nfsattrstat *ns, struct exportinfo *exi,
980Sstevel@tonic-gate struct svc_req *req, cred_t *cr)
990Sstevel@tonic-gate {
1000Sstevel@tonic-gate int error;
1010Sstevel@tonic-gate vnode_t *vp;
1020Sstevel@tonic-gate struct vattr va;
1030Sstevel@tonic-gate
1040Sstevel@tonic-gate vp = nfs_fhtovp(fhp, exi);
1050Sstevel@tonic-gate if (vp == NULL) {
1060Sstevel@tonic-gate ns->ns_status = NFSERR_STALE;
1070Sstevel@tonic-gate return;
1080Sstevel@tonic-gate }
1090Sstevel@tonic-gate
1100Sstevel@tonic-gate /*
1110Sstevel@tonic-gate * Do the getattr.
1120Sstevel@tonic-gate */
1130Sstevel@tonic-gate va.va_mask = AT_ALL; /* we want all the attributes */
1147387SRobert.Gordon@Sun.COM
1150Sstevel@tonic-gate error = rfs4_delegated_getattr(vp, &va, 0, cr);
1160Sstevel@tonic-gate
1170Sstevel@tonic-gate /* check for overflows */
1180Sstevel@tonic-gate if (!error) {
11911291SRobert.Thurlow@Sun.COM /* Lie about the object type for a referral */
12011291SRobert.Thurlow@Sun.COM if (vn_is_nfs_reparse(vp, cr))
12111291SRobert.Thurlow@Sun.COM va.va_type = VLNK;
12211291SRobert.Thurlow@Sun.COM
1230Sstevel@tonic-gate acl_perm(vp, exi, &va, cr);
1240Sstevel@tonic-gate error = vattr_to_nattr(&va, &ns->ns_attr);
1250Sstevel@tonic-gate }
1260Sstevel@tonic-gate
1270Sstevel@tonic-gate VN_RELE(vp);
1280Sstevel@tonic-gate
1290Sstevel@tonic-gate ns->ns_status = puterrno(error);
1300Sstevel@tonic-gate }
1311610Sthurlow void *
rfs_getattr_getfh(fhandle_t * fhp)1320Sstevel@tonic-gate rfs_getattr_getfh(fhandle_t *fhp)
1330Sstevel@tonic-gate {
1340Sstevel@tonic-gate return (fhp);
1350Sstevel@tonic-gate }
1360Sstevel@tonic-gate
1370Sstevel@tonic-gate /*
1380Sstevel@tonic-gate * Set file attributes.
1390Sstevel@tonic-gate * Sets the attributes of the file with the given fhandle. Returns
1400Sstevel@tonic-gate * the new attributes.
1410Sstevel@tonic-gate */
1420Sstevel@tonic-gate void
rfs_setattr(struct nfssaargs * args,struct nfsattrstat * ns,struct exportinfo * exi,struct svc_req * req,cred_t * cr)1430Sstevel@tonic-gate rfs_setattr(struct nfssaargs *args, struct nfsattrstat *ns,
1440Sstevel@tonic-gate struct exportinfo *exi, struct svc_req *req, cred_t *cr)
1450Sstevel@tonic-gate {
1460Sstevel@tonic-gate int error;
1470Sstevel@tonic-gate int flag;
1480Sstevel@tonic-gate int in_crit = 0;
1490Sstevel@tonic-gate vnode_t *vp;
1500Sstevel@tonic-gate struct vattr va;
1510Sstevel@tonic-gate struct vattr bva;
1520Sstevel@tonic-gate struct flock64 bf;
1535599Sjwahlig caller_context_t ct;
1540Sstevel@tonic-gate
1550Sstevel@tonic-gate
1560Sstevel@tonic-gate vp = nfs_fhtovp(&args->saa_fh, exi);
1570Sstevel@tonic-gate if (vp == NULL) {
1580Sstevel@tonic-gate ns->ns_status = NFSERR_STALE;
1590Sstevel@tonic-gate return;
1600Sstevel@tonic-gate }
1610Sstevel@tonic-gate
1620Sstevel@tonic-gate if (rdonly(exi, req) || vn_is_readonly(vp)) {
1630Sstevel@tonic-gate VN_RELE(vp);
1640Sstevel@tonic-gate ns->ns_status = NFSERR_ROFS;
1650Sstevel@tonic-gate return;
1660Sstevel@tonic-gate }
1670Sstevel@tonic-gate
1680Sstevel@tonic-gate error = sattr_to_vattr(&args->saa_sa, &va);
1690Sstevel@tonic-gate if (error) {
1700Sstevel@tonic-gate VN_RELE(vp);
1710Sstevel@tonic-gate ns->ns_status = puterrno(error);
1720Sstevel@tonic-gate return;
1730Sstevel@tonic-gate }
1740Sstevel@tonic-gate
1750Sstevel@tonic-gate /*
1760Sstevel@tonic-gate * If the client is requesting a change to the mtime,
1770Sstevel@tonic-gate * but the nanosecond field is set to 1 billion, then
1780Sstevel@tonic-gate * this is a flag to the server that it should set the
1790Sstevel@tonic-gate * atime and mtime fields to the server's current time.
1800Sstevel@tonic-gate * The 1 billion number actually came from the client
1810Sstevel@tonic-gate * as 1 million, but the units in the over the wire
1820Sstevel@tonic-gate * request are microseconds instead of nanoseconds.
1830Sstevel@tonic-gate *
1840Sstevel@tonic-gate * This is an overload of the protocol and should be
1850Sstevel@tonic-gate * documented in the NFS Version 2 protocol specification.
1860Sstevel@tonic-gate */
1870Sstevel@tonic-gate if (va.va_mask & AT_MTIME) {
1880Sstevel@tonic-gate if (va.va_mtime.tv_nsec == 1000000000) {
1890Sstevel@tonic-gate gethrestime(&va.va_mtime);
1900Sstevel@tonic-gate va.va_atime = va.va_mtime;
1910Sstevel@tonic-gate va.va_mask |= AT_ATIME;
1920Sstevel@tonic-gate flag = 0;
1930Sstevel@tonic-gate } else
1940Sstevel@tonic-gate flag = ATTR_UTIME;
1950Sstevel@tonic-gate } else
1960Sstevel@tonic-gate flag = 0;
1970Sstevel@tonic-gate
1980Sstevel@tonic-gate /*
1990Sstevel@tonic-gate * If the filesystem is exported with nosuid, then mask off
2000Sstevel@tonic-gate * the setuid and setgid bits.
2010Sstevel@tonic-gate */
2020Sstevel@tonic-gate if ((va.va_mask & AT_MODE) && vp->v_type == VREG &&
2030Sstevel@tonic-gate (exi->exi_export.ex_flags & EX_NOSUID))
2040Sstevel@tonic-gate va.va_mode &= ~(VSUID | VSGID);
2050Sstevel@tonic-gate
2065599Sjwahlig ct.cc_sysid = 0;
2075599Sjwahlig ct.cc_pid = 0;
2085599Sjwahlig ct.cc_caller_id = nfs2_srv_caller_id;
2095599Sjwahlig ct.cc_flags = CC_DONTBLOCK;
2105599Sjwahlig
2110Sstevel@tonic-gate /*
2120Sstevel@tonic-gate * We need to specially handle size changes because it is
2130Sstevel@tonic-gate * possible for the client to create a file with modes
2140Sstevel@tonic-gate * which indicate read-only, but with the file opened for
2150Sstevel@tonic-gate * writing. If the client then tries to set the size of
2160Sstevel@tonic-gate * the file, then the normal access checking done in
2170Sstevel@tonic-gate * VOP_SETATTR would prevent the client from doing so,
2180Sstevel@tonic-gate * although it should be legal for it to do so. To get
2190Sstevel@tonic-gate * around this, we do the access checking for ourselves
2200Sstevel@tonic-gate * and then use VOP_SPACE which doesn't do the access
2210Sstevel@tonic-gate * checking which VOP_SETATTR does. VOP_SPACE can only
2220Sstevel@tonic-gate * operate on VREG files, let VOP_SETATTR handle the other
2230Sstevel@tonic-gate * extremely rare cases.
2240Sstevel@tonic-gate * Also the client should not be allowed to change the
2250Sstevel@tonic-gate * size of the file if there is a conflicting non-blocking
2260Sstevel@tonic-gate * mandatory lock in the region of change.
2270Sstevel@tonic-gate */
2280Sstevel@tonic-gate if (vp->v_type == VREG && va.va_mask & AT_SIZE) {
2290Sstevel@tonic-gate if (nbl_need_check(vp)) {
2300Sstevel@tonic-gate nbl_start_crit(vp, RW_READER);
2310Sstevel@tonic-gate in_crit = 1;
2320Sstevel@tonic-gate }
2330Sstevel@tonic-gate
2340Sstevel@tonic-gate bva.va_mask = AT_UID | AT_SIZE;
2357387SRobert.Gordon@Sun.COM
2365599Sjwahlig error = VOP_GETATTR(vp, &bva, 0, cr, &ct);
2377387SRobert.Gordon@Sun.COM
2380Sstevel@tonic-gate if (error) {
2390Sstevel@tonic-gate if (in_crit)
2400Sstevel@tonic-gate nbl_end_crit(vp);
2410Sstevel@tonic-gate VN_RELE(vp);
2420Sstevel@tonic-gate ns->ns_status = puterrno(error);
2430Sstevel@tonic-gate return;
2440Sstevel@tonic-gate }
2450Sstevel@tonic-gate
2460Sstevel@tonic-gate if (in_crit) {
2470Sstevel@tonic-gate u_offset_t offset;
2480Sstevel@tonic-gate ssize_t length;
2490Sstevel@tonic-gate
2500Sstevel@tonic-gate if (va.va_size < bva.va_size) {
2510Sstevel@tonic-gate offset = va.va_size;
2520Sstevel@tonic-gate length = bva.va_size - va.va_size;
2530Sstevel@tonic-gate } else {
2540Sstevel@tonic-gate offset = bva.va_size;
2550Sstevel@tonic-gate length = va.va_size - bva.va_size;
2560Sstevel@tonic-gate }
2575331Samw if (nbl_conflict(vp, NBL_WRITE, offset, length, 0,
2585331Samw NULL)) {
2590Sstevel@tonic-gate error = EACCES;
2600Sstevel@tonic-gate }
2610Sstevel@tonic-gate }
2620Sstevel@tonic-gate
2630Sstevel@tonic-gate if (crgetuid(cr) == bva.va_uid && !error &&
2645050Sjwahlig va.va_size != bva.va_size) {
2650Sstevel@tonic-gate va.va_mask &= ~AT_SIZE;
2660Sstevel@tonic-gate bf.l_type = F_WRLCK;
2670Sstevel@tonic-gate bf.l_whence = 0;
2680Sstevel@tonic-gate bf.l_start = (off64_t)va.va_size;
2690Sstevel@tonic-gate bf.l_len = 0;
2700Sstevel@tonic-gate bf.l_sysid = 0;
2710Sstevel@tonic-gate bf.l_pid = 0;
2727387SRobert.Gordon@Sun.COM
2730Sstevel@tonic-gate error = VOP_SPACE(vp, F_FREESP, &bf, FWRITE,
2745599Sjwahlig (offset_t)va.va_size, cr, &ct);
2750Sstevel@tonic-gate }
2760Sstevel@tonic-gate if (in_crit)
2770Sstevel@tonic-gate nbl_end_crit(vp);
2780Sstevel@tonic-gate } else
2790Sstevel@tonic-gate error = 0;
2800Sstevel@tonic-gate
2810Sstevel@tonic-gate /*
2820Sstevel@tonic-gate * Do the setattr.
2830Sstevel@tonic-gate */
2840Sstevel@tonic-gate if (!error && va.va_mask) {
2855599Sjwahlig error = VOP_SETATTR(vp, &va, flag, cr, &ct);
2860Sstevel@tonic-gate }
2870Sstevel@tonic-gate
2885599Sjwahlig /*
2895599Sjwahlig * check if the monitor on either vop_space or vop_setattr detected
2905599Sjwahlig * a delegation conflict and if so, mark the thread flag as
2915599Sjwahlig * wouldblock so that the response is dropped and the client will
2925599Sjwahlig * try again.
2935599Sjwahlig */
2945599Sjwahlig if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
2955599Sjwahlig VN_RELE(vp);
2965599Sjwahlig curthread->t_flag |= T_WOULDBLOCK;
2975599Sjwahlig return;
2985599Sjwahlig }
2995599Sjwahlig
3000Sstevel@tonic-gate if (!error) {
3010Sstevel@tonic-gate va.va_mask = AT_ALL; /* get everything */
3027387SRobert.Gordon@Sun.COM
3030Sstevel@tonic-gate error = rfs4_delegated_getattr(vp, &va, 0, cr);
3040Sstevel@tonic-gate
3050Sstevel@tonic-gate /* check for overflows */
3060Sstevel@tonic-gate if (!error) {
3070Sstevel@tonic-gate acl_perm(vp, exi, &va, cr);
3080Sstevel@tonic-gate error = vattr_to_nattr(&va, &ns->ns_attr);
3090Sstevel@tonic-gate }
3100Sstevel@tonic-gate }
3110Sstevel@tonic-gate
3125599Sjwahlig ct.cc_flags = 0;
3135599Sjwahlig
3140Sstevel@tonic-gate /*
3150Sstevel@tonic-gate * Force modified metadata out to stable storage.
3160Sstevel@tonic-gate */
3175599Sjwahlig (void) VOP_FSYNC(vp, FNODSYNC, cr, &ct);
3180Sstevel@tonic-gate
3190Sstevel@tonic-gate VN_RELE(vp);
3200Sstevel@tonic-gate
3210Sstevel@tonic-gate ns->ns_status = puterrno(error);
3220Sstevel@tonic-gate }
3231610Sthurlow void *
rfs_setattr_getfh(struct nfssaargs * args)3240Sstevel@tonic-gate rfs_setattr_getfh(struct nfssaargs *args)
3250Sstevel@tonic-gate {
3260Sstevel@tonic-gate return (&args->saa_fh);
3270Sstevel@tonic-gate }
3280Sstevel@tonic-gate
3290Sstevel@tonic-gate /*
3300Sstevel@tonic-gate * Directory lookup.
3310Sstevel@tonic-gate * Returns an fhandle and file attributes for file name in a directory.
3320Sstevel@tonic-gate */
3330Sstevel@tonic-gate /* ARGSUSED */
3340Sstevel@tonic-gate void
rfs_lookup(struct nfsdiropargs * da,struct nfsdiropres * dr,struct exportinfo * exi,struct svc_req * req,cred_t * cr)3350Sstevel@tonic-gate rfs_lookup(struct nfsdiropargs *da, struct nfsdiropres *dr,
3360Sstevel@tonic-gate struct exportinfo *exi, struct svc_req *req, cred_t *cr)
3370Sstevel@tonic-gate {
3380Sstevel@tonic-gate int error;
3390Sstevel@tonic-gate vnode_t *dvp;
3400Sstevel@tonic-gate vnode_t *vp;
3410Sstevel@tonic-gate struct vattr va;
3420Sstevel@tonic-gate fhandle_t *fhp = da->da_fhandle;
3430Sstevel@tonic-gate struct sec_ol sec = {0, 0};
3440Sstevel@tonic-gate bool_t publicfh_flag = FALSE, auth_weak = FALSE;
3457961SNatalie.Li@Sun.COM char *name;
3467961SNatalie.Li@Sun.COM struct sockaddr *ca;
3470Sstevel@tonic-gate
3480Sstevel@tonic-gate /*
3494971Sjarrett * Trusted Extension doesn't support NFSv2. MOUNT
3504971Sjarrett * will reject v2 clients. Need to prevent v2 client
3514971Sjarrett * access via WebNFS here.
3524971Sjarrett */
3534971Sjarrett if (is_system_labeled() && req->rq_vers == 2) {
3544971Sjarrett dr->dr_status = NFSERR_ACCES;
3554971Sjarrett return;
3564971Sjarrett }
3574971Sjarrett
3584971Sjarrett /*
3590Sstevel@tonic-gate * Disallow NULL paths
3600Sstevel@tonic-gate */
3610Sstevel@tonic-gate if (da->da_name == NULL || *da->da_name == '\0') {
3620Sstevel@tonic-gate dr->dr_status = NFSERR_ACCES;
3630Sstevel@tonic-gate return;
3640Sstevel@tonic-gate }
3650Sstevel@tonic-gate
3660Sstevel@tonic-gate /*
3670Sstevel@tonic-gate * Allow lookups from the root - the default
3680Sstevel@tonic-gate * location of the public filehandle.
3690Sstevel@tonic-gate */
3700Sstevel@tonic-gate if (exi != NULL && (exi->exi_export.ex_flags & EX_PUBLIC)) {
3710Sstevel@tonic-gate dvp = rootdir;
3720Sstevel@tonic-gate VN_HOLD(dvp);
3730Sstevel@tonic-gate } else {
3740Sstevel@tonic-gate dvp = nfs_fhtovp(fhp, exi);
3750Sstevel@tonic-gate if (dvp == NULL) {
3760Sstevel@tonic-gate dr->dr_status = NFSERR_STALE;
3770Sstevel@tonic-gate return;
3780Sstevel@tonic-gate }
3790Sstevel@tonic-gate }
3800Sstevel@tonic-gate
3810Sstevel@tonic-gate /*
3820Sstevel@tonic-gate * Not allow lookup beyond root.
3830Sstevel@tonic-gate * If the filehandle matches a filehandle of the exi,
3840Sstevel@tonic-gate * then the ".." refers beyond the root of an exported filesystem.
3850Sstevel@tonic-gate */
3860Sstevel@tonic-gate if (strcmp(da->da_name, "..") == 0 &&
3870Sstevel@tonic-gate EQFID(&exi->exi_fid, (fid_t *)&fhp->fh_len)) {
3880Sstevel@tonic-gate VN_RELE(dvp);
3890Sstevel@tonic-gate dr->dr_status = NFSERR_NOENT;
3900Sstevel@tonic-gate return;
3910Sstevel@tonic-gate }
3920Sstevel@tonic-gate
3937961SNatalie.Li@Sun.COM ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
3947961SNatalie.Li@Sun.COM name = nfscmd_convname(ca, exi, da->da_name, NFSCMD_CONV_INBOUND,
3957961SNatalie.Li@Sun.COM MAXPATHLEN);
3967961SNatalie.Li@Sun.COM
3977961SNatalie.Li@Sun.COM if (name == NULL) {
3987961SNatalie.Li@Sun.COM dr->dr_status = NFSERR_ACCES;
3997961SNatalie.Li@Sun.COM return;
4007961SNatalie.Li@Sun.COM }
4017961SNatalie.Li@Sun.COM
4020Sstevel@tonic-gate /*
4030Sstevel@tonic-gate * If the public filehandle is used then allow
4040Sstevel@tonic-gate * a multi-component lookup, i.e. evaluate
4050Sstevel@tonic-gate * a pathname and follow symbolic links if
4060Sstevel@tonic-gate * necessary.
4070Sstevel@tonic-gate *
4080Sstevel@tonic-gate * This may result in a vnode in another filesystem
4090Sstevel@tonic-gate * which is OK as long as the filesystem is exported.
4100Sstevel@tonic-gate */
4110Sstevel@tonic-gate if (PUBLIC_FH2(fhp)) {
4120Sstevel@tonic-gate publicfh_flag = TRUE;
4137961SNatalie.Li@Sun.COM error = rfs_publicfh_mclookup(name, dvp, cr, &vp, &exi,
4145050Sjwahlig &sec);
4150Sstevel@tonic-gate } else {
4160Sstevel@tonic-gate /*
4170Sstevel@tonic-gate * Do a normal single component lookup.
4180Sstevel@tonic-gate */
4197961SNatalie.Li@Sun.COM error = VOP_LOOKUP(dvp, name, &vp, NULL, 0, NULL, cr,
4205331Samw NULL, NULL, NULL);
4210Sstevel@tonic-gate }
4220Sstevel@tonic-gate
4237961SNatalie.Li@Sun.COM if (name != da->da_name)
4247961SNatalie.Li@Sun.COM kmem_free(name, MAXPATHLEN);
4257961SNatalie.Li@Sun.COM
4267961SNatalie.Li@Sun.COM
4270Sstevel@tonic-gate if (!error) {
4280Sstevel@tonic-gate va.va_mask = AT_ALL; /* we want everything */
4297387SRobert.Gordon@Sun.COM
4300Sstevel@tonic-gate error = rfs4_delegated_getattr(vp, &va, 0, cr);
4317387SRobert.Gordon@Sun.COM
4320Sstevel@tonic-gate /* check for overflows */
4330Sstevel@tonic-gate if (!error) {
4340Sstevel@tonic-gate acl_perm(vp, exi, &va, cr);
4350Sstevel@tonic-gate error = vattr_to_nattr(&va, &dr->dr_attr);
4360Sstevel@tonic-gate if (!error) {
4370Sstevel@tonic-gate if (sec.sec_flags & SEC_QUERY)
4380Sstevel@tonic-gate error = makefh_ol(&dr->dr_fhandle, exi,
4395050Sjwahlig sec.sec_index);
4400Sstevel@tonic-gate else {
4410Sstevel@tonic-gate error = makefh(&dr->dr_fhandle, vp,
4425050Sjwahlig exi);
4430Sstevel@tonic-gate if (!error && publicfh_flag &&
4445050Sjwahlig !chk_clnt_sec(exi, req))
4450Sstevel@tonic-gate auth_weak = TRUE;
4460Sstevel@tonic-gate }
4470Sstevel@tonic-gate }
4480Sstevel@tonic-gate }
4490Sstevel@tonic-gate VN_RELE(vp);
4500Sstevel@tonic-gate }
4510Sstevel@tonic-gate
4520Sstevel@tonic-gate VN_RELE(dvp);
4530Sstevel@tonic-gate
4540Sstevel@tonic-gate /*
4550Sstevel@tonic-gate * If publicfh_flag is true then we have called rfs_publicfh_mclookup
4560Sstevel@tonic-gate * and have obtained a new exportinfo in exi which needs to be
4570Sstevel@tonic-gate * released. Note the the original exportinfo pointed to by exi
4580Sstevel@tonic-gate * will be released by the caller, comon_dispatch.
4590Sstevel@tonic-gate */
4600Sstevel@tonic-gate if (publicfh_flag && exi != NULL)
4610Sstevel@tonic-gate exi_rele(exi);
4620Sstevel@tonic-gate
4630Sstevel@tonic-gate /*
4640Sstevel@tonic-gate * If it's public fh, no 0x81, and client's flavor is
4650Sstevel@tonic-gate * invalid, set WebNFS status to WNFSERR_CLNT_FLAVOR now.
4660Sstevel@tonic-gate * Then set RPC status to AUTH_TOOWEAK in common_dispatch.
4670Sstevel@tonic-gate */
4680Sstevel@tonic-gate if (auth_weak)
4690Sstevel@tonic-gate dr->dr_status = (enum nfsstat)WNFSERR_CLNT_FLAVOR;
4700Sstevel@tonic-gate else
4710Sstevel@tonic-gate dr->dr_status = puterrno(error);
4720Sstevel@tonic-gate }
4731610Sthurlow void *
rfs_lookup_getfh(struct nfsdiropargs * da)4740Sstevel@tonic-gate rfs_lookup_getfh(struct nfsdiropargs *da)
4750Sstevel@tonic-gate {
4760Sstevel@tonic-gate return (da->da_fhandle);
4770Sstevel@tonic-gate }
4780Sstevel@tonic-gate
4790Sstevel@tonic-gate /*
4800Sstevel@tonic-gate * Read symbolic link.
4810Sstevel@tonic-gate * Returns the string in the symbolic link at the given fhandle.
4820Sstevel@tonic-gate */
4830Sstevel@tonic-gate /* ARGSUSED */
4840Sstevel@tonic-gate void
rfs_readlink(fhandle_t * fhp,struct nfsrdlnres * rl,struct exportinfo * exi,struct svc_req * req,cred_t * cr)4850Sstevel@tonic-gate rfs_readlink(fhandle_t *fhp, struct nfsrdlnres *rl, struct exportinfo *exi,
4860Sstevel@tonic-gate struct svc_req *req, cred_t *cr)
4870Sstevel@tonic-gate {
4880Sstevel@tonic-gate int error;
4890Sstevel@tonic-gate struct iovec iov;
4900Sstevel@tonic-gate struct uio uio;
4910Sstevel@tonic-gate vnode_t *vp;
4920Sstevel@tonic-gate struct vattr va;
4937961SNatalie.Li@Sun.COM struct sockaddr *ca;
4947961SNatalie.Li@Sun.COM char *name = NULL;
49511291SRobert.Thurlow@Sun.COM int is_referral = 0;
4960Sstevel@tonic-gate
4970Sstevel@tonic-gate vp = nfs_fhtovp(fhp, exi);
4980Sstevel@tonic-gate if (vp == NULL) {
4990Sstevel@tonic-gate rl->rl_data = NULL;
5000Sstevel@tonic-gate rl->rl_status = NFSERR_STALE;
5010Sstevel@tonic-gate return;
5020Sstevel@tonic-gate }
5030Sstevel@tonic-gate
5040Sstevel@tonic-gate va.va_mask = AT_MODE;
5057387SRobert.Gordon@Sun.COM
5065331Samw error = VOP_GETATTR(vp, &va, 0, cr, NULL);
5070Sstevel@tonic-gate
5080Sstevel@tonic-gate if (error) {
5090Sstevel@tonic-gate VN_RELE(vp);
5100Sstevel@tonic-gate rl->rl_data = NULL;
5110Sstevel@tonic-gate rl->rl_status = puterrno(error);
5120Sstevel@tonic-gate return;
5130Sstevel@tonic-gate }
5140Sstevel@tonic-gate
5150Sstevel@tonic-gate if (MANDLOCK(vp, va.va_mode)) {
5160Sstevel@tonic-gate VN_RELE(vp);
5170Sstevel@tonic-gate rl->rl_data = NULL;
5180Sstevel@tonic-gate rl->rl_status = NFSERR_ACCES;
5190Sstevel@tonic-gate return;
5200Sstevel@tonic-gate }
5210Sstevel@tonic-gate
52211291SRobert.Thurlow@Sun.COM /* We lied about the object type for a referral */
52311291SRobert.Thurlow@Sun.COM if (vn_is_nfs_reparse(vp, cr))
52411291SRobert.Thurlow@Sun.COM is_referral = 1;
52511291SRobert.Thurlow@Sun.COM
5260Sstevel@tonic-gate /*
5270Sstevel@tonic-gate * XNFS and RFC1094 require us to return ENXIO if argument
5280Sstevel@tonic-gate * is not a link. BUGID 1138002.
5290Sstevel@tonic-gate */
53011291SRobert.Thurlow@Sun.COM if (vp->v_type != VLNK && !is_referral) {
5310Sstevel@tonic-gate VN_RELE(vp);
5320Sstevel@tonic-gate rl->rl_data = NULL;
5330Sstevel@tonic-gate rl->rl_status = NFSERR_NXIO;
5340Sstevel@tonic-gate return;
5350Sstevel@tonic-gate }
5360Sstevel@tonic-gate
5370Sstevel@tonic-gate /*
5380Sstevel@tonic-gate * Allocate data for pathname. This will be freed by rfs_rlfree.
5390Sstevel@tonic-gate */
5400Sstevel@tonic-gate rl->rl_data = kmem_alloc(NFS_MAXPATHLEN, KM_SLEEP);
5410Sstevel@tonic-gate
54211291SRobert.Thurlow@Sun.COM if (is_referral) {
54311291SRobert.Thurlow@Sun.COM char *s;
54411291SRobert.Thurlow@Sun.COM size_t strsz;
54511291SRobert.Thurlow@Sun.COM
54611291SRobert.Thurlow@Sun.COM /* Get an artificial symlink based on a referral */
54711291SRobert.Thurlow@Sun.COM s = build_symlink(vp, cr, &strsz);
54811291SRobert.Thurlow@Sun.COM global_svstat_ptr[2][NFS_REFERLINKS].value.ui64++;
54911291SRobert.Thurlow@Sun.COM DTRACE_PROBE2(nfs2serv__func__referral__reflink,
55011291SRobert.Thurlow@Sun.COM vnode_t *, vp, char *, s);
55111291SRobert.Thurlow@Sun.COM if (s == NULL)
55211291SRobert.Thurlow@Sun.COM error = EINVAL;
55311291SRobert.Thurlow@Sun.COM else {
55411291SRobert.Thurlow@Sun.COM error = 0;
55511291SRobert.Thurlow@Sun.COM (void) strlcpy(rl->rl_data, s, NFS_MAXPATHLEN);
55611291SRobert.Thurlow@Sun.COM rl->rl_count = (uint32_t)MIN(strsz, NFS_MAXPATHLEN);
55711291SRobert.Thurlow@Sun.COM kmem_free(s, strsz);
55811291SRobert.Thurlow@Sun.COM }
55911291SRobert.Thurlow@Sun.COM
56011291SRobert.Thurlow@Sun.COM } else {
56111291SRobert.Thurlow@Sun.COM
56211291SRobert.Thurlow@Sun.COM /*
56311291SRobert.Thurlow@Sun.COM * Set up io vector to read sym link data
56411291SRobert.Thurlow@Sun.COM */
56511291SRobert.Thurlow@Sun.COM iov.iov_base = rl->rl_data;
56611291SRobert.Thurlow@Sun.COM iov.iov_len = NFS_MAXPATHLEN;
56711291SRobert.Thurlow@Sun.COM uio.uio_iov = &iov;
56811291SRobert.Thurlow@Sun.COM uio.uio_iovcnt = 1;
56911291SRobert.Thurlow@Sun.COM uio.uio_segflg = UIO_SYSSPACE;
57011291SRobert.Thurlow@Sun.COM uio.uio_extflg = UIO_COPY_CACHED;
57111291SRobert.Thurlow@Sun.COM uio.uio_loffset = (offset_t)0;
57211291SRobert.Thurlow@Sun.COM uio.uio_resid = NFS_MAXPATHLEN;
57311291SRobert.Thurlow@Sun.COM
57411291SRobert.Thurlow@Sun.COM /*
57511291SRobert.Thurlow@Sun.COM * Do the readlink.
57611291SRobert.Thurlow@Sun.COM */
57711291SRobert.Thurlow@Sun.COM error = VOP_READLINK(vp, &uio, cr, NULL);
57811291SRobert.Thurlow@Sun.COM
57911291SRobert.Thurlow@Sun.COM rl->rl_count = (uint32_t)(NFS_MAXPATHLEN - uio.uio_resid);
58011291SRobert.Thurlow@Sun.COM
58111291SRobert.Thurlow@Sun.COM if (!error)
58211291SRobert.Thurlow@Sun.COM rl->rl_data[rl->rl_count] = '\0';
58311291SRobert.Thurlow@Sun.COM
58411291SRobert.Thurlow@Sun.COM }
58511291SRobert.Thurlow@Sun.COM
5860Sstevel@tonic-gate
5870Sstevel@tonic-gate VN_RELE(vp);
5880Sstevel@tonic-gate
5897961SNatalie.Li@Sun.COM ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
5907961SNatalie.Li@Sun.COM name = nfscmd_convname(ca, exi, rl->rl_data,
5917961SNatalie.Li@Sun.COM NFSCMD_CONV_OUTBOUND, MAXPATHLEN);
5927961SNatalie.Li@Sun.COM
5937961SNatalie.Li@Sun.COM if (name != NULL && name != rl->rl_data) {
5947961SNatalie.Li@Sun.COM kmem_free(rl->rl_data, NFS_MAXPATHLEN);
5957961SNatalie.Li@Sun.COM rl->rl_data = name;
5967961SNatalie.Li@Sun.COM }
5970Sstevel@tonic-gate
5980Sstevel@tonic-gate /*
5990Sstevel@tonic-gate * XNFS and RFC1094 require us to return ENXIO if argument
6000Sstevel@tonic-gate * is not a link. UFS returns EINVAL if this is the case,
6010Sstevel@tonic-gate * so we do the mapping here. BUGID 1138002.
6020Sstevel@tonic-gate */
6030Sstevel@tonic-gate if (error == EINVAL)
6040Sstevel@tonic-gate rl->rl_status = NFSERR_NXIO;
6050Sstevel@tonic-gate else
6060Sstevel@tonic-gate rl->rl_status = puterrno(error);
6070Sstevel@tonic-gate
6080Sstevel@tonic-gate }
6091610Sthurlow void *
rfs_readlink_getfh(fhandle_t * fhp)6100Sstevel@tonic-gate rfs_readlink_getfh(fhandle_t *fhp)
6110Sstevel@tonic-gate {
6120Sstevel@tonic-gate return (fhp);
6130Sstevel@tonic-gate }
6140Sstevel@tonic-gate /*
6150Sstevel@tonic-gate * Free data allocated by rfs_readlink
6160Sstevel@tonic-gate */
6170Sstevel@tonic-gate void
rfs_rlfree(struct nfsrdlnres * rl)6180Sstevel@tonic-gate rfs_rlfree(struct nfsrdlnres *rl)
6190Sstevel@tonic-gate {
6200Sstevel@tonic-gate if (rl->rl_data != NULL)
6210Sstevel@tonic-gate kmem_free(rl->rl_data, NFS_MAXPATHLEN);
6220Sstevel@tonic-gate }
6230Sstevel@tonic-gate
6247387SRobert.Gordon@Sun.COM static int rdma_setup_read_data2(struct nfsreadargs *, struct nfsrdresult *);
6257387SRobert.Gordon@Sun.COM
6260Sstevel@tonic-gate /*
6270Sstevel@tonic-gate * Read data.
6280Sstevel@tonic-gate * Returns some data read from the file at the given fhandle.
6290Sstevel@tonic-gate */
6300Sstevel@tonic-gate /* ARGSUSED */
6310Sstevel@tonic-gate void
rfs_read(struct nfsreadargs * ra,struct nfsrdresult * rr,struct exportinfo * exi,struct svc_req * req,cred_t * cr)6320Sstevel@tonic-gate rfs_read(struct nfsreadargs *ra, struct nfsrdresult *rr,
6330Sstevel@tonic-gate struct exportinfo *exi, struct svc_req *req, cred_t *cr)
6340Sstevel@tonic-gate {
6350Sstevel@tonic-gate vnode_t *vp;
6360Sstevel@tonic-gate int error;
6370Sstevel@tonic-gate struct vattr va;
6380Sstevel@tonic-gate struct iovec iov;
6390Sstevel@tonic-gate struct uio uio;
6400Sstevel@tonic-gate mblk_t *mp;
6410Sstevel@tonic-gate int alloc_err = 0;
6420Sstevel@tonic-gate int in_crit = 0;
6435599Sjwahlig caller_context_t ct;
6440Sstevel@tonic-gate
6450Sstevel@tonic-gate vp = nfs_fhtovp(&ra->ra_fhandle, exi);
6460Sstevel@tonic-gate if (vp == NULL) {
6470Sstevel@tonic-gate rr->rr_data = NULL;
6480Sstevel@tonic-gate rr->rr_status = NFSERR_STALE;
6490Sstevel@tonic-gate return;
6500Sstevel@tonic-gate }
6510Sstevel@tonic-gate
6520Sstevel@tonic-gate if (vp->v_type != VREG) {
6530Sstevel@tonic-gate VN_RELE(vp);
6540Sstevel@tonic-gate rr->rr_data = NULL;
6550Sstevel@tonic-gate rr->rr_status = NFSERR_ISDIR;
6560Sstevel@tonic-gate return;
6570Sstevel@tonic-gate }
6580Sstevel@tonic-gate
6595599Sjwahlig ct.cc_sysid = 0;
6605599Sjwahlig ct.cc_pid = 0;
6615599Sjwahlig ct.cc_caller_id = nfs2_srv_caller_id;
6625599Sjwahlig ct.cc_flags = CC_DONTBLOCK;
6630Sstevel@tonic-gate
6640Sstevel@tonic-gate /*
6650Sstevel@tonic-gate * Enter the critical region before calling VOP_RWLOCK
6660Sstevel@tonic-gate * to avoid a deadlock with write requests.
6670Sstevel@tonic-gate */
6680Sstevel@tonic-gate if (nbl_need_check(vp)) {
6690Sstevel@tonic-gate nbl_start_crit(vp, RW_READER);
6700Sstevel@tonic-gate if (nbl_conflict(vp, NBL_READ, ra->ra_offset, ra->ra_count,
6715331Samw 0, NULL)) {
6720Sstevel@tonic-gate nbl_end_crit(vp);
6730Sstevel@tonic-gate VN_RELE(vp);
6740Sstevel@tonic-gate rr->rr_data = NULL;
6750Sstevel@tonic-gate rr->rr_status = NFSERR_ACCES;
6760Sstevel@tonic-gate return;
6770Sstevel@tonic-gate }
6780Sstevel@tonic-gate in_crit = 1;
6790Sstevel@tonic-gate }
6800Sstevel@tonic-gate
6815599Sjwahlig error = VOP_RWLOCK(vp, V_WRITELOCK_FALSE, &ct);
6820Sstevel@tonic-gate
6835599Sjwahlig /* check if a monitor detected a delegation conflict */
6845599Sjwahlig if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
6855599Sjwahlig VN_RELE(vp);
6865599Sjwahlig /* mark as wouldblock so response is dropped */
6875599Sjwahlig curthread->t_flag |= T_WOULDBLOCK;
6887387SRobert.Gordon@Sun.COM
6895599Sjwahlig rr->rr_data = NULL;
6905599Sjwahlig return;
6915599Sjwahlig }
6925599Sjwahlig
6930Sstevel@tonic-gate va.va_mask = AT_ALL;
6947387SRobert.Gordon@Sun.COM
6955599Sjwahlig error = VOP_GETATTR(vp, &va, 0, cr, &ct);
6960Sstevel@tonic-gate
6970Sstevel@tonic-gate if (error) {
6985599Sjwahlig VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
6990Sstevel@tonic-gate if (in_crit)
7000Sstevel@tonic-gate nbl_end_crit(vp);
7017387SRobert.Gordon@Sun.COM
7020Sstevel@tonic-gate VN_RELE(vp);
7030Sstevel@tonic-gate rr->rr_data = NULL;
7040Sstevel@tonic-gate rr->rr_status = puterrno(error);
7057387SRobert.Gordon@Sun.COM
7060Sstevel@tonic-gate return;
7070Sstevel@tonic-gate }
7080Sstevel@tonic-gate
7090Sstevel@tonic-gate /*
7100Sstevel@tonic-gate * This is a kludge to allow reading of files created
7110Sstevel@tonic-gate * with no read permission. The owner of the file
7120Sstevel@tonic-gate * is always allowed to read it.
7130Sstevel@tonic-gate */
7140Sstevel@tonic-gate if (crgetuid(cr) != va.va_uid) {
7155599Sjwahlig error = VOP_ACCESS(vp, VREAD, 0, cr, &ct);
7167387SRobert.Gordon@Sun.COM
7170Sstevel@tonic-gate if (error) {
7180Sstevel@tonic-gate /*
7190Sstevel@tonic-gate * Exec is the same as read over the net because
7200Sstevel@tonic-gate * of demand loading.
7210Sstevel@tonic-gate */
7225599Sjwahlig error = VOP_ACCESS(vp, VEXEC, 0, cr, &ct);
7230Sstevel@tonic-gate }
7240Sstevel@tonic-gate if (error) {
7255599Sjwahlig VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
7260Sstevel@tonic-gate if (in_crit)
7270Sstevel@tonic-gate nbl_end_crit(vp);
7280Sstevel@tonic-gate VN_RELE(vp);
7290Sstevel@tonic-gate rr->rr_data = NULL;
7300Sstevel@tonic-gate rr->rr_status = puterrno(error);
7317387SRobert.Gordon@Sun.COM
7320Sstevel@tonic-gate return;
7330Sstevel@tonic-gate }
7340Sstevel@tonic-gate }
7350Sstevel@tonic-gate
7360Sstevel@tonic-gate if (MANDLOCK(vp, va.va_mode)) {
7375599Sjwahlig VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
7380Sstevel@tonic-gate if (in_crit)
7390Sstevel@tonic-gate nbl_end_crit(vp);
7407387SRobert.Gordon@Sun.COM
7410Sstevel@tonic-gate VN_RELE(vp);
7420Sstevel@tonic-gate rr->rr_data = NULL;
7430Sstevel@tonic-gate rr->rr_status = NFSERR_ACCES;
7447387SRobert.Gordon@Sun.COM
7450Sstevel@tonic-gate return;
7460Sstevel@tonic-gate }
7470Sstevel@tonic-gate
7487387SRobert.Gordon@Sun.COM rr->rr_ok.rrok_wlist_len = 0;
7497387SRobert.Gordon@Sun.COM rr->rr_ok.rrok_wlist = NULL;
7507387SRobert.Gordon@Sun.COM
7510Sstevel@tonic-gate if ((u_offset_t)ra->ra_offset >= va.va_size) {
7520Sstevel@tonic-gate rr->rr_count = 0;
7530Sstevel@tonic-gate rr->rr_data = NULL;
7540Sstevel@tonic-gate /*
7550Sstevel@tonic-gate * In this case, status is NFS_OK, but there is no data
7560Sstevel@tonic-gate * to encode. So set rr_mp to NULL.
7570Sstevel@tonic-gate */
7580Sstevel@tonic-gate rr->rr_mp = NULL;
7599348SSiddheshwar.Mahesh@Sun.COM rr->rr_ok.rrok_wlist = ra->ra_wlist;
7609348SSiddheshwar.Mahesh@Sun.COM if (rr->rr_ok.rrok_wlist)
7619348SSiddheshwar.Mahesh@Sun.COM clist_zero_len(rr->rr_ok.rrok_wlist);
7620Sstevel@tonic-gate goto done;
7630Sstevel@tonic-gate }
7640Sstevel@tonic-gate
7657387SRobert.Gordon@Sun.COM if (ra->ra_wlist) {
7667387SRobert.Gordon@Sun.COM mp = NULL;
7677387SRobert.Gordon@Sun.COM rr->rr_mp = NULL;
7687387SRobert.Gordon@Sun.COM (void) rdma_get_wchunk(req, &iov, ra->ra_wlist);
769*13002SKaren.Rochford@Sun.COM if (ra->ra_count > iov.iov_len) {
770*13002SKaren.Rochford@Sun.COM rr->rr_data = NULL;
771*13002SKaren.Rochford@Sun.COM rr->rr_status = NFSERR_INVAL;
772*13002SKaren.Rochford@Sun.COM goto done;
773*13002SKaren.Rochford@Sun.COM }
7747387SRobert.Gordon@Sun.COM } else {
7757387SRobert.Gordon@Sun.COM /*
7767387SRobert.Gordon@Sun.COM * mp will contain the data to be sent out in the read reply.
7777387SRobert.Gordon@Sun.COM * This will be freed after the reply has been sent out (by the
7787387SRobert.Gordon@Sun.COM * driver).
7797387SRobert.Gordon@Sun.COM * Let's roundup the data to a BYTES_PER_XDR_UNIT multiple, so
7807387SRobert.Gordon@Sun.COM * that the call to xdrmblk_putmblk() never fails.
7817387SRobert.Gordon@Sun.COM */
7827387SRobert.Gordon@Sun.COM mp = allocb_wait(RNDUP(ra->ra_count), BPRI_MED, STR_NOSIG,
7837387SRobert.Gordon@Sun.COM &alloc_err);
7847387SRobert.Gordon@Sun.COM ASSERT(mp != NULL);
7857387SRobert.Gordon@Sun.COM ASSERT(alloc_err == 0);
7867387SRobert.Gordon@Sun.COM
7877387SRobert.Gordon@Sun.COM rr->rr_mp = mp;
7887387SRobert.Gordon@Sun.COM
7897387SRobert.Gordon@Sun.COM /*
7907387SRobert.Gordon@Sun.COM * Set up io vector
7917387SRobert.Gordon@Sun.COM */
7927387SRobert.Gordon@Sun.COM iov.iov_base = (caddr_t)mp->b_datap->db_base;
7937387SRobert.Gordon@Sun.COM iov.iov_len = ra->ra_count;
7947387SRobert.Gordon@Sun.COM }
7957387SRobert.Gordon@Sun.COM
7960Sstevel@tonic-gate uio.uio_iov = &iov;
7970Sstevel@tonic-gate uio.uio_iovcnt = 1;
7980Sstevel@tonic-gate uio.uio_segflg = UIO_SYSSPACE;
7990Sstevel@tonic-gate uio.uio_extflg = UIO_COPY_CACHED;
8000Sstevel@tonic-gate uio.uio_loffset = (offset_t)ra->ra_offset;
8010Sstevel@tonic-gate uio.uio_resid = ra->ra_count;
8020Sstevel@tonic-gate
8035599Sjwahlig error = VOP_READ(vp, &uio, 0, cr, &ct);
8040Sstevel@tonic-gate
8050Sstevel@tonic-gate if (error) {
8067387SRobert.Gordon@Sun.COM if (mp)
8077387SRobert.Gordon@Sun.COM freeb(mp);
8085599Sjwahlig
8095599Sjwahlig /*
8105599Sjwahlig * check if a monitor detected a delegation conflict and
8115599Sjwahlig * mark as wouldblock so response is dropped
8125599Sjwahlig */
8135599Sjwahlig if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK))
8145599Sjwahlig curthread->t_flag |= T_WOULDBLOCK;
8155599Sjwahlig else
8165599Sjwahlig rr->rr_status = puterrno(error);
8175599Sjwahlig
8185599Sjwahlig VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
8190Sstevel@tonic-gate if (in_crit)
8200Sstevel@tonic-gate nbl_end_crit(vp);
8217387SRobert.Gordon@Sun.COM
8220Sstevel@tonic-gate VN_RELE(vp);
8230Sstevel@tonic-gate rr->rr_data = NULL;
8247387SRobert.Gordon@Sun.COM
8250Sstevel@tonic-gate return;
8260Sstevel@tonic-gate }
8270Sstevel@tonic-gate
8280Sstevel@tonic-gate /*
8290Sstevel@tonic-gate * Get attributes again so we can send the latest access
8300Sstevel@tonic-gate * time to the client side for his cache.
8310Sstevel@tonic-gate */
8320Sstevel@tonic-gate va.va_mask = AT_ALL;
8337387SRobert.Gordon@Sun.COM
8345599Sjwahlig error = VOP_GETATTR(vp, &va, 0, cr, &ct);
8357387SRobert.Gordon@Sun.COM
8360Sstevel@tonic-gate if (error) {
8377387SRobert.Gordon@Sun.COM if (mp)
8387387SRobert.Gordon@Sun.COM freeb(mp);
8397387SRobert.Gordon@Sun.COM
8405599Sjwahlig VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
8410Sstevel@tonic-gate if (in_crit)
8420Sstevel@tonic-gate nbl_end_crit(vp);
8437387SRobert.Gordon@Sun.COM
8440Sstevel@tonic-gate VN_RELE(vp);
8450Sstevel@tonic-gate rr->rr_data = NULL;
8460Sstevel@tonic-gate rr->rr_status = puterrno(error);
8477387SRobert.Gordon@Sun.COM
8480Sstevel@tonic-gate return;
8490Sstevel@tonic-gate }
8500Sstevel@tonic-gate
8510Sstevel@tonic-gate rr->rr_count = (uint32_t)(ra->ra_count - uio.uio_resid);
8520Sstevel@tonic-gate
8537387SRobert.Gordon@Sun.COM if (mp) {
8547387SRobert.Gordon@Sun.COM rr->rr_data = (char *)mp->b_datap->db_base;
8557387SRobert.Gordon@Sun.COM } else {
8567387SRobert.Gordon@Sun.COM if (ra->ra_wlist) {
8577387SRobert.Gordon@Sun.COM rr->rr_data = (caddr_t)iov.iov_base;
8587387SRobert.Gordon@Sun.COM if (!rdma_setup_read_data2(ra, rr)) {
8597387SRobert.Gordon@Sun.COM rr->rr_data = NULL;
8607387SRobert.Gordon@Sun.COM rr->rr_status = puterrno(NFSERR_INVAL);
8617387SRobert.Gordon@Sun.COM }
8627387SRobert.Gordon@Sun.COM }
8637387SRobert.Gordon@Sun.COM }
8640Sstevel@tonic-gate done:
8655599Sjwahlig VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
8660Sstevel@tonic-gate if (in_crit)
8670Sstevel@tonic-gate nbl_end_crit(vp);
8680Sstevel@tonic-gate
8690Sstevel@tonic-gate acl_perm(vp, exi, &va, cr);
8700Sstevel@tonic-gate
8710Sstevel@tonic-gate /* check for overflows */
8720Sstevel@tonic-gate error = vattr_to_nattr(&va, &rr->rr_attr);
8730Sstevel@tonic-gate
8740Sstevel@tonic-gate VN_RELE(vp);
8750Sstevel@tonic-gate
8760Sstevel@tonic-gate rr->rr_status = puterrno(error);
8770Sstevel@tonic-gate }
8780Sstevel@tonic-gate
8790Sstevel@tonic-gate /*
8800Sstevel@tonic-gate * Free data allocated by rfs_read
8810Sstevel@tonic-gate */
8820Sstevel@tonic-gate void
rfs_rdfree(struct nfsrdresult * rr)8830Sstevel@tonic-gate rfs_rdfree(struct nfsrdresult *rr)
8840Sstevel@tonic-gate {
8850Sstevel@tonic-gate mblk_t *mp;
8860Sstevel@tonic-gate
8870Sstevel@tonic-gate if (rr->rr_status == NFS_OK) {
8880Sstevel@tonic-gate mp = rr->rr_mp;
8890Sstevel@tonic-gate if (mp != NULL)
8900Sstevel@tonic-gate freeb(mp);
8910Sstevel@tonic-gate }
8920Sstevel@tonic-gate }
8930Sstevel@tonic-gate
8941610Sthurlow void *
rfs_read_getfh(struct nfsreadargs * ra)8950Sstevel@tonic-gate rfs_read_getfh(struct nfsreadargs *ra)
8960Sstevel@tonic-gate {
8970Sstevel@tonic-gate return (&ra->ra_fhandle);
8980Sstevel@tonic-gate }
8990Sstevel@tonic-gate
9000Sstevel@tonic-gate #define MAX_IOVECS 12
9010Sstevel@tonic-gate
9020Sstevel@tonic-gate #ifdef DEBUG
9030Sstevel@tonic-gate static int rfs_write_sync_hits = 0;
9040Sstevel@tonic-gate static int rfs_write_sync_misses = 0;
9050Sstevel@tonic-gate #endif
9060Sstevel@tonic-gate
9070Sstevel@tonic-gate /*
9080Sstevel@tonic-gate * Write data to file.
9090Sstevel@tonic-gate * Returns attributes of a file after writing some data to it.
9100Sstevel@tonic-gate *
9110Sstevel@tonic-gate * Any changes made here, especially in error handling might have
9120Sstevel@tonic-gate * to also be done in rfs_write (which clusters write requests).
9130Sstevel@tonic-gate */
9140Sstevel@tonic-gate void
rfs_write_sync(struct nfswriteargs * wa,struct nfsattrstat * ns,struct exportinfo * exi,struct svc_req * req,cred_t * cr)9150Sstevel@tonic-gate rfs_write_sync(struct nfswriteargs *wa, struct nfsattrstat *ns,
9160Sstevel@tonic-gate struct exportinfo *exi, struct svc_req *req, cred_t *cr)
9170Sstevel@tonic-gate {
9180Sstevel@tonic-gate int error;
9190Sstevel@tonic-gate vnode_t *vp;
9200Sstevel@tonic-gate rlim64_t rlimit;
9210Sstevel@tonic-gate struct vattr va;
9220Sstevel@tonic-gate struct uio uio;
9230Sstevel@tonic-gate struct iovec iov[MAX_IOVECS];
9240Sstevel@tonic-gate mblk_t *m;
9250Sstevel@tonic-gate struct iovec *iovp;
9260Sstevel@tonic-gate int iovcnt;
9270Sstevel@tonic-gate cred_t *savecred;
9280Sstevel@tonic-gate int in_crit = 0;
9295599Sjwahlig caller_context_t ct;
9300Sstevel@tonic-gate
9310Sstevel@tonic-gate vp = nfs_fhtovp(&wa->wa_fhandle, exi);
9320Sstevel@tonic-gate if (vp == NULL) {
9330Sstevel@tonic-gate ns->ns_status = NFSERR_STALE;
9340Sstevel@tonic-gate return;
9350Sstevel@tonic-gate }
9360Sstevel@tonic-gate
9370Sstevel@tonic-gate if (rdonly(exi, req)) {
9380Sstevel@tonic-gate VN_RELE(vp);
9390Sstevel@tonic-gate ns->ns_status = NFSERR_ROFS;
9400Sstevel@tonic-gate return;
9410Sstevel@tonic-gate }
9420Sstevel@tonic-gate
9430Sstevel@tonic-gate if (vp->v_type != VREG) {
9440Sstevel@tonic-gate VN_RELE(vp);
9450Sstevel@tonic-gate ns->ns_status = NFSERR_ISDIR;
9460Sstevel@tonic-gate return;
9470Sstevel@tonic-gate }
9480Sstevel@tonic-gate
9495599Sjwahlig ct.cc_sysid = 0;
9505599Sjwahlig ct.cc_pid = 0;
9515599Sjwahlig ct.cc_caller_id = nfs2_srv_caller_id;
9525599Sjwahlig ct.cc_flags = CC_DONTBLOCK;
9530Sstevel@tonic-gate
9540Sstevel@tonic-gate va.va_mask = AT_UID|AT_MODE;
9557387SRobert.Gordon@Sun.COM
9565599Sjwahlig error = VOP_GETATTR(vp, &va, 0, cr, &ct);
9570Sstevel@tonic-gate
9580Sstevel@tonic-gate if (error) {
9590Sstevel@tonic-gate VN_RELE(vp);
9600Sstevel@tonic-gate ns->ns_status = puterrno(error);
9617387SRobert.Gordon@Sun.COM
9620Sstevel@tonic-gate return;
9630Sstevel@tonic-gate }
9640Sstevel@tonic-gate
9650Sstevel@tonic-gate if (crgetuid(cr) != va.va_uid) {
9660Sstevel@tonic-gate /*
9670Sstevel@tonic-gate * This is a kludge to allow writes of files created
9680Sstevel@tonic-gate * with read only permission. The owner of the file
9690Sstevel@tonic-gate * is always allowed to write it.
9700Sstevel@tonic-gate */
9715599Sjwahlig error = VOP_ACCESS(vp, VWRITE, 0, cr, &ct);
9727387SRobert.Gordon@Sun.COM
9730Sstevel@tonic-gate if (error) {
9740Sstevel@tonic-gate VN_RELE(vp);
9750Sstevel@tonic-gate ns->ns_status = puterrno(error);
9760Sstevel@tonic-gate return;
9770Sstevel@tonic-gate }
9780Sstevel@tonic-gate }
9790Sstevel@tonic-gate
9800Sstevel@tonic-gate /*
9810Sstevel@tonic-gate * Can't access a mandatory lock file. This might cause
9820Sstevel@tonic-gate * the NFS service thread to block forever waiting for a
9830Sstevel@tonic-gate * lock to be released that will never be released.
9840Sstevel@tonic-gate */
9850Sstevel@tonic-gate if (MANDLOCK(vp, va.va_mode)) {
9860Sstevel@tonic-gate VN_RELE(vp);
9870Sstevel@tonic-gate ns->ns_status = NFSERR_ACCES;
9880Sstevel@tonic-gate return;
9890Sstevel@tonic-gate }
9900Sstevel@tonic-gate
9910Sstevel@tonic-gate /*
9920Sstevel@tonic-gate * We have to enter the critical region before calling VOP_RWLOCK
9930Sstevel@tonic-gate * to avoid a deadlock with ufs.
9940Sstevel@tonic-gate */
9950Sstevel@tonic-gate if (nbl_need_check(vp)) {
9960Sstevel@tonic-gate nbl_start_crit(vp, RW_READER);
9970Sstevel@tonic-gate in_crit = 1;
9980Sstevel@tonic-gate if (nbl_conflict(vp, NBL_WRITE, wa->wa_offset,
9995331Samw wa->wa_count, 0, NULL)) {
10000Sstevel@tonic-gate error = EACCES;
10010Sstevel@tonic-gate goto out;
10020Sstevel@tonic-gate }
10030Sstevel@tonic-gate }
10040Sstevel@tonic-gate
10055599Sjwahlig error = VOP_RWLOCK(vp, V_WRITELOCK_TRUE, &ct);
10060Sstevel@tonic-gate
10075599Sjwahlig /* check if a monitor detected a delegation conflict */
10085599Sjwahlig if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
10095599Sjwahlig VN_RELE(vp);
10105599Sjwahlig /* mark as wouldblock so response is dropped */
10115599Sjwahlig curthread->t_flag |= T_WOULDBLOCK;
10125599Sjwahlig return;
10135599Sjwahlig }
10145599Sjwahlig
10157387SRobert.Gordon@Sun.COM if (wa->wa_data || wa->wa_rlist) {
10167387SRobert.Gordon@Sun.COM /* Do the RDMA thing if necessary */
10177387SRobert.Gordon@Sun.COM if (wa->wa_rlist) {
10187387SRobert.Gordon@Sun.COM iov[0].iov_base = (char *)((wa->wa_rlist)->u.c_daddr3);
10197387SRobert.Gordon@Sun.COM iov[0].iov_len = wa->wa_count;
10207387SRobert.Gordon@Sun.COM } else {
10217387SRobert.Gordon@Sun.COM iov[0].iov_base = wa->wa_data;
10227387SRobert.Gordon@Sun.COM iov[0].iov_len = wa->wa_count;
10237387SRobert.Gordon@Sun.COM }
10240Sstevel@tonic-gate uio.uio_iov = iov;
10250Sstevel@tonic-gate uio.uio_iovcnt = 1;
10260Sstevel@tonic-gate uio.uio_segflg = UIO_SYSSPACE;
10270Sstevel@tonic-gate uio.uio_extflg = UIO_COPY_DEFAULT;
10280Sstevel@tonic-gate uio.uio_loffset = (offset_t)wa->wa_offset;
10290Sstevel@tonic-gate uio.uio_resid = wa->wa_count;
10300Sstevel@tonic-gate /*
10310Sstevel@tonic-gate * The limit is checked on the client. We
10320Sstevel@tonic-gate * should allow any size writes here.
10330Sstevel@tonic-gate */
10340Sstevel@tonic-gate uio.uio_llimit = curproc->p_fsz_ctl;
10350Sstevel@tonic-gate rlimit = uio.uio_llimit - wa->wa_offset;
10360Sstevel@tonic-gate if (rlimit < (rlim64_t)uio.uio_resid)
10370Sstevel@tonic-gate uio.uio_resid = (uint_t)rlimit;
10380Sstevel@tonic-gate
10390Sstevel@tonic-gate /*
10400Sstevel@tonic-gate * for now we assume no append mode
10410Sstevel@tonic-gate */
10420Sstevel@tonic-gate /*
10430Sstevel@tonic-gate * We're changing creds because VM may fault and we need
10440Sstevel@tonic-gate * the cred of the current thread to be used if quota
10450Sstevel@tonic-gate * checking is enabled.
10460Sstevel@tonic-gate */
10470Sstevel@tonic-gate savecred = curthread->t_cred;
10480Sstevel@tonic-gate curthread->t_cred = cr;
10495599Sjwahlig error = VOP_WRITE(vp, &uio, FSYNC, cr, &ct);
10500Sstevel@tonic-gate curthread->t_cred = savecred;
10510Sstevel@tonic-gate } else {
10520Sstevel@tonic-gate iovcnt = 0;
10530Sstevel@tonic-gate for (m = wa->wa_mblk; m != NULL; m = m->b_cont)
10540Sstevel@tonic-gate iovcnt++;
10550Sstevel@tonic-gate if (iovcnt <= MAX_IOVECS) {
10560Sstevel@tonic-gate #ifdef DEBUG
10570Sstevel@tonic-gate rfs_write_sync_hits++;
10580Sstevel@tonic-gate #endif
10590Sstevel@tonic-gate iovp = iov;
10600Sstevel@tonic-gate } else {
10610Sstevel@tonic-gate #ifdef DEBUG
10620Sstevel@tonic-gate rfs_write_sync_misses++;
10630Sstevel@tonic-gate #endif
10640Sstevel@tonic-gate iovp = kmem_alloc(sizeof (*iovp) * iovcnt, KM_SLEEP);
10650Sstevel@tonic-gate }
10660Sstevel@tonic-gate mblk_to_iov(wa->wa_mblk, iovcnt, iovp);
10670Sstevel@tonic-gate uio.uio_iov = iovp;
10680Sstevel@tonic-gate uio.uio_iovcnt = iovcnt;
10690Sstevel@tonic-gate uio.uio_segflg = UIO_SYSSPACE;
10700Sstevel@tonic-gate uio.uio_extflg = UIO_COPY_DEFAULT;
10710Sstevel@tonic-gate uio.uio_loffset = (offset_t)wa->wa_offset;
10720Sstevel@tonic-gate uio.uio_resid = wa->wa_count;
10730Sstevel@tonic-gate /*
10740Sstevel@tonic-gate * The limit is checked on the client. We
10750Sstevel@tonic-gate * should allow any size writes here.
10760Sstevel@tonic-gate */
10770Sstevel@tonic-gate uio.uio_llimit = curproc->p_fsz_ctl;
10780Sstevel@tonic-gate rlimit = uio.uio_llimit - wa->wa_offset;
10790Sstevel@tonic-gate if (rlimit < (rlim64_t)uio.uio_resid)
10800Sstevel@tonic-gate uio.uio_resid = (uint_t)rlimit;
10810Sstevel@tonic-gate
10820Sstevel@tonic-gate /*
10830Sstevel@tonic-gate * For now we assume no append mode.
10840Sstevel@tonic-gate */
10850Sstevel@tonic-gate /*
10860Sstevel@tonic-gate * We're changing creds because VM may fault and we need
10870Sstevel@tonic-gate * the cred of the current thread to be used if quota
10880Sstevel@tonic-gate * checking is enabled.
10890Sstevel@tonic-gate */
10900Sstevel@tonic-gate savecred = curthread->t_cred;
10910Sstevel@tonic-gate curthread->t_cred = cr;
10925599Sjwahlig error = VOP_WRITE(vp, &uio, FSYNC, cr, &ct);
10930Sstevel@tonic-gate curthread->t_cred = savecred;
10940Sstevel@tonic-gate
10950Sstevel@tonic-gate if (iovp != iov)
10960Sstevel@tonic-gate kmem_free(iovp, sizeof (*iovp) * iovcnt);
10970Sstevel@tonic-gate }
10980Sstevel@tonic-gate
10995599Sjwahlig VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, &ct);
11000Sstevel@tonic-gate
11010Sstevel@tonic-gate if (!error) {
11020Sstevel@tonic-gate /*
11030Sstevel@tonic-gate * Get attributes again so we send the latest mod
11040Sstevel@tonic-gate * time to the client side for his cache.
11050Sstevel@tonic-gate */
11060Sstevel@tonic-gate va.va_mask = AT_ALL; /* now we want everything */
11077387SRobert.Gordon@Sun.COM
11085599Sjwahlig error = VOP_GETATTR(vp, &va, 0, cr, &ct);
11097387SRobert.Gordon@Sun.COM
11100Sstevel@tonic-gate /* check for overflows */
11110Sstevel@tonic-gate if (!error) {
11120Sstevel@tonic-gate acl_perm(vp, exi, &va, cr);
11130Sstevel@tonic-gate error = vattr_to_nattr(&va, &ns->ns_attr);
11140Sstevel@tonic-gate }
11150Sstevel@tonic-gate }
11160Sstevel@tonic-gate
11170Sstevel@tonic-gate out:
11180Sstevel@tonic-gate if (in_crit)
11190Sstevel@tonic-gate nbl_end_crit(vp);
11200Sstevel@tonic-gate VN_RELE(vp);
11210Sstevel@tonic-gate
11225599Sjwahlig /* check if a monitor detected a delegation conflict */
11235599Sjwahlig if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK))
11245599Sjwahlig /* mark as wouldblock so response is dropped */
11255599Sjwahlig curthread->t_flag |= T_WOULDBLOCK;
11265599Sjwahlig else
11275599Sjwahlig ns->ns_status = puterrno(error);
11280Sstevel@tonic-gate
11290Sstevel@tonic-gate }
11300Sstevel@tonic-gate
11310Sstevel@tonic-gate struct rfs_async_write {
11320Sstevel@tonic-gate struct nfswriteargs *wa;
11330Sstevel@tonic-gate struct nfsattrstat *ns;
11340Sstevel@tonic-gate struct svc_req *req;
11350Sstevel@tonic-gate cred_t *cr;
11360Sstevel@tonic-gate kthread_t *thread;
11370Sstevel@tonic-gate struct rfs_async_write *list;
11380Sstevel@tonic-gate };
11390Sstevel@tonic-gate
11400Sstevel@tonic-gate struct rfs_async_write_list {
11410Sstevel@tonic-gate fhandle_t *fhp;
11420Sstevel@tonic-gate kcondvar_t cv;
11430Sstevel@tonic-gate struct rfs_async_write *list;
11440Sstevel@tonic-gate struct rfs_async_write_list *next;
11450Sstevel@tonic-gate };
11460Sstevel@tonic-gate
11470Sstevel@tonic-gate static struct rfs_async_write_list *rfs_async_write_head = NULL;
11480Sstevel@tonic-gate static kmutex_t rfs_async_write_lock;
11490Sstevel@tonic-gate static int rfs_write_async = 1; /* enables write clustering if == 1 */
11500Sstevel@tonic-gate
11510Sstevel@tonic-gate #define MAXCLIOVECS 42
11520Sstevel@tonic-gate #define RFSWRITE_INITVAL (enum nfsstat) -1
11530Sstevel@tonic-gate
11540Sstevel@tonic-gate #ifdef DEBUG
11550Sstevel@tonic-gate static int rfs_write_hits = 0;
11560Sstevel@tonic-gate static int rfs_write_misses = 0;
11570Sstevel@tonic-gate #endif
11580Sstevel@tonic-gate
11590Sstevel@tonic-gate /*
11600Sstevel@tonic-gate * Write data to file.
11610Sstevel@tonic-gate * Returns attributes of a file after writing some data to it.
11620Sstevel@tonic-gate */
11630Sstevel@tonic-gate void
rfs_write(struct nfswriteargs * wa,struct nfsattrstat * ns,struct exportinfo * exi,struct svc_req * req,cred_t * cr)11640Sstevel@tonic-gate rfs_write(struct nfswriteargs *wa, struct nfsattrstat *ns,
11650Sstevel@tonic-gate struct exportinfo *exi, struct svc_req *req, cred_t *cr)
11660Sstevel@tonic-gate {
11670Sstevel@tonic-gate int error;
11680Sstevel@tonic-gate vnode_t *vp;
11690Sstevel@tonic-gate rlim64_t rlimit;
11700Sstevel@tonic-gate struct vattr va;
11710Sstevel@tonic-gate struct uio uio;
11720Sstevel@tonic-gate struct rfs_async_write_list *lp;
11730Sstevel@tonic-gate struct rfs_async_write_list *nlp;
11740Sstevel@tonic-gate struct rfs_async_write *rp;
11750Sstevel@tonic-gate struct rfs_async_write *nrp;
11760Sstevel@tonic-gate struct rfs_async_write *trp;
11770Sstevel@tonic-gate struct rfs_async_write *lrp;
11780Sstevel@tonic-gate int data_written;
11790Sstevel@tonic-gate int iovcnt;
11800Sstevel@tonic-gate mblk_t *m;
11810Sstevel@tonic-gate struct iovec *iovp;
11820Sstevel@tonic-gate struct iovec *niovp;
11830Sstevel@tonic-gate struct iovec iov[MAXCLIOVECS];
11840Sstevel@tonic-gate int count;
11850Sstevel@tonic-gate int rcount;
11860Sstevel@tonic-gate uint_t off;
11870Sstevel@tonic-gate uint_t len;
11880Sstevel@tonic-gate struct rfs_async_write nrpsp;
11890Sstevel@tonic-gate struct rfs_async_write_list nlpsp;
11900Sstevel@tonic-gate ushort_t t_flag;
11910Sstevel@tonic-gate cred_t *savecred;
11920Sstevel@tonic-gate int in_crit = 0;
11935599Sjwahlig caller_context_t ct;
11940Sstevel@tonic-gate
11950Sstevel@tonic-gate if (!rfs_write_async) {
11960Sstevel@tonic-gate rfs_write_sync(wa, ns, exi, req, cr);
11970Sstevel@tonic-gate return;
11980Sstevel@tonic-gate }
11990Sstevel@tonic-gate
12000Sstevel@tonic-gate /*
12010Sstevel@tonic-gate * Initialize status to RFSWRITE_INITVAL instead of 0, since value of 0
12020Sstevel@tonic-gate * is considered an OK.
12030Sstevel@tonic-gate */
12040Sstevel@tonic-gate ns->ns_status = RFSWRITE_INITVAL;
12050Sstevel@tonic-gate
12060Sstevel@tonic-gate nrp = &nrpsp;
12070Sstevel@tonic-gate nrp->wa = wa;
12080Sstevel@tonic-gate nrp->ns = ns;
12090Sstevel@tonic-gate nrp->req = req;
12100Sstevel@tonic-gate nrp->cr = cr;
12110Sstevel@tonic-gate nrp->thread = curthread;
12120Sstevel@tonic-gate
12130Sstevel@tonic-gate ASSERT(curthread->t_schedflag & TS_DONT_SWAP);
12140Sstevel@tonic-gate
12150Sstevel@tonic-gate /*
12160Sstevel@tonic-gate * Look to see if there is already a cluster started
12170Sstevel@tonic-gate * for this file.
12180Sstevel@tonic-gate */
12190Sstevel@tonic-gate mutex_enter(&rfs_async_write_lock);
12200Sstevel@tonic-gate for (lp = rfs_async_write_head; lp != NULL; lp = lp->next) {
12210Sstevel@tonic-gate if (bcmp(&wa->wa_fhandle, lp->fhp,
12220Sstevel@tonic-gate sizeof (fhandle_t)) == 0)
12230Sstevel@tonic-gate break;
12240Sstevel@tonic-gate }
12250Sstevel@tonic-gate
12260Sstevel@tonic-gate /*
12270Sstevel@tonic-gate * If lp is non-NULL, then there is already a cluster
12280Sstevel@tonic-gate * started. We need to place ourselves in the cluster
12290Sstevel@tonic-gate * list in the right place as determined by starting
12300Sstevel@tonic-gate * offset. Conflicts with non-blocking mandatory locked
12310Sstevel@tonic-gate * regions will be checked when the cluster is processed.
12320Sstevel@tonic-gate */
12330Sstevel@tonic-gate if (lp != NULL) {
12340Sstevel@tonic-gate rp = lp->list;
12350Sstevel@tonic-gate trp = NULL;
12360Sstevel@tonic-gate while (rp != NULL && rp->wa->wa_offset < wa->wa_offset) {
12370Sstevel@tonic-gate trp = rp;
12380Sstevel@tonic-gate rp = rp->list;
12390Sstevel@tonic-gate }
12400Sstevel@tonic-gate nrp->list = rp;
12410Sstevel@tonic-gate if (trp == NULL)
12420Sstevel@tonic-gate lp->list = nrp;
12430Sstevel@tonic-gate else
12440Sstevel@tonic-gate trp->list = nrp;
12450Sstevel@tonic-gate while (nrp->ns->ns_status == RFSWRITE_INITVAL)
12460Sstevel@tonic-gate cv_wait(&lp->cv, &rfs_async_write_lock);
12470Sstevel@tonic-gate mutex_exit(&rfs_async_write_lock);
12487387SRobert.Gordon@Sun.COM
12490Sstevel@tonic-gate return;
12500Sstevel@tonic-gate }
12510Sstevel@tonic-gate
12520Sstevel@tonic-gate /*
12530Sstevel@tonic-gate * No cluster started yet, start one and add ourselves
12540Sstevel@tonic-gate * to the list of clusters.
12550Sstevel@tonic-gate */
12560Sstevel@tonic-gate nrp->list = NULL;
12570Sstevel@tonic-gate
12580Sstevel@tonic-gate nlp = &nlpsp;
12590Sstevel@tonic-gate nlp->fhp = &wa->wa_fhandle;
12600Sstevel@tonic-gate cv_init(&nlp->cv, NULL, CV_DEFAULT, NULL);
12610Sstevel@tonic-gate nlp->list = nrp;
12620Sstevel@tonic-gate nlp->next = NULL;
12630Sstevel@tonic-gate
12640Sstevel@tonic-gate if (rfs_async_write_head == NULL) {
12650Sstevel@tonic-gate rfs_async_write_head = nlp;
12660Sstevel@tonic-gate } else {
12670Sstevel@tonic-gate lp = rfs_async_write_head;
12680Sstevel@tonic-gate while (lp->next != NULL)
12690Sstevel@tonic-gate lp = lp->next;
12700Sstevel@tonic-gate lp->next = nlp;
12710Sstevel@tonic-gate }
12720Sstevel@tonic-gate mutex_exit(&rfs_async_write_lock);
12730Sstevel@tonic-gate
12740Sstevel@tonic-gate /*
12750Sstevel@tonic-gate * Convert the file handle common to all of the requests
12760Sstevel@tonic-gate * in this cluster to a vnode.
12770Sstevel@tonic-gate */
12780Sstevel@tonic-gate vp = nfs_fhtovp(&wa->wa_fhandle, exi);
12790Sstevel@tonic-gate if (vp == NULL) {
12800Sstevel@tonic-gate mutex_enter(&rfs_async_write_lock);
12810Sstevel@tonic-gate if (rfs_async_write_head == nlp)
12820Sstevel@tonic-gate rfs_async_write_head = nlp->next;
12830Sstevel@tonic-gate else {
12840Sstevel@tonic-gate lp = rfs_async_write_head;
12850Sstevel@tonic-gate while (lp->next != nlp)
12860Sstevel@tonic-gate lp = lp->next;
12870Sstevel@tonic-gate lp->next = nlp->next;
12880Sstevel@tonic-gate }
12890Sstevel@tonic-gate t_flag = curthread->t_flag & T_WOULDBLOCK;
12900Sstevel@tonic-gate for (rp = nlp->list; rp != NULL; rp = rp->list) {
12910Sstevel@tonic-gate rp->ns->ns_status = NFSERR_STALE;
12920Sstevel@tonic-gate rp->thread->t_flag |= t_flag;
12930Sstevel@tonic-gate }
12940Sstevel@tonic-gate cv_broadcast(&nlp->cv);
12950Sstevel@tonic-gate mutex_exit(&rfs_async_write_lock);
12967387SRobert.Gordon@Sun.COM
12970Sstevel@tonic-gate return;
12980Sstevel@tonic-gate }
12990Sstevel@tonic-gate
13000Sstevel@tonic-gate /*
13010Sstevel@tonic-gate * Can only write regular files. Attempts to write any
13020Sstevel@tonic-gate * other file types fail with EISDIR.
13030Sstevel@tonic-gate */
13040Sstevel@tonic-gate if (vp->v_type != VREG) {
13050Sstevel@tonic-gate VN_RELE(vp);
13060Sstevel@tonic-gate mutex_enter(&rfs_async_write_lock);
13070Sstevel@tonic-gate if (rfs_async_write_head == nlp)
13080Sstevel@tonic-gate rfs_async_write_head = nlp->next;
13090Sstevel@tonic-gate else {
13100Sstevel@tonic-gate lp = rfs_async_write_head;
13110Sstevel@tonic-gate while (lp->next != nlp)
13120Sstevel@tonic-gate lp = lp->next;
13130Sstevel@tonic-gate lp->next = nlp->next;
13140Sstevel@tonic-gate }
13150Sstevel@tonic-gate t_flag = curthread->t_flag & T_WOULDBLOCK;
13160Sstevel@tonic-gate for (rp = nlp->list; rp != NULL; rp = rp->list) {
13170Sstevel@tonic-gate rp->ns->ns_status = NFSERR_ISDIR;
13180Sstevel@tonic-gate rp->thread->t_flag |= t_flag;
13190Sstevel@tonic-gate }
13200Sstevel@tonic-gate cv_broadcast(&nlp->cv);
13210Sstevel@tonic-gate mutex_exit(&rfs_async_write_lock);
13227387SRobert.Gordon@Sun.COM
13230Sstevel@tonic-gate return;
13240Sstevel@tonic-gate }
13250Sstevel@tonic-gate
13260Sstevel@tonic-gate /*
13270Sstevel@tonic-gate * Enter the critical region before calling VOP_RWLOCK, to avoid a
13280Sstevel@tonic-gate * deadlock with ufs.
13290Sstevel@tonic-gate */
13300Sstevel@tonic-gate if (nbl_need_check(vp)) {
13310Sstevel@tonic-gate nbl_start_crit(vp, RW_READER);
13320Sstevel@tonic-gate in_crit = 1;
13330Sstevel@tonic-gate }
13340Sstevel@tonic-gate
13355599Sjwahlig ct.cc_sysid = 0;
13365599Sjwahlig ct.cc_pid = 0;
13375599Sjwahlig ct.cc_caller_id = nfs2_srv_caller_id;
13385599Sjwahlig ct.cc_flags = CC_DONTBLOCK;
13395599Sjwahlig
13400Sstevel@tonic-gate /*
13410Sstevel@tonic-gate * Lock the file for writing. This operation provides
13420Sstevel@tonic-gate * the delay which allows clusters to grow.
13430Sstevel@tonic-gate */
13445599Sjwahlig error = VOP_RWLOCK(vp, V_WRITELOCK_TRUE, &ct);
13450Sstevel@tonic-gate
13465599Sjwahlig /* check if a monitor detected a delegation conflict */
13475599Sjwahlig if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
13489075SNagakiran.Rajashekar@Sun.COM if (in_crit)
13499075SNagakiran.Rajashekar@Sun.COM nbl_end_crit(vp);
13505599Sjwahlig VN_RELE(vp);
13515599Sjwahlig /* mark as wouldblock so response is dropped */
13525599Sjwahlig curthread->t_flag |= T_WOULDBLOCK;
13535599Sjwahlig mutex_enter(&rfs_async_write_lock);
13549075SNagakiran.Rajashekar@Sun.COM if (rfs_async_write_head == nlp)
13559075SNagakiran.Rajashekar@Sun.COM rfs_async_write_head = nlp->next;
13569075SNagakiran.Rajashekar@Sun.COM else {
13579075SNagakiran.Rajashekar@Sun.COM lp = rfs_async_write_head;
13589075SNagakiran.Rajashekar@Sun.COM while (lp->next != nlp)
13599075SNagakiran.Rajashekar@Sun.COM lp = lp->next;
13609075SNagakiran.Rajashekar@Sun.COM lp->next = nlp->next;
13619075SNagakiran.Rajashekar@Sun.COM }
13625599Sjwahlig for (rp = nlp->list; rp != NULL; rp = rp->list) {
13635599Sjwahlig if (rp->ns->ns_status == RFSWRITE_INITVAL) {
13645599Sjwahlig rp->ns->ns_status = puterrno(error);
13655599Sjwahlig rp->thread->t_flag |= T_WOULDBLOCK;
13665599Sjwahlig }
13675599Sjwahlig }
13685599Sjwahlig cv_broadcast(&nlp->cv);
13695599Sjwahlig mutex_exit(&rfs_async_write_lock);
13707387SRobert.Gordon@Sun.COM
13715599Sjwahlig return;
13725599Sjwahlig }
13735599Sjwahlig
13740Sstevel@tonic-gate /*
13750Sstevel@tonic-gate * Disconnect this cluster from the list of clusters.
13760Sstevel@tonic-gate * The cluster that is being dealt with must be fixed
13770Sstevel@tonic-gate * in size after this point, so there is no reason
13780Sstevel@tonic-gate * to leave it on the list so that new requests can
13790Sstevel@tonic-gate * find it.
13800Sstevel@tonic-gate *
13810Sstevel@tonic-gate * The algorithm is that the first write request will
13820Sstevel@tonic-gate * create a cluster, convert the file handle to a
13830Sstevel@tonic-gate * vnode pointer, and then lock the file for writing.
13840Sstevel@tonic-gate * This request is not likely to be clustered with
13850Sstevel@tonic-gate * any others. However, the next request will create
13860Sstevel@tonic-gate * a new cluster and be blocked in VOP_RWLOCK while
13870Sstevel@tonic-gate * the first request is being processed. This delay
13880Sstevel@tonic-gate * will allow more requests to be clustered in this
13890Sstevel@tonic-gate * second cluster.
13900Sstevel@tonic-gate */
13910Sstevel@tonic-gate mutex_enter(&rfs_async_write_lock);
13920Sstevel@tonic-gate if (rfs_async_write_head == nlp)
13930Sstevel@tonic-gate rfs_async_write_head = nlp->next;
13940Sstevel@tonic-gate else {
13950Sstevel@tonic-gate lp = rfs_async_write_head;
13960Sstevel@tonic-gate while (lp->next != nlp)
13970Sstevel@tonic-gate lp = lp->next;
13980Sstevel@tonic-gate lp->next = nlp->next;
13990Sstevel@tonic-gate }
14000Sstevel@tonic-gate mutex_exit(&rfs_async_write_lock);
14010Sstevel@tonic-gate
14020Sstevel@tonic-gate /*
14030Sstevel@tonic-gate * Step through the list of requests in this cluster.
14040Sstevel@tonic-gate * We need to check permissions to make sure that all
14050Sstevel@tonic-gate * of the requests have sufficient permission to write
14060Sstevel@tonic-gate * the file. A cluster can be composed of requests
14070Sstevel@tonic-gate * from different clients and different users on each
14080Sstevel@tonic-gate * client.
14090Sstevel@tonic-gate *
14100Sstevel@tonic-gate * As a side effect, we also calculate the size of the
14110Sstevel@tonic-gate * byte range that this cluster encompasses.
14120Sstevel@tonic-gate */
14130Sstevel@tonic-gate rp = nlp->list;
14140Sstevel@tonic-gate off = rp->wa->wa_offset;
14150Sstevel@tonic-gate len = (uint_t)0;
14160Sstevel@tonic-gate do {
14170Sstevel@tonic-gate if (rdonly(exi, rp->req)) {
14180Sstevel@tonic-gate rp->ns->ns_status = NFSERR_ROFS;
14190Sstevel@tonic-gate t_flag = curthread->t_flag & T_WOULDBLOCK;
14200Sstevel@tonic-gate rp->thread->t_flag |= t_flag;
14210Sstevel@tonic-gate continue;
14220Sstevel@tonic-gate }
14230Sstevel@tonic-gate
14240Sstevel@tonic-gate va.va_mask = AT_UID|AT_MODE;
14257387SRobert.Gordon@Sun.COM
14265599Sjwahlig error = VOP_GETATTR(vp, &va, 0, rp->cr, &ct);
14277387SRobert.Gordon@Sun.COM
14280Sstevel@tonic-gate if (!error) {
14290Sstevel@tonic-gate if (crgetuid(rp->cr) != va.va_uid) {
14300Sstevel@tonic-gate /*
14310Sstevel@tonic-gate * This is a kludge to allow writes of files
14320Sstevel@tonic-gate * created with read only permission. The
14330Sstevel@tonic-gate * owner of the file is always allowed to
14340Sstevel@tonic-gate * write it.
14350Sstevel@tonic-gate */
14365599Sjwahlig error = VOP_ACCESS(vp, VWRITE, 0, rp->cr, &ct);
14370Sstevel@tonic-gate }
14380Sstevel@tonic-gate if (!error && MANDLOCK(vp, va.va_mode))
14390Sstevel@tonic-gate error = EACCES;
14400Sstevel@tonic-gate }
14410Sstevel@tonic-gate
14420Sstevel@tonic-gate /*
14430Sstevel@tonic-gate * Check for a conflict with a nbmand-locked region.
14440Sstevel@tonic-gate */
14450Sstevel@tonic-gate if (in_crit && nbl_conflict(vp, NBL_WRITE, rp->wa->wa_offset,
14465331Samw rp->wa->wa_count, 0, NULL)) {
14470Sstevel@tonic-gate error = EACCES;
14480Sstevel@tonic-gate }
14490Sstevel@tonic-gate
14500Sstevel@tonic-gate if (error) {
14510Sstevel@tonic-gate rp->ns->ns_status = puterrno(error);
14520Sstevel@tonic-gate t_flag = curthread->t_flag & T_WOULDBLOCK;
14530Sstevel@tonic-gate rp->thread->t_flag |= t_flag;
14540Sstevel@tonic-gate continue;
14550Sstevel@tonic-gate }
14560Sstevel@tonic-gate if (len < rp->wa->wa_offset + rp->wa->wa_count - off)
14570Sstevel@tonic-gate len = rp->wa->wa_offset + rp->wa->wa_count - off;
14580Sstevel@tonic-gate } while ((rp = rp->list) != NULL);
14590Sstevel@tonic-gate
14600Sstevel@tonic-gate /*
14610Sstevel@tonic-gate * Step through the cluster attempting to gather as many
14620Sstevel@tonic-gate * requests which are contiguous as possible. These
14630Sstevel@tonic-gate * contiguous requests are handled via one call to VOP_WRITE
14640Sstevel@tonic-gate * instead of different calls to VOP_WRITE. We also keep
14650Sstevel@tonic-gate * track of the fact that any data was written.
14660Sstevel@tonic-gate */
14670Sstevel@tonic-gate rp = nlp->list;
14680Sstevel@tonic-gate data_written = 0;
14690Sstevel@tonic-gate do {
14700Sstevel@tonic-gate /*
14710Sstevel@tonic-gate * Skip any requests which are already marked as having an
14720Sstevel@tonic-gate * error.
14730Sstevel@tonic-gate */
14740Sstevel@tonic-gate if (rp->ns->ns_status != RFSWRITE_INITVAL) {
14750Sstevel@tonic-gate rp = rp->list;
14760Sstevel@tonic-gate continue;
14770Sstevel@tonic-gate }
14780Sstevel@tonic-gate
14790Sstevel@tonic-gate /*
14800Sstevel@tonic-gate * Count the number of iovec's which are required
14810Sstevel@tonic-gate * to handle this set of requests. One iovec is
14820Sstevel@tonic-gate * needed for each data buffer, whether addressed
14830Sstevel@tonic-gate * by wa_data or by the b_rptr pointers in the
14840Sstevel@tonic-gate * mblk chains.
14850Sstevel@tonic-gate */
14860Sstevel@tonic-gate iovcnt = 0;
14870Sstevel@tonic-gate lrp = rp;
14880Sstevel@tonic-gate for (;;) {
14897387SRobert.Gordon@Sun.COM if (lrp->wa->wa_data || lrp->wa->wa_rlist)
14900Sstevel@tonic-gate iovcnt++;
14910Sstevel@tonic-gate else {
14920Sstevel@tonic-gate m = lrp->wa->wa_mblk;
14930Sstevel@tonic-gate while (m != NULL) {
14940Sstevel@tonic-gate iovcnt++;
14950Sstevel@tonic-gate m = m->b_cont;
14960Sstevel@tonic-gate }
14970Sstevel@tonic-gate }
14980Sstevel@tonic-gate if (lrp->list == NULL ||
14990Sstevel@tonic-gate lrp->list->ns->ns_status != RFSWRITE_INITVAL ||
15000Sstevel@tonic-gate lrp->wa->wa_offset + lrp->wa->wa_count !=
15010Sstevel@tonic-gate lrp->list->wa->wa_offset) {
15020Sstevel@tonic-gate lrp = lrp->list;
15030Sstevel@tonic-gate break;
15040Sstevel@tonic-gate }
15050Sstevel@tonic-gate lrp = lrp->list;
15060Sstevel@tonic-gate }
15070Sstevel@tonic-gate
15080Sstevel@tonic-gate if (iovcnt <= MAXCLIOVECS) {
15090Sstevel@tonic-gate #ifdef DEBUG
15100Sstevel@tonic-gate rfs_write_hits++;
15110Sstevel@tonic-gate #endif
15120Sstevel@tonic-gate niovp = iov;
15130Sstevel@tonic-gate } else {
15140Sstevel@tonic-gate #ifdef DEBUG
15150Sstevel@tonic-gate rfs_write_misses++;
15160Sstevel@tonic-gate #endif
15170Sstevel@tonic-gate niovp = kmem_alloc(sizeof (*niovp) * iovcnt, KM_SLEEP);
15180Sstevel@tonic-gate }
15190Sstevel@tonic-gate /*
15200Sstevel@tonic-gate * Put together the scatter/gather iovecs.
15210Sstevel@tonic-gate */
15220Sstevel@tonic-gate iovp = niovp;
15230Sstevel@tonic-gate trp = rp;
15240Sstevel@tonic-gate count = 0;
15250Sstevel@tonic-gate do {
15267387SRobert.Gordon@Sun.COM if (trp->wa->wa_data || trp->wa->wa_rlist) {
15277387SRobert.Gordon@Sun.COM if (trp->wa->wa_rlist) {
15287387SRobert.Gordon@Sun.COM iovp->iov_base =
15297387SRobert.Gordon@Sun.COM (char *)((trp->wa->wa_rlist)->
15307387SRobert.Gordon@Sun.COM u.c_daddr3);
15317387SRobert.Gordon@Sun.COM iovp->iov_len = trp->wa->wa_count;
15327387SRobert.Gordon@Sun.COM } else {
15337387SRobert.Gordon@Sun.COM iovp->iov_base = trp->wa->wa_data;
15347387SRobert.Gordon@Sun.COM iovp->iov_len = trp->wa->wa_count;
15357387SRobert.Gordon@Sun.COM }
15360Sstevel@tonic-gate iovp++;
15370Sstevel@tonic-gate } else {
15380Sstevel@tonic-gate m = trp->wa->wa_mblk;
15390Sstevel@tonic-gate rcount = trp->wa->wa_count;
15400Sstevel@tonic-gate while (m != NULL) {
15410Sstevel@tonic-gate iovp->iov_base = (caddr_t)m->b_rptr;
15420Sstevel@tonic-gate iovp->iov_len = (m->b_wptr - m->b_rptr);
15430Sstevel@tonic-gate rcount -= iovp->iov_len;
15440Sstevel@tonic-gate if (rcount < 0)
15450Sstevel@tonic-gate iovp->iov_len += rcount;
15460Sstevel@tonic-gate iovp++;
15470Sstevel@tonic-gate if (rcount <= 0)
15480Sstevel@tonic-gate break;
15490Sstevel@tonic-gate m = m->b_cont;
15500Sstevel@tonic-gate }
15510Sstevel@tonic-gate }
15520Sstevel@tonic-gate count += trp->wa->wa_count;
15530Sstevel@tonic-gate trp = trp->list;
15540Sstevel@tonic-gate } while (trp != lrp);
15550Sstevel@tonic-gate
15560Sstevel@tonic-gate uio.uio_iov = niovp;
15570Sstevel@tonic-gate uio.uio_iovcnt = iovcnt;
15580Sstevel@tonic-gate uio.uio_segflg = UIO_SYSSPACE;
15590Sstevel@tonic-gate uio.uio_extflg = UIO_COPY_DEFAULT;
15600Sstevel@tonic-gate uio.uio_loffset = (offset_t)rp->wa->wa_offset;
15610Sstevel@tonic-gate uio.uio_resid = count;
15620Sstevel@tonic-gate /*
15630Sstevel@tonic-gate * The limit is checked on the client. We
15640Sstevel@tonic-gate * should allow any size writes here.
15650Sstevel@tonic-gate */
15660Sstevel@tonic-gate uio.uio_llimit = curproc->p_fsz_ctl;
15670Sstevel@tonic-gate rlimit = uio.uio_llimit - rp->wa->wa_offset;
15680Sstevel@tonic-gate if (rlimit < (rlim64_t)uio.uio_resid)
15690Sstevel@tonic-gate uio.uio_resid = (uint_t)rlimit;
15700Sstevel@tonic-gate
15710Sstevel@tonic-gate /*
15720Sstevel@tonic-gate * For now we assume no append mode.
15730Sstevel@tonic-gate */
15740Sstevel@tonic-gate
15750Sstevel@tonic-gate /*
15765599Sjwahlig * We're changing creds because VM may fault
15775599Sjwahlig * and we need the cred of the current
15785599Sjwahlig * thread to be used if quota * checking is
15795599Sjwahlig * enabled.
15800Sstevel@tonic-gate */
15815599Sjwahlig savecred = curthread->t_cred;
15825599Sjwahlig curthread->t_cred = cr;
15835599Sjwahlig error = VOP_WRITE(vp, &uio, 0, rp->cr, &ct);
15845599Sjwahlig curthread->t_cred = savecred;
15855599Sjwahlig
15865599Sjwahlig /* check if a monitor detected a delegation conflict */
15875599Sjwahlig if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK))
15885599Sjwahlig /* mark as wouldblock so response is dropped */
15890Sstevel@tonic-gate curthread->t_flag |= T_WOULDBLOCK;
15900Sstevel@tonic-gate
15910Sstevel@tonic-gate if (niovp != iov)
15920Sstevel@tonic-gate kmem_free(niovp, sizeof (*niovp) * iovcnt);
15930Sstevel@tonic-gate
15940Sstevel@tonic-gate if (!error) {
15950Sstevel@tonic-gate data_written = 1;
15960Sstevel@tonic-gate /*
15970Sstevel@tonic-gate * Get attributes again so we send the latest mod
15980Sstevel@tonic-gate * time to the client side for his cache.
15990Sstevel@tonic-gate */
16000Sstevel@tonic-gate va.va_mask = AT_ALL; /* now we want everything */
16017387SRobert.Gordon@Sun.COM
16025599Sjwahlig error = VOP_GETATTR(vp, &va, 0, rp->cr, &ct);
16037387SRobert.Gordon@Sun.COM
16040Sstevel@tonic-gate if (!error)
16050Sstevel@tonic-gate acl_perm(vp, exi, &va, rp->cr);
16060Sstevel@tonic-gate }
16070Sstevel@tonic-gate
16080Sstevel@tonic-gate /*
16090Sstevel@tonic-gate * Fill in the status responses for each request
16100Sstevel@tonic-gate * which was just handled. Also, copy the latest
16110Sstevel@tonic-gate * attributes in to the attribute responses if
16120Sstevel@tonic-gate * appropriate.
16130Sstevel@tonic-gate */
16140Sstevel@tonic-gate t_flag = curthread->t_flag & T_WOULDBLOCK;
16150Sstevel@tonic-gate do {
16160Sstevel@tonic-gate rp->thread->t_flag |= t_flag;
16170Sstevel@tonic-gate /* check for overflows */
16180Sstevel@tonic-gate if (!error) {
16190Sstevel@tonic-gate error = vattr_to_nattr(&va, &rp->ns->ns_attr);
16200Sstevel@tonic-gate }
16210Sstevel@tonic-gate rp->ns->ns_status = puterrno(error);
16220Sstevel@tonic-gate rp = rp->list;
16230Sstevel@tonic-gate } while (rp != lrp);
16240Sstevel@tonic-gate } while (rp != NULL);
16250Sstevel@tonic-gate
16260Sstevel@tonic-gate /*
16270Sstevel@tonic-gate * If any data was written at all, then we need to flush
16280Sstevel@tonic-gate * the data and metadata to stable storage.
16290Sstevel@tonic-gate */
16300Sstevel@tonic-gate if (data_written) {
16315599Sjwahlig error = VOP_PUTPAGE(vp, (u_offset_t)off, len, 0, cr, &ct);
16327387SRobert.Gordon@Sun.COM
16330Sstevel@tonic-gate if (!error) {
16345599Sjwahlig error = VOP_FSYNC(vp, FNODSYNC, cr, &ct);
16350Sstevel@tonic-gate }
16360Sstevel@tonic-gate }
16370Sstevel@tonic-gate
16385599Sjwahlig VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, &ct);
16390Sstevel@tonic-gate
16400Sstevel@tonic-gate if (in_crit)
16410Sstevel@tonic-gate nbl_end_crit(vp);
16420Sstevel@tonic-gate VN_RELE(vp);
16430Sstevel@tonic-gate
16440Sstevel@tonic-gate t_flag = curthread->t_flag & T_WOULDBLOCK;
16450Sstevel@tonic-gate mutex_enter(&rfs_async_write_lock);
16460Sstevel@tonic-gate for (rp = nlp->list; rp != NULL; rp = rp->list) {
16470Sstevel@tonic-gate if (rp->ns->ns_status == RFSWRITE_INITVAL) {
16480Sstevel@tonic-gate rp->ns->ns_status = puterrno(error);
16490Sstevel@tonic-gate rp->thread->t_flag |= t_flag;
16500Sstevel@tonic-gate }
16510Sstevel@tonic-gate }
16520Sstevel@tonic-gate cv_broadcast(&nlp->cv);
16530Sstevel@tonic-gate mutex_exit(&rfs_async_write_lock);
16540Sstevel@tonic-gate
16550Sstevel@tonic-gate }
16560Sstevel@tonic-gate
16571610Sthurlow void *
rfs_write_getfh(struct nfswriteargs * wa)16580Sstevel@tonic-gate rfs_write_getfh(struct nfswriteargs *wa)
16590Sstevel@tonic-gate {
16600Sstevel@tonic-gate return (&wa->wa_fhandle);
16610Sstevel@tonic-gate }
16620Sstevel@tonic-gate
16630Sstevel@tonic-gate /*
16640Sstevel@tonic-gate * Create a file.
16650Sstevel@tonic-gate * Creates a file with given attributes and returns those attributes
16660Sstevel@tonic-gate * and an fhandle for the new file.
16670Sstevel@tonic-gate */
16680Sstevel@tonic-gate void
rfs_create(struct nfscreatargs * args,struct nfsdiropres * dr,struct exportinfo * exi,struct svc_req * req,cred_t * cr)16690Sstevel@tonic-gate rfs_create(struct nfscreatargs *args, struct nfsdiropres *dr,
16700Sstevel@tonic-gate struct exportinfo *exi, struct svc_req *req, cred_t *cr)
16710Sstevel@tonic-gate {
16720Sstevel@tonic-gate int error;
16730Sstevel@tonic-gate int lookuperr;
16740Sstevel@tonic-gate int in_crit = 0;
16750Sstevel@tonic-gate struct vattr va;
16760Sstevel@tonic-gate vnode_t *vp;
16776402Sgt29601 vnode_t *realvp;
16780Sstevel@tonic-gate vnode_t *dvp;
16790Sstevel@tonic-gate char *name = args->ca_da.da_name;
16800Sstevel@tonic-gate vnode_t *tvp = NULL;
16810Sstevel@tonic-gate int mode;
16820Sstevel@tonic-gate int lookup_ok;
16830Sstevel@tonic-gate bool_t trunc;
16847961SNatalie.Li@Sun.COM struct sockaddr *ca;
16850Sstevel@tonic-gate
16860Sstevel@tonic-gate /*
16870Sstevel@tonic-gate * Disallow NULL paths
16880Sstevel@tonic-gate */
16890Sstevel@tonic-gate if (name == NULL || *name == '\0') {
16900Sstevel@tonic-gate dr->dr_status = NFSERR_ACCES;
16910Sstevel@tonic-gate return;
16920Sstevel@tonic-gate }
16930Sstevel@tonic-gate
16940Sstevel@tonic-gate dvp = nfs_fhtovp(args->ca_da.da_fhandle, exi);
16950Sstevel@tonic-gate if (dvp == NULL) {
16960Sstevel@tonic-gate dr->dr_status = NFSERR_STALE;
16970Sstevel@tonic-gate return;
16980Sstevel@tonic-gate }
16990Sstevel@tonic-gate
17000Sstevel@tonic-gate error = sattr_to_vattr(args->ca_sa, &va);
17010Sstevel@tonic-gate if (error) {
17020Sstevel@tonic-gate dr->dr_status = puterrno(error);
17030Sstevel@tonic-gate return;
17040Sstevel@tonic-gate }
17050Sstevel@tonic-gate
17060Sstevel@tonic-gate /*
17070Sstevel@tonic-gate * Must specify the mode.
17080Sstevel@tonic-gate */
17090Sstevel@tonic-gate if (!(va.va_mask & AT_MODE)) {
17100Sstevel@tonic-gate VN_RELE(dvp);
17110Sstevel@tonic-gate dr->dr_status = NFSERR_INVAL;
17120Sstevel@tonic-gate return;
17130Sstevel@tonic-gate }
17140Sstevel@tonic-gate
17150Sstevel@tonic-gate /*
17160Sstevel@tonic-gate * This is a completely gross hack to make mknod
17170Sstevel@tonic-gate * work over the wire until we can wack the protocol
17180Sstevel@tonic-gate */
17190Sstevel@tonic-gate if ((va.va_mode & IFMT) == IFCHR) {
17200Sstevel@tonic-gate if (args->ca_sa->sa_size == (uint_t)NFS_FIFO_DEV)
17210Sstevel@tonic-gate va.va_type = VFIFO; /* xtra kludge for named pipe */
17220Sstevel@tonic-gate else {
17230Sstevel@tonic-gate va.va_type = VCHR;
17240Sstevel@tonic-gate /*
17250Sstevel@tonic-gate * uncompress the received dev_t
17260Sstevel@tonic-gate * if the top half is zero indicating a request
17270Sstevel@tonic-gate * from an `older style' OS.
17280Sstevel@tonic-gate */
17290Sstevel@tonic-gate if ((va.va_size & 0xffff0000) == 0)
17300Sstevel@tonic-gate va.va_rdev = nfsv2_expdev(va.va_size);
17310Sstevel@tonic-gate else
17320Sstevel@tonic-gate va.va_rdev = (dev_t)va.va_size;
17330Sstevel@tonic-gate }
17340Sstevel@tonic-gate va.va_mask &= ~AT_SIZE;
17350Sstevel@tonic-gate } else if ((va.va_mode & IFMT) == IFBLK) {
17360Sstevel@tonic-gate va.va_type = VBLK;
17370Sstevel@tonic-gate /*
17380Sstevel@tonic-gate * uncompress the received dev_t
17390Sstevel@tonic-gate * if the top half is zero indicating a request
17400Sstevel@tonic-gate * from an `older style' OS.
17410Sstevel@tonic-gate */
17420Sstevel@tonic-gate if ((va.va_size & 0xffff0000) == 0)
17430Sstevel@tonic-gate va.va_rdev = nfsv2_expdev(va.va_size);
17440Sstevel@tonic-gate else
17450Sstevel@tonic-gate va.va_rdev = (dev_t)va.va_size;
17460Sstevel@tonic-gate va.va_mask &= ~AT_SIZE;
17470Sstevel@tonic-gate } else if ((va.va_mode & IFMT) == IFSOCK) {
17480Sstevel@tonic-gate va.va_type = VSOCK;
17497961SNatalie.Li@Sun.COM } else {
17500Sstevel@tonic-gate va.va_type = VREG;
17517961SNatalie.Li@Sun.COM }
17520Sstevel@tonic-gate va.va_mode &= ~IFMT;
17530Sstevel@tonic-gate va.va_mask |= AT_TYPE;
17540Sstevel@tonic-gate
17557961SNatalie.Li@Sun.COM ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
17567961SNatalie.Li@Sun.COM name = nfscmd_convname(ca, exi, name, NFSCMD_CONV_INBOUND,
17577961SNatalie.Li@Sun.COM MAXPATHLEN);
17587961SNatalie.Li@Sun.COM if (name == NULL) {
17597961SNatalie.Li@Sun.COM dr->dr_status = puterrno(EINVAL);
17607961SNatalie.Li@Sun.COM return;
17617961SNatalie.Li@Sun.COM }
17627961SNatalie.Li@Sun.COM
17630Sstevel@tonic-gate /*
17640Sstevel@tonic-gate * Why was the choice made to use VWRITE as the mode to the
17650Sstevel@tonic-gate * call to VOP_CREATE ? This results in a bug. When a client
17660Sstevel@tonic-gate * opens a file that already exists and is RDONLY, the second
17670Sstevel@tonic-gate * open fails with an EACESS because of the mode.
17680Sstevel@tonic-gate * bug ID 1054648.
17690Sstevel@tonic-gate */
17700Sstevel@tonic-gate lookup_ok = 0;
17710Sstevel@tonic-gate mode = VWRITE;
17720Sstevel@tonic-gate if (!(va.va_mask & AT_SIZE) || va.va_type != VREG) {
17735331Samw error = VOP_LOOKUP(dvp, name, &tvp, NULL, 0, NULL, cr,
17745331Samw NULL, NULL, NULL);
17750Sstevel@tonic-gate if (!error) {
17760Sstevel@tonic-gate struct vattr at;
17770Sstevel@tonic-gate
17780Sstevel@tonic-gate lookup_ok = 1;
17790Sstevel@tonic-gate at.va_mask = AT_MODE;
17805331Samw error = VOP_GETATTR(tvp, &at, 0, cr, NULL);
17810Sstevel@tonic-gate if (!error)
17820Sstevel@tonic-gate mode = (at.va_mode & S_IWUSR) ? VWRITE : VREAD;
17830Sstevel@tonic-gate VN_RELE(tvp);
17840Sstevel@tonic-gate tvp = NULL;
17850Sstevel@tonic-gate }
17860Sstevel@tonic-gate }
17870Sstevel@tonic-gate
17880Sstevel@tonic-gate if (!lookup_ok) {
17890Sstevel@tonic-gate if (rdonly(exi, req)) {
17900Sstevel@tonic-gate error = EROFS;
17910Sstevel@tonic-gate } else if (va.va_type != VREG && va.va_type != VFIFO &&
17920Sstevel@tonic-gate va.va_type != VSOCK && secpolicy_sys_devices(cr) != 0) {
17930Sstevel@tonic-gate error = EPERM;
17940Sstevel@tonic-gate } else {
17950Sstevel@tonic-gate error = 0;
17960Sstevel@tonic-gate }
17970Sstevel@tonic-gate }
17980Sstevel@tonic-gate
17990Sstevel@tonic-gate /*
18000Sstevel@tonic-gate * If file size is being modified on an already existing file
18010Sstevel@tonic-gate * make sure that there are no conflicting non-blocking mandatory
18020Sstevel@tonic-gate * locks in the region being manipulated. Return EACCES if there
18030Sstevel@tonic-gate * are conflicting locks.
18040Sstevel@tonic-gate */
18050Sstevel@tonic-gate if (!error && (va.va_type == VREG) && (va.va_mask & AT_SIZE)) {
18065331Samw lookuperr = VOP_LOOKUP(dvp, name, &tvp, NULL, 0, NULL, cr,
18075331Samw NULL, NULL, NULL);
18080Sstevel@tonic-gate
18090Sstevel@tonic-gate if (!lookuperr &&
18100Sstevel@tonic-gate rfs4_check_delegated(FWRITE, tvp, va.va_size == 0)) {
18110Sstevel@tonic-gate VN_RELE(tvp);
18120Sstevel@tonic-gate curthread->t_flag |= T_WOULDBLOCK;
18130Sstevel@tonic-gate goto out;
18140Sstevel@tonic-gate }
18150Sstevel@tonic-gate
18160Sstevel@tonic-gate if (!lookuperr && nbl_need_check(tvp)) {
18170Sstevel@tonic-gate /*
18180Sstevel@tonic-gate * The file exists. Now check if it has any
18190Sstevel@tonic-gate * conflicting non-blocking mandatory locks
18200Sstevel@tonic-gate * in the region being changed.
18210Sstevel@tonic-gate */
18220Sstevel@tonic-gate struct vattr bva;
18230Sstevel@tonic-gate u_offset_t offset;
18240Sstevel@tonic-gate ssize_t length;
18250Sstevel@tonic-gate
18260Sstevel@tonic-gate nbl_start_crit(tvp, RW_READER);
18270Sstevel@tonic-gate in_crit = 1;
18280Sstevel@tonic-gate
18290Sstevel@tonic-gate bva.va_mask = AT_SIZE;
18305331Samw error = VOP_GETATTR(tvp, &bva, 0, cr, NULL);
18310Sstevel@tonic-gate if (!error) {
18320Sstevel@tonic-gate if (va.va_size < bva.va_size) {
18330Sstevel@tonic-gate offset = va.va_size;
18340Sstevel@tonic-gate length = bva.va_size - va.va_size;
18350Sstevel@tonic-gate } else {
18360Sstevel@tonic-gate offset = bva.va_size;
18370Sstevel@tonic-gate length = va.va_size - bva.va_size;
18380Sstevel@tonic-gate }
18390Sstevel@tonic-gate if (length) {
18400Sstevel@tonic-gate if (nbl_conflict(tvp, NBL_WRITE,
18415331Samw offset, length, 0, NULL)) {
18420Sstevel@tonic-gate error = EACCES;
18430Sstevel@tonic-gate }
18440Sstevel@tonic-gate }
18450Sstevel@tonic-gate }
18460Sstevel@tonic-gate if (error) {
18470Sstevel@tonic-gate nbl_end_crit(tvp);
18480Sstevel@tonic-gate VN_RELE(tvp);
18490Sstevel@tonic-gate in_crit = 0;
18500Sstevel@tonic-gate }
18510Sstevel@tonic-gate } else if (tvp != NULL) {
18520Sstevel@tonic-gate VN_RELE(tvp);
18530Sstevel@tonic-gate }
18540Sstevel@tonic-gate }
18550Sstevel@tonic-gate
18560Sstevel@tonic-gate if (!error) {
18570Sstevel@tonic-gate /*
18580Sstevel@tonic-gate * If filesystem is shared with nosuid the remove any
18590Sstevel@tonic-gate * setuid/setgid bits on create.
18600Sstevel@tonic-gate */
18610Sstevel@tonic-gate if (va.va_type == VREG &&
18620Sstevel@tonic-gate exi->exi_export.ex_flags & EX_NOSUID)
18630Sstevel@tonic-gate va.va_mode &= ~(VSUID | VSGID);
18640Sstevel@tonic-gate
18655331Samw error = VOP_CREATE(dvp, name, &va, NONEXCL, mode, &vp, cr, 0,
18665331Samw NULL, NULL);
18670Sstevel@tonic-gate
18680Sstevel@tonic-gate if (!error) {
18690Sstevel@tonic-gate
18700Sstevel@tonic-gate if ((va.va_mask & AT_SIZE) && (va.va_size == 0))
18710Sstevel@tonic-gate trunc = TRUE;
18720Sstevel@tonic-gate else
18730Sstevel@tonic-gate trunc = FALSE;
18740Sstevel@tonic-gate
18755050Sjwahlig if (rfs4_check_delegated(FWRITE, vp, trunc)) {
18765050Sjwahlig VN_RELE(vp);
18770Sstevel@tonic-gate curthread->t_flag |= T_WOULDBLOCK;
18780Sstevel@tonic-gate goto out;
18790Sstevel@tonic-gate }
18800Sstevel@tonic-gate va.va_mask = AT_ALL;
18817387SRobert.Gordon@Sun.COM
18825331Samw error = VOP_GETATTR(vp, &va, 0, cr, NULL);
18837387SRobert.Gordon@Sun.COM
18840Sstevel@tonic-gate /* check for overflows */
18850Sstevel@tonic-gate if (!error) {
18860Sstevel@tonic-gate acl_perm(vp, exi, &va, cr);
18870Sstevel@tonic-gate error = vattr_to_nattr(&va, &dr->dr_attr);
18880Sstevel@tonic-gate if (!error) {
18890Sstevel@tonic-gate error = makefh(&dr->dr_fhandle, vp,
18905050Sjwahlig exi);
18910Sstevel@tonic-gate }
18920Sstevel@tonic-gate }
18930Sstevel@tonic-gate /*
18940Sstevel@tonic-gate * Force modified metadata out to stable storage.
18956402Sgt29601 *
18966402Sgt29601 * if a underlying vp exists, pass it to VOP_FSYNC
18970Sstevel@tonic-gate */
18986402Sgt29601 if (VOP_REALVP(vp, &realvp, NULL) == 0)
18996402Sgt29601 (void) VOP_FSYNC(realvp, FNODSYNC, cr, NULL);
19006402Sgt29601 else
19016402Sgt29601 (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
19020Sstevel@tonic-gate VN_RELE(vp);
19030Sstevel@tonic-gate }
19040Sstevel@tonic-gate
19050Sstevel@tonic-gate if (in_crit) {
19060Sstevel@tonic-gate nbl_end_crit(tvp);
19070Sstevel@tonic-gate VN_RELE(tvp);
19080Sstevel@tonic-gate }
19090Sstevel@tonic-gate }
19100Sstevel@tonic-gate
19110Sstevel@tonic-gate /*
19120Sstevel@tonic-gate * Force modified data and metadata out to stable storage.
19130Sstevel@tonic-gate */
19145331Samw (void) VOP_FSYNC(dvp, 0, cr, NULL);
19150Sstevel@tonic-gate
19160Sstevel@tonic-gate out:
19170Sstevel@tonic-gate
19180Sstevel@tonic-gate VN_RELE(dvp);
19190Sstevel@tonic-gate
19200Sstevel@tonic-gate dr->dr_status = puterrno(error);
19210Sstevel@tonic-gate
19227961SNatalie.Li@Sun.COM if (name != args->ca_da.da_name)
19237961SNatalie.Li@Sun.COM kmem_free(name, MAXPATHLEN);
19240Sstevel@tonic-gate }
19251610Sthurlow void *
rfs_create_getfh(struct nfscreatargs * args)19260Sstevel@tonic-gate rfs_create_getfh(struct nfscreatargs *args)
19270Sstevel@tonic-gate {
19280Sstevel@tonic-gate return (args->ca_da.da_fhandle);
19290Sstevel@tonic-gate }
19300Sstevel@tonic-gate
19310Sstevel@tonic-gate /*
19320Sstevel@tonic-gate * Remove a file.
19330Sstevel@tonic-gate * Remove named file from parent directory.
19340Sstevel@tonic-gate */
19350Sstevel@tonic-gate void
rfs_remove(struct nfsdiropargs * da,enum nfsstat * status,struct exportinfo * exi,struct svc_req * req,cred_t * cr)19360Sstevel@tonic-gate rfs_remove(struct nfsdiropargs *da, enum nfsstat *status,
19370Sstevel@tonic-gate struct exportinfo *exi, struct svc_req *req, cred_t *cr)
19380Sstevel@tonic-gate {
19390Sstevel@tonic-gate int error = 0;
19400Sstevel@tonic-gate vnode_t *vp;
19410Sstevel@tonic-gate vnode_t *targvp;
19420Sstevel@tonic-gate int in_crit = 0;
19430Sstevel@tonic-gate
19440Sstevel@tonic-gate /*
19450Sstevel@tonic-gate * Disallow NULL paths
19460Sstevel@tonic-gate */
19470Sstevel@tonic-gate if (da->da_name == NULL || *da->da_name == '\0') {
19480Sstevel@tonic-gate *status = NFSERR_ACCES;
19490Sstevel@tonic-gate return;
19500Sstevel@tonic-gate }
19510Sstevel@tonic-gate
19520Sstevel@tonic-gate vp = nfs_fhtovp(da->da_fhandle, exi);
19530Sstevel@tonic-gate if (vp == NULL) {
19540Sstevel@tonic-gate *status = NFSERR_STALE;
19550Sstevel@tonic-gate return;
19560Sstevel@tonic-gate }
19570Sstevel@tonic-gate
19580Sstevel@tonic-gate if (rdonly(exi, req)) {
19590Sstevel@tonic-gate VN_RELE(vp);
19600Sstevel@tonic-gate *status = NFSERR_ROFS;
19610Sstevel@tonic-gate return;
19620Sstevel@tonic-gate }
19630Sstevel@tonic-gate
19640Sstevel@tonic-gate /*
19650Sstevel@tonic-gate * Check for a conflict with a non-blocking mandatory share reservation.
19660Sstevel@tonic-gate */
19675331Samw error = VOP_LOOKUP(vp, da->da_name, &targvp, NULL, 0,
19685331Samw NULL, cr, NULL, NULL, NULL);
19690Sstevel@tonic-gate if (error != 0) {
19700Sstevel@tonic-gate VN_RELE(vp);
19710Sstevel@tonic-gate *status = puterrno(error);
19720Sstevel@tonic-gate return;
19730Sstevel@tonic-gate }
19740Sstevel@tonic-gate
19750Sstevel@tonic-gate /*
19760Sstevel@tonic-gate * If the file is delegated to an v4 client, then initiate
19770Sstevel@tonic-gate * recall and drop this request (by setting T_WOULDBLOCK).
19780Sstevel@tonic-gate * The client will eventually re-transmit the request and
19790Sstevel@tonic-gate * (hopefully), by then, the v4 client will have returned
19800Sstevel@tonic-gate * the delegation.
19810Sstevel@tonic-gate */
19820Sstevel@tonic-gate
19830Sstevel@tonic-gate if (rfs4_check_delegated(FWRITE, targvp, TRUE)) {
19840Sstevel@tonic-gate VN_RELE(vp);
19850Sstevel@tonic-gate VN_RELE(targvp);
19860Sstevel@tonic-gate curthread->t_flag |= T_WOULDBLOCK;
19870Sstevel@tonic-gate return;
19880Sstevel@tonic-gate }
19890Sstevel@tonic-gate
19900Sstevel@tonic-gate if (nbl_need_check(targvp)) {
19910Sstevel@tonic-gate nbl_start_crit(targvp, RW_READER);
19920Sstevel@tonic-gate in_crit = 1;
19935331Samw if (nbl_conflict(targvp, NBL_REMOVE, 0, 0, 0, NULL)) {
19940Sstevel@tonic-gate error = EACCES;
19950Sstevel@tonic-gate goto out;
19960Sstevel@tonic-gate }
19970Sstevel@tonic-gate }
19980Sstevel@tonic-gate
19995331Samw error = VOP_REMOVE(vp, da->da_name, cr, NULL, 0);
20000Sstevel@tonic-gate
20010Sstevel@tonic-gate /*
20020Sstevel@tonic-gate * Force modified data and metadata out to stable storage.
20030Sstevel@tonic-gate */
20045331Samw (void) VOP_FSYNC(vp, 0, cr, NULL);
20050Sstevel@tonic-gate
20060Sstevel@tonic-gate out:
20070Sstevel@tonic-gate if (in_crit)
20080Sstevel@tonic-gate nbl_end_crit(targvp);
20090Sstevel@tonic-gate VN_RELE(targvp);
20100Sstevel@tonic-gate VN_RELE(vp);
20110Sstevel@tonic-gate
20120Sstevel@tonic-gate *status = puterrno(error);
20130Sstevel@tonic-gate
20140Sstevel@tonic-gate }
20150Sstevel@tonic-gate
20161610Sthurlow void *
rfs_remove_getfh(struct nfsdiropargs * da)20170Sstevel@tonic-gate rfs_remove_getfh(struct nfsdiropargs *da)
20180Sstevel@tonic-gate {
20190Sstevel@tonic-gate return (da->da_fhandle);
20200Sstevel@tonic-gate }
20210Sstevel@tonic-gate
20220Sstevel@tonic-gate /*
20230Sstevel@tonic-gate * rename a file
20240Sstevel@tonic-gate * Give a file (from) a new name (to).
20250Sstevel@tonic-gate */
20260Sstevel@tonic-gate void
rfs_rename(struct nfsrnmargs * args,enum nfsstat * status,struct exportinfo * exi,struct svc_req * req,cred_t * cr)20270Sstevel@tonic-gate rfs_rename(struct nfsrnmargs *args, enum nfsstat *status,
20280Sstevel@tonic-gate struct exportinfo *exi, struct svc_req *req, cred_t *cr)
20290Sstevel@tonic-gate {
20300Sstevel@tonic-gate int error = 0;
20310Sstevel@tonic-gate vnode_t *fromvp;
20320Sstevel@tonic-gate vnode_t *tovp;
20330Sstevel@tonic-gate struct exportinfo *to_exi;
20340Sstevel@tonic-gate fhandle_t *fh;
20350Sstevel@tonic-gate vnode_t *srcvp;
20360Sstevel@tonic-gate vnode_t *targvp;
20370Sstevel@tonic-gate int in_crit = 0;
20380Sstevel@tonic-gate
20390Sstevel@tonic-gate fromvp = nfs_fhtovp(args->rna_from.da_fhandle, exi);
20400Sstevel@tonic-gate if (fromvp == NULL) {
20410Sstevel@tonic-gate *status = NFSERR_STALE;
20420Sstevel@tonic-gate return;
20430Sstevel@tonic-gate }
20440Sstevel@tonic-gate
20450Sstevel@tonic-gate fh = args->rna_to.da_fhandle;
20460Sstevel@tonic-gate to_exi = checkexport(&fh->fh_fsid, (fid_t *)&fh->fh_xlen);
20470Sstevel@tonic-gate if (to_exi == NULL) {
20480Sstevel@tonic-gate VN_RELE(fromvp);
20490Sstevel@tonic-gate *status = NFSERR_ACCES;
20500Sstevel@tonic-gate return;
20510Sstevel@tonic-gate }
20520Sstevel@tonic-gate exi_rele(to_exi);
20530Sstevel@tonic-gate
20540Sstevel@tonic-gate if (to_exi != exi) {
20550Sstevel@tonic-gate VN_RELE(fromvp);
20560Sstevel@tonic-gate *status = NFSERR_XDEV;
20570Sstevel@tonic-gate return;
20580Sstevel@tonic-gate }
20590Sstevel@tonic-gate
20600Sstevel@tonic-gate tovp = nfs_fhtovp(args->rna_to.da_fhandle, exi);
20610Sstevel@tonic-gate if (tovp == NULL) {
20620Sstevel@tonic-gate VN_RELE(fromvp);
20630Sstevel@tonic-gate *status = NFSERR_STALE;
20640Sstevel@tonic-gate return;
20650Sstevel@tonic-gate }
20660Sstevel@tonic-gate
20670Sstevel@tonic-gate if (fromvp->v_type != VDIR || tovp->v_type != VDIR) {
20680Sstevel@tonic-gate VN_RELE(tovp);
20690Sstevel@tonic-gate VN_RELE(fromvp);
20700Sstevel@tonic-gate *status = NFSERR_NOTDIR;
20710Sstevel@tonic-gate return;
20720Sstevel@tonic-gate }
20730Sstevel@tonic-gate
20740Sstevel@tonic-gate /*
20750Sstevel@tonic-gate * Disallow NULL paths
20760Sstevel@tonic-gate */
20770Sstevel@tonic-gate if (args->rna_from.da_name == NULL || *args->rna_from.da_name == '\0' ||
20780Sstevel@tonic-gate args->rna_to.da_name == NULL || *args->rna_to.da_name == '\0') {
20790Sstevel@tonic-gate VN_RELE(tovp);
20800Sstevel@tonic-gate VN_RELE(fromvp);
20810Sstevel@tonic-gate *status = NFSERR_ACCES;
20820Sstevel@tonic-gate return;
20830Sstevel@tonic-gate }
20840Sstevel@tonic-gate
20850Sstevel@tonic-gate if (rdonly(exi, req)) {
20860Sstevel@tonic-gate VN_RELE(tovp);
20870Sstevel@tonic-gate VN_RELE(fromvp);
20880Sstevel@tonic-gate *status = NFSERR_ROFS;
20890Sstevel@tonic-gate return;
20900Sstevel@tonic-gate }
20910Sstevel@tonic-gate
20920Sstevel@tonic-gate /*
20930Sstevel@tonic-gate * Check for a conflict with a non-blocking mandatory share reservation.
20940Sstevel@tonic-gate */
20950Sstevel@tonic-gate error = VOP_LOOKUP(fromvp, args->rna_from.da_name, &srcvp, NULL, 0,
20965331Samw NULL, cr, NULL, NULL, NULL);
20970Sstevel@tonic-gate if (error != 0) {
20980Sstevel@tonic-gate VN_RELE(tovp);
20990Sstevel@tonic-gate VN_RELE(fromvp);
21000Sstevel@tonic-gate *status = puterrno(error);
21010Sstevel@tonic-gate return;
21020Sstevel@tonic-gate }
21030Sstevel@tonic-gate
21040Sstevel@tonic-gate /* Check for delegations on the source file */
21050Sstevel@tonic-gate
21060Sstevel@tonic-gate if (rfs4_check_delegated(FWRITE, srcvp, FALSE)) {
21070Sstevel@tonic-gate VN_RELE(tovp);
21080Sstevel@tonic-gate VN_RELE(fromvp);
21090Sstevel@tonic-gate VN_RELE(srcvp);
21100Sstevel@tonic-gate curthread->t_flag |= T_WOULDBLOCK;
21110Sstevel@tonic-gate return;
21120Sstevel@tonic-gate }
21130Sstevel@tonic-gate
21140Sstevel@tonic-gate /* Check for delegation on the file being renamed over, if it exists */
21150Sstevel@tonic-gate
21160Sstevel@tonic-gate if (rfs4_deleg_policy != SRV_NEVER_DELEGATE &&
21175331Samw VOP_LOOKUP(tovp, args->rna_to.da_name, &targvp, NULL, 0, NULL, cr,
21185331Samw NULL, NULL, NULL) == 0) {
21190Sstevel@tonic-gate
21200Sstevel@tonic-gate if (rfs4_check_delegated(FWRITE, targvp, TRUE)) {
21210Sstevel@tonic-gate VN_RELE(tovp);
21220Sstevel@tonic-gate VN_RELE(fromvp);
21230Sstevel@tonic-gate VN_RELE(srcvp);
21240Sstevel@tonic-gate VN_RELE(targvp);
21250Sstevel@tonic-gate curthread->t_flag |= T_WOULDBLOCK;
21260Sstevel@tonic-gate return;
21270Sstevel@tonic-gate }
21280Sstevel@tonic-gate VN_RELE(targvp);
21290Sstevel@tonic-gate }
21300Sstevel@tonic-gate
21310Sstevel@tonic-gate
21320Sstevel@tonic-gate if (nbl_need_check(srcvp)) {
21330Sstevel@tonic-gate nbl_start_crit(srcvp, RW_READER);
21340Sstevel@tonic-gate in_crit = 1;
21355331Samw if (nbl_conflict(srcvp, NBL_RENAME, 0, 0, 0, NULL)) {
21360Sstevel@tonic-gate error = EACCES;
21370Sstevel@tonic-gate goto out;
21380Sstevel@tonic-gate }
21390Sstevel@tonic-gate }
21400Sstevel@tonic-gate
21410Sstevel@tonic-gate error = VOP_RENAME(fromvp, args->rna_from.da_name,
21425331Samw tovp, args->rna_to.da_name, cr, NULL, 0);
21430Sstevel@tonic-gate
21446976Seschrock if (error == 0)
21456976Seschrock vn_renamepath(tovp, srcvp, args->rna_to.da_name,
21465050Sjwahlig strlen(args->rna_to.da_name));
21471146Sjwahlig
21480Sstevel@tonic-gate /*
21490Sstevel@tonic-gate * Force modified data and metadata out to stable storage.
21500Sstevel@tonic-gate */
21515331Samw (void) VOP_FSYNC(tovp, 0, cr, NULL);
21525331Samw (void) VOP_FSYNC(fromvp, 0, cr, NULL);
21530Sstevel@tonic-gate
21540Sstevel@tonic-gate out:
21550Sstevel@tonic-gate if (in_crit)
21560Sstevel@tonic-gate nbl_end_crit(srcvp);
21570Sstevel@tonic-gate VN_RELE(srcvp);
21580Sstevel@tonic-gate VN_RELE(tovp);
21590Sstevel@tonic-gate VN_RELE(fromvp);
21600Sstevel@tonic-gate
21610Sstevel@tonic-gate *status = puterrno(error);
21620Sstevel@tonic-gate
21630Sstevel@tonic-gate }
21641610Sthurlow void *
rfs_rename_getfh(struct nfsrnmargs * args)21650Sstevel@tonic-gate rfs_rename_getfh(struct nfsrnmargs *args)
21660Sstevel@tonic-gate {
21670Sstevel@tonic-gate return (args->rna_from.da_fhandle);
21680Sstevel@tonic-gate }
21690Sstevel@tonic-gate
21700Sstevel@tonic-gate /*
21710Sstevel@tonic-gate * Link to a file.
21720Sstevel@tonic-gate * Create a file (to) which is a hard link to the given file (from).
21730Sstevel@tonic-gate */
21740Sstevel@tonic-gate void
rfs_link(struct nfslinkargs * args,enum nfsstat * status,struct exportinfo * exi,struct svc_req * req,cred_t * cr)21750Sstevel@tonic-gate rfs_link(struct nfslinkargs *args, enum nfsstat *status,
21760Sstevel@tonic-gate struct exportinfo *exi, struct svc_req *req, cred_t *cr)
21770Sstevel@tonic-gate {
21780Sstevel@tonic-gate int error;
21790Sstevel@tonic-gate vnode_t *fromvp;
21800Sstevel@tonic-gate vnode_t *tovp;
21810Sstevel@tonic-gate struct exportinfo *to_exi;
21820Sstevel@tonic-gate fhandle_t *fh;
21830Sstevel@tonic-gate
21840Sstevel@tonic-gate fromvp = nfs_fhtovp(args->la_from, exi);
21850Sstevel@tonic-gate if (fromvp == NULL) {
21860Sstevel@tonic-gate *status = NFSERR_STALE;
21870Sstevel@tonic-gate return;
21880Sstevel@tonic-gate }
21890Sstevel@tonic-gate
21900Sstevel@tonic-gate fh = args->la_to.da_fhandle;
21910Sstevel@tonic-gate to_exi = checkexport(&fh->fh_fsid, (fid_t *)&fh->fh_xlen);
21920Sstevel@tonic-gate if (to_exi == NULL) {
21930Sstevel@tonic-gate VN_RELE(fromvp);
21940Sstevel@tonic-gate *status = NFSERR_ACCES;
21950Sstevel@tonic-gate return;
21960Sstevel@tonic-gate }
21970Sstevel@tonic-gate exi_rele(to_exi);
21980Sstevel@tonic-gate
21990Sstevel@tonic-gate if (to_exi != exi) {
22000Sstevel@tonic-gate VN_RELE(fromvp);
22010Sstevel@tonic-gate *status = NFSERR_XDEV;
22020Sstevel@tonic-gate return;
22030Sstevel@tonic-gate }
22040Sstevel@tonic-gate
22050Sstevel@tonic-gate tovp = nfs_fhtovp(args->la_to.da_fhandle, exi);
22060Sstevel@tonic-gate if (tovp == NULL) {
22070Sstevel@tonic-gate VN_RELE(fromvp);
22080Sstevel@tonic-gate *status = NFSERR_STALE;
22090Sstevel@tonic-gate return;
22100Sstevel@tonic-gate }
22110Sstevel@tonic-gate
22120Sstevel@tonic-gate if (tovp->v_type != VDIR) {
22130Sstevel@tonic-gate VN_RELE(tovp);
22140Sstevel@tonic-gate VN_RELE(fromvp);
22150Sstevel@tonic-gate *status = NFSERR_NOTDIR;
22160Sstevel@tonic-gate return;
22170Sstevel@tonic-gate }
22180Sstevel@tonic-gate /*
22190Sstevel@tonic-gate * Disallow NULL paths
22200Sstevel@tonic-gate */
22210Sstevel@tonic-gate if (args->la_to.da_name == NULL || *args->la_to.da_name == '\0') {
22220Sstevel@tonic-gate VN_RELE(tovp);
22230Sstevel@tonic-gate VN_RELE(fromvp);
22240Sstevel@tonic-gate *status = NFSERR_ACCES;
22250Sstevel@tonic-gate return;
22260Sstevel@tonic-gate }
22270Sstevel@tonic-gate
22280Sstevel@tonic-gate if (rdonly(exi, req)) {
22290Sstevel@tonic-gate VN_RELE(tovp);
22300Sstevel@tonic-gate VN_RELE(fromvp);
22310Sstevel@tonic-gate *status = NFSERR_ROFS;
22320Sstevel@tonic-gate return;
22330Sstevel@tonic-gate }
22340Sstevel@tonic-gate
22355331Samw error = VOP_LINK(tovp, fromvp, args->la_to.da_name, cr, NULL, 0);
22360Sstevel@tonic-gate
22370Sstevel@tonic-gate /*
22380Sstevel@tonic-gate * Force modified data and metadata out to stable storage.
22390Sstevel@tonic-gate */
22405331Samw (void) VOP_FSYNC(tovp, 0, cr, NULL);
22415331Samw (void) VOP_FSYNC(fromvp, FNODSYNC, cr, NULL);
22420Sstevel@tonic-gate
22430Sstevel@tonic-gate VN_RELE(tovp);
22440Sstevel@tonic-gate VN_RELE(fromvp);
22450Sstevel@tonic-gate
22460Sstevel@tonic-gate *status = puterrno(error);
22470Sstevel@tonic-gate
22480Sstevel@tonic-gate }
22491610Sthurlow void *
rfs_link_getfh(struct nfslinkargs * args)22500Sstevel@tonic-gate rfs_link_getfh(struct nfslinkargs *args)
22510Sstevel@tonic-gate {
22520Sstevel@tonic-gate return (args->la_from);
22530Sstevel@tonic-gate }
22540Sstevel@tonic-gate
22550Sstevel@tonic-gate /*
22560Sstevel@tonic-gate * Symbolicly link to a file.
22570Sstevel@tonic-gate * Create a file (to) with the given attributes which is a symbolic link
22580Sstevel@tonic-gate * to the given path name (to).
22590Sstevel@tonic-gate */
22600Sstevel@tonic-gate void
rfs_symlink(struct nfsslargs * args,enum nfsstat * status,struct exportinfo * exi,struct svc_req * req,cred_t * cr)22610Sstevel@tonic-gate rfs_symlink(struct nfsslargs *args, enum nfsstat *status,
22620Sstevel@tonic-gate struct exportinfo *exi, struct svc_req *req, cred_t *cr)
22630Sstevel@tonic-gate {
22640Sstevel@tonic-gate int error;
22650Sstevel@tonic-gate struct vattr va;
22660Sstevel@tonic-gate vnode_t *vp;
22670Sstevel@tonic-gate vnode_t *svp;
22680Sstevel@tonic-gate int lerror;
22697961SNatalie.Li@Sun.COM struct sockaddr *ca;
22707961SNatalie.Li@Sun.COM char *name = NULL;
22710Sstevel@tonic-gate
22720Sstevel@tonic-gate /*
22730Sstevel@tonic-gate * Disallow NULL paths
22740Sstevel@tonic-gate */
22750Sstevel@tonic-gate if (args->sla_from.da_name == NULL || *args->sla_from.da_name == '\0') {
22760Sstevel@tonic-gate *status = NFSERR_ACCES;
22770Sstevel@tonic-gate return;
22780Sstevel@tonic-gate }
22790Sstevel@tonic-gate
22800Sstevel@tonic-gate vp = nfs_fhtovp(args->sla_from.da_fhandle, exi);
22810Sstevel@tonic-gate if (vp == NULL) {
22820Sstevel@tonic-gate *status = NFSERR_STALE;
22830Sstevel@tonic-gate return;
22840Sstevel@tonic-gate }
22850Sstevel@tonic-gate
22860Sstevel@tonic-gate if (rdonly(exi, req)) {
22870Sstevel@tonic-gate VN_RELE(vp);
22880Sstevel@tonic-gate *status = NFSERR_ROFS;
22890Sstevel@tonic-gate return;
22900Sstevel@tonic-gate }
22910Sstevel@tonic-gate
22920Sstevel@tonic-gate error = sattr_to_vattr(args->sla_sa, &va);
22930Sstevel@tonic-gate if (error) {
22940Sstevel@tonic-gate VN_RELE(vp);
22950Sstevel@tonic-gate *status = puterrno(error);
22960Sstevel@tonic-gate return;
22970Sstevel@tonic-gate }
22980Sstevel@tonic-gate
22990Sstevel@tonic-gate if (!(va.va_mask & AT_MODE)) {
23000Sstevel@tonic-gate VN_RELE(vp);
23010Sstevel@tonic-gate *status = NFSERR_INVAL;
23020Sstevel@tonic-gate return;
23030Sstevel@tonic-gate }
23040Sstevel@tonic-gate
23057961SNatalie.Li@Sun.COM ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
23067961SNatalie.Li@Sun.COM name = nfscmd_convname(ca, exi, args->sla_tnm,
23077961SNatalie.Li@Sun.COM NFSCMD_CONV_INBOUND, MAXPATHLEN);
23087961SNatalie.Li@Sun.COM
23097961SNatalie.Li@Sun.COM if (name == NULL) {
23107961SNatalie.Li@Sun.COM *status = NFSERR_ACCES;
23117961SNatalie.Li@Sun.COM return;
23127961SNatalie.Li@Sun.COM }
23137961SNatalie.Li@Sun.COM
23140Sstevel@tonic-gate va.va_type = VLNK;
23150Sstevel@tonic-gate va.va_mask |= AT_TYPE;
23160Sstevel@tonic-gate
23177961SNatalie.Li@Sun.COM error = VOP_SYMLINK(vp, args->sla_from.da_name, &va, name, cr, NULL, 0);
23180Sstevel@tonic-gate
23190Sstevel@tonic-gate /*
23200Sstevel@tonic-gate * Force new data and metadata out to stable storage.
23210Sstevel@tonic-gate */
23227961SNatalie.Li@Sun.COM lerror = VOP_LOOKUP(vp, args->sla_from.da_name, &svp, NULL, 0,
23237961SNatalie.Li@Sun.COM NULL, cr, NULL, NULL, NULL);
23247387SRobert.Gordon@Sun.COM
23250Sstevel@tonic-gate if (!lerror) {
23265331Samw (void) VOP_FSYNC(svp, 0, cr, NULL);
23270Sstevel@tonic-gate VN_RELE(svp);
23280Sstevel@tonic-gate }
23290Sstevel@tonic-gate
23300Sstevel@tonic-gate /*
23310Sstevel@tonic-gate * Force modified data and metadata out to stable storage.
23320Sstevel@tonic-gate */
23335331Samw (void) VOP_FSYNC(vp, 0, cr, NULL);
23340Sstevel@tonic-gate
23350Sstevel@tonic-gate VN_RELE(vp);
23360Sstevel@tonic-gate
23370Sstevel@tonic-gate *status = puterrno(error);
23387961SNatalie.Li@Sun.COM if (name != args->sla_tnm)
23397961SNatalie.Li@Sun.COM kmem_free(name, MAXPATHLEN);
23400Sstevel@tonic-gate
23410Sstevel@tonic-gate }
23421610Sthurlow void *
rfs_symlink_getfh(struct nfsslargs * args)23430Sstevel@tonic-gate rfs_symlink_getfh(struct nfsslargs *args)
23440Sstevel@tonic-gate {
23450Sstevel@tonic-gate return (args->sla_from.da_fhandle);
23460Sstevel@tonic-gate }
23470Sstevel@tonic-gate
23480Sstevel@tonic-gate /*
23490Sstevel@tonic-gate * Make a directory.
23500Sstevel@tonic-gate * Create a directory with the given name, parent directory, and attributes.
23510Sstevel@tonic-gate * Returns a file handle and attributes for the new directory.
23520Sstevel@tonic-gate */
23530Sstevel@tonic-gate void
rfs_mkdir(struct nfscreatargs * args,struct nfsdiropres * dr,struct exportinfo * exi,struct svc_req * req,cred_t * cr)23540Sstevel@tonic-gate rfs_mkdir(struct nfscreatargs *args, struct nfsdiropres *dr,
23550Sstevel@tonic-gate struct exportinfo *exi, struct svc_req *req, cred_t *cr)
23560Sstevel@tonic-gate {
23570Sstevel@tonic-gate int error;
23580Sstevel@tonic-gate struct vattr va;
23590Sstevel@tonic-gate vnode_t *dvp = NULL;
23600Sstevel@tonic-gate vnode_t *vp;
23610Sstevel@tonic-gate char *name = args->ca_da.da_name;
23620Sstevel@tonic-gate
23630Sstevel@tonic-gate /*
23640Sstevel@tonic-gate * Disallow NULL paths
23650Sstevel@tonic-gate */
23660Sstevel@tonic-gate if (name == NULL || *name == '\0') {
23670Sstevel@tonic-gate dr->dr_status = NFSERR_ACCES;
23680Sstevel@tonic-gate return;
23690Sstevel@tonic-gate }
23700Sstevel@tonic-gate
23710Sstevel@tonic-gate vp = nfs_fhtovp(args->ca_da.da_fhandle, exi);
23720Sstevel@tonic-gate if (vp == NULL) {
23730Sstevel@tonic-gate dr->dr_status = NFSERR_STALE;
23740Sstevel@tonic-gate return;
23750Sstevel@tonic-gate }
23760Sstevel@tonic-gate
23770Sstevel@tonic-gate if (rdonly(exi, req)) {
23780Sstevel@tonic-gate VN_RELE(vp);
23790Sstevel@tonic-gate dr->dr_status = NFSERR_ROFS;
23800Sstevel@tonic-gate return;
23810Sstevel@tonic-gate }
23820Sstevel@tonic-gate
23830Sstevel@tonic-gate error = sattr_to_vattr(args->ca_sa, &va);
23840Sstevel@tonic-gate if (error) {
23850Sstevel@tonic-gate VN_RELE(vp);
23860Sstevel@tonic-gate dr->dr_status = puterrno(error);
23870Sstevel@tonic-gate return;
23880Sstevel@tonic-gate }
23890Sstevel@tonic-gate
23900Sstevel@tonic-gate if (!(va.va_mask & AT_MODE)) {
23910Sstevel@tonic-gate VN_RELE(vp);
23920Sstevel@tonic-gate dr->dr_status = NFSERR_INVAL;
23930Sstevel@tonic-gate return;
23940Sstevel@tonic-gate }
23950Sstevel@tonic-gate
23960Sstevel@tonic-gate va.va_type = VDIR;
23970Sstevel@tonic-gate va.va_mask |= AT_TYPE;
23980Sstevel@tonic-gate
23995331Samw error = VOP_MKDIR(vp, name, &va, &dvp, cr, NULL, 0, NULL);
24000Sstevel@tonic-gate
24010Sstevel@tonic-gate if (!error) {
24020Sstevel@tonic-gate /*
24030Sstevel@tonic-gate * Attribtutes of the newly created directory should
24040Sstevel@tonic-gate * be returned to the client.
24050Sstevel@tonic-gate */
24060Sstevel@tonic-gate va.va_mask = AT_ALL; /* We want everything */
24075331Samw error = VOP_GETATTR(dvp, &va, 0, cr, NULL);
24087387SRobert.Gordon@Sun.COM
24090Sstevel@tonic-gate /* check for overflows */
24100Sstevel@tonic-gate if (!error) {
24110Sstevel@tonic-gate acl_perm(vp, exi, &va, cr);
24120Sstevel@tonic-gate error = vattr_to_nattr(&va, &dr->dr_attr);
24130Sstevel@tonic-gate if (!error) {
24140Sstevel@tonic-gate error = makefh(&dr->dr_fhandle, dvp, exi);
24150Sstevel@tonic-gate }
24160Sstevel@tonic-gate }
24170Sstevel@tonic-gate /*
24180Sstevel@tonic-gate * Force new data and metadata out to stable storage.
24190Sstevel@tonic-gate */
24205331Samw (void) VOP_FSYNC(dvp, 0, cr, NULL);
24210Sstevel@tonic-gate VN_RELE(dvp);
24220Sstevel@tonic-gate }
24230Sstevel@tonic-gate
24240Sstevel@tonic-gate /*
24250Sstevel@tonic-gate * Force modified data and metadata out to stable storage.
24260Sstevel@tonic-gate */
24275331Samw (void) VOP_FSYNC(vp, 0, cr, NULL);
24280Sstevel@tonic-gate
24290Sstevel@tonic-gate VN_RELE(vp);
24300Sstevel@tonic-gate
24310Sstevel@tonic-gate dr->dr_status = puterrno(error);
24320Sstevel@tonic-gate
24330Sstevel@tonic-gate }
24341610Sthurlow void *
rfs_mkdir_getfh(struct nfscreatargs * args)24350Sstevel@tonic-gate rfs_mkdir_getfh(struct nfscreatargs *args)
24360Sstevel@tonic-gate {
24370Sstevel@tonic-gate return (args->ca_da.da_fhandle);
24380Sstevel@tonic-gate }
24390Sstevel@tonic-gate
24400Sstevel@tonic-gate /*
24410Sstevel@tonic-gate * Remove a directory.
24420Sstevel@tonic-gate * Remove the given directory name from the given parent directory.
24430Sstevel@tonic-gate */
24440Sstevel@tonic-gate void
rfs_rmdir(struct nfsdiropargs * da,enum nfsstat * status,struct exportinfo * exi,struct svc_req * req,cred_t * cr)24450Sstevel@tonic-gate rfs_rmdir(struct nfsdiropargs *da, enum nfsstat *status,
24460Sstevel@tonic-gate struct exportinfo *exi, struct svc_req *req, cred_t *cr)
24470Sstevel@tonic-gate {
24480Sstevel@tonic-gate int error;
24490Sstevel@tonic-gate vnode_t *vp;
24500Sstevel@tonic-gate
24510Sstevel@tonic-gate
24520Sstevel@tonic-gate /*
24530Sstevel@tonic-gate * Disallow NULL paths
24540Sstevel@tonic-gate */
24550Sstevel@tonic-gate if (da->da_name == NULL || *da->da_name == '\0') {
24560Sstevel@tonic-gate *status = NFSERR_ACCES;
24570Sstevel@tonic-gate return;
24580Sstevel@tonic-gate }
24590Sstevel@tonic-gate
24600Sstevel@tonic-gate vp = nfs_fhtovp(da->da_fhandle, exi);
24610Sstevel@tonic-gate if (vp == NULL) {
24620Sstevel@tonic-gate *status = NFSERR_STALE;
24630Sstevel@tonic-gate return;
24640Sstevel@tonic-gate }
24650Sstevel@tonic-gate
24660Sstevel@tonic-gate if (rdonly(exi, req)) {
24670Sstevel@tonic-gate VN_RELE(vp);
24680Sstevel@tonic-gate *status = NFSERR_ROFS;
24690Sstevel@tonic-gate return;
24700Sstevel@tonic-gate }
24710Sstevel@tonic-gate
24720Sstevel@tonic-gate /*
24730Sstevel@tonic-gate * VOP_RMDIR now takes a new third argument (the current
24740Sstevel@tonic-gate * directory of the process). That's because someone
24750Sstevel@tonic-gate * wants to return EINVAL if one tries to remove ".".
24760Sstevel@tonic-gate * Of course, NFS servers have no idea what their
24770Sstevel@tonic-gate * clients' current directories are. We fake it by
24780Sstevel@tonic-gate * supplying a vnode known to exist and illegal to
24790Sstevel@tonic-gate * remove.
24800Sstevel@tonic-gate */
24815331Samw error = VOP_RMDIR(vp, da->da_name, rootdir, cr, NULL, 0);
24820Sstevel@tonic-gate
24830Sstevel@tonic-gate /*
24840Sstevel@tonic-gate * Force modified data and metadata out to stable storage.
24850Sstevel@tonic-gate */
24865331Samw (void) VOP_FSYNC(vp, 0, cr, NULL);
24870Sstevel@tonic-gate
24880Sstevel@tonic-gate VN_RELE(vp);
24890Sstevel@tonic-gate
24900Sstevel@tonic-gate /*
24910Sstevel@tonic-gate * System V defines rmdir to return EEXIST, not ENOTEMPTY,
24920Sstevel@tonic-gate * if the directory is not empty. A System V NFS server
24930Sstevel@tonic-gate * needs to map NFSERR_EXIST to NFSERR_NOTEMPTY to transmit
24940Sstevel@tonic-gate * over the wire.
24950Sstevel@tonic-gate */
24960Sstevel@tonic-gate if (error == EEXIST)
24970Sstevel@tonic-gate *status = NFSERR_NOTEMPTY;
24980Sstevel@tonic-gate else
24990Sstevel@tonic-gate *status = puterrno(error);
25000Sstevel@tonic-gate
25010Sstevel@tonic-gate }
25021610Sthurlow void *
rfs_rmdir_getfh(struct nfsdiropargs * da)25030Sstevel@tonic-gate rfs_rmdir_getfh(struct nfsdiropargs *da)
25040Sstevel@tonic-gate {
25050Sstevel@tonic-gate return (da->da_fhandle);
25060Sstevel@tonic-gate }
25070Sstevel@tonic-gate
25080Sstevel@tonic-gate /* ARGSUSED */
25090Sstevel@tonic-gate void
rfs_readdir(struct nfsrddirargs * rda,struct nfsrddirres * rd,struct exportinfo * exi,struct svc_req * req,cred_t * cr)25100Sstevel@tonic-gate rfs_readdir(struct nfsrddirargs *rda, struct nfsrddirres *rd,
25110Sstevel@tonic-gate struct exportinfo *exi, struct svc_req *req, cred_t *cr)
25120Sstevel@tonic-gate {
25130Sstevel@tonic-gate int error;
25140Sstevel@tonic-gate int iseof;
25150Sstevel@tonic-gate struct iovec iov;
25160Sstevel@tonic-gate struct uio uio;
25170Sstevel@tonic-gate vnode_t *vp;
25187961SNatalie.Li@Sun.COM char *ndata = NULL;
25197961SNatalie.Li@Sun.COM struct sockaddr *ca;
25207961SNatalie.Li@Sun.COM size_t nents;
25217961SNatalie.Li@Sun.COM int ret;
25220Sstevel@tonic-gate
25230Sstevel@tonic-gate vp = nfs_fhtovp(&rda->rda_fh, exi);
25240Sstevel@tonic-gate if (vp == NULL) {
25250Sstevel@tonic-gate rd->rd_entries = NULL;
25260Sstevel@tonic-gate rd->rd_status = NFSERR_STALE;
25270Sstevel@tonic-gate return;
25280Sstevel@tonic-gate }
25290Sstevel@tonic-gate
25300Sstevel@tonic-gate if (vp->v_type != VDIR) {
25310Sstevel@tonic-gate VN_RELE(vp);
25320Sstevel@tonic-gate rd->rd_entries = NULL;
25330Sstevel@tonic-gate rd->rd_status = NFSERR_NOTDIR;
25340Sstevel@tonic-gate return;
25350Sstevel@tonic-gate }
25360Sstevel@tonic-gate
25370Sstevel@tonic-gate (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
25387387SRobert.Gordon@Sun.COM
25395331Samw error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
25407387SRobert.Gordon@Sun.COM
25410Sstevel@tonic-gate if (error) {
25420Sstevel@tonic-gate rd->rd_entries = NULL;
25430Sstevel@tonic-gate goto bad;
25440Sstevel@tonic-gate }
25450Sstevel@tonic-gate
25460Sstevel@tonic-gate if (rda->rda_count == 0) {
25470Sstevel@tonic-gate rd->rd_entries = NULL;
25480Sstevel@tonic-gate rd->rd_size = 0;
25490Sstevel@tonic-gate rd->rd_eof = FALSE;
25500Sstevel@tonic-gate goto bad;
25510Sstevel@tonic-gate }
25520Sstevel@tonic-gate
25530Sstevel@tonic-gate rda->rda_count = MIN(rda->rda_count, NFS_MAXDATA);
25540Sstevel@tonic-gate
25550Sstevel@tonic-gate /*
25560Sstevel@tonic-gate * Allocate data for entries. This will be freed by rfs_rddirfree.
25570Sstevel@tonic-gate */
25580Sstevel@tonic-gate rd->rd_bufsize = (uint_t)rda->rda_count;
25590Sstevel@tonic-gate rd->rd_entries = kmem_alloc(rd->rd_bufsize, KM_SLEEP);
25600Sstevel@tonic-gate
25610Sstevel@tonic-gate /*
25620Sstevel@tonic-gate * Set up io vector to read directory data
25630Sstevel@tonic-gate */
25640Sstevel@tonic-gate iov.iov_base = (caddr_t)rd->rd_entries;
25650Sstevel@tonic-gate iov.iov_len = rda->rda_count;
25660Sstevel@tonic-gate uio.uio_iov = &iov;
25670Sstevel@tonic-gate uio.uio_iovcnt = 1;
25680Sstevel@tonic-gate uio.uio_segflg = UIO_SYSSPACE;
25690Sstevel@tonic-gate uio.uio_extflg = UIO_COPY_CACHED;
25700Sstevel@tonic-gate uio.uio_loffset = (offset_t)rda->rda_offset;
25710Sstevel@tonic-gate uio.uio_resid = rda->rda_count;
25720Sstevel@tonic-gate
25730Sstevel@tonic-gate /*
25740Sstevel@tonic-gate * read directory
25750Sstevel@tonic-gate */
25765331Samw error = VOP_READDIR(vp, &uio, cr, &iseof, NULL, 0);
25770Sstevel@tonic-gate
25780Sstevel@tonic-gate /*
25790Sstevel@tonic-gate * Clean up
25800Sstevel@tonic-gate */
25810Sstevel@tonic-gate if (!error) {
25820Sstevel@tonic-gate /*
25830Sstevel@tonic-gate * set size and eof
25840Sstevel@tonic-gate */
25850Sstevel@tonic-gate if (uio.uio_resid == rda->rda_count) {
25860Sstevel@tonic-gate rd->rd_size = 0;
25870Sstevel@tonic-gate rd->rd_eof = TRUE;
25880Sstevel@tonic-gate } else {
25890Sstevel@tonic-gate rd->rd_size = (uint32_t)(rda->rda_count -
25900Sstevel@tonic-gate uio.uio_resid);
25910Sstevel@tonic-gate rd->rd_eof = iseof ? TRUE : FALSE;
25920Sstevel@tonic-gate }
25930Sstevel@tonic-gate }
25940Sstevel@tonic-gate
25957961SNatalie.Li@Sun.COM ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
25967961SNatalie.Li@Sun.COM nents = nfscmd_countents((char *)rd->rd_entries, rd->rd_size);
25977961SNatalie.Li@Sun.COM ret = nfscmd_convdirplus(ca, exi, (char *)rd->rd_entries, nents,
25987961SNatalie.Li@Sun.COM rda->rda_count, &ndata);
25997961SNatalie.Li@Sun.COM
26007961SNatalie.Li@Sun.COM if (ret != 0) {
26017961SNatalie.Li@Sun.COM size_t dropbytes;
26027961SNatalie.Li@Sun.COM /*
26037961SNatalie.Li@Sun.COM * We had to drop one or more entries in order to fit
26047961SNatalie.Li@Sun.COM * during the character conversion. We need to patch
26057961SNatalie.Li@Sun.COM * up the size and eof info.
26067961SNatalie.Li@Sun.COM */
26077961SNatalie.Li@Sun.COM if (rd->rd_eof)
26087961SNatalie.Li@Sun.COM rd->rd_eof = FALSE;
26097961SNatalie.Li@Sun.COM dropbytes = nfscmd_dropped_entrysize(
26107961SNatalie.Li@Sun.COM (struct dirent64 *)rd->rd_entries, nents, ret);
26117961SNatalie.Li@Sun.COM rd->rd_size -= dropbytes;
26127961SNatalie.Li@Sun.COM }
26137961SNatalie.Li@Sun.COM if (ndata == NULL) {
26147961SNatalie.Li@Sun.COM ndata = (char *)rd->rd_entries;
26157961SNatalie.Li@Sun.COM } else if (ndata != (char *)rd->rd_entries) {
26167961SNatalie.Li@Sun.COM kmem_free(rd->rd_entries, rd->rd_bufsize);
26177961SNatalie.Li@Sun.COM rd->rd_entries = (void *)ndata;
26187961SNatalie.Li@Sun.COM rd->rd_bufsize = rda->rda_count;
26197961SNatalie.Li@Sun.COM }
26207961SNatalie.Li@Sun.COM
26210Sstevel@tonic-gate bad:
26220Sstevel@tonic-gate VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
26230Sstevel@tonic-gate
26240Sstevel@tonic-gate #if 0 /* notyet */
26250Sstevel@tonic-gate /*
26260Sstevel@tonic-gate * Don't do this. It causes local disk writes when just
26270Sstevel@tonic-gate * reading the file and the overhead is deemed larger
26280Sstevel@tonic-gate * than the benefit.
26290Sstevel@tonic-gate */
26300Sstevel@tonic-gate /*
26310Sstevel@tonic-gate * Force modified metadata out to stable storage.
26320Sstevel@tonic-gate */
26335331Samw (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
26340Sstevel@tonic-gate #endif
26350Sstevel@tonic-gate
26360Sstevel@tonic-gate VN_RELE(vp);
26370Sstevel@tonic-gate
26380Sstevel@tonic-gate rd->rd_status = puterrno(error);
26390Sstevel@tonic-gate
26400Sstevel@tonic-gate }
26411610Sthurlow void *
rfs_readdir_getfh(struct nfsrddirargs * rda)26420Sstevel@tonic-gate rfs_readdir_getfh(struct nfsrddirargs *rda)
26430Sstevel@tonic-gate {
26440Sstevel@tonic-gate return (&rda->rda_fh);
26450Sstevel@tonic-gate }
26460Sstevel@tonic-gate void
rfs_rddirfree(struct nfsrddirres * rd)26470Sstevel@tonic-gate rfs_rddirfree(struct nfsrddirres *rd)
26480Sstevel@tonic-gate {
26490Sstevel@tonic-gate if (rd->rd_entries != NULL)
26500Sstevel@tonic-gate kmem_free(rd->rd_entries, rd->rd_bufsize);
26510Sstevel@tonic-gate }
26520Sstevel@tonic-gate
26530Sstevel@tonic-gate /* ARGSUSED */
26540Sstevel@tonic-gate void
rfs_statfs(fhandle_t * fh,struct nfsstatfs * fs,struct exportinfo * exi,struct svc_req * req,cred_t * cr)26550Sstevel@tonic-gate rfs_statfs(fhandle_t *fh, struct nfsstatfs *fs, struct exportinfo *exi,
26560Sstevel@tonic-gate struct svc_req *req, cred_t *cr)
26570Sstevel@tonic-gate {
26580Sstevel@tonic-gate int error;
26590Sstevel@tonic-gate struct statvfs64 sb;
26600Sstevel@tonic-gate vnode_t *vp;
26610Sstevel@tonic-gate
26620Sstevel@tonic-gate vp = nfs_fhtovp(fh, exi);
26630Sstevel@tonic-gate if (vp == NULL) {
26640Sstevel@tonic-gate fs->fs_status = NFSERR_STALE;
26650Sstevel@tonic-gate return;
26660Sstevel@tonic-gate }
26670Sstevel@tonic-gate
26680Sstevel@tonic-gate error = VFS_STATVFS(vp->v_vfsp, &sb);
26690Sstevel@tonic-gate
26700Sstevel@tonic-gate if (!error) {
26710Sstevel@tonic-gate fs->fs_tsize = nfstsize();
26720Sstevel@tonic-gate fs->fs_bsize = sb.f_frsize;
26730Sstevel@tonic-gate fs->fs_blocks = sb.f_blocks;
26740Sstevel@tonic-gate fs->fs_bfree = sb.f_bfree;
26750Sstevel@tonic-gate fs->fs_bavail = sb.f_bavail;
26760Sstevel@tonic-gate }
26770Sstevel@tonic-gate
26780Sstevel@tonic-gate VN_RELE(vp);
26790Sstevel@tonic-gate
26800Sstevel@tonic-gate fs->fs_status = puterrno(error);
26810Sstevel@tonic-gate
26820Sstevel@tonic-gate }
26831610Sthurlow void *
rfs_statfs_getfh(fhandle_t * fh)26840Sstevel@tonic-gate rfs_statfs_getfh(fhandle_t *fh)
26850Sstevel@tonic-gate {
26860Sstevel@tonic-gate return (fh);
26870Sstevel@tonic-gate }
26880Sstevel@tonic-gate
26890Sstevel@tonic-gate static int
sattr_to_vattr(struct nfssattr * sa,struct vattr * vap)26900Sstevel@tonic-gate sattr_to_vattr(struct nfssattr *sa, struct vattr *vap)
26910Sstevel@tonic-gate {
26920Sstevel@tonic-gate vap->va_mask = 0;
26930Sstevel@tonic-gate
26940Sstevel@tonic-gate /*
26950Sstevel@tonic-gate * There was a sign extension bug in some VFS based systems
26960Sstevel@tonic-gate * which stored the mode as a short. When it would get
26970Sstevel@tonic-gate * assigned to a u_long, no sign extension would occur.
26980Sstevel@tonic-gate * It needed to, but this wasn't noticed because sa_mode
26990Sstevel@tonic-gate * would then get assigned back to the short, thus ignoring
27000Sstevel@tonic-gate * the upper 16 bits of sa_mode.
27010Sstevel@tonic-gate *
27020Sstevel@tonic-gate * To make this implementation work for both broken
27030Sstevel@tonic-gate * clients and good clients, we check for both versions
27040Sstevel@tonic-gate * of the mode.
27050Sstevel@tonic-gate */
27060Sstevel@tonic-gate if (sa->sa_mode != (uint32_t)((ushort_t)-1) &&
27070Sstevel@tonic-gate sa->sa_mode != (uint32_t)-1) {
27080Sstevel@tonic-gate vap->va_mask |= AT_MODE;
27090Sstevel@tonic-gate vap->va_mode = sa->sa_mode;
27100Sstevel@tonic-gate }
27110Sstevel@tonic-gate if (sa->sa_uid != (uint32_t)-1) {
27120Sstevel@tonic-gate vap->va_mask |= AT_UID;
27130Sstevel@tonic-gate vap->va_uid = sa->sa_uid;
27140Sstevel@tonic-gate }
27150Sstevel@tonic-gate if (sa->sa_gid != (uint32_t)-1) {
27160Sstevel@tonic-gate vap->va_mask |= AT_GID;
27170Sstevel@tonic-gate vap->va_gid = sa->sa_gid;
27180Sstevel@tonic-gate }
27190Sstevel@tonic-gate if (sa->sa_size != (uint32_t)-1) {
27200Sstevel@tonic-gate vap->va_mask |= AT_SIZE;
27210Sstevel@tonic-gate vap->va_size = sa->sa_size;
27220Sstevel@tonic-gate }
27230Sstevel@tonic-gate if (sa->sa_atime.tv_sec != (int32_t)-1 &&
27240Sstevel@tonic-gate sa->sa_atime.tv_usec != (int32_t)-1) {
27250Sstevel@tonic-gate #ifndef _LP64
27260Sstevel@tonic-gate /* return error if time overflow */
27270Sstevel@tonic-gate if (!NFS2_TIME_OK(sa->sa_atime.tv_sec))
27280Sstevel@tonic-gate return (EOVERFLOW);
27290Sstevel@tonic-gate #endif
27300Sstevel@tonic-gate vap->va_mask |= AT_ATIME;
27310Sstevel@tonic-gate /*
27320Sstevel@tonic-gate * nfs protocol defines times as unsigned so don't extend sign,
27330Sstevel@tonic-gate * unless sysadmin set nfs_allow_preepoch_time.
27340Sstevel@tonic-gate */
27350Sstevel@tonic-gate NFS_TIME_T_CONVERT(vap->va_atime.tv_sec, sa->sa_atime.tv_sec);
27360Sstevel@tonic-gate vap->va_atime.tv_nsec = (uint32_t)(sa->sa_atime.tv_usec * 1000);
27370Sstevel@tonic-gate }
27380Sstevel@tonic-gate if (sa->sa_mtime.tv_sec != (int32_t)-1 &&
27390Sstevel@tonic-gate sa->sa_mtime.tv_usec != (int32_t)-1) {
27400Sstevel@tonic-gate #ifndef _LP64
27410Sstevel@tonic-gate /* return error if time overflow */
27420Sstevel@tonic-gate if (!NFS2_TIME_OK(sa->sa_mtime.tv_sec))
27430Sstevel@tonic-gate return (EOVERFLOW);
27440Sstevel@tonic-gate #endif
27450Sstevel@tonic-gate vap->va_mask |= AT_MTIME;
27460Sstevel@tonic-gate /*
27470Sstevel@tonic-gate * nfs protocol defines times as unsigned so don't extend sign,
27480Sstevel@tonic-gate * unless sysadmin set nfs_allow_preepoch_time.
27490Sstevel@tonic-gate */
27500Sstevel@tonic-gate NFS_TIME_T_CONVERT(vap->va_mtime.tv_sec, sa->sa_mtime.tv_sec);
27510Sstevel@tonic-gate vap->va_mtime.tv_nsec = (uint32_t)(sa->sa_mtime.tv_usec * 1000);
27520Sstevel@tonic-gate }
27530Sstevel@tonic-gate return (0);
27540Sstevel@tonic-gate }
27550Sstevel@tonic-gate
27560Sstevel@tonic-gate static enum nfsftype vt_to_nf[] = {
27570Sstevel@tonic-gate 0, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, 0, 0, 0, NFSOC, 0
27580Sstevel@tonic-gate };
27590Sstevel@tonic-gate
27600Sstevel@tonic-gate /*
27610Sstevel@tonic-gate * check the following fields for overflow: nodeid, size, and time.
27620Sstevel@tonic-gate * There could be a problem when converting 64-bit LP64 fields
27630Sstevel@tonic-gate * into 32-bit ones. Return an error if there is an overflow.
27640Sstevel@tonic-gate */
27650Sstevel@tonic-gate int
vattr_to_nattr(struct vattr * vap,struct nfsfattr * na)27660Sstevel@tonic-gate vattr_to_nattr(struct vattr *vap, struct nfsfattr *na)
27670Sstevel@tonic-gate {
27680Sstevel@tonic-gate ASSERT(vap->va_type >= VNON && vap->va_type <= VBAD);
27690Sstevel@tonic-gate na->na_type = vt_to_nf[vap->va_type];
27700Sstevel@tonic-gate
27710Sstevel@tonic-gate if (vap->va_mode == (unsigned short) -1)
27720Sstevel@tonic-gate na->na_mode = (uint32_t)-1;
27730Sstevel@tonic-gate else
27740Sstevel@tonic-gate na->na_mode = VTTOIF(vap->va_type) | vap->va_mode;
27750Sstevel@tonic-gate
27760Sstevel@tonic-gate if (vap->va_uid == (unsigned short)(-1))
27770Sstevel@tonic-gate na->na_uid = (uint32_t)(-1);
27780Sstevel@tonic-gate else if (vap->va_uid == UID_NOBODY)
27790Sstevel@tonic-gate na->na_uid = (uint32_t)NFS_UID_NOBODY;
27800Sstevel@tonic-gate else
27810Sstevel@tonic-gate na->na_uid = vap->va_uid;
27820Sstevel@tonic-gate
27830Sstevel@tonic-gate if (vap->va_gid == (unsigned short)(-1))
27840Sstevel@tonic-gate na->na_gid = (uint32_t)-1;
27850Sstevel@tonic-gate else if (vap->va_gid == GID_NOBODY)
27860Sstevel@tonic-gate na->na_gid = (uint32_t)NFS_GID_NOBODY;
27870Sstevel@tonic-gate else
27880Sstevel@tonic-gate na->na_gid = vap->va_gid;
27890Sstevel@tonic-gate
27900Sstevel@tonic-gate /*
27910Sstevel@tonic-gate * Do we need to check fsid for overflow? It is 64-bit in the
27920Sstevel@tonic-gate * vattr, but are bigger than 32 bit values supported?
27930Sstevel@tonic-gate */
27940Sstevel@tonic-gate na->na_fsid = vap->va_fsid;
27950Sstevel@tonic-gate
27960Sstevel@tonic-gate na->na_nodeid = vap->va_nodeid;
27970Sstevel@tonic-gate
27980Sstevel@tonic-gate /*
27990Sstevel@tonic-gate * Check to make sure that the nodeid is representable over the
28000Sstevel@tonic-gate * wire without losing bits.
28010Sstevel@tonic-gate */
28020Sstevel@tonic-gate if (vap->va_nodeid != (u_longlong_t)na->na_nodeid)
28030Sstevel@tonic-gate return (EFBIG);
28040Sstevel@tonic-gate na->na_nlink = vap->va_nlink;
28050Sstevel@tonic-gate
28060Sstevel@tonic-gate /*
28070Sstevel@tonic-gate * Check for big files here, instead of at the caller. See
28080Sstevel@tonic-gate * comments in cstat for large special file explanation.
28090Sstevel@tonic-gate */
28100Sstevel@tonic-gate if (vap->va_size > (u_longlong_t)MAXOFF32_T) {
28110Sstevel@tonic-gate if ((vap->va_type == VREG) || (vap->va_type == VDIR))
28120Sstevel@tonic-gate return (EFBIG);
28130Sstevel@tonic-gate if ((vap->va_type == VBLK) || (vap->va_type == VCHR)) {
28140Sstevel@tonic-gate /* UNKNOWN_SIZE | OVERFLOW */
28150Sstevel@tonic-gate na->na_size = MAXOFF32_T;
28160Sstevel@tonic-gate } else
28170Sstevel@tonic-gate na->na_size = vap->va_size;
28180Sstevel@tonic-gate } else
28190Sstevel@tonic-gate na->na_size = vap->va_size;
28200Sstevel@tonic-gate
28210Sstevel@tonic-gate /*
28220Sstevel@tonic-gate * If the vnode times overflow the 32-bit times that NFS2
28230Sstevel@tonic-gate * uses on the wire then return an error.
28240Sstevel@tonic-gate */
28250Sstevel@tonic-gate if (!NFS_VAP_TIME_OK(vap)) {
28260Sstevel@tonic-gate return (EOVERFLOW);
28270Sstevel@tonic-gate }
28280Sstevel@tonic-gate na->na_atime.tv_sec = vap->va_atime.tv_sec;
28290Sstevel@tonic-gate na->na_atime.tv_usec = vap->va_atime.tv_nsec / 1000;
28300Sstevel@tonic-gate
28310Sstevel@tonic-gate na->na_mtime.tv_sec = vap->va_mtime.tv_sec;
28320Sstevel@tonic-gate na->na_mtime.tv_usec = vap->va_mtime.tv_nsec / 1000;
28330Sstevel@tonic-gate
28340Sstevel@tonic-gate na->na_ctime.tv_sec = vap->va_ctime.tv_sec;
28350Sstevel@tonic-gate na->na_ctime.tv_usec = vap->va_ctime.tv_nsec / 1000;
28360Sstevel@tonic-gate
28370Sstevel@tonic-gate /*
28380Sstevel@tonic-gate * If the dev_t will fit into 16 bits then compress
28390Sstevel@tonic-gate * it, otherwise leave it alone. See comments in
28400Sstevel@tonic-gate * nfs_client.c.
28410Sstevel@tonic-gate */
28420Sstevel@tonic-gate if (getminor(vap->va_rdev) <= SO4_MAXMIN &&
28430Sstevel@tonic-gate getmajor(vap->va_rdev) <= SO4_MAXMAJ)
28440Sstevel@tonic-gate na->na_rdev = nfsv2_cmpdev(vap->va_rdev);
28450Sstevel@tonic-gate else
28460Sstevel@tonic-gate (void) cmpldev(&na->na_rdev, vap->va_rdev);
28470Sstevel@tonic-gate
28480Sstevel@tonic-gate na->na_blocks = vap->va_nblocks;
28490Sstevel@tonic-gate na->na_blocksize = vap->va_blksize;
28500Sstevel@tonic-gate
28510Sstevel@tonic-gate /*
28520Sstevel@tonic-gate * This bit of ugliness is a *TEMPORARY* hack to preserve the
28530Sstevel@tonic-gate * over-the-wire protocols for named-pipe vnodes. It remaps the
28540Sstevel@tonic-gate * VFIFO type to the special over-the-wire type. (see note in nfs.h)
28550Sstevel@tonic-gate *
28560Sstevel@tonic-gate * BUYER BEWARE:
28570Sstevel@tonic-gate * If you are porting the NFS to a non-Sun server, you probably
28580Sstevel@tonic-gate * don't want to include the following block of code. The
28590Sstevel@tonic-gate * over-the-wire special file types will be changing with the
28600Sstevel@tonic-gate * NFS Protocol Revision.
28610Sstevel@tonic-gate */
28620Sstevel@tonic-gate if (vap->va_type == VFIFO)
28630Sstevel@tonic-gate NA_SETFIFO(na);
28640Sstevel@tonic-gate return (0);
28650Sstevel@tonic-gate }
28660Sstevel@tonic-gate
28670Sstevel@tonic-gate /*
28680Sstevel@tonic-gate * acl v2 support: returns approximate permission.
28690Sstevel@tonic-gate * default: returns minimal permission (more restrictive)
28700Sstevel@tonic-gate * aclok: returns maximal permission (less restrictive)
28710Sstevel@tonic-gate * This routine changes the permissions that are alaredy in *va.
28720Sstevel@tonic-gate * If a file has minimal ACL, i.e. aclcnt == MIN_ACL_ENTRIES,
28730Sstevel@tonic-gate * CLASS_OBJ is always the same as GROUP_OBJ entry.
28740Sstevel@tonic-gate */
28750Sstevel@tonic-gate static void
acl_perm(struct vnode * vp,struct exportinfo * exi,struct vattr * va,cred_t * cr)28760Sstevel@tonic-gate acl_perm(struct vnode *vp, struct exportinfo *exi, struct vattr *va, cred_t *cr)
28770Sstevel@tonic-gate {
28780Sstevel@tonic-gate vsecattr_t vsa;
28790Sstevel@tonic-gate int aclcnt;
28800Sstevel@tonic-gate aclent_t *aclentp;
28810Sstevel@tonic-gate mode_t mask_perm;
28820Sstevel@tonic-gate mode_t grp_perm;
28830Sstevel@tonic-gate mode_t other_perm;
28840Sstevel@tonic-gate mode_t other_orig;
28850Sstevel@tonic-gate int error;
28860Sstevel@tonic-gate
28870Sstevel@tonic-gate /* dont care default acl */
28880Sstevel@tonic-gate vsa.vsa_mask = (VSA_ACL | VSA_ACLCNT);
28895331Samw error = VOP_GETSECATTR(vp, &vsa, 0, cr, NULL);
28900Sstevel@tonic-gate
28910Sstevel@tonic-gate if (!error) {
28920Sstevel@tonic-gate aclcnt = vsa.vsa_aclcnt;
28930Sstevel@tonic-gate if (aclcnt > MIN_ACL_ENTRIES) {
28940Sstevel@tonic-gate /* non-trivial ACL */
28950Sstevel@tonic-gate aclentp = vsa.vsa_aclentp;
28960Sstevel@tonic-gate if (exi->exi_export.ex_flags & EX_ACLOK) {
28970Sstevel@tonic-gate /* maximal permissions */
28980Sstevel@tonic-gate grp_perm = 0;
28990Sstevel@tonic-gate other_perm = 0;
29000Sstevel@tonic-gate for (; aclcnt > 0; aclcnt--, aclentp++) {
29010Sstevel@tonic-gate switch (aclentp->a_type) {
29020Sstevel@tonic-gate case USER_OBJ:
29030Sstevel@tonic-gate break;
29040Sstevel@tonic-gate case USER:
29050Sstevel@tonic-gate grp_perm |=
29060Sstevel@tonic-gate aclentp->a_perm << 3;
29070Sstevel@tonic-gate other_perm |= aclentp->a_perm;
29080Sstevel@tonic-gate break;
29090Sstevel@tonic-gate case GROUP_OBJ:
29100Sstevel@tonic-gate grp_perm |=
29110Sstevel@tonic-gate aclentp->a_perm << 3;
29120Sstevel@tonic-gate break;
29130Sstevel@tonic-gate case GROUP:
29140Sstevel@tonic-gate other_perm |= aclentp->a_perm;
29150Sstevel@tonic-gate break;
29160Sstevel@tonic-gate case OTHER_OBJ:
29170Sstevel@tonic-gate other_orig = aclentp->a_perm;
29180Sstevel@tonic-gate break;
29190Sstevel@tonic-gate case CLASS_OBJ:
29200Sstevel@tonic-gate mask_perm = aclentp->a_perm;
29210Sstevel@tonic-gate break;
29220Sstevel@tonic-gate default:
29230Sstevel@tonic-gate break;
29240Sstevel@tonic-gate }
29250Sstevel@tonic-gate }
29260Sstevel@tonic-gate grp_perm &= mask_perm << 3;
29270Sstevel@tonic-gate other_perm &= mask_perm;
29280Sstevel@tonic-gate other_perm |= other_orig;
29290Sstevel@tonic-gate
29300Sstevel@tonic-gate } else {
29310Sstevel@tonic-gate /* minimal permissions */
29320Sstevel@tonic-gate grp_perm = 070;
29330Sstevel@tonic-gate other_perm = 07;
29340Sstevel@tonic-gate for (; aclcnt > 0; aclcnt--, aclentp++) {
29350Sstevel@tonic-gate switch (aclentp->a_type) {
29360Sstevel@tonic-gate case USER_OBJ:
29370Sstevel@tonic-gate break;
29380Sstevel@tonic-gate case USER:
29390Sstevel@tonic-gate case CLASS_OBJ:
29400Sstevel@tonic-gate grp_perm &=
29410Sstevel@tonic-gate aclentp->a_perm << 3;
29420Sstevel@tonic-gate other_perm &=
29430Sstevel@tonic-gate aclentp->a_perm;
29440Sstevel@tonic-gate break;
29450Sstevel@tonic-gate case GROUP_OBJ:
29460Sstevel@tonic-gate grp_perm &=
29470Sstevel@tonic-gate aclentp->a_perm << 3;
29480Sstevel@tonic-gate break;
29490Sstevel@tonic-gate case GROUP:
29500Sstevel@tonic-gate other_perm &=
29510Sstevel@tonic-gate aclentp->a_perm;
29520Sstevel@tonic-gate break;
29530Sstevel@tonic-gate case OTHER_OBJ:
29540Sstevel@tonic-gate other_perm &=
29550Sstevel@tonic-gate aclentp->a_perm;
29560Sstevel@tonic-gate break;
29570Sstevel@tonic-gate default:
29580Sstevel@tonic-gate break;
29590Sstevel@tonic-gate }
29600Sstevel@tonic-gate }
29610Sstevel@tonic-gate }
29620Sstevel@tonic-gate /* copy to va */
29630Sstevel@tonic-gate va->va_mode &= ~077;
29640Sstevel@tonic-gate va->va_mode |= grp_perm | other_perm;
29650Sstevel@tonic-gate }
29660Sstevel@tonic-gate if (vsa.vsa_aclcnt)
29670Sstevel@tonic-gate kmem_free(vsa.vsa_aclentp,
29680Sstevel@tonic-gate vsa.vsa_aclcnt * sizeof (aclent_t));
29690Sstevel@tonic-gate }
29700Sstevel@tonic-gate }
29710Sstevel@tonic-gate
29720Sstevel@tonic-gate void
rfs_srvrinit(void)29730Sstevel@tonic-gate rfs_srvrinit(void)
29740Sstevel@tonic-gate {
29750Sstevel@tonic-gate mutex_init(&rfs_async_write_lock, NULL, MUTEX_DEFAULT, NULL);
29765599Sjwahlig nfs2_srv_caller_id = fs_new_caller_id();
29770Sstevel@tonic-gate }
29780Sstevel@tonic-gate
29790Sstevel@tonic-gate void
rfs_srvrfini(void)29800Sstevel@tonic-gate rfs_srvrfini(void)
29810Sstevel@tonic-gate {
29820Sstevel@tonic-gate mutex_destroy(&rfs_async_write_lock);
29830Sstevel@tonic-gate }
29847387SRobert.Gordon@Sun.COM
29857387SRobert.Gordon@Sun.COM static int
rdma_setup_read_data2(struct nfsreadargs * ra,struct nfsrdresult * rr)29867387SRobert.Gordon@Sun.COM rdma_setup_read_data2(struct nfsreadargs *ra, struct nfsrdresult *rr)
29877387SRobert.Gordon@Sun.COM {
29887387SRobert.Gordon@Sun.COM struct clist *wcl;
29899348SSiddheshwar.Mahesh@Sun.COM int wlist_len;
29907387SRobert.Gordon@Sun.COM uint32_t count = rr->rr_count;
29917387SRobert.Gordon@Sun.COM
29927387SRobert.Gordon@Sun.COM wcl = ra->ra_wlist;
29939348SSiddheshwar.Mahesh@Sun.COM
29949348SSiddheshwar.Mahesh@Sun.COM if (rdma_setup_read_chunks(wcl, count, &wlist_len) == FALSE) {
29957387SRobert.Gordon@Sun.COM return (FALSE);
29967387SRobert.Gordon@Sun.COM }
29977387SRobert.Gordon@Sun.COM
29987387SRobert.Gordon@Sun.COM wcl = ra->ra_wlist;
29999348SSiddheshwar.Mahesh@Sun.COM rr->rr_ok.rrok_wlist_len = wlist_len;
30007387SRobert.Gordon@Sun.COM rr->rr_ok.rrok_wlist = wcl;
30017387SRobert.Gordon@Sun.COM
30027387SRobert.Gordon@Sun.COM return (TRUE);
30037387SRobert.Gordon@Sun.COM }
3004