17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 527242a7cSthurlow * Common Development and Distribution License (the "License"). 627242a7cSthurlow * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 2235bbd688SKaren Rochford * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved. 23ef1d0734SMarcel Telka * Copyright 2014 Nexenta Systems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate /* 277c478bd9Sstevel@tonic-gate * Copyright (c) 1983,1984,1985,1986,1987,1988,1989 AT&T. 287c478bd9Sstevel@tonic-gate * All rights reserved. 297c478bd9Sstevel@tonic-gate */ 307c478bd9Sstevel@tonic-gate 317c478bd9Sstevel@tonic-gate #include <sys/param.h> 327c478bd9Sstevel@tonic-gate #include <sys/types.h> 337c478bd9Sstevel@tonic-gate #include <sys/systm.h> 347c478bd9Sstevel@tonic-gate #include <sys/cred.h> 357c478bd9Sstevel@tonic-gate #include <sys/buf.h> 367c478bd9Sstevel@tonic-gate #include <sys/vfs.h> 377c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 387c478bd9Sstevel@tonic-gate #include <sys/uio.h> 397c478bd9Sstevel@tonic-gate #include <sys/stat.h> 407c478bd9Sstevel@tonic-gate #include <sys/errno.h> 417c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 427c478bd9Sstevel@tonic-gate #include <sys/statvfs.h> 437c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 447c478bd9Sstevel@tonic-gate #include <sys/kstat.h> 457c478bd9Sstevel@tonic-gate #include <sys/dirent.h> 467c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 477c478bd9Sstevel@tonic-gate #include <sys/debug.h> 487c478bd9Sstevel@tonic-gate #include <sys/vtrace.h> 497c478bd9Sstevel@tonic-gate #include <sys/mode.h> 507c478bd9Sstevel@tonic-gate #include <sys/acl.h> 517c478bd9Sstevel@tonic-gate #include <sys/nbmlock.h> 527c478bd9Sstevel@tonic-gate #include <sys/policy.h> 530a701b1eSRobert Gordon #include <sys/sdt.h> 547c478bd9Sstevel@tonic-gate 557c478bd9Sstevel@tonic-gate #include <rpc/types.h> 567c478bd9Sstevel@tonic-gate #include <rpc/auth.h> 577c478bd9Sstevel@tonic-gate #include <rpc/svc.h> 587c478bd9Sstevel@tonic-gate 597c478bd9Sstevel@tonic-gate #include <nfs/nfs.h> 607c478bd9Sstevel@tonic-gate #include <nfs/export.h> 61b89a8333Snatalie li - Sun Microsystems - Irvine United States #include <nfs/nfs_cmd.h> 627c478bd9Sstevel@tonic-gate 637c478bd9Sstevel@tonic-gate #include <vm/hat.h> 647c478bd9Sstevel@tonic-gate #include <vm/as.h> 657c478bd9Sstevel@tonic-gate #include <vm/seg.h> 667c478bd9Sstevel@tonic-gate #include <vm/seg_map.h> 677c478bd9Sstevel@tonic-gate #include <vm/seg_kmem.h> 687c478bd9Sstevel@tonic-gate 697c478bd9Sstevel@tonic-gate #include <sys/strsubr.h> 707c478bd9Sstevel@tonic-gate 717c478bd9Sstevel@tonic-gate /* 727c478bd9Sstevel@tonic-gate * These are the interface routines for the server side of the 737c478bd9Sstevel@tonic-gate * Network File System. See the NFS version 2 protocol specification 747c478bd9Sstevel@tonic-gate * for a description of this interface. 757c478bd9Sstevel@tonic-gate */ 767c478bd9Sstevel@tonic-gate 777c478bd9Sstevel@tonic-gate static int sattr_to_vattr(struct nfssattr *, struct vattr *); 787c478bd9Sstevel@tonic-gate static void acl_perm(struct vnode *, struct exportinfo *, struct vattr *, 797c478bd9Sstevel@tonic-gate cred_t *); 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate /* 827c478bd9Sstevel@tonic-gate * Some "over the wire" UNIX file types. These are encoded 837c478bd9Sstevel@tonic-gate * into the mode. This needs to be fixed in the next rev. 847c478bd9Sstevel@tonic-gate */ 857c478bd9Sstevel@tonic-gate #define IFMT 0170000 /* type of file */ 867c478bd9Sstevel@tonic-gate #define IFCHR 0020000 /* character special */ 877c478bd9Sstevel@tonic-gate #define IFBLK 0060000 /* block special */ 887c478bd9Sstevel@tonic-gate #define IFSOCK 0140000 /* socket */ 897c478bd9Sstevel@tonic-gate 90cfae96c2Sjwahlig u_longlong_t nfs2_srv_caller_id; 91cfae96c2Sjwahlig 927c478bd9Sstevel@tonic-gate /* 937c478bd9Sstevel@tonic-gate * Get file attributes. 947c478bd9Sstevel@tonic-gate * Returns the current attributes of the file with the given fhandle. 957c478bd9Sstevel@tonic-gate */ 967c478bd9Sstevel@tonic-gate /* ARGSUSED */ 977c478bd9Sstevel@tonic-gate void 987c478bd9Sstevel@tonic-gate rfs_getattr(fhandle_t *fhp, struct nfsattrstat *ns, struct exportinfo *exi, 995cb0d679SMarcel Telka struct svc_req *req, cred_t *cr, bool_t ro) 1007c478bd9Sstevel@tonic-gate { 1017c478bd9Sstevel@tonic-gate int error; 1027c478bd9Sstevel@tonic-gate vnode_t *vp; 1037c478bd9Sstevel@tonic-gate struct vattr va; 1047c478bd9Sstevel@tonic-gate 1057c478bd9Sstevel@tonic-gate vp = nfs_fhtovp(fhp, exi); 1067c478bd9Sstevel@tonic-gate if (vp == NULL) { 1077c478bd9Sstevel@tonic-gate ns->ns_status = NFSERR_STALE; 1087c478bd9Sstevel@tonic-gate return; 1097c478bd9Sstevel@tonic-gate } 1107c478bd9Sstevel@tonic-gate 1117c478bd9Sstevel@tonic-gate /* 1127c478bd9Sstevel@tonic-gate * Do the getattr. 1137c478bd9Sstevel@tonic-gate */ 1147c478bd9Sstevel@tonic-gate va.va_mask = AT_ALL; /* we want all the attributes */ 1150a701b1eSRobert Gordon 1167c478bd9Sstevel@tonic-gate error = rfs4_delegated_getattr(vp, &va, 0, cr); 1177c478bd9Sstevel@tonic-gate 1187c478bd9Sstevel@tonic-gate /* check for overflows */ 1197c478bd9Sstevel@tonic-gate if (!error) { 1202f172c55SRobert Thurlow /* Lie about the object type for a referral */ 1212f172c55SRobert Thurlow if (vn_is_nfs_reparse(vp, cr)) 1222f172c55SRobert Thurlow va.va_type = VLNK; 1232f172c55SRobert Thurlow 1247c478bd9Sstevel@tonic-gate acl_perm(vp, exi, &va, cr); 1257c478bd9Sstevel@tonic-gate error = vattr_to_nattr(&va, &ns->ns_attr); 1267c478bd9Sstevel@tonic-gate } 1277c478bd9Sstevel@tonic-gate 1287c478bd9Sstevel@tonic-gate VN_RELE(vp); 1297c478bd9Sstevel@tonic-gate 1307c478bd9Sstevel@tonic-gate ns->ns_status = puterrno(error); 1317c478bd9Sstevel@tonic-gate } 13227242a7cSthurlow void * 1337c478bd9Sstevel@tonic-gate rfs_getattr_getfh(fhandle_t *fhp) 1347c478bd9Sstevel@tonic-gate { 1357c478bd9Sstevel@tonic-gate return (fhp); 1367c478bd9Sstevel@tonic-gate } 1377c478bd9Sstevel@tonic-gate 1387c478bd9Sstevel@tonic-gate /* 1397c478bd9Sstevel@tonic-gate * Set file attributes. 1407c478bd9Sstevel@tonic-gate * Sets the attributes of the file with the given fhandle. Returns 1417c478bd9Sstevel@tonic-gate * the new attributes. 1427c478bd9Sstevel@tonic-gate */ 1435cb0d679SMarcel Telka /* ARGSUSED */ 1447c478bd9Sstevel@tonic-gate void 1457c478bd9Sstevel@tonic-gate rfs_setattr(struct nfssaargs *args, struct nfsattrstat *ns, 1465cb0d679SMarcel Telka struct exportinfo *exi, struct svc_req *req, cred_t *cr, bool_t ro) 1477c478bd9Sstevel@tonic-gate { 1487c478bd9Sstevel@tonic-gate int error; 1497c478bd9Sstevel@tonic-gate int flag; 1507c478bd9Sstevel@tonic-gate int in_crit = 0; 1517c478bd9Sstevel@tonic-gate vnode_t *vp; 1527c478bd9Sstevel@tonic-gate struct vattr va; 1537c478bd9Sstevel@tonic-gate struct vattr bva; 1547c478bd9Sstevel@tonic-gate struct flock64 bf; 155cfae96c2Sjwahlig caller_context_t ct; 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate vp = nfs_fhtovp(&args->saa_fh, exi); 1597c478bd9Sstevel@tonic-gate if (vp == NULL) { 1607c478bd9Sstevel@tonic-gate ns->ns_status = NFSERR_STALE; 1617c478bd9Sstevel@tonic-gate return; 1627c478bd9Sstevel@tonic-gate } 1637c478bd9Sstevel@tonic-gate 1645cb0d679SMarcel Telka if (rdonly(ro, vp)) { 1657c478bd9Sstevel@tonic-gate VN_RELE(vp); 1667c478bd9Sstevel@tonic-gate ns->ns_status = NFSERR_ROFS; 1677c478bd9Sstevel@tonic-gate return; 1687c478bd9Sstevel@tonic-gate } 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate error = sattr_to_vattr(&args->saa_sa, &va); 1717c478bd9Sstevel@tonic-gate if (error) { 1727c478bd9Sstevel@tonic-gate VN_RELE(vp); 1737c478bd9Sstevel@tonic-gate ns->ns_status = puterrno(error); 1747c478bd9Sstevel@tonic-gate return; 1757c478bd9Sstevel@tonic-gate } 1767c478bd9Sstevel@tonic-gate 1777c478bd9Sstevel@tonic-gate /* 1787c478bd9Sstevel@tonic-gate * If the client is requesting a change to the mtime, 1797c478bd9Sstevel@tonic-gate * but the nanosecond field is set to 1 billion, then 1807c478bd9Sstevel@tonic-gate * this is a flag to the server that it should set the 1817c478bd9Sstevel@tonic-gate * atime and mtime fields to the server's current time. 1827c478bd9Sstevel@tonic-gate * The 1 billion number actually came from the client 1837c478bd9Sstevel@tonic-gate * as 1 million, but the units in the over the wire 1847c478bd9Sstevel@tonic-gate * request are microseconds instead of nanoseconds. 1857c478bd9Sstevel@tonic-gate * 1867c478bd9Sstevel@tonic-gate * This is an overload of the protocol and should be 1877c478bd9Sstevel@tonic-gate * documented in the NFS Version 2 protocol specification. 1887c478bd9Sstevel@tonic-gate */ 1897c478bd9Sstevel@tonic-gate if (va.va_mask & AT_MTIME) { 1907c478bd9Sstevel@tonic-gate if (va.va_mtime.tv_nsec == 1000000000) { 1917c478bd9Sstevel@tonic-gate gethrestime(&va.va_mtime); 1927c478bd9Sstevel@tonic-gate va.va_atime = va.va_mtime; 1937c478bd9Sstevel@tonic-gate va.va_mask |= AT_ATIME; 1947c478bd9Sstevel@tonic-gate flag = 0; 1957c478bd9Sstevel@tonic-gate } else 1967c478bd9Sstevel@tonic-gate flag = ATTR_UTIME; 1977c478bd9Sstevel@tonic-gate } else 1987c478bd9Sstevel@tonic-gate flag = 0; 1997c478bd9Sstevel@tonic-gate 2007c478bd9Sstevel@tonic-gate /* 2017c478bd9Sstevel@tonic-gate * If the filesystem is exported with nosuid, then mask off 2027c478bd9Sstevel@tonic-gate * the setuid and setgid bits. 2037c478bd9Sstevel@tonic-gate */ 2047c478bd9Sstevel@tonic-gate if ((va.va_mask & AT_MODE) && vp->v_type == VREG && 2057c478bd9Sstevel@tonic-gate (exi->exi_export.ex_flags & EX_NOSUID)) 2067c478bd9Sstevel@tonic-gate va.va_mode &= ~(VSUID | VSGID); 2077c478bd9Sstevel@tonic-gate 208cfae96c2Sjwahlig ct.cc_sysid = 0; 209cfae96c2Sjwahlig ct.cc_pid = 0; 210cfae96c2Sjwahlig ct.cc_caller_id = nfs2_srv_caller_id; 211cfae96c2Sjwahlig ct.cc_flags = CC_DONTBLOCK; 212cfae96c2Sjwahlig 2137c478bd9Sstevel@tonic-gate /* 2147c478bd9Sstevel@tonic-gate * We need to specially handle size changes because it is 2157c478bd9Sstevel@tonic-gate * possible for the client to create a file with modes 2167c478bd9Sstevel@tonic-gate * which indicate read-only, but with the file opened for 2177c478bd9Sstevel@tonic-gate * writing. If the client then tries to set the size of 2187c478bd9Sstevel@tonic-gate * the file, then the normal access checking done in 2197c478bd9Sstevel@tonic-gate * VOP_SETATTR would prevent the client from doing so, 2207c478bd9Sstevel@tonic-gate * although it should be legal for it to do so. To get 2217c478bd9Sstevel@tonic-gate * around this, we do the access checking for ourselves 2227c478bd9Sstevel@tonic-gate * and then use VOP_SPACE which doesn't do the access 2237c478bd9Sstevel@tonic-gate * checking which VOP_SETATTR does. VOP_SPACE can only 2247c478bd9Sstevel@tonic-gate * operate on VREG files, let VOP_SETATTR handle the other 2257c478bd9Sstevel@tonic-gate * extremely rare cases. 2267c478bd9Sstevel@tonic-gate * Also the client should not be allowed to change the 2277c478bd9Sstevel@tonic-gate * size of the file if there is a conflicting non-blocking 2287c478bd9Sstevel@tonic-gate * mandatory lock in the region of change. 2297c478bd9Sstevel@tonic-gate */ 2307c478bd9Sstevel@tonic-gate if (vp->v_type == VREG && va.va_mask & AT_SIZE) { 2317c478bd9Sstevel@tonic-gate if (nbl_need_check(vp)) { 2327c478bd9Sstevel@tonic-gate nbl_start_crit(vp, RW_READER); 2337c478bd9Sstevel@tonic-gate in_crit = 1; 2347c478bd9Sstevel@tonic-gate } 2357c478bd9Sstevel@tonic-gate 2367c478bd9Sstevel@tonic-gate bva.va_mask = AT_UID | AT_SIZE; 2370a701b1eSRobert Gordon 238cfae96c2Sjwahlig error = VOP_GETATTR(vp, &bva, 0, cr, &ct); 2390a701b1eSRobert Gordon 2407c478bd9Sstevel@tonic-gate if (error) { 2417c478bd9Sstevel@tonic-gate if (in_crit) 2427c478bd9Sstevel@tonic-gate nbl_end_crit(vp); 2437c478bd9Sstevel@tonic-gate VN_RELE(vp); 2447c478bd9Sstevel@tonic-gate ns->ns_status = puterrno(error); 2457c478bd9Sstevel@tonic-gate return; 2467c478bd9Sstevel@tonic-gate } 2477c478bd9Sstevel@tonic-gate 2487c478bd9Sstevel@tonic-gate if (in_crit) { 2497c478bd9Sstevel@tonic-gate u_offset_t offset; 2507c478bd9Sstevel@tonic-gate ssize_t length; 2517c478bd9Sstevel@tonic-gate 2527c478bd9Sstevel@tonic-gate if (va.va_size < bva.va_size) { 2537c478bd9Sstevel@tonic-gate offset = va.va_size; 2547c478bd9Sstevel@tonic-gate length = bva.va_size - va.va_size; 2557c478bd9Sstevel@tonic-gate } else { 2567c478bd9Sstevel@tonic-gate offset = bva.va_size; 2577c478bd9Sstevel@tonic-gate length = va.va_size - bva.va_size; 2587c478bd9Sstevel@tonic-gate } 259da6c28aaSamw if (nbl_conflict(vp, NBL_WRITE, offset, length, 0, 260da6c28aaSamw NULL)) { 2617c478bd9Sstevel@tonic-gate error = EACCES; 2627c478bd9Sstevel@tonic-gate } 2637c478bd9Sstevel@tonic-gate } 2647c478bd9Sstevel@tonic-gate 2657c478bd9Sstevel@tonic-gate if (crgetuid(cr) == bva.va_uid && !error && 2667c478bd9Sstevel@tonic-gate va.va_size != bva.va_size) { 2677c478bd9Sstevel@tonic-gate va.va_mask &= ~AT_SIZE; 2687c478bd9Sstevel@tonic-gate bf.l_type = F_WRLCK; 2697c478bd9Sstevel@tonic-gate bf.l_whence = 0; 2707c478bd9Sstevel@tonic-gate bf.l_start = (off64_t)va.va_size; 2717c478bd9Sstevel@tonic-gate bf.l_len = 0; 2727c478bd9Sstevel@tonic-gate bf.l_sysid = 0; 2737c478bd9Sstevel@tonic-gate bf.l_pid = 0; 2740a701b1eSRobert Gordon 2757c478bd9Sstevel@tonic-gate error = VOP_SPACE(vp, F_FREESP, &bf, FWRITE, 276cfae96c2Sjwahlig (offset_t)va.va_size, cr, &ct); 2777c478bd9Sstevel@tonic-gate } 2787c478bd9Sstevel@tonic-gate if (in_crit) 2797c478bd9Sstevel@tonic-gate nbl_end_crit(vp); 2807c478bd9Sstevel@tonic-gate } else 2817c478bd9Sstevel@tonic-gate error = 0; 2827c478bd9Sstevel@tonic-gate 2837c478bd9Sstevel@tonic-gate /* 2847c478bd9Sstevel@tonic-gate * Do the setattr. 2857c478bd9Sstevel@tonic-gate */ 2867c478bd9Sstevel@tonic-gate if (!error && va.va_mask) { 287cfae96c2Sjwahlig error = VOP_SETATTR(vp, &va, flag, cr, &ct); 2887c478bd9Sstevel@tonic-gate } 2897c478bd9Sstevel@tonic-gate 290cfae96c2Sjwahlig /* 291cfae96c2Sjwahlig * check if the monitor on either vop_space or vop_setattr detected 292cfae96c2Sjwahlig * a delegation conflict and if so, mark the thread flag as 293cfae96c2Sjwahlig * wouldblock so that the response is dropped and the client will 294cfae96c2Sjwahlig * try again. 295cfae96c2Sjwahlig */ 296cfae96c2Sjwahlig if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) { 297cfae96c2Sjwahlig VN_RELE(vp); 298cfae96c2Sjwahlig curthread->t_flag |= T_WOULDBLOCK; 299cfae96c2Sjwahlig return; 300cfae96c2Sjwahlig } 301cfae96c2Sjwahlig 3027c478bd9Sstevel@tonic-gate if (!error) { 3037c478bd9Sstevel@tonic-gate va.va_mask = AT_ALL; /* get everything */ 3040a701b1eSRobert Gordon 3057c478bd9Sstevel@tonic-gate error = rfs4_delegated_getattr(vp, &va, 0, cr); 3067c478bd9Sstevel@tonic-gate 3077c478bd9Sstevel@tonic-gate /* check for overflows */ 3087c478bd9Sstevel@tonic-gate if (!error) { 3097c478bd9Sstevel@tonic-gate acl_perm(vp, exi, &va, cr); 3107c478bd9Sstevel@tonic-gate error = vattr_to_nattr(&va, &ns->ns_attr); 3117c478bd9Sstevel@tonic-gate } 3127c478bd9Sstevel@tonic-gate } 3137c478bd9Sstevel@tonic-gate 314cfae96c2Sjwahlig ct.cc_flags = 0; 315cfae96c2Sjwahlig 3167c478bd9Sstevel@tonic-gate /* 3177c478bd9Sstevel@tonic-gate * Force modified metadata out to stable storage. 3187c478bd9Sstevel@tonic-gate */ 319cfae96c2Sjwahlig (void) VOP_FSYNC(vp, FNODSYNC, cr, &ct); 3207c478bd9Sstevel@tonic-gate 3217c478bd9Sstevel@tonic-gate VN_RELE(vp); 3227c478bd9Sstevel@tonic-gate 3237c478bd9Sstevel@tonic-gate ns->ns_status = puterrno(error); 3247c478bd9Sstevel@tonic-gate } 32527242a7cSthurlow void * 3267c478bd9Sstevel@tonic-gate rfs_setattr_getfh(struct nfssaargs *args) 3277c478bd9Sstevel@tonic-gate { 3287c478bd9Sstevel@tonic-gate return (&args->saa_fh); 3297c478bd9Sstevel@tonic-gate } 3307c478bd9Sstevel@tonic-gate 3317c478bd9Sstevel@tonic-gate /* 3327c478bd9Sstevel@tonic-gate * Directory lookup. 3337c478bd9Sstevel@tonic-gate * Returns an fhandle and file attributes for file name in a directory. 3347c478bd9Sstevel@tonic-gate */ 3357c478bd9Sstevel@tonic-gate /* ARGSUSED */ 3367c478bd9Sstevel@tonic-gate void 3377c478bd9Sstevel@tonic-gate rfs_lookup(struct nfsdiropargs *da, struct nfsdiropres *dr, 3385cb0d679SMarcel Telka struct exportinfo *exi, struct svc_req *req, cred_t *cr, bool_t ro) 3397c478bd9Sstevel@tonic-gate { 3407c478bd9Sstevel@tonic-gate int error; 3417c478bd9Sstevel@tonic-gate vnode_t *dvp; 3427c478bd9Sstevel@tonic-gate vnode_t *vp; 3437c478bd9Sstevel@tonic-gate struct vattr va; 3447c478bd9Sstevel@tonic-gate fhandle_t *fhp = da->da_fhandle; 3457c478bd9Sstevel@tonic-gate struct sec_ol sec = {0, 0}; 3467c478bd9Sstevel@tonic-gate bool_t publicfh_flag = FALSE, auth_weak = FALSE; 347b89a8333Snatalie li - Sun Microsystems - Irvine United States char *name; 348b89a8333Snatalie li - Sun Microsystems - Irvine United States struct sockaddr *ca; 3497c478bd9Sstevel@tonic-gate 3507c478bd9Sstevel@tonic-gate /* 35103986916Sjarrett * Trusted Extension doesn't support NFSv2. MOUNT 35203986916Sjarrett * will reject v2 clients. Need to prevent v2 client 35303986916Sjarrett * access via WebNFS here. 35403986916Sjarrett */ 35503986916Sjarrett if (is_system_labeled() && req->rq_vers == 2) { 35603986916Sjarrett dr->dr_status = NFSERR_ACCES; 35703986916Sjarrett return; 35803986916Sjarrett } 35903986916Sjarrett 36003986916Sjarrett /* 3617c478bd9Sstevel@tonic-gate * Disallow NULL paths 3627c478bd9Sstevel@tonic-gate */ 3637c478bd9Sstevel@tonic-gate if (da->da_name == NULL || *da->da_name == '\0') { 3647c478bd9Sstevel@tonic-gate dr->dr_status = NFSERR_ACCES; 3657c478bd9Sstevel@tonic-gate return; 3667c478bd9Sstevel@tonic-gate } 3677c478bd9Sstevel@tonic-gate 3687c478bd9Sstevel@tonic-gate /* 3697c478bd9Sstevel@tonic-gate * Allow lookups from the root - the default 3707c478bd9Sstevel@tonic-gate * location of the public filehandle. 3717c478bd9Sstevel@tonic-gate */ 3727c478bd9Sstevel@tonic-gate if (exi != NULL && (exi->exi_export.ex_flags & EX_PUBLIC)) { 3737c478bd9Sstevel@tonic-gate dvp = rootdir; 3747c478bd9Sstevel@tonic-gate VN_HOLD(dvp); 3757c478bd9Sstevel@tonic-gate } else { 3767c478bd9Sstevel@tonic-gate dvp = nfs_fhtovp(fhp, exi); 3777c478bd9Sstevel@tonic-gate if (dvp == NULL) { 3787c478bd9Sstevel@tonic-gate dr->dr_status = NFSERR_STALE; 3797c478bd9Sstevel@tonic-gate return; 3807c478bd9Sstevel@tonic-gate } 3817c478bd9Sstevel@tonic-gate } 3827c478bd9Sstevel@tonic-gate 3837c478bd9Sstevel@tonic-gate /* 3847c478bd9Sstevel@tonic-gate * Not allow lookup beyond root. 3857c478bd9Sstevel@tonic-gate * If the filehandle matches a filehandle of the exi, 3867c478bd9Sstevel@tonic-gate * then the ".." refers beyond the root of an exported filesystem. 3877c478bd9Sstevel@tonic-gate */ 3887c478bd9Sstevel@tonic-gate if (strcmp(da->da_name, "..") == 0 && 3897c478bd9Sstevel@tonic-gate EQFID(&exi->exi_fid, (fid_t *)&fhp->fh_len)) { 3907c478bd9Sstevel@tonic-gate VN_RELE(dvp); 3917c478bd9Sstevel@tonic-gate dr->dr_status = NFSERR_NOENT; 3927c478bd9Sstevel@tonic-gate return; 3937c478bd9Sstevel@tonic-gate } 3947c478bd9Sstevel@tonic-gate 395b89a8333Snatalie li - Sun Microsystems - Irvine United States ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 396b89a8333Snatalie li - Sun Microsystems - Irvine United States name = nfscmd_convname(ca, exi, da->da_name, NFSCMD_CONV_INBOUND, 397b89a8333Snatalie li - Sun Microsystems - Irvine United States MAXPATHLEN); 398b89a8333Snatalie li - Sun Microsystems - Irvine United States 399b89a8333Snatalie li - Sun Microsystems - Irvine United States if (name == NULL) { 400b89a8333Snatalie li - Sun Microsystems - Irvine United States dr->dr_status = NFSERR_ACCES; 401b89a8333Snatalie li - Sun Microsystems - Irvine United States return; 402b89a8333Snatalie li - Sun Microsystems - Irvine United States } 403b89a8333Snatalie li - Sun Microsystems - Irvine United States 4047c478bd9Sstevel@tonic-gate /* 4057c478bd9Sstevel@tonic-gate * If the public filehandle is used then allow 4067c478bd9Sstevel@tonic-gate * a multi-component lookup, i.e. evaluate 4077c478bd9Sstevel@tonic-gate * a pathname and follow symbolic links if 4087c478bd9Sstevel@tonic-gate * necessary. 4097c478bd9Sstevel@tonic-gate * 4107c478bd9Sstevel@tonic-gate * This may result in a vnode in another filesystem 4117c478bd9Sstevel@tonic-gate * which is OK as long as the filesystem is exported. 4127c478bd9Sstevel@tonic-gate */ 4137c478bd9Sstevel@tonic-gate if (PUBLIC_FH2(fhp)) { 4147c478bd9Sstevel@tonic-gate publicfh_flag = TRUE; 415596bc239SMarcel Telka error = rfs_publicfh_mclookup(name, dvp, cr, &vp, &exi, 4167c478bd9Sstevel@tonic-gate &sec); 4177c478bd9Sstevel@tonic-gate } else { 4187c478bd9Sstevel@tonic-gate /* 4197c478bd9Sstevel@tonic-gate * Do a normal single component lookup. 4207c478bd9Sstevel@tonic-gate */ 421b89a8333Snatalie li - Sun Microsystems - Irvine United States error = VOP_LOOKUP(dvp, name, &vp, NULL, 0, NULL, cr, 422da6c28aaSamw NULL, NULL, NULL); 4237c478bd9Sstevel@tonic-gate } 4247c478bd9Sstevel@tonic-gate 425b89a8333Snatalie li - Sun Microsystems - Irvine United States if (name != da->da_name) 426b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(name, MAXPATHLEN); 427b89a8333Snatalie li - Sun Microsystems - Irvine United States 428b89a8333Snatalie li - Sun Microsystems - Irvine United States 4297c478bd9Sstevel@tonic-gate if (!error) { 4307c478bd9Sstevel@tonic-gate va.va_mask = AT_ALL; /* we want everything */ 4310a701b1eSRobert Gordon 4327c478bd9Sstevel@tonic-gate error = rfs4_delegated_getattr(vp, &va, 0, cr); 4330a701b1eSRobert Gordon 4347c478bd9Sstevel@tonic-gate /* check for overflows */ 4357c478bd9Sstevel@tonic-gate if (!error) { 4367c478bd9Sstevel@tonic-gate acl_perm(vp, exi, &va, cr); 4377c478bd9Sstevel@tonic-gate error = vattr_to_nattr(&va, &dr->dr_attr); 4387c478bd9Sstevel@tonic-gate if (!error) { 4397c478bd9Sstevel@tonic-gate if (sec.sec_flags & SEC_QUERY) 4407c478bd9Sstevel@tonic-gate error = makefh_ol(&dr->dr_fhandle, exi, 4417c478bd9Sstevel@tonic-gate sec.sec_index); 4427c478bd9Sstevel@tonic-gate else { 4437c478bd9Sstevel@tonic-gate error = makefh(&dr->dr_fhandle, vp, 4447c478bd9Sstevel@tonic-gate exi); 4457c478bd9Sstevel@tonic-gate if (!error && publicfh_flag && 4467c478bd9Sstevel@tonic-gate !chk_clnt_sec(exi, req)) 4477c478bd9Sstevel@tonic-gate auth_weak = TRUE; 4487c478bd9Sstevel@tonic-gate } 4497c478bd9Sstevel@tonic-gate } 4507c478bd9Sstevel@tonic-gate } 4517c478bd9Sstevel@tonic-gate VN_RELE(vp); 4527c478bd9Sstevel@tonic-gate } 4537c478bd9Sstevel@tonic-gate 4547c478bd9Sstevel@tonic-gate VN_RELE(dvp); 4557c478bd9Sstevel@tonic-gate 4567c478bd9Sstevel@tonic-gate /* 457596bc239SMarcel Telka * If publicfh_flag is true then we have called rfs_publicfh_mclookup 458596bc239SMarcel Telka * and have obtained a new exportinfo in exi which needs to be 459596bc239SMarcel Telka * released. Note the the original exportinfo pointed to by exi 460596bc239SMarcel Telka * will be released by the caller, comon_dispatch. 4617c478bd9Sstevel@tonic-gate */ 462596bc239SMarcel Telka if (publicfh_flag && exi != NULL) 4637c478bd9Sstevel@tonic-gate exi_rele(exi); 4647c478bd9Sstevel@tonic-gate 4657c478bd9Sstevel@tonic-gate /* 4667c478bd9Sstevel@tonic-gate * If it's public fh, no 0x81, and client's flavor is 4677c478bd9Sstevel@tonic-gate * invalid, set WebNFS status to WNFSERR_CLNT_FLAVOR now. 4687c478bd9Sstevel@tonic-gate * Then set RPC status to AUTH_TOOWEAK in common_dispatch. 4697c478bd9Sstevel@tonic-gate */ 4707c478bd9Sstevel@tonic-gate if (auth_weak) 4717c478bd9Sstevel@tonic-gate dr->dr_status = (enum nfsstat)WNFSERR_CLNT_FLAVOR; 4727c478bd9Sstevel@tonic-gate else 4737c478bd9Sstevel@tonic-gate dr->dr_status = puterrno(error); 4747c478bd9Sstevel@tonic-gate } 47527242a7cSthurlow void * 4767c478bd9Sstevel@tonic-gate rfs_lookup_getfh(struct nfsdiropargs *da) 4777c478bd9Sstevel@tonic-gate { 4787c478bd9Sstevel@tonic-gate return (da->da_fhandle); 4797c478bd9Sstevel@tonic-gate } 4807c478bd9Sstevel@tonic-gate 4817c478bd9Sstevel@tonic-gate /* 4827c478bd9Sstevel@tonic-gate * Read symbolic link. 4837c478bd9Sstevel@tonic-gate * Returns the string in the symbolic link at the given fhandle. 4847c478bd9Sstevel@tonic-gate */ 4857c478bd9Sstevel@tonic-gate /* ARGSUSED */ 4867c478bd9Sstevel@tonic-gate void 4877c478bd9Sstevel@tonic-gate rfs_readlink(fhandle_t *fhp, struct nfsrdlnres *rl, struct exportinfo *exi, 4885cb0d679SMarcel Telka struct svc_req *req, cred_t *cr, bool_t ro) 4897c478bd9Sstevel@tonic-gate { 4907c478bd9Sstevel@tonic-gate int error; 4917c478bd9Sstevel@tonic-gate struct iovec iov; 4927c478bd9Sstevel@tonic-gate struct uio uio; 4937c478bd9Sstevel@tonic-gate vnode_t *vp; 4947c478bd9Sstevel@tonic-gate struct vattr va; 495b89a8333Snatalie li - Sun Microsystems - Irvine United States struct sockaddr *ca; 496b89a8333Snatalie li - Sun Microsystems - Irvine United States char *name = NULL; 4972f172c55SRobert Thurlow int is_referral = 0; 4987c478bd9Sstevel@tonic-gate 4997c478bd9Sstevel@tonic-gate vp = nfs_fhtovp(fhp, exi); 5007c478bd9Sstevel@tonic-gate if (vp == NULL) { 5017c478bd9Sstevel@tonic-gate rl->rl_data = NULL; 5027c478bd9Sstevel@tonic-gate rl->rl_status = NFSERR_STALE; 5037c478bd9Sstevel@tonic-gate return; 5047c478bd9Sstevel@tonic-gate } 5057c478bd9Sstevel@tonic-gate 5067c478bd9Sstevel@tonic-gate va.va_mask = AT_MODE; 5070a701b1eSRobert Gordon 508da6c28aaSamw error = VOP_GETATTR(vp, &va, 0, cr, NULL); 5097c478bd9Sstevel@tonic-gate 5107c478bd9Sstevel@tonic-gate if (error) { 5117c478bd9Sstevel@tonic-gate VN_RELE(vp); 5127c478bd9Sstevel@tonic-gate rl->rl_data = NULL; 5137c478bd9Sstevel@tonic-gate rl->rl_status = puterrno(error); 5147c478bd9Sstevel@tonic-gate return; 5157c478bd9Sstevel@tonic-gate } 5167c478bd9Sstevel@tonic-gate 5177c478bd9Sstevel@tonic-gate if (MANDLOCK(vp, va.va_mode)) { 5187c478bd9Sstevel@tonic-gate VN_RELE(vp); 5197c478bd9Sstevel@tonic-gate rl->rl_data = NULL; 5207c478bd9Sstevel@tonic-gate rl->rl_status = NFSERR_ACCES; 5217c478bd9Sstevel@tonic-gate return; 5227c478bd9Sstevel@tonic-gate } 5237c478bd9Sstevel@tonic-gate 5242f172c55SRobert Thurlow /* We lied about the object type for a referral */ 5252f172c55SRobert Thurlow if (vn_is_nfs_reparse(vp, cr)) 5262f172c55SRobert Thurlow is_referral = 1; 5272f172c55SRobert Thurlow 5287c478bd9Sstevel@tonic-gate /* 5297c478bd9Sstevel@tonic-gate * XNFS and RFC1094 require us to return ENXIO if argument 5307c478bd9Sstevel@tonic-gate * is not a link. BUGID 1138002. 5317c478bd9Sstevel@tonic-gate */ 5322f172c55SRobert Thurlow if (vp->v_type != VLNK && !is_referral) { 5337c478bd9Sstevel@tonic-gate VN_RELE(vp); 5347c478bd9Sstevel@tonic-gate rl->rl_data = NULL; 5357c478bd9Sstevel@tonic-gate rl->rl_status = NFSERR_NXIO; 5367c478bd9Sstevel@tonic-gate return; 5377c478bd9Sstevel@tonic-gate } 5387c478bd9Sstevel@tonic-gate 5397c478bd9Sstevel@tonic-gate /* 5407c478bd9Sstevel@tonic-gate * Allocate data for pathname. This will be freed by rfs_rlfree. 5417c478bd9Sstevel@tonic-gate */ 5427c478bd9Sstevel@tonic-gate rl->rl_data = kmem_alloc(NFS_MAXPATHLEN, KM_SLEEP); 5437c478bd9Sstevel@tonic-gate 5442f172c55SRobert Thurlow if (is_referral) { 5452f172c55SRobert Thurlow char *s; 5462f172c55SRobert Thurlow size_t strsz; 5472f172c55SRobert Thurlow 5482f172c55SRobert Thurlow /* Get an artificial symlink based on a referral */ 5492f172c55SRobert Thurlow s = build_symlink(vp, cr, &strsz); 5502f172c55SRobert Thurlow global_svstat_ptr[2][NFS_REFERLINKS].value.ui64++; 5512f172c55SRobert Thurlow DTRACE_PROBE2(nfs2serv__func__referral__reflink, 5522f172c55SRobert Thurlow vnode_t *, vp, char *, s); 5532f172c55SRobert Thurlow if (s == NULL) 5542f172c55SRobert Thurlow error = EINVAL; 5552f172c55SRobert Thurlow else { 5562f172c55SRobert Thurlow error = 0; 5572f172c55SRobert Thurlow (void) strlcpy(rl->rl_data, s, NFS_MAXPATHLEN); 5582f172c55SRobert Thurlow rl->rl_count = (uint32_t)MIN(strsz, NFS_MAXPATHLEN); 5592f172c55SRobert Thurlow kmem_free(s, strsz); 5602f172c55SRobert Thurlow } 5612f172c55SRobert Thurlow 5622f172c55SRobert Thurlow } else { 5632f172c55SRobert Thurlow 5647c478bd9Sstevel@tonic-gate /* 5657c478bd9Sstevel@tonic-gate * Set up io vector to read sym link data 5667c478bd9Sstevel@tonic-gate */ 5677c478bd9Sstevel@tonic-gate iov.iov_base = rl->rl_data; 5687c478bd9Sstevel@tonic-gate iov.iov_len = NFS_MAXPATHLEN; 5697c478bd9Sstevel@tonic-gate uio.uio_iov = &iov; 5707c478bd9Sstevel@tonic-gate uio.uio_iovcnt = 1; 5717c478bd9Sstevel@tonic-gate uio.uio_segflg = UIO_SYSSPACE; 5727c478bd9Sstevel@tonic-gate uio.uio_extflg = UIO_COPY_CACHED; 5737c478bd9Sstevel@tonic-gate uio.uio_loffset = (offset_t)0; 5747c478bd9Sstevel@tonic-gate uio.uio_resid = NFS_MAXPATHLEN; 5757c478bd9Sstevel@tonic-gate 5767c478bd9Sstevel@tonic-gate /* 5777c478bd9Sstevel@tonic-gate * Do the readlink. 5787c478bd9Sstevel@tonic-gate */ 579da6c28aaSamw error = VOP_READLINK(vp, &uio, cr, NULL); 5807c478bd9Sstevel@tonic-gate 5817c478bd9Sstevel@tonic-gate rl->rl_count = (uint32_t)(NFS_MAXPATHLEN - uio.uio_resid); 5822f172c55SRobert Thurlow 5832f172c55SRobert Thurlow if (!error) 584b89a8333Snatalie li - Sun Microsystems - Irvine United States rl->rl_data[rl->rl_count] = '\0'; 585b89a8333Snatalie li - Sun Microsystems - Irvine United States 5862f172c55SRobert Thurlow } 5872f172c55SRobert Thurlow 5882f172c55SRobert Thurlow 5892f172c55SRobert Thurlow VN_RELE(vp); 5902f172c55SRobert Thurlow 591b89a8333Snatalie li - Sun Microsystems - Irvine United States ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 592b89a8333Snatalie li - Sun Microsystems - Irvine United States name = nfscmd_convname(ca, exi, rl->rl_data, 593b89a8333Snatalie li - Sun Microsystems - Irvine United States NFSCMD_CONV_OUTBOUND, MAXPATHLEN); 594b89a8333Snatalie li - Sun Microsystems - Irvine United States 595b89a8333Snatalie li - Sun Microsystems - Irvine United States if (name != NULL && name != rl->rl_data) { 596b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(rl->rl_data, NFS_MAXPATHLEN); 597b89a8333Snatalie li - Sun Microsystems - Irvine United States rl->rl_data = name; 598b89a8333Snatalie li - Sun Microsystems - Irvine United States } 5997c478bd9Sstevel@tonic-gate 6007c478bd9Sstevel@tonic-gate /* 6017c478bd9Sstevel@tonic-gate * XNFS and RFC1094 require us to return ENXIO if argument 6027c478bd9Sstevel@tonic-gate * is not a link. UFS returns EINVAL if this is the case, 6037c478bd9Sstevel@tonic-gate * so we do the mapping here. BUGID 1138002. 6047c478bd9Sstevel@tonic-gate */ 6057c478bd9Sstevel@tonic-gate if (error == EINVAL) 6067c478bd9Sstevel@tonic-gate rl->rl_status = NFSERR_NXIO; 6077c478bd9Sstevel@tonic-gate else 6087c478bd9Sstevel@tonic-gate rl->rl_status = puterrno(error); 6097c478bd9Sstevel@tonic-gate 6107c478bd9Sstevel@tonic-gate } 61127242a7cSthurlow void * 6127c478bd9Sstevel@tonic-gate rfs_readlink_getfh(fhandle_t *fhp) 6137c478bd9Sstevel@tonic-gate { 6147c478bd9Sstevel@tonic-gate return (fhp); 6157c478bd9Sstevel@tonic-gate } 6167c478bd9Sstevel@tonic-gate /* 6177c478bd9Sstevel@tonic-gate * Free data allocated by rfs_readlink 6187c478bd9Sstevel@tonic-gate */ 6197c478bd9Sstevel@tonic-gate void 6207c478bd9Sstevel@tonic-gate rfs_rlfree(struct nfsrdlnres *rl) 6217c478bd9Sstevel@tonic-gate { 6227c478bd9Sstevel@tonic-gate if (rl->rl_data != NULL) 6237c478bd9Sstevel@tonic-gate kmem_free(rl->rl_data, NFS_MAXPATHLEN); 6247c478bd9Sstevel@tonic-gate } 6257c478bd9Sstevel@tonic-gate 6260a701b1eSRobert Gordon static int rdma_setup_read_data2(struct nfsreadargs *, struct nfsrdresult *); 6270a701b1eSRobert Gordon 6287c478bd9Sstevel@tonic-gate /* 6297c478bd9Sstevel@tonic-gate * Read data. 6307c478bd9Sstevel@tonic-gate * Returns some data read from the file at the given fhandle. 6317c478bd9Sstevel@tonic-gate */ 6327c478bd9Sstevel@tonic-gate /* ARGSUSED */ 6337c478bd9Sstevel@tonic-gate void 6347c478bd9Sstevel@tonic-gate rfs_read(struct nfsreadargs *ra, struct nfsrdresult *rr, 6355cb0d679SMarcel Telka struct exportinfo *exi, struct svc_req *req, cred_t *cr, bool_t ro) 6367c478bd9Sstevel@tonic-gate { 6377c478bd9Sstevel@tonic-gate vnode_t *vp; 6387c478bd9Sstevel@tonic-gate int error; 6397c478bd9Sstevel@tonic-gate struct vattr va; 6407c478bd9Sstevel@tonic-gate struct iovec iov; 6417c478bd9Sstevel@tonic-gate struct uio uio; 6427c478bd9Sstevel@tonic-gate mblk_t *mp; 6437c478bd9Sstevel@tonic-gate int alloc_err = 0; 6447c478bd9Sstevel@tonic-gate int in_crit = 0; 645cfae96c2Sjwahlig caller_context_t ct; 6467c478bd9Sstevel@tonic-gate 6477c478bd9Sstevel@tonic-gate vp = nfs_fhtovp(&ra->ra_fhandle, exi); 6487c478bd9Sstevel@tonic-gate if (vp == NULL) { 6497c478bd9Sstevel@tonic-gate rr->rr_data = NULL; 6507c478bd9Sstevel@tonic-gate rr->rr_status = NFSERR_STALE; 6517c478bd9Sstevel@tonic-gate return; 6527c478bd9Sstevel@tonic-gate } 6537c478bd9Sstevel@tonic-gate 6547c478bd9Sstevel@tonic-gate if (vp->v_type != VREG) { 6557c478bd9Sstevel@tonic-gate VN_RELE(vp); 6567c478bd9Sstevel@tonic-gate rr->rr_data = NULL; 6577c478bd9Sstevel@tonic-gate rr->rr_status = NFSERR_ISDIR; 6587c478bd9Sstevel@tonic-gate return; 6597c478bd9Sstevel@tonic-gate } 6607c478bd9Sstevel@tonic-gate 661cfae96c2Sjwahlig ct.cc_sysid = 0; 662cfae96c2Sjwahlig ct.cc_pid = 0; 663cfae96c2Sjwahlig ct.cc_caller_id = nfs2_srv_caller_id; 664cfae96c2Sjwahlig ct.cc_flags = CC_DONTBLOCK; 6657c478bd9Sstevel@tonic-gate 6667c478bd9Sstevel@tonic-gate /* 6677c478bd9Sstevel@tonic-gate * Enter the critical region before calling VOP_RWLOCK 6687c478bd9Sstevel@tonic-gate * to avoid a deadlock with write requests. 6697c478bd9Sstevel@tonic-gate */ 6707c478bd9Sstevel@tonic-gate if (nbl_need_check(vp)) { 6717c478bd9Sstevel@tonic-gate nbl_start_crit(vp, RW_READER); 6727c478bd9Sstevel@tonic-gate if (nbl_conflict(vp, NBL_READ, ra->ra_offset, ra->ra_count, 673da6c28aaSamw 0, NULL)) { 6747c478bd9Sstevel@tonic-gate nbl_end_crit(vp); 6757c478bd9Sstevel@tonic-gate VN_RELE(vp); 6767c478bd9Sstevel@tonic-gate rr->rr_data = NULL; 6777c478bd9Sstevel@tonic-gate rr->rr_status = NFSERR_ACCES; 6787c478bd9Sstevel@tonic-gate return; 6797c478bd9Sstevel@tonic-gate } 6807c478bd9Sstevel@tonic-gate in_crit = 1; 6817c478bd9Sstevel@tonic-gate } 6827c478bd9Sstevel@tonic-gate 683cfae96c2Sjwahlig error = VOP_RWLOCK(vp, V_WRITELOCK_FALSE, &ct); 6847c478bd9Sstevel@tonic-gate 685cfae96c2Sjwahlig /* check if a monitor detected a delegation conflict */ 686cfae96c2Sjwahlig if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) { 687cfae96c2Sjwahlig VN_RELE(vp); 688cfae96c2Sjwahlig /* mark as wouldblock so response is dropped */ 689cfae96c2Sjwahlig curthread->t_flag |= T_WOULDBLOCK; 6900a701b1eSRobert Gordon 691cfae96c2Sjwahlig rr->rr_data = NULL; 692cfae96c2Sjwahlig return; 693cfae96c2Sjwahlig } 694cfae96c2Sjwahlig 6957c478bd9Sstevel@tonic-gate va.va_mask = AT_ALL; 6960a701b1eSRobert Gordon 697cfae96c2Sjwahlig error = VOP_GETATTR(vp, &va, 0, cr, &ct); 6987c478bd9Sstevel@tonic-gate 6997c478bd9Sstevel@tonic-gate if (error) { 700cfae96c2Sjwahlig VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct); 7017c478bd9Sstevel@tonic-gate if (in_crit) 7027c478bd9Sstevel@tonic-gate nbl_end_crit(vp); 7030a701b1eSRobert Gordon 7047c478bd9Sstevel@tonic-gate VN_RELE(vp); 7057c478bd9Sstevel@tonic-gate rr->rr_data = NULL; 7067c478bd9Sstevel@tonic-gate rr->rr_status = puterrno(error); 7070a701b1eSRobert Gordon 7087c478bd9Sstevel@tonic-gate return; 7097c478bd9Sstevel@tonic-gate } 7107c478bd9Sstevel@tonic-gate 7117c478bd9Sstevel@tonic-gate /* 7127c478bd9Sstevel@tonic-gate * This is a kludge to allow reading of files created 7137c478bd9Sstevel@tonic-gate * with no read permission. The owner of the file 7147c478bd9Sstevel@tonic-gate * is always allowed to read it. 7157c478bd9Sstevel@tonic-gate */ 7167c478bd9Sstevel@tonic-gate if (crgetuid(cr) != va.va_uid) { 717cfae96c2Sjwahlig error = VOP_ACCESS(vp, VREAD, 0, cr, &ct); 7180a701b1eSRobert Gordon 7197c478bd9Sstevel@tonic-gate if (error) { 7207c478bd9Sstevel@tonic-gate /* 7217c478bd9Sstevel@tonic-gate * Exec is the same as read over the net because 7227c478bd9Sstevel@tonic-gate * of demand loading. 7237c478bd9Sstevel@tonic-gate */ 724cfae96c2Sjwahlig error = VOP_ACCESS(vp, VEXEC, 0, cr, &ct); 7257c478bd9Sstevel@tonic-gate } 7267c478bd9Sstevel@tonic-gate if (error) { 727cfae96c2Sjwahlig VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct); 7287c478bd9Sstevel@tonic-gate if (in_crit) 7297c478bd9Sstevel@tonic-gate nbl_end_crit(vp); 7307c478bd9Sstevel@tonic-gate VN_RELE(vp); 7317c478bd9Sstevel@tonic-gate rr->rr_data = NULL; 7327c478bd9Sstevel@tonic-gate rr->rr_status = puterrno(error); 7330a701b1eSRobert Gordon 7347c478bd9Sstevel@tonic-gate return; 7357c478bd9Sstevel@tonic-gate } 7367c478bd9Sstevel@tonic-gate } 7377c478bd9Sstevel@tonic-gate 7387c478bd9Sstevel@tonic-gate if (MANDLOCK(vp, va.va_mode)) { 739cfae96c2Sjwahlig VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct); 7407c478bd9Sstevel@tonic-gate if (in_crit) 7417c478bd9Sstevel@tonic-gate nbl_end_crit(vp); 7420a701b1eSRobert Gordon 7437c478bd9Sstevel@tonic-gate VN_RELE(vp); 7447c478bd9Sstevel@tonic-gate rr->rr_data = NULL; 7457c478bd9Sstevel@tonic-gate rr->rr_status = NFSERR_ACCES; 7460a701b1eSRobert Gordon 7477c478bd9Sstevel@tonic-gate return; 7487c478bd9Sstevel@tonic-gate } 7497c478bd9Sstevel@tonic-gate 7500a701b1eSRobert Gordon rr->rr_ok.rrok_wlist_len = 0; 7510a701b1eSRobert Gordon rr->rr_ok.rrok_wlist = NULL; 7520a701b1eSRobert Gordon 7537c478bd9Sstevel@tonic-gate if ((u_offset_t)ra->ra_offset >= va.va_size) { 7547c478bd9Sstevel@tonic-gate rr->rr_count = 0; 7557c478bd9Sstevel@tonic-gate rr->rr_data = NULL; 7567c478bd9Sstevel@tonic-gate /* 7577c478bd9Sstevel@tonic-gate * In this case, status is NFS_OK, but there is no data 7587c478bd9Sstevel@tonic-gate * to encode. So set rr_mp to NULL. 7597c478bd9Sstevel@tonic-gate */ 7607c478bd9Sstevel@tonic-gate rr->rr_mp = NULL; 761f837ee4aSSiddheshwar Mahesh rr->rr_ok.rrok_wlist = ra->ra_wlist; 762f837ee4aSSiddheshwar Mahesh if (rr->rr_ok.rrok_wlist) 763f837ee4aSSiddheshwar Mahesh clist_zero_len(rr->rr_ok.rrok_wlist); 7647c478bd9Sstevel@tonic-gate goto done; 7657c478bd9Sstevel@tonic-gate } 7667c478bd9Sstevel@tonic-gate 7670a701b1eSRobert Gordon if (ra->ra_wlist) { 7680a701b1eSRobert Gordon mp = NULL; 7690a701b1eSRobert Gordon rr->rr_mp = NULL; 7700a701b1eSRobert Gordon (void) rdma_get_wchunk(req, &iov, ra->ra_wlist); 77135bbd688SKaren Rochford if (ra->ra_count > iov.iov_len) { 77235bbd688SKaren Rochford rr->rr_data = NULL; 77335bbd688SKaren Rochford rr->rr_status = NFSERR_INVAL; 77435bbd688SKaren Rochford goto done; 77535bbd688SKaren Rochford } 7760a701b1eSRobert Gordon } else { 7777c478bd9Sstevel@tonic-gate /* 7787c478bd9Sstevel@tonic-gate * mp will contain the data to be sent out in the read reply. 7797c478bd9Sstevel@tonic-gate * This will be freed after the reply has been sent out (by the 7807c478bd9Sstevel@tonic-gate * driver). 7817c478bd9Sstevel@tonic-gate * Let's roundup the data to a BYTES_PER_XDR_UNIT multiple, so 7827c478bd9Sstevel@tonic-gate * that the call to xdrmblk_putmblk() never fails. 7837c478bd9Sstevel@tonic-gate */ 7847c478bd9Sstevel@tonic-gate mp = allocb_wait(RNDUP(ra->ra_count), BPRI_MED, STR_NOSIG, 7857c478bd9Sstevel@tonic-gate &alloc_err); 7867c478bd9Sstevel@tonic-gate ASSERT(mp != NULL); 7877c478bd9Sstevel@tonic-gate ASSERT(alloc_err == 0); 7887c478bd9Sstevel@tonic-gate 7897c478bd9Sstevel@tonic-gate rr->rr_mp = mp; 7907c478bd9Sstevel@tonic-gate 7917c478bd9Sstevel@tonic-gate /* 7927c478bd9Sstevel@tonic-gate * Set up io vector 7937c478bd9Sstevel@tonic-gate */ 7947c478bd9Sstevel@tonic-gate iov.iov_base = (caddr_t)mp->b_datap->db_base; 7957c478bd9Sstevel@tonic-gate iov.iov_len = ra->ra_count; 7960a701b1eSRobert Gordon } 7970a701b1eSRobert Gordon 7987c478bd9Sstevel@tonic-gate uio.uio_iov = &iov; 7997c478bd9Sstevel@tonic-gate uio.uio_iovcnt = 1; 8007c478bd9Sstevel@tonic-gate uio.uio_segflg = UIO_SYSSPACE; 8017c478bd9Sstevel@tonic-gate uio.uio_extflg = UIO_COPY_CACHED; 8027c478bd9Sstevel@tonic-gate uio.uio_loffset = (offset_t)ra->ra_offset; 8037c478bd9Sstevel@tonic-gate uio.uio_resid = ra->ra_count; 8047c478bd9Sstevel@tonic-gate 805cfae96c2Sjwahlig error = VOP_READ(vp, &uio, 0, cr, &ct); 8067c478bd9Sstevel@tonic-gate 8077c478bd9Sstevel@tonic-gate if (error) { 8080a701b1eSRobert Gordon if (mp) 8097c478bd9Sstevel@tonic-gate freeb(mp); 810cfae96c2Sjwahlig 811cfae96c2Sjwahlig /* 812cfae96c2Sjwahlig * check if a monitor detected a delegation conflict and 813cfae96c2Sjwahlig * mark as wouldblock so response is dropped 814cfae96c2Sjwahlig */ 815cfae96c2Sjwahlig if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) 816cfae96c2Sjwahlig curthread->t_flag |= T_WOULDBLOCK; 817cfae96c2Sjwahlig else 818cfae96c2Sjwahlig rr->rr_status = puterrno(error); 819cfae96c2Sjwahlig 820cfae96c2Sjwahlig VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct); 8217c478bd9Sstevel@tonic-gate if (in_crit) 8227c478bd9Sstevel@tonic-gate nbl_end_crit(vp); 8230a701b1eSRobert Gordon 8247c478bd9Sstevel@tonic-gate VN_RELE(vp); 8257c478bd9Sstevel@tonic-gate rr->rr_data = NULL; 8260a701b1eSRobert Gordon 8277c478bd9Sstevel@tonic-gate return; 8287c478bd9Sstevel@tonic-gate } 8297c478bd9Sstevel@tonic-gate 8307c478bd9Sstevel@tonic-gate /* 8317c478bd9Sstevel@tonic-gate * Get attributes again so we can send the latest access 8327c478bd9Sstevel@tonic-gate * time to the client side for his cache. 8337c478bd9Sstevel@tonic-gate */ 8347c478bd9Sstevel@tonic-gate va.va_mask = AT_ALL; 8350a701b1eSRobert Gordon 836cfae96c2Sjwahlig error = VOP_GETATTR(vp, &va, 0, cr, &ct); 8370a701b1eSRobert Gordon 8387c478bd9Sstevel@tonic-gate if (error) { 8390a701b1eSRobert Gordon if (mp) 8407c478bd9Sstevel@tonic-gate freeb(mp); 8410a701b1eSRobert Gordon 842cfae96c2Sjwahlig VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct); 8437c478bd9Sstevel@tonic-gate if (in_crit) 8447c478bd9Sstevel@tonic-gate nbl_end_crit(vp); 8450a701b1eSRobert Gordon 8467c478bd9Sstevel@tonic-gate VN_RELE(vp); 8477c478bd9Sstevel@tonic-gate rr->rr_data = NULL; 8487c478bd9Sstevel@tonic-gate rr->rr_status = puterrno(error); 8490a701b1eSRobert Gordon 8507c478bd9Sstevel@tonic-gate return; 8517c478bd9Sstevel@tonic-gate } 8527c478bd9Sstevel@tonic-gate 8537c478bd9Sstevel@tonic-gate rr->rr_count = (uint32_t)(ra->ra_count - uio.uio_resid); 8547c478bd9Sstevel@tonic-gate 8550a701b1eSRobert Gordon if (mp) { 8567c478bd9Sstevel@tonic-gate rr->rr_data = (char *)mp->b_datap->db_base; 8570a701b1eSRobert Gordon } else { 8580a701b1eSRobert Gordon if (ra->ra_wlist) { 8590a701b1eSRobert Gordon rr->rr_data = (caddr_t)iov.iov_base; 8600a701b1eSRobert Gordon if (!rdma_setup_read_data2(ra, rr)) { 8610a701b1eSRobert Gordon rr->rr_data = NULL; 8620a701b1eSRobert Gordon rr->rr_status = puterrno(NFSERR_INVAL); 8630a701b1eSRobert Gordon } 8640a701b1eSRobert Gordon } 8650a701b1eSRobert Gordon } 8667c478bd9Sstevel@tonic-gate done: 867cfae96c2Sjwahlig VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct); 8687c478bd9Sstevel@tonic-gate if (in_crit) 8697c478bd9Sstevel@tonic-gate nbl_end_crit(vp); 8707c478bd9Sstevel@tonic-gate 8717c478bd9Sstevel@tonic-gate acl_perm(vp, exi, &va, cr); 8727c478bd9Sstevel@tonic-gate 8737c478bd9Sstevel@tonic-gate /* check for overflows */ 8747c478bd9Sstevel@tonic-gate error = vattr_to_nattr(&va, &rr->rr_attr); 8757c478bd9Sstevel@tonic-gate 8767c478bd9Sstevel@tonic-gate VN_RELE(vp); 8777c478bd9Sstevel@tonic-gate 8787c478bd9Sstevel@tonic-gate rr->rr_status = puterrno(error); 8797c478bd9Sstevel@tonic-gate } 8807c478bd9Sstevel@tonic-gate 8817c478bd9Sstevel@tonic-gate /* 8827c478bd9Sstevel@tonic-gate * Free data allocated by rfs_read 8837c478bd9Sstevel@tonic-gate */ 8847c478bd9Sstevel@tonic-gate void 8857c478bd9Sstevel@tonic-gate rfs_rdfree(struct nfsrdresult *rr) 8867c478bd9Sstevel@tonic-gate { 8877c478bd9Sstevel@tonic-gate mblk_t *mp; 8887c478bd9Sstevel@tonic-gate 8897c478bd9Sstevel@tonic-gate if (rr->rr_status == NFS_OK) { 8907c478bd9Sstevel@tonic-gate mp = rr->rr_mp; 8917c478bd9Sstevel@tonic-gate if (mp != NULL) 8927c478bd9Sstevel@tonic-gate freeb(mp); 8937c478bd9Sstevel@tonic-gate } 8947c478bd9Sstevel@tonic-gate } 8957c478bd9Sstevel@tonic-gate 89627242a7cSthurlow void * 8977c478bd9Sstevel@tonic-gate rfs_read_getfh(struct nfsreadargs *ra) 8987c478bd9Sstevel@tonic-gate { 8997c478bd9Sstevel@tonic-gate return (&ra->ra_fhandle); 9007c478bd9Sstevel@tonic-gate } 9017c478bd9Sstevel@tonic-gate 9027c478bd9Sstevel@tonic-gate #define MAX_IOVECS 12 9037c478bd9Sstevel@tonic-gate 9047c478bd9Sstevel@tonic-gate #ifdef DEBUG 9057c478bd9Sstevel@tonic-gate static int rfs_write_sync_hits = 0; 9067c478bd9Sstevel@tonic-gate static int rfs_write_sync_misses = 0; 9077c478bd9Sstevel@tonic-gate #endif 9087c478bd9Sstevel@tonic-gate 9097c478bd9Sstevel@tonic-gate /* 9107c478bd9Sstevel@tonic-gate * Write data to file. 9117c478bd9Sstevel@tonic-gate * Returns attributes of a file after writing some data to it. 9127c478bd9Sstevel@tonic-gate * 9137c478bd9Sstevel@tonic-gate * Any changes made here, especially in error handling might have 9147c478bd9Sstevel@tonic-gate * to also be done in rfs_write (which clusters write requests). 9157c478bd9Sstevel@tonic-gate */ 9165cb0d679SMarcel Telka /* ARGSUSED */ 9177c478bd9Sstevel@tonic-gate void 9187c478bd9Sstevel@tonic-gate rfs_write_sync(struct nfswriteargs *wa, struct nfsattrstat *ns, 9195cb0d679SMarcel Telka struct exportinfo *exi, struct svc_req *req, cred_t *cr, bool_t ro) 9207c478bd9Sstevel@tonic-gate { 9217c478bd9Sstevel@tonic-gate int error; 9227c478bd9Sstevel@tonic-gate vnode_t *vp; 9237c478bd9Sstevel@tonic-gate rlim64_t rlimit; 9247c478bd9Sstevel@tonic-gate struct vattr va; 9257c478bd9Sstevel@tonic-gate struct uio uio; 9267c478bd9Sstevel@tonic-gate struct iovec iov[MAX_IOVECS]; 9277c478bd9Sstevel@tonic-gate mblk_t *m; 9287c478bd9Sstevel@tonic-gate struct iovec *iovp; 9297c478bd9Sstevel@tonic-gate int iovcnt; 9307c478bd9Sstevel@tonic-gate cred_t *savecred; 9317c478bd9Sstevel@tonic-gate int in_crit = 0; 932cfae96c2Sjwahlig caller_context_t ct; 9337c478bd9Sstevel@tonic-gate 9347c478bd9Sstevel@tonic-gate vp = nfs_fhtovp(&wa->wa_fhandle, exi); 9357c478bd9Sstevel@tonic-gate if (vp == NULL) { 9367c478bd9Sstevel@tonic-gate ns->ns_status = NFSERR_STALE; 9377c478bd9Sstevel@tonic-gate return; 9387c478bd9Sstevel@tonic-gate } 9397c478bd9Sstevel@tonic-gate 9405cb0d679SMarcel Telka if (rdonly(ro, vp)) { 9417c478bd9Sstevel@tonic-gate VN_RELE(vp); 9427c478bd9Sstevel@tonic-gate ns->ns_status = NFSERR_ROFS; 9437c478bd9Sstevel@tonic-gate return; 9447c478bd9Sstevel@tonic-gate } 9457c478bd9Sstevel@tonic-gate 9467c478bd9Sstevel@tonic-gate if (vp->v_type != VREG) { 9477c478bd9Sstevel@tonic-gate VN_RELE(vp); 9487c478bd9Sstevel@tonic-gate ns->ns_status = NFSERR_ISDIR; 9497c478bd9Sstevel@tonic-gate return; 9507c478bd9Sstevel@tonic-gate } 9517c478bd9Sstevel@tonic-gate 952cfae96c2Sjwahlig ct.cc_sysid = 0; 953cfae96c2Sjwahlig ct.cc_pid = 0; 954cfae96c2Sjwahlig ct.cc_caller_id = nfs2_srv_caller_id; 955cfae96c2Sjwahlig ct.cc_flags = CC_DONTBLOCK; 9567c478bd9Sstevel@tonic-gate 9577c478bd9Sstevel@tonic-gate va.va_mask = AT_UID|AT_MODE; 9580a701b1eSRobert Gordon 959cfae96c2Sjwahlig error = VOP_GETATTR(vp, &va, 0, cr, &ct); 9607c478bd9Sstevel@tonic-gate 9617c478bd9Sstevel@tonic-gate if (error) { 9627c478bd9Sstevel@tonic-gate VN_RELE(vp); 9637c478bd9Sstevel@tonic-gate ns->ns_status = puterrno(error); 9640a701b1eSRobert Gordon 9657c478bd9Sstevel@tonic-gate return; 9667c478bd9Sstevel@tonic-gate } 9677c478bd9Sstevel@tonic-gate 9687c478bd9Sstevel@tonic-gate if (crgetuid(cr) != va.va_uid) { 9697c478bd9Sstevel@tonic-gate /* 9707c478bd9Sstevel@tonic-gate * This is a kludge to allow writes of files created 9717c478bd9Sstevel@tonic-gate * with read only permission. The owner of the file 9727c478bd9Sstevel@tonic-gate * is always allowed to write it. 9737c478bd9Sstevel@tonic-gate */ 974cfae96c2Sjwahlig error = VOP_ACCESS(vp, VWRITE, 0, cr, &ct); 9750a701b1eSRobert Gordon 9767c478bd9Sstevel@tonic-gate if (error) { 9777c478bd9Sstevel@tonic-gate VN_RELE(vp); 9787c478bd9Sstevel@tonic-gate ns->ns_status = puterrno(error); 9797c478bd9Sstevel@tonic-gate return; 9807c478bd9Sstevel@tonic-gate } 9817c478bd9Sstevel@tonic-gate } 9827c478bd9Sstevel@tonic-gate 9837c478bd9Sstevel@tonic-gate /* 9847c478bd9Sstevel@tonic-gate * Can't access a mandatory lock file. This might cause 9857c478bd9Sstevel@tonic-gate * the NFS service thread to block forever waiting for a 9867c478bd9Sstevel@tonic-gate * lock to be released that will never be released. 9877c478bd9Sstevel@tonic-gate */ 9887c478bd9Sstevel@tonic-gate if (MANDLOCK(vp, va.va_mode)) { 9897c478bd9Sstevel@tonic-gate VN_RELE(vp); 9907c478bd9Sstevel@tonic-gate ns->ns_status = NFSERR_ACCES; 9917c478bd9Sstevel@tonic-gate return; 9927c478bd9Sstevel@tonic-gate } 9937c478bd9Sstevel@tonic-gate 9947c478bd9Sstevel@tonic-gate /* 9957c478bd9Sstevel@tonic-gate * We have to enter the critical region before calling VOP_RWLOCK 9967c478bd9Sstevel@tonic-gate * to avoid a deadlock with ufs. 9977c478bd9Sstevel@tonic-gate */ 9987c478bd9Sstevel@tonic-gate if (nbl_need_check(vp)) { 9997c478bd9Sstevel@tonic-gate nbl_start_crit(vp, RW_READER); 10007c478bd9Sstevel@tonic-gate in_crit = 1; 10017c478bd9Sstevel@tonic-gate if (nbl_conflict(vp, NBL_WRITE, wa->wa_offset, 1002da6c28aaSamw wa->wa_count, 0, NULL)) { 10037c478bd9Sstevel@tonic-gate error = EACCES; 10047c478bd9Sstevel@tonic-gate goto out; 10057c478bd9Sstevel@tonic-gate } 10067c478bd9Sstevel@tonic-gate } 10077c478bd9Sstevel@tonic-gate 1008cfae96c2Sjwahlig error = VOP_RWLOCK(vp, V_WRITELOCK_TRUE, &ct); 10097c478bd9Sstevel@tonic-gate 1010cfae96c2Sjwahlig /* check if a monitor detected a delegation conflict */ 1011cfae96c2Sjwahlig if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) { 1012cfae96c2Sjwahlig VN_RELE(vp); 1013cfae96c2Sjwahlig /* mark as wouldblock so response is dropped */ 1014cfae96c2Sjwahlig curthread->t_flag |= T_WOULDBLOCK; 1015cfae96c2Sjwahlig return; 1016cfae96c2Sjwahlig } 1017cfae96c2Sjwahlig 10180a701b1eSRobert Gordon if (wa->wa_data || wa->wa_rlist) { 10190a701b1eSRobert Gordon /* Do the RDMA thing if necessary */ 10200a701b1eSRobert Gordon if (wa->wa_rlist) { 10210a701b1eSRobert Gordon iov[0].iov_base = (char *)((wa->wa_rlist)->u.c_daddr3); 10220a701b1eSRobert Gordon iov[0].iov_len = wa->wa_count; 10230a701b1eSRobert Gordon } else { 10247c478bd9Sstevel@tonic-gate iov[0].iov_base = wa->wa_data; 10257c478bd9Sstevel@tonic-gate iov[0].iov_len = wa->wa_count; 10260a701b1eSRobert Gordon } 10277c478bd9Sstevel@tonic-gate uio.uio_iov = iov; 10287c478bd9Sstevel@tonic-gate uio.uio_iovcnt = 1; 10297c478bd9Sstevel@tonic-gate uio.uio_segflg = UIO_SYSSPACE; 10307c478bd9Sstevel@tonic-gate uio.uio_extflg = UIO_COPY_DEFAULT; 10317c478bd9Sstevel@tonic-gate uio.uio_loffset = (offset_t)wa->wa_offset; 10327c478bd9Sstevel@tonic-gate uio.uio_resid = wa->wa_count; 10337c478bd9Sstevel@tonic-gate /* 10347c478bd9Sstevel@tonic-gate * The limit is checked on the client. We 10357c478bd9Sstevel@tonic-gate * should allow any size writes here. 10367c478bd9Sstevel@tonic-gate */ 10377c478bd9Sstevel@tonic-gate uio.uio_llimit = curproc->p_fsz_ctl; 10387c478bd9Sstevel@tonic-gate rlimit = uio.uio_llimit - wa->wa_offset; 10397c478bd9Sstevel@tonic-gate if (rlimit < (rlim64_t)uio.uio_resid) 10407c478bd9Sstevel@tonic-gate uio.uio_resid = (uint_t)rlimit; 10417c478bd9Sstevel@tonic-gate 10427c478bd9Sstevel@tonic-gate /* 10437c478bd9Sstevel@tonic-gate * for now we assume no append mode 10447c478bd9Sstevel@tonic-gate */ 10457c478bd9Sstevel@tonic-gate /* 10467c478bd9Sstevel@tonic-gate * We're changing creds because VM may fault and we need 10477c478bd9Sstevel@tonic-gate * the cred of the current thread to be used if quota 10487c478bd9Sstevel@tonic-gate * checking is enabled. 10497c478bd9Sstevel@tonic-gate */ 10507c478bd9Sstevel@tonic-gate savecred = curthread->t_cred; 10517c478bd9Sstevel@tonic-gate curthread->t_cred = cr; 1052cfae96c2Sjwahlig error = VOP_WRITE(vp, &uio, FSYNC, cr, &ct); 10537c478bd9Sstevel@tonic-gate curthread->t_cred = savecred; 10547c478bd9Sstevel@tonic-gate } else { 10557c478bd9Sstevel@tonic-gate iovcnt = 0; 10567c478bd9Sstevel@tonic-gate for (m = wa->wa_mblk; m != NULL; m = m->b_cont) 10577c478bd9Sstevel@tonic-gate iovcnt++; 10587c478bd9Sstevel@tonic-gate if (iovcnt <= MAX_IOVECS) { 10597c478bd9Sstevel@tonic-gate #ifdef DEBUG 10607c478bd9Sstevel@tonic-gate rfs_write_sync_hits++; 10617c478bd9Sstevel@tonic-gate #endif 10627c478bd9Sstevel@tonic-gate iovp = iov; 10637c478bd9Sstevel@tonic-gate } else { 10647c478bd9Sstevel@tonic-gate #ifdef DEBUG 10657c478bd9Sstevel@tonic-gate rfs_write_sync_misses++; 10667c478bd9Sstevel@tonic-gate #endif 10677c478bd9Sstevel@tonic-gate iovp = kmem_alloc(sizeof (*iovp) * iovcnt, KM_SLEEP); 10687c478bd9Sstevel@tonic-gate } 10697c478bd9Sstevel@tonic-gate mblk_to_iov(wa->wa_mblk, iovcnt, iovp); 10707c478bd9Sstevel@tonic-gate uio.uio_iov = iovp; 10717c478bd9Sstevel@tonic-gate uio.uio_iovcnt = iovcnt; 10727c478bd9Sstevel@tonic-gate uio.uio_segflg = UIO_SYSSPACE; 10737c478bd9Sstevel@tonic-gate uio.uio_extflg = UIO_COPY_DEFAULT; 10747c478bd9Sstevel@tonic-gate uio.uio_loffset = (offset_t)wa->wa_offset; 10757c478bd9Sstevel@tonic-gate uio.uio_resid = wa->wa_count; 10767c478bd9Sstevel@tonic-gate /* 10777c478bd9Sstevel@tonic-gate * The limit is checked on the client. We 10787c478bd9Sstevel@tonic-gate * should allow any size writes here. 10797c478bd9Sstevel@tonic-gate */ 10807c478bd9Sstevel@tonic-gate uio.uio_llimit = curproc->p_fsz_ctl; 10817c478bd9Sstevel@tonic-gate rlimit = uio.uio_llimit - wa->wa_offset; 10827c478bd9Sstevel@tonic-gate if (rlimit < (rlim64_t)uio.uio_resid) 10837c478bd9Sstevel@tonic-gate uio.uio_resid = (uint_t)rlimit; 10847c478bd9Sstevel@tonic-gate 10857c478bd9Sstevel@tonic-gate /* 10867c478bd9Sstevel@tonic-gate * For now we assume no append mode. 10877c478bd9Sstevel@tonic-gate */ 10887c478bd9Sstevel@tonic-gate /* 10897c478bd9Sstevel@tonic-gate * We're changing creds because VM may fault and we need 10907c478bd9Sstevel@tonic-gate * the cred of the current thread to be used if quota 10917c478bd9Sstevel@tonic-gate * checking is enabled. 10927c478bd9Sstevel@tonic-gate */ 10937c478bd9Sstevel@tonic-gate savecred = curthread->t_cred; 10947c478bd9Sstevel@tonic-gate curthread->t_cred = cr; 1095cfae96c2Sjwahlig error = VOP_WRITE(vp, &uio, FSYNC, cr, &ct); 10967c478bd9Sstevel@tonic-gate curthread->t_cred = savecred; 10977c478bd9Sstevel@tonic-gate 10987c478bd9Sstevel@tonic-gate if (iovp != iov) 10997c478bd9Sstevel@tonic-gate kmem_free(iovp, sizeof (*iovp) * iovcnt); 11007c478bd9Sstevel@tonic-gate } 11017c478bd9Sstevel@tonic-gate 1102cfae96c2Sjwahlig VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, &ct); 11037c478bd9Sstevel@tonic-gate 11047c478bd9Sstevel@tonic-gate if (!error) { 11057c478bd9Sstevel@tonic-gate /* 11067c478bd9Sstevel@tonic-gate * Get attributes again so we send the latest mod 11077c478bd9Sstevel@tonic-gate * time to the client side for his cache. 11087c478bd9Sstevel@tonic-gate */ 11097c478bd9Sstevel@tonic-gate va.va_mask = AT_ALL; /* now we want everything */ 11100a701b1eSRobert Gordon 1111cfae96c2Sjwahlig error = VOP_GETATTR(vp, &va, 0, cr, &ct); 11120a701b1eSRobert Gordon 11137c478bd9Sstevel@tonic-gate /* check for overflows */ 11147c478bd9Sstevel@tonic-gate if (!error) { 11157c478bd9Sstevel@tonic-gate acl_perm(vp, exi, &va, cr); 11167c478bd9Sstevel@tonic-gate error = vattr_to_nattr(&va, &ns->ns_attr); 11177c478bd9Sstevel@tonic-gate } 11187c478bd9Sstevel@tonic-gate } 11197c478bd9Sstevel@tonic-gate 11207c478bd9Sstevel@tonic-gate out: 11217c478bd9Sstevel@tonic-gate if (in_crit) 11227c478bd9Sstevel@tonic-gate nbl_end_crit(vp); 11237c478bd9Sstevel@tonic-gate VN_RELE(vp); 11247c478bd9Sstevel@tonic-gate 1125cfae96c2Sjwahlig /* check if a monitor detected a delegation conflict */ 1126cfae96c2Sjwahlig if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) 1127cfae96c2Sjwahlig /* mark as wouldblock so response is dropped */ 1128cfae96c2Sjwahlig curthread->t_flag |= T_WOULDBLOCK; 1129cfae96c2Sjwahlig else 11307c478bd9Sstevel@tonic-gate ns->ns_status = puterrno(error); 11317c478bd9Sstevel@tonic-gate 11327c478bd9Sstevel@tonic-gate } 11337c478bd9Sstevel@tonic-gate 11347c478bd9Sstevel@tonic-gate struct rfs_async_write { 11357c478bd9Sstevel@tonic-gate struct nfswriteargs *wa; 11367c478bd9Sstevel@tonic-gate struct nfsattrstat *ns; 11377c478bd9Sstevel@tonic-gate struct svc_req *req; 11387c478bd9Sstevel@tonic-gate cred_t *cr; 11395cb0d679SMarcel Telka bool_t ro; 11407c478bd9Sstevel@tonic-gate kthread_t *thread; 11417c478bd9Sstevel@tonic-gate struct rfs_async_write *list; 11427c478bd9Sstevel@tonic-gate }; 11437c478bd9Sstevel@tonic-gate 11447c478bd9Sstevel@tonic-gate struct rfs_async_write_list { 11457c478bd9Sstevel@tonic-gate fhandle_t *fhp; 11467c478bd9Sstevel@tonic-gate kcondvar_t cv; 11477c478bd9Sstevel@tonic-gate struct rfs_async_write *list; 11487c478bd9Sstevel@tonic-gate struct rfs_async_write_list *next; 11497c478bd9Sstevel@tonic-gate }; 11507c478bd9Sstevel@tonic-gate 11517c478bd9Sstevel@tonic-gate static struct rfs_async_write_list *rfs_async_write_head = NULL; 11527c478bd9Sstevel@tonic-gate static kmutex_t rfs_async_write_lock; 11537c478bd9Sstevel@tonic-gate static int rfs_write_async = 1; /* enables write clustering if == 1 */ 11547c478bd9Sstevel@tonic-gate 11557c478bd9Sstevel@tonic-gate #define MAXCLIOVECS 42 11567c478bd9Sstevel@tonic-gate #define RFSWRITE_INITVAL (enum nfsstat) -1 11577c478bd9Sstevel@tonic-gate 11587c478bd9Sstevel@tonic-gate #ifdef DEBUG 11597c478bd9Sstevel@tonic-gate static int rfs_write_hits = 0; 11607c478bd9Sstevel@tonic-gate static int rfs_write_misses = 0; 11617c478bd9Sstevel@tonic-gate #endif 11627c478bd9Sstevel@tonic-gate 11637c478bd9Sstevel@tonic-gate /* 11647c478bd9Sstevel@tonic-gate * Write data to file. 11657c478bd9Sstevel@tonic-gate * Returns attributes of a file after writing some data to it. 11667c478bd9Sstevel@tonic-gate */ 11677c478bd9Sstevel@tonic-gate void 11687c478bd9Sstevel@tonic-gate rfs_write(struct nfswriteargs *wa, struct nfsattrstat *ns, 11695cb0d679SMarcel Telka struct exportinfo *exi, struct svc_req *req, cred_t *cr, bool_t ro) 11707c478bd9Sstevel@tonic-gate { 11717c478bd9Sstevel@tonic-gate int error; 11727c478bd9Sstevel@tonic-gate vnode_t *vp; 11737c478bd9Sstevel@tonic-gate rlim64_t rlimit; 11747c478bd9Sstevel@tonic-gate struct vattr va; 11757c478bd9Sstevel@tonic-gate struct uio uio; 11767c478bd9Sstevel@tonic-gate struct rfs_async_write_list *lp; 11777c478bd9Sstevel@tonic-gate struct rfs_async_write_list *nlp; 11787c478bd9Sstevel@tonic-gate struct rfs_async_write *rp; 11797c478bd9Sstevel@tonic-gate struct rfs_async_write *nrp; 11807c478bd9Sstevel@tonic-gate struct rfs_async_write *trp; 11817c478bd9Sstevel@tonic-gate struct rfs_async_write *lrp; 11827c478bd9Sstevel@tonic-gate int data_written; 11837c478bd9Sstevel@tonic-gate int iovcnt; 11847c478bd9Sstevel@tonic-gate mblk_t *m; 11857c478bd9Sstevel@tonic-gate struct iovec *iovp; 11867c478bd9Sstevel@tonic-gate struct iovec *niovp; 11877c478bd9Sstevel@tonic-gate struct iovec iov[MAXCLIOVECS]; 11887c478bd9Sstevel@tonic-gate int count; 11897c478bd9Sstevel@tonic-gate int rcount; 11907c478bd9Sstevel@tonic-gate uint_t off; 11917c478bd9Sstevel@tonic-gate uint_t len; 11927c478bd9Sstevel@tonic-gate struct rfs_async_write nrpsp; 11937c478bd9Sstevel@tonic-gate struct rfs_async_write_list nlpsp; 11947c478bd9Sstevel@tonic-gate ushort_t t_flag; 11957c478bd9Sstevel@tonic-gate cred_t *savecred; 11967c478bd9Sstevel@tonic-gate int in_crit = 0; 1197cfae96c2Sjwahlig caller_context_t ct; 11987c478bd9Sstevel@tonic-gate 11997c478bd9Sstevel@tonic-gate if (!rfs_write_async) { 12005cb0d679SMarcel Telka rfs_write_sync(wa, ns, exi, req, cr, ro); 12017c478bd9Sstevel@tonic-gate return; 12027c478bd9Sstevel@tonic-gate } 12037c478bd9Sstevel@tonic-gate 12047c478bd9Sstevel@tonic-gate /* 12057c478bd9Sstevel@tonic-gate * Initialize status to RFSWRITE_INITVAL instead of 0, since value of 0 12067c478bd9Sstevel@tonic-gate * is considered an OK. 12077c478bd9Sstevel@tonic-gate */ 12087c478bd9Sstevel@tonic-gate ns->ns_status = RFSWRITE_INITVAL; 12097c478bd9Sstevel@tonic-gate 12107c478bd9Sstevel@tonic-gate nrp = &nrpsp; 12117c478bd9Sstevel@tonic-gate nrp->wa = wa; 12127c478bd9Sstevel@tonic-gate nrp->ns = ns; 12137c478bd9Sstevel@tonic-gate nrp->req = req; 12147c478bd9Sstevel@tonic-gate nrp->cr = cr; 12155cb0d679SMarcel Telka nrp->ro = ro; 12167c478bd9Sstevel@tonic-gate nrp->thread = curthread; 12177c478bd9Sstevel@tonic-gate 12187c478bd9Sstevel@tonic-gate ASSERT(curthread->t_schedflag & TS_DONT_SWAP); 12197c478bd9Sstevel@tonic-gate 12207c478bd9Sstevel@tonic-gate /* 12217c478bd9Sstevel@tonic-gate * Look to see if there is already a cluster started 12227c478bd9Sstevel@tonic-gate * for this file. 12237c478bd9Sstevel@tonic-gate */ 12247c478bd9Sstevel@tonic-gate mutex_enter(&rfs_async_write_lock); 12257c478bd9Sstevel@tonic-gate for (lp = rfs_async_write_head; lp != NULL; lp = lp->next) { 12267c478bd9Sstevel@tonic-gate if (bcmp(&wa->wa_fhandle, lp->fhp, 12277c478bd9Sstevel@tonic-gate sizeof (fhandle_t)) == 0) 12287c478bd9Sstevel@tonic-gate break; 12297c478bd9Sstevel@tonic-gate } 12307c478bd9Sstevel@tonic-gate 12317c478bd9Sstevel@tonic-gate /* 12327c478bd9Sstevel@tonic-gate * If lp is non-NULL, then there is already a cluster 12337c478bd9Sstevel@tonic-gate * started. We need to place ourselves in the cluster 12347c478bd9Sstevel@tonic-gate * list in the right place as determined by starting 12357c478bd9Sstevel@tonic-gate * offset. Conflicts with non-blocking mandatory locked 12367c478bd9Sstevel@tonic-gate * regions will be checked when the cluster is processed. 12377c478bd9Sstevel@tonic-gate */ 12387c478bd9Sstevel@tonic-gate if (lp != NULL) { 12397c478bd9Sstevel@tonic-gate rp = lp->list; 12407c478bd9Sstevel@tonic-gate trp = NULL; 12417c478bd9Sstevel@tonic-gate while (rp != NULL && rp->wa->wa_offset < wa->wa_offset) { 12427c478bd9Sstevel@tonic-gate trp = rp; 12437c478bd9Sstevel@tonic-gate rp = rp->list; 12447c478bd9Sstevel@tonic-gate } 12457c478bd9Sstevel@tonic-gate nrp->list = rp; 12467c478bd9Sstevel@tonic-gate if (trp == NULL) 12477c478bd9Sstevel@tonic-gate lp->list = nrp; 12487c478bd9Sstevel@tonic-gate else 12497c478bd9Sstevel@tonic-gate trp->list = nrp; 12507c478bd9Sstevel@tonic-gate while (nrp->ns->ns_status == RFSWRITE_INITVAL) 12517c478bd9Sstevel@tonic-gate cv_wait(&lp->cv, &rfs_async_write_lock); 12527c478bd9Sstevel@tonic-gate mutex_exit(&rfs_async_write_lock); 12530a701b1eSRobert Gordon 12547c478bd9Sstevel@tonic-gate return; 12557c478bd9Sstevel@tonic-gate } 12567c478bd9Sstevel@tonic-gate 12577c478bd9Sstevel@tonic-gate /* 12587c478bd9Sstevel@tonic-gate * No cluster started yet, start one and add ourselves 12597c478bd9Sstevel@tonic-gate * to the list of clusters. 12607c478bd9Sstevel@tonic-gate */ 12617c478bd9Sstevel@tonic-gate nrp->list = NULL; 12627c478bd9Sstevel@tonic-gate 12637c478bd9Sstevel@tonic-gate nlp = &nlpsp; 12647c478bd9Sstevel@tonic-gate nlp->fhp = &wa->wa_fhandle; 12657c478bd9Sstevel@tonic-gate cv_init(&nlp->cv, NULL, CV_DEFAULT, NULL); 12667c478bd9Sstevel@tonic-gate nlp->list = nrp; 12677c478bd9Sstevel@tonic-gate nlp->next = NULL; 12687c478bd9Sstevel@tonic-gate 12697c478bd9Sstevel@tonic-gate if (rfs_async_write_head == NULL) { 12707c478bd9Sstevel@tonic-gate rfs_async_write_head = nlp; 12717c478bd9Sstevel@tonic-gate } else { 12727c478bd9Sstevel@tonic-gate lp = rfs_async_write_head; 12737c478bd9Sstevel@tonic-gate while (lp->next != NULL) 12747c478bd9Sstevel@tonic-gate lp = lp->next; 12757c478bd9Sstevel@tonic-gate lp->next = nlp; 12767c478bd9Sstevel@tonic-gate } 12777c478bd9Sstevel@tonic-gate mutex_exit(&rfs_async_write_lock); 12787c478bd9Sstevel@tonic-gate 12797c478bd9Sstevel@tonic-gate /* 12807c478bd9Sstevel@tonic-gate * Convert the file handle common to all of the requests 12817c478bd9Sstevel@tonic-gate * in this cluster to a vnode. 12827c478bd9Sstevel@tonic-gate */ 12837c478bd9Sstevel@tonic-gate vp = nfs_fhtovp(&wa->wa_fhandle, exi); 12847c478bd9Sstevel@tonic-gate if (vp == NULL) { 12857c478bd9Sstevel@tonic-gate mutex_enter(&rfs_async_write_lock); 12867c478bd9Sstevel@tonic-gate if (rfs_async_write_head == nlp) 12877c478bd9Sstevel@tonic-gate rfs_async_write_head = nlp->next; 12887c478bd9Sstevel@tonic-gate else { 12897c478bd9Sstevel@tonic-gate lp = rfs_async_write_head; 12907c478bd9Sstevel@tonic-gate while (lp->next != nlp) 12917c478bd9Sstevel@tonic-gate lp = lp->next; 12927c478bd9Sstevel@tonic-gate lp->next = nlp->next; 12937c478bd9Sstevel@tonic-gate } 12947c478bd9Sstevel@tonic-gate t_flag = curthread->t_flag & T_WOULDBLOCK; 12957c478bd9Sstevel@tonic-gate for (rp = nlp->list; rp != NULL; rp = rp->list) { 12967c478bd9Sstevel@tonic-gate rp->ns->ns_status = NFSERR_STALE; 12977c478bd9Sstevel@tonic-gate rp->thread->t_flag |= t_flag; 12987c478bd9Sstevel@tonic-gate } 12997c478bd9Sstevel@tonic-gate cv_broadcast(&nlp->cv); 13007c478bd9Sstevel@tonic-gate mutex_exit(&rfs_async_write_lock); 13010a701b1eSRobert Gordon 13027c478bd9Sstevel@tonic-gate return; 13037c478bd9Sstevel@tonic-gate } 13047c478bd9Sstevel@tonic-gate 13057c478bd9Sstevel@tonic-gate /* 13067c478bd9Sstevel@tonic-gate * Can only write regular files. Attempts to write any 13077c478bd9Sstevel@tonic-gate * other file types fail with EISDIR. 13087c478bd9Sstevel@tonic-gate */ 13097c478bd9Sstevel@tonic-gate if (vp->v_type != VREG) { 13107c478bd9Sstevel@tonic-gate VN_RELE(vp); 13117c478bd9Sstevel@tonic-gate mutex_enter(&rfs_async_write_lock); 13127c478bd9Sstevel@tonic-gate if (rfs_async_write_head == nlp) 13137c478bd9Sstevel@tonic-gate rfs_async_write_head = nlp->next; 13147c478bd9Sstevel@tonic-gate else { 13157c478bd9Sstevel@tonic-gate lp = rfs_async_write_head; 13167c478bd9Sstevel@tonic-gate while (lp->next != nlp) 13177c478bd9Sstevel@tonic-gate lp = lp->next; 13187c478bd9Sstevel@tonic-gate lp->next = nlp->next; 13197c478bd9Sstevel@tonic-gate } 13207c478bd9Sstevel@tonic-gate t_flag = curthread->t_flag & T_WOULDBLOCK; 13217c478bd9Sstevel@tonic-gate for (rp = nlp->list; rp != NULL; rp = rp->list) { 13227c478bd9Sstevel@tonic-gate rp->ns->ns_status = NFSERR_ISDIR; 13237c478bd9Sstevel@tonic-gate rp->thread->t_flag |= t_flag; 13247c478bd9Sstevel@tonic-gate } 13257c478bd9Sstevel@tonic-gate cv_broadcast(&nlp->cv); 13267c478bd9Sstevel@tonic-gate mutex_exit(&rfs_async_write_lock); 13270a701b1eSRobert Gordon 13287c478bd9Sstevel@tonic-gate return; 13297c478bd9Sstevel@tonic-gate } 13307c478bd9Sstevel@tonic-gate 13317c478bd9Sstevel@tonic-gate /* 13327c478bd9Sstevel@tonic-gate * Enter the critical region before calling VOP_RWLOCK, to avoid a 13337c478bd9Sstevel@tonic-gate * deadlock with ufs. 13347c478bd9Sstevel@tonic-gate */ 13357c478bd9Sstevel@tonic-gate if (nbl_need_check(vp)) { 13367c478bd9Sstevel@tonic-gate nbl_start_crit(vp, RW_READER); 13377c478bd9Sstevel@tonic-gate in_crit = 1; 13387c478bd9Sstevel@tonic-gate } 13397c478bd9Sstevel@tonic-gate 1340cfae96c2Sjwahlig ct.cc_sysid = 0; 1341cfae96c2Sjwahlig ct.cc_pid = 0; 1342cfae96c2Sjwahlig ct.cc_caller_id = nfs2_srv_caller_id; 1343cfae96c2Sjwahlig ct.cc_flags = CC_DONTBLOCK; 1344cfae96c2Sjwahlig 13457c478bd9Sstevel@tonic-gate /* 13467c478bd9Sstevel@tonic-gate * Lock the file for writing. This operation provides 13477c478bd9Sstevel@tonic-gate * the delay which allows clusters to grow. 13487c478bd9Sstevel@tonic-gate */ 1349cfae96c2Sjwahlig error = VOP_RWLOCK(vp, V_WRITELOCK_TRUE, &ct); 13507c478bd9Sstevel@tonic-gate 1351cfae96c2Sjwahlig /* check if a monitor detected a delegation conflict */ 1352cfae96c2Sjwahlig if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) { 13534061974fSNagakiran Rajashekar if (in_crit) 13544061974fSNagakiran Rajashekar nbl_end_crit(vp); 1355cfae96c2Sjwahlig VN_RELE(vp); 1356cfae96c2Sjwahlig /* mark as wouldblock so response is dropped */ 1357cfae96c2Sjwahlig curthread->t_flag |= T_WOULDBLOCK; 1358cfae96c2Sjwahlig mutex_enter(&rfs_async_write_lock); 13594061974fSNagakiran Rajashekar if (rfs_async_write_head == nlp) 13604061974fSNagakiran Rajashekar rfs_async_write_head = nlp->next; 13614061974fSNagakiran Rajashekar else { 13624061974fSNagakiran Rajashekar lp = rfs_async_write_head; 13634061974fSNagakiran Rajashekar while (lp->next != nlp) 13644061974fSNagakiran Rajashekar lp = lp->next; 13654061974fSNagakiran Rajashekar lp->next = nlp->next; 13664061974fSNagakiran Rajashekar } 1367cfae96c2Sjwahlig for (rp = nlp->list; rp != NULL; rp = rp->list) { 1368cfae96c2Sjwahlig if (rp->ns->ns_status == RFSWRITE_INITVAL) { 1369cfae96c2Sjwahlig rp->ns->ns_status = puterrno(error); 1370cfae96c2Sjwahlig rp->thread->t_flag |= T_WOULDBLOCK; 1371cfae96c2Sjwahlig } 1372cfae96c2Sjwahlig } 1373cfae96c2Sjwahlig cv_broadcast(&nlp->cv); 1374cfae96c2Sjwahlig mutex_exit(&rfs_async_write_lock); 13750a701b1eSRobert Gordon 1376cfae96c2Sjwahlig return; 1377cfae96c2Sjwahlig } 1378cfae96c2Sjwahlig 13797c478bd9Sstevel@tonic-gate /* 13807c478bd9Sstevel@tonic-gate * Disconnect this cluster from the list of clusters. 13817c478bd9Sstevel@tonic-gate * The cluster that is being dealt with must be fixed 13827c478bd9Sstevel@tonic-gate * in size after this point, so there is no reason 13837c478bd9Sstevel@tonic-gate * to leave it on the list so that new requests can 13847c478bd9Sstevel@tonic-gate * find it. 13857c478bd9Sstevel@tonic-gate * 13867c478bd9Sstevel@tonic-gate * The algorithm is that the first write request will 13877c478bd9Sstevel@tonic-gate * create a cluster, convert the file handle to a 13887c478bd9Sstevel@tonic-gate * vnode pointer, and then lock the file for writing. 13897c478bd9Sstevel@tonic-gate * This request is not likely to be clustered with 13907c478bd9Sstevel@tonic-gate * any others. However, the next request will create 13917c478bd9Sstevel@tonic-gate * a new cluster and be blocked in VOP_RWLOCK while 13927c478bd9Sstevel@tonic-gate * the first request is being processed. This delay 13937c478bd9Sstevel@tonic-gate * will allow more requests to be clustered in this 13947c478bd9Sstevel@tonic-gate * second cluster. 13957c478bd9Sstevel@tonic-gate */ 13967c478bd9Sstevel@tonic-gate mutex_enter(&rfs_async_write_lock); 13977c478bd9Sstevel@tonic-gate if (rfs_async_write_head == nlp) 13987c478bd9Sstevel@tonic-gate rfs_async_write_head = nlp->next; 13997c478bd9Sstevel@tonic-gate else { 14007c478bd9Sstevel@tonic-gate lp = rfs_async_write_head; 14017c478bd9Sstevel@tonic-gate while (lp->next != nlp) 14027c478bd9Sstevel@tonic-gate lp = lp->next; 14037c478bd9Sstevel@tonic-gate lp->next = nlp->next; 14047c478bd9Sstevel@tonic-gate } 14057c478bd9Sstevel@tonic-gate mutex_exit(&rfs_async_write_lock); 14067c478bd9Sstevel@tonic-gate 14077c478bd9Sstevel@tonic-gate /* 14087c478bd9Sstevel@tonic-gate * Step through the list of requests in this cluster. 14097c478bd9Sstevel@tonic-gate * We need to check permissions to make sure that all 14107c478bd9Sstevel@tonic-gate * of the requests have sufficient permission to write 14117c478bd9Sstevel@tonic-gate * the file. A cluster can be composed of requests 14127c478bd9Sstevel@tonic-gate * from different clients and different users on each 14137c478bd9Sstevel@tonic-gate * client. 14147c478bd9Sstevel@tonic-gate * 14157c478bd9Sstevel@tonic-gate * As a side effect, we also calculate the size of the 14167c478bd9Sstevel@tonic-gate * byte range that this cluster encompasses. 14177c478bd9Sstevel@tonic-gate */ 14187c478bd9Sstevel@tonic-gate rp = nlp->list; 14197c478bd9Sstevel@tonic-gate off = rp->wa->wa_offset; 14207c478bd9Sstevel@tonic-gate len = (uint_t)0; 14217c478bd9Sstevel@tonic-gate do { 14225cb0d679SMarcel Telka if (rdonly(rp->ro, vp)) { 14237c478bd9Sstevel@tonic-gate rp->ns->ns_status = NFSERR_ROFS; 14247c478bd9Sstevel@tonic-gate t_flag = curthread->t_flag & T_WOULDBLOCK; 14257c478bd9Sstevel@tonic-gate rp->thread->t_flag |= t_flag; 14267c478bd9Sstevel@tonic-gate continue; 14277c478bd9Sstevel@tonic-gate } 14287c478bd9Sstevel@tonic-gate 14297c478bd9Sstevel@tonic-gate va.va_mask = AT_UID|AT_MODE; 14300a701b1eSRobert Gordon 1431cfae96c2Sjwahlig error = VOP_GETATTR(vp, &va, 0, rp->cr, &ct); 14320a701b1eSRobert Gordon 14337c478bd9Sstevel@tonic-gate if (!error) { 14347c478bd9Sstevel@tonic-gate if (crgetuid(rp->cr) != va.va_uid) { 14357c478bd9Sstevel@tonic-gate /* 14367c478bd9Sstevel@tonic-gate * This is a kludge to allow writes of files 14377c478bd9Sstevel@tonic-gate * created with read only permission. The 14387c478bd9Sstevel@tonic-gate * owner of the file is always allowed to 14397c478bd9Sstevel@tonic-gate * write it. 14407c478bd9Sstevel@tonic-gate */ 1441cfae96c2Sjwahlig error = VOP_ACCESS(vp, VWRITE, 0, rp->cr, &ct); 14427c478bd9Sstevel@tonic-gate } 14437c478bd9Sstevel@tonic-gate if (!error && MANDLOCK(vp, va.va_mode)) 14447c478bd9Sstevel@tonic-gate error = EACCES; 14457c478bd9Sstevel@tonic-gate } 14467c478bd9Sstevel@tonic-gate 14477c478bd9Sstevel@tonic-gate /* 14487c478bd9Sstevel@tonic-gate * Check for a conflict with a nbmand-locked region. 14497c478bd9Sstevel@tonic-gate */ 14507c478bd9Sstevel@tonic-gate if (in_crit && nbl_conflict(vp, NBL_WRITE, rp->wa->wa_offset, 1451da6c28aaSamw rp->wa->wa_count, 0, NULL)) { 14527c478bd9Sstevel@tonic-gate error = EACCES; 14537c478bd9Sstevel@tonic-gate } 14547c478bd9Sstevel@tonic-gate 14557c478bd9Sstevel@tonic-gate if (error) { 14567c478bd9Sstevel@tonic-gate rp->ns->ns_status = puterrno(error); 14577c478bd9Sstevel@tonic-gate t_flag = curthread->t_flag & T_WOULDBLOCK; 14587c478bd9Sstevel@tonic-gate rp->thread->t_flag |= t_flag; 14597c478bd9Sstevel@tonic-gate continue; 14607c478bd9Sstevel@tonic-gate } 14617c478bd9Sstevel@tonic-gate if (len < rp->wa->wa_offset + rp->wa->wa_count - off) 14627c478bd9Sstevel@tonic-gate len = rp->wa->wa_offset + rp->wa->wa_count - off; 14637c478bd9Sstevel@tonic-gate } while ((rp = rp->list) != NULL); 14647c478bd9Sstevel@tonic-gate 14657c478bd9Sstevel@tonic-gate /* 14667c478bd9Sstevel@tonic-gate * Step through the cluster attempting to gather as many 14677c478bd9Sstevel@tonic-gate * requests which are contiguous as possible. These 14687c478bd9Sstevel@tonic-gate * contiguous requests are handled via one call to VOP_WRITE 14697c478bd9Sstevel@tonic-gate * instead of different calls to VOP_WRITE. We also keep 14707c478bd9Sstevel@tonic-gate * track of the fact that any data was written. 14717c478bd9Sstevel@tonic-gate */ 14727c478bd9Sstevel@tonic-gate rp = nlp->list; 14737c478bd9Sstevel@tonic-gate data_written = 0; 14747c478bd9Sstevel@tonic-gate do { 14757c478bd9Sstevel@tonic-gate /* 14767c478bd9Sstevel@tonic-gate * Skip any requests which are already marked as having an 14777c478bd9Sstevel@tonic-gate * error. 14787c478bd9Sstevel@tonic-gate */ 14797c478bd9Sstevel@tonic-gate if (rp->ns->ns_status != RFSWRITE_INITVAL) { 14807c478bd9Sstevel@tonic-gate rp = rp->list; 14817c478bd9Sstevel@tonic-gate continue; 14827c478bd9Sstevel@tonic-gate } 14837c478bd9Sstevel@tonic-gate 14847c478bd9Sstevel@tonic-gate /* 14857c478bd9Sstevel@tonic-gate * Count the number of iovec's which are required 14867c478bd9Sstevel@tonic-gate * to handle this set of requests. One iovec is 14877c478bd9Sstevel@tonic-gate * needed for each data buffer, whether addressed 14887c478bd9Sstevel@tonic-gate * by wa_data or by the b_rptr pointers in the 14897c478bd9Sstevel@tonic-gate * mblk chains. 14907c478bd9Sstevel@tonic-gate */ 14917c478bd9Sstevel@tonic-gate iovcnt = 0; 14927c478bd9Sstevel@tonic-gate lrp = rp; 14937c478bd9Sstevel@tonic-gate for (;;) { 14940a701b1eSRobert Gordon if (lrp->wa->wa_data || lrp->wa->wa_rlist) 14957c478bd9Sstevel@tonic-gate iovcnt++; 14967c478bd9Sstevel@tonic-gate else { 14977c478bd9Sstevel@tonic-gate m = lrp->wa->wa_mblk; 14987c478bd9Sstevel@tonic-gate while (m != NULL) { 14997c478bd9Sstevel@tonic-gate iovcnt++; 15007c478bd9Sstevel@tonic-gate m = m->b_cont; 15017c478bd9Sstevel@tonic-gate } 15027c478bd9Sstevel@tonic-gate } 15037c478bd9Sstevel@tonic-gate if (lrp->list == NULL || 15047c478bd9Sstevel@tonic-gate lrp->list->ns->ns_status != RFSWRITE_INITVAL || 15057c478bd9Sstevel@tonic-gate lrp->wa->wa_offset + lrp->wa->wa_count != 15067c478bd9Sstevel@tonic-gate lrp->list->wa->wa_offset) { 15077c478bd9Sstevel@tonic-gate lrp = lrp->list; 15087c478bd9Sstevel@tonic-gate break; 15097c478bd9Sstevel@tonic-gate } 15107c478bd9Sstevel@tonic-gate lrp = lrp->list; 15117c478bd9Sstevel@tonic-gate } 15127c478bd9Sstevel@tonic-gate 15137c478bd9Sstevel@tonic-gate if (iovcnt <= MAXCLIOVECS) { 15147c478bd9Sstevel@tonic-gate #ifdef DEBUG 15157c478bd9Sstevel@tonic-gate rfs_write_hits++; 15167c478bd9Sstevel@tonic-gate #endif 15177c478bd9Sstevel@tonic-gate niovp = iov; 15187c478bd9Sstevel@tonic-gate } else { 15197c478bd9Sstevel@tonic-gate #ifdef DEBUG 15207c478bd9Sstevel@tonic-gate rfs_write_misses++; 15217c478bd9Sstevel@tonic-gate #endif 15227c478bd9Sstevel@tonic-gate niovp = kmem_alloc(sizeof (*niovp) * iovcnt, KM_SLEEP); 15237c478bd9Sstevel@tonic-gate } 15247c478bd9Sstevel@tonic-gate /* 15257c478bd9Sstevel@tonic-gate * Put together the scatter/gather iovecs. 15267c478bd9Sstevel@tonic-gate */ 15277c478bd9Sstevel@tonic-gate iovp = niovp; 15287c478bd9Sstevel@tonic-gate trp = rp; 15297c478bd9Sstevel@tonic-gate count = 0; 15307c478bd9Sstevel@tonic-gate do { 15310a701b1eSRobert Gordon if (trp->wa->wa_data || trp->wa->wa_rlist) { 15320a701b1eSRobert Gordon if (trp->wa->wa_rlist) { 15330a701b1eSRobert Gordon iovp->iov_base = 15340a701b1eSRobert Gordon (char *)((trp->wa->wa_rlist)-> 15350a701b1eSRobert Gordon u.c_daddr3); 15360a701b1eSRobert Gordon iovp->iov_len = trp->wa->wa_count; 15370a701b1eSRobert Gordon } else { 15387c478bd9Sstevel@tonic-gate iovp->iov_base = trp->wa->wa_data; 15397c478bd9Sstevel@tonic-gate iovp->iov_len = trp->wa->wa_count; 15400a701b1eSRobert Gordon } 15417c478bd9Sstevel@tonic-gate iovp++; 15427c478bd9Sstevel@tonic-gate } else { 15437c478bd9Sstevel@tonic-gate m = trp->wa->wa_mblk; 15447c478bd9Sstevel@tonic-gate rcount = trp->wa->wa_count; 15457c478bd9Sstevel@tonic-gate while (m != NULL) { 15467c478bd9Sstevel@tonic-gate iovp->iov_base = (caddr_t)m->b_rptr; 15477c478bd9Sstevel@tonic-gate iovp->iov_len = (m->b_wptr - m->b_rptr); 15487c478bd9Sstevel@tonic-gate rcount -= iovp->iov_len; 15497c478bd9Sstevel@tonic-gate if (rcount < 0) 15507c478bd9Sstevel@tonic-gate iovp->iov_len += rcount; 15517c478bd9Sstevel@tonic-gate iovp++; 15527c478bd9Sstevel@tonic-gate if (rcount <= 0) 15537c478bd9Sstevel@tonic-gate break; 15547c478bd9Sstevel@tonic-gate m = m->b_cont; 15557c478bd9Sstevel@tonic-gate } 15567c478bd9Sstevel@tonic-gate } 15577c478bd9Sstevel@tonic-gate count += trp->wa->wa_count; 15587c478bd9Sstevel@tonic-gate trp = trp->list; 15597c478bd9Sstevel@tonic-gate } while (trp != lrp); 15607c478bd9Sstevel@tonic-gate 15617c478bd9Sstevel@tonic-gate uio.uio_iov = niovp; 15627c478bd9Sstevel@tonic-gate uio.uio_iovcnt = iovcnt; 15637c478bd9Sstevel@tonic-gate uio.uio_segflg = UIO_SYSSPACE; 15647c478bd9Sstevel@tonic-gate uio.uio_extflg = UIO_COPY_DEFAULT; 15657c478bd9Sstevel@tonic-gate uio.uio_loffset = (offset_t)rp->wa->wa_offset; 15667c478bd9Sstevel@tonic-gate uio.uio_resid = count; 15677c478bd9Sstevel@tonic-gate /* 15687c478bd9Sstevel@tonic-gate * The limit is checked on the client. We 15697c478bd9Sstevel@tonic-gate * should allow any size writes here. 15707c478bd9Sstevel@tonic-gate */ 15717c478bd9Sstevel@tonic-gate uio.uio_llimit = curproc->p_fsz_ctl; 15727c478bd9Sstevel@tonic-gate rlimit = uio.uio_llimit - rp->wa->wa_offset; 15737c478bd9Sstevel@tonic-gate if (rlimit < (rlim64_t)uio.uio_resid) 15747c478bd9Sstevel@tonic-gate uio.uio_resid = (uint_t)rlimit; 15757c478bd9Sstevel@tonic-gate 15767c478bd9Sstevel@tonic-gate /* 15777c478bd9Sstevel@tonic-gate * For now we assume no append mode. 15787c478bd9Sstevel@tonic-gate */ 15797c478bd9Sstevel@tonic-gate 15807c478bd9Sstevel@tonic-gate /* 15817c478bd9Sstevel@tonic-gate * We're changing creds because VM may fault 15827c478bd9Sstevel@tonic-gate * and we need the cred of the current 15837c478bd9Sstevel@tonic-gate * thread to be used if quota * checking is 15847c478bd9Sstevel@tonic-gate * enabled. 15857c478bd9Sstevel@tonic-gate */ 15867c478bd9Sstevel@tonic-gate savecred = curthread->t_cred; 15877c478bd9Sstevel@tonic-gate curthread->t_cred = cr; 1588cfae96c2Sjwahlig error = VOP_WRITE(vp, &uio, 0, rp->cr, &ct); 15897c478bd9Sstevel@tonic-gate curthread->t_cred = savecred; 1590cfae96c2Sjwahlig 1591cfae96c2Sjwahlig /* check if a monitor detected a delegation conflict */ 1592cfae96c2Sjwahlig if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) 1593cfae96c2Sjwahlig /* mark as wouldblock so response is dropped */ 1594cfae96c2Sjwahlig curthread->t_flag |= T_WOULDBLOCK; 15957c478bd9Sstevel@tonic-gate 15967c478bd9Sstevel@tonic-gate if (niovp != iov) 15977c478bd9Sstevel@tonic-gate kmem_free(niovp, sizeof (*niovp) * iovcnt); 15987c478bd9Sstevel@tonic-gate 15997c478bd9Sstevel@tonic-gate if (!error) { 16007c478bd9Sstevel@tonic-gate data_written = 1; 16017c478bd9Sstevel@tonic-gate /* 16027c478bd9Sstevel@tonic-gate * Get attributes again so we send the latest mod 16037c478bd9Sstevel@tonic-gate * time to the client side for his cache. 16047c478bd9Sstevel@tonic-gate */ 16057c478bd9Sstevel@tonic-gate va.va_mask = AT_ALL; /* now we want everything */ 16060a701b1eSRobert Gordon 1607cfae96c2Sjwahlig error = VOP_GETATTR(vp, &va, 0, rp->cr, &ct); 16080a701b1eSRobert Gordon 16097c478bd9Sstevel@tonic-gate if (!error) 16107c478bd9Sstevel@tonic-gate acl_perm(vp, exi, &va, rp->cr); 16117c478bd9Sstevel@tonic-gate } 16127c478bd9Sstevel@tonic-gate 16137c478bd9Sstevel@tonic-gate /* 16147c478bd9Sstevel@tonic-gate * Fill in the status responses for each request 16157c478bd9Sstevel@tonic-gate * which was just handled. Also, copy the latest 16167c478bd9Sstevel@tonic-gate * attributes in to the attribute responses if 16177c478bd9Sstevel@tonic-gate * appropriate. 16187c478bd9Sstevel@tonic-gate */ 16197c478bd9Sstevel@tonic-gate t_flag = curthread->t_flag & T_WOULDBLOCK; 16207c478bd9Sstevel@tonic-gate do { 16217c478bd9Sstevel@tonic-gate rp->thread->t_flag |= t_flag; 16227c478bd9Sstevel@tonic-gate /* check for overflows */ 16237c478bd9Sstevel@tonic-gate if (!error) { 16247c478bd9Sstevel@tonic-gate error = vattr_to_nattr(&va, &rp->ns->ns_attr); 16257c478bd9Sstevel@tonic-gate } 16267c478bd9Sstevel@tonic-gate rp->ns->ns_status = puterrno(error); 16277c478bd9Sstevel@tonic-gate rp = rp->list; 16287c478bd9Sstevel@tonic-gate } while (rp != lrp); 16297c478bd9Sstevel@tonic-gate } while (rp != NULL); 16307c478bd9Sstevel@tonic-gate 16317c478bd9Sstevel@tonic-gate /* 16327c478bd9Sstevel@tonic-gate * If any data was written at all, then we need to flush 16337c478bd9Sstevel@tonic-gate * the data and metadata to stable storage. 16347c478bd9Sstevel@tonic-gate */ 16357c478bd9Sstevel@tonic-gate if (data_written) { 1636cfae96c2Sjwahlig error = VOP_PUTPAGE(vp, (u_offset_t)off, len, 0, cr, &ct); 16370a701b1eSRobert Gordon 16387c478bd9Sstevel@tonic-gate if (!error) { 1639cfae96c2Sjwahlig error = VOP_FSYNC(vp, FNODSYNC, cr, &ct); 16407c478bd9Sstevel@tonic-gate } 16417c478bd9Sstevel@tonic-gate } 16427c478bd9Sstevel@tonic-gate 1643cfae96c2Sjwahlig VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, &ct); 16447c478bd9Sstevel@tonic-gate 16457c478bd9Sstevel@tonic-gate if (in_crit) 16467c478bd9Sstevel@tonic-gate nbl_end_crit(vp); 16477c478bd9Sstevel@tonic-gate VN_RELE(vp); 16487c478bd9Sstevel@tonic-gate 16497c478bd9Sstevel@tonic-gate t_flag = curthread->t_flag & T_WOULDBLOCK; 16507c478bd9Sstevel@tonic-gate mutex_enter(&rfs_async_write_lock); 16517c478bd9Sstevel@tonic-gate for (rp = nlp->list; rp != NULL; rp = rp->list) { 16527c478bd9Sstevel@tonic-gate if (rp->ns->ns_status == RFSWRITE_INITVAL) { 16537c478bd9Sstevel@tonic-gate rp->ns->ns_status = puterrno(error); 16547c478bd9Sstevel@tonic-gate rp->thread->t_flag |= t_flag; 16557c478bd9Sstevel@tonic-gate } 16567c478bd9Sstevel@tonic-gate } 16577c478bd9Sstevel@tonic-gate cv_broadcast(&nlp->cv); 16587c478bd9Sstevel@tonic-gate mutex_exit(&rfs_async_write_lock); 16597c478bd9Sstevel@tonic-gate 16607c478bd9Sstevel@tonic-gate } 16617c478bd9Sstevel@tonic-gate 166227242a7cSthurlow void * 16637c478bd9Sstevel@tonic-gate rfs_write_getfh(struct nfswriteargs *wa) 16647c478bd9Sstevel@tonic-gate { 16657c478bd9Sstevel@tonic-gate return (&wa->wa_fhandle); 16667c478bd9Sstevel@tonic-gate } 16677c478bd9Sstevel@tonic-gate 16687c478bd9Sstevel@tonic-gate /* 16697c478bd9Sstevel@tonic-gate * Create a file. 16707c478bd9Sstevel@tonic-gate * Creates a file with given attributes and returns those attributes 16717c478bd9Sstevel@tonic-gate * and an fhandle for the new file. 16727c478bd9Sstevel@tonic-gate */ 16737c478bd9Sstevel@tonic-gate void 16747c478bd9Sstevel@tonic-gate rfs_create(struct nfscreatargs *args, struct nfsdiropres *dr, 16755cb0d679SMarcel Telka struct exportinfo *exi, struct svc_req *req, cred_t *cr, bool_t ro) 16767c478bd9Sstevel@tonic-gate { 16777c478bd9Sstevel@tonic-gate int error; 16787c478bd9Sstevel@tonic-gate int lookuperr; 16797c478bd9Sstevel@tonic-gate int in_crit = 0; 16807c478bd9Sstevel@tonic-gate struct vattr va; 16817c478bd9Sstevel@tonic-gate vnode_t *vp; 1682fd7da618Sgt29601 vnode_t *realvp; 16837c478bd9Sstevel@tonic-gate vnode_t *dvp; 16847c478bd9Sstevel@tonic-gate char *name = args->ca_da.da_name; 16857c478bd9Sstevel@tonic-gate vnode_t *tvp = NULL; 16867c478bd9Sstevel@tonic-gate int mode; 16877c478bd9Sstevel@tonic-gate int lookup_ok; 16887c478bd9Sstevel@tonic-gate bool_t trunc; 1689b89a8333Snatalie li - Sun Microsystems - Irvine United States struct sockaddr *ca; 16907c478bd9Sstevel@tonic-gate 16917c478bd9Sstevel@tonic-gate /* 16927c478bd9Sstevel@tonic-gate * Disallow NULL paths 16937c478bd9Sstevel@tonic-gate */ 16947c478bd9Sstevel@tonic-gate if (name == NULL || *name == '\0') { 16957c478bd9Sstevel@tonic-gate dr->dr_status = NFSERR_ACCES; 16967c478bd9Sstevel@tonic-gate return; 16977c478bd9Sstevel@tonic-gate } 16987c478bd9Sstevel@tonic-gate 16997c478bd9Sstevel@tonic-gate dvp = nfs_fhtovp(args->ca_da.da_fhandle, exi); 17007c478bd9Sstevel@tonic-gate if (dvp == NULL) { 17017c478bd9Sstevel@tonic-gate dr->dr_status = NFSERR_STALE; 17027c478bd9Sstevel@tonic-gate return; 17037c478bd9Sstevel@tonic-gate } 17047c478bd9Sstevel@tonic-gate 17057c478bd9Sstevel@tonic-gate error = sattr_to_vattr(args->ca_sa, &va); 17067c478bd9Sstevel@tonic-gate if (error) { 17077c478bd9Sstevel@tonic-gate dr->dr_status = puterrno(error); 17087c478bd9Sstevel@tonic-gate return; 17097c478bd9Sstevel@tonic-gate } 17107c478bd9Sstevel@tonic-gate 17117c478bd9Sstevel@tonic-gate /* 17127c478bd9Sstevel@tonic-gate * Must specify the mode. 17137c478bd9Sstevel@tonic-gate */ 17147c478bd9Sstevel@tonic-gate if (!(va.va_mask & AT_MODE)) { 17157c478bd9Sstevel@tonic-gate VN_RELE(dvp); 17167c478bd9Sstevel@tonic-gate dr->dr_status = NFSERR_INVAL; 17177c478bd9Sstevel@tonic-gate return; 17187c478bd9Sstevel@tonic-gate } 17197c478bd9Sstevel@tonic-gate 17207c478bd9Sstevel@tonic-gate /* 17217c478bd9Sstevel@tonic-gate * This is a completely gross hack to make mknod 17227c478bd9Sstevel@tonic-gate * work over the wire until we can wack the protocol 17237c478bd9Sstevel@tonic-gate */ 17247c478bd9Sstevel@tonic-gate if ((va.va_mode & IFMT) == IFCHR) { 17257c478bd9Sstevel@tonic-gate if (args->ca_sa->sa_size == (uint_t)NFS_FIFO_DEV) 17267c478bd9Sstevel@tonic-gate va.va_type = VFIFO; /* xtra kludge for named pipe */ 17277c478bd9Sstevel@tonic-gate else { 17287c478bd9Sstevel@tonic-gate va.va_type = VCHR; 17297c478bd9Sstevel@tonic-gate /* 17307c478bd9Sstevel@tonic-gate * uncompress the received dev_t 17317c478bd9Sstevel@tonic-gate * if the top half is zero indicating a request 17327c478bd9Sstevel@tonic-gate * from an `older style' OS. 17337c478bd9Sstevel@tonic-gate */ 17347c478bd9Sstevel@tonic-gate if ((va.va_size & 0xffff0000) == 0) 17357c478bd9Sstevel@tonic-gate va.va_rdev = nfsv2_expdev(va.va_size); 17367c478bd9Sstevel@tonic-gate else 17377c478bd9Sstevel@tonic-gate va.va_rdev = (dev_t)va.va_size; 17387c478bd9Sstevel@tonic-gate } 17397c478bd9Sstevel@tonic-gate va.va_mask &= ~AT_SIZE; 17407c478bd9Sstevel@tonic-gate } else if ((va.va_mode & IFMT) == IFBLK) { 17417c478bd9Sstevel@tonic-gate va.va_type = VBLK; 17427c478bd9Sstevel@tonic-gate /* 17437c478bd9Sstevel@tonic-gate * uncompress the received dev_t 17447c478bd9Sstevel@tonic-gate * if the top half is zero indicating a request 17457c478bd9Sstevel@tonic-gate * from an `older style' OS. 17467c478bd9Sstevel@tonic-gate */ 17477c478bd9Sstevel@tonic-gate if ((va.va_size & 0xffff0000) == 0) 17487c478bd9Sstevel@tonic-gate va.va_rdev = nfsv2_expdev(va.va_size); 17497c478bd9Sstevel@tonic-gate else 17507c478bd9Sstevel@tonic-gate va.va_rdev = (dev_t)va.va_size; 17517c478bd9Sstevel@tonic-gate va.va_mask &= ~AT_SIZE; 17527c478bd9Sstevel@tonic-gate } else if ((va.va_mode & IFMT) == IFSOCK) { 17537c478bd9Sstevel@tonic-gate va.va_type = VSOCK; 1754b89a8333Snatalie li - Sun Microsystems - Irvine United States } else { 17557c478bd9Sstevel@tonic-gate va.va_type = VREG; 1756b89a8333Snatalie li - Sun Microsystems - Irvine United States } 17577c478bd9Sstevel@tonic-gate va.va_mode &= ~IFMT; 17587c478bd9Sstevel@tonic-gate va.va_mask |= AT_TYPE; 17597c478bd9Sstevel@tonic-gate 1760b89a8333Snatalie li - Sun Microsystems - Irvine United States ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 1761b89a8333Snatalie li - Sun Microsystems - Irvine United States name = nfscmd_convname(ca, exi, name, NFSCMD_CONV_INBOUND, 1762b89a8333Snatalie li - Sun Microsystems - Irvine United States MAXPATHLEN); 1763b89a8333Snatalie li - Sun Microsystems - Irvine United States if (name == NULL) { 1764b89a8333Snatalie li - Sun Microsystems - Irvine United States dr->dr_status = puterrno(EINVAL); 1765b89a8333Snatalie li - Sun Microsystems - Irvine United States return; 1766b89a8333Snatalie li - Sun Microsystems - Irvine United States } 1767b89a8333Snatalie li - Sun Microsystems - Irvine United States 17687c478bd9Sstevel@tonic-gate /* 17697c478bd9Sstevel@tonic-gate * Why was the choice made to use VWRITE as the mode to the 17707c478bd9Sstevel@tonic-gate * call to VOP_CREATE ? This results in a bug. When a client 17717c478bd9Sstevel@tonic-gate * opens a file that already exists and is RDONLY, the second 17727c478bd9Sstevel@tonic-gate * open fails with an EACESS because of the mode. 17737c478bd9Sstevel@tonic-gate * bug ID 1054648. 17747c478bd9Sstevel@tonic-gate */ 17757c478bd9Sstevel@tonic-gate lookup_ok = 0; 17767c478bd9Sstevel@tonic-gate mode = VWRITE; 17777c478bd9Sstevel@tonic-gate if (!(va.va_mask & AT_SIZE) || va.va_type != VREG) { 1778da6c28aaSamw error = VOP_LOOKUP(dvp, name, &tvp, NULL, 0, NULL, cr, 1779da6c28aaSamw NULL, NULL, NULL); 17807c478bd9Sstevel@tonic-gate if (!error) { 17817c478bd9Sstevel@tonic-gate struct vattr at; 17827c478bd9Sstevel@tonic-gate 17837c478bd9Sstevel@tonic-gate lookup_ok = 1; 17847c478bd9Sstevel@tonic-gate at.va_mask = AT_MODE; 1785da6c28aaSamw error = VOP_GETATTR(tvp, &at, 0, cr, NULL); 17867c478bd9Sstevel@tonic-gate if (!error) 17877c478bd9Sstevel@tonic-gate mode = (at.va_mode & S_IWUSR) ? VWRITE : VREAD; 17887c478bd9Sstevel@tonic-gate VN_RELE(tvp); 17897c478bd9Sstevel@tonic-gate tvp = NULL; 17907c478bd9Sstevel@tonic-gate } 17917c478bd9Sstevel@tonic-gate } 17927c478bd9Sstevel@tonic-gate 17937c478bd9Sstevel@tonic-gate if (!lookup_ok) { 17945cb0d679SMarcel Telka if (rdonly(ro, dvp)) { 17957c478bd9Sstevel@tonic-gate error = EROFS; 17967c478bd9Sstevel@tonic-gate } else if (va.va_type != VREG && va.va_type != VFIFO && 17977c478bd9Sstevel@tonic-gate va.va_type != VSOCK && secpolicy_sys_devices(cr) != 0) { 17987c478bd9Sstevel@tonic-gate error = EPERM; 17997c478bd9Sstevel@tonic-gate } else { 18007c478bd9Sstevel@tonic-gate error = 0; 18017c478bd9Sstevel@tonic-gate } 18027c478bd9Sstevel@tonic-gate } 18037c478bd9Sstevel@tonic-gate 18047c478bd9Sstevel@tonic-gate /* 18057c478bd9Sstevel@tonic-gate * If file size is being modified on an already existing file 18067c478bd9Sstevel@tonic-gate * make sure that there are no conflicting non-blocking mandatory 18077c478bd9Sstevel@tonic-gate * locks in the region being manipulated. Return EACCES if there 18087c478bd9Sstevel@tonic-gate * are conflicting locks. 18097c478bd9Sstevel@tonic-gate */ 18107c478bd9Sstevel@tonic-gate if (!error && (va.va_type == VREG) && (va.va_mask & AT_SIZE)) { 1811da6c28aaSamw lookuperr = VOP_LOOKUP(dvp, name, &tvp, NULL, 0, NULL, cr, 1812da6c28aaSamw NULL, NULL, NULL); 18137c478bd9Sstevel@tonic-gate 18147c478bd9Sstevel@tonic-gate if (!lookuperr && 18157c478bd9Sstevel@tonic-gate rfs4_check_delegated(FWRITE, tvp, va.va_size == 0)) { 18167c478bd9Sstevel@tonic-gate VN_RELE(tvp); 18177c478bd9Sstevel@tonic-gate curthread->t_flag |= T_WOULDBLOCK; 18187c478bd9Sstevel@tonic-gate goto out; 18197c478bd9Sstevel@tonic-gate } 18207c478bd9Sstevel@tonic-gate 18217c478bd9Sstevel@tonic-gate if (!lookuperr && nbl_need_check(tvp)) { 18227c478bd9Sstevel@tonic-gate /* 18237c478bd9Sstevel@tonic-gate * The file exists. Now check if it has any 18247c478bd9Sstevel@tonic-gate * conflicting non-blocking mandatory locks 18257c478bd9Sstevel@tonic-gate * in the region being changed. 18267c478bd9Sstevel@tonic-gate */ 18277c478bd9Sstevel@tonic-gate struct vattr bva; 18287c478bd9Sstevel@tonic-gate u_offset_t offset; 18297c478bd9Sstevel@tonic-gate ssize_t length; 18307c478bd9Sstevel@tonic-gate 18317c478bd9Sstevel@tonic-gate nbl_start_crit(tvp, RW_READER); 18327c478bd9Sstevel@tonic-gate in_crit = 1; 18337c478bd9Sstevel@tonic-gate 18347c478bd9Sstevel@tonic-gate bva.va_mask = AT_SIZE; 1835da6c28aaSamw error = VOP_GETATTR(tvp, &bva, 0, cr, NULL); 18367c478bd9Sstevel@tonic-gate if (!error) { 18377c478bd9Sstevel@tonic-gate if (va.va_size < bva.va_size) { 18387c478bd9Sstevel@tonic-gate offset = va.va_size; 18397c478bd9Sstevel@tonic-gate length = bva.va_size - va.va_size; 18407c478bd9Sstevel@tonic-gate } else { 18417c478bd9Sstevel@tonic-gate offset = bva.va_size; 18427c478bd9Sstevel@tonic-gate length = va.va_size - bva.va_size; 18437c478bd9Sstevel@tonic-gate } 18447c478bd9Sstevel@tonic-gate if (length) { 18457c478bd9Sstevel@tonic-gate if (nbl_conflict(tvp, NBL_WRITE, 1846da6c28aaSamw offset, length, 0, NULL)) { 18477c478bd9Sstevel@tonic-gate error = EACCES; 18487c478bd9Sstevel@tonic-gate } 18497c478bd9Sstevel@tonic-gate } 18507c478bd9Sstevel@tonic-gate } 18517c478bd9Sstevel@tonic-gate if (error) { 18527c478bd9Sstevel@tonic-gate nbl_end_crit(tvp); 18537c478bd9Sstevel@tonic-gate VN_RELE(tvp); 18547c478bd9Sstevel@tonic-gate in_crit = 0; 18557c478bd9Sstevel@tonic-gate } 18567c478bd9Sstevel@tonic-gate } else if (tvp != NULL) { 18577c478bd9Sstevel@tonic-gate VN_RELE(tvp); 18587c478bd9Sstevel@tonic-gate } 18597c478bd9Sstevel@tonic-gate } 18607c478bd9Sstevel@tonic-gate 18617c478bd9Sstevel@tonic-gate if (!error) { 18627c478bd9Sstevel@tonic-gate /* 18637c478bd9Sstevel@tonic-gate * If filesystem is shared with nosuid the remove any 18647c478bd9Sstevel@tonic-gate * setuid/setgid bits on create. 18657c478bd9Sstevel@tonic-gate */ 18667c478bd9Sstevel@tonic-gate if (va.va_type == VREG && 18677c478bd9Sstevel@tonic-gate exi->exi_export.ex_flags & EX_NOSUID) 18687c478bd9Sstevel@tonic-gate va.va_mode &= ~(VSUID | VSGID); 18697c478bd9Sstevel@tonic-gate 1870da6c28aaSamw error = VOP_CREATE(dvp, name, &va, NONEXCL, mode, &vp, cr, 0, 1871da6c28aaSamw NULL, NULL); 18727c478bd9Sstevel@tonic-gate 18737c478bd9Sstevel@tonic-gate if (!error) { 18747c478bd9Sstevel@tonic-gate 18757c478bd9Sstevel@tonic-gate if ((va.va_mask & AT_SIZE) && (va.va_size == 0)) 18767c478bd9Sstevel@tonic-gate trunc = TRUE; 18777c478bd9Sstevel@tonic-gate else 18787c478bd9Sstevel@tonic-gate trunc = FALSE; 18797c478bd9Sstevel@tonic-gate 18801b300de9Sjwahlig if (rfs4_check_delegated(FWRITE, vp, trunc)) { 18811b300de9Sjwahlig VN_RELE(vp); 18827c478bd9Sstevel@tonic-gate curthread->t_flag |= T_WOULDBLOCK; 18837c478bd9Sstevel@tonic-gate goto out; 18847c478bd9Sstevel@tonic-gate } 18857c478bd9Sstevel@tonic-gate va.va_mask = AT_ALL; 18860a701b1eSRobert Gordon 1887da6c28aaSamw error = VOP_GETATTR(vp, &va, 0, cr, NULL); 18880a701b1eSRobert Gordon 18897c478bd9Sstevel@tonic-gate /* check for overflows */ 18907c478bd9Sstevel@tonic-gate if (!error) { 18917c478bd9Sstevel@tonic-gate acl_perm(vp, exi, &va, cr); 18927c478bd9Sstevel@tonic-gate error = vattr_to_nattr(&va, &dr->dr_attr); 18937c478bd9Sstevel@tonic-gate if (!error) { 18947c478bd9Sstevel@tonic-gate error = makefh(&dr->dr_fhandle, vp, 18957c478bd9Sstevel@tonic-gate exi); 18967c478bd9Sstevel@tonic-gate } 18977c478bd9Sstevel@tonic-gate } 18987c478bd9Sstevel@tonic-gate /* 18997c478bd9Sstevel@tonic-gate * Force modified metadata out to stable storage. 1900fd7da618Sgt29601 * 1901fd7da618Sgt29601 * if a underlying vp exists, pass it to VOP_FSYNC 19027c478bd9Sstevel@tonic-gate */ 1903fd7da618Sgt29601 if (VOP_REALVP(vp, &realvp, NULL) == 0) 1904fd7da618Sgt29601 (void) VOP_FSYNC(realvp, FNODSYNC, cr, NULL); 1905fd7da618Sgt29601 else 1906da6c28aaSamw (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL); 19077c478bd9Sstevel@tonic-gate VN_RELE(vp); 19087c478bd9Sstevel@tonic-gate } 19097c478bd9Sstevel@tonic-gate 19107c478bd9Sstevel@tonic-gate if (in_crit) { 19117c478bd9Sstevel@tonic-gate nbl_end_crit(tvp); 19127c478bd9Sstevel@tonic-gate VN_RELE(tvp); 19137c478bd9Sstevel@tonic-gate } 19147c478bd9Sstevel@tonic-gate } 19157c478bd9Sstevel@tonic-gate 19167c478bd9Sstevel@tonic-gate /* 19177c478bd9Sstevel@tonic-gate * Force modified data and metadata out to stable storage. 19187c478bd9Sstevel@tonic-gate */ 1919da6c28aaSamw (void) VOP_FSYNC(dvp, 0, cr, NULL); 19207c478bd9Sstevel@tonic-gate 19217c478bd9Sstevel@tonic-gate out: 19227c478bd9Sstevel@tonic-gate 19237c478bd9Sstevel@tonic-gate VN_RELE(dvp); 19247c478bd9Sstevel@tonic-gate 19257c478bd9Sstevel@tonic-gate dr->dr_status = puterrno(error); 19267c478bd9Sstevel@tonic-gate 1927b89a8333Snatalie li - Sun Microsystems - Irvine United States if (name != args->ca_da.da_name) 1928b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(name, MAXPATHLEN); 19297c478bd9Sstevel@tonic-gate } 193027242a7cSthurlow void * 19317c478bd9Sstevel@tonic-gate rfs_create_getfh(struct nfscreatargs *args) 19327c478bd9Sstevel@tonic-gate { 19337c478bd9Sstevel@tonic-gate return (args->ca_da.da_fhandle); 19347c478bd9Sstevel@tonic-gate } 19357c478bd9Sstevel@tonic-gate 19367c478bd9Sstevel@tonic-gate /* 19377c478bd9Sstevel@tonic-gate * Remove a file. 19387c478bd9Sstevel@tonic-gate * Remove named file from parent directory. 19397c478bd9Sstevel@tonic-gate */ 19405cb0d679SMarcel Telka /* ARGSUSED */ 19417c478bd9Sstevel@tonic-gate void 19427c478bd9Sstevel@tonic-gate rfs_remove(struct nfsdiropargs *da, enum nfsstat *status, 19435cb0d679SMarcel Telka struct exportinfo *exi, struct svc_req *req, cred_t *cr, bool_t ro) 19447c478bd9Sstevel@tonic-gate { 19457c478bd9Sstevel@tonic-gate int error = 0; 19467c478bd9Sstevel@tonic-gate vnode_t *vp; 19477c478bd9Sstevel@tonic-gate vnode_t *targvp; 19487c478bd9Sstevel@tonic-gate int in_crit = 0; 19497c478bd9Sstevel@tonic-gate 19507c478bd9Sstevel@tonic-gate /* 19517c478bd9Sstevel@tonic-gate * Disallow NULL paths 19527c478bd9Sstevel@tonic-gate */ 19537c478bd9Sstevel@tonic-gate if (da->da_name == NULL || *da->da_name == '\0') { 19547c478bd9Sstevel@tonic-gate *status = NFSERR_ACCES; 19557c478bd9Sstevel@tonic-gate return; 19567c478bd9Sstevel@tonic-gate } 19577c478bd9Sstevel@tonic-gate 19587c478bd9Sstevel@tonic-gate vp = nfs_fhtovp(da->da_fhandle, exi); 19597c478bd9Sstevel@tonic-gate if (vp == NULL) { 19607c478bd9Sstevel@tonic-gate *status = NFSERR_STALE; 19617c478bd9Sstevel@tonic-gate return; 19627c478bd9Sstevel@tonic-gate } 19637c478bd9Sstevel@tonic-gate 19645cb0d679SMarcel Telka if (rdonly(ro, vp)) { 19657c478bd9Sstevel@tonic-gate VN_RELE(vp); 19667c478bd9Sstevel@tonic-gate *status = NFSERR_ROFS; 19677c478bd9Sstevel@tonic-gate return; 19687c478bd9Sstevel@tonic-gate } 19697c478bd9Sstevel@tonic-gate 19707c478bd9Sstevel@tonic-gate /* 19717c478bd9Sstevel@tonic-gate * Check for a conflict with a non-blocking mandatory share reservation. 19727c478bd9Sstevel@tonic-gate */ 1973da6c28aaSamw error = VOP_LOOKUP(vp, da->da_name, &targvp, NULL, 0, 1974da6c28aaSamw NULL, cr, NULL, NULL, NULL); 19757c478bd9Sstevel@tonic-gate if (error != 0) { 19767c478bd9Sstevel@tonic-gate VN_RELE(vp); 19777c478bd9Sstevel@tonic-gate *status = puterrno(error); 19787c478bd9Sstevel@tonic-gate return; 19797c478bd9Sstevel@tonic-gate } 19807c478bd9Sstevel@tonic-gate 19817c478bd9Sstevel@tonic-gate /* 19827c478bd9Sstevel@tonic-gate * If the file is delegated to an v4 client, then initiate 19837c478bd9Sstevel@tonic-gate * recall and drop this request (by setting T_WOULDBLOCK). 19847c478bd9Sstevel@tonic-gate * The client will eventually re-transmit the request and 19857c478bd9Sstevel@tonic-gate * (hopefully), by then, the v4 client will have returned 19867c478bd9Sstevel@tonic-gate * the delegation. 19877c478bd9Sstevel@tonic-gate */ 19887c478bd9Sstevel@tonic-gate 19897c478bd9Sstevel@tonic-gate if (rfs4_check_delegated(FWRITE, targvp, TRUE)) { 19907c478bd9Sstevel@tonic-gate VN_RELE(vp); 19917c478bd9Sstevel@tonic-gate VN_RELE(targvp); 19927c478bd9Sstevel@tonic-gate curthread->t_flag |= T_WOULDBLOCK; 19937c478bd9Sstevel@tonic-gate return; 19947c478bd9Sstevel@tonic-gate } 19957c478bd9Sstevel@tonic-gate 19967c478bd9Sstevel@tonic-gate if (nbl_need_check(targvp)) { 19977c478bd9Sstevel@tonic-gate nbl_start_crit(targvp, RW_READER); 19987c478bd9Sstevel@tonic-gate in_crit = 1; 1999da6c28aaSamw if (nbl_conflict(targvp, NBL_REMOVE, 0, 0, 0, NULL)) { 20007c478bd9Sstevel@tonic-gate error = EACCES; 20017c478bd9Sstevel@tonic-gate goto out; 20027c478bd9Sstevel@tonic-gate } 20037c478bd9Sstevel@tonic-gate } 20047c478bd9Sstevel@tonic-gate 2005da6c28aaSamw error = VOP_REMOVE(vp, da->da_name, cr, NULL, 0); 20067c478bd9Sstevel@tonic-gate 20077c478bd9Sstevel@tonic-gate /* 20087c478bd9Sstevel@tonic-gate * Force modified data and metadata out to stable storage. 20097c478bd9Sstevel@tonic-gate */ 2010da6c28aaSamw (void) VOP_FSYNC(vp, 0, cr, NULL); 20117c478bd9Sstevel@tonic-gate 20127c478bd9Sstevel@tonic-gate out: 20137c478bd9Sstevel@tonic-gate if (in_crit) 20147c478bd9Sstevel@tonic-gate nbl_end_crit(targvp); 20157c478bd9Sstevel@tonic-gate VN_RELE(targvp); 20167c478bd9Sstevel@tonic-gate VN_RELE(vp); 20177c478bd9Sstevel@tonic-gate 20187c478bd9Sstevel@tonic-gate *status = puterrno(error); 20197c478bd9Sstevel@tonic-gate 20207c478bd9Sstevel@tonic-gate } 20217c478bd9Sstevel@tonic-gate 202227242a7cSthurlow void * 20237c478bd9Sstevel@tonic-gate rfs_remove_getfh(struct nfsdiropargs *da) 20247c478bd9Sstevel@tonic-gate { 20257c478bd9Sstevel@tonic-gate return (da->da_fhandle); 20267c478bd9Sstevel@tonic-gate } 20277c478bd9Sstevel@tonic-gate 20287c478bd9Sstevel@tonic-gate /* 20297c478bd9Sstevel@tonic-gate * rename a file 20307c478bd9Sstevel@tonic-gate * Give a file (from) a new name (to). 20317c478bd9Sstevel@tonic-gate */ 20325cb0d679SMarcel Telka /* ARGSUSED */ 20337c478bd9Sstevel@tonic-gate void 20347c478bd9Sstevel@tonic-gate rfs_rename(struct nfsrnmargs *args, enum nfsstat *status, 20355cb0d679SMarcel Telka struct exportinfo *exi, struct svc_req *req, cred_t *cr, bool_t ro) 20367c478bd9Sstevel@tonic-gate { 20377c478bd9Sstevel@tonic-gate int error = 0; 20387c478bd9Sstevel@tonic-gate vnode_t *fromvp; 20397c478bd9Sstevel@tonic-gate vnode_t *tovp; 20407c478bd9Sstevel@tonic-gate struct exportinfo *to_exi; 20417c478bd9Sstevel@tonic-gate fhandle_t *fh; 20427c478bd9Sstevel@tonic-gate vnode_t *srcvp; 20437c478bd9Sstevel@tonic-gate vnode_t *targvp; 20447c478bd9Sstevel@tonic-gate int in_crit = 0; 20457c478bd9Sstevel@tonic-gate 20467c478bd9Sstevel@tonic-gate fromvp = nfs_fhtovp(args->rna_from.da_fhandle, exi); 20477c478bd9Sstevel@tonic-gate if (fromvp == NULL) { 20487c478bd9Sstevel@tonic-gate *status = NFSERR_STALE; 20497c478bd9Sstevel@tonic-gate return; 20507c478bd9Sstevel@tonic-gate } 20517c478bd9Sstevel@tonic-gate 20527c478bd9Sstevel@tonic-gate fh = args->rna_to.da_fhandle; 2053*fbd2e8e1SArne Jansen to_exi = checkexport(&fh->fh_fsid, (fid_t *)&fh->fh_xlen, NULL); 20547c478bd9Sstevel@tonic-gate if (to_exi == NULL) { 20557c478bd9Sstevel@tonic-gate VN_RELE(fromvp); 20567c478bd9Sstevel@tonic-gate *status = NFSERR_ACCES; 20577c478bd9Sstevel@tonic-gate return; 20587c478bd9Sstevel@tonic-gate } 20597c478bd9Sstevel@tonic-gate exi_rele(to_exi); 20607c478bd9Sstevel@tonic-gate 20617c478bd9Sstevel@tonic-gate if (to_exi != exi) { 20627c478bd9Sstevel@tonic-gate VN_RELE(fromvp); 20637c478bd9Sstevel@tonic-gate *status = NFSERR_XDEV; 20647c478bd9Sstevel@tonic-gate return; 20657c478bd9Sstevel@tonic-gate } 20667c478bd9Sstevel@tonic-gate 20677c478bd9Sstevel@tonic-gate tovp = nfs_fhtovp(args->rna_to.da_fhandle, exi); 20687c478bd9Sstevel@tonic-gate if (tovp == NULL) { 20697c478bd9Sstevel@tonic-gate VN_RELE(fromvp); 20707c478bd9Sstevel@tonic-gate *status = NFSERR_STALE; 20717c478bd9Sstevel@tonic-gate return; 20727c478bd9Sstevel@tonic-gate } 20737c478bd9Sstevel@tonic-gate 20747c478bd9Sstevel@tonic-gate if (fromvp->v_type != VDIR || tovp->v_type != VDIR) { 20757c478bd9Sstevel@tonic-gate VN_RELE(tovp); 20767c478bd9Sstevel@tonic-gate VN_RELE(fromvp); 20777c478bd9Sstevel@tonic-gate *status = NFSERR_NOTDIR; 20787c478bd9Sstevel@tonic-gate return; 20797c478bd9Sstevel@tonic-gate } 20807c478bd9Sstevel@tonic-gate 20817c478bd9Sstevel@tonic-gate /* 20827c478bd9Sstevel@tonic-gate * Disallow NULL paths 20837c478bd9Sstevel@tonic-gate */ 20847c478bd9Sstevel@tonic-gate if (args->rna_from.da_name == NULL || *args->rna_from.da_name == '\0' || 20857c478bd9Sstevel@tonic-gate args->rna_to.da_name == NULL || *args->rna_to.da_name == '\0') { 20867c478bd9Sstevel@tonic-gate VN_RELE(tovp); 20877c478bd9Sstevel@tonic-gate VN_RELE(fromvp); 20887c478bd9Sstevel@tonic-gate *status = NFSERR_ACCES; 20897c478bd9Sstevel@tonic-gate return; 20907c478bd9Sstevel@tonic-gate } 20917c478bd9Sstevel@tonic-gate 20925cb0d679SMarcel Telka if (rdonly(ro, tovp)) { 20937c478bd9Sstevel@tonic-gate VN_RELE(tovp); 20947c478bd9Sstevel@tonic-gate VN_RELE(fromvp); 20957c478bd9Sstevel@tonic-gate *status = NFSERR_ROFS; 20967c478bd9Sstevel@tonic-gate return; 20977c478bd9Sstevel@tonic-gate } 20987c478bd9Sstevel@tonic-gate 20997c478bd9Sstevel@tonic-gate /* 21007c478bd9Sstevel@tonic-gate * Check for a conflict with a non-blocking mandatory share reservation. 21017c478bd9Sstevel@tonic-gate */ 21027c478bd9Sstevel@tonic-gate error = VOP_LOOKUP(fromvp, args->rna_from.da_name, &srcvp, NULL, 0, 2103da6c28aaSamw NULL, cr, NULL, NULL, NULL); 21047c478bd9Sstevel@tonic-gate if (error != 0) { 21057c478bd9Sstevel@tonic-gate VN_RELE(tovp); 21067c478bd9Sstevel@tonic-gate VN_RELE(fromvp); 21077c478bd9Sstevel@tonic-gate *status = puterrno(error); 21087c478bd9Sstevel@tonic-gate return; 21097c478bd9Sstevel@tonic-gate } 21107c478bd9Sstevel@tonic-gate 21117c478bd9Sstevel@tonic-gate /* Check for delegations on the source file */ 21127c478bd9Sstevel@tonic-gate 21137c478bd9Sstevel@tonic-gate if (rfs4_check_delegated(FWRITE, srcvp, FALSE)) { 21147c478bd9Sstevel@tonic-gate VN_RELE(tovp); 21157c478bd9Sstevel@tonic-gate VN_RELE(fromvp); 21167c478bd9Sstevel@tonic-gate VN_RELE(srcvp); 21177c478bd9Sstevel@tonic-gate curthread->t_flag |= T_WOULDBLOCK; 21187c478bd9Sstevel@tonic-gate return; 21197c478bd9Sstevel@tonic-gate } 21207c478bd9Sstevel@tonic-gate 21217c478bd9Sstevel@tonic-gate /* Check for delegation on the file being renamed over, if it exists */ 21227c478bd9Sstevel@tonic-gate 21237c478bd9Sstevel@tonic-gate if (rfs4_deleg_policy != SRV_NEVER_DELEGATE && 2124da6c28aaSamw VOP_LOOKUP(tovp, args->rna_to.da_name, &targvp, NULL, 0, NULL, cr, 2125da6c28aaSamw NULL, NULL, NULL) == 0) { 21267c478bd9Sstevel@tonic-gate 21277c478bd9Sstevel@tonic-gate if (rfs4_check_delegated(FWRITE, targvp, TRUE)) { 21287c478bd9Sstevel@tonic-gate VN_RELE(tovp); 21297c478bd9Sstevel@tonic-gate VN_RELE(fromvp); 21307c478bd9Sstevel@tonic-gate VN_RELE(srcvp); 21317c478bd9Sstevel@tonic-gate VN_RELE(targvp); 21327c478bd9Sstevel@tonic-gate curthread->t_flag |= T_WOULDBLOCK; 21337c478bd9Sstevel@tonic-gate return; 21347c478bd9Sstevel@tonic-gate } 21357c478bd9Sstevel@tonic-gate VN_RELE(targvp); 21367c478bd9Sstevel@tonic-gate } 21377c478bd9Sstevel@tonic-gate 21387c478bd9Sstevel@tonic-gate 21397c478bd9Sstevel@tonic-gate if (nbl_need_check(srcvp)) { 21407c478bd9Sstevel@tonic-gate nbl_start_crit(srcvp, RW_READER); 21417c478bd9Sstevel@tonic-gate in_crit = 1; 2142da6c28aaSamw if (nbl_conflict(srcvp, NBL_RENAME, 0, 0, 0, NULL)) { 21437c478bd9Sstevel@tonic-gate error = EACCES; 21447c478bd9Sstevel@tonic-gate goto out; 21457c478bd9Sstevel@tonic-gate } 21467c478bd9Sstevel@tonic-gate } 21477c478bd9Sstevel@tonic-gate 21487c478bd9Sstevel@tonic-gate error = VOP_RENAME(fromvp, args->rna_from.da_name, 2149da6c28aaSamw tovp, args->rna_to.da_name, cr, NULL, 0); 21507c478bd9Sstevel@tonic-gate 215151ece835Seschrock if (error == 0) 215251ece835Seschrock vn_renamepath(tovp, srcvp, args->rna_to.da_name, 2153c9264041Sjwahlig strlen(args->rna_to.da_name)); 2154c9264041Sjwahlig 21557c478bd9Sstevel@tonic-gate /* 21567c478bd9Sstevel@tonic-gate * Force modified data and metadata out to stable storage. 21577c478bd9Sstevel@tonic-gate */ 2158da6c28aaSamw (void) VOP_FSYNC(tovp, 0, cr, NULL); 2159da6c28aaSamw (void) VOP_FSYNC(fromvp, 0, cr, NULL); 21607c478bd9Sstevel@tonic-gate 21617c478bd9Sstevel@tonic-gate out: 21627c478bd9Sstevel@tonic-gate if (in_crit) 21637c478bd9Sstevel@tonic-gate nbl_end_crit(srcvp); 21647c478bd9Sstevel@tonic-gate VN_RELE(srcvp); 21657c478bd9Sstevel@tonic-gate VN_RELE(tovp); 21667c478bd9Sstevel@tonic-gate VN_RELE(fromvp); 21677c478bd9Sstevel@tonic-gate 21687c478bd9Sstevel@tonic-gate *status = puterrno(error); 21697c478bd9Sstevel@tonic-gate 21707c478bd9Sstevel@tonic-gate } 217127242a7cSthurlow void * 21727c478bd9Sstevel@tonic-gate rfs_rename_getfh(struct nfsrnmargs *args) 21737c478bd9Sstevel@tonic-gate { 21747c478bd9Sstevel@tonic-gate return (args->rna_from.da_fhandle); 21757c478bd9Sstevel@tonic-gate } 21767c478bd9Sstevel@tonic-gate 21777c478bd9Sstevel@tonic-gate /* 21787c478bd9Sstevel@tonic-gate * Link to a file. 21797c478bd9Sstevel@tonic-gate * Create a file (to) which is a hard link to the given file (from). 21807c478bd9Sstevel@tonic-gate */ 21815cb0d679SMarcel Telka /* ARGSUSED */ 21827c478bd9Sstevel@tonic-gate void 21837c478bd9Sstevel@tonic-gate rfs_link(struct nfslinkargs *args, enum nfsstat *status, 21845cb0d679SMarcel Telka struct exportinfo *exi, struct svc_req *req, cred_t *cr, bool_t ro) 21857c478bd9Sstevel@tonic-gate { 21867c478bd9Sstevel@tonic-gate int error; 21877c478bd9Sstevel@tonic-gate vnode_t *fromvp; 21887c478bd9Sstevel@tonic-gate vnode_t *tovp; 21897c478bd9Sstevel@tonic-gate struct exportinfo *to_exi; 21907c478bd9Sstevel@tonic-gate fhandle_t *fh; 21917c478bd9Sstevel@tonic-gate 21927c478bd9Sstevel@tonic-gate fromvp = nfs_fhtovp(args->la_from, exi); 21937c478bd9Sstevel@tonic-gate if (fromvp == NULL) { 21947c478bd9Sstevel@tonic-gate *status = NFSERR_STALE; 21957c478bd9Sstevel@tonic-gate return; 21967c478bd9Sstevel@tonic-gate } 21977c478bd9Sstevel@tonic-gate 21987c478bd9Sstevel@tonic-gate fh = args->la_to.da_fhandle; 2199*fbd2e8e1SArne Jansen to_exi = checkexport(&fh->fh_fsid, (fid_t *)&fh->fh_xlen, NULL); 22007c478bd9Sstevel@tonic-gate if (to_exi == NULL) { 22017c478bd9Sstevel@tonic-gate VN_RELE(fromvp); 22027c478bd9Sstevel@tonic-gate *status = NFSERR_ACCES; 22037c478bd9Sstevel@tonic-gate return; 22047c478bd9Sstevel@tonic-gate } 22057c478bd9Sstevel@tonic-gate exi_rele(to_exi); 22067c478bd9Sstevel@tonic-gate 22077c478bd9Sstevel@tonic-gate if (to_exi != exi) { 22087c478bd9Sstevel@tonic-gate VN_RELE(fromvp); 22097c478bd9Sstevel@tonic-gate *status = NFSERR_XDEV; 22107c478bd9Sstevel@tonic-gate return; 22117c478bd9Sstevel@tonic-gate } 22127c478bd9Sstevel@tonic-gate 22137c478bd9Sstevel@tonic-gate tovp = nfs_fhtovp(args->la_to.da_fhandle, exi); 22147c478bd9Sstevel@tonic-gate if (tovp == NULL) { 22157c478bd9Sstevel@tonic-gate VN_RELE(fromvp); 22167c478bd9Sstevel@tonic-gate *status = NFSERR_STALE; 22177c478bd9Sstevel@tonic-gate return; 22187c478bd9Sstevel@tonic-gate } 22197c478bd9Sstevel@tonic-gate 22207c478bd9Sstevel@tonic-gate if (tovp->v_type != VDIR) { 22217c478bd9Sstevel@tonic-gate VN_RELE(tovp); 22227c478bd9Sstevel@tonic-gate VN_RELE(fromvp); 22237c478bd9Sstevel@tonic-gate *status = NFSERR_NOTDIR; 22247c478bd9Sstevel@tonic-gate return; 22257c478bd9Sstevel@tonic-gate } 22267c478bd9Sstevel@tonic-gate /* 22277c478bd9Sstevel@tonic-gate * Disallow NULL paths 22287c478bd9Sstevel@tonic-gate */ 22297c478bd9Sstevel@tonic-gate if (args->la_to.da_name == NULL || *args->la_to.da_name == '\0') { 22307c478bd9Sstevel@tonic-gate VN_RELE(tovp); 22317c478bd9Sstevel@tonic-gate VN_RELE(fromvp); 22327c478bd9Sstevel@tonic-gate *status = NFSERR_ACCES; 22337c478bd9Sstevel@tonic-gate return; 22347c478bd9Sstevel@tonic-gate } 22357c478bd9Sstevel@tonic-gate 22365cb0d679SMarcel Telka if (rdonly(ro, tovp)) { 22377c478bd9Sstevel@tonic-gate VN_RELE(tovp); 22387c478bd9Sstevel@tonic-gate VN_RELE(fromvp); 22397c478bd9Sstevel@tonic-gate *status = NFSERR_ROFS; 22407c478bd9Sstevel@tonic-gate return; 22417c478bd9Sstevel@tonic-gate } 22427c478bd9Sstevel@tonic-gate 2243da6c28aaSamw error = VOP_LINK(tovp, fromvp, args->la_to.da_name, cr, NULL, 0); 22447c478bd9Sstevel@tonic-gate 22457c478bd9Sstevel@tonic-gate /* 22467c478bd9Sstevel@tonic-gate * Force modified data and metadata out to stable storage. 22477c478bd9Sstevel@tonic-gate */ 2248da6c28aaSamw (void) VOP_FSYNC(tovp, 0, cr, NULL); 2249da6c28aaSamw (void) VOP_FSYNC(fromvp, FNODSYNC, cr, NULL); 22507c478bd9Sstevel@tonic-gate 22517c478bd9Sstevel@tonic-gate VN_RELE(tovp); 22527c478bd9Sstevel@tonic-gate VN_RELE(fromvp); 22537c478bd9Sstevel@tonic-gate 22547c478bd9Sstevel@tonic-gate *status = puterrno(error); 22557c478bd9Sstevel@tonic-gate 22567c478bd9Sstevel@tonic-gate } 225727242a7cSthurlow void * 22587c478bd9Sstevel@tonic-gate rfs_link_getfh(struct nfslinkargs *args) 22597c478bd9Sstevel@tonic-gate { 22607c478bd9Sstevel@tonic-gate return (args->la_from); 22617c478bd9Sstevel@tonic-gate } 22627c478bd9Sstevel@tonic-gate 22637c478bd9Sstevel@tonic-gate /* 22647c478bd9Sstevel@tonic-gate * Symbolicly link to a file. 22657c478bd9Sstevel@tonic-gate * Create a file (to) with the given attributes which is a symbolic link 22667c478bd9Sstevel@tonic-gate * to the given path name (to). 22677c478bd9Sstevel@tonic-gate */ 22687c478bd9Sstevel@tonic-gate void 22697c478bd9Sstevel@tonic-gate rfs_symlink(struct nfsslargs *args, enum nfsstat *status, 22705cb0d679SMarcel Telka struct exportinfo *exi, struct svc_req *req, cred_t *cr, bool_t ro) 22717c478bd9Sstevel@tonic-gate { 22727c478bd9Sstevel@tonic-gate int error; 22737c478bd9Sstevel@tonic-gate struct vattr va; 22747c478bd9Sstevel@tonic-gate vnode_t *vp; 22757c478bd9Sstevel@tonic-gate vnode_t *svp; 22767c478bd9Sstevel@tonic-gate int lerror; 2277b89a8333Snatalie li - Sun Microsystems - Irvine United States struct sockaddr *ca; 2278b89a8333Snatalie li - Sun Microsystems - Irvine United States char *name = NULL; 22797c478bd9Sstevel@tonic-gate 22807c478bd9Sstevel@tonic-gate /* 22817c478bd9Sstevel@tonic-gate * Disallow NULL paths 22827c478bd9Sstevel@tonic-gate */ 22837c478bd9Sstevel@tonic-gate if (args->sla_from.da_name == NULL || *args->sla_from.da_name == '\0') { 22847c478bd9Sstevel@tonic-gate *status = NFSERR_ACCES; 22857c478bd9Sstevel@tonic-gate return; 22867c478bd9Sstevel@tonic-gate } 22877c478bd9Sstevel@tonic-gate 22887c478bd9Sstevel@tonic-gate vp = nfs_fhtovp(args->sla_from.da_fhandle, exi); 22897c478bd9Sstevel@tonic-gate if (vp == NULL) { 22907c478bd9Sstevel@tonic-gate *status = NFSERR_STALE; 22917c478bd9Sstevel@tonic-gate return; 22927c478bd9Sstevel@tonic-gate } 22937c478bd9Sstevel@tonic-gate 22945cb0d679SMarcel Telka if (rdonly(ro, vp)) { 22957c478bd9Sstevel@tonic-gate VN_RELE(vp); 22967c478bd9Sstevel@tonic-gate *status = NFSERR_ROFS; 22977c478bd9Sstevel@tonic-gate return; 22987c478bd9Sstevel@tonic-gate } 22997c478bd9Sstevel@tonic-gate 23007c478bd9Sstevel@tonic-gate error = sattr_to_vattr(args->sla_sa, &va); 23017c478bd9Sstevel@tonic-gate if (error) { 23027c478bd9Sstevel@tonic-gate VN_RELE(vp); 23037c478bd9Sstevel@tonic-gate *status = puterrno(error); 23047c478bd9Sstevel@tonic-gate return; 23057c478bd9Sstevel@tonic-gate } 23067c478bd9Sstevel@tonic-gate 23077c478bd9Sstevel@tonic-gate if (!(va.va_mask & AT_MODE)) { 23087c478bd9Sstevel@tonic-gate VN_RELE(vp); 23097c478bd9Sstevel@tonic-gate *status = NFSERR_INVAL; 23107c478bd9Sstevel@tonic-gate return; 23117c478bd9Sstevel@tonic-gate } 23127c478bd9Sstevel@tonic-gate 2313b89a8333Snatalie li - Sun Microsystems - Irvine United States ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 2314b89a8333Snatalie li - Sun Microsystems - Irvine United States name = nfscmd_convname(ca, exi, args->sla_tnm, 2315b89a8333Snatalie li - Sun Microsystems - Irvine United States NFSCMD_CONV_INBOUND, MAXPATHLEN); 2316b89a8333Snatalie li - Sun Microsystems - Irvine United States 2317b89a8333Snatalie li - Sun Microsystems - Irvine United States if (name == NULL) { 2318b89a8333Snatalie li - Sun Microsystems - Irvine United States *status = NFSERR_ACCES; 2319b89a8333Snatalie li - Sun Microsystems - Irvine United States return; 2320b89a8333Snatalie li - Sun Microsystems - Irvine United States } 2321b89a8333Snatalie li - Sun Microsystems - Irvine United States 23227c478bd9Sstevel@tonic-gate va.va_type = VLNK; 23237c478bd9Sstevel@tonic-gate va.va_mask |= AT_TYPE; 23247c478bd9Sstevel@tonic-gate 2325b89a8333Snatalie li - Sun Microsystems - Irvine United States error = VOP_SYMLINK(vp, args->sla_from.da_name, &va, name, cr, NULL, 0); 23267c478bd9Sstevel@tonic-gate 23277c478bd9Sstevel@tonic-gate /* 23287c478bd9Sstevel@tonic-gate * Force new data and metadata out to stable storage. 23297c478bd9Sstevel@tonic-gate */ 2330b89a8333Snatalie li - Sun Microsystems - Irvine United States lerror = VOP_LOOKUP(vp, args->sla_from.da_name, &svp, NULL, 0, 2331b89a8333Snatalie li - Sun Microsystems - Irvine United States NULL, cr, NULL, NULL, NULL); 23320a701b1eSRobert Gordon 23337c478bd9Sstevel@tonic-gate if (!lerror) { 2334da6c28aaSamw (void) VOP_FSYNC(svp, 0, cr, NULL); 23357c478bd9Sstevel@tonic-gate VN_RELE(svp); 23367c478bd9Sstevel@tonic-gate } 23377c478bd9Sstevel@tonic-gate 23387c478bd9Sstevel@tonic-gate /* 23397c478bd9Sstevel@tonic-gate * Force modified data and metadata out to stable storage. 23407c478bd9Sstevel@tonic-gate */ 2341da6c28aaSamw (void) VOP_FSYNC(vp, 0, cr, NULL); 23427c478bd9Sstevel@tonic-gate 23437c478bd9Sstevel@tonic-gate VN_RELE(vp); 23447c478bd9Sstevel@tonic-gate 23457c478bd9Sstevel@tonic-gate *status = puterrno(error); 2346b89a8333Snatalie li - Sun Microsystems - Irvine United States if (name != args->sla_tnm) 2347b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(name, MAXPATHLEN); 23487c478bd9Sstevel@tonic-gate 23497c478bd9Sstevel@tonic-gate } 235027242a7cSthurlow void * 23517c478bd9Sstevel@tonic-gate rfs_symlink_getfh(struct nfsslargs *args) 23527c478bd9Sstevel@tonic-gate { 23537c478bd9Sstevel@tonic-gate return (args->sla_from.da_fhandle); 23547c478bd9Sstevel@tonic-gate } 23557c478bd9Sstevel@tonic-gate 23567c478bd9Sstevel@tonic-gate /* 23577c478bd9Sstevel@tonic-gate * Make a directory. 23587c478bd9Sstevel@tonic-gate * Create a directory with the given name, parent directory, and attributes. 23597c478bd9Sstevel@tonic-gate * Returns a file handle and attributes for the new directory. 23607c478bd9Sstevel@tonic-gate */ 23615cb0d679SMarcel Telka /* ARGSUSED */ 23627c478bd9Sstevel@tonic-gate void 23637c478bd9Sstevel@tonic-gate rfs_mkdir(struct nfscreatargs *args, struct nfsdiropres *dr, 23645cb0d679SMarcel Telka struct exportinfo *exi, struct svc_req *req, cred_t *cr, bool_t ro) 23657c478bd9Sstevel@tonic-gate { 23667c478bd9Sstevel@tonic-gate int error; 23677c478bd9Sstevel@tonic-gate struct vattr va; 23687c478bd9Sstevel@tonic-gate vnode_t *dvp = NULL; 23697c478bd9Sstevel@tonic-gate vnode_t *vp; 23707c478bd9Sstevel@tonic-gate char *name = args->ca_da.da_name; 23717c478bd9Sstevel@tonic-gate 23727c478bd9Sstevel@tonic-gate /* 23737c478bd9Sstevel@tonic-gate * Disallow NULL paths 23747c478bd9Sstevel@tonic-gate */ 23757c478bd9Sstevel@tonic-gate if (name == NULL || *name == '\0') { 23767c478bd9Sstevel@tonic-gate dr->dr_status = NFSERR_ACCES; 23777c478bd9Sstevel@tonic-gate return; 23787c478bd9Sstevel@tonic-gate } 23797c478bd9Sstevel@tonic-gate 23807c478bd9Sstevel@tonic-gate vp = nfs_fhtovp(args->ca_da.da_fhandle, exi); 23817c478bd9Sstevel@tonic-gate if (vp == NULL) { 23827c478bd9Sstevel@tonic-gate dr->dr_status = NFSERR_STALE; 23837c478bd9Sstevel@tonic-gate return; 23847c478bd9Sstevel@tonic-gate } 23857c478bd9Sstevel@tonic-gate 23865cb0d679SMarcel Telka if (rdonly(ro, vp)) { 23877c478bd9Sstevel@tonic-gate VN_RELE(vp); 23887c478bd9Sstevel@tonic-gate dr->dr_status = NFSERR_ROFS; 23897c478bd9Sstevel@tonic-gate return; 23907c478bd9Sstevel@tonic-gate } 23917c478bd9Sstevel@tonic-gate 23927c478bd9Sstevel@tonic-gate error = sattr_to_vattr(args->ca_sa, &va); 23937c478bd9Sstevel@tonic-gate if (error) { 23947c478bd9Sstevel@tonic-gate VN_RELE(vp); 23957c478bd9Sstevel@tonic-gate dr->dr_status = puterrno(error); 23967c478bd9Sstevel@tonic-gate return; 23977c478bd9Sstevel@tonic-gate } 23987c478bd9Sstevel@tonic-gate 23997c478bd9Sstevel@tonic-gate if (!(va.va_mask & AT_MODE)) { 24007c478bd9Sstevel@tonic-gate VN_RELE(vp); 24017c478bd9Sstevel@tonic-gate dr->dr_status = NFSERR_INVAL; 24027c478bd9Sstevel@tonic-gate return; 24037c478bd9Sstevel@tonic-gate } 24047c478bd9Sstevel@tonic-gate 24057c478bd9Sstevel@tonic-gate va.va_type = VDIR; 24067c478bd9Sstevel@tonic-gate va.va_mask |= AT_TYPE; 24077c478bd9Sstevel@tonic-gate 2408da6c28aaSamw error = VOP_MKDIR(vp, name, &va, &dvp, cr, NULL, 0, NULL); 24097c478bd9Sstevel@tonic-gate 24107c478bd9Sstevel@tonic-gate if (!error) { 24117c478bd9Sstevel@tonic-gate /* 24127c478bd9Sstevel@tonic-gate * Attribtutes of the newly created directory should 24137c478bd9Sstevel@tonic-gate * be returned to the client. 24147c478bd9Sstevel@tonic-gate */ 24157c478bd9Sstevel@tonic-gate va.va_mask = AT_ALL; /* We want everything */ 2416da6c28aaSamw error = VOP_GETATTR(dvp, &va, 0, cr, NULL); 24170a701b1eSRobert Gordon 24187c478bd9Sstevel@tonic-gate /* check for overflows */ 24197c478bd9Sstevel@tonic-gate if (!error) { 24207c478bd9Sstevel@tonic-gate acl_perm(vp, exi, &va, cr); 24217c478bd9Sstevel@tonic-gate error = vattr_to_nattr(&va, &dr->dr_attr); 24227c478bd9Sstevel@tonic-gate if (!error) { 24237c478bd9Sstevel@tonic-gate error = makefh(&dr->dr_fhandle, dvp, exi); 24247c478bd9Sstevel@tonic-gate } 24257c478bd9Sstevel@tonic-gate } 24267c478bd9Sstevel@tonic-gate /* 24277c478bd9Sstevel@tonic-gate * Force new data and metadata out to stable storage. 24287c478bd9Sstevel@tonic-gate */ 2429da6c28aaSamw (void) VOP_FSYNC(dvp, 0, cr, NULL); 24307c478bd9Sstevel@tonic-gate VN_RELE(dvp); 24317c478bd9Sstevel@tonic-gate } 24327c478bd9Sstevel@tonic-gate 24337c478bd9Sstevel@tonic-gate /* 24347c478bd9Sstevel@tonic-gate * Force modified data and metadata out to stable storage. 24357c478bd9Sstevel@tonic-gate */ 2436da6c28aaSamw (void) VOP_FSYNC(vp, 0, cr, NULL); 24377c478bd9Sstevel@tonic-gate 24387c478bd9Sstevel@tonic-gate VN_RELE(vp); 24397c478bd9Sstevel@tonic-gate 24407c478bd9Sstevel@tonic-gate dr->dr_status = puterrno(error); 24417c478bd9Sstevel@tonic-gate 24427c478bd9Sstevel@tonic-gate } 244327242a7cSthurlow void * 24447c478bd9Sstevel@tonic-gate rfs_mkdir_getfh(struct nfscreatargs *args) 24457c478bd9Sstevel@tonic-gate { 24467c478bd9Sstevel@tonic-gate return (args->ca_da.da_fhandle); 24477c478bd9Sstevel@tonic-gate } 24487c478bd9Sstevel@tonic-gate 24497c478bd9Sstevel@tonic-gate /* 24507c478bd9Sstevel@tonic-gate * Remove a directory. 24517c478bd9Sstevel@tonic-gate * Remove the given directory name from the given parent directory. 24527c478bd9Sstevel@tonic-gate */ 24535cb0d679SMarcel Telka /* ARGSUSED */ 24547c478bd9Sstevel@tonic-gate void 24557c478bd9Sstevel@tonic-gate rfs_rmdir(struct nfsdiropargs *da, enum nfsstat *status, 24565cb0d679SMarcel Telka struct exportinfo *exi, struct svc_req *req, cred_t *cr, bool_t ro) 24577c478bd9Sstevel@tonic-gate { 24587c478bd9Sstevel@tonic-gate int error; 24597c478bd9Sstevel@tonic-gate vnode_t *vp; 24607c478bd9Sstevel@tonic-gate 24617c478bd9Sstevel@tonic-gate /* 24627c478bd9Sstevel@tonic-gate * Disallow NULL paths 24637c478bd9Sstevel@tonic-gate */ 24647c478bd9Sstevel@tonic-gate if (da->da_name == NULL || *da->da_name == '\0') { 24657c478bd9Sstevel@tonic-gate *status = NFSERR_ACCES; 24667c478bd9Sstevel@tonic-gate return; 24677c478bd9Sstevel@tonic-gate } 24687c478bd9Sstevel@tonic-gate 24697c478bd9Sstevel@tonic-gate vp = nfs_fhtovp(da->da_fhandle, exi); 24707c478bd9Sstevel@tonic-gate if (vp == NULL) { 24717c478bd9Sstevel@tonic-gate *status = NFSERR_STALE; 24727c478bd9Sstevel@tonic-gate return; 24737c478bd9Sstevel@tonic-gate } 24747c478bd9Sstevel@tonic-gate 24755cb0d679SMarcel Telka if (rdonly(ro, vp)) { 24767c478bd9Sstevel@tonic-gate VN_RELE(vp); 24777c478bd9Sstevel@tonic-gate *status = NFSERR_ROFS; 24787c478bd9Sstevel@tonic-gate return; 24797c478bd9Sstevel@tonic-gate } 24807c478bd9Sstevel@tonic-gate 24817c478bd9Sstevel@tonic-gate /* 2482ef1d0734SMarcel Telka * VOP_RMDIR takes a third argument (the current 24837c478bd9Sstevel@tonic-gate * directory of the process). That's because someone 24847c478bd9Sstevel@tonic-gate * wants to return EINVAL if one tries to remove ".". 24857c478bd9Sstevel@tonic-gate * Of course, NFS servers have no idea what their 24867c478bd9Sstevel@tonic-gate * clients' current directories are. We fake it by 24877c478bd9Sstevel@tonic-gate * supplying a vnode known to exist and illegal to 24887c478bd9Sstevel@tonic-gate * remove. 24897c478bd9Sstevel@tonic-gate */ 2490da6c28aaSamw error = VOP_RMDIR(vp, da->da_name, rootdir, cr, NULL, 0); 24917c478bd9Sstevel@tonic-gate 24927c478bd9Sstevel@tonic-gate /* 24937c478bd9Sstevel@tonic-gate * Force modified data and metadata out to stable storage. 24947c478bd9Sstevel@tonic-gate */ 2495da6c28aaSamw (void) VOP_FSYNC(vp, 0, cr, NULL); 24967c478bd9Sstevel@tonic-gate 24977c478bd9Sstevel@tonic-gate VN_RELE(vp); 24987c478bd9Sstevel@tonic-gate 24997c478bd9Sstevel@tonic-gate /* 25007c478bd9Sstevel@tonic-gate * System V defines rmdir to return EEXIST, not ENOTEMPTY, 25017c478bd9Sstevel@tonic-gate * if the directory is not empty. A System V NFS server 25027c478bd9Sstevel@tonic-gate * needs to map NFSERR_EXIST to NFSERR_NOTEMPTY to transmit 25037c478bd9Sstevel@tonic-gate * over the wire. 25047c478bd9Sstevel@tonic-gate */ 25057c478bd9Sstevel@tonic-gate if (error == EEXIST) 25067c478bd9Sstevel@tonic-gate *status = NFSERR_NOTEMPTY; 25077c478bd9Sstevel@tonic-gate else 25087c478bd9Sstevel@tonic-gate *status = puterrno(error); 25097c478bd9Sstevel@tonic-gate 25107c478bd9Sstevel@tonic-gate } 251127242a7cSthurlow void * 25127c478bd9Sstevel@tonic-gate rfs_rmdir_getfh(struct nfsdiropargs *da) 25137c478bd9Sstevel@tonic-gate { 25147c478bd9Sstevel@tonic-gate return (da->da_fhandle); 25157c478bd9Sstevel@tonic-gate } 25167c478bd9Sstevel@tonic-gate 25177c478bd9Sstevel@tonic-gate /* ARGSUSED */ 25187c478bd9Sstevel@tonic-gate void 25197c478bd9Sstevel@tonic-gate rfs_readdir(struct nfsrddirargs *rda, struct nfsrddirres *rd, 25205cb0d679SMarcel Telka struct exportinfo *exi, struct svc_req *req, cred_t *cr, bool_t ro) 25217c478bd9Sstevel@tonic-gate { 25227c478bd9Sstevel@tonic-gate int error; 25237c478bd9Sstevel@tonic-gate int iseof; 25247c478bd9Sstevel@tonic-gate struct iovec iov; 25257c478bd9Sstevel@tonic-gate struct uio uio; 25267c478bd9Sstevel@tonic-gate vnode_t *vp; 2527b89a8333Snatalie li - Sun Microsystems - Irvine United States char *ndata = NULL; 2528b89a8333Snatalie li - Sun Microsystems - Irvine United States struct sockaddr *ca; 2529b89a8333Snatalie li - Sun Microsystems - Irvine United States size_t nents; 2530b89a8333Snatalie li - Sun Microsystems - Irvine United States int ret; 25317c478bd9Sstevel@tonic-gate 25327c478bd9Sstevel@tonic-gate vp = nfs_fhtovp(&rda->rda_fh, exi); 25337c478bd9Sstevel@tonic-gate if (vp == NULL) { 25347c478bd9Sstevel@tonic-gate rd->rd_entries = NULL; 25357c478bd9Sstevel@tonic-gate rd->rd_status = NFSERR_STALE; 25367c478bd9Sstevel@tonic-gate return; 25377c478bd9Sstevel@tonic-gate } 25387c478bd9Sstevel@tonic-gate 25397c478bd9Sstevel@tonic-gate if (vp->v_type != VDIR) { 25407c478bd9Sstevel@tonic-gate VN_RELE(vp); 25417c478bd9Sstevel@tonic-gate rd->rd_entries = NULL; 25427c478bd9Sstevel@tonic-gate rd->rd_status = NFSERR_NOTDIR; 25437c478bd9Sstevel@tonic-gate return; 25447c478bd9Sstevel@tonic-gate } 25457c478bd9Sstevel@tonic-gate 25467c478bd9Sstevel@tonic-gate (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL); 25477c478bd9Sstevel@tonic-gate 2548da6c28aaSamw error = VOP_ACCESS(vp, VREAD, 0, cr, NULL); 25490a701b1eSRobert Gordon 25507c478bd9Sstevel@tonic-gate if (error) { 25517c478bd9Sstevel@tonic-gate rd->rd_entries = NULL; 25527c478bd9Sstevel@tonic-gate goto bad; 25537c478bd9Sstevel@tonic-gate } 25547c478bd9Sstevel@tonic-gate 25557c478bd9Sstevel@tonic-gate if (rda->rda_count == 0) { 25567c478bd9Sstevel@tonic-gate rd->rd_entries = NULL; 25577c478bd9Sstevel@tonic-gate rd->rd_size = 0; 25587c478bd9Sstevel@tonic-gate rd->rd_eof = FALSE; 25597c478bd9Sstevel@tonic-gate goto bad; 25607c478bd9Sstevel@tonic-gate } 25617c478bd9Sstevel@tonic-gate 25627c478bd9Sstevel@tonic-gate rda->rda_count = MIN(rda->rda_count, NFS_MAXDATA); 25637c478bd9Sstevel@tonic-gate 25647c478bd9Sstevel@tonic-gate /* 25657c478bd9Sstevel@tonic-gate * Allocate data for entries. This will be freed by rfs_rddirfree. 25667c478bd9Sstevel@tonic-gate */ 25677c478bd9Sstevel@tonic-gate rd->rd_bufsize = (uint_t)rda->rda_count; 25687c478bd9Sstevel@tonic-gate rd->rd_entries = kmem_alloc(rd->rd_bufsize, KM_SLEEP); 25697c478bd9Sstevel@tonic-gate 25707c478bd9Sstevel@tonic-gate /* 25717c478bd9Sstevel@tonic-gate * Set up io vector to read directory data 25727c478bd9Sstevel@tonic-gate */ 25737c478bd9Sstevel@tonic-gate iov.iov_base = (caddr_t)rd->rd_entries; 25747c478bd9Sstevel@tonic-gate iov.iov_len = rda->rda_count; 25757c478bd9Sstevel@tonic-gate uio.uio_iov = &iov; 25767c478bd9Sstevel@tonic-gate uio.uio_iovcnt = 1; 25777c478bd9Sstevel@tonic-gate uio.uio_segflg = UIO_SYSSPACE; 25787c478bd9Sstevel@tonic-gate uio.uio_extflg = UIO_COPY_CACHED; 25797c478bd9Sstevel@tonic-gate uio.uio_loffset = (offset_t)rda->rda_offset; 25807c478bd9Sstevel@tonic-gate uio.uio_resid = rda->rda_count; 25817c478bd9Sstevel@tonic-gate 25827c478bd9Sstevel@tonic-gate /* 25837c478bd9Sstevel@tonic-gate * read directory 25847c478bd9Sstevel@tonic-gate */ 2585da6c28aaSamw error = VOP_READDIR(vp, &uio, cr, &iseof, NULL, 0); 25867c478bd9Sstevel@tonic-gate 25877c478bd9Sstevel@tonic-gate /* 25887c478bd9Sstevel@tonic-gate * Clean up 25897c478bd9Sstevel@tonic-gate */ 25907c478bd9Sstevel@tonic-gate if (!error) { 25917c478bd9Sstevel@tonic-gate /* 25927c478bd9Sstevel@tonic-gate * set size and eof 25937c478bd9Sstevel@tonic-gate */ 25947c478bd9Sstevel@tonic-gate if (uio.uio_resid == rda->rda_count) { 25957c478bd9Sstevel@tonic-gate rd->rd_size = 0; 25967c478bd9Sstevel@tonic-gate rd->rd_eof = TRUE; 25977c478bd9Sstevel@tonic-gate } else { 25987c478bd9Sstevel@tonic-gate rd->rd_size = (uint32_t)(rda->rda_count - 25997c478bd9Sstevel@tonic-gate uio.uio_resid); 26007c478bd9Sstevel@tonic-gate rd->rd_eof = iseof ? TRUE : FALSE; 26017c478bd9Sstevel@tonic-gate } 26027c478bd9Sstevel@tonic-gate } 26037c478bd9Sstevel@tonic-gate 2604b89a8333Snatalie li - Sun Microsystems - Irvine United States ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 2605b89a8333Snatalie li - Sun Microsystems - Irvine United States nents = nfscmd_countents((char *)rd->rd_entries, rd->rd_size); 2606b89a8333Snatalie li - Sun Microsystems - Irvine United States ret = nfscmd_convdirplus(ca, exi, (char *)rd->rd_entries, nents, 2607b89a8333Snatalie li - Sun Microsystems - Irvine United States rda->rda_count, &ndata); 2608b89a8333Snatalie li - Sun Microsystems - Irvine United States 2609b89a8333Snatalie li - Sun Microsystems - Irvine United States if (ret != 0) { 2610b89a8333Snatalie li - Sun Microsystems - Irvine United States size_t dropbytes; 2611b89a8333Snatalie li - Sun Microsystems - Irvine United States /* 2612b89a8333Snatalie li - Sun Microsystems - Irvine United States * We had to drop one or more entries in order to fit 2613b89a8333Snatalie li - Sun Microsystems - Irvine United States * during the character conversion. We need to patch 2614b89a8333Snatalie li - Sun Microsystems - Irvine United States * up the size and eof info. 2615b89a8333Snatalie li - Sun Microsystems - Irvine United States */ 2616b89a8333Snatalie li - Sun Microsystems - Irvine United States if (rd->rd_eof) 2617b89a8333Snatalie li - Sun Microsystems - Irvine United States rd->rd_eof = FALSE; 2618b89a8333Snatalie li - Sun Microsystems - Irvine United States dropbytes = nfscmd_dropped_entrysize( 2619b89a8333Snatalie li - Sun Microsystems - Irvine United States (struct dirent64 *)rd->rd_entries, nents, ret); 2620b89a8333Snatalie li - Sun Microsystems - Irvine United States rd->rd_size -= dropbytes; 2621b89a8333Snatalie li - Sun Microsystems - Irvine United States } 2622b89a8333Snatalie li - Sun Microsystems - Irvine United States if (ndata == NULL) { 2623b89a8333Snatalie li - Sun Microsystems - Irvine United States ndata = (char *)rd->rd_entries; 2624b89a8333Snatalie li - Sun Microsystems - Irvine United States } else if (ndata != (char *)rd->rd_entries) { 2625b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(rd->rd_entries, rd->rd_bufsize); 2626b89a8333Snatalie li - Sun Microsystems - Irvine United States rd->rd_entries = (void *)ndata; 2627b89a8333Snatalie li - Sun Microsystems - Irvine United States rd->rd_bufsize = rda->rda_count; 2628b89a8333Snatalie li - Sun Microsystems - Irvine United States } 2629b89a8333Snatalie li - Sun Microsystems - Irvine United States 26307c478bd9Sstevel@tonic-gate bad: 26317c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL); 26327c478bd9Sstevel@tonic-gate 26337c478bd9Sstevel@tonic-gate #if 0 /* notyet */ 26347c478bd9Sstevel@tonic-gate /* 26357c478bd9Sstevel@tonic-gate * Don't do this. It causes local disk writes when just 26367c478bd9Sstevel@tonic-gate * reading the file and the overhead is deemed larger 26377c478bd9Sstevel@tonic-gate * than the benefit. 26387c478bd9Sstevel@tonic-gate */ 26397c478bd9Sstevel@tonic-gate /* 26407c478bd9Sstevel@tonic-gate * Force modified metadata out to stable storage. 26417c478bd9Sstevel@tonic-gate */ 2642da6c28aaSamw (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL); 26437c478bd9Sstevel@tonic-gate #endif 26447c478bd9Sstevel@tonic-gate 26457c478bd9Sstevel@tonic-gate VN_RELE(vp); 26467c478bd9Sstevel@tonic-gate 26477c478bd9Sstevel@tonic-gate rd->rd_status = puterrno(error); 26487c478bd9Sstevel@tonic-gate 26497c478bd9Sstevel@tonic-gate } 265027242a7cSthurlow void * 26517c478bd9Sstevel@tonic-gate rfs_readdir_getfh(struct nfsrddirargs *rda) 26527c478bd9Sstevel@tonic-gate { 26537c478bd9Sstevel@tonic-gate return (&rda->rda_fh); 26547c478bd9Sstevel@tonic-gate } 26557c478bd9Sstevel@tonic-gate void 26567c478bd9Sstevel@tonic-gate rfs_rddirfree(struct nfsrddirres *rd) 26577c478bd9Sstevel@tonic-gate { 26587c478bd9Sstevel@tonic-gate if (rd->rd_entries != NULL) 26597c478bd9Sstevel@tonic-gate kmem_free(rd->rd_entries, rd->rd_bufsize); 26607c478bd9Sstevel@tonic-gate } 26617c478bd9Sstevel@tonic-gate 26627c478bd9Sstevel@tonic-gate /* ARGSUSED */ 26637c478bd9Sstevel@tonic-gate void 26647c478bd9Sstevel@tonic-gate rfs_statfs(fhandle_t *fh, struct nfsstatfs *fs, struct exportinfo *exi, 26655cb0d679SMarcel Telka struct svc_req *req, cred_t *cr, bool_t ro) 26667c478bd9Sstevel@tonic-gate { 26677c478bd9Sstevel@tonic-gate int error; 26687c478bd9Sstevel@tonic-gate struct statvfs64 sb; 26697c478bd9Sstevel@tonic-gate vnode_t *vp; 26707c478bd9Sstevel@tonic-gate 26717c478bd9Sstevel@tonic-gate vp = nfs_fhtovp(fh, exi); 26727c478bd9Sstevel@tonic-gate if (vp == NULL) { 26737c478bd9Sstevel@tonic-gate fs->fs_status = NFSERR_STALE; 26747c478bd9Sstevel@tonic-gate return; 26757c478bd9Sstevel@tonic-gate } 26767c478bd9Sstevel@tonic-gate 26777c478bd9Sstevel@tonic-gate error = VFS_STATVFS(vp->v_vfsp, &sb); 26787c478bd9Sstevel@tonic-gate 26797c478bd9Sstevel@tonic-gate if (!error) { 26807c478bd9Sstevel@tonic-gate fs->fs_tsize = nfstsize(); 26817c478bd9Sstevel@tonic-gate fs->fs_bsize = sb.f_frsize; 26827c478bd9Sstevel@tonic-gate fs->fs_blocks = sb.f_blocks; 26837c478bd9Sstevel@tonic-gate fs->fs_bfree = sb.f_bfree; 26847c478bd9Sstevel@tonic-gate fs->fs_bavail = sb.f_bavail; 26857c478bd9Sstevel@tonic-gate } 26867c478bd9Sstevel@tonic-gate 26877c478bd9Sstevel@tonic-gate VN_RELE(vp); 26887c478bd9Sstevel@tonic-gate 26897c478bd9Sstevel@tonic-gate fs->fs_status = puterrno(error); 26907c478bd9Sstevel@tonic-gate 26917c478bd9Sstevel@tonic-gate } 269227242a7cSthurlow void * 26937c478bd9Sstevel@tonic-gate rfs_statfs_getfh(fhandle_t *fh) 26947c478bd9Sstevel@tonic-gate { 26957c478bd9Sstevel@tonic-gate return (fh); 26967c478bd9Sstevel@tonic-gate } 26977c478bd9Sstevel@tonic-gate 26987c478bd9Sstevel@tonic-gate static int 26997c478bd9Sstevel@tonic-gate sattr_to_vattr(struct nfssattr *sa, struct vattr *vap) 27007c478bd9Sstevel@tonic-gate { 27017c478bd9Sstevel@tonic-gate vap->va_mask = 0; 27027c478bd9Sstevel@tonic-gate 27037c478bd9Sstevel@tonic-gate /* 27047c478bd9Sstevel@tonic-gate * There was a sign extension bug in some VFS based systems 27057c478bd9Sstevel@tonic-gate * which stored the mode as a short. When it would get 27067c478bd9Sstevel@tonic-gate * assigned to a u_long, no sign extension would occur. 27077c478bd9Sstevel@tonic-gate * It needed to, but this wasn't noticed because sa_mode 27087c478bd9Sstevel@tonic-gate * would then get assigned back to the short, thus ignoring 27097c478bd9Sstevel@tonic-gate * the upper 16 bits of sa_mode. 27107c478bd9Sstevel@tonic-gate * 27117c478bd9Sstevel@tonic-gate * To make this implementation work for both broken 27127c478bd9Sstevel@tonic-gate * clients and good clients, we check for both versions 27137c478bd9Sstevel@tonic-gate * of the mode. 27147c478bd9Sstevel@tonic-gate */ 27157c478bd9Sstevel@tonic-gate if (sa->sa_mode != (uint32_t)((ushort_t)-1) && 27167c478bd9Sstevel@tonic-gate sa->sa_mode != (uint32_t)-1) { 27177c478bd9Sstevel@tonic-gate vap->va_mask |= AT_MODE; 27187c478bd9Sstevel@tonic-gate vap->va_mode = sa->sa_mode; 27197c478bd9Sstevel@tonic-gate } 27207c478bd9Sstevel@tonic-gate if (sa->sa_uid != (uint32_t)-1) { 27217c478bd9Sstevel@tonic-gate vap->va_mask |= AT_UID; 27227c478bd9Sstevel@tonic-gate vap->va_uid = sa->sa_uid; 27237c478bd9Sstevel@tonic-gate } 27247c478bd9Sstevel@tonic-gate if (sa->sa_gid != (uint32_t)-1) { 27257c478bd9Sstevel@tonic-gate vap->va_mask |= AT_GID; 27267c478bd9Sstevel@tonic-gate vap->va_gid = sa->sa_gid; 27277c478bd9Sstevel@tonic-gate } 27287c478bd9Sstevel@tonic-gate if (sa->sa_size != (uint32_t)-1) { 27297c478bd9Sstevel@tonic-gate vap->va_mask |= AT_SIZE; 27307c478bd9Sstevel@tonic-gate vap->va_size = sa->sa_size; 27317c478bd9Sstevel@tonic-gate } 27327c478bd9Sstevel@tonic-gate if (sa->sa_atime.tv_sec != (int32_t)-1 && 27337c478bd9Sstevel@tonic-gate sa->sa_atime.tv_usec != (int32_t)-1) { 27347c478bd9Sstevel@tonic-gate #ifndef _LP64 27357c478bd9Sstevel@tonic-gate /* return error if time overflow */ 27367c478bd9Sstevel@tonic-gate if (!NFS2_TIME_OK(sa->sa_atime.tv_sec)) 27377c478bd9Sstevel@tonic-gate return (EOVERFLOW); 27387c478bd9Sstevel@tonic-gate #endif 27397c478bd9Sstevel@tonic-gate vap->va_mask |= AT_ATIME; 27407c478bd9Sstevel@tonic-gate /* 27417c478bd9Sstevel@tonic-gate * nfs protocol defines times as unsigned so don't extend sign, 27427c478bd9Sstevel@tonic-gate * unless sysadmin set nfs_allow_preepoch_time. 27437c478bd9Sstevel@tonic-gate */ 27447c478bd9Sstevel@tonic-gate NFS_TIME_T_CONVERT(vap->va_atime.tv_sec, sa->sa_atime.tv_sec); 27457c478bd9Sstevel@tonic-gate vap->va_atime.tv_nsec = (uint32_t)(sa->sa_atime.tv_usec * 1000); 27467c478bd9Sstevel@tonic-gate } 27477c478bd9Sstevel@tonic-gate if (sa->sa_mtime.tv_sec != (int32_t)-1 && 27487c478bd9Sstevel@tonic-gate sa->sa_mtime.tv_usec != (int32_t)-1) { 27497c478bd9Sstevel@tonic-gate #ifndef _LP64 27507c478bd9Sstevel@tonic-gate /* return error if time overflow */ 27517c478bd9Sstevel@tonic-gate if (!NFS2_TIME_OK(sa->sa_mtime.tv_sec)) 27527c478bd9Sstevel@tonic-gate return (EOVERFLOW); 27537c478bd9Sstevel@tonic-gate #endif 27547c478bd9Sstevel@tonic-gate vap->va_mask |= AT_MTIME; 27557c478bd9Sstevel@tonic-gate /* 27567c478bd9Sstevel@tonic-gate * nfs protocol defines times as unsigned so don't extend sign, 27577c478bd9Sstevel@tonic-gate * unless sysadmin set nfs_allow_preepoch_time. 27587c478bd9Sstevel@tonic-gate */ 27597c478bd9Sstevel@tonic-gate NFS_TIME_T_CONVERT(vap->va_mtime.tv_sec, sa->sa_mtime.tv_sec); 27607c478bd9Sstevel@tonic-gate vap->va_mtime.tv_nsec = (uint32_t)(sa->sa_mtime.tv_usec * 1000); 27617c478bd9Sstevel@tonic-gate } 27627c478bd9Sstevel@tonic-gate return (0); 27637c478bd9Sstevel@tonic-gate } 27647c478bd9Sstevel@tonic-gate 27657c478bd9Sstevel@tonic-gate static enum nfsftype vt_to_nf[] = { 27667c478bd9Sstevel@tonic-gate 0, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, 0, 0, 0, NFSOC, 0 27677c478bd9Sstevel@tonic-gate }; 27687c478bd9Sstevel@tonic-gate 27697c478bd9Sstevel@tonic-gate /* 27707c478bd9Sstevel@tonic-gate * check the following fields for overflow: nodeid, size, and time. 27717c478bd9Sstevel@tonic-gate * There could be a problem when converting 64-bit LP64 fields 27727c478bd9Sstevel@tonic-gate * into 32-bit ones. Return an error if there is an overflow. 27737c478bd9Sstevel@tonic-gate */ 27747c478bd9Sstevel@tonic-gate int 27757c478bd9Sstevel@tonic-gate vattr_to_nattr(struct vattr *vap, struct nfsfattr *na) 27767c478bd9Sstevel@tonic-gate { 27777c478bd9Sstevel@tonic-gate ASSERT(vap->va_type >= VNON && vap->va_type <= VBAD); 27787c478bd9Sstevel@tonic-gate na->na_type = vt_to_nf[vap->va_type]; 27797c478bd9Sstevel@tonic-gate 27807c478bd9Sstevel@tonic-gate if (vap->va_mode == (unsigned short) -1) 27817c478bd9Sstevel@tonic-gate na->na_mode = (uint32_t)-1; 27827c478bd9Sstevel@tonic-gate else 27837c478bd9Sstevel@tonic-gate na->na_mode = VTTOIF(vap->va_type) | vap->va_mode; 27847c478bd9Sstevel@tonic-gate 27857c478bd9Sstevel@tonic-gate if (vap->va_uid == (unsigned short)(-1)) 27867c478bd9Sstevel@tonic-gate na->na_uid = (uint32_t)(-1); 27877c478bd9Sstevel@tonic-gate else if (vap->va_uid == UID_NOBODY) 27887c478bd9Sstevel@tonic-gate na->na_uid = (uint32_t)NFS_UID_NOBODY; 27897c478bd9Sstevel@tonic-gate else 27907c478bd9Sstevel@tonic-gate na->na_uid = vap->va_uid; 27917c478bd9Sstevel@tonic-gate 27927c478bd9Sstevel@tonic-gate if (vap->va_gid == (unsigned short)(-1)) 27937c478bd9Sstevel@tonic-gate na->na_gid = (uint32_t)-1; 27947c478bd9Sstevel@tonic-gate else if (vap->va_gid == GID_NOBODY) 27957c478bd9Sstevel@tonic-gate na->na_gid = (uint32_t)NFS_GID_NOBODY; 27967c478bd9Sstevel@tonic-gate else 27977c478bd9Sstevel@tonic-gate na->na_gid = vap->va_gid; 27987c478bd9Sstevel@tonic-gate 27997c478bd9Sstevel@tonic-gate /* 28007c478bd9Sstevel@tonic-gate * Do we need to check fsid for overflow? It is 64-bit in the 28017c478bd9Sstevel@tonic-gate * vattr, but are bigger than 32 bit values supported? 28027c478bd9Sstevel@tonic-gate */ 28037c478bd9Sstevel@tonic-gate na->na_fsid = vap->va_fsid; 28047c478bd9Sstevel@tonic-gate 28057c478bd9Sstevel@tonic-gate na->na_nodeid = vap->va_nodeid; 28067c478bd9Sstevel@tonic-gate 28077c478bd9Sstevel@tonic-gate /* 28087c478bd9Sstevel@tonic-gate * Check to make sure that the nodeid is representable over the 28097c478bd9Sstevel@tonic-gate * wire without losing bits. 28107c478bd9Sstevel@tonic-gate */ 28117c478bd9Sstevel@tonic-gate if (vap->va_nodeid != (u_longlong_t)na->na_nodeid) 28127c478bd9Sstevel@tonic-gate return (EFBIG); 28137c478bd9Sstevel@tonic-gate na->na_nlink = vap->va_nlink; 28147c478bd9Sstevel@tonic-gate 28157c478bd9Sstevel@tonic-gate /* 28167c478bd9Sstevel@tonic-gate * Check for big files here, instead of at the caller. See 28177c478bd9Sstevel@tonic-gate * comments in cstat for large special file explanation. 28187c478bd9Sstevel@tonic-gate */ 28197c478bd9Sstevel@tonic-gate if (vap->va_size > (u_longlong_t)MAXOFF32_T) { 28207c478bd9Sstevel@tonic-gate if ((vap->va_type == VREG) || (vap->va_type == VDIR)) 28217c478bd9Sstevel@tonic-gate return (EFBIG); 28227c478bd9Sstevel@tonic-gate if ((vap->va_type == VBLK) || (vap->va_type == VCHR)) { 28237c478bd9Sstevel@tonic-gate /* UNKNOWN_SIZE | OVERFLOW */ 28247c478bd9Sstevel@tonic-gate na->na_size = MAXOFF32_T; 28257c478bd9Sstevel@tonic-gate } else 28267c478bd9Sstevel@tonic-gate na->na_size = vap->va_size; 28277c478bd9Sstevel@tonic-gate } else 28287c478bd9Sstevel@tonic-gate na->na_size = vap->va_size; 28297c478bd9Sstevel@tonic-gate 28307c478bd9Sstevel@tonic-gate /* 28317c478bd9Sstevel@tonic-gate * If the vnode times overflow the 32-bit times that NFS2 28327c478bd9Sstevel@tonic-gate * uses on the wire then return an error. 28337c478bd9Sstevel@tonic-gate */ 28347c478bd9Sstevel@tonic-gate if (!NFS_VAP_TIME_OK(vap)) { 28357c478bd9Sstevel@tonic-gate return (EOVERFLOW); 28367c478bd9Sstevel@tonic-gate } 28377c478bd9Sstevel@tonic-gate na->na_atime.tv_sec = vap->va_atime.tv_sec; 28387c478bd9Sstevel@tonic-gate na->na_atime.tv_usec = vap->va_atime.tv_nsec / 1000; 28397c478bd9Sstevel@tonic-gate 28407c478bd9Sstevel@tonic-gate na->na_mtime.tv_sec = vap->va_mtime.tv_sec; 28417c478bd9Sstevel@tonic-gate na->na_mtime.tv_usec = vap->va_mtime.tv_nsec / 1000; 28427c478bd9Sstevel@tonic-gate 28437c478bd9Sstevel@tonic-gate na->na_ctime.tv_sec = vap->va_ctime.tv_sec; 28447c478bd9Sstevel@tonic-gate na->na_ctime.tv_usec = vap->va_ctime.tv_nsec / 1000; 28457c478bd9Sstevel@tonic-gate 28467c478bd9Sstevel@tonic-gate /* 28477c478bd9Sstevel@tonic-gate * If the dev_t will fit into 16 bits then compress 28487c478bd9Sstevel@tonic-gate * it, otherwise leave it alone. See comments in 28497c478bd9Sstevel@tonic-gate * nfs_client.c. 28507c478bd9Sstevel@tonic-gate */ 28517c478bd9Sstevel@tonic-gate if (getminor(vap->va_rdev) <= SO4_MAXMIN && 28527c478bd9Sstevel@tonic-gate getmajor(vap->va_rdev) <= SO4_MAXMAJ) 28537c478bd9Sstevel@tonic-gate na->na_rdev = nfsv2_cmpdev(vap->va_rdev); 28547c478bd9Sstevel@tonic-gate else 28557c478bd9Sstevel@tonic-gate (void) cmpldev(&na->na_rdev, vap->va_rdev); 28567c478bd9Sstevel@tonic-gate 28577c478bd9Sstevel@tonic-gate na->na_blocks = vap->va_nblocks; 28587c478bd9Sstevel@tonic-gate na->na_blocksize = vap->va_blksize; 28597c478bd9Sstevel@tonic-gate 28607c478bd9Sstevel@tonic-gate /* 28617c478bd9Sstevel@tonic-gate * This bit of ugliness is a *TEMPORARY* hack to preserve the 28627c478bd9Sstevel@tonic-gate * over-the-wire protocols for named-pipe vnodes. It remaps the 28637c478bd9Sstevel@tonic-gate * VFIFO type to the special over-the-wire type. (see note in nfs.h) 28647c478bd9Sstevel@tonic-gate * 28657c478bd9Sstevel@tonic-gate * BUYER BEWARE: 28667c478bd9Sstevel@tonic-gate * If you are porting the NFS to a non-Sun server, you probably 28677c478bd9Sstevel@tonic-gate * don't want to include the following block of code. The 28687c478bd9Sstevel@tonic-gate * over-the-wire special file types will be changing with the 28697c478bd9Sstevel@tonic-gate * NFS Protocol Revision. 28707c478bd9Sstevel@tonic-gate */ 28717c478bd9Sstevel@tonic-gate if (vap->va_type == VFIFO) 28727c478bd9Sstevel@tonic-gate NA_SETFIFO(na); 28737c478bd9Sstevel@tonic-gate return (0); 28747c478bd9Sstevel@tonic-gate } 28757c478bd9Sstevel@tonic-gate 28767c478bd9Sstevel@tonic-gate /* 28777c478bd9Sstevel@tonic-gate * acl v2 support: returns approximate permission. 28787c478bd9Sstevel@tonic-gate * default: returns minimal permission (more restrictive) 28797c478bd9Sstevel@tonic-gate * aclok: returns maximal permission (less restrictive) 28807c478bd9Sstevel@tonic-gate * This routine changes the permissions that are alaredy in *va. 28817c478bd9Sstevel@tonic-gate * If a file has minimal ACL, i.e. aclcnt == MIN_ACL_ENTRIES, 28827c478bd9Sstevel@tonic-gate * CLASS_OBJ is always the same as GROUP_OBJ entry. 28837c478bd9Sstevel@tonic-gate */ 28847c478bd9Sstevel@tonic-gate static void 28857c478bd9Sstevel@tonic-gate acl_perm(struct vnode *vp, struct exportinfo *exi, struct vattr *va, cred_t *cr) 28867c478bd9Sstevel@tonic-gate { 28877c478bd9Sstevel@tonic-gate vsecattr_t vsa; 28887c478bd9Sstevel@tonic-gate int aclcnt; 28897c478bd9Sstevel@tonic-gate aclent_t *aclentp; 28907c478bd9Sstevel@tonic-gate mode_t mask_perm; 28917c478bd9Sstevel@tonic-gate mode_t grp_perm; 28927c478bd9Sstevel@tonic-gate mode_t other_perm; 28937c478bd9Sstevel@tonic-gate mode_t other_orig; 28947c478bd9Sstevel@tonic-gate int error; 28957c478bd9Sstevel@tonic-gate 28967c478bd9Sstevel@tonic-gate /* dont care default acl */ 28977c478bd9Sstevel@tonic-gate vsa.vsa_mask = (VSA_ACL | VSA_ACLCNT); 2898da6c28aaSamw error = VOP_GETSECATTR(vp, &vsa, 0, cr, NULL); 28997c478bd9Sstevel@tonic-gate 29007c478bd9Sstevel@tonic-gate if (!error) { 29017c478bd9Sstevel@tonic-gate aclcnt = vsa.vsa_aclcnt; 29027c478bd9Sstevel@tonic-gate if (aclcnt > MIN_ACL_ENTRIES) { 29037c478bd9Sstevel@tonic-gate /* non-trivial ACL */ 29047c478bd9Sstevel@tonic-gate aclentp = vsa.vsa_aclentp; 29057c478bd9Sstevel@tonic-gate if (exi->exi_export.ex_flags & EX_ACLOK) { 29067c478bd9Sstevel@tonic-gate /* maximal permissions */ 29077c478bd9Sstevel@tonic-gate grp_perm = 0; 29087c478bd9Sstevel@tonic-gate other_perm = 0; 29097c478bd9Sstevel@tonic-gate for (; aclcnt > 0; aclcnt--, aclentp++) { 29107c478bd9Sstevel@tonic-gate switch (aclentp->a_type) { 29117c478bd9Sstevel@tonic-gate case USER_OBJ: 29127c478bd9Sstevel@tonic-gate break; 29137c478bd9Sstevel@tonic-gate case USER: 29147c478bd9Sstevel@tonic-gate grp_perm |= 29157c478bd9Sstevel@tonic-gate aclentp->a_perm << 3; 29167c478bd9Sstevel@tonic-gate other_perm |= aclentp->a_perm; 29177c478bd9Sstevel@tonic-gate break; 29187c478bd9Sstevel@tonic-gate case GROUP_OBJ: 29197c478bd9Sstevel@tonic-gate grp_perm |= 29207c478bd9Sstevel@tonic-gate aclentp->a_perm << 3; 29217c478bd9Sstevel@tonic-gate break; 29227c478bd9Sstevel@tonic-gate case GROUP: 29237c478bd9Sstevel@tonic-gate other_perm |= aclentp->a_perm; 29247c478bd9Sstevel@tonic-gate break; 29257c478bd9Sstevel@tonic-gate case OTHER_OBJ: 29267c478bd9Sstevel@tonic-gate other_orig = aclentp->a_perm; 29277c478bd9Sstevel@tonic-gate break; 29287c478bd9Sstevel@tonic-gate case CLASS_OBJ: 29297c478bd9Sstevel@tonic-gate mask_perm = aclentp->a_perm; 29307c478bd9Sstevel@tonic-gate break; 29317c478bd9Sstevel@tonic-gate default: 29327c478bd9Sstevel@tonic-gate break; 29337c478bd9Sstevel@tonic-gate } 29347c478bd9Sstevel@tonic-gate } 29357c478bd9Sstevel@tonic-gate grp_perm &= mask_perm << 3; 29367c478bd9Sstevel@tonic-gate other_perm &= mask_perm; 29377c478bd9Sstevel@tonic-gate other_perm |= other_orig; 29387c478bd9Sstevel@tonic-gate 29397c478bd9Sstevel@tonic-gate } else { 29407c478bd9Sstevel@tonic-gate /* minimal permissions */ 29417c478bd9Sstevel@tonic-gate grp_perm = 070; 29427c478bd9Sstevel@tonic-gate other_perm = 07; 29437c478bd9Sstevel@tonic-gate for (; aclcnt > 0; aclcnt--, aclentp++) { 29447c478bd9Sstevel@tonic-gate switch (aclentp->a_type) { 29457c478bd9Sstevel@tonic-gate case USER_OBJ: 29467c478bd9Sstevel@tonic-gate break; 29477c478bd9Sstevel@tonic-gate case USER: 29487c478bd9Sstevel@tonic-gate case CLASS_OBJ: 29497c478bd9Sstevel@tonic-gate grp_perm &= 29507c478bd9Sstevel@tonic-gate aclentp->a_perm << 3; 29517c478bd9Sstevel@tonic-gate other_perm &= 29527c478bd9Sstevel@tonic-gate aclentp->a_perm; 29537c478bd9Sstevel@tonic-gate break; 29547c478bd9Sstevel@tonic-gate case GROUP_OBJ: 29557c478bd9Sstevel@tonic-gate grp_perm &= 29567c478bd9Sstevel@tonic-gate aclentp->a_perm << 3; 29577c478bd9Sstevel@tonic-gate break; 29587c478bd9Sstevel@tonic-gate case GROUP: 29597c478bd9Sstevel@tonic-gate other_perm &= 29607c478bd9Sstevel@tonic-gate aclentp->a_perm; 29617c478bd9Sstevel@tonic-gate break; 29627c478bd9Sstevel@tonic-gate case OTHER_OBJ: 29637c478bd9Sstevel@tonic-gate other_perm &= 29647c478bd9Sstevel@tonic-gate aclentp->a_perm; 29657c478bd9Sstevel@tonic-gate break; 29667c478bd9Sstevel@tonic-gate default: 29677c478bd9Sstevel@tonic-gate break; 29687c478bd9Sstevel@tonic-gate } 29697c478bd9Sstevel@tonic-gate } 29707c478bd9Sstevel@tonic-gate } 29717c478bd9Sstevel@tonic-gate /* copy to va */ 29727c478bd9Sstevel@tonic-gate va->va_mode &= ~077; 29737c478bd9Sstevel@tonic-gate va->va_mode |= grp_perm | other_perm; 29747c478bd9Sstevel@tonic-gate } 29757c478bd9Sstevel@tonic-gate if (vsa.vsa_aclcnt) 29767c478bd9Sstevel@tonic-gate kmem_free(vsa.vsa_aclentp, 29777c478bd9Sstevel@tonic-gate vsa.vsa_aclcnt * sizeof (aclent_t)); 29787c478bd9Sstevel@tonic-gate } 29797c478bd9Sstevel@tonic-gate } 29807c478bd9Sstevel@tonic-gate 29817c478bd9Sstevel@tonic-gate void 29827c478bd9Sstevel@tonic-gate rfs_srvrinit(void) 29837c478bd9Sstevel@tonic-gate { 29847c478bd9Sstevel@tonic-gate mutex_init(&rfs_async_write_lock, NULL, MUTEX_DEFAULT, NULL); 2985cfae96c2Sjwahlig nfs2_srv_caller_id = fs_new_caller_id(); 29867c478bd9Sstevel@tonic-gate } 29877c478bd9Sstevel@tonic-gate 29887c478bd9Sstevel@tonic-gate void 29897c478bd9Sstevel@tonic-gate rfs_srvrfini(void) 29907c478bd9Sstevel@tonic-gate { 29917c478bd9Sstevel@tonic-gate mutex_destroy(&rfs_async_write_lock); 29927c478bd9Sstevel@tonic-gate } 29930a701b1eSRobert Gordon 29940a701b1eSRobert Gordon static int 29950a701b1eSRobert Gordon rdma_setup_read_data2(struct nfsreadargs *ra, struct nfsrdresult *rr) 29960a701b1eSRobert Gordon { 29970a701b1eSRobert Gordon struct clist *wcl; 2998f837ee4aSSiddheshwar Mahesh int wlist_len; 29990a701b1eSRobert Gordon uint32_t count = rr->rr_count; 30000a701b1eSRobert Gordon 30010a701b1eSRobert Gordon wcl = ra->ra_wlist; 30020a701b1eSRobert Gordon 3003f837ee4aSSiddheshwar Mahesh if (rdma_setup_read_chunks(wcl, count, &wlist_len) == FALSE) { 30040a701b1eSRobert Gordon return (FALSE); 30050a701b1eSRobert Gordon } 30060a701b1eSRobert Gordon 30070a701b1eSRobert Gordon wcl = ra->ra_wlist; 3008f837ee4aSSiddheshwar Mahesh rr->rr_ok.rrok_wlist_len = wlist_len; 30090a701b1eSRobert Gordon rr->rr_ok.rrok_wlist = wcl; 30100a701b1eSRobert Gordon 30110a701b1eSRobert Gordon return (TRUE); 30120a701b1eSRobert Gordon } 3013