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 */ 21f46abf18SMarcel Telka 227c478bd9Sstevel@tonic-gate /* 23f46abf18SMarcel Telka * Copyright 2015 Nexenta Systems, Inc. All rights reserved. 2435bbd688SKaren Rochford * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved. 25e36d7b11SSebastien Roy * Copyright (c) 2013 by Delphix. All rights reserved. 267c478bd9Sstevel@tonic-gate */ 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 297c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 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/errno.h> 407c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 417c478bd9Sstevel@tonic-gate #include <sys/statvfs.h> 427c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 437c478bd9Sstevel@tonic-gate #include <sys/dirent.h> 447c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 457c478bd9Sstevel@tonic-gate #include <sys/debug.h> 467c478bd9Sstevel@tonic-gate #include <sys/systeminfo.h> 477c478bd9Sstevel@tonic-gate #include <sys/flock.h> 487c478bd9Sstevel@tonic-gate #include <sys/nbmlock.h> 497c478bd9Sstevel@tonic-gate #include <sys/policy.h> 5003986916Sjarrett #include <sys/sdt.h> 517c478bd9Sstevel@tonic-gate 527c478bd9Sstevel@tonic-gate #include <rpc/types.h> 537c478bd9Sstevel@tonic-gate #include <rpc/auth.h> 547c478bd9Sstevel@tonic-gate #include <rpc/svc.h> 550a701b1eSRobert Gordon #include <rpc/rpc_rdma.h> 567c478bd9Sstevel@tonic-gate 577c478bd9Sstevel@tonic-gate #include <nfs/nfs.h> 587c478bd9Sstevel@tonic-gate #include <nfs/export.h> 59b89a8333Snatalie li - Sun Microsystems - Irvine United States #include <nfs/nfs_cmd.h> 607c478bd9Sstevel@tonic-gate 617c478bd9Sstevel@tonic-gate #include <sys/strsubr.h> 6203986916Sjarrett #include <sys/tsol/label.h> 6303986916Sjarrett #include <sys/tsol/tndb.h> 6403986916Sjarrett 655679c89fSjv227347 #include <sys/zone.h> 665679c89fSjv227347 6703986916Sjarrett #include <inet/ip.h> 6803986916Sjarrett #include <inet/ip6.h> 6903986916Sjarrett 707c478bd9Sstevel@tonic-gate /* 717c478bd9Sstevel@tonic-gate * These are the interface routines for the server side of the 727c478bd9Sstevel@tonic-gate * Network File System. See the NFS version 3 protocol specification 737c478bd9Sstevel@tonic-gate * for a description of this interface. 747c478bd9Sstevel@tonic-gate */ 757c478bd9Sstevel@tonic-gate 767c478bd9Sstevel@tonic-gate static writeverf3 write3verf; 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate static int sattr3_to_vattr(sattr3 *, struct vattr *); 797c478bd9Sstevel@tonic-gate static int vattr_to_fattr3(struct vattr *, fattr3 *); 807c478bd9Sstevel@tonic-gate static int vattr_to_wcc_attr(struct vattr *, wcc_attr *); 817c478bd9Sstevel@tonic-gate static void vattr_to_pre_op_attr(struct vattr *, pre_op_attr *); 827c478bd9Sstevel@tonic-gate static void vattr_to_wcc_data(struct vattr *, struct vattr *, wcc_data *); 830a701b1eSRobert Gordon static int rdma_setup_read_data3(READ3args *, READ3resok *); 847c478bd9Sstevel@tonic-gate 85c242f9a0Schunli zhang - Sun Microsystems - Irvine United States extern int nfs_loaned_buffers; 86c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 87cfae96c2Sjwahlig u_longlong_t nfs3_srv_caller_id; 88cfae96c2Sjwahlig 897c478bd9Sstevel@tonic-gate /* ARGSUSED */ 907c478bd9Sstevel@tonic-gate void 917c478bd9Sstevel@tonic-gate rfs3_getattr(GETATTR3args *args, GETATTR3res *resp, struct exportinfo *exi, 925cb0d679SMarcel Telka struct svc_req *req, cred_t *cr, bool_t ro) 937c478bd9Sstevel@tonic-gate { 947c478bd9Sstevel@tonic-gate int error; 957c478bd9Sstevel@tonic-gate vnode_t *vp; 967c478bd9Sstevel@tonic-gate struct vattr va; 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate vp = nfs3_fhtovp(&args->object, exi); 99e1adf50cSahl 100e1adf50cSahl DTRACE_NFSV3_4(op__getattr__start, struct svc_req *, req, 101e1adf50cSahl cred_t *, cr, vnode_t *, vp, GETATTR3args *, args); 102e1adf50cSahl 1037c478bd9Sstevel@tonic-gate if (vp == NULL) { 1047c478bd9Sstevel@tonic-gate error = ESTALE; 1057c478bd9Sstevel@tonic-gate goto out; 1067c478bd9Sstevel@tonic-gate } 1077c478bd9Sstevel@tonic-gate 1087c478bd9Sstevel@tonic-gate va.va_mask = AT_ALL; 1097c478bd9Sstevel@tonic-gate error = rfs4_delegated_getattr(vp, &va, 0, cr); 1107c478bd9Sstevel@tonic-gate 1117c478bd9Sstevel@tonic-gate if (!error) { 1122f172c55SRobert Thurlow /* Lie about the object type for a referral */ 1132f172c55SRobert Thurlow if (vn_is_nfs_reparse(vp, cr)) 1142f172c55SRobert Thurlow va.va_type = VLNK; 1152f172c55SRobert Thurlow 1167c478bd9Sstevel@tonic-gate /* overflow error if time or size is out of range */ 1177c478bd9Sstevel@tonic-gate error = vattr_to_fattr3(&va, &resp->resok.obj_attributes); 1187c478bd9Sstevel@tonic-gate if (error) 1197c478bd9Sstevel@tonic-gate goto out; 1207c478bd9Sstevel@tonic-gate resp->status = NFS3_OK; 121e1adf50cSahl 122e1adf50cSahl DTRACE_NFSV3_4(op__getattr__done, struct svc_req *, req, 123e1adf50cSahl cred_t *, cr, vnode_t *, vp, GETATTR3res *, resp); 124e1adf50cSahl 125e1adf50cSahl VN_RELE(vp); 126e1adf50cSahl 1277c478bd9Sstevel@tonic-gate return; 1287c478bd9Sstevel@tonic-gate } 1297c478bd9Sstevel@tonic-gate 1307c478bd9Sstevel@tonic-gate out: 1317c478bd9Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK) { 1327c478bd9Sstevel@tonic-gate curthread->t_flag &= ~T_WOULDBLOCK; 1337c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX; 1347c478bd9Sstevel@tonic-gate } else 1357c478bd9Sstevel@tonic-gate resp->status = puterrno3(error); 136e1adf50cSahl 137e1adf50cSahl DTRACE_NFSV3_4(op__getattr__done, struct svc_req *, req, 138e1adf50cSahl cred_t *, cr, vnode_t *, vp, GETATTR3res *, resp); 139e1adf50cSahl 140e1adf50cSahl if (vp != NULL) 141e1adf50cSahl VN_RELE(vp); 1427c478bd9Sstevel@tonic-gate } 1437c478bd9Sstevel@tonic-gate 14427242a7cSthurlow void * 1457c478bd9Sstevel@tonic-gate rfs3_getattr_getfh(GETATTR3args *args) 1467c478bd9Sstevel@tonic-gate { 1477c478bd9Sstevel@tonic-gate 14827242a7cSthurlow return (&args->object); 1497c478bd9Sstevel@tonic-gate } 1507c478bd9Sstevel@tonic-gate 1517c478bd9Sstevel@tonic-gate void 1527c478bd9Sstevel@tonic-gate rfs3_setattr(SETATTR3args *args, SETATTR3res *resp, struct exportinfo *exi, 1535cb0d679SMarcel Telka struct svc_req *req, cred_t *cr, bool_t ro) 1547c478bd9Sstevel@tonic-gate { 1557c478bd9Sstevel@tonic-gate int error; 1567c478bd9Sstevel@tonic-gate vnode_t *vp; 1577c478bd9Sstevel@tonic-gate struct vattr *bvap; 1587c478bd9Sstevel@tonic-gate struct vattr bva; 1597c478bd9Sstevel@tonic-gate struct vattr *avap; 1607c478bd9Sstevel@tonic-gate struct vattr ava; 1617c478bd9Sstevel@tonic-gate int flag; 1627c478bd9Sstevel@tonic-gate int in_crit = 0; 1637c478bd9Sstevel@tonic-gate struct flock64 bf; 164cfae96c2Sjwahlig caller_context_t ct; 1657c478bd9Sstevel@tonic-gate 1667c478bd9Sstevel@tonic-gate bvap = NULL; 1677c478bd9Sstevel@tonic-gate avap = NULL; 1687c478bd9Sstevel@tonic-gate 1697c478bd9Sstevel@tonic-gate vp = nfs3_fhtovp(&args->object, exi); 170e1adf50cSahl 171e1adf50cSahl DTRACE_NFSV3_4(op__setattr__start, struct svc_req *, req, 172e1adf50cSahl cred_t *, cr, vnode_t *, vp, SETATTR3args *, args); 173e1adf50cSahl 1747c478bd9Sstevel@tonic-gate if (vp == NULL) { 1757c478bd9Sstevel@tonic-gate error = ESTALE; 1767c478bd9Sstevel@tonic-gate goto out; 1777c478bd9Sstevel@tonic-gate } 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate error = sattr3_to_vattr(&args->new_attributes, &ava); 1807c478bd9Sstevel@tonic-gate if (error) 1817c478bd9Sstevel@tonic-gate goto out; 1827c478bd9Sstevel@tonic-gate 18303986916Sjarrett if (is_system_labeled()) { 18403986916Sjarrett bslabel_t *clabel = req->rq_label; 18503986916Sjarrett 18603986916Sjarrett ASSERT(clabel != NULL); 18703986916Sjarrett DTRACE_PROBE2(tx__rfs3__log__info__opsetattr__clabel, char *, 18803986916Sjarrett "got client label from request(1)", struct svc_req *, req); 18903986916Sjarrett 19003986916Sjarrett if (!blequal(&l_admin_low->tsl_label, clabel)) { 191bd6f1640SJarrett Lu if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK, 192bd6f1640SJarrett Lu exi)) { 19303986916Sjarrett resp->status = NFS3ERR_ACCES; 19403986916Sjarrett goto out1; 19503986916Sjarrett } 19603986916Sjarrett } 19703986916Sjarrett } 19803986916Sjarrett 1997c478bd9Sstevel@tonic-gate /* 2007c478bd9Sstevel@tonic-gate * We need to specially handle size changes because of 2017c478bd9Sstevel@tonic-gate * possible conflicting NBMAND locks. Get into critical 2027c478bd9Sstevel@tonic-gate * region before VOP_GETATTR, so the size attribute is 2037c478bd9Sstevel@tonic-gate * valid when checking conflicts. 2047c478bd9Sstevel@tonic-gate * 2057c478bd9Sstevel@tonic-gate * Also, check to see if the v4 side of the server has 2067c478bd9Sstevel@tonic-gate * delegated this file. If so, then we return JUKEBOX to 2077c478bd9Sstevel@tonic-gate * allow the client to retrasmit its request. 2087c478bd9Sstevel@tonic-gate */ 2097c478bd9Sstevel@tonic-gate if (vp->v_type == VREG && (ava.va_mask & AT_SIZE)) { 2107c478bd9Sstevel@tonic-gate if (nbl_need_check(vp)) { 2117c478bd9Sstevel@tonic-gate nbl_start_crit(vp, RW_READER); 2127c478bd9Sstevel@tonic-gate in_crit = 1; 2137c478bd9Sstevel@tonic-gate } 2147c478bd9Sstevel@tonic-gate } 2157c478bd9Sstevel@tonic-gate 2167c478bd9Sstevel@tonic-gate bva.va_mask = AT_ALL; 2177c478bd9Sstevel@tonic-gate error = rfs4_delegated_getattr(vp, &bva, 0, cr); 2187c478bd9Sstevel@tonic-gate 2197c478bd9Sstevel@tonic-gate /* 2207c478bd9Sstevel@tonic-gate * If we can't get the attributes, then we can't do the 2217c478bd9Sstevel@tonic-gate * right access checking. So, we'll fail the request. 2227c478bd9Sstevel@tonic-gate */ 2237c478bd9Sstevel@tonic-gate if (error) 2247c478bd9Sstevel@tonic-gate goto out; 2257c478bd9Sstevel@tonic-gate 2267c478bd9Sstevel@tonic-gate bvap = &bva; 2277c478bd9Sstevel@tonic-gate 2285cb0d679SMarcel Telka if (rdonly(ro, vp)) { 2297c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_ROFS; 2307c478bd9Sstevel@tonic-gate goto out1; 2317c478bd9Sstevel@tonic-gate } 2327c478bd9Sstevel@tonic-gate 2337c478bd9Sstevel@tonic-gate if (args->guard.check && 2347c478bd9Sstevel@tonic-gate (args->guard.obj_ctime.seconds != bva.va_ctime.tv_sec || 2357c478bd9Sstevel@tonic-gate args->guard.obj_ctime.nseconds != bva.va_ctime.tv_nsec)) { 2367c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_NOT_SYNC; 2377c478bd9Sstevel@tonic-gate goto out1; 2387c478bd9Sstevel@tonic-gate } 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate if (args->new_attributes.mtime.set_it == SET_TO_CLIENT_TIME) 2417c478bd9Sstevel@tonic-gate flag = ATTR_UTIME; 2427c478bd9Sstevel@tonic-gate else 2437c478bd9Sstevel@tonic-gate flag = 0; 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate /* 2467c478bd9Sstevel@tonic-gate * If the filesystem is exported with nosuid, then mask off 2477c478bd9Sstevel@tonic-gate * the setuid and setgid bits. 2487c478bd9Sstevel@tonic-gate */ 2497c478bd9Sstevel@tonic-gate if ((ava.va_mask & AT_MODE) && vp->v_type == VREG && 2507c478bd9Sstevel@tonic-gate (exi->exi_export.ex_flags & EX_NOSUID)) 2517c478bd9Sstevel@tonic-gate ava.va_mode &= ~(VSUID | VSGID); 2527c478bd9Sstevel@tonic-gate 253cfae96c2Sjwahlig ct.cc_sysid = 0; 254cfae96c2Sjwahlig ct.cc_pid = 0; 255cfae96c2Sjwahlig ct.cc_caller_id = nfs3_srv_caller_id; 256cfae96c2Sjwahlig ct.cc_flags = CC_DONTBLOCK; 257cfae96c2Sjwahlig 2587c478bd9Sstevel@tonic-gate /* 2597c478bd9Sstevel@tonic-gate * We need to specially handle size changes because it is 2607c478bd9Sstevel@tonic-gate * possible for the client to create a file with modes 2617c478bd9Sstevel@tonic-gate * which indicate read-only, but with the file opened for 2627c478bd9Sstevel@tonic-gate * writing. If the client then tries to set the size of 2637c478bd9Sstevel@tonic-gate * the file, then the normal access checking done in 2647c478bd9Sstevel@tonic-gate * VOP_SETATTR would prevent the client from doing so, 2657c478bd9Sstevel@tonic-gate * although it should be legal for it to do so. To get 2667c478bd9Sstevel@tonic-gate * around this, we do the access checking for ourselves 2677c478bd9Sstevel@tonic-gate * and then use VOP_SPACE which doesn't do the access 2687c478bd9Sstevel@tonic-gate * checking which VOP_SETATTR does. VOP_SPACE can only 2697c478bd9Sstevel@tonic-gate * operate on VREG files, let VOP_SETATTR handle the other 2707c478bd9Sstevel@tonic-gate * extremely rare cases. 2717c478bd9Sstevel@tonic-gate * Also the client should not be allowed to change the 2727c478bd9Sstevel@tonic-gate * size of the file if there is a conflicting non-blocking 2737c478bd9Sstevel@tonic-gate * mandatory lock in the region the change. 2747c478bd9Sstevel@tonic-gate */ 2757c478bd9Sstevel@tonic-gate if (vp->v_type == VREG && (ava.va_mask & AT_SIZE)) { 2767c478bd9Sstevel@tonic-gate if (in_crit) { 2777c478bd9Sstevel@tonic-gate u_offset_t offset; 2787c478bd9Sstevel@tonic-gate ssize_t length; 2797c478bd9Sstevel@tonic-gate 2807c478bd9Sstevel@tonic-gate if (ava.va_size < bva.va_size) { 2817c478bd9Sstevel@tonic-gate offset = ava.va_size; 2827c478bd9Sstevel@tonic-gate length = bva.va_size - ava.va_size; 2837c478bd9Sstevel@tonic-gate } else { 2847c478bd9Sstevel@tonic-gate offset = bva.va_size; 2857c478bd9Sstevel@tonic-gate length = ava.va_size - bva.va_size; 2867c478bd9Sstevel@tonic-gate } 287da6c28aaSamw if (nbl_conflict(vp, NBL_WRITE, offset, length, 0, 288da6c28aaSamw NULL)) { 2897c478bd9Sstevel@tonic-gate error = EACCES; 2907c478bd9Sstevel@tonic-gate goto out; 2917c478bd9Sstevel@tonic-gate } 2927c478bd9Sstevel@tonic-gate } 2937c478bd9Sstevel@tonic-gate 2947c478bd9Sstevel@tonic-gate if (crgetuid(cr) == bva.va_uid && ava.va_size != bva.va_size) { 2957c478bd9Sstevel@tonic-gate ava.va_mask &= ~AT_SIZE; 2967c478bd9Sstevel@tonic-gate bf.l_type = F_WRLCK; 2977c478bd9Sstevel@tonic-gate bf.l_whence = 0; 2987c478bd9Sstevel@tonic-gate bf.l_start = (off64_t)ava.va_size; 2997c478bd9Sstevel@tonic-gate bf.l_len = 0; 3007c478bd9Sstevel@tonic-gate bf.l_sysid = 0; 3017c478bd9Sstevel@tonic-gate bf.l_pid = 0; 3027c478bd9Sstevel@tonic-gate error = VOP_SPACE(vp, F_FREESP, &bf, FWRITE, 303cfae96c2Sjwahlig (offset_t)ava.va_size, cr, &ct); 3047c478bd9Sstevel@tonic-gate } 3057c478bd9Sstevel@tonic-gate } 3067c478bd9Sstevel@tonic-gate 3077c478bd9Sstevel@tonic-gate if (!error && ava.va_mask) 308cfae96c2Sjwahlig error = VOP_SETATTR(vp, &ava, flag, cr, &ct); 309cfae96c2Sjwahlig 310cfae96c2Sjwahlig /* check if a monitor detected a delegation conflict */ 311cfae96c2Sjwahlig if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) { 312cfae96c2Sjwahlig resp->status = NFS3ERR_JUKEBOX; 313cfae96c2Sjwahlig goto out1; 314cfae96c2Sjwahlig } 3157c478bd9Sstevel@tonic-gate 3167c478bd9Sstevel@tonic-gate ava.va_mask = AT_ALL; 3177c478bd9Sstevel@tonic-gate avap = rfs4_delegated_getattr(vp, &ava, 0, cr) ? NULL : &ava; 3187c478bd9Sstevel@tonic-gate 3197c478bd9Sstevel@tonic-gate /* 3207c478bd9Sstevel@tonic-gate * Force modified metadata out to stable storage. 3217c478bd9Sstevel@tonic-gate */ 322cfae96c2Sjwahlig (void) VOP_FSYNC(vp, FNODSYNC, cr, &ct); 3237c478bd9Sstevel@tonic-gate 3247c478bd9Sstevel@tonic-gate if (error) 3257c478bd9Sstevel@tonic-gate goto out; 3267c478bd9Sstevel@tonic-gate 3277c478bd9Sstevel@tonic-gate if (in_crit) 3287c478bd9Sstevel@tonic-gate nbl_end_crit(vp); 3297c478bd9Sstevel@tonic-gate 3307c478bd9Sstevel@tonic-gate resp->status = NFS3_OK; 3317c478bd9Sstevel@tonic-gate vattr_to_wcc_data(bvap, avap, &resp->resok.obj_wcc); 332e1adf50cSahl 333e1adf50cSahl DTRACE_NFSV3_4(op__setattr__done, struct svc_req *, req, 334e1adf50cSahl cred_t *, cr, vnode_t *, vp, SETATTR3res *, resp); 335e1adf50cSahl 336e1adf50cSahl VN_RELE(vp); 337e1adf50cSahl 3387c478bd9Sstevel@tonic-gate return; 3397c478bd9Sstevel@tonic-gate 3407c478bd9Sstevel@tonic-gate out: 3417c478bd9Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK) { 3427c478bd9Sstevel@tonic-gate curthread->t_flag &= ~T_WOULDBLOCK; 3437c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX; 3447c478bd9Sstevel@tonic-gate } else 3457c478bd9Sstevel@tonic-gate resp->status = puterrno3(error); 3467c478bd9Sstevel@tonic-gate out1: 347e1adf50cSahl DTRACE_NFSV3_4(op__setattr__done, struct svc_req *, req, 348e1adf50cSahl cred_t *, cr, vnode_t *, vp, SETATTR3res *, resp); 349e1adf50cSahl 3507c478bd9Sstevel@tonic-gate if (vp != NULL) { 3517c478bd9Sstevel@tonic-gate if (in_crit) 3527c478bd9Sstevel@tonic-gate nbl_end_crit(vp); 3537c478bd9Sstevel@tonic-gate VN_RELE(vp); 3547c478bd9Sstevel@tonic-gate } 3557c478bd9Sstevel@tonic-gate vattr_to_wcc_data(bvap, avap, &resp->resfail.obj_wcc); 3567c478bd9Sstevel@tonic-gate } 3577c478bd9Sstevel@tonic-gate 35827242a7cSthurlow void * 3597c478bd9Sstevel@tonic-gate rfs3_setattr_getfh(SETATTR3args *args) 3607c478bd9Sstevel@tonic-gate { 3617c478bd9Sstevel@tonic-gate 36227242a7cSthurlow return (&args->object); 3637c478bd9Sstevel@tonic-gate } 3647c478bd9Sstevel@tonic-gate 3657c478bd9Sstevel@tonic-gate /* ARGSUSED */ 3667c478bd9Sstevel@tonic-gate void 3677c478bd9Sstevel@tonic-gate rfs3_lookup(LOOKUP3args *args, LOOKUP3res *resp, struct exportinfo *exi, 3685cb0d679SMarcel Telka struct svc_req *req, cred_t *cr, bool_t ro) 3697c478bd9Sstevel@tonic-gate { 3707c478bd9Sstevel@tonic-gate int error; 3717c478bd9Sstevel@tonic-gate vnode_t *vp; 3727c478bd9Sstevel@tonic-gate vnode_t *dvp; 3737c478bd9Sstevel@tonic-gate struct vattr *vap; 3747c478bd9Sstevel@tonic-gate struct vattr va; 3757c478bd9Sstevel@tonic-gate struct vattr *dvap; 3767c478bd9Sstevel@tonic-gate struct vattr dva; 3777c478bd9Sstevel@tonic-gate nfs_fh3 *fhp; 3787c478bd9Sstevel@tonic-gate struct sec_ol sec = {0, 0}; 3797c478bd9Sstevel@tonic-gate bool_t publicfh_flag = FALSE, auth_weak = FALSE; 380b89a8333Snatalie li - Sun Microsystems - Irvine United States struct sockaddr *ca; 381b89a8333Snatalie li - Sun Microsystems - Irvine United States char *name = NULL; 3827c478bd9Sstevel@tonic-gate 3837c478bd9Sstevel@tonic-gate dvap = NULL; 3847c478bd9Sstevel@tonic-gate 3857c478bd9Sstevel@tonic-gate /* 3867c478bd9Sstevel@tonic-gate * Allow lookups from the root - the default 3877c478bd9Sstevel@tonic-gate * location of the public filehandle. 3887c478bd9Sstevel@tonic-gate */ 3897c478bd9Sstevel@tonic-gate if (exi != NULL && (exi->exi_export.ex_flags & EX_PUBLIC)) { 3907c478bd9Sstevel@tonic-gate dvp = rootdir; 3917c478bd9Sstevel@tonic-gate VN_HOLD(dvp); 392e1adf50cSahl 393e1adf50cSahl DTRACE_NFSV3_4(op__lookup__start, struct svc_req *, req, 394e1adf50cSahl cred_t *, cr, vnode_t *, dvp, LOOKUP3args *, args); 3957c478bd9Sstevel@tonic-gate } else { 39627242a7cSthurlow dvp = nfs3_fhtovp(&args->what.dir, exi); 397e1adf50cSahl 398e1adf50cSahl DTRACE_NFSV3_4(op__lookup__start, struct svc_req *, req, 399e1adf50cSahl cred_t *, cr, vnode_t *, dvp, LOOKUP3args *, args); 400e1adf50cSahl 4017c478bd9Sstevel@tonic-gate if (dvp == NULL) { 4027c478bd9Sstevel@tonic-gate error = ESTALE; 4037c478bd9Sstevel@tonic-gate goto out; 4047c478bd9Sstevel@tonic-gate } 4057c478bd9Sstevel@tonic-gate } 4067c478bd9Sstevel@tonic-gate 4077c478bd9Sstevel@tonic-gate dva.va_mask = AT_ALL; 408da6c28aaSamw dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva; 4097c478bd9Sstevel@tonic-gate 4107c478bd9Sstevel@tonic-gate if (args->what.name == nfs3nametoolong) { 4117c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_NAMETOOLONG; 4127c478bd9Sstevel@tonic-gate goto out1; 4137c478bd9Sstevel@tonic-gate } 4147c478bd9Sstevel@tonic-gate 4157c478bd9Sstevel@tonic-gate if (args->what.name == NULL || *(args->what.name) == '\0') { 4167c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_ACCES; 4177c478bd9Sstevel@tonic-gate goto out1; 4187c478bd9Sstevel@tonic-gate } 4197c478bd9Sstevel@tonic-gate 42027242a7cSthurlow fhp = &args->what.dir; 4217c478bd9Sstevel@tonic-gate if (strcmp(args->what.name, "..") == 0 && 42227242a7cSthurlow EQFID(&exi->exi_fid, FH3TOFIDP(fhp))) { 4237c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_NOENT; 4247c478bd9Sstevel@tonic-gate goto out1; 4257c478bd9Sstevel@tonic-gate } 4267c478bd9Sstevel@tonic-gate 427b89a8333Snatalie li - Sun Microsystems - Irvine United States ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 428b89a8333Snatalie li - Sun Microsystems - Irvine United States name = nfscmd_convname(ca, exi, args->what.name, 429b89a8333Snatalie li - Sun Microsystems - Irvine United States NFSCMD_CONV_INBOUND, MAXPATHLEN + 1); 430b89a8333Snatalie li - Sun Microsystems - Irvine United States 431b89a8333Snatalie li - Sun Microsystems - Irvine United States if (name == NULL) { 432b89a8333Snatalie li - Sun Microsystems - Irvine United States resp->status = NFS3ERR_ACCES; 433b89a8333Snatalie li - Sun Microsystems - Irvine United States goto out1; 434b89a8333Snatalie li - Sun Microsystems - Irvine United States } 435b89a8333Snatalie li - Sun Microsystems - Irvine United States 4367c478bd9Sstevel@tonic-gate /* 4377c478bd9Sstevel@tonic-gate * If the public filehandle is used then allow 4387c478bd9Sstevel@tonic-gate * a multi-component lookup 4397c478bd9Sstevel@tonic-gate */ 44027242a7cSthurlow if (PUBLIC_FH3(&args->what.dir)) { 4417c478bd9Sstevel@tonic-gate publicfh_flag = TRUE; 442b89a8333Snatalie li - Sun Microsystems - Irvine United States error = rfs_publicfh_mclookup(name, dvp, cr, &vp, 443596bc239SMarcel Telka &exi, &sec); 444596bc239SMarcel Telka if (error && exi != NULL) 445596bc239SMarcel Telka exi_rele(exi); /* See comment below Re: publicfh_flag */ 44603986916Sjarrett /* 44703986916Sjarrett * Since WebNFS may bypass MOUNT, we need to ensure this 44803986916Sjarrett * request didn't come from an unlabeled admin_low client. 44903986916Sjarrett */ 45003986916Sjarrett if (is_system_labeled() && error == 0) { 45103986916Sjarrett int addr_type; 45203986916Sjarrett void *ipaddr; 45303986916Sjarrett tsol_tpc_t *tp; 45403986916Sjarrett 45503986916Sjarrett if (ca->sa_family == AF_INET) { 45603986916Sjarrett addr_type = IPV4_VERSION; 45703986916Sjarrett ipaddr = &((struct sockaddr_in *)ca)->sin_addr; 45803986916Sjarrett } else if (ca->sa_family == AF_INET6) { 45903986916Sjarrett addr_type = IPV6_VERSION; 46003986916Sjarrett ipaddr = &((struct sockaddr_in6 *) 46103986916Sjarrett ca)->sin6_addr; 46203986916Sjarrett } 46303986916Sjarrett tp = find_tpc(ipaddr, addr_type, B_FALSE); 46403986916Sjarrett if (tp == NULL || tp->tpc_tp.tp_doi != 46503986916Sjarrett l_admin_low->tsl_doi || tp->tpc_tp.host_type != 46603986916Sjarrett SUN_CIPSO) { 467596bc239SMarcel Telka if (exi != NULL) 468596bc239SMarcel Telka exi_rele(exi); 46903986916Sjarrett VN_RELE(vp); 470f46abf18SMarcel Telka error = EACCES; 47103986916Sjarrett } 47203986916Sjarrett if (tp != NULL) 47303986916Sjarrett TPC_RELE(tp); 47403986916Sjarrett } 4757c478bd9Sstevel@tonic-gate } else { 476b89a8333Snatalie li - Sun Microsystems - Irvine United States error = VOP_LOOKUP(dvp, name, &vp, 477da6c28aaSamw NULL, 0, NULL, cr, NULL, NULL, NULL); 4787c478bd9Sstevel@tonic-gate } 4797c478bd9Sstevel@tonic-gate 480b89a8333Snatalie li - Sun Microsystems - Irvine United States if (name != args->what.name) 481b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(name, MAXPATHLEN + 1); 482b89a8333Snatalie li - Sun Microsystems - Irvine United States 48303986916Sjarrett if (is_system_labeled() && error == 0) { 48403986916Sjarrett bslabel_t *clabel = req->rq_label; 48503986916Sjarrett 48603986916Sjarrett ASSERT(clabel != NULL); 48703986916Sjarrett DTRACE_PROBE2(tx__rfs3__log__info__oplookup__clabel, char *, 48803986916Sjarrett "got client label from request(1)", struct svc_req *, req); 48903986916Sjarrett 49003986916Sjarrett if (!blequal(&l_admin_low->tsl_label, clabel)) { 49103986916Sjarrett if (!do_rfs_label_check(clabel, dvp, 492bd6f1640SJarrett Lu DOMINANCE_CHECK, exi)) { 493596bc239SMarcel Telka if (publicfh_flag && exi != NULL) 494596bc239SMarcel Telka exi_rele(exi); 49503986916Sjarrett VN_RELE(vp); 496f46abf18SMarcel Telka error = EACCES; 49703986916Sjarrett } 49803986916Sjarrett } 49903986916Sjarrett } 50003986916Sjarrett 5017c478bd9Sstevel@tonic-gate dva.va_mask = AT_ALL; 502da6c28aaSamw dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva; 5037c478bd9Sstevel@tonic-gate 5047c478bd9Sstevel@tonic-gate if (error) 5057c478bd9Sstevel@tonic-gate goto out; 5067c478bd9Sstevel@tonic-gate 5077c478bd9Sstevel@tonic-gate if (sec.sec_flags & SEC_QUERY) { 5087c478bd9Sstevel@tonic-gate error = makefh3_ol(&resp->resok.object, exi, sec.sec_index); 5097c478bd9Sstevel@tonic-gate } else { 5107c478bd9Sstevel@tonic-gate error = makefh3(&resp->resok.object, vp, exi); 5117c478bd9Sstevel@tonic-gate if (!error && publicfh_flag && !chk_clnt_sec(exi, req)) 5127c478bd9Sstevel@tonic-gate auth_weak = TRUE; 5137c478bd9Sstevel@tonic-gate } 5147c478bd9Sstevel@tonic-gate 515596bc239SMarcel Telka /* 516596bc239SMarcel Telka * If publicfh_flag is true then we have called rfs_publicfh_mclookup 517596bc239SMarcel Telka * and have obtained a new exportinfo in exi which needs to be 518fd9d0a82SMarcel Telka * released. Note that the original exportinfo pointed to by exi 519596bc239SMarcel Telka * will be released by the caller, common_dispatch. 520596bc239SMarcel Telka */ 521596bc239SMarcel Telka if (publicfh_flag) 522596bc239SMarcel Telka exi_rele(exi); 523596bc239SMarcel Telka 524fd9d0a82SMarcel Telka if (error) { 525fd9d0a82SMarcel Telka VN_RELE(vp); 526fd9d0a82SMarcel Telka goto out; 527fd9d0a82SMarcel Telka } 528fd9d0a82SMarcel Telka 5297c478bd9Sstevel@tonic-gate va.va_mask = AT_ALL; 5307c478bd9Sstevel@tonic-gate vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va; 5317c478bd9Sstevel@tonic-gate 5327c478bd9Sstevel@tonic-gate VN_RELE(vp); 5337c478bd9Sstevel@tonic-gate 5347c478bd9Sstevel@tonic-gate resp->status = NFS3_OK; 5357c478bd9Sstevel@tonic-gate vattr_to_post_op_attr(vap, &resp->resok.obj_attributes); 5367c478bd9Sstevel@tonic-gate vattr_to_post_op_attr(dvap, &resp->resok.dir_attributes); 5377c478bd9Sstevel@tonic-gate 5387c478bd9Sstevel@tonic-gate /* 5397c478bd9Sstevel@tonic-gate * If it's public fh, no 0x81, and client's flavor is 5407c478bd9Sstevel@tonic-gate * invalid, set WebNFS status to WNFSERR_CLNT_FLAVOR now. 5417c478bd9Sstevel@tonic-gate * Then set RPC status to AUTH_TOOWEAK in common_dispatch. 5427c478bd9Sstevel@tonic-gate */ 5437c478bd9Sstevel@tonic-gate if (auth_weak) 5447c478bd9Sstevel@tonic-gate resp->status = (enum nfsstat3)WNFSERR_CLNT_FLAVOR; 5457c478bd9Sstevel@tonic-gate 546e1adf50cSahl DTRACE_NFSV3_4(op__lookup__done, struct svc_req *, req, 547e1adf50cSahl cred_t *, cr, vnode_t *, dvp, LOOKUP3res *, resp); 548e1adf50cSahl VN_RELE(dvp); 549e1adf50cSahl 5507c478bd9Sstevel@tonic-gate return; 5517c478bd9Sstevel@tonic-gate 5527c478bd9Sstevel@tonic-gate out: 5537c478bd9Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK) { 5547c478bd9Sstevel@tonic-gate curthread->t_flag &= ~T_WOULDBLOCK; 5557c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX; 5567c478bd9Sstevel@tonic-gate } else 5577c478bd9Sstevel@tonic-gate resp->status = puterrno3(error); 5587c478bd9Sstevel@tonic-gate out1: 559e1adf50cSahl DTRACE_NFSV3_4(op__lookup__done, struct svc_req *, req, 560e1adf50cSahl cred_t *, cr, vnode_t *, dvp, LOOKUP3res *, resp); 561e1adf50cSahl 5627c478bd9Sstevel@tonic-gate if (dvp != NULL) 5637c478bd9Sstevel@tonic-gate VN_RELE(dvp); 5647c478bd9Sstevel@tonic-gate vattr_to_post_op_attr(dvap, &resp->resfail.dir_attributes); 5657c478bd9Sstevel@tonic-gate 5667c478bd9Sstevel@tonic-gate } 5677c478bd9Sstevel@tonic-gate 56827242a7cSthurlow void * 5697c478bd9Sstevel@tonic-gate rfs3_lookup_getfh(LOOKUP3args *args) 5707c478bd9Sstevel@tonic-gate { 5717c478bd9Sstevel@tonic-gate 57227242a7cSthurlow return (&args->what.dir); 5737c478bd9Sstevel@tonic-gate } 5747c478bd9Sstevel@tonic-gate 5757c478bd9Sstevel@tonic-gate /* ARGSUSED */ 5767c478bd9Sstevel@tonic-gate void 5777c478bd9Sstevel@tonic-gate rfs3_access(ACCESS3args *args, ACCESS3res *resp, struct exportinfo *exi, 5785cb0d679SMarcel Telka struct svc_req *req, cred_t *cr, bool_t ro) 5797c478bd9Sstevel@tonic-gate { 5807c478bd9Sstevel@tonic-gate int error; 5817c478bd9Sstevel@tonic-gate vnode_t *vp; 5827c478bd9Sstevel@tonic-gate struct vattr *vap; 5837c478bd9Sstevel@tonic-gate struct vattr va; 5847c478bd9Sstevel@tonic-gate int checkwriteperm; 58503986916Sjarrett boolean_t dominant_label = B_FALSE; 58603986916Sjarrett boolean_t equal_label = B_FALSE; 58703986916Sjarrett boolean_t admin_low_client; 5887c478bd9Sstevel@tonic-gate 5897c478bd9Sstevel@tonic-gate vap = NULL; 5907c478bd9Sstevel@tonic-gate 5917c478bd9Sstevel@tonic-gate vp = nfs3_fhtovp(&args->object, exi); 592e1adf50cSahl 593e1adf50cSahl DTRACE_NFSV3_4(op__access__start, struct svc_req *, req, 594e1adf50cSahl cred_t *, cr, vnode_t *, vp, ACCESS3args *, args); 595e1adf50cSahl 5967c478bd9Sstevel@tonic-gate if (vp == NULL) { 5977c478bd9Sstevel@tonic-gate error = ESTALE; 5987c478bd9Sstevel@tonic-gate goto out; 5997c478bd9Sstevel@tonic-gate } 6007c478bd9Sstevel@tonic-gate 6017c478bd9Sstevel@tonic-gate /* 6027c478bd9Sstevel@tonic-gate * If the file system is exported read only, it is not appropriate 6037c478bd9Sstevel@tonic-gate * to check write permissions for regular files and directories. 6047c478bd9Sstevel@tonic-gate * Special files are interpreted by the client, so the underlying 6057c478bd9Sstevel@tonic-gate * permissions are sent back to the client for interpretation. 6067c478bd9Sstevel@tonic-gate */ 6075cb0d679SMarcel Telka if (rdonly(ro, vp) && (vp->v_type == VREG || vp->v_type == VDIR)) 6087c478bd9Sstevel@tonic-gate checkwriteperm = 0; 6097c478bd9Sstevel@tonic-gate else 6107c478bd9Sstevel@tonic-gate checkwriteperm = 1; 6117c478bd9Sstevel@tonic-gate 6127c478bd9Sstevel@tonic-gate /* 6137c478bd9Sstevel@tonic-gate * We need the mode so that we can correctly determine access 6147c478bd9Sstevel@tonic-gate * permissions relative to a mandatory lock file. Access to 6157c478bd9Sstevel@tonic-gate * mandatory lock files is denied on the server, so it might 6167c478bd9Sstevel@tonic-gate * as well be reflected to the server during the open. 6177c478bd9Sstevel@tonic-gate */ 6187c478bd9Sstevel@tonic-gate va.va_mask = AT_MODE; 619da6c28aaSamw error = VOP_GETATTR(vp, &va, 0, cr, NULL); 6207c478bd9Sstevel@tonic-gate if (error) 6217c478bd9Sstevel@tonic-gate goto out; 6227c478bd9Sstevel@tonic-gate 6237c478bd9Sstevel@tonic-gate vap = &va; 6247c478bd9Sstevel@tonic-gate 6257c478bd9Sstevel@tonic-gate resp->resok.access = 0; 6267c478bd9Sstevel@tonic-gate 62703986916Sjarrett if (is_system_labeled()) { 62803986916Sjarrett bslabel_t *clabel = req->rq_label; 62903986916Sjarrett 63003986916Sjarrett ASSERT(clabel != NULL); 63103986916Sjarrett DTRACE_PROBE2(tx__rfs3__log__info__opaccess__clabel, char *, 63203986916Sjarrett "got client label from request(1)", struct svc_req *, req); 63303986916Sjarrett 63403986916Sjarrett if (!blequal(&l_admin_low->tsl_label, clabel)) { 63503986916Sjarrett if ((equal_label = do_rfs_label_check(clabel, vp, 636bd6f1640SJarrett Lu EQUALITY_CHECK, exi)) == B_FALSE) { 63703986916Sjarrett dominant_label = do_rfs_label_check(clabel, 638bd6f1640SJarrett Lu vp, DOMINANCE_CHECK, exi); 63903986916Sjarrett } else 64003986916Sjarrett dominant_label = B_TRUE; 64103986916Sjarrett admin_low_client = B_FALSE; 64203986916Sjarrett } else 64303986916Sjarrett admin_low_client = B_TRUE; 64403986916Sjarrett } 64503986916Sjarrett 6467c478bd9Sstevel@tonic-gate if (args->access & ACCESS3_READ) { 647da6c28aaSamw error = VOP_ACCESS(vp, VREAD, 0, cr, NULL); 6487c478bd9Sstevel@tonic-gate if (error) { 6497c478bd9Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK) 6507c478bd9Sstevel@tonic-gate goto out; 65103986916Sjarrett } else if (!MANDLOCK(vp, va.va_mode) && 65203986916Sjarrett (!is_system_labeled() || admin_low_client || 65303986916Sjarrett dominant_label)) 6547c478bd9Sstevel@tonic-gate resp->resok.access |= ACCESS3_READ; 6557c478bd9Sstevel@tonic-gate } 6567c478bd9Sstevel@tonic-gate if ((args->access & ACCESS3_LOOKUP) && vp->v_type == VDIR) { 657da6c28aaSamw error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL); 6587c478bd9Sstevel@tonic-gate if (error) { 6597c478bd9Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK) 6607c478bd9Sstevel@tonic-gate goto out; 66103986916Sjarrett } else if (!is_system_labeled() || admin_low_client || 66203986916Sjarrett dominant_label) 6637c478bd9Sstevel@tonic-gate resp->resok.access |= ACCESS3_LOOKUP; 6647c478bd9Sstevel@tonic-gate } 6657c478bd9Sstevel@tonic-gate if (checkwriteperm && 6667c478bd9Sstevel@tonic-gate (args->access & (ACCESS3_MODIFY|ACCESS3_EXTEND))) { 667da6c28aaSamw error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL); 6687c478bd9Sstevel@tonic-gate if (error) { 6697c478bd9Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK) 6707c478bd9Sstevel@tonic-gate goto out; 67103986916Sjarrett } else if (!MANDLOCK(vp, va.va_mode) && 67203986916Sjarrett (!is_system_labeled() || admin_low_client || equal_label)) { 6737c478bd9Sstevel@tonic-gate resp->resok.access |= 6747c478bd9Sstevel@tonic-gate (args->access & (ACCESS3_MODIFY|ACCESS3_EXTEND)); 6757c478bd9Sstevel@tonic-gate } 6767c478bd9Sstevel@tonic-gate } 6777c478bd9Sstevel@tonic-gate if (checkwriteperm && 6787c478bd9Sstevel@tonic-gate (args->access & ACCESS3_DELETE) && vp->v_type == VDIR) { 679da6c28aaSamw error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL); 6807c478bd9Sstevel@tonic-gate if (error) { 6817c478bd9Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK) 6827c478bd9Sstevel@tonic-gate goto out; 68303986916Sjarrett } else if (!is_system_labeled() || admin_low_client || 68403986916Sjarrett equal_label) 6857c478bd9Sstevel@tonic-gate resp->resok.access |= ACCESS3_DELETE; 6867c478bd9Sstevel@tonic-gate } 6877c478bd9Sstevel@tonic-gate if (args->access & ACCESS3_EXECUTE) { 688da6c28aaSamw error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL); 6897c478bd9Sstevel@tonic-gate if (error) { 6907c478bd9Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK) 6917c478bd9Sstevel@tonic-gate goto out; 69203986916Sjarrett } else if (!MANDLOCK(vp, va.va_mode) && 69303986916Sjarrett (!is_system_labeled() || admin_low_client || 69403986916Sjarrett dominant_label)) 6957c478bd9Sstevel@tonic-gate resp->resok.access |= ACCESS3_EXECUTE; 6967c478bd9Sstevel@tonic-gate } 6977c478bd9Sstevel@tonic-gate 6987c478bd9Sstevel@tonic-gate va.va_mask = AT_ALL; 6997c478bd9Sstevel@tonic-gate vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va; 7007c478bd9Sstevel@tonic-gate 7017c478bd9Sstevel@tonic-gate resp->status = NFS3_OK; 7027c478bd9Sstevel@tonic-gate vattr_to_post_op_attr(vap, &resp->resok.obj_attributes); 703e1adf50cSahl 704e1adf50cSahl DTRACE_NFSV3_4(op__access__done, struct svc_req *, req, 705e1adf50cSahl cred_t *, cr, vnode_t *, vp, ACCESS3res *, resp); 706e1adf50cSahl 707e1adf50cSahl VN_RELE(vp); 708e1adf50cSahl 7097c478bd9Sstevel@tonic-gate return; 7107c478bd9Sstevel@tonic-gate 7117c478bd9Sstevel@tonic-gate out: 7127c478bd9Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK) { 7137c478bd9Sstevel@tonic-gate curthread->t_flag &= ~T_WOULDBLOCK; 7147c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX; 7157c478bd9Sstevel@tonic-gate } else 7167c478bd9Sstevel@tonic-gate resp->status = puterrno3(error); 717e1adf50cSahl DTRACE_NFSV3_4(op__access__done, struct svc_req *, req, 718e1adf50cSahl cred_t *, cr, vnode_t *, vp, ACCESS3res *, resp); 7197c478bd9Sstevel@tonic-gate if (vp != NULL) 7207c478bd9Sstevel@tonic-gate VN_RELE(vp); 7217c478bd9Sstevel@tonic-gate vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes); 7227c478bd9Sstevel@tonic-gate } 7237c478bd9Sstevel@tonic-gate 72427242a7cSthurlow void * 7257c478bd9Sstevel@tonic-gate rfs3_access_getfh(ACCESS3args *args) 7267c478bd9Sstevel@tonic-gate { 7277c478bd9Sstevel@tonic-gate 72827242a7cSthurlow return (&args->object); 7297c478bd9Sstevel@tonic-gate } 7307c478bd9Sstevel@tonic-gate 7317c478bd9Sstevel@tonic-gate /* ARGSUSED */ 7327c478bd9Sstevel@tonic-gate void 7337c478bd9Sstevel@tonic-gate rfs3_readlink(READLINK3args *args, READLINK3res *resp, struct exportinfo *exi, 7345cb0d679SMarcel Telka struct svc_req *req, cred_t *cr, bool_t ro) 7357c478bd9Sstevel@tonic-gate { 7367c478bd9Sstevel@tonic-gate int error; 7377c478bd9Sstevel@tonic-gate vnode_t *vp; 7387c478bd9Sstevel@tonic-gate struct vattr *vap; 7397c478bd9Sstevel@tonic-gate struct vattr va; 7407c478bd9Sstevel@tonic-gate struct iovec iov; 7417c478bd9Sstevel@tonic-gate struct uio uio; 7427c478bd9Sstevel@tonic-gate char *data; 743b89a8333Snatalie li - Sun Microsystems - Irvine United States struct sockaddr *ca; 744b89a8333Snatalie li - Sun Microsystems - Irvine United States char *name = NULL; 7452f172c55SRobert Thurlow int is_referral = 0; 7467c478bd9Sstevel@tonic-gate 7477c478bd9Sstevel@tonic-gate vap = NULL; 7487c478bd9Sstevel@tonic-gate 7497c478bd9Sstevel@tonic-gate vp = nfs3_fhtovp(&args->symlink, exi); 750e1adf50cSahl 751e1adf50cSahl DTRACE_NFSV3_4(op__readlink__start, struct svc_req *, req, 752e1adf50cSahl cred_t *, cr, vnode_t *, vp, READLINK3args *, args); 753e1adf50cSahl 7547c478bd9Sstevel@tonic-gate if (vp == NULL) { 7557c478bd9Sstevel@tonic-gate error = ESTALE; 7567c478bd9Sstevel@tonic-gate goto out; 7577c478bd9Sstevel@tonic-gate } 7587c478bd9Sstevel@tonic-gate 7597c478bd9Sstevel@tonic-gate va.va_mask = AT_ALL; 760da6c28aaSamw error = VOP_GETATTR(vp, &va, 0, cr, NULL); 7617c478bd9Sstevel@tonic-gate if (error) 7627c478bd9Sstevel@tonic-gate goto out; 7637c478bd9Sstevel@tonic-gate 7647c478bd9Sstevel@tonic-gate vap = &va; 7657c478bd9Sstevel@tonic-gate 7662f172c55SRobert Thurlow /* We lied about the object type for a referral */ 7672f172c55SRobert Thurlow if (vn_is_nfs_reparse(vp, cr)) 7682f172c55SRobert Thurlow is_referral = 1; 7692f172c55SRobert Thurlow 7702f172c55SRobert Thurlow if (vp->v_type != VLNK && !is_referral) { 7717c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_INVAL; 7727c478bd9Sstevel@tonic-gate goto out1; 7737c478bd9Sstevel@tonic-gate } 7747c478bd9Sstevel@tonic-gate 7757c478bd9Sstevel@tonic-gate if (MANDLOCK(vp, va.va_mode)) { 7767c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_ACCES; 7777c478bd9Sstevel@tonic-gate goto out1; 7787c478bd9Sstevel@tonic-gate } 7797c478bd9Sstevel@tonic-gate 78003986916Sjarrett if (is_system_labeled()) { 78103986916Sjarrett bslabel_t *clabel = req->rq_label; 78203986916Sjarrett 78303986916Sjarrett ASSERT(clabel != NULL); 78403986916Sjarrett DTRACE_PROBE2(tx__rfs3__log__info__opreadlink__clabel, char *, 78503986916Sjarrett "got client label from request(1)", struct svc_req *, req); 78603986916Sjarrett 78703986916Sjarrett if (!blequal(&l_admin_low->tsl_label, clabel)) { 788bd6f1640SJarrett Lu if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK, 789bd6f1640SJarrett Lu exi)) { 79003986916Sjarrett resp->status = NFS3ERR_ACCES; 79103986916Sjarrett goto out1; 79203986916Sjarrett } 79303986916Sjarrett } 79403986916Sjarrett } 79503986916Sjarrett 7967c478bd9Sstevel@tonic-gate data = kmem_alloc(MAXPATHLEN + 1, KM_SLEEP); 7977c478bd9Sstevel@tonic-gate 7982f172c55SRobert Thurlow if (is_referral) { 7992f172c55SRobert Thurlow char *s; 8002f172c55SRobert Thurlow size_t strsz; 8012f172c55SRobert Thurlow 8022f172c55SRobert Thurlow /* Get an artificial symlink based on a referral */ 8032f172c55SRobert Thurlow s = build_symlink(vp, cr, &strsz); 8042f172c55SRobert Thurlow global_svstat_ptr[3][NFS_REFERLINKS].value.ui64++; 8052f172c55SRobert Thurlow DTRACE_PROBE2(nfs3serv__func__referral__reflink, 8062f172c55SRobert Thurlow vnode_t *, vp, char *, s); 8072f172c55SRobert Thurlow if (s == NULL) 8082f172c55SRobert Thurlow error = EINVAL; 8092f172c55SRobert Thurlow else { 8102f172c55SRobert Thurlow error = 0; 8112f172c55SRobert Thurlow (void) strlcpy(data, s, MAXPATHLEN + 1); 8122f172c55SRobert Thurlow kmem_free(s, strsz); 8132f172c55SRobert Thurlow } 8142f172c55SRobert Thurlow 8152f172c55SRobert Thurlow } else { 8162f172c55SRobert Thurlow 8177c478bd9Sstevel@tonic-gate iov.iov_base = data; 8187c478bd9Sstevel@tonic-gate iov.iov_len = MAXPATHLEN; 8197c478bd9Sstevel@tonic-gate uio.uio_iov = &iov; 8207c478bd9Sstevel@tonic-gate uio.uio_iovcnt = 1; 8217c478bd9Sstevel@tonic-gate uio.uio_segflg = UIO_SYSSPACE; 8227c478bd9Sstevel@tonic-gate uio.uio_extflg = UIO_COPY_CACHED; 8237c478bd9Sstevel@tonic-gate uio.uio_loffset = 0; 8247c478bd9Sstevel@tonic-gate uio.uio_resid = MAXPATHLEN; 8257c478bd9Sstevel@tonic-gate 826da6c28aaSamw error = VOP_READLINK(vp, &uio, cr, NULL); 8277c478bd9Sstevel@tonic-gate 8282f172c55SRobert Thurlow if (!error) 8292f172c55SRobert Thurlow *(data + MAXPATHLEN - uio.uio_resid) = '\0'; 8302f172c55SRobert Thurlow } 8312f172c55SRobert Thurlow 8327c478bd9Sstevel@tonic-gate va.va_mask = AT_ALL; 833da6c28aaSamw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 83427246829SVitaliy Gusev 8352f172c55SRobert Thurlow /* Lie about object type again just to be consistent */ 8362f172c55SRobert Thurlow if (is_referral && vap != NULL) 8372f172c55SRobert Thurlow vap->va_type = VLNK; 8387c478bd9Sstevel@tonic-gate 8397c478bd9Sstevel@tonic-gate #if 0 /* notyet */ 8407c478bd9Sstevel@tonic-gate /* 8417c478bd9Sstevel@tonic-gate * Don't do this. It causes local disk writes when just 8427c478bd9Sstevel@tonic-gate * reading the file and the overhead is deemed larger 8437c478bd9Sstevel@tonic-gate * than the benefit. 8447c478bd9Sstevel@tonic-gate */ 8457c478bd9Sstevel@tonic-gate /* 8467c478bd9Sstevel@tonic-gate * Force modified metadata out to stable storage. 8477c478bd9Sstevel@tonic-gate */ 848da6c28aaSamw (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL); 8497c478bd9Sstevel@tonic-gate #endif 8507c478bd9Sstevel@tonic-gate 8517c478bd9Sstevel@tonic-gate if (error) { 8527c478bd9Sstevel@tonic-gate kmem_free(data, MAXPATHLEN + 1); 8537c478bd9Sstevel@tonic-gate goto out; 8547c478bd9Sstevel@tonic-gate } 8557c478bd9Sstevel@tonic-gate 856b89a8333Snatalie li - Sun Microsystems - Irvine United States ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 857b89a8333Snatalie li - Sun Microsystems - Irvine United States name = nfscmd_convname(ca, exi, data, NFSCMD_CONV_OUTBOUND, 858b89a8333Snatalie li - Sun Microsystems - Irvine United States MAXPATHLEN + 1); 859b89a8333Snatalie li - Sun Microsystems - Irvine United States 860b89a8333Snatalie li - Sun Microsystems - Irvine United States if (name == NULL) { 861b89a8333Snatalie li - Sun Microsystems - Irvine United States /* 862b89a8333Snatalie li - Sun Microsystems - Irvine United States * Even though the conversion failed, we return 863b89a8333Snatalie li - Sun Microsystems - Irvine United States * something. We just don't translate it. 864b89a8333Snatalie li - Sun Microsystems - Irvine United States */ 865b89a8333Snatalie li - Sun Microsystems - Irvine United States name = data; 866b89a8333Snatalie li - Sun Microsystems - Irvine United States } 867b89a8333Snatalie li - Sun Microsystems - Irvine United States 8687c478bd9Sstevel@tonic-gate resp->status = NFS3_OK; 8697c478bd9Sstevel@tonic-gate vattr_to_post_op_attr(vap, &resp->resok.symlink_attributes); 870b89a8333Snatalie li - Sun Microsystems - Irvine United States resp->resok.data = name; 871e1adf50cSahl 872e1adf50cSahl DTRACE_NFSV3_4(op__readlink__done, struct svc_req *, req, 873e1adf50cSahl cred_t *, cr, vnode_t *, vp, READLINK3res *, resp); 874e1adf50cSahl VN_RELE(vp); 875e1adf50cSahl 876b89a8333Snatalie li - Sun Microsystems - Irvine United States if (name != data) 877b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(data, MAXPATHLEN + 1); 878b89a8333Snatalie li - Sun Microsystems - Irvine United States 8797c478bd9Sstevel@tonic-gate return; 8807c478bd9Sstevel@tonic-gate 8817c478bd9Sstevel@tonic-gate out: 8827c478bd9Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK) { 8837c478bd9Sstevel@tonic-gate curthread->t_flag &= ~T_WOULDBLOCK; 8847c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX; 8857c478bd9Sstevel@tonic-gate } else 8867c478bd9Sstevel@tonic-gate resp->status = puterrno3(error); 8877c478bd9Sstevel@tonic-gate out1: 888e1adf50cSahl DTRACE_NFSV3_4(op__readlink__done, struct svc_req *, req, 889e1adf50cSahl cred_t *, cr, vnode_t *, vp, READLINK3res *, resp); 8907c478bd9Sstevel@tonic-gate if (vp != NULL) 8917c478bd9Sstevel@tonic-gate VN_RELE(vp); 8927c478bd9Sstevel@tonic-gate vattr_to_post_op_attr(vap, &resp->resfail.symlink_attributes); 8937c478bd9Sstevel@tonic-gate } 8947c478bd9Sstevel@tonic-gate 89527242a7cSthurlow void * 8967c478bd9Sstevel@tonic-gate rfs3_readlink_getfh(READLINK3args *args) 8977c478bd9Sstevel@tonic-gate { 8987c478bd9Sstevel@tonic-gate 89927242a7cSthurlow return (&args->symlink); 9007c478bd9Sstevel@tonic-gate } 9017c478bd9Sstevel@tonic-gate 9027c478bd9Sstevel@tonic-gate void 9037c478bd9Sstevel@tonic-gate rfs3_readlink_free(READLINK3res *resp) 9047c478bd9Sstevel@tonic-gate { 9057c478bd9Sstevel@tonic-gate 9067c478bd9Sstevel@tonic-gate if (resp->status == NFS3_OK) 9077c478bd9Sstevel@tonic-gate kmem_free(resp->resok.data, MAXPATHLEN + 1); 9087c478bd9Sstevel@tonic-gate } 9097c478bd9Sstevel@tonic-gate 9100a701b1eSRobert Gordon /* 9110a701b1eSRobert Gordon * Server routine to handle read 9120a701b1eSRobert Gordon * May handle RDMA data as well as mblks 9130a701b1eSRobert Gordon */ 9147c478bd9Sstevel@tonic-gate /* ARGSUSED */ 9157c478bd9Sstevel@tonic-gate void 9167c478bd9Sstevel@tonic-gate rfs3_read(READ3args *args, READ3res *resp, struct exportinfo *exi, 9175cb0d679SMarcel Telka struct svc_req *req, cred_t *cr, bool_t ro) 9187c478bd9Sstevel@tonic-gate { 9197c478bd9Sstevel@tonic-gate int error; 9207c478bd9Sstevel@tonic-gate vnode_t *vp; 9217c478bd9Sstevel@tonic-gate struct vattr *vap; 9227c478bd9Sstevel@tonic-gate struct vattr va; 923e36d7b11SSebastien Roy struct iovec iov, *iovp = NULL; 924e36d7b11SSebastien Roy int iovcnt; 9257c478bd9Sstevel@tonic-gate struct uio uio; 9267c478bd9Sstevel@tonic-gate u_offset_t offset; 92741b8345aSchunli zhang - Sun Microsystems - Irvine United States mblk_t *mp = NULL; 9287c478bd9Sstevel@tonic-gate int in_crit = 0; 9297c478bd9Sstevel@tonic-gate int need_rwunlock = 0; 930cfae96c2Sjwahlig caller_context_t ct; 931c242f9a0Schunli zhang - Sun Microsystems - Irvine United States int rdma_used = 0; 932c242f9a0Schunli zhang - Sun Microsystems - Irvine United States int loaned_buffers; 933c242f9a0Schunli zhang - Sun Microsystems - Irvine United States struct uio *uiop; 9347c478bd9Sstevel@tonic-gate 9357c478bd9Sstevel@tonic-gate vap = NULL; 9367c478bd9Sstevel@tonic-gate 9377c478bd9Sstevel@tonic-gate vp = nfs3_fhtovp(&args->file, exi); 938e1adf50cSahl 939e1adf50cSahl DTRACE_NFSV3_4(op__read__start, struct svc_req *, req, 940e1adf50cSahl cred_t *, cr, vnode_t *, vp, READ3args *, args); 941e1adf50cSahl 9427c478bd9Sstevel@tonic-gate if (vp == NULL) { 9437c478bd9Sstevel@tonic-gate error = ESTALE; 9447c478bd9Sstevel@tonic-gate goto out; 9457c478bd9Sstevel@tonic-gate } 9467c478bd9Sstevel@tonic-gate 94735bbd688SKaren Rochford if (args->wlist) { 94835bbd688SKaren Rochford if (args->count > clist_len(args->wlist)) { 94935bbd688SKaren Rochford error = EINVAL; 95035bbd688SKaren Rochford goto out; 95135bbd688SKaren Rochford } 952c242f9a0Schunli zhang - Sun Microsystems - Irvine United States rdma_used = 1; 95335bbd688SKaren Rochford } 954c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 955c242f9a0Schunli zhang - Sun Microsystems - Irvine United States /* use loaned buffers for TCP */ 956c242f9a0Schunli zhang - Sun Microsystems - Irvine United States loaned_buffers = (nfs_loaned_buffers && !rdma_used) ? 1 : 0; 957c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 95803986916Sjarrett if (is_system_labeled()) { 95903986916Sjarrett bslabel_t *clabel = req->rq_label; 96003986916Sjarrett 96103986916Sjarrett ASSERT(clabel != NULL); 96203986916Sjarrett DTRACE_PROBE2(tx__rfs3__log__info__opread__clabel, char *, 96303986916Sjarrett "got client label from request(1)", struct svc_req *, req); 96403986916Sjarrett 96503986916Sjarrett if (!blequal(&l_admin_low->tsl_label, clabel)) { 966bd6f1640SJarrett Lu if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK, 967bd6f1640SJarrett Lu exi)) { 96803986916Sjarrett resp->status = NFS3ERR_ACCES; 96903986916Sjarrett goto out1; 97003986916Sjarrett } 97103986916Sjarrett } 97203986916Sjarrett } 97303986916Sjarrett 974cfae96c2Sjwahlig ct.cc_sysid = 0; 975cfae96c2Sjwahlig ct.cc_pid = 0; 976cfae96c2Sjwahlig ct.cc_caller_id = nfs3_srv_caller_id; 977cfae96c2Sjwahlig ct.cc_flags = CC_DONTBLOCK; 9787c478bd9Sstevel@tonic-gate 9797c478bd9Sstevel@tonic-gate /* 9807c478bd9Sstevel@tonic-gate * Enter the critical region before calling VOP_RWLOCK 9817c478bd9Sstevel@tonic-gate * to avoid a deadlock with write requests. 9827c478bd9Sstevel@tonic-gate */ 9837c478bd9Sstevel@tonic-gate if (nbl_need_check(vp)) { 9847c478bd9Sstevel@tonic-gate nbl_start_crit(vp, RW_READER); 9857c478bd9Sstevel@tonic-gate in_crit = 1; 986da6c28aaSamw if (nbl_conflict(vp, NBL_READ, args->offset, args->count, 0, 987da6c28aaSamw NULL)) { 9887c478bd9Sstevel@tonic-gate error = EACCES; 9897c478bd9Sstevel@tonic-gate goto out; 9907c478bd9Sstevel@tonic-gate } 9917c478bd9Sstevel@tonic-gate } 9927c478bd9Sstevel@tonic-gate 993cfae96c2Sjwahlig error = VOP_RWLOCK(vp, V_WRITELOCK_FALSE, &ct); 994cfae96c2Sjwahlig 995cfae96c2Sjwahlig /* check if a monitor detected a delegation conflict */ 996cfae96c2Sjwahlig if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) { 997cfae96c2Sjwahlig resp->status = NFS3ERR_JUKEBOX; 998cfae96c2Sjwahlig goto out1; 999cfae96c2Sjwahlig } 1000cfae96c2Sjwahlig 10017c478bd9Sstevel@tonic-gate need_rwunlock = 1; 10027c478bd9Sstevel@tonic-gate 10037c478bd9Sstevel@tonic-gate va.va_mask = AT_ALL; 1004cfae96c2Sjwahlig error = VOP_GETATTR(vp, &va, 0, cr, &ct); 10057c478bd9Sstevel@tonic-gate 10067c478bd9Sstevel@tonic-gate /* 10077c478bd9Sstevel@tonic-gate * If we can't get the attributes, then we can't do the 10087c478bd9Sstevel@tonic-gate * right access checking. So, we'll fail the request. 10097c478bd9Sstevel@tonic-gate */ 10107c478bd9Sstevel@tonic-gate if (error) 10117c478bd9Sstevel@tonic-gate goto out; 10127c478bd9Sstevel@tonic-gate 10137c478bd9Sstevel@tonic-gate vap = &va; 10147c478bd9Sstevel@tonic-gate 10157c478bd9Sstevel@tonic-gate if (vp->v_type != VREG) { 10167c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_INVAL; 10177c478bd9Sstevel@tonic-gate goto out1; 10187c478bd9Sstevel@tonic-gate } 10197c478bd9Sstevel@tonic-gate 10207c478bd9Sstevel@tonic-gate if (crgetuid(cr) != va.va_uid) { 1021cfae96c2Sjwahlig error = VOP_ACCESS(vp, VREAD, 0, cr, &ct); 10227c478bd9Sstevel@tonic-gate if (error) { 10237c478bd9Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK) 10247c478bd9Sstevel@tonic-gate goto out; 1025cfae96c2Sjwahlig error = VOP_ACCESS(vp, VEXEC, 0, cr, &ct); 10267c478bd9Sstevel@tonic-gate if (error) 10277c478bd9Sstevel@tonic-gate goto out; 10287c478bd9Sstevel@tonic-gate } 10297c478bd9Sstevel@tonic-gate } 10307c478bd9Sstevel@tonic-gate 10317c478bd9Sstevel@tonic-gate if (MANDLOCK(vp, va.va_mode)) { 10327c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_ACCES; 10337c478bd9Sstevel@tonic-gate goto out1; 10347c478bd9Sstevel@tonic-gate } 10357c478bd9Sstevel@tonic-gate 10367c478bd9Sstevel@tonic-gate offset = args->offset; 10377c478bd9Sstevel@tonic-gate if (offset >= va.va_size) { 1038cfae96c2Sjwahlig VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct); 10397c478bd9Sstevel@tonic-gate if (in_crit) 10407c478bd9Sstevel@tonic-gate nbl_end_crit(vp); 10417c478bd9Sstevel@tonic-gate resp->status = NFS3_OK; 10427c478bd9Sstevel@tonic-gate vattr_to_post_op_attr(vap, &resp->resok.file_attributes); 10437c478bd9Sstevel@tonic-gate resp->resok.count = 0; 10447c478bd9Sstevel@tonic-gate resp->resok.eof = TRUE; 10457c478bd9Sstevel@tonic-gate resp->resok.data.data_len = 0; 10467c478bd9Sstevel@tonic-gate resp->resok.data.data_val = NULL; 10477c478bd9Sstevel@tonic-gate resp->resok.data.mp = NULL; 10480a701b1eSRobert Gordon /* RDMA */ 10490a701b1eSRobert Gordon resp->resok.wlist = args->wlist; 10500a701b1eSRobert Gordon resp->resok.wlist_len = resp->resok.count; 1051f837ee4aSSiddheshwar Mahesh if (resp->resok.wlist) 1052f837ee4aSSiddheshwar Mahesh clist_zero_len(resp->resok.wlist); 1053e1adf50cSahl goto done; 10547c478bd9Sstevel@tonic-gate } 10557c478bd9Sstevel@tonic-gate 10567c478bd9Sstevel@tonic-gate if (args->count == 0) { 1057cfae96c2Sjwahlig VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct); 10587c478bd9Sstevel@tonic-gate if (in_crit) 10597c478bd9Sstevel@tonic-gate nbl_end_crit(vp); 10607c478bd9Sstevel@tonic-gate resp->status = NFS3_OK; 10617c478bd9Sstevel@tonic-gate vattr_to_post_op_attr(vap, &resp->resok.file_attributes); 10627c478bd9Sstevel@tonic-gate resp->resok.count = 0; 10637c478bd9Sstevel@tonic-gate resp->resok.eof = FALSE; 10647c478bd9Sstevel@tonic-gate resp->resok.data.data_len = 0; 10657c478bd9Sstevel@tonic-gate resp->resok.data.data_val = NULL; 10667c478bd9Sstevel@tonic-gate resp->resok.data.mp = NULL; 10670a701b1eSRobert Gordon /* RDMA */ 10680a701b1eSRobert Gordon resp->resok.wlist = args->wlist; 10690a701b1eSRobert Gordon resp->resok.wlist_len = resp->resok.count; 1070f837ee4aSSiddheshwar Mahesh if (resp->resok.wlist) 1071f837ee4aSSiddheshwar Mahesh clist_zero_len(resp->resok.wlist); 1072e1adf50cSahl goto done; 10737c478bd9Sstevel@tonic-gate } 10747c478bd9Sstevel@tonic-gate 10757c478bd9Sstevel@tonic-gate /* 10767c478bd9Sstevel@tonic-gate * do not allocate memory more the max. allowed 10777c478bd9Sstevel@tonic-gate * transfer size 10787c478bd9Sstevel@tonic-gate */ 10797c478bd9Sstevel@tonic-gate if (args->count > rfs3_tsize(req)) 10807c478bd9Sstevel@tonic-gate args->count = rfs3_tsize(req); 10817c478bd9Sstevel@tonic-gate 1082c242f9a0Schunli zhang - Sun Microsystems - Irvine United States if (loaned_buffers) { 1083c242f9a0Schunli zhang - Sun Microsystems - Irvine United States uiop = (uio_t *)rfs_setup_xuio(vp); 1084c242f9a0Schunli zhang - Sun Microsystems - Irvine United States ASSERT(uiop != NULL); 1085c242f9a0Schunli zhang - Sun Microsystems - Irvine United States uiop->uio_segflg = UIO_SYSSPACE; 1086c242f9a0Schunli zhang - Sun Microsystems - Irvine United States uiop->uio_loffset = args->offset; 1087c242f9a0Schunli zhang - Sun Microsystems - Irvine United States uiop->uio_resid = args->count; 1088c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 1089c242f9a0Schunli zhang - Sun Microsystems - Irvine United States /* Jump to do the read if successful */ 1090c242f9a0Schunli zhang - Sun Microsystems - Irvine United States if (VOP_REQZCBUF(vp, UIO_READ, (xuio_t *)uiop, cr, &ct) == 0) { 1091c242f9a0Schunli zhang - Sun Microsystems - Irvine United States /* 1092c242f9a0Schunli zhang - Sun Microsystems - Irvine United States * Need to hold the vnode until after VOP_RETZCBUF() 1093c242f9a0Schunli zhang - Sun Microsystems - Irvine United States * is called. 1094c242f9a0Schunli zhang - Sun Microsystems - Irvine United States */ 1095c242f9a0Schunli zhang - Sun Microsystems - Irvine United States VN_HOLD(vp); 1096c242f9a0Schunli zhang - Sun Microsystems - Irvine United States goto doio_read; 1097c242f9a0Schunli zhang - Sun Microsystems - Irvine United States } 1098c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 1099c242f9a0Schunli zhang - Sun Microsystems - Irvine United States DTRACE_PROBE2(nfss__i__reqzcbuf_failed, int, 1100c242f9a0Schunli zhang - Sun Microsystems - Irvine United States uiop->uio_loffset, int, uiop->uio_resid); 1101c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 1102c242f9a0Schunli zhang - Sun Microsystems - Irvine United States uiop->uio_extflg = 0; 1103c242f9a0Schunli zhang - Sun Microsystems - Irvine United States /* failure to setup for zero copy */ 1104c242f9a0Schunli zhang - Sun Microsystems - Irvine United States rfs_free_xuio((void *)uiop); 1105c242f9a0Schunli zhang - Sun Microsystems - Irvine United States loaned_buffers = 0; 1106c242f9a0Schunli zhang - Sun Microsystems - Irvine United States } 1107c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 11087c478bd9Sstevel@tonic-gate /* 11090a701b1eSRobert Gordon * If returning data via RDMA Write, then grab the chunk list. 11100a701b1eSRobert Gordon * If we aren't returning READ data w/RDMA_WRITE, then grab 11110a701b1eSRobert Gordon * a mblk. 11120a701b1eSRobert Gordon */ 1113c242f9a0Schunli zhang - Sun Microsystems - Irvine United States if (rdma_used) { 11140a701b1eSRobert Gordon (void) rdma_get_wchunk(req, &iov, args->wlist); 1115e36d7b11SSebastien Roy uio.uio_iov = &iov; 1116e36d7b11SSebastien Roy uio.uio_iovcnt = 1; 11170a701b1eSRobert Gordon } else { 11180a701b1eSRobert Gordon /* 11197c478bd9Sstevel@tonic-gate * mp will contain the data to be sent out in the read reply. 1120e36d7b11SSebastien Roy * For UDP, this will be freed after the reply has been sent 1121e36d7b11SSebastien Roy * out by the driver. For TCP, it will be freed after the last 1122e36d7b11SSebastien Roy * segment associated with the reply has been ACKed by the 1123e36d7b11SSebastien Roy * client. 11247c478bd9Sstevel@tonic-gate */ 1125e36d7b11SSebastien Roy mp = rfs_read_alloc(args->count, &iovp, &iovcnt); 1126e36d7b11SSebastien Roy uio.uio_iov = iovp; 1127e36d7b11SSebastien Roy uio.uio_iovcnt = iovcnt; 11280a701b1eSRobert Gordon } 11290a701b1eSRobert Gordon 11307c478bd9Sstevel@tonic-gate uio.uio_segflg = UIO_SYSSPACE; 11317c478bd9Sstevel@tonic-gate uio.uio_extflg = UIO_COPY_CACHED; 11327c478bd9Sstevel@tonic-gate uio.uio_loffset = args->offset; 11337c478bd9Sstevel@tonic-gate uio.uio_resid = args->count; 1134c242f9a0Schunli zhang - Sun Microsystems - Irvine United States uiop = &uio; 11357c478bd9Sstevel@tonic-gate 1136c242f9a0Schunli zhang - Sun Microsystems - Irvine United States doio_read: 1137c242f9a0Schunli zhang - Sun Microsystems - Irvine United States error = VOP_READ(vp, uiop, 0, cr, &ct); 11387c478bd9Sstevel@tonic-gate 11397c478bd9Sstevel@tonic-gate if (error) { 1140c242f9a0Schunli zhang - Sun Microsystems - Irvine United States if (mp) 1141c242f9a0Schunli zhang - Sun Microsystems - Irvine United States freemsg(mp); 1142cfae96c2Sjwahlig /* check if a monitor detected a delegation conflict */ 1143cfae96c2Sjwahlig if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) { 1144cfae96c2Sjwahlig resp->status = NFS3ERR_JUKEBOX; 1145cfae96c2Sjwahlig goto out1; 1146cfae96c2Sjwahlig } 11477c478bd9Sstevel@tonic-gate goto out; 11487c478bd9Sstevel@tonic-gate } 11497c478bd9Sstevel@tonic-gate 1150c242f9a0Schunli zhang - Sun Microsystems - Irvine United States /* make mblk using zc buffers */ 1151c242f9a0Schunli zhang - Sun Microsystems - Irvine United States if (loaned_buffers) { 1152c242f9a0Schunli zhang - Sun Microsystems - Irvine United States mp = uio_to_mblk(uiop); 1153c242f9a0Schunli zhang - Sun Microsystems - Irvine United States ASSERT(mp != NULL); 1154c242f9a0Schunli zhang - Sun Microsystems - Irvine United States } 1155c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 11567c478bd9Sstevel@tonic-gate va.va_mask = AT_ALL; 1157cfae96c2Sjwahlig error = VOP_GETATTR(vp, &va, 0, cr, &ct); 11587c478bd9Sstevel@tonic-gate 11597c478bd9Sstevel@tonic-gate if (error) 11607c478bd9Sstevel@tonic-gate vap = NULL; 11617c478bd9Sstevel@tonic-gate else 11627c478bd9Sstevel@tonic-gate vap = &va; 11637c478bd9Sstevel@tonic-gate 1164cfae96c2Sjwahlig VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct); 11657c478bd9Sstevel@tonic-gate 11667c478bd9Sstevel@tonic-gate if (in_crit) 11677c478bd9Sstevel@tonic-gate nbl_end_crit(vp); 11687c478bd9Sstevel@tonic-gate 11697c478bd9Sstevel@tonic-gate resp->status = NFS3_OK; 11707c478bd9Sstevel@tonic-gate vattr_to_post_op_attr(vap, &resp->resok.file_attributes); 1171c242f9a0Schunli zhang - Sun Microsystems - Irvine United States resp->resok.count = args->count - uiop->uio_resid; 11727c478bd9Sstevel@tonic-gate if (!error && offset + resp->resok.count == va.va_size) 11737c478bd9Sstevel@tonic-gate resp->resok.eof = TRUE; 11747c478bd9Sstevel@tonic-gate else 11757c478bd9Sstevel@tonic-gate resp->resok.eof = FALSE; 11767c478bd9Sstevel@tonic-gate resp->resok.data.data_len = resp->resok.count; 1177c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 1178c242f9a0Schunli zhang - Sun Microsystems - Irvine United States if (mp) 1179c242f9a0Schunli zhang - Sun Microsystems - Irvine United States rfs_rndup_mblks(mp, resp->resok.count, loaned_buffers); 1180c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 11817c478bd9Sstevel@tonic-gate resp->resok.data.mp = mp; 11827c478bd9Sstevel@tonic-gate resp->resok.size = (uint_t)args->count; 1183e1adf50cSahl 1184c242f9a0Schunli zhang - Sun Microsystems - Irvine United States if (rdma_used) { 11850a701b1eSRobert Gordon resp->resok.data.data_val = (caddr_t)iov.iov_base; 11860a701b1eSRobert Gordon if (!rdma_setup_read_data3(args, &(resp->resok))) { 11870a701b1eSRobert Gordon resp->status = NFS3ERR_INVAL; 11880a701b1eSRobert Gordon } 11890a701b1eSRobert Gordon } else { 11900a701b1eSRobert Gordon resp->resok.data.data_val = (caddr_t)mp->b_datap->db_base; 11910a701b1eSRobert Gordon (resp->resok).wlist = NULL; 11920a701b1eSRobert Gordon } 11930a701b1eSRobert Gordon 1194e1adf50cSahl done: 1195e1adf50cSahl DTRACE_NFSV3_4(op__read__done, struct svc_req *, req, 1196e1adf50cSahl cred_t *, cr, vnode_t *, vp, READ3res *, resp); 1197e1adf50cSahl 1198e1adf50cSahl VN_RELE(vp); 1199e1adf50cSahl 1200e36d7b11SSebastien Roy if (iovp != NULL) 1201e36d7b11SSebastien Roy kmem_free(iovp, iovcnt * sizeof (struct iovec)); 1202e36d7b11SSebastien Roy 12037c478bd9Sstevel@tonic-gate return; 12047c478bd9Sstevel@tonic-gate 12057c478bd9Sstevel@tonic-gate out: 12067c478bd9Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK) { 12077c478bd9Sstevel@tonic-gate curthread->t_flag &= ~T_WOULDBLOCK; 12087c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX; 12097c478bd9Sstevel@tonic-gate } else 12107c478bd9Sstevel@tonic-gate resp->status = puterrno3(error); 12117c478bd9Sstevel@tonic-gate out1: 1212e1adf50cSahl DTRACE_NFSV3_4(op__read__done, struct svc_req *, req, 1213e1adf50cSahl cred_t *, cr, vnode_t *, vp, READ3res *, resp); 1214e1adf50cSahl 12157c478bd9Sstevel@tonic-gate if (vp != NULL) { 12167c478bd9Sstevel@tonic-gate if (need_rwunlock) 1217cfae96c2Sjwahlig VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct); 12187c478bd9Sstevel@tonic-gate if (in_crit) 12197c478bd9Sstevel@tonic-gate nbl_end_crit(vp); 12207c478bd9Sstevel@tonic-gate VN_RELE(vp); 12217c478bd9Sstevel@tonic-gate } 12227c478bd9Sstevel@tonic-gate vattr_to_post_op_attr(vap, &resp->resfail.file_attributes); 1223e36d7b11SSebastien Roy 1224e36d7b11SSebastien Roy if (iovp != NULL) 1225e36d7b11SSebastien Roy kmem_free(iovp, iovcnt * sizeof (struct iovec)); 12267c478bd9Sstevel@tonic-gate } 12277c478bd9Sstevel@tonic-gate 12287c478bd9Sstevel@tonic-gate void 12297c478bd9Sstevel@tonic-gate rfs3_read_free(READ3res *resp) 12307c478bd9Sstevel@tonic-gate { 12317c478bd9Sstevel@tonic-gate mblk_t *mp; 12327c478bd9Sstevel@tonic-gate 12337c478bd9Sstevel@tonic-gate if (resp->status == NFS3_OK) { 12347c478bd9Sstevel@tonic-gate mp = resp->resok.data.mp; 12357c478bd9Sstevel@tonic-gate if (mp != NULL) 1236c242f9a0Schunli zhang - Sun Microsystems - Irvine United States freemsg(mp); 12377c478bd9Sstevel@tonic-gate } 12387c478bd9Sstevel@tonic-gate } 12397c478bd9Sstevel@tonic-gate 124027242a7cSthurlow void * 12417c478bd9Sstevel@tonic-gate rfs3_read_getfh(READ3args *args) 12427c478bd9Sstevel@tonic-gate { 12437c478bd9Sstevel@tonic-gate 124427242a7cSthurlow return (&args->file); 12457c478bd9Sstevel@tonic-gate } 12467c478bd9Sstevel@tonic-gate 12477c478bd9Sstevel@tonic-gate #define MAX_IOVECS 12 12487c478bd9Sstevel@tonic-gate 12497c478bd9Sstevel@tonic-gate #ifdef DEBUG 12507c478bd9Sstevel@tonic-gate static int rfs3_write_hits = 0; 12517c478bd9Sstevel@tonic-gate static int rfs3_write_misses = 0; 12527c478bd9Sstevel@tonic-gate #endif 12537c478bd9Sstevel@tonic-gate 12547c478bd9Sstevel@tonic-gate void 12557c478bd9Sstevel@tonic-gate rfs3_write(WRITE3args *args, WRITE3res *resp, struct exportinfo *exi, 12565cb0d679SMarcel Telka struct svc_req *req, cred_t *cr, bool_t ro) 12577c478bd9Sstevel@tonic-gate { 12587c478bd9Sstevel@tonic-gate int error; 12597c478bd9Sstevel@tonic-gate vnode_t *vp; 12607c478bd9Sstevel@tonic-gate struct vattr *bvap = NULL; 12617c478bd9Sstevel@tonic-gate struct vattr bva; 12627c478bd9Sstevel@tonic-gate struct vattr *avap = NULL; 12637c478bd9Sstevel@tonic-gate struct vattr ava; 12647c478bd9Sstevel@tonic-gate u_offset_t rlimit; 12657c478bd9Sstevel@tonic-gate struct uio uio; 12667c478bd9Sstevel@tonic-gate struct iovec iov[MAX_IOVECS]; 12677c478bd9Sstevel@tonic-gate mblk_t *m; 12687c478bd9Sstevel@tonic-gate struct iovec *iovp; 12697c478bd9Sstevel@tonic-gate int iovcnt; 12707c478bd9Sstevel@tonic-gate int ioflag; 12717c478bd9Sstevel@tonic-gate cred_t *savecred; 12727c478bd9Sstevel@tonic-gate int in_crit = 0; 12737c478bd9Sstevel@tonic-gate int rwlock_ret = -1; 1274cfae96c2Sjwahlig caller_context_t ct; 12757c478bd9Sstevel@tonic-gate 12767c478bd9Sstevel@tonic-gate vp = nfs3_fhtovp(&args->file, exi); 1277e1adf50cSahl 1278e1adf50cSahl DTRACE_NFSV3_4(op__write__start, struct svc_req *, req, 1279e1adf50cSahl cred_t *, cr, vnode_t *, vp, WRITE3args *, args); 1280e1adf50cSahl 12817c478bd9Sstevel@tonic-gate if (vp == NULL) { 12827c478bd9Sstevel@tonic-gate error = ESTALE; 1283e1adf50cSahl goto err; 12847c478bd9Sstevel@tonic-gate } 12857c478bd9Sstevel@tonic-gate 128603986916Sjarrett if (is_system_labeled()) { 128703986916Sjarrett bslabel_t *clabel = req->rq_label; 128803986916Sjarrett 128903986916Sjarrett ASSERT(clabel != NULL); 129003986916Sjarrett DTRACE_PROBE2(tx__rfs3__log__info__opwrite__clabel, char *, 129103986916Sjarrett "got client label from request(1)", struct svc_req *, req); 129203986916Sjarrett 129303986916Sjarrett if (!blequal(&l_admin_low->tsl_label, clabel)) { 1294bd6f1640SJarrett Lu if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK, 1295bd6f1640SJarrett Lu exi)) { 129603986916Sjarrett resp->status = NFS3ERR_ACCES; 1297e1adf50cSahl goto err1; 129803986916Sjarrett } 129903986916Sjarrett } 130003986916Sjarrett } 130103986916Sjarrett 1302cfae96c2Sjwahlig ct.cc_sysid = 0; 1303cfae96c2Sjwahlig ct.cc_pid = 0; 1304cfae96c2Sjwahlig ct.cc_caller_id = nfs3_srv_caller_id; 1305cfae96c2Sjwahlig ct.cc_flags = CC_DONTBLOCK; 13067c478bd9Sstevel@tonic-gate 13077c478bd9Sstevel@tonic-gate /* 13087c478bd9Sstevel@tonic-gate * We have to enter the critical region before calling VOP_RWLOCK 13097c478bd9Sstevel@tonic-gate * to avoid a deadlock with ufs. 13107c478bd9Sstevel@tonic-gate */ 13117c478bd9Sstevel@tonic-gate if (nbl_need_check(vp)) { 13127c478bd9Sstevel@tonic-gate nbl_start_crit(vp, RW_READER); 13137c478bd9Sstevel@tonic-gate in_crit = 1; 1314da6c28aaSamw if (nbl_conflict(vp, NBL_WRITE, args->offset, args->count, 0, 1315da6c28aaSamw NULL)) { 13167c478bd9Sstevel@tonic-gate error = EACCES; 1317e1adf50cSahl goto err; 13187c478bd9Sstevel@tonic-gate } 13197c478bd9Sstevel@tonic-gate } 13207c478bd9Sstevel@tonic-gate 1321cfae96c2Sjwahlig rwlock_ret = VOP_RWLOCK(vp, V_WRITELOCK_TRUE, &ct); 1322cfae96c2Sjwahlig 1323cfae96c2Sjwahlig /* check if a monitor detected a delegation conflict */ 1324cfae96c2Sjwahlig if (rwlock_ret == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) { 1325cfae96c2Sjwahlig resp->status = NFS3ERR_JUKEBOX; 1326cfae96c2Sjwahlig rwlock_ret = -1; 1327e1adf50cSahl goto err1; 1328cfae96c2Sjwahlig } 1329cfae96c2Sjwahlig 13307c478bd9Sstevel@tonic-gate 13317c478bd9Sstevel@tonic-gate bva.va_mask = AT_ALL; 1332cfae96c2Sjwahlig error = VOP_GETATTR(vp, &bva, 0, cr, &ct); 13337c478bd9Sstevel@tonic-gate 13347c478bd9Sstevel@tonic-gate /* 13357c478bd9Sstevel@tonic-gate * If we can't get the attributes, then we can't do the 13367c478bd9Sstevel@tonic-gate * right access checking. So, we'll fail the request. 13377c478bd9Sstevel@tonic-gate */ 13387c478bd9Sstevel@tonic-gate if (error) 1339e1adf50cSahl goto err; 13407c478bd9Sstevel@tonic-gate 13417c478bd9Sstevel@tonic-gate bvap = &bva; 13427c478bd9Sstevel@tonic-gate avap = bvap; 13437c478bd9Sstevel@tonic-gate 13447c478bd9Sstevel@tonic-gate if (args->count != args->data.data_len) { 13457c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_INVAL; 1346e1adf50cSahl goto err1; 13477c478bd9Sstevel@tonic-gate } 13487c478bd9Sstevel@tonic-gate 13495cb0d679SMarcel Telka if (rdonly(ro, vp)) { 13507c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_ROFS; 1351e1adf50cSahl goto err1; 13527c478bd9Sstevel@tonic-gate } 13537c478bd9Sstevel@tonic-gate 13547c478bd9Sstevel@tonic-gate if (vp->v_type != VREG) { 13557c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_INVAL; 1356e1adf50cSahl goto err1; 13577c478bd9Sstevel@tonic-gate } 13587c478bd9Sstevel@tonic-gate 13597c478bd9Sstevel@tonic-gate if (crgetuid(cr) != bva.va_uid && 1360cfae96c2Sjwahlig (error = VOP_ACCESS(vp, VWRITE, 0, cr, &ct))) 1361e1adf50cSahl goto err; 13627c478bd9Sstevel@tonic-gate 13637c478bd9Sstevel@tonic-gate if (MANDLOCK(vp, bva.va_mode)) { 13647c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_ACCES; 1365e1adf50cSahl goto err1; 13667c478bd9Sstevel@tonic-gate } 13677c478bd9Sstevel@tonic-gate 13687c478bd9Sstevel@tonic-gate if (args->count == 0) { 13697c478bd9Sstevel@tonic-gate resp->status = NFS3_OK; 13707c478bd9Sstevel@tonic-gate vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc); 13717c478bd9Sstevel@tonic-gate resp->resok.count = 0; 13727c478bd9Sstevel@tonic-gate resp->resok.committed = args->stable; 13737c478bd9Sstevel@tonic-gate resp->resok.verf = write3verf; 1374e1adf50cSahl goto out; 13757c478bd9Sstevel@tonic-gate } 13767c478bd9Sstevel@tonic-gate 13777c478bd9Sstevel@tonic-gate if (args->mblk != NULL) { 13787c478bd9Sstevel@tonic-gate iovcnt = 0; 13797c478bd9Sstevel@tonic-gate for (m = args->mblk; m != NULL; m = m->b_cont) 13807c478bd9Sstevel@tonic-gate iovcnt++; 13817c478bd9Sstevel@tonic-gate if (iovcnt <= MAX_IOVECS) { 13827c478bd9Sstevel@tonic-gate #ifdef DEBUG 13837c478bd9Sstevel@tonic-gate rfs3_write_hits++; 13847c478bd9Sstevel@tonic-gate #endif 13857c478bd9Sstevel@tonic-gate iovp = iov; 13867c478bd9Sstevel@tonic-gate } else { 13877c478bd9Sstevel@tonic-gate #ifdef DEBUG 13887c478bd9Sstevel@tonic-gate rfs3_write_misses++; 13897c478bd9Sstevel@tonic-gate #endif 13907c478bd9Sstevel@tonic-gate iovp = kmem_alloc(sizeof (*iovp) * iovcnt, KM_SLEEP); 13917c478bd9Sstevel@tonic-gate } 13927c478bd9Sstevel@tonic-gate mblk_to_iov(args->mblk, iovcnt, iovp); 13930a701b1eSRobert Gordon 13940a701b1eSRobert Gordon } else if (args->rlist != NULL) { 13950a701b1eSRobert Gordon iovcnt = 1; 13960a701b1eSRobert Gordon iovp = iov; 13970a701b1eSRobert Gordon iovp->iov_base = (char *)((args->rlist)->u.c_daddr3); 13980a701b1eSRobert Gordon iovp->iov_len = args->count; 13997c478bd9Sstevel@tonic-gate } else { 14007c478bd9Sstevel@tonic-gate iovcnt = 1; 14017c478bd9Sstevel@tonic-gate iovp = iov; 14027c478bd9Sstevel@tonic-gate iovp->iov_base = args->data.data_val; 14037c478bd9Sstevel@tonic-gate iovp->iov_len = args->count; 14047c478bd9Sstevel@tonic-gate } 14057c478bd9Sstevel@tonic-gate 14067c478bd9Sstevel@tonic-gate uio.uio_iov = iovp; 14077c478bd9Sstevel@tonic-gate uio.uio_iovcnt = iovcnt; 14087c478bd9Sstevel@tonic-gate 14097c478bd9Sstevel@tonic-gate uio.uio_segflg = UIO_SYSSPACE; 14107c478bd9Sstevel@tonic-gate uio.uio_extflg = UIO_COPY_DEFAULT; 14117c478bd9Sstevel@tonic-gate uio.uio_loffset = args->offset; 14127c478bd9Sstevel@tonic-gate uio.uio_resid = args->count; 14137c478bd9Sstevel@tonic-gate uio.uio_llimit = curproc->p_fsz_ctl; 14147c478bd9Sstevel@tonic-gate rlimit = uio.uio_llimit - args->offset; 14157c478bd9Sstevel@tonic-gate if (rlimit < (u_offset_t)uio.uio_resid) 14167c478bd9Sstevel@tonic-gate uio.uio_resid = (int)rlimit; 14177c478bd9Sstevel@tonic-gate 14187c478bd9Sstevel@tonic-gate if (args->stable == UNSTABLE) 14197c478bd9Sstevel@tonic-gate ioflag = 0; 14207c478bd9Sstevel@tonic-gate else if (args->stable == FILE_SYNC) 14217c478bd9Sstevel@tonic-gate ioflag = FSYNC; 14227c478bd9Sstevel@tonic-gate else if (args->stable == DATA_SYNC) 14237c478bd9Sstevel@tonic-gate ioflag = FDSYNC; 14247c478bd9Sstevel@tonic-gate else { 14257c478bd9Sstevel@tonic-gate if (iovp != iov) 14267c478bd9Sstevel@tonic-gate kmem_free(iovp, sizeof (*iovp) * iovcnt); 14277c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_INVAL; 1428e1adf50cSahl goto err1; 14297c478bd9Sstevel@tonic-gate } 14307c478bd9Sstevel@tonic-gate 14317c478bd9Sstevel@tonic-gate /* 14327c478bd9Sstevel@tonic-gate * We're changing creds because VM may fault and we need 14337c478bd9Sstevel@tonic-gate * the cred of the current thread to be used if quota 14347c478bd9Sstevel@tonic-gate * checking is enabled. 14357c478bd9Sstevel@tonic-gate */ 14367c478bd9Sstevel@tonic-gate savecred = curthread->t_cred; 14377c478bd9Sstevel@tonic-gate curthread->t_cred = cr; 1438cfae96c2Sjwahlig error = VOP_WRITE(vp, &uio, ioflag, cr, &ct); 14397c478bd9Sstevel@tonic-gate curthread->t_cred = savecred; 14407c478bd9Sstevel@tonic-gate 14417c478bd9Sstevel@tonic-gate if (iovp != iov) 14427c478bd9Sstevel@tonic-gate kmem_free(iovp, sizeof (*iovp) * iovcnt); 14437c478bd9Sstevel@tonic-gate 1444cfae96c2Sjwahlig /* check if a monitor detected a delegation conflict */ 1445cfae96c2Sjwahlig if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) { 1446cfae96c2Sjwahlig resp->status = NFS3ERR_JUKEBOX; 1447e1adf50cSahl goto err1; 1448cfae96c2Sjwahlig } 1449cfae96c2Sjwahlig 14507c478bd9Sstevel@tonic-gate ava.va_mask = AT_ALL; 1451cfae96c2Sjwahlig avap = VOP_GETATTR(vp, &ava, 0, cr, &ct) ? NULL : &ava; 14527c478bd9Sstevel@tonic-gate 14537c478bd9Sstevel@tonic-gate if (error) 1454e1adf50cSahl goto err; 14557c478bd9Sstevel@tonic-gate 14567c478bd9Sstevel@tonic-gate /* 14577c478bd9Sstevel@tonic-gate * If we were unable to get the V_WRITELOCK_TRUE, then we 14587c478bd9Sstevel@tonic-gate * may not have accurate after attrs, so check if 14597c478bd9Sstevel@tonic-gate * we have both attributes, they have a non-zero va_seq, and 14607c478bd9Sstevel@tonic-gate * va_seq has changed by exactly one, 14617c478bd9Sstevel@tonic-gate * if not, turn off the before attr. 14627c478bd9Sstevel@tonic-gate */ 14637c478bd9Sstevel@tonic-gate if (rwlock_ret != V_WRITELOCK_TRUE) { 14647c478bd9Sstevel@tonic-gate if (bvap == NULL || avap == NULL || 14657c478bd9Sstevel@tonic-gate bvap->va_seq == 0 || avap->va_seq == 0 || 14667c478bd9Sstevel@tonic-gate avap->va_seq != (bvap->va_seq + 1)) { 14677c478bd9Sstevel@tonic-gate bvap = NULL; 14687c478bd9Sstevel@tonic-gate } 14697c478bd9Sstevel@tonic-gate } 14707c478bd9Sstevel@tonic-gate 14717c478bd9Sstevel@tonic-gate resp->status = NFS3_OK; 14727c478bd9Sstevel@tonic-gate vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc); 14737c478bd9Sstevel@tonic-gate resp->resok.count = args->count - uio.uio_resid; 14747c478bd9Sstevel@tonic-gate resp->resok.committed = args->stable; 14757c478bd9Sstevel@tonic-gate resp->resok.verf = write3verf; 1476e1adf50cSahl goto out; 14777c478bd9Sstevel@tonic-gate 1478e1adf50cSahl err: 14797c478bd9Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK) { 14807c478bd9Sstevel@tonic-gate curthread->t_flag &= ~T_WOULDBLOCK; 14817c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX; 14827c478bd9Sstevel@tonic-gate } else 14837c478bd9Sstevel@tonic-gate resp->status = puterrno3(error); 1484e1adf50cSahl err1: 1485e1adf50cSahl vattr_to_wcc_data(bvap, avap, &resp->resfail.file_wcc); 1486e1adf50cSahl out: 1487e1adf50cSahl DTRACE_NFSV3_4(op__write__done, struct svc_req *, req, 1488e1adf50cSahl cred_t *, cr, vnode_t *, vp, WRITE3res *, resp); 1489e1adf50cSahl 14907c478bd9Sstevel@tonic-gate if (vp != NULL) { 14917c478bd9Sstevel@tonic-gate if (rwlock_ret != -1) 1492cfae96c2Sjwahlig VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, &ct); 14937c478bd9Sstevel@tonic-gate if (in_crit) 14947c478bd9Sstevel@tonic-gate nbl_end_crit(vp); 14957c478bd9Sstevel@tonic-gate VN_RELE(vp); 14967c478bd9Sstevel@tonic-gate } 14977c478bd9Sstevel@tonic-gate } 14987c478bd9Sstevel@tonic-gate 149927242a7cSthurlow void * 15007c478bd9Sstevel@tonic-gate rfs3_write_getfh(WRITE3args *args) 15017c478bd9Sstevel@tonic-gate { 15027c478bd9Sstevel@tonic-gate 150327242a7cSthurlow return (&args->file); 15047c478bd9Sstevel@tonic-gate } 15057c478bd9Sstevel@tonic-gate 15067c478bd9Sstevel@tonic-gate void 15077c478bd9Sstevel@tonic-gate rfs3_create(CREATE3args *args, CREATE3res *resp, struct exportinfo *exi, 15085cb0d679SMarcel Telka struct svc_req *req, cred_t *cr, bool_t ro) 15097c478bd9Sstevel@tonic-gate { 15107c478bd9Sstevel@tonic-gate int error; 15117c478bd9Sstevel@tonic-gate int in_crit = 0; 15127c478bd9Sstevel@tonic-gate vnode_t *vp; 15137c478bd9Sstevel@tonic-gate vnode_t *tvp = NULL; 15147c478bd9Sstevel@tonic-gate vnode_t *dvp; 15157c478bd9Sstevel@tonic-gate struct vattr *vap; 15167c478bd9Sstevel@tonic-gate struct vattr va; 15177c478bd9Sstevel@tonic-gate struct vattr *dbvap; 15187c478bd9Sstevel@tonic-gate struct vattr dbva; 15197c478bd9Sstevel@tonic-gate struct vattr *davap; 15207c478bd9Sstevel@tonic-gate struct vattr dava; 15217c478bd9Sstevel@tonic-gate enum vcexcl excl; 15227c478bd9Sstevel@tonic-gate nfstime3 *mtime; 15237c478bd9Sstevel@tonic-gate len_t reqsize; 15247c478bd9Sstevel@tonic-gate bool_t trunc; 1525b89a8333Snatalie li - Sun Microsystems - Irvine United States struct sockaddr *ca; 1526b89a8333Snatalie li - Sun Microsystems - Irvine United States char *name = NULL; 15277c478bd9Sstevel@tonic-gate 15287c478bd9Sstevel@tonic-gate dbvap = NULL; 15297c478bd9Sstevel@tonic-gate davap = NULL; 15307c478bd9Sstevel@tonic-gate 153127242a7cSthurlow dvp = nfs3_fhtovp(&args->where.dir, exi); 1532e1adf50cSahl 1533e1adf50cSahl DTRACE_NFSV3_4(op__create__start, struct svc_req *, req, 1534e1adf50cSahl cred_t *, cr, vnode_t *, dvp, CREATE3args *, args); 1535e1adf50cSahl 15367c478bd9Sstevel@tonic-gate if (dvp == NULL) { 15377c478bd9Sstevel@tonic-gate error = ESTALE; 15387c478bd9Sstevel@tonic-gate goto out; 15397c478bd9Sstevel@tonic-gate } 15407c478bd9Sstevel@tonic-gate 15417c478bd9Sstevel@tonic-gate dbva.va_mask = AT_ALL; 1542da6c28aaSamw dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva; 15437c478bd9Sstevel@tonic-gate davap = dbvap; 15447c478bd9Sstevel@tonic-gate 15457c478bd9Sstevel@tonic-gate if (args->where.name == nfs3nametoolong) { 15467c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_NAMETOOLONG; 15477c478bd9Sstevel@tonic-gate goto out1; 15487c478bd9Sstevel@tonic-gate } 15497c478bd9Sstevel@tonic-gate 15507c478bd9Sstevel@tonic-gate if (args->where.name == NULL || *(args->where.name) == '\0') { 15517c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_ACCES; 15527c478bd9Sstevel@tonic-gate goto out1; 15537c478bd9Sstevel@tonic-gate } 15547c478bd9Sstevel@tonic-gate 15555cb0d679SMarcel Telka if (rdonly(ro, dvp)) { 15567c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_ROFS; 15577c478bd9Sstevel@tonic-gate goto out1; 15587c478bd9Sstevel@tonic-gate } 15597c478bd9Sstevel@tonic-gate 156003986916Sjarrett if (is_system_labeled()) { 156103986916Sjarrett bslabel_t *clabel = req->rq_label; 156203986916Sjarrett 156303986916Sjarrett ASSERT(clabel != NULL); 156403986916Sjarrett DTRACE_PROBE2(tx__rfs3__log__info__opcreate__clabel, char *, 156503986916Sjarrett "got client label from request(1)", struct svc_req *, req); 156603986916Sjarrett 156703986916Sjarrett if (!blequal(&l_admin_low->tsl_label, clabel)) { 1568bd6f1640SJarrett Lu if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK, 1569bd6f1640SJarrett Lu exi)) { 157003986916Sjarrett resp->status = NFS3ERR_ACCES; 157103986916Sjarrett goto out1; 157203986916Sjarrett } 157303986916Sjarrett } 157403986916Sjarrett } 157503986916Sjarrett 1576b89a8333Snatalie li - Sun Microsystems - Irvine United States ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 1577b89a8333Snatalie li - Sun Microsystems - Irvine United States name = nfscmd_convname(ca, exi, args->where.name, 1578b89a8333Snatalie li - Sun Microsystems - Irvine United States NFSCMD_CONV_INBOUND, MAXPATHLEN + 1); 1579b89a8333Snatalie li - Sun Microsystems - Irvine United States 1580b89a8333Snatalie li - Sun Microsystems - Irvine United States if (name == NULL) { 1581b89a8333Snatalie li - Sun Microsystems - Irvine United States /* This is really a Solaris EILSEQ */ 1582b89a8333Snatalie li - Sun Microsystems - Irvine United States resp->status = NFS3ERR_INVAL; 1583b89a8333Snatalie li - Sun Microsystems - Irvine United States goto out1; 1584b89a8333Snatalie li - Sun Microsystems - Irvine United States } 1585b89a8333Snatalie li - Sun Microsystems - Irvine United States 15867c478bd9Sstevel@tonic-gate if (args->how.mode == EXCLUSIVE) { 15877c478bd9Sstevel@tonic-gate va.va_mask = AT_TYPE | AT_MODE | AT_MTIME; 15887c478bd9Sstevel@tonic-gate va.va_type = VREG; 15897c478bd9Sstevel@tonic-gate va.va_mode = (mode_t)0; 15907c478bd9Sstevel@tonic-gate /* 15917c478bd9Sstevel@tonic-gate * Ensure no time overflows and that types match 15927c478bd9Sstevel@tonic-gate */ 15937c478bd9Sstevel@tonic-gate mtime = (nfstime3 *)&args->how.createhow3_u.verf; 15947c478bd9Sstevel@tonic-gate va.va_mtime.tv_sec = mtime->seconds % INT32_MAX; 15957c478bd9Sstevel@tonic-gate va.va_mtime.tv_nsec = mtime->nseconds; 15967c478bd9Sstevel@tonic-gate excl = EXCL; 15977c478bd9Sstevel@tonic-gate } else { 15987c478bd9Sstevel@tonic-gate error = sattr3_to_vattr(&args->how.createhow3_u.obj_attributes, 15997c478bd9Sstevel@tonic-gate &va); 16007c478bd9Sstevel@tonic-gate if (error) 16017c478bd9Sstevel@tonic-gate goto out; 16027c478bd9Sstevel@tonic-gate va.va_mask |= AT_TYPE; 16037c478bd9Sstevel@tonic-gate va.va_type = VREG; 16047c478bd9Sstevel@tonic-gate if (args->how.mode == GUARDED) 16057c478bd9Sstevel@tonic-gate excl = EXCL; 16067c478bd9Sstevel@tonic-gate else { 16077c478bd9Sstevel@tonic-gate excl = NONEXCL; 16087c478bd9Sstevel@tonic-gate 16097c478bd9Sstevel@tonic-gate /* 16107c478bd9Sstevel@tonic-gate * During creation of file in non-exclusive mode 16117c478bd9Sstevel@tonic-gate * if size of file is being set then make sure 16127c478bd9Sstevel@tonic-gate * that if the file already exists that no conflicting 16137c478bd9Sstevel@tonic-gate * non-blocking mandatory locks exists in the region 16147c478bd9Sstevel@tonic-gate * being modified. If there are conflicting locks fail 16157c478bd9Sstevel@tonic-gate * the operation with EACCES. 16167c478bd9Sstevel@tonic-gate */ 16177c478bd9Sstevel@tonic-gate if (va.va_mask & AT_SIZE) { 16187c478bd9Sstevel@tonic-gate struct vattr tva; 16197c478bd9Sstevel@tonic-gate 16207c478bd9Sstevel@tonic-gate /* 16217c478bd9Sstevel@tonic-gate * Does file already exist? 16227c478bd9Sstevel@tonic-gate */ 1623b89a8333Snatalie li - Sun Microsystems - Irvine United States error = VOP_LOOKUP(dvp, name, &tvp, 1624da6c28aaSamw NULL, 0, NULL, cr, NULL, NULL, NULL); 16257c478bd9Sstevel@tonic-gate 16267c478bd9Sstevel@tonic-gate /* 16277c478bd9Sstevel@tonic-gate * Check to see if the file has been delegated 16287c478bd9Sstevel@tonic-gate * to a v4 client. If so, then begin recall of 16297c478bd9Sstevel@tonic-gate * the delegation and return JUKEBOX to allow 16307c478bd9Sstevel@tonic-gate * the client to retrasmit its request. 16317c478bd9Sstevel@tonic-gate */ 16327c478bd9Sstevel@tonic-gate 16337c478bd9Sstevel@tonic-gate trunc = va.va_size == 0; 16347c478bd9Sstevel@tonic-gate if (!error && 16357c478bd9Sstevel@tonic-gate rfs4_check_delegated(FWRITE, tvp, trunc)) { 16367c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX; 16377c478bd9Sstevel@tonic-gate goto out1; 16387c478bd9Sstevel@tonic-gate } 16397c478bd9Sstevel@tonic-gate 16407c478bd9Sstevel@tonic-gate /* 16417c478bd9Sstevel@tonic-gate * Check for NBMAND lock conflicts 16427c478bd9Sstevel@tonic-gate */ 16437c478bd9Sstevel@tonic-gate if (!error && nbl_need_check(tvp)) { 16447c478bd9Sstevel@tonic-gate u_offset_t offset; 16457c478bd9Sstevel@tonic-gate ssize_t len; 16467c478bd9Sstevel@tonic-gate 16477c478bd9Sstevel@tonic-gate nbl_start_crit(tvp, RW_READER); 16487c478bd9Sstevel@tonic-gate in_crit = 1; 16497c478bd9Sstevel@tonic-gate 16507c478bd9Sstevel@tonic-gate tva.va_mask = AT_SIZE; 1651da6c28aaSamw error = VOP_GETATTR(tvp, &tva, 0, cr, 1652da6c28aaSamw NULL); 16537c478bd9Sstevel@tonic-gate /* 16547c478bd9Sstevel@tonic-gate * Can't check for conflicts, so return 16557c478bd9Sstevel@tonic-gate * error. 16567c478bd9Sstevel@tonic-gate */ 16577c478bd9Sstevel@tonic-gate if (error) 16587c478bd9Sstevel@tonic-gate goto out; 16597c478bd9Sstevel@tonic-gate 16607c478bd9Sstevel@tonic-gate offset = tva.va_size < va.va_size ? 16617c478bd9Sstevel@tonic-gate tva.va_size : va.va_size; 16627c478bd9Sstevel@tonic-gate len = tva.va_size < va.va_size ? 16637c478bd9Sstevel@tonic-gate va.va_size - tva.va_size : 16647c478bd9Sstevel@tonic-gate tva.va_size - va.va_size; 16657c478bd9Sstevel@tonic-gate if (nbl_conflict(tvp, NBL_WRITE, 1666da6c28aaSamw offset, len, 0, NULL)) { 16677c478bd9Sstevel@tonic-gate error = EACCES; 16687c478bd9Sstevel@tonic-gate goto out; 16697c478bd9Sstevel@tonic-gate } 16707c478bd9Sstevel@tonic-gate } else if (tvp) { 16717c478bd9Sstevel@tonic-gate VN_RELE(tvp); 16727c478bd9Sstevel@tonic-gate tvp = NULL; 16737c478bd9Sstevel@tonic-gate } 16747c478bd9Sstevel@tonic-gate } 16757c478bd9Sstevel@tonic-gate } 16767c478bd9Sstevel@tonic-gate if (va.va_mask & AT_SIZE) 16777c478bd9Sstevel@tonic-gate reqsize = va.va_size; 16787c478bd9Sstevel@tonic-gate } 16797c478bd9Sstevel@tonic-gate 16807c478bd9Sstevel@tonic-gate /* 16817c478bd9Sstevel@tonic-gate * Must specify the mode. 16827c478bd9Sstevel@tonic-gate */ 16837c478bd9Sstevel@tonic-gate if (!(va.va_mask & AT_MODE)) { 16847c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_INVAL; 16857c478bd9Sstevel@tonic-gate goto out1; 16867c478bd9Sstevel@tonic-gate } 16877c478bd9Sstevel@tonic-gate 16887c478bd9Sstevel@tonic-gate /* 16897c478bd9Sstevel@tonic-gate * If the filesystem is exported with nosuid, then mask off 16907c478bd9Sstevel@tonic-gate * the setuid and setgid bits. 16917c478bd9Sstevel@tonic-gate */ 16927c478bd9Sstevel@tonic-gate if (va.va_type == VREG && (exi->exi_export.ex_flags & EX_NOSUID)) 16937c478bd9Sstevel@tonic-gate va.va_mode &= ~(VSUID | VSGID); 16947c478bd9Sstevel@tonic-gate 16957c478bd9Sstevel@tonic-gate tryagain: 16967c478bd9Sstevel@tonic-gate /* 16977c478bd9Sstevel@tonic-gate * The file open mode used is VWRITE. If the client needs 16987c478bd9Sstevel@tonic-gate * some other semantic, then it should do the access checking 16997c478bd9Sstevel@tonic-gate * itself. It would have been nice to have the file open mode 17007c478bd9Sstevel@tonic-gate * passed as part of the arguments. 17017c478bd9Sstevel@tonic-gate */ 1702b89a8333Snatalie li - Sun Microsystems - Irvine United States error = VOP_CREATE(dvp, name, &va, excl, VWRITE, 1703da6c28aaSamw &vp, cr, 0, NULL, NULL); 17047c478bd9Sstevel@tonic-gate 17057c478bd9Sstevel@tonic-gate dava.va_mask = AT_ALL; 1706da6c28aaSamw davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava; 17077c478bd9Sstevel@tonic-gate 17087c478bd9Sstevel@tonic-gate if (error) { 17097c478bd9Sstevel@tonic-gate /* 17107c478bd9Sstevel@tonic-gate * If we got something other than file already exists 17117c478bd9Sstevel@tonic-gate * then just return this error. Otherwise, we got 17127c478bd9Sstevel@tonic-gate * EEXIST. If we were doing a GUARDED create, then 17137c478bd9Sstevel@tonic-gate * just return this error. Otherwise, we need to 17147c478bd9Sstevel@tonic-gate * make sure that this wasn't a duplicate of an 17157c478bd9Sstevel@tonic-gate * exclusive create request. 17167c478bd9Sstevel@tonic-gate * 17177c478bd9Sstevel@tonic-gate * The assumption is made that a non-exclusive create 17187c478bd9Sstevel@tonic-gate * request will never return EEXIST. 17197c478bd9Sstevel@tonic-gate */ 17207c478bd9Sstevel@tonic-gate if (error != EEXIST || args->how.mode == GUARDED) 17217c478bd9Sstevel@tonic-gate goto out; 17227c478bd9Sstevel@tonic-gate /* 17237c478bd9Sstevel@tonic-gate * Lookup the file so that we can get a vnode for it. 17247c478bd9Sstevel@tonic-gate */ 1725b89a8333Snatalie li - Sun Microsystems - Irvine United States error = VOP_LOOKUP(dvp, name, &vp, NULL, 0, 1726da6c28aaSamw NULL, cr, NULL, NULL, NULL); 17277c478bd9Sstevel@tonic-gate if (error) { 17287c478bd9Sstevel@tonic-gate /* 17297c478bd9Sstevel@tonic-gate * We couldn't find the file that we thought that 17307c478bd9Sstevel@tonic-gate * we just created. So, we'll just try creating 17317c478bd9Sstevel@tonic-gate * it again. 17327c478bd9Sstevel@tonic-gate */ 17337c478bd9Sstevel@tonic-gate if (error == ENOENT) 17347c478bd9Sstevel@tonic-gate goto tryagain; 17357c478bd9Sstevel@tonic-gate goto out; 17367c478bd9Sstevel@tonic-gate } 17377c478bd9Sstevel@tonic-gate 17387c478bd9Sstevel@tonic-gate /* 17397c478bd9Sstevel@tonic-gate * If the file is delegated to a v4 client, go ahead 17407c478bd9Sstevel@tonic-gate * and initiate recall, this create is a hint that a 17417c478bd9Sstevel@tonic-gate * conflicting v3 open has occurred. 17427c478bd9Sstevel@tonic-gate */ 17437c478bd9Sstevel@tonic-gate 17447c478bd9Sstevel@tonic-gate if (rfs4_check_delegated(FWRITE, vp, FALSE)) { 17457c478bd9Sstevel@tonic-gate VN_RELE(vp); 17467c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX; 17477c478bd9Sstevel@tonic-gate goto out1; 17487c478bd9Sstevel@tonic-gate } 17497c478bd9Sstevel@tonic-gate 17507c478bd9Sstevel@tonic-gate va.va_mask = AT_ALL; 1751da6c28aaSamw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 17527c478bd9Sstevel@tonic-gate 17537c478bd9Sstevel@tonic-gate mtime = (nfstime3 *)&args->how.createhow3_u.verf; 17547c478bd9Sstevel@tonic-gate /* % with INT32_MAX to prevent overflows */ 17557c478bd9Sstevel@tonic-gate if (args->how.mode == EXCLUSIVE && (vap == NULL || 17567c478bd9Sstevel@tonic-gate vap->va_mtime.tv_sec != 17577c478bd9Sstevel@tonic-gate (mtime->seconds % INT32_MAX) || 17587c478bd9Sstevel@tonic-gate vap->va_mtime.tv_nsec != mtime->nseconds)) { 17597c478bd9Sstevel@tonic-gate VN_RELE(vp); 17607c478bd9Sstevel@tonic-gate error = EEXIST; 17617c478bd9Sstevel@tonic-gate goto out; 17627c478bd9Sstevel@tonic-gate } 17637c478bd9Sstevel@tonic-gate } else { 17647c478bd9Sstevel@tonic-gate 17657c478bd9Sstevel@tonic-gate if ((args->how.mode == UNCHECKED || 17667c478bd9Sstevel@tonic-gate args->how.mode == GUARDED) && 17677c478bd9Sstevel@tonic-gate args->how.createhow3_u.obj_attributes.size.set_it && 17687c478bd9Sstevel@tonic-gate va.va_size == 0) 17697c478bd9Sstevel@tonic-gate trunc = TRUE; 17707c478bd9Sstevel@tonic-gate else 17717c478bd9Sstevel@tonic-gate trunc = FALSE; 17727c478bd9Sstevel@tonic-gate 17737c478bd9Sstevel@tonic-gate if (rfs4_check_delegated(FWRITE, vp, trunc)) { 17747c478bd9Sstevel@tonic-gate VN_RELE(vp); 17757c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX; 17767c478bd9Sstevel@tonic-gate goto out1; 17777c478bd9Sstevel@tonic-gate } 17787c478bd9Sstevel@tonic-gate 17797c478bd9Sstevel@tonic-gate va.va_mask = AT_ALL; 1780da6c28aaSamw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 17817c478bd9Sstevel@tonic-gate 17827c478bd9Sstevel@tonic-gate /* 17837c478bd9Sstevel@tonic-gate * We need to check to make sure that the file got 17847c478bd9Sstevel@tonic-gate * created to the indicated size. If not, we do a 17857c478bd9Sstevel@tonic-gate * setattr to try to change the size, but we don't 17867c478bd9Sstevel@tonic-gate * try too hard. This shouldn't a problem as most 17877c478bd9Sstevel@tonic-gate * clients will only specifiy a size of zero which 17887c478bd9Sstevel@tonic-gate * local file systems handle. However, even if 17897c478bd9Sstevel@tonic-gate * the client does specify a non-zero size, it can 17907c478bd9Sstevel@tonic-gate * still recover by checking the size of the file 17917c478bd9Sstevel@tonic-gate * after it has created it and then issue a setattr 17927c478bd9Sstevel@tonic-gate * request of its own to set the size of the file. 17937c478bd9Sstevel@tonic-gate */ 17947c478bd9Sstevel@tonic-gate if (vap != NULL && 17957c478bd9Sstevel@tonic-gate (args->how.mode == UNCHECKED || 17967c478bd9Sstevel@tonic-gate args->how.mode == GUARDED) && 17977c478bd9Sstevel@tonic-gate args->how.createhow3_u.obj_attributes.size.set_it && 17987c478bd9Sstevel@tonic-gate vap->va_size != reqsize) { 17997c478bd9Sstevel@tonic-gate va.va_mask = AT_SIZE; 18007c478bd9Sstevel@tonic-gate va.va_size = reqsize; 18017c478bd9Sstevel@tonic-gate (void) VOP_SETATTR(vp, &va, 0, cr, NULL); 18027c478bd9Sstevel@tonic-gate va.va_mask = AT_ALL; 1803da6c28aaSamw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 18047c478bd9Sstevel@tonic-gate } 18057c478bd9Sstevel@tonic-gate } 18067c478bd9Sstevel@tonic-gate 1807b89a8333Snatalie li - Sun Microsystems - Irvine United States if (name != args->where.name) 1808b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(name, MAXPATHLEN + 1); 1809b89a8333Snatalie li - Sun Microsystems - Irvine United States 18107c478bd9Sstevel@tonic-gate error = makefh3(&resp->resok.obj.handle, vp, exi); 18117c478bd9Sstevel@tonic-gate if (error) 18127c478bd9Sstevel@tonic-gate resp->resok.obj.handle_follows = FALSE; 18137c478bd9Sstevel@tonic-gate else 18147c478bd9Sstevel@tonic-gate resp->resok.obj.handle_follows = TRUE; 18157c478bd9Sstevel@tonic-gate 18167c478bd9Sstevel@tonic-gate /* 18177c478bd9Sstevel@tonic-gate * Force modified data and metadata out to stable storage. 18187c478bd9Sstevel@tonic-gate */ 1819da6c28aaSamw (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL); 1820da6c28aaSamw (void) VOP_FSYNC(dvp, 0, cr, NULL); 18217c478bd9Sstevel@tonic-gate 18227c478bd9Sstevel@tonic-gate VN_RELE(vp); 18237c478bd9Sstevel@tonic-gate if (tvp != NULL) { 18247c478bd9Sstevel@tonic-gate if (in_crit) 18257c478bd9Sstevel@tonic-gate nbl_end_crit(tvp); 18267c478bd9Sstevel@tonic-gate VN_RELE(tvp); 18277c478bd9Sstevel@tonic-gate } 18287c478bd9Sstevel@tonic-gate 18297c478bd9Sstevel@tonic-gate resp->status = NFS3_OK; 18307c478bd9Sstevel@tonic-gate vattr_to_post_op_attr(vap, &resp->resok.obj_attributes); 18317c478bd9Sstevel@tonic-gate vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc); 1832e1adf50cSahl 1833e1adf50cSahl DTRACE_NFSV3_4(op__create__done, struct svc_req *, req, 1834e1adf50cSahl cred_t *, cr, vnode_t *, dvp, CREATE3res *, resp); 1835e1adf50cSahl 1836e1adf50cSahl VN_RELE(dvp); 18377c478bd9Sstevel@tonic-gate return; 18387c478bd9Sstevel@tonic-gate 18397c478bd9Sstevel@tonic-gate out: 18407c478bd9Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK) { 18417c478bd9Sstevel@tonic-gate curthread->t_flag &= ~T_WOULDBLOCK; 18427c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX; 18437c478bd9Sstevel@tonic-gate } else 18447c478bd9Sstevel@tonic-gate resp->status = puterrno3(error); 18457c478bd9Sstevel@tonic-gate out1: 1846e1adf50cSahl DTRACE_NFSV3_4(op__create__done, struct svc_req *, req, 1847e1adf50cSahl cred_t *, cr, vnode_t *, dvp, CREATE3res *, resp); 1848e1adf50cSahl 1849b89a8333Snatalie li - Sun Microsystems - Irvine United States if (name != NULL && name != args->where.name) 1850b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(name, MAXPATHLEN + 1); 1851b89a8333Snatalie li - Sun Microsystems - Irvine United States 18527c478bd9Sstevel@tonic-gate if (tvp != NULL) { 18537c478bd9Sstevel@tonic-gate if (in_crit) 18547c478bd9Sstevel@tonic-gate nbl_end_crit(tvp); 18557c478bd9Sstevel@tonic-gate VN_RELE(tvp); 18567c478bd9Sstevel@tonic-gate } 18577c478bd9Sstevel@tonic-gate if (dvp != NULL) 18587c478bd9Sstevel@tonic-gate VN_RELE(dvp); 18597c478bd9Sstevel@tonic-gate vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc); 18607c478bd9Sstevel@tonic-gate } 18617c478bd9Sstevel@tonic-gate 186227242a7cSthurlow void * 18637c478bd9Sstevel@tonic-gate rfs3_create_getfh(CREATE3args *args) 18647c478bd9Sstevel@tonic-gate { 18657c478bd9Sstevel@tonic-gate 186627242a7cSthurlow return (&args->where.dir); 18677c478bd9Sstevel@tonic-gate } 18687c478bd9Sstevel@tonic-gate 18697c478bd9Sstevel@tonic-gate void 18707c478bd9Sstevel@tonic-gate rfs3_mkdir(MKDIR3args *args, MKDIR3res *resp, struct exportinfo *exi, 18715cb0d679SMarcel Telka struct svc_req *req, cred_t *cr, bool_t ro) 18727c478bd9Sstevel@tonic-gate { 18737c478bd9Sstevel@tonic-gate int error; 18747c478bd9Sstevel@tonic-gate vnode_t *vp = NULL; 18757c478bd9Sstevel@tonic-gate vnode_t *dvp; 18767c478bd9Sstevel@tonic-gate struct vattr *vap; 18777c478bd9Sstevel@tonic-gate struct vattr va; 18787c478bd9Sstevel@tonic-gate struct vattr *dbvap; 18797c478bd9Sstevel@tonic-gate struct vattr dbva; 18807c478bd9Sstevel@tonic-gate struct vattr *davap; 18817c478bd9Sstevel@tonic-gate struct vattr dava; 1882b89a8333Snatalie li - Sun Microsystems - Irvine United States struct sockaddr *ca; 1883b89a8333Snatalie li - Sun Microsystems - Irvine United States char *name = NULL; 18847c478bd9Sstevel@tonic-gate 18857c478bd9Sstevel@tonic-gate dbvap = NULL; 18867c478bd9Sstevel@tonic-gate davap = NULL; 18877c478bd9Sstevel@tonic-gate 188827242a7cSthurlow dvp = nfs3_fhtovp(&args->where.dir, exi); 1889e1adf50cSahl 1890e1adf50cSahl DTRACE_NFSV3_4(op__mkdir__start, struct svc_req *, req, 1891e1adf50cSahl cred_t *, cr, vnode_t *, dvp, MKDIR3args *, args); 1892e1adf50cSahl 18937c478bd9Sstevel@tonic-gate if (dvp == NULL) { 18947c478bd9Sstevel@tonic-gate error = ESTALE; 18957c478bd9Sstevel@tonic-gate goto out; 18967c478bd9Sstevel@tonic-gate } 18977c478bd9Sstevel@tonic-gate 18987c478bd9Sstevel@tonic-gate dbva.va_mask = AT_ALL; 1899da6c28aaSamw dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva; 19007c478bd9Sstevel@tonic-gate davap = dbvap; 19017c478bd9Sstevel@tonic-gate 19027c478bd9Sstevel@tonic-gate if (args->where.name == nfs3nametoolong) { 19037c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_NAMETOOLONG; 19047c478bd9Sstevel@tonic-gate goto out1; 19057c478bd9Sstevel@tonic-gate } 19067c478bd9Sstevel@tonic-gate 19077c478bd9Sstevel@tonic-gate if (args->where.name == NULL || *(args->where.name) == '\0') { 19087c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_ACCES; 19097c478bd9Sstevel@tonic-gate goto out1; 19107c478bd9Sstevel@tonic-gate } 19117c478bd9Sstevel@tonic-gate 19125cb0d679SMarcel Telka if (rdonly(ro, dvp)) { 19137c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_ROFS; 19147c478bd9Sstevel@tonic-gate goto out1; 19157c478bd9Sstevel@tonic-gate } 19167c478bd9Sstevel@tonic-gate 191703986916Sjarrett if (is_system_labeled()) { 191803986916Sjarrett bslabel_t *clabel = req->rq_label; 191903986916Sjarrett 192003986916Sjarrett ASSERT(clabel != NULL); 192103986916Sjarrett DTRACE_PROBE2(tx__rfs3__log__info__opmkdir__clabel, char *, 192203986916Sjarrett "got client label from request(1)", struct svc_req *, req); 192303986916Sjarrett 192403986916Sjarrett if (!blequal(&l_admin_low->tsl_label, clabel)) { 1925bd6f1640SJarrett Lu if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK, 1926bd6f1640SJarrett Lu exi)) { 192703986916Sjarrett resp->status = NFS3ERR_ACCES; 192803986916Sjarrett goto out1; 192903986916Sjarrett } 193003986916Sjarrett } 193103986916Sjarrett } 193203986916Sjarrett 19337c478bd9Sstevel@tonic-gate error = sattr3_to_vattr(&args->attributes, &va); 19347c478bd9Sstevel@tonic-gate if (error) 19357c478bd9Sstevel@tonic-gate goto out; 19367c478bd9Sstevel@tonic-gate 19377c478bd9Sstevel@tonic-gate if (!(va.va_mask & AT_MODE)) { 19387c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_INVAL; 19397c478bd9Sstevel@tonic-gate goto out1; 19407c478bd9Sstevel@tonic-gate } 19417c478bd9Sstevel@tonic-gate 1942b89a8333Snatalie li - Sun Microsystems - Irvine United States ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 1943b89a8333Snatalie li - Sun Microsystems - Irvine United States name = nfscmd_convname(ca, exi, args->where.name, 1944b89a8333Snatalie li - Sun Microsystems - Irvine United States NFSCMD_CONV_INBOUND, MAXPATHLEN + 1); 1945b89a8333Snatalie li - Sun Microsystems - Irvine United States 1946b89a8333Snatalie li - Sun Microsystems - Irvine United States if (name == NULL) { 1947b89a8333Snatalie li - Sun Microsystems - Irvine United States resp->status = NFS3ERR_INVAL; 1948b89a8333Snatalie li - Sun Microsystems - Irvine United States goto out1; 1949b89a8333Snatalie li - Sun Microsystems - Irvine United States } 1950b89a8333Snatalie li - Sun Microsystems - Irvine United States 19517c478bd9Sstevel@tonic-gate va.va_mask |= AT_TYPE; 19527c478bd9Sstevel@tonic-gate va.va_type = VDIR; 19537c478bd9Sstevel@tonic-gate 1954b89a8333Snatalie li - Sun Microsystems - Irvine United States error = VOP_MKDIR(dvp, name, &va, &vp, cr, NULL, 0, NULL); 1955b89a8333Snatalie li - Sun Microsystems - Irvine United States 1956b89a8333Snatalie li - Sun Microsystems - Irvine United States if (name != args->where.name) 1957b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(name, MAXPATHLEN + 1); 19587c478bd9Sstevel@tonic-gate 19597c478bd9Sstevel@tonic-gate dava.va_mask = AT_ALL; 1960da6c28aaSamw davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava; 19617c478bd9Sstevel@tonic-gate 19627c478bd9Sstevel@tonic-gate /* 19637c478bd9Sstevel@tonic-gate * Force modified data and metadata out to stable storage. 19647c478bd9Sstevel@tonic-gate */ 1965da6c28aaSamw (void) VOP_FSYNC(dvp, 0, cr, NULL); 19667c478bd9Sstevel@tonic-gate 19677c478bd9Sstevel@tonic-gate if (error) 19687c478bd9Sstevel@tonic-gate goto out; 19697c478bd9Sstevel@tonic-gate 19707c478bd9Sstevel@tonic-gate error = makefh3(&resp->resok.obj.handle, vp, exi); 19717c478bd9Sstevel@tonic-gate if (error) 19727c478bd9Sstevel@tonic-gate resp->resok.obj.handle_follows = FALSE; 19737c478bd9Sstevel@tonic-gate else 19747c478bd9Sstevel@tonic-gate resp->resok.obj.handle_follows = TRUE; 19757c478bd9Sstevel@tonic-gate 19767c478bd9Sstevel@tonic-gate va.va_mask = AT_ALL; 1977da6c28aaSamw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 19787c478bd9Sstevel@tonic-gate 19797c478bd9Sstevel@tonic-gate /* 19807c478bd9Sstevel@tonic-gate * Force modified data and metadata out to stable storage. 19817c478bd9Sstevel@tonic-gate */ 1982da6c28aaSamw (void) VOP_FSYNC(vp, 0, cr, NULL); 19837c478bd9Sstevel@tonic-gate 19847c478bd9Sstevel@tonic-gate VN_RELE(vp); 19857c478bd9Sstevel@tonic-gate 19867c478bd9Sstevel@tonic-gate resp->status = NFS3_OK; 19877c478bd9Sstevel@tonic-gate vattr_to_post_op_attr(vap, &resp->resok.obj_attributes); 19887c478bd9Sstevel@tonic-gate vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc); 1989e1adf50cSahl 1990e1adf50cSahl DTRACE_NFSV3_4(op__mkdir__done, struct svc_req *, req, 1991e1adf50cSahl cred_t *, cr, vnode_t *, dvp, MKDIR3res *, resp); 1992e1adf50cSahl VN_RELE(dvp); 1993e1adf50cSahl 19947c478bd9Sstevel@tonic-gate return; 19957c478bd9Sstevel@tonic-gate 19967c478bd9Sstevel@tonic-gate out: 19977c478bd9Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK) { 19987c478bd9Sstevel@tonic-gate curthread->t_flag &= ~T_WOULDBLOCK; 19997c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX; 20007c478bd9Sstevel@tonic-gate } else 20017c478bd9Sstevel@tonic-gate resp->status = puterrno3(error); 20027c478bd9Sstevel@tonic-gate out1: 2003e1adf50cSahl DTRACE_NFSV3_4(op__mkdir__done, struct svc_req *, req, 2004e1adf50cSahl cred_t *, cr, vnode_t *, dvp, MKDIR3res *, resp); 20057c478bd9Sstevel@tonic-gate if (dvp != NULL) 20067c478bd9Sstevel@tonic-gate VN_RELE(dvp); 20077c478bd9Sstevel@tonic-gate vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc); 20087c478bd9Sstevel@tonic-gate } 20097c478bd9Sstevel@tonic-gate 201027242a7cSthurlow void * 20117c478bd9Sstevel@tonic-gate rfs3_mkdir_getfh(MKDIR3args *args) 20127c478bd9Sstevel@tonic-gate { 20137c478bd9Sstevel@tonic-gate 201427242a7cSthurlow return (&args->where.dir); 20157c478bd9Sstevel@tonic-gate } 20167c478bd9Sstevel@tonic-gate 20177c478bd9Sstevel@tonic-gate void 20187c478bd9Sstevel@tonic-gate rfs3_symlink(SYMLINK3args *args, SYMLINK3res *resp, struct exportinfo *exi, 20195cb0d679SMarcel Telka struct svc_req *req, cred_t *cr, bool_t ro) 20207c478bd9Sstevel@tonic-gate { 20217c478bd9Sstevel@tonic-gate int error; 20227c478bd9Sstevel@tonic-gate vnode_t *vp; 20237c478bd9Sstevel@tonic-gate vnode_t *dvp; 20247c478bd9Sstevel@tonic-gate struct vattr *vap; 20257c478bd9Sstevel@tonic-gate struct vattr va; 20267c478bd9Sstevel@tonic-gate struct vattr *dbvap; 20277c478bd9Sstevel@tonic-gate struct vattr dbva; 20287c478bd9Sstevel@tonic-gate struct vattr *davap; 20297c478bd9Sstevel@tonic-gate struct vattr dava; 2030b89a8333Snatalie li - Sun Microsystems - Irvine United States struct sockaddr *ca; 2031b89a8333Snatalie li - Sun Microsystems - Irvine United States char *name = NULL; 2032b89a8333Snatalie li - Sun Microsystems - Irvine United States char *symdata = NULL; 20337c478bd9Sstevel@tonic-gate 20347c478bd9Sstevel@tonic-gate dbvap = NULL; 20357c478bd9Sstevel@tonic-gate davap = NULL; 20367c478bd9Sstevel@tonic-gate 203727242a7cSthurlow dvp = nfs3_fhtovp(&args->where.dir, exi); 2038e1adf50cSahl 2039e1adf50cSahl DTRACE_NFSV3_4(op__symlink__start, struct svc_req *, req, 2040e1adf50cSahl cred_t *, cr, vnode_t *, dvp, SYMLINK3args *, args); 2041e1adf50cSahl 20427c478bd9Sstevel@tonic-gate if (dvp == NULL) { 20437c478bd9Sstevel@tonic-gate error = ESTALE; 2044e1adf50cSahl goto err; 20457c478bd9Sstevel@tonic-gate } 20467c478bd9Sstevel@tonic-gate 20477c478bd9Sstevel@tonic-gate dbva.va_mask = AT_ALL; 2048da6c28aaSamw dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva; 20497c478bd9Sstevel@tonic-gate davap = dbvap; 20507c478bd9Sstevel@tonic-gate 20517c478bd9Sstevel@tonic-gate if (args->where.name == nfs3nametoolong) { 20527c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_NAMETOOLONG; 2053e1adf50cSahl goto err1; 20547c478bd9Sstevel@tonic-gate } 20557c478bd9Sstevel@tonic-gate 20567c478bd9Sstevel@tonic-gate if (args->where.name == NULL || *(args->where.name) == '\0') { 20577c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_ACCES; 2058e1adf50cSahl goto err1; 20597c478bd9Sstevel@tonic-gate } 20607c478bd9Sstevel@tonic-gate 20615cb0d679SMarcel Telka if (rdonly(ro, dvp)) { 20627c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_ROFS; 2063e1adf50cSahl goto err1; 20647c478bd9Sstevel@tonic-gate } 20657c478bd9Sstevel@tonic-gate 206603986916Sjarrett if (is_system_labeled()) { 206703986916Sjarrett bslabel_t *clabel = req->rq_label; 206803986916Sjarrett 206903986916Sjarrett ASSERT(clabel != NULL); 207003986916Sjarrett DTRACE_PROBE2(tx__rfs3__log__info__opsymlink__clabel, char *, 207103986916Sjarrett "got client label from request(1)", struct svc_req *, req); 207203986916Sjarrett 207303986916Sjarrett if (!blequal(&l_admin_low->tsl_label, clabel)) { 2074bd6f1640SJarrett Lu if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK, 2075bd6f1640SJarrett Lu exi)) { 207603986916Sjarrett resp->status = NFS3ERR_ACCES; 2077e1adf50cSahl goto err1; 207803986916Sjarrett } 207903986916Sjarrett } 208003986916Sjarrett } 208103986916Sjarrett 20827c478bd9Sstevel@tonic-gate error = sattr3_to_vattr(&args->symlink.symlink_attributes, &va); 20837c478bd9Sstevel@tonic-gate if (error) 2084e1adf50cSahl goto err; 20857c478bd9Sstevel@tonic-gate 20867c478bd9Sstevel@tonic-gate if (!(va.va_mask & AT_MODE)) { 20877c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_INVAL; 2088e1adf50cSahl goto err1; 20897c478bd9Sstevel@tonic-gate } 20907c478bd9Sstevel@tonic-gate 20917c478bd9Sstevel@tonic-gate if (args->symlink.symlink_data == nfs3nametoolong) { 20927c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_NAMETOOLONG; 2093e1adf50cSahl goto err1; 20947c478bd9Sstevel@tonic-gate } 20957c478bd9Sstevel@tonic-gate 2096b89a8333Snatalie li - Sun Microsystems - Irvine United States ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 2097b89a8333Snatalie li - Sun Microsystems - Irvine United States name = nfscmd_convname(ca, exi, args->where.name, 2098b89a8333Snatalie li - Sun Microsystems - Irvine United States NFSCMD_CONV_INBOUND, MAXPATHLEN + 1); 2099b89a8333Snatalie li - Sun Microsystems - Irvine United States 2100b89a8333Snatalie li - Sun Microsystems - Irvine United States if (name == NULL) { 2101b89a8333Snatalie li - Sun Microsystems - Irvine United States /* This is really a Solaris EILSEQ */ 2102b89a8333Snatalie li - Sun Microsystems - Irvine United States resp->status = NFS3ERR_INVAL; 2103b89a8333Snatalie li - Sun Microsystems - Irvine United States goto err1; 2104b89a8333Snatalie li - Sun Microsystems - Irvine United States } 2105b89a8333Snatalie li - Sun Microsystems - Irvine United States 2106b89a8333Snatalie li - Sun Microsystems - Irvine United States symdata = nfscmd_convname(ca, exi, args->symlink.symlink_data, 2107b89a8333Snatalie li - Sun Microsystems - Irvine United States NFSCMD_CONV_INBOUND, MAXPATHLEN + 1); 2108b89a8333Snatalie li - Sun Microsystems - Irvine United States if (symdata == NULL) { 2109b89a8333Snatalie li - Sun Microsystems - Irvine United States /* This is really a Solaris EILSEQ */ 2110b89a8333Snatalie li - Sun Microsystems - Irvine United States resp->status = NFS3ERR_INVAL; 2111b89a8333Snatalie li - Sun Microsystems - Irvine United States goto err1; 2112b89a8333Snatalie li - Sun Microsystems - Irvine United States } 2113b89a8333Snatalie li - Sun Microsystems - Irvine United States 2114b89a8333Snatalie li - Sun Microsystems - Irvine United States 21157c478bd9Sstevel@tonic-gate va.va_mask |= AT_TYPE; 21167c478bd9Sstevel@tonic-gate va.va_type = VLNK; 21177c478bd9Sstevel@tonic-gate 2118b89a8333Snatalie li - Sun Microsystems - Irvine United States error = VOP_SYMLINK(dvp, name, &va, symdata, cr, NULL, 0); 21197c478bd9Sstevel@tonic-gate 21207c478bd9Sstevel@tonic-gate dava.va_mask = AT_ALL; 2121da6c28aaSamw davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava; 21227c478bd9Sstevel@tonic-gate 21237c478bd9Sstevel@tonic-gate if (error) 2124e1adf50cSahl goto err; 21257c478bd9Sstevel@tonic-gate 2126b89a8333Snatalie li - Sun Microsystems - Irvine United States error = VOP_LOOKUP(dvp, name, &vp, NULL, 0, NULL, cr, 2127da6c28aaSamw NULL, NULL, NULL); 21287c478bd9Sstevel@tonic-gate 21297c478bd9Sstevel@tonic-gate /* 21307c478bd9Sstevel@tonic-gate * Force modified data and metadata out to stable storage. 21317c478bd9Sstevel@tonic-gate */ 2132da6c28aaSamw (void) VOP_FSYNC(dvp, 0, cr, NULL); 21337c478bd9Sstevel@tonic-gate 21347c478bd9Sstevel@tonic-gate 21357c478bd9Sstevel@tonic-gate resp->status = NFS3_OK; 21367c478bd9Sstevel@tonic-gate if (error) { 21377c478bd9Sstevel@tonic-gate resp->resok.obj.handle_follows = FALSE; 21387c478bd9Sstevel@tonic-gate vattr_to_post_op_attr(NULL, &resp->resok.obj_attributes); 21397c478bd9Sstevel@tonic-gate vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc); 2140e1adf50cSahl goto out; 21417c478bd9Sstevel@tonic-gate } 21427c478bd9Sstevel@tonic-gate 21437c478bd9Sstevel@tonic-gate error = makefh3(&resp->resok.obj.handle, vp, exi); 21447c478bd9Sstevel@tonic-gate if (error) 21457c478bd9Sstevel@tonic-gate resp->resok.obj.handle_follows = FALSE; 21467c478bd9Sstevel@tonic-gate else 21477c478bd9Sstevel@tonic-gate resp->resok.obj.handle_follows = TRUE; 21487c478bd9Sstevel@tonic-gate 21497c478bd9Sstevel@tonic-gate va.va_mask = AT_ALL; 2150da6c28aaSamw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 21517c478bd9Sstevel@tonic-gate 21527c478bd9Sstevel@tonic-gate /* 21537c478bd9Sstevel@tonic-gate * Force modified data and metadata out to stable storage. 21547c478bd9Sstevel@tonic-gate */ 2155da6c28aaSamw (void) VOP_FSYNC(vp, 0, cr, NULL); 21567c478bd9Sstevel@tonic-gate 21577c478bd9Sstevel@tonic-gate VN_RELE(vp); 21587c478bd9Sstevel@tonic-gate 21597c478bd9Sstevel@tonic-gate vattr_to_post_op_attr(vap, &resp->resok.obj_attributes); 21607c478bd9Sstevel@tonic-gate vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc); 2161e1adf50cSahl goto out; 21627c478bd9Sstevel@tonic-gate 2163e1adf50cSahl err: 21647c478bd9Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK) { 21657c478bd9Sstevel@tonic-gate curthread->t_flag &= ~T_WOULDBLOCK; 21667c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX; 21677c478bd9Sstevel@tonic-gate } else 21687c478bd9Sstevel@tonic-gate resp->status = puterrno3(error); 2169e1adf50cSahl err1: 2170e1adf50cSahl vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc); 2171e1adf50cSahl out: 2172b89a8333Snatalie li - Sun Microsystems - Irvine United States if (name != NULL && name != args->where.name) 2173b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(name, MAXPATHLEN + 1); 2174b89a8333Snatalie li - Sun Microsystems - Irvine United States if (symdata != NULL && symdata != args->symlink.symlink_data) 2175b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(symdata, MAXPATHLEN + 1); 2176b89a8333Snatalie li - Sun Microsystems - Irvine United States 2177e1adf50cSahl DTRACE_NFSV3_4(op__symlink__done, struct svc_req *, req, 2178e1adf50cSahl cred_t *, cr, vnode_t *, dvp, SYMLINK3res *, resp); 2179e1adf50cSahl 21807c478bd9Sstevel@tonic-gate if (dvp != NULL) 21817c478bd9Sstevel@tonic-gate VN_RELE(dvp); 21827c478bd9Sstevel@tonic-gate } 21837c478bd9Sstevel@tonic-gate 218427242a7cSthurlow void * 21857c478bd9Sstevel@tonic-gate rfs3_symlink_getfh(SYMLINK3args *args) 21867c478bd9Sstevel@tonic-gate { 21877c478bd9Sstevel@tonic-gate 218827242a7cSthurlow return (&args->where.dir); 21897c478bd9Sstevel@tonic-gate } 21907c478bd9Sstevel@tonic-gate 21917c478bd9Sstevel@tonic-gate void 21927c478bd9Sstevel@tonic-gate rfs3_mknod(MKNOD3args *args, MKNOD3res *resp, struct exportinfo *exi, 21935cb0d679SMarcel Telka struct svc_req *req, cred_t *cr, bool_t ro) 21947c478bd9Sstevel@tonic-gate { 21957c478bd9Sstevel@tonic-gate int error; 21967c478bd9Sstevel@tonic-gate vnode_t *vp; 2197fd7da618Sgt29601 vnode_t *realvp; 21987c478bd9Sstevel@tonic-gate vnode_t *dvp; 21997c478bd9Sstevel@tonic-gate struct vattr *vap; 22007c478bd9Sstevel@tonic-gate struct vattr va; 22017c478bd9Sstevel@tonic-gate struct vattr *dbvap; 22027c478bd9Sstevel@tonic-gate struct vattr dbva; 22037c478bd9Sstevel@tonic-gate struct vattr *davap; 22047c478bd9Sstevel@tonic-gate struct vattr dava; 22057c478bd9Sstevel@tonic-gate int mode; 22067c478bd9Sstevel@tonic-gate enum vcexcl excl; 2207b89a8333Snatalie li - Sun Microsystems - Irvine United States struct sockaddr *ca; 2208b89a8333Snatalie li - Sun Microsystems - Irvine United States char *name = NULL; 22097c478bd9Sstevel@tonic-gate 22107c478bd9Sstevel@tonic-gate dbvap = NULL; 22117c478bd9Sstevel@tonic-gate davap = NULL; 22127c478bd9Sstevel@tonic-gate 221327242a7cSthurlow dvp = nfs3_fhtovp(&args->where.dir, exi); 2214e1adf50cSahl 2215e1adf50cSahl DTRACE_NFSV3_4(op__mknod__start, struct svc_req *, req, 2216e1adf50cSahl cred_t *, cr, vnode_t *, dvp, MKNOD3args *, args); 2217e1adf50cSahl 22187c478bd9Sstevel@tonic-gate if (dvp == NULL) { 22197c478bd9Sstevel@tonic-gate error = ESTALE; 22207c478bd9Sstevel@tonic-gate goto out; 22217c478bd9Sstevel@tonic-gate } 22227c478bd9Sstevel@tonic-gate 22237c478bd9Sstevel@tonic-gate dbva.va_mask = AT_ALL; 2224da6c28aaSamw dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva; 22257c478bd9Sstevel@tonic-gate davap = dbvap; 22267c478bd9Sstevel@tonic-gate 22277c478bd9Sstevel@tonic-gate if (args->where.name == nfs3nametoolong) { 22287c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_NAMETOOLONG; 22297c478bd9Sstevel@tonic-gate goto out1; 22307c478bd9Sstevel@tonic-gate } 22317c478bd9Sstevel@tonic-gate 22327c478bd9Sstevel@tonic-gate if (args->where.name == NULL || *(args->where.name) == '\0') { 22337c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_ACCES; 22347c478bd9Sstevel@tonic-gate goto out1; 22357c478bd9Sstevel@tonic-gate } 22367c478bd9Sstevel@tonic-gate 22375cb0d679SMarcel Telka if (rdonly(ro, dvp)) { 22387c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_ROFS; 22397c478bd9Sstevel@tonic-gate goto out1; 22407c478bd9Sstevel@tonic-gate } 22417c478bd9Sstevel@tonic-gate 224203986916Sjarrett if (is_system_labeled()) { 224303986916Sjarrett bslabel_t *clabel = req->rq_label; 224403986916Sjarrett 224503986916Sjarrett ASSERT(clabel != NULL); 224603986916Sjarrett DTRACE_PROBE2(tx__rfs3__log__info__opmknod__clabel, char *, 224703986916Sjarrett "got client label from request(1)", struct svc_req *, req); 224803986916Sjarrett 224903986916Sjarrett if (!blequal(&l_admin_low->tsl_label, clabel)) { 2250bd6f1640SJarrett Lu if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK, 2251bd6f1640SJarrett Lu exi)) { 225203986916Sjarrett resp->status = NFS3ERR_ACCES; 225303986916Sjarrett goto out1; 225403986916Sjarrett } 225503986916Sjarrett } 225603986916Sjarrett } 225703986916Sjarrett 22587c478bd9Sstevel@tonic-gate switch (args->what.type) { 22597c478bd9Sstevel@tonic-gate case NF3CHR: 22607c478bd9Sstevel@tonic-gate case NF3BLK: 22617c478bd9Sstevel@tonic-gate error = sattr3_to_vattr( 22627c478bd9Sstevel@tonic-gate &args->what.mknoddata3_u.device.dev_attributes, &va); 22637c478bd9Sstevel@tonic-gate if (error) 22647c478bd9Sstevel@tonic-gate goto out; 22657c478bd9Sstevel@tonic-gate if (secpolicy_sys_devices(cr) != 0) { 22667c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_PERM; 22677c478bd9Sstevel@tonic-gate goto out1; 22687c478bd9Sstevel@tonic-gate } 22697c478bd9Sstevel@tonic-gate if (args->what.type == NF3CHR) 22707c478bd9Sstevel@tonic-gate va.va_type = VCHR; 22717c478bd9Sstevel@tonic-gate else 22727c478bd9Sstevel@tonic-gate va.va_type = VBLK; 22737c478bd9Sstevel@tonic-gate va.va_rdev = makedevice( 22747c478bd9Sstevel@tonic-gate args->what.mknoddata3_u.device.spec.specdata1, 22757c478bd9Sstevel@tonic-gate args->what.mknoddata3_u.device.spec.specdata2); 22767c478bd9Sstevel@tonic-gate va.va_mask |= AT_TYPE | AT_RDEV; 22777c478bd9Sstevel@tonic-gate break; 22787c478bd9Sstevel@tonic-gate case NF3SOCK: 22797c478bd9Sstevel@tonic-gate error = sattr3_to_vattr( 22807c478bd9Sstevel@tonic-gate &args->what.mknoddata3_u.pipe_attributes, &va); 22817c478bd9Sstevel@tonic-gate if (error) 22827c478bd9Sstevel@tonic-gate goto out; 22837c478bd9Sstevel@tonic-gate va.va_type = VSOCK; 22847c478bd9Sstevel@tonic-gate va.va_mask |= AT_TYPE; 22857c478bd9Sstevel@tonic-gate break; 22867c478bd9Sstevel@tonic-gate case NF3FIFO: 22877c478bd9Sstevel@tonic-gate error = sattr3_to_vattr( 22887c478bd9Sstevel@tonic-gate &args->what.mknoddata3_u.pipe_attributes, &va); 22897c478bd9Sstevel@tonic-gate if (error) 22907c478bd9Sstevel@tonic-gate goto out; 22917c478bd9Sstevel@tonic-gate va.va_type = VFIFO; 22927c478bd9Sstevel@tonic-gate va.va_mask |= AT_TYPE; 22937c478bd9Sstevel@tonic-gate break; 22947c478bd9Sstevel@tonic-gate default: 22957c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_BADTYPE; 22967c478bd9Sstevel@tonic-gate goto out1; 22977c478bd9Sstevel@tonic-gate } 22987c478bd9Sstevel@tonic-gate 22997c478bd9Sstevel@tonic-gate /* 23007c478bd9Sstevel@tonic-gate * Must specify the mode. 23017c478bd9Sstevel@tonic-gate */ 23027c478bd9Sstevel@tonic-gate if (!(va.va_mask & AT_MODE)) { 23037c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_INVAL; 23047c478bd9Sstevel@tonic-gate goto out1; 23057c478bd9Sstevel@tonic-gate } 23067c478bd9Sstevel@tonic-gate 2307b89a8333Snatalie li - Sun Microsystems - Irvine United States ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 2308b89a8333Snatalie li - Sun Microsystems - Irvine United States name = nfscmd_convname(ca, exi, args->where.name, 2309b89a8333Snatalie li - Sun Microsystems - Irvine United States NFSCMD_CONV_INBOUND, MAXPATHLEN + 1); 2310b89a8333Snatalie li - Sun Microsystems - Irvine United States 2311b89a8333Snatalie li - Sun Microsystems - Irvine United States if (name == NULL) { 2312b89a8333Snatalie li - Sun Microsystems - Irvine United States resp->status = NFS3ERR_INVAL; 2313b89a8333Snatalie li - Sun Microsystems - Irvine United States goto out1; 2314b89a8333Snatalie li - Sun Microsystems - Irvine United States } 2315b89a8333Snatalie li - Sun Microsystems - Irvine United States 23167c478bd9Sstevel@tonic-gate excl = EXCL; 23177c478bd9Sstevel@tonic-gate 23187c478bd9Sstevel@tonic-gate mode = 0; 23197c478bd9Sstevel@tonic-gate 2320b89a8333Snatalie li - Sun Microsystems - Irvine United States error = VOP_CREATE(dvp, name, &va, excl, mode, 2321da6c28aaSamw &vp, cr, 0, NULL, NULL); 23227c478bd9Sstevel@tonic-gate 2323b89a8333Snatalie li - Sun Microsystems - Irvine United States if (name != args->where.name) 2324b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(name, MAXPATHLEN + 1); 2325b89a8333Snatalie li - Sun Microsystems - Irvine United States 23267c478bd9Sstevel@tonic-gate dava.va_mask = AT_ALL; 2327da6c28aaSamw davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava; 23287c478bd9Sstevel@tonic-gate 23297c478bd9Sstevel@tonic-gate /* 23307c478bd9Sstevel@tonic-gate * Force modified data and metadata out to stable storage. 23317c478bd9Sstevel@tonic-gate */ 2332da6c28aaSamw (void) VOP_FSYNC(dvp, 0, cr, NULL); 23337c478bd9Sstevel@tonic-gate 23347c478bd9Sstevel@tonic-gate if (error) 23357c478bd9Sstevel@tonic-gate goto out; 23367c478bd9Sstevel@tonic-gate 23377c478bd9Sstevel@tonic-gate resp->status = NFS3_OK; 23387c478bd9Sstevel@tonic-gate 23397c478bd9Sstevel@tonic-gate error = makefh3(&resp->resok.obj.handle, vp, exi); 23407c478bd9Sstevel@tonic-gate if (error) 23417c478bd9Sstevel@tonic-gate resp->resok.obj.handle_follows = FALSE; 23427c478bd9Sstevel@tonic-gate else 23437c478bd9Sstevel@tonic-gate resp->resok.obj.handle_follows = TRUE; 23447c478bd9Sstevel@tonic-gate 23457c478bd9Sstevel@tonic-gate va.va_mask = AT_ALL; 2346da6c28aaSamw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 23477c478bd9Sstevel@tonic-gate 23487c478bd9Sstevel@tonic-gate /* 23497c478bd9Sstevel@tonic-gate * Force modified metadata out to stable storage. 2350fd7da618Sgt29601 * 2351fd7da618Sgt29601 * if a underlying vp exists, pass it to VOP_FSYNC 23527c478bd9Sstevel@tonic-gate */ 2353fd7da618Sgt29601 if (VOP_REALVP(vp, &realvp, NULL) == 0) 2354fd7da618Sgt29601 (void) VOP_FSYNC(realvp, FNODSYNC, cr, NULL); 2355fd7da618Sgt29601 else 2356da6c28aaSamw (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL); 23577c478bd9Sstevel@tonic-gate 23587c478bd9Sstevel@tonic-gate VN_RELE(vp); 23597c478bd9Sstevel@tonic-gate 23607c478bd9Sstevel@tonic-gate vattr_to_post_op_attr(vap, &resp->resok.obj_attributes); 23617c478bd9Sstevel@tonic-gate vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc); 2362e1adf50cSahl DTRACE_NFSV3_4(op__mknod__done, struct svc_req *, req, 2363e1adf50cSahl cred_t *, cr, vnode_t *, dvp, MKNOD3res *, resp); 2364e1adf50cSahl VN_RELE(dvp); 23657c478bd9Sstevel@tonic-gate return; 23667c478bd9Sstevel@tonic-gate 23677c478bd9Sstevel@tonic-gate out: 23687c478bd9Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK) { 23697c478bd9Sstevel@tonic-gate curthread->t_flag &= ~T_WOULDBLOCK; 23707c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX; 23717c478bd9Sstevel@tonic-gate } else 23727c478bd9Sstevel@tonic-gate resp->status = puterrno3(error); 23737c478bd9Sstevel@tonic-gate out1: 2374e1adf50cSahl DTRACE_NFSV3_4(op__mknod__done, struct svc_req *, req, 2375e1adf50cSahl cred_t *, cr, vnode_t *, dvp, MKNOD3res *, resp); 23767c478bd9Sstevel@tonic-gate if (dvp != NULL) 23777c478bd9Sstevel@tonic-gate VN_RELE(dvp); 23787c478bd9Sstevel@tonic-gate vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc); 23797c478bd9Sstevel@tonic-gate } 23807c478bd9Sstevel@tonic-gate 238127242a7cSthurlow void * 23827c478bd9Sstevel@tonic-gate rfs3_mknod_getfh(MKNOD3args *args) 23837c478bd9Sstevel@tonic-gate { 23847c478bd9Sstevel@tonic-gate 238527242a7cSthurlow return (&args->where.dir); 23867c478bd9Sstevel@tonic-gate } 23877c478bd9Sstevel@tonic-gate 23887c478bd9Sstevel@tonic-gate void 23897c478bd9Sstevel@tonic-gate rfs3_remove(REMOVE3args *args, REMOVE3res *resp, struct exportinfo *exi, 23905cb0d679SMarcel Telka struct svc_req *req, cred_t *cr, bool_t ro) 23917c478bd9Sstevel@tonic-gate { 23927c478bd9Sstevel@tonic-gate int error = 0; 23937c478bd9Sstevel@tonic-gate vnode_t *vp; 23947c478bd9Sstevel@tonic-gate struct vattr *bvap; 23957c478bd9Sstevel@tonic-gate struct vattr bva; 23967c478bd9Sstevel@tonic-gate struct vattr *avap; 23977c478bd9Sstevel@tonic-gate struct vattr ava; 23987c478bd9Sstevel@tonic-gate vnode_t *targvp = NULL; 2399b89a8333Snatalie li - Sun Microsystems - Irvine United States struct sockaddr *ca; 2400b89a8333Snatalie li - Sun Microsystems - Irvine United States char *name = NULL; 24017c478bd9Sstevel@tonic-gate 24027c478bd9Sstevel@tonic-gate bvap = NULL; 24037c478bd9Sstevel@tonic-gate avap = NULL; 24047c478bd9Sstevel@tonic-gate 240527242a7cSthurlow vp = nfs3_fhtovp(&args->object.dir, exi); 2406e1adf50cSahl 2407e1adf50cSahl DTRACE_NFSV3_4(op__remove__start, struct svc_req *, req, 2408e1adf50cSahl cred_t *, cr, vnode_t *, vp, REMOVE3args *, args); 2409e1adf50cSahl 24107c478bd9Sstevel@tonic-gate if (vp == NULL) { 24117c478bd9Sstevel@tonic-gate error = ESTALE; 2412e1adf50cSahl goto err; 24137c478bd9Sstevel@tonic-gate } 24147c478bd9Sstevel@tonic-gate 24157c478bd9Sstevel@tonic-gate bva.va_mask = AT_ALL; 2416da6c28aaSamw bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva; 24177c478bd9Sstevel@tonic-gate avap = bvap; 24187c478bd9Sstevel@tonic-gate 24197c478bd9Sstevel@tonic-gate if (vp->v_type != VDIR) { 24207c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_NOTDIR; 2421e1adf50cSahl goto err1; 24227c478bd9Sstevel@tonic-gate } 24237c478bd9Sstevel@tonic-gate 24247c478bd9Sstevel@tonic-gate if (args->object.name == nfs3nametoolong) { 24257c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_NAMETOOLONG; 2426e1adf50cSahl goto err1; 24277c478bd9Sstevel@tonic-gate } 24287c478bd9Sstevel@tonic-gate 24297c478bd9Sstevel@tonic-gate if (args->object.name == NULL || *(args->object.name) == '\0') { 24307c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_ACCES; 2431e1adf50cSahl goto err1; 24327c478bd9Sstevel@tonic-gate } 24337c478bd9Sstevel@tonic-gate 24345cb0d679SMarcel Telka if (rdonly(ro, vp)) { 24357c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_ROFS; 2436e1adf50cSahl goto err1; 24377c478bd9Sstevel@tonic-gate } 24387c478bd9Sstevel@tonic-gate 243903986916Sjarrett if (is_system_labeled()) { 244003986916Sjarrett bslabel_t *clabel = req->rq_label; 244103986916Sjarrett 244203986916Sjarrett ASSERT(clabel != NULL); 244303986916Sjarrett DTRACE_PROBE2(tx__rfs3__log__info__opremove__clabel, char *, 244403986916Sjarrett "got client label from request(1)", struct svc_req *, req); 244503986916Sjarrett 244603986916Sjarrett if (!blequal(&l_admin_low->tsl_label, clabel)) { 2447bd6f1640SJarrett Lu if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK, 2448bd6f1640SJarrett Lu exi)) { 244903986916Sjarrett resp->status = NFS3ERR_ACCES; 2450e1adf50cSahl goto err1; 245103986916Sjarrett } 245203986916Sjarrett } 245303986916Sjarrett } 245403986916Sjarrett 2455b89a8333Snatalie li - Sun Microsystems - Irvine United States ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 2456b89a8333Snatalie li - Sun Microsystems - Irvine United States name = nfscmd_convname(ca, exi, args->object.name, 2457b89a8333Snatalie li - Sun Microsystems - Irvine United States NFSCMD_CONV_INBOUND, MAXPATHLEN + 1); 2458b89a8333Snatalie li - Sun Microsystems - Irvine United States 2459b89a8333Snatalie li - Sun Microsystems - Irvine United States if (name == NULL) { 2460b89a8333Snatalie li - Sun Microsystems - Irvine United States resp->status = NFS3ERR_INVAL; 2461b89a8333Snatalie li - Sun Microsystems - Irvine United States goto err1; 2462b89a8333Snatalie li - Sun Microsystems - Irvine United States } 2463b89a8333Snatalie li - Sun Microsystems - Irvine United States 24647c478bd9Sstevel@tonic-gate /* 24657c478bd9Sstevel@tonic-gate * Check for a conflict with a non-blocking mandatory share 24667c478bd9Sstevel@tonic-gate * reservation and V4 delegations 24677c478bd9Sstevel@tonic-gate */ 2468b89a8333Snatalie li - Sun Microsystems - Irvine United States error = VOP_LOOKUP(vp, name, &targvp, NULL, 0, 2469da6c28aaSamw NULL, cr, NULL, NULL, NULL); 24707c478bd9Sstevel@tonic-gate if (error != 0) 2471e1adf50cSahl goto err; 24727c478bd9Sstevel@tonic-gate 24737c478bd9Sstevel@tonic-gate if (rfs4_check_delegated(FWRITE, targvp, TRUE)) { 24747c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX; 2475e1adf50cSahl goto err1; 24767c478bd9Sstevel@tonic-gate } 24777c478bd9Sstevel@tonic-gate 24787c478bd9Sstevel@tonic-gate if (!nbl_need_check(targvp)) { 2479b89a8333Snatalie li - Sun Microsystems - Irvine United States error = VOP_REMOVE(vp, name, cr, NULL, 0); 24807c478bd9Sstevel@tonic-gate } else { 24817c478bd9Sstevel@tonic-gate nbl_start_crit(targvp, RW_READER); 2482da6c28aaSamw if (nbl_conflict(targvp, NBL_REMOVE, 0, 0, 0, NULL)) { 24837c478bd9Sstevel@tonic-gate error = EACCES; 24847c478bd9Sstevel@tonic-gate } else { 2485b89a8333Snatalie li - Sun Microsystems - Irvine United States error = VOP_REMOVE(vp, name, cr, NULL, 0); 24867c478bd9Sstevel@tonic-gate } 24877c478bd9Sstevel@tonic-gate nbl_end_crit(targvp); 24887c478bd9Sstevel@tonic-gate } 24897c478bd9Sstevel@tonic-gate VN_RELE(targvp); 24907c478bd9Sstevel@tonic-gate targvp = NULL; 24917c478bd9Sstevel@tonic-gate 24927c478bd9Sstevel@tonic-gate ava.va_mask = AT_ALL; 2493da6c28aaSamw avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava; 24947c478bd9Sstevel@tonic-gate 24957c478bd9Sstevel@tonic-gate /* 24967c478bd9Sstevel@tonic-gate * Force modified data and metadata out to stable storage. 24977c478bd9Sstevel@tonic-gate */ 2498da6c28aaSamw (void) VOP_FSYNC(vp, 0, cr, NULL); 24997c478bd9Sstevel@tonic-gate 25007c478bd9Sstevel@tonic-gate if (error) 2501e1adf50cSahl goto err; 25027c478bd9Sstevel@tonic-gate 25037c478bd9Sstevel@tonic-gate resp->status = NFS3_OK; 25047c478bd9Sstevel@tonic-gate vattr_to_wcc_data(bvap, avap, &resp->resok.dir_wcc); 2505e1adf50cSahl goto out; 25067c478bd9Sstevel@tonic-gate 2507e1adf50cSahl err: 25087c478bd9Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK) { 25097c478bd9Sstevel@tonic-gate curthread->t_flag &= ~T_WOULDBLOCK; 25107c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX; 25117c478bd9Sstevel@tonic-gate } else 25127c478bd9Sstevel@tonic-gate resp->status = puterrno3(error); 2513e1adf50cSahl err1: 2514e1adf50cSahl vattr_to_wcc_data(bvap, avap, &resp->resfail.dir_wcc); 2515e1adf50cSahl out: 2516e1adf50cSahl DTRACE_NFSV3_4(op__remove__done, struct svc_req *, req, 2517e1adf50cSahl cred_t *, cr, vnode_t *, vp, REMOVE3res *, resp); 2518b89a8333Snatalie li - Sun Microsystems - Irvine United States 2519b89a8333Snatalie li - Sun Microsystems - Irvine United States if (name != NULL && name != args->object.name) 2520b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(name, MAXPATHLEN + 1); 2521b89a8333Snatalie li - Sun Microsystems - Irvine United States 25227c478bd9Sstevel@tonic-gate if (vp != NULL) 25237c478bd9Sstevel@tonic-gate VN_RELE(vp); 25247c478bd9Sstevel@tonic-gate } 25257c478bd9Sstevel@tonic-gate 252627242a7cSthurlow void * 25277c478bd9Sstevel@tonic-gate rfs3_remove_getfh(REMOVE3args *args) 25287c478bd9Sstevel@tonic-gate { 25297c478bd9Sstevel@tonic-gate 253027242a7cSthurlow return (&args->object.dir); 25317c478bd9Sstevel@tonic-gate } 25327c478bd9Sstevel@tonic-gate 25337c478bd9Sstevel@tonic-gate void 25347c478bd9Sstevel@tonic-gate rfs3_rmdir(RMDIR3args *args, RMDIR3res *resp, struct exportinfo *exi, 25355cb0d679SMarcel Telka struct svc_req *req, cred_t *cr, bool_t ro) 25367c478bd9Sstevel@tonic-gate { 25377c478bd9Sstevel@tonic-gate int error; 25387c478bd9Sstevel@tonic-gate vnode_t *vp; 25397c478bd9Sstevel@tonic-gate struct vattr *bvap; 25407c478bd9Sstevel@tonic-gate struct vattr bva; 25417c478bd9Sstevel@tonic-gate struct vattr *avap; 25427c478bd9Sstevel@tonic-gate struct vattr ava; 2543b89a8333Snatalie li - Sun Microsystems - Irvine United States struct sockaddr *ca; 2544b89a8333Snatalie li - Sun Microsystems - Irvine United States char *name = NULL; 25457c478bd9Sstevel@tonic-gate 25467c478bd9Sstevel@tonic-gate bvap = NULL; 25477c478bd9Sstevel@tonic-gate avap = NULL; 25487c478bd9Sstevel@tonic-gate 254927242a7cSthurlow vp = nfs3_fhtovp(&args->object.dir, exi); 2550e1adf50cSahl 2551e1adf50cSahl DTRACE_NFSV3_4(op__rmdir__start, struct svc_req *, req, 2552e1adf50cSahl cred_t *, cr, vnode_t *, vp, RMDIR3args *, args); 2553e1adf50cSahl 25547c478bd9Sstevel@tonic-gate if (vp == NULL) { 25557c478bd9Sstevel@tonic-gate error = ESTALE; 2556e1adf50cSahl goto err; 25577c478bd9Sstevel@tonic-gate } 25587c478bd9Sstevel@tonic-gate 25597c478bd9Sstevel@tonic-gate bva.va_mask = AT_ALL; 2560da6c28aaSamw bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva; 25617c478bd9Sstevel@tonic-gate avap = bvap; 25627c478bd9Sstevel@tonic-gate 25637c478bd9Sstevel@tonic-gate if (vp->v_type != VDIR) { 25647c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_NOTDIR; 2565e1adf50cSahl goto err1; 25667c478bd9Sstevel@tonic-gate } 25677c478bd9Sstevel@tonic-gate 25687c478bd9Sstevel@tonic-gate if (args->object.name == nfs3nametoolong) { 25697c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_NAMETOOLONG; 2570e1adf50cSahl goto err1; 25717c478bd9Sstevel@tonic-gate } 25727c478bd9Sstevel@tonic-gate 25737c478bd9Sstevel@tonic-gate if (args->object.name == NULL || *(args->object.name) == '\0') { 25747c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_ACCES; 2575e1adf50cSahl goto err1; 25767c478bd9Sstevel@tonic-gate } 25777c478bd9Sstevel@tonic-gate 25785cb0d679SMarcel Telka if (rdonly(ro, vp)) { 25797c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_ROFS; 2580e1adf50cSahl goto err1; 25817c478bd9Sstevel@tonic-gate } 25827c478bd9Sstevel@tonic-gate 258303986916Sjarrett if (is_system_labeled()) { 258403986916Sjarrett bslabel_t *clabel = req->rq_label; 258503986916Sjarrett 258603986916Sjarrett ASSERT(clabel != NULL); 258703986916Sjarrett DTRACE_PROBE2(tx__rfs3__log__info__opremovedir__clabel, char *, 258803986916Sjarrett "got client label from request(1)", struct svc_req *, req); 258903986916Sjarrett 259003986916Sjarrett if (!blequal(&l_admin_low->tsl_label, clabel)) { 2591bd6f1640SJarrett Lu if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK, 2592bd6f1640SJarrett Lu exi)) { 259303986916Sjarrett resp->status = NFS3ERR_ACCES; 2594e1adf50cSahl goto err1; 259503986916Sjarrett } 259603986916Sjarrett } 259703986916Sjarrett } 259803986916Sjarrett 2599b89a8333Snatalie li - Sun Microsystems - Irvine United States ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 2600b89a8333Snatalie li - Sun Microsystems - Irvine United States name = nfscmd_convname(ca, exi, args->object.name, 2601b89a8333Snatalie li - Sun Microsystems - Irvine United States NFSCMD_CONV_INBOUND, MAXPATHLEN + 1); 2602b89a8333Snatalie li - Sun Microsystems - Irvine United States 2603b89a8333Snatalie li - Sun Microsystems - Irvine United States if (name == NULL) { 2604b89a8333Snatalie li - Sun Microsystems - Irvine United States resp->status = NFS3ERR_INVAL; 2605b89a8333Snatalie li - Sun Microsystems - Irvine United States goto err1; 2606b89a8333Snatalie li - Sun Microsystems - Irvine United States } 2607b89a8333Snatalie li - Sun Microsystems - Irvine United States 2608b89a8333Snatalie li - Sun Microsystems - Irvine United States error = VOP_RMDIR(vp, name, rootdir, cr, NULL, 0); 2609b89a8333Snatalie li - Sun Microsystems - Irvine United States 2610b89a8333Snatalie li - Sun Microsystems - Irvine United States if (name != args->object.name) 2611b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(name, MAXPATHLEN + 1); 26127c478bd9Sstevel@tonic-gate 26137c478bd9Sstevel@tonic-gate ava.va_mask = AT_ALL; 2614da6c28aaSamw avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava; 26157c478bd9Sstevel@tonic-gate 26167c478bd9Sstevel@tonic-gate /* 26177c478bd9Sstevel@tonic-gate * Force modified data and metadata out to stable storage. 26187c478bd9Sstevel@tonic-gate */ 2619da6c28aaSamw (void) VOP_FSYNC(vp, 0, cr, NULL); 26207c478bd9Sstevel@tonic-gate 26217c478bd9Sstevel@tonic-gate if (error) { 26227c478bd9Sstevel@tonic-gate /* 26237c478bd9Sstevel@tonic-gate * System V defines rmdir to return EEXIST, not ENOTEMPTY, 26247c478bd9Sstevel@tonic-gate * if the directory is not empty. A System V NFS server 26257c478bd9Sstevel@tonic-gate * needs to map NFS3ERR_EXIST to NFS3ERR_NOTEMPTY to transmit 26267c478bd9Sstevel@tonic-gate * over the wire. 26277c478bd9Sstevel@tonic-gate */ 26287c478bd9Sstevel@tonic-gate if (error == EEXIST) 26297c478bd9Sstevel@tonic-gate error = ENOTEMPTY; 2630e1adf50cSahl goto err; 26317c478bd9Sstevel@tonic-gate } 26327c478bd9Sstevel@tonic-gate 26337c478bd9Sstevel@tonic-gate resp->status = NFS3_OK; 26347c478bd9Sstevel@tonic-gate vattr_to_wcc_data(bvap, avap, &resp->resok.dir_wcc); 2635e1adf50cSahl goto out; 26367c478bd9Sstevel@tonic-gate 2637e1adf50cSahl err: 26387c478bd9Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK) { 26397c478bd9Sstevel@tonic-gate curthread->t_flag &= ~T_WOULDBLOCK; 26407c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX; 26417c478bd9Sstevel@tonic-gate } else 26427c478bd9Sstevel@tonic-gate resp->status = puterrno3(error); 2643e1adf50cSahl err1: 2644e1adf50cSahl vattr_to_wcc_data(bvap, avap, &resp->resfail.dir_wcc); 2645e1adf50cSahl out: 2646e1adf50cSahl DTRACE_NFSV3_4(op__rmdir__done, struct svc_req *, req, 2647e1adf50cSahl cred_t *, cr, vnode_t *, vp, RMDIR3res *, resp); 26487c478bd9Sstevel@tonic-gate if (vp != NULL) 26497c478bd9Sstevel@tonic-gate VN_RELE(vp); 2650e1adf50cSahl 26517c478bd9Sstevel@tonic-gate } 26527c478bd9Sstevel@tonic-gate 265327242a7cSthurlow void * 26547c478bd9Sstevel@tonic-gate rfs3_rmdir_getfh(RMDIR3args *args) 26557c478bd9Sstevel@tonic-gate { 26567c478bd9Sstevel@tonic-gate 265727242a7cSthurlow return (&args->object.dir); 26587c478bd9Sstevel@tonic-gate } 26597c478bd9Sstevel@tonic-gate 26607c478bd9Sstevel@tonic-gate void 26617c478bd9Sstevel@tonic-gate rfs3_rename(RENAME3args *args, RENAME3res *resp, struct exportinfo *exi, 26625cb0d679SMarcel Telka struct svc_req *req, cred_t *cr, bool_t ro) 26637c478bd9Sstevel@tonic-gate { 26647c478bd9Sstevel@tonic-gate int error = 0; 26657c478bd9Sstevel@tonic-gate vnode_t *fvp; 26667c478bd9Sstevel@tonic-gate vnode_t *tvp; 26677c478bd9Sstevel@tonic-gate vnode_t *targvp; 26687c478bd9Sstevel@tonic-gate struct vattr *fbvap; 26697c478bd9Sstevel@tonic-gate struct vattr fbva; 26707c478bd9Sstevel@tonic-gate struct vattr *favap; 26717c478bd9Sstevel@tonic-gate struct vattr fava; 26727c478bd9Sstevel@tonic-gate struct vattr *tbvap; 26737c478bd9Sstevel@tonic-gate struct vattr tbva; 26747c478bd9Sstevel@tonic-gate struct vattr *tavap; 26757c478bd9Sstevel@tonic-gate struct vattr tava; 26767c478bd9Sstevel@tonic-gate nfs_fh3 *fh3; 26777c478bd9Sstevel@tonic-gate struct exportinfo *to_exi; 26787c478bd9Sstevel@tonic-gate vnode_t *srcvp = NULL; 267903986916Sjarrett bslabel_t *clabel; 2680b89a8333Snatalie li - Sun Microsystems - Irvine United States struct sockaddr *ca; 2681b89a8333Snatalie li - Sun Microsystems - Irvine United States char *name = NULL; 2682b89a8333Snatalie li - Sun Microsystems - Irvine United States char *toname = NULL; 26837c478bd9Sstevel@tonic-gate 26847c478bd9Sstevel@tonic-gate fbvap = NULL; 26857c478bd9Sstevel@tonic-gate favap = NULL; 26867c478bd9Sstevel@tonic-gate tbvap = NULL; 26877c478bd9Sstevel@tonic-gate tavap = NULL; 26887c478bd9Sstevel@tonic-gate tvp = NULL; 26897c478bd9Sstevel@tonic-gate 269027242a7cSthurlow fvp = nfs3_fhtovp(&args->from.dir, exi); 2691e1adf50cSahl 2692e1adf50cSahl DTRACE_NFSV3_4(op__rename__start, struct svc_req *, req, 2693e1adf50cSahl cred_t *, cr, vnode_t *, fvp, RENAME3args *, args); 2694e1adf50cSahl 26957c478bd9Sstevel@tonic-gate if (fvp == NULL) { 26967c478bd9Sstevel@tonic-gate error = ESTALE; 2697e1adf50cSahl goto err; 26987c478bd9Sstevel@tonic-gate } 26997c478bd9Sstevel@tonic-gate 270003986916Sjarrett if (is_system_labeled()) { 270103986916Sjarrett clabel = req->rq_label; 270203986916Sjarrett ASSERT(clabel != NULL); 270303986916Sjarrett DTRACE_PROBE2(tx__rfs3__log__info__oprename__clabel, char *, 270403986916Sjarrett "got client label from request(1)", struct svc_req *, req); 270503986916Sjarrett 270603986916Sjarrett if (!blequal(&l_admin_low->tsl_label, clabel)) { 2707bd6f1640SJarrett Lu if (!do_rfs_label_check(clabel, fvp, EQUALITY_CHECK, 2708bd6f1640SJarrett Lu exi)) { 270903986916Sjarrett resp->status = NFS3ERR_ACCES; 2710e1adf50cSahl goto err1; 271103986916Sjarrett } 271203986916Sjarrett } 271303986916Sjarrett } 271403986916Sjarrett 27157c478bd9Sstevel@tonic-gate fbva.va_mask = AT_ALL; 2716da6c28aaSamw fbvap = VOP_GETATTR(fvp, &fbva, 0, cr, NULL) ? NULL : &fbva; 27177c478bd9Sstevel@tonic-gate favap = fbvap; 27187c478bd9Sstevel@tonic-gate 271927242a7cSthurlow fh3 = &args->to.dir; 2720*fbd2e8e1SArne Jansen to_exi = checkexport(&fh3->fh3_fsid, FH3TOXFIDP(fh3), NULL); 27217c478bd9Sstevel@tonic-gate if (to_exi == NULL) { 27227c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_ACCES; 2723e1adf50cSahl goto err1; 27247c478bd9Sstevel@tonic-gate } 27257c478bd9Sstevel@tonic-gate exi_rele(to_exi); 27267c478bd9Sstevel@tonic-gate 27277c478bd9Sstevel@tonic-gate if (to_exi != exi) { 27287c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_XDEV; 2729e1adf50cSahl goto err1; 27307c478bd9Sstevel@tonic-gate } 27317c478bd9Sstevel@tonic-gate 273227242a7cSthurlow tvp = nfs3_fhtovp(&args->to.dir, exi); 27337c478bd9Sstevel@tonic-gate if (tvp == NULL) { 27347c478bd9Sstevel@tonic-gate error = ESTALE; 2735e1adf50cSahl goto err; 27367c478bd9Sstevel@tonic-gate } 27377c478bd9Sstevel@tonic-gate 27387c478bd9Sstevel@tonic-gate tbva.va_mask = AT_ALL; 2739da6c28aaSamw tbvap = VOP_GETATTR(tvp, &tbva, 0, cr, NULL) ? NULL : &tbva; 27407c478bd9Sstevel@tonic-gate tavap = tbvap; 27417c478bd9Sstevel@tonic-gate 27427c478bd9Sstevel@tonic-gate if (fvp->v_type != VDIR || tvp->v_type != VDIR) { 27437c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_NOTDIR; 2744e1adf50cSahl goto err1; 27457c478bd9Sstevel@tonic-gate } 27467c478bd9Sstevel@tonic-gate 27477c478bd9Sstevel@tonic-gate if (args->from.name == nfs3nametoolong || 27487c478bd9Sstevel@tonic-gate args->to.name == nfs3nametoolong) { 27497c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_NAMETOOLONG; 2750e1adf50cSahl goto err1; 27517c478bd9Sstevel@tonic-gate } 27527c478bd9Sstevel@tonic-gate if (args->from.name == NULL || *(args->from.name) == '\0' || 27537c478bd9Sstevel@tonic-gate args->to.name == NULL || *(args->to.name) == '\0') { 27547c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_ACCES; 2755e1adf50cSahl goto err1; 27567c478bd9Sstevel@tonic-gate } 27577c478bd9Sstevel@tonic-gate 27585cb0d679SMarcel Telka if (rdonly(ro, tvp)) { 27597c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_ROFS; 2760e1adf50cSahl goto err1; 27617c478bd9Sstevel@tonic-gate } 27627c478bd9Sstevel@tonic-gate 276303986916Sjarrett if (is_system_labeled()) { 276403986916Sjarrett if (!blequal(&l_admin_low->tsl_label, clabel)) { 2765bd6f1640SJarrett Lu if (!do_rfs_label_check(clabel, tvp, EQUALITY_CHECK, 2766bd6f1640SJarrett Lu exi)) { 276703986916Sjarrett resp->status = NFS3ERR_ACCES; 2768e1adf50cSahl goto err1; 276903986916Sjarrett } 277003986916Sjarrett } 277103986916Sjarrett } 277203986916Sjarrett 2773b89a8333Snatalie li - Sun Microsystems - Irvine United States ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 2774b89a8333Snatalie li - Sun Microsystems - Irvine United States name = nfscmd_convname(ca, exi, args->from.name, 2775b89a8333Snatalie li - Sun Microsystems - Irvine United States NFSCMD_CONV_INBOUND, MAXPATHLEN + 1); 2776b89a8333Snatalie li - Sun Microsystems - Irvine United States 2777b89a8333Snatalie li - Sun Microsystems - Irvine United States if (name == NULL) { 2778b89a8333Snatalie li - Sun Microsystems - Irvine United States resp->status = NFS3ERR_INVAL; 2779b89a8333Snatalie li - Sun Microsystems - Irvine United States goto err1; 2780b89a8333Snatalie li - Sun Microsystems - Irvine United States } 2781b89a8333Snatalie li - Sun Microsystems - Irvine United States 2782b89a8333Snatalie li - Sun Microsystems - Irvine United States toname = nfscmd_convname(ca, exi, args->to.name, 2783b89a8333Snatalie li - Sun Microsystems - Irvine United States NFSCMD_CONV_INBOUND, MAXPATHLEN + 1); 2784b89a8333Snatalie li - Sun Microsystems - Irvine United States 2785b89a8333Snatalie li - Sun Microsystems - Irvine United States if (toname == NULL) { 2786b89a8333Snatalie li - Sun Microsystems - Irvine United States resp->status = NFS3ERR_INVAL; 2787b89a8333Snatalie li - Sun Microsystems - Irvine United States goto err1; 2788b89a8333Snatalie li - Sun Microsystems - Irvine United States } 2789b89a8333Snatalie li - Sun Microsystems - Irvine United States 27907c478bd9Sstevel@tonic-gate /* 27917c478bd9Sstevel@tonic-gate * Check for a conflict with a non-blocking mandatory share 27927c478bd9Sstevel@tonic-gate * reservation or V4 delegations. 27937c478bd9Sstevel@tonic-gate */ 2794b89a8333Snatalie li - Sun Microsystems - Irvine United States error = VOP_LOOKUP(fvp, name, &srcvp, NULL, 0, 2795da6c28aaSamw NULL, cr, NULL, NULL, NULL); 27967c478bd9Sstevel@tonic-gate if (error != 0) 2797e1adf50cSahl goto err; 27987c478bd9Sstevel@tonic-gate 27997c478bd9Sstevel@tonic-gate /* 28007c478bd9Sstevel@tonic-gate * If we rename a delegated file we should recall the 28017c478bd9Sstevel@tonic-gate * delegation, since future opens should fail or would 28027c478bd9Sstevel@tonic-gate * refer to a new file. 28037c478bd9Sstevel@tonic-gate */ 28047c478bd9Sstevel@tonic-gate if (rfs4_check_delegated(FWRITE, srcvp, FALSE)) { 28057c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX; 2806e1adf50cSahl goto err1; 28077c478bd9Sstevel@tonic-gate } 28087c478bd9Sstevel@tonic-gate 28097c478bd9Sstevel@tonic-gate /* 28107c478bd9Sstevel@tonic-gate * Check for renaming over a delegated file. Check rfs4_deleg_policy 28117c478bd9Sstevel@tonic-gate * first to avoid VOP_LOOKUP if possible. 28127c478bd9Sstevel@tonic-gate */ 28137c478bd9Sstevel@tonic-gate if (rfs4_deleg_policy != SRV_NEVER_DELEGATE && 2814b89a8333Snatalie li - Sun Microsystems - Irvine United States VOP_LOOKUP(tvp, toname, &targvp, NULL, 0, NULL, cr, 2815da6c28aaSamw NULL, NULL, NULL) == 0) { 28167c478bd9Sstevel@tonic-gate 28177c478bd9Sstevel@tonic-gate if (rfs4_check_delegated(FWRITE, targvp, TRUE)) { 28187c478bd9Sstevel@tonic-gate VN_RELE(targvp); 28197c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX; 2820e1adf50cSahl goto err1; 28217c478bd9Sstevel@tonic-gate } 28227c478bd9Sstevel@tonic-gate VN_RELE(targvp); 28237c478bd9Sstevel@tonic-gate } 28247c478bd9Sstevel@tonic-gate 28257c478bd9Sstevel@tonic-gate if (!nbl_need_check(srcvp)) { 2826b89a8333Snatalie li - Sun Microsystems - Irvine United States error = VOP_RENAME(fvp, name, tvp, toname, cr, NULL, 0); 28277c478bd9Sstevel@tonic-gate } else { 28287c478bd9Sstevel@tonic-gate nbl_start_crit(srcvp, RW_READER); 2829b89a8333Snatalie li - Sun Microsystems - Irvine United States if (nbl_conflict(srcvp, NBL_RENAME, 0, 0, 0, NULL)) 28307c478bd9Sstevel@tonic-gate error = EACCES; 2831b89a8333Snatalie li - Sun Microsystems - Irvine United States else 2832b89a8333Snatalie li - Sun Microsystems - Irvine United States error = VOP_RENAME(fvp, name, tvp, toname, cr, NULL, 0); 28337c478bd9Sstevel@tonic-gate nbl_end_crit(srcvp); 28347c478bd9Sstevel@tonic-gate } 283551ece835Seschrock if (error == 0) 283651ece835Seschrock vn_renamepath(tvp, srcvp, args->to.name, 2837c9264041Sjwahlig strlen(args->to.name)); 28387c478bd9Sstevel@tonic-gate VN_RELE(srcvp); 28397c478bd9Sstevel@tonic-gate srcvp = NULL; 28407c478bd9Sstevel@tonic-gate 28417c478bd9Sstevel@tonic-gate fava.va_mask = AT_ALL; 2842da6c28aaSamw favap = VOP_GETATTR(fvp, &fava, 0, cr, NULL) ? NULL : &fava; 28437c478bd9Sstevel@tonic-gate tava.va_mask = AT_ALL; 2844da6c28aaSamw tavap = VOP_GETATTR(tvp, &tava, 0, cr, NULL) ? NULL : &tava; 28457c478bd9Sstevel@tonic-gate 28467c478bd9Sstevel@tonic-gate /* 28477c478bd9Sstevel@tonic-gate * Force modified data and metadata out to stable storage. 28487c478bd9Sstevel@tonic-gate */ 2849da6c28aaSamw (void) VOP_FSYNC(fvp, 0, cr, NULL); 2850da6c28aaSamw (void) VOP_FSYNC(tvp, 0, cr, NULL); 28517c478bd9Sstevel@tonic-gate 28527c478bd9Sstevel@tonic-gate if (error) 2853e1adf50cSahl goto err; 28547c478bd9Sstevel@tonic-gate 28557c478bd9Sstevel@tonic-gate resp->status = NFS3_OK; 28567c478bd9Sstevel@tonic-gate vattr_to_wcc_data(fbvap, favap, &resp->resok.fromdir_wcc); 28577c478bd9Sstevel@tonic-gate vattr_to_wcc_data(tbvap, tavap, &resp->resok.todir_wcc); 2858e1adf50cSahl goto out; 28597c478bd9Sstevel@tonic-gate 2860e1adf50cSahl err: 28617c478bd9Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK) { 28627c478bd9Sstevel@tonic-gate curthread->t_flag &= ~T_WOULDBLOCK; 28637c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX; 2864b89a8333Snatalie li - Sun Microsystems - Irvine United States } else { 28657c478bd9Sstevel@tonic-gate resp->status = puterrno3(error); 2866b89a8333Snatalie li - Sun Microsystems - Irvine United States } 2867e1adf50cSahl err1: 2868e1adf50cSahl vattr_to_wcc_data(fbvap, favap, &resp->resfail.fromdir_wcc); 2869e1adf50cSahl vattr_to_wcc_data(tbvap, tavap, &resp->resfail.todir_wcc); 2870b89a8333Snatalie li - Sun Microsystems - Irvine United States 2871e1adf50cSahl out: 2872b89a8333Snatalie li - Sun Microsystems - Irvine United States if (name != NULL && name != args->from.name) 2873b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(name, MAXPATHLEN + 1); 2874b89a8333Snatalie li - Sun Microsystems - Irvine United States if (toname != NULL && toname != args->to.name) 2875b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(toname, MAXPATHLEN + 1); 2876b89a8333Snatalie li - Sun Microsystems - Irvine United States 2877e1adf50cSahl DTRACE_NFSV3_4(op__rename__done, struct svc_req *, req, 2878e1adf50cSahl cred_t *, cr, vnode_t *, fvp, RENAME3res *, resp); 28797c478bd9Sstevel@tonic-gate if (fvp != NULL) 28807c478bd9Sstevel@tonic-gate VN_RELE(fvp); 28817c478bd9Sstevel@tonic-gate if (tvp != NULL) 28827c478bd9Sstevel@tonic-gate VN_RELE(tvp); 28837c478bd9Sstevel@tonic-gate } 28847c478bd9Sstevel@tonic-gate 288527242a7cSthurlow void * 28867c478bd9Sstevel@tonic-gate rfs3_rename_getfh(RENAME3args *args) 28877c478bd9Sstevel@tonic-gate { 28887c478bd9Sstevel@tonic-gate 288927242a7cSthurlow return (&args->from.dir); 28907c478bd9Sstevel@tonic-gate } 28917c478bd9Sstevel@tonic-gate 28927c478bd9Sstevel@tonic-gate void 28937c478bd9Sstevel@tonic-gate rfs3_link(LINK3args *args, LINK3res *resp, struct exportinfo *exi, 28945cb0d679SMarcel Telka struct svc_req *req, cred_t *cr, bool_t ro) 28957c478bd9Sstevel@tonic-gate { 28967c478bd9Sstevel@tonic-gate int error; 28977c478bd9Sstevel@tonic-gate vnode_t *vp; 28987c478bd9Sstevel@tonic-gate vnode_t *dvp; 28997c478bd9Sstevel@tonic-gate struct vattr *vap; 29007c478bd9Sstevel@tonic-gate struct vattr va; 29017c478bd9Sstevel@tonic-gate struct vattr *bvap; 29027c478bd9Sstevel@tonic-gate struct vattr bva; 29037c478bd9Sstevel@tonic-gate struct vattr *avap; 29047c478bd9Sstevel@tonic-gate struct vattr ava; 29057c478bd9Sstevel@tonic-gate nfs_fh3 *fh3; 29067c478bd9Sstevel@tonic-gate struct exportinfo *to_exi; 290703986916Sjarrett bslabel_t *clabel; 2908b89a8333Snatalie li - Sun Microsystems - Irvine United States struct sockaddr *ca; 2909b89a8333Snatalie li - Sun Microsystems - Irvine United States char *name = NULL; 29107c478bd9Sstevel@tonic-gate 29117c478bd9Sstevel@tonic-gate vap = NULL; 29127c478bd9Sstevel@tonic-gate bvap = NULL; 29137c478bd9Sstevel@tonic-gate avap = NULL; 29147c478bd9Sstevel@tonic-gate dvp = NULL; 29157c478bd9Sstevel@tonic-gate 29167c478bd9Sstevel@tonic-gate vp = nfs3_fhtovp(&args->file, exi); 2917e1adf50cSahl 2918e1adf50cSahl DTRACE_NFSV3_4(op__link__start, struct svc_req *, req, 2919e1adf50cSahl cred_t *, cr, vnode_t *, vp, LINK3args *, args); 2920e1adf50cSahl 29217c478bd9Sstevel@tonic-gate if (vp == NULL) { 29227c478bd9Sstevel@tonic-gate error = ESTALE; 29237c478bd9Sstevel@tonic-gate goto out; 29247c478bd9Sstevel@tonic-gate } 29257c478bd9Sstevel@tonic-gate 29267c478bd9Sstevel@tonic-gate va.va_mask = AT_ALL; 2927da6c28aaSamw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 29287c478bd9Sstevel@tonic-gate 292927242a7cSthurlow fh3 = &args->link.dir; 2930*fbd2e8e1SArne Jansen to_exi = checkexport(&fh3->fh3_fsid, FH3TOXFIDP(fh3), NULL); 29317c478bd9Sstevel@tonic-gate if (to_exi == NULL) { 29327c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_ACCES; 29337c478bd9Sstevel@tonic-gate goto out1; 29347c478bd9Sstevel@tonic-gate } 29357c478bd9Sstevel@tonic-gate exi_rele(to_exi); 29367c478bd9Sstevel@tonic-gate 29377c478bd9Sstevel@tonic-gate if (to_exi != exi) { 29387c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_XDEV; 29397c478bd9Sstevel@tonic-gate goto out1; 29407c478bd9Sstevel@tonic-gate } 29417c478bd9Sstevel@tonic-gate 294203986916Sjarrett if (is_system_labeled()) { 294303986916Sjarrett clabel = req->rq_label; 294403986916Sjarrett 294503986916Sjarrett ASSERT(clabel != NULL); 294603986916Sjarrett DTRACE_PROBE2(tx__rfs3__log__info__oplink__clabel, char *, 294703986916Sjarrett "got client label from request(1)", struct svc_req *, req); 294803986916Sjarrett 294903986916Sjarrett if (!blequal(&l_admin_low->tsl_label, clabel)) { 2950bd6f1640SJarrett Lu if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK, 2951bd6f1640SJarrett Lu exi)) { 295203986916Sjarrett resp->status = NFS3ERR_ACCES; 295303986916Sjarrett goto out1; 295403986916Sjarrett } 295503986916Sjarrett } 295603986916Sjarrett } 295703986916Sjarrett 295827242a7cSthurlow dvp = nfs3_fhtovp(&args->link.dir, exi); 29597c478bd9Sstevel@tonic-gate if (dvp == NULL) { 29607c478bd9Sstevel@tonic-gate error = ESTALE; 29617c478bd9Sstevel@tonic-gate goto out; 29627c478bd9Sstevel@tonic-gate } 29637c478bd9Sstevel@tonic-gate 29647c478bd9Sstevel@tonic-gate bva.va_mask = AT_ALL; 2965da6c28aaSamw bvap = VOP_GETATTR(dvp, &bva, 0, cr, NULL) ? NULL : &bva; 29667c478bd9Sstevel@tonic-gate 29677c478bd9Sstevel@tonic-gate if (dvp->v_type != VDIR) { 29687c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_NOTDIR; 29697c478bd9Sstevel@tonic-gate goto out1; 29707c478bd9Sstevel@tonic-gate } 29717c478bd9Sstevel@tonic-gate 29727c478bd9Sstevel@tonic-gate if (args->link.name == nfs3nametoolong) { 29737c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_NAMETOOLONG; 29747c478bd9Sstevel@tonic-gate goto out1; 29757c478bd9Sstevel@tonic-gate } 29767c478bd9Sstevel@tonic-gate 29777c478bd9Sstevel@tonic-gate if (args->link.name == NULL || *(args->link.name) == '\0') { 29787c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_ACCES; 29797c478bd9Sstevel@tonic-gate goto out1; 29807c478bd9Sstevel@tonic-gate } 29817c478bd9Sstevel@tonic-gate 29825cb0d679SMarcel Telka if (rdonly(ro, dvp)) { 29837c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_ROFS; 29847c478bd9Sstevel@tonic-gate goto out1; 29857c478bd9Sstevel@tonic-gate } 29867c478bd9Sstevel@tonic-gate 298703986916Sjarrett if (is_system_labeled()) { 298803986916Sjarrett DTRACE_PROBE2(tx__rfs3__log__info__oplinkdir__clabel, char *, 298903986916Sjarrett "got client label from request(1)", struct svc_req *, req); 299003986916Sjarrett 299103986916Sjarrett if (!blequal(&l_admin_low->tsl_label, clabel)) { 2992bd6f1640SJarrett Lu if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK, 2993bd6f1640SJarrett Lu exi)) { 299403986916Sjarrett resp->status = NFS3ERR_ACCES; 299503986916Sjarrett goto out1; 299603986916Sjarrett } 299703986916Sjarrett } 299803986916Sjarrett } 299903986916Sjarrett 3000b89a8333Snatalie li - Sun Microsystems - Irvine United States ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 3001b89a8333Snatalie li - Sun Microsystems - Irvine United States name = nfscmd_convname(ca, exi, args->link.name, 3002b89a8333Snatalie li - Sun Microsystems - Irvine United States NFSCMD_CONV_INBOUND, MAXPATHLEN + 1); 3003b89a8333Snatalie li - Sun Microsystems - Irvine United States 3004b89a8333Snatalie li - Sun Microsystems - Irvine United States if (name == NULL) { 3005b89a8333Snatalie li - Sun Microsystems - Irvine United States resp->status = NFS3ERR_SERVERFAULT; 3006b89a8333Snatalie li - Sun Microsystems - Irvine United States goto out1; 3007b89a8333Snatalie li - Sun Microsystems - Irvine United States } 3008b89a8333Snatalie li - Sun Microsystems - Irvine United States 3009b89a8333Snatalie li - Sun Microsystems - Irvine United States error = VOP_LINK(dvp, vp, name, cr, NULL, 0); 30107c478bd9Sstevel@tonic-gate 30117c478bd9Sstevel@tonic-gate va.va_mask = AT_ALL; 3012da6c28aaSamw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 30137c478bd9Sstevel@tonic-gate ava.va_mask = AT_ALL; 3014da6c28aaSamw avap = VOP_GETATTR(dvp, &ava, 0, cr, NULL) ? NULL : &ava; 30157c478bd9Sstevel@tonic-gate 30167c478bd9Sstevel@tonic-gate /* 30177c478bd9Sstevel@tonic-gate * Force modified data and metadata out to stable storage. 30187c478bd9Sstevel@tonic-gate */ 3019da6c28aaSamw (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL); 3020da6c28aaSamw (void) VOP_FSYNC(dvp, 0, cr, NULL); 30217c478bd9Sstevel@tonic-gate 30227c478bd9Sstevel@tonic-gate if (error) 30237c478bd9Sstevel@tonic-gate goto out; 30247c478bd9Sstevel@tonic-gate 30257c478bd9Sstevel@tonic-gate VN_RELE(dvp); 30267c478bd9Sstevel@tonic-gate 30277c478bd9Sstevel@tonic-gate resp->status = NFS3_OK; 30287c478bd9Sstevel@tonic-gate vattr_to_post_op_attr(vap, &resp->resok.file_attributes); 30297c478bd9Sstevel@tonic-gate vattr_to_wcc_data(bvap, avap, &resp->resok.linkdir_wcc); 3030e1adf50cSahl 3031e1adf50cSahl DTRACE_NFSV3_4(op__link__done, struct svc_req *, req, 3032e1adf50cSahl cred_t *, cr, vnode_t *, vp, LINK3res *, resp); 3033e1adf50cSahl 3034e1adf50cSahl VN_RELE(vp); 3035e1adf50cSahl 30367c478bd9Sstevel@tonic-gate return; 30377c478bd9Sstevel@tonic-gate 30387c478bd9Sstevel@tonic-gate out: 30397c478bd9Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK) { 30407c478bd9Sstevel@tonic-gate curthread->t_flag &= ~T_WOULDBLOCK; 30417c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX; 30427c478bd9Sstevel@tonic-gate } else 30437c478bd9Sstevel@tonic-gate resp->status = puterrno3(error); 30447c478bd9Sstevel@tonic-gate out1: 3045b89a8333Snatalie li - Sun Microsystems - Irvine United States if (name != NULL && name != args->link.name) 3046b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(name, MAXPATHLEN + 1); 3047b89a8333Snatalie li - Sun Microsystems - Irvine United States 3048e1adf50cSahl DTRACE_NFSV3_4(op__link__done, struct svc_req *, req, 3049e1adf50cSahl cred_t *, cr, vnode_t *, vp, LINK3res *, resp); 3050e1adf50cSahl 30517c478bd9Sstevel@tonic-gate if (vp != NULL) 30527c478bd9Sstevel@tonic-gate VN_RELE(vp); 30537c478bd9Sstevel@tonic-gate if (dvp != NULL) 30547c478bd9Sstevel@tonic-gate VN_RELE(dvp); 30557c478bd9Sstevel@tonic-gate vattr_to_post_op_attr(vap, &resp->resfail.file_attributes); 30567c478bd9Sstevel@tonic-gate vattr_to_wcc_data(bvap, avap, &resp->resfail.linkdir_wcc); 30577c478bd9Sstevel@tonic-gate } 30587c478bd9Sstevel@tonic-gate 305927242a7cSthurlow void * 30607c478bd9Sstevel@tonic-gate rfs3_link_getfh(LINK3args *args) 30617c478bd9Sstevel@tonic-gate { 30627c478bd9Sstevel@tonic-gate 306327242a7cSthurlow return (&args->file); 30647c478bd9Sstevel@tonic-gate } 30657c478bd9Sstevel@tonic-gate 30667c478bd9Sstevel@tonic-gate /* 30677c478bd9Sstevel@tonic-gate * This macro defines the size of a response which contains attribute 30687c478bd9Sstevel@tonic-gate * information and one directory entry (whose length is specified by 30697c478bd9Sstevel@tonic-gate * the macro parameter). If the incoming request is larger than this, 30707c478bd9Sstevel@tonic-gate * then we are guaranteed to be able to return at one directory entry 30717c478bd9Sstevel@tonic-gate * if one exists. Therefore, we do not need to check for 30727c478bd9Sstevel@tonic-gate * NFS3ERR_TOOSMALL if the requested size is larger then this. If it 30737c478bd9Sstevel@tonic-gate * is not, then we need to check to make sure that this error does not 30747c478bd9Sstevel@tonic-gate * need to be returned. 30757c478bd9Sstevel@tonic-gate * 30767c478bd9Sstevel@tonic-gate * NFS3_READDIR_MIN_COUNT is comprised of following : 30777c478bd9Sstevel@tonic-gate * 30787c478bd9Sstevel@tonic-gate * status - 1 * BYTES_PER_XDR_UNIT 30797c478bd9Sstevel@tonic-gate * attr. flag - 1 * BYTES_PER_XDR_UNIT 30807c478bd9Sstevel@tonic-gate * cookie verifier - 2 * BYTES_PER_XDR_UNIT 30817c478bd9Sstevel@tonic-gate * attributes - NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT 30827c478bd9Sstevel@tonic-gate * boolean - 1 * BYTES_PER_XDR_UNIT 30837c478bd9Sstevel@tonic-gate * file id - 2 * BYTES_PER_XDR_UNIT 3084da6c28aaSamw * directory name length - 1 * BYTES_PER_XDR_UNIT 30857c478bd9Sstevel@tonic-gate * cookie - 2 * BYTES_PER_XDR_UNIT 30867c478bd9Sstevel@tonic-gate * end of list - 1 * BYTES_PER_XDR_UNIT 30877c478bd9Sstevel@tonic-gate * end of file - 1 * BYTES_PER_XDR_UNIT 30887c478bd9Sstevel@tonic-gate * Name length of directory to the nearest byte 30897c478bd9Sstevel@tonic-gate */ 30907c478bd9Sstevel@tonic-gate 30917c478bd9Sstevel@tonic-gate #define NFS3_READDIR_MIN_COUNT(length) \ 30927c478bd9Sstevel@tonic-gate ((1 + 1 + 2 + NFS3_SIZEOF_FATTR3 + 1 + 2 + 1 + 2 + 1 + 1) * \ 30937c478bd9Sstevel@tonic-gate BYTES_PER_XDR_UNIT + roundup((length), BYTES_PER_XDR_UNIT)) 30947c478bd9Sstevel@tonic-gate 30957c478bd9Sstevel@tonic-gate /* ARGSUSED */ 30967c478bd9Sstevel@tonic-gate void 30977c478bd9Sstevel@tonic-gate rfs3_readdir(READDIR3args *args, READDIR3res *resp, struct exportinfo *exi, 30985cb0d679SMarcel Telka struct svc_req *req, cred_t *cr, bool_t ro) 30997c478bd9Sstevel@tonic-gate { 31007c478bd9Sstevel@tonic-gate int error; 31017c478bd9Sstevel@tonic-gate vnode_t *vp; 31027c478bd9Sstevel@tonic-gate struct vattr *vap; 31037c478bd9Sstevel@tonic-gate struct vattr va; 31047c478bd9Sstevel@tonic-gate struct iovec iov; 31057c478bd9Sstevel@tonic-gate struct uio uio; 31067c478bd9Sstevel@tonic-gate char *data; 31077c478bd9Sstevel@tonic-gate int iseof; 31087c478bd9Sstevel@tonic-gate int bufsize; 31097c478bd9Sstevel@tonic-gate int namlen; 31107c478bd9Sstevel@tonic-gate uint_t count; 3111b89a8333Snatalie li - Sun Microsystems - Irvine United States struct sockaddr *ca; 31127c478bd9Sstevel@tonic-gate 31137c478bd9Sstevel@tonic-gate vap = NULL; 31147c478bd9Sstevel@tonic-gate 31157c478bd9Sstevel@tonic-gate vp = nfs3_fhtovp(&args->dir, exi); 3116e1adf50cSahl 3117e1adf50cSahl DTRACE_NFSV3_4(op__readdir__start, struct svc_req *, req, 3118e1adf50cSahl cred_t *, cr, vnode_t *, vp, READDIR3args *, args); 3119e1adf50cSahl 31207c478bd9Sstevel@tonic-gate if (vp == NULL) { 31217c478bd9Sstevel@tonic-gate error = ESTALE; 31227c478bd9Sstevel@tonic-gate goto out; 31237c478bd9Sstevel@tonic-gate } 31247c478bd9Sstevel@tonic-gate 312503986916Sjarrett if (is_system_labeled()) { 312603986916Sjarrett bslabel_t *clabel = req->rq_label; 312703986916Sjarrett 312803986916Sjarrett ASSERT(clabel != NULL); 312903986916Sjarrett DTRACE_PROBE2(tx__rfs3__log__info__opreaddir__clabel, char *, 313003986916Sjarrett "got client label from request(1)", struct svc_req *, req); 313103986916Sjarrett 313203986916Sjarrett if (!blequal(&l_admin_low->tsl_label, clabel)) { 3133bd6f1640SJarrett Lu if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK, 3134bd6f1640SJarrett Lu exi)) { 313503986916Sjarrett resp->status = NFS3ERR_ACCES; 313603986916Sjarrett goto out1; 313703986916Sjarrett } 313803986916Sjarrett } 313903986916Sjarrett } 314003986916Sjarrett 31417c478bd9Sstevel@tonic-gate (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL); 31427c478bd9Sstevel@tonic-gate 31437c478bd9Sstevel@tonic-gate va.va_mask = AT_ALL; 3144da6c28aaSamw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 31457c478bd9Sstevel@tonic-gate 31467c478bd9Sstevel@tonic-gate if (vp->v_type != VDIR) { 31477c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_NOTDIR; 31487c478bd9Sstevel@tonic-gate goto out1; 31497c478bd9Sstevel@tonic-gate } 31507c478bd9Sstevel@tonic-gate 3151da6c28aaSamw error = VOP_ACCESS(vp, VREAD, 0, cr, NULL); 31527c478bd9Sstevel@tonic-gate if (error) 31537c478bd9Sstevel@tonic-gate goto out; 31547c478bd9Sstevel@tonic-gate 31557c478bd9Sstevel@tonic-gate /* 31567c478bd9Sstevel@tonic-gate * Now don't allow arbitrary count to alloc; 31577c478bd9Sstevel@tonic-gate * allow the maximum not to exceed rfs3_tsize() 31587c478bd9Sstevel@tonic-gate */ 31597c478bd9Sstevel@tonic-gate if (args->count > rfs3_tsize(req)) 31607c478bd9Sstevel@tonic-gate args->count = rfs3_tsize(req); 31617c478bd9Sstevel@tonic-gate 31627c478bd9Sstevel@tonic-gate /* 31637c478bd9Sstevel@tonic-gate * Make sure that there is room to read at least one entry 31647c478bd9Sstevel@tonic-gate * if any are available. 31657c478bd9Sstevel@tonic-gate */ 31667c478bd9Sstevel@tonic-gate if (args->count < DIRENT64_RECLEN(MAXNAMELEN)) 31677c478bd9Sstevel@tonic-gate count = DIRENT64_RECLEN(MAXNAMELEN); 31687c478bd9Sstevel@tonic-gate else 31697c478bd9Sstevel@tonic-gate count = args->count; 31707c478bd9Sstevel@tonic-gate 31717c478bd9Sstevel@tonic-gate data = kmem_alloc(count, KM_SLEEP); 31727c478bd9Sstevel@tonic-gate 31737c478bd9Sstevel@tonic-gate iov.iov_base = data; 31747c478bd9Sstevel@tonic-gate iov.iov_len = count; 31757c478bd9Sstevel@tonic-gate uio.uio_iov = &iov; 31767c478bd9Sstevel@tonic-gate uio.uio_iovcnt = 1; 31777c478bd9Sstevel@tonic-gate uio.uio_segflg = UIO_SYSSPACE; 31787c478bd9Sstevel@tonic-gate uio.uio_extflg = UIO_COPY_CACHED; 31797c478bd9Sstevel@tonic-gate uio.uio_loffset = (offset_t)args->cookie; 31807c478bd9Sstevel@tonic-gate uio.uio_resid = count; 31817c478bd9Sstevel@tonic-gate 3182da6c28aaSamw error = VOP_READDIR(vp, &uio, cr, &iseof, NULL, 0); 31837c478bd9Sstevel@tonic-gate 31847c478bd9Sstevel@tonic-gate va.va_mask = AT_ALL; 3185da6c28aaSamw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 31867c478bd9Sstevel@tonic-gate 31877c478bd9Sstevel@tonic-gate if (error) { 31887c478bd9Sstevel@tonic-gate kmem_free(data, count); 31897c478bd9Sstevel@tonic-gate goto out; 31907c478bd9Sstevel@tonic-gate } 31917c478bd9Sstevel@tonic-gate 31927c478bd9Sstevel@tonic-gate /* 31937c478bd9Sstevel@tonic-gate * If the count was not large enough to be able to guarantee 31947c478bd9Sstevel@tonic-gate * to be able to return at least one entry, then need to 31957c478bd9Sstevel@tonic-gate * check to see if NFS3ERR_TOOSMALL should be returned. 31967c478bd9Sstevel@tonic-gate */ 31977c478bd9Sstevel@tonic-gate if (args->count < NFS3_READDIR_MIN_COUNT(MAXNAMELEN)) { 31987c478bd9Sstevel@tonic-gate /* 31997c478bd9Sstevel@tonic-gate * bufsize is used to keep track of the size of the response. 32007c478bd9Sstevel@tonic-gate * It is primed with: 32017c478bd9Sstevel@tonic-gate * 1 for the status + 32027c478bd9Sstevel@tonic-gate * 1 for the dir_attributes.attributes boolean + 32037c478bd9Sstevel@tonic-gate * 2 for the cookie verifier 32047c478bd9Sstevel@tonic-gate * all times BYTES_PER_XDR_UNIT to convert from XDR units 32057c478bd9Sstevel@tonic-gate * to bytes. If there are directory attributes to be 32067c478bd9Sstevel@tonic-gate * returned, then: 32077c478bd9Sstevel@tonic-gate * NFS3_SIZEOF_FATTR3 for the dir_attributes.attr fattr3 32087c478bd9Sstevel@tonic-gate * time BYTES_PER_XDR_UNIT is added to account for them. 32097c478bd9Sstevel@tonic-gate */ 32107c478bd9Sstevel@tonic-gate bufsize = (1 + 1 + 2) * BYTES_PER_XDR_UNIT; 32117c478bd9Sstevel@tonic-gate if (vap != NULL) 32127c478bd9Sstevel@tonic-gate bufsize += NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT; 32137c478bd9Sstevel@tonic-gate /* 32147c478bd9Sstevel@tonic-gate * An entry is composed of: 32157c478bd9Sstevel@tonic-gate * 1 for the true/false list indicator + 32167c478bd9Sstevel@tonic-gate * 2 for the fileid + 32177c478bd9Sstevel@tonic-gate * 1 for the length of the name + 32187c478bd9Sstevel@tonic-gate * 2 for the cookie + 32197c478bd9Sstevel@tonic-gate * all times BYTES_PER_XDR_UNIT to convert from 32207c478bd9Sstevel@tonic-gate * XDR units to bytes, plus the length of the name 32217c478bd9Sstevel@tonic-gate * rounded up to the nearest BYTES_PER_XDR_UNIT. 32227c478bd9Sstevel@tonic-gate */ 32237c478bd9Sstevel@tonic-gate if (count != uio.uio_resid) { 32247c478bd9Sstevel@tonic-gate namlen = strlen(((struct dirent64 *)data)->d_name); 32257c478bd9Sstevel@tonic-gate bufsize += (1 + 2 + 1 + 2) * BYTES_PER_XDR_UNIT + 32267c478bd9Sstevel@tonic-gate roundup(namlen, BYTES_PER_XDR_UNIT); 32277c478bd9Sstevel@tonic-gate } 32287c478bd9Sstevel@tonic-gate /* 32297c478bd9Sstevel@tonic-gate * We need to check to see if the number of bytes left 32307c478bd9Sstevel@tonic-gate * to go into the buffer will actually fit into the 32317c478bd9Sstevel@tonic-gate * buffer. This is calculated as the size of this 32327c478bd9Sstevel@tonic-gate * entry plus: 32337c478bd9Sstevel@tonic-gate * 1 for the true/false list indicator + 32347c478bd9Sstevel@tonic-gate * 1 for the eof indicator 32357c478bd9Sstevel@tonic-gate * times BYTES_PER_XDR_UNIT to convert from from 32367c478bd9Sstevel@tonic-gate * XDR units to bytes. 32377c478bd9Sstevel@tonic-gate */ 32387c478bd9Sstevel@tonic-gate bufsize += (1 + 1) * BYTES_PER_XDR_UNIT; 32397c478bd9Sstevel@tonic-gate if (bufsize > args->count) { 32407c478bd9Sstevel@tonic-gate kmem_free(data, count); 32417c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_TOOSMALL; 32427c478bd9Sstevel@tonic-gate goto out1; 32437c478bd9Sstevel@tonic-gate } 32447c478bd9Sstevel@tonic-gate } 32457c478bd9Sstevel@tonic-gate 3246b89a8333Snatalie li - Sun Microsystems - Irvine United States /* 3247b89a8333Snatalie li - Sun Microsystems - Irvine United States * Have a valid readir buffer for the native character 3248b89a8333Snatalie li - Sun Microsystems - Irvine United States * set. Need to check if a conversion is necessary and 3249b89a8333Snatalie li - Sun Microsystems - Irvine United States * potentially rewrite the whole buffer. Note that if the 3250b89a8333Snatalie li - Sun Microsystems - Irvine United States * conversion expands names enough, the structure may not 3251b89a8333Snatalie li - Sun Microsystems - Irvine United States * fit. In this case, we need to drop entries until if fits 3252b89a8333Snatalie li - Sun Microsystems - Irvine United States * and patch the counts in order that the next readdir will 3253b89a8333Snatalie li - Sun Microsystems - Irvine United States * get the correct entries. 3254b89a8333Snatalie li - Sun Microsystems - Irvine United States */ 3255b89a8333Snatalie li - Sun Microsystems - Irvine United States ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 3256b89a8333Snatalie li - Sun Microsystems - Irvine United States data = nfscmd_convdirent(ca, exi, data, count, &resp->status); 3257b89a8333Snatalie li - Sun Microsystems - Irvine United States 3258b89a8333Snatalie li - Sun Microsystems - Irvine United States 32597c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL); 32607c478bd9Sstevel@tonic-gate 32617c478bd9Sstevel@tonic-gate #if 0 /* notyet */ 32627c478bd9Sstevel@tonic-gate /* 32637c478bd9Sstevel@tonic-gate * Don't do this. It causes local disk writes when just 32647c478bd9Sstevel@tonic-gate * reading the file and the overhead is deemed larger 32657c478bd9Sstevel@tonic-gate * than the benefit. 32667c478bd9Sstevel@tonic-gate */ 32677c478bd9Sstevel@tonic-gate /* 32687c478bd9Sstevel@tonic-gate * Force modified metadata out to stable storage. 32697c478bd9Sstevel@tonic-gate */ 3270da6c28aaSamw (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL); 32717c478bd9Sstevel@tonic-gate #endif 32727c478bd9Sstevel@tonic-gate 32737c478bd9Sstevel@tonic-gate resp->status = NFS3_OK; 32747c478bd9Sstevel@tonic-gate vattr_to_post_op_attr(vap, &resp->resok.dir_attributes); 32757c478bd9Sstevel@tonic-gate resp->resok.cookieverf = 0; 32767c478bd9Sstevel@tonic-gate resp->resok.reply.entries = (entry3 *)data; 32777c478bd9Sstevel@tonic-gate resp->resok.reply.eof = iseof; 32787c478bd9Sstevel@tonic-gate resp->resok.size = count - uio.uio_resid; 32797c478bd9Sstevel@tonic-gate resp->resok.count = args->count; 32807c478bd9Sstevel@tonic-gate resp->resok.freecount = count; 3281e1adf50cSahl 3282e1adf50cSahl DTRACE_NFSV3_4(op__readdir__done, struct svc_req *, req, 3283e1adf50cSahl cred_t *, cr, vnode_t *, vp, READDIR3res *, resp); 3284e1adf50cSahl 3285e1adf50cSahl VN_RELE(vp); 3286e1adf50cSahl 32877c478bd9Sstevel@tonic-gate return; 32887c478bd9Sstevel@tonic-gate 32897c478bd9Sstevel@tonic-gate out: 32907c478bd9Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK) { 32917c478bd9Sstevel@tonic-gate curthread->t_flag &= ~T_WOULDBLOCK; 32927c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX; 32937c478bd9Sstevel@tonic-gate } else 32947c478bd9Sstevel@tonic-gate resp->status = puterrno3(error); 32957c478bd9Sstevel@tonic-gate out1: 3296e1adf50cSahl DTRACE_NFSV3_4(op__readdir__done, struct svc_req *, req, 3297e1adf50cSahl cred_t *, cr, vnode_t *, vp, READDIR3res *, resp); 3298e1adf50cSahl 32997c478bd9Sstevel@tonic-gate if (vp != NULL) { 33007c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL); 33017c478bd9Sstevel@tonic-gate VN_RELE(vp); 33027c478bd9Sstevel@tonic-gate } 33037c478bd9Sstevel@tonic-gate vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes); 33047c478bd9Sstevel@tonic-gate } 33057c478bd9Sstevel@tonic-gate 330627242a7cSthurlow void * 33077c478bd9Sstevel@tonic-gate rfs3_readdir_getfh(READDIR3args *args) 33087c478bd9Sstevel@tonic-gate { 33097c478bd9Sstevel@tonic-gate 331027242a7cSthurlow return (&args->dir); 33117c478bd9Sstevel@tonic-gate } 33127c478bd9Sstevel@tonic-gate 33137c478bd9Sstevel@tonic-gate void 33147c478bd9Sstevel@tonic-gate rfs3_readdir_free(READDIR3res *resp) 33157c478bd9Sstevel@tonic-gate { 33167c478bd9Sstevel@tonic-gate 33177c478bd9Sstevel@tonic-gate if (resp->status == NFS3_OK) 33187c478bd9Sstevel@tonic-gate kmem_free(resp->resok.reply.entries, resp->resok.freecount); 33197c478bd9Sstevel@tonic-gate } 33207c478bd9Sstevel@tonic-gate 33217c478bd9Sstevel@tonic-gate #ifdef nextdp 33227c478bd9Sstevel@tonic-gate #undef nextdp 33237c478bd9Sstevel@tonic-gate #endif 33247c478bd9Sstevel@tonic-gate #define nextdp(dp) ((struct dirent64 *)((char *)(dp) + (dp)->d_reclen)) 33257c478bd9Sstevel@tonic-gate 33267c478bd9Sstevel@tonic-gate /* 33277c478bd9Sstevel@tonic-gate * This macro computes the size of a response which contains 33287c478bd9Sstevel@tonic-gate * one directory entry including the attributes as well as file handle. 33297c478bd9Sstevel@tonic-gate * If the incoming request is larger than this, then we are guaranteed to be 33307c478bd9Sstevel@tonic-gate * able to return at least one more directory entry if one exists. 33317c478bd9Sstevel@tonic-gate * 33327c478bd9Sstevel@tonic-gate * NFS3_READDIRPLUS_ENTRY is made up of the following: 33337c478bd9Sstevel@tonic-gate * 33347c478bd9Sstevel@tonic-gate * boolean - 1 * BYTES_PER_XDR_UNIT 33357c478bd9Sstevel@tonic-gate * file id - 2 * BYTES_PER_XDR_UNIT 33367c478bd9Sstevel@tonic-gate * directory name length - 1 * BYTES_PER_XDR_UNIT 33377c478bd9Sstevel@tonic-gate * cookie - 2 * BYTES_PER_XDR_UNIT 33387c478bd9Sstevel@tonic-gate * attribute flag - 1 * BYTES_PER_XDR_UNIT 33397c478bd9Sstevel@tonic-gate * attributes - NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT 33407c478bd9Sstevel@tonic-gate * status byte for file handle - 1 * BYTES_PER_XDR_UNIT 33417c478bd9Sstevel@tonic-gate * length of a file handle - 1 * BYTES_PER_XDR_UNIT 3342da6c28aaSamw * Maximum length of a file handle (NFS3_MAXFHSIZE) 33437c478bd9Sstevel@tonic-gate * name length of the entry to the nearest bytes 33447c478bd9Sstevel@tonic-gate */ 33457c478bd9Sstevel@tonic-gate #define NFS3_READDIRPLUS_ENTRY(namelen) \ 33467c478bd9Sstevel@tonic-gate ((1 + 2 + 1 + 2 + 1 + NFS3_SIZEOF_FATTR3 + 1 + 1) * \ 33477c478bd9Sstevel@tonic-gate BYTES_PER_XDR_UNIT + \ 334827242a7cSthurlow NFS3_MAXFHSIZE + roundup(namelen, BYTES_PER_XDR_UNIT)) 33497c478bd9Sstevel@tonic-gate 33507c478bd9Sstevel@tonic-gate static int rfs3_readdir_unit = MAXBSIZE; 33517c478bd9Sstevel@tonic-gate 33527c478bd9Sstevel@tonic-gate /* ARGSUSED */ 33537c478bd9Sstevel@tonic-gate void 33547c478bd9Sstevel@tonic-gate rfs3_readdirplus(READDIRPLUS3args *args, READDIRPLUS3res *resp, 33555cb0d679SMarcel Telka struct exportinfo *exi, struct svc_req *req, cred_t *cr, bool_t ro) 33567c478bd9Sstevel@tonic-gate { 33577c478bd9Sstevel@tonic-gate int error; 33587c478bd9Sstevel@tonic-gate vnode_t *vp; 33597c478bd9Sstevel@tonic-gate struct vattr *vap; 33607c478bd9Sstevel@tonic-gate struct vattr va; 33617c478bd9Sstevel@tonic-gate struct iovec iov; 33627c478bd9Sstevel@tonic-gate struct uio uio; 33637c478bd9Sstevel@tonic-gate char *data; 33647c478bd9Sstevel@tonic-gate int iseof; 33657c478bd9Sstevel@tonic-gate struct dirent64 *dp; 33667c478bd9Sstevel@tonic-gate vnode_t *nvp; 33677c478bd9Sstevel@tonic-gate struct vattr *nvap; 33687c478bd9Sstevel@tonic-gate struct vattr nva; 33697c478bd9Sstevel@tonic-gate entryplus3_info *infop = NULL; 33707c478bd9Sstevel@tonic-gate int size = 0; 33717c478bd9Sstevel@tonic-gate int nents = 0; 33727c478bd9Sstevel@tonic-gate int bufsize = 0; 33737c478bd9Sstevel@tonic-gate int entrysize = 0; 33747c478bd9Sstevel@tonic-gate int tofit = 0; 33757c478bd9Sstevel@tonic-gate int rd_unit = rfs3_readdir_unit; 33767c478bd9Sstevel@tonic-gate int prev_len; 33777c478bd9Sstevel@tonic-gate int space_left; 33787c478bd9Sstevel@tonic-gate int i; 33797c478bd9Sstevel@tonic-gate uint_t *namlen = NULL; 3380b89a8333Snatalie li - Sun Microsystems - Irvine United States char *ndata = NULL; 3381b89a8333Snatalie li - Sun Microsystems - Irvine United States struct sockaddr *ca; 3382b89a8333Snatalie li - Sun Microsystems - Irvine United States size_t ret; 33837c478bd9Sstevel@tonic-gate 33847c478bd9Sstevel@tonic-gate vap = NULL; 33857c478bd9Sstevel@tonic-gate 33867c478bd9Sstevel@tonic-gate vp = nfs3_fhtovp(&args->dir, exi); 3387e1adf50cSahl 3388e1adf50cSahl DTRACE_NFSV3_4(op__readdirplus__start, struct svc_req *, req, 3389e1adf50cSahl cred_t *, cr, vnode_t *, vp, READDIRPLUS3args *, args); 3390e1adf50cSahl 33917c478bd9Sstevel@tonic-gate if (vp == NULL) { 33927c478bd9Sstevel@tonic-gate error = ESTALE; 33937c478bd9Sstevel@tonic-gate goto out; 33947c478bd9Sstevel@tonic-gate } 33957c478bd9Sstevel@tonic-gate 339603986916Sjarrett if (is_system_labeled()) { 339703986916Sjarrett bslabel_t *clabel = req->rq_label; 339803986916Sjarrett 339903986916Sjarrett ASSERT(clabel != NULL); 340003986916Sjarrett DTRACE_PROBE2(tx__rfs3__log__info__opreaddirplus__clabel, 340103986916Sjarrett char *, "got client label from request(1)", 340203986916Sjarrett struct svc_req *, req); 340303986916Sjarrett 340403986916Sjarrett if (!blequal(&l_admin_low->tsl_label, clabel)) { 3405bd6f1640SJarrett Lu if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK, 3406bd6f1640SJarrett Lu exi)) { 340703986916Sjarrett resp->status = NFS3ERR_ACCES; 340803986916Sjarrett goto out1; 340903986916Sjarrett } 341003986916Sjarrett } 341103986916Sjarrett } 341203986916Sjarrett 34137c478bd9Sstevel@tonic-gate (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL); 34147c478bd9Sstevel@tonic-gate 34157c478bd9Sstevel@tonic-gate va.va_mask = AT_ALL; 3416da6c28aaSamw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 34177c478bd9Sstevel@tonic-gate 34187c478bd9Sstevel@tonic-gate if (vp->v_type != VDIR) { 34197c478bd9Sstevel@tonic-gate error = ENOTDIR; 34207c478bd9Sstevel@tonic-gate goto out; 34217c478bd9Sstevel@tonic-gate } 34227c478bd9Sstevel@tonic-gate 3423da6c28aaSamw error = VOP_ACCESS(vp, VREAD, 0, cr, NULL); 34247c478bd9Sstevel@tonic-gate if (error) 34257c478bd9Sstevel@tonic-gate goto out; 34267c478bd9Sstevel@tonic-gate 34277c478bd9Sstevel@tonic-gate /* 34287c478bd9Sstevel@tonic-gate * Don't allow arbitrary counts for allocation 34297c478bd9Sstevel@tonic-gate */ 34307c478bd9Sstevel@tonic-gate if (args->maxcount > rfs3_tsize(req)) 34317c478bd9Sstevel@tonic-gate args->maxcount = rfs3_tsize(req); 34327c478bd9Sstevel@tonic-gate 34337c478bd9Sstevel@tonic-gate /* 34347c478bd9Sstevel@tonic-gate * Make sure that there is room to read at least one entry 34357c478bd9Sstevel@tonic-gate * if any are available 34367c478bd9Sstevel@tonic-gate */ 34377c478bd9Sstevel@tonic-gate args->dircount = MIN(args->dircount, args->maxcount); 34387c478bd9Sstevel@tonic-gate 34397c478bd9Sstevel@tonic-gate if (args->dircount < DIRENT64_RECLEN(MAXNAMELEN)) 34407c478bd9Sstevel@tonic-gate args->dircount = DIRENT64_RECLEN(MAXNAMELEN); 34417c478bd9Sstevel@tonic-gate 34427c478bd9Sstevel@tonic-gate /* 34437c478bd9Sstevel@tonic-gate * This allocation relies on a minimum directory entry 34447c478bd9Sstevel@tonic-gate * being roughly 24 bytes. Therefore, the namlen array 34457c478bd9Sstevel@tonic-gate * will have enough space based on the maximum number of 34467c478bd9Sstevel@tonic-gate * entries to read. 34477c478bd9Sstevel@tonic-gate */ 34487c478bd9Sstevel@tonic-gate namlen = kmem_alloc(args->dircount, KM_SLEEP); 34497c478bd9Sstevel@tonic-gate 34507c478bd9Sstevel@tonic-gate space_left = args->dircount; 34517c478bd9Sstevel@tonic-gate data = kmem_alloc(args->dircount, KM_SLEEP); 34527c478bd9Sstevel@tonic-gate dp = (struct dirent64 *)data; 34537c478bd9Sstevel@tonic-gate uio.uio_iov = &iov; 34547c478bd9Sstevel@tonic-gate uio.uio_iovcnt = 1; 34557c478bd9Sstevel@tonic-gate uio.uio_segflg = UIO_SYSSPACE; 34567c478bd9Sstevel@tonic-gate uio.uio_extflg = UIO_COPY_CACHED; 34577c478bd9Sstevel@tonic-gate uio.uio_loffset = (offset_t)args->cookie; 34587c478bd9Sstevel@tonic-gate 34597c478bd9Sstevel@tonic-gate /* 34607c478bd9Sstevel@tonic-gate * bufsize is used to keep track of the size of the response as we 34617c478bd9Sstevel@tonic-gate * get post op attributes and filehandles for each entry. This is 34627c478bd9Sstevel@tonic-gate * an optimization as the server may have read more entries than will 34637c478bd9Sstevel@tonic-gate * fit in the buffer specified by maxcount. We stop calculating 34647c478bd9Sstevel@tonic-gate * post op attributes and filehandles once we have exceeded maxcount. 34657c478bd9Sstevel@tonic-gate * This will minimize the effect of truncation. 34667c478bd9Sstevel@tonic-gate * 34677c478bd9Sstevel@tonic-gate * It is primed with: 34687c478bd9Sstevel@tonic-gate * 1 for the status + 34697c478bd9Sstevel@tonic-gate * 1 for the dir_attributes.attributes boolean + 34707c478bd9Sstevel@tonic-gate * 2 for the cookie verifier 34717c478bd9Sstevel@tonic-gate * all times BYTES_PER_XDR_UNIT to convert from XDR units 34727c478bd9Sstevel@tonic-gate * to bytes. If there are directory attributes to be 34737c478bd9Sstevel@tonic-gate * returned, then: 34747c478bd9Sstevel@tonic-gate * NFS3_SIZEOF_FATTR3 for the dir_attributes.attr fattr3 34757c478bd9Sstevel@tonic-gate * time BYTES_PER_XDR_UNIT is added to account for them. 34767c478bd9Sstevel@tonic-gate */ 34777c478bd9Sstevel@tonic-gate bufsize = (1 + 1 + 2) * BYTES_PER_XDR_UNIT; 34787c478bd9Sstevel@tonic-gate if (vap != NULL) 34797c478bd9Sstevel@tonic-gate bufsize += NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT; 34807c478bd9Sstevel@tonic-gate 34817c478bd9Sstevel@tonic-gate getmoredents: 34827c478bd9Sstevel@tonic-gate /* 34837c478bd9Sstevel@tonic-gate * Here we make a check so that our read unit is not larger than 34847c478bd9Sstevel@tonic-gate * the space left in the buffer. 34857c478bd9Sstevel@tonic-gate */ 34867c478bd9Sstevel@tonic-gate rd_unit = MIN(rd_unit, space_left); 34877c478bd9Sstevel@tonic-gate iov.iov_base = (char *)dp; 34887c478bd9Sstevel@tonic-gate iov.iov_len = rd_unit; 34897c478bd9Sstevel@tonic-gate uio.uio_resid = rd_unit; 34907c478bd9Sstevel@tonic-gate prev_len = rd_unit; 34917c478bd9Sstevel@tonic-gate 3492da6c28aaSamw error = VOP_READDIR(vp, &uio, cr, &iseof, NULL, 0); 34937c478bd9Sstevel@tonic-gate 34947c478bd9Sstevel@tonic-gate if (error) { 34957c478bd9Sstevel@tonic-gate kmem_free(data, args->dircount); 34967c478bd9Sstevel@tonic-gate goto out; 34977c478bd9Sstevel@tonic-gate } 34987c478bd9Sstevel@tonic-gate 34997c478bd9Sstevel@tonic-gate if (uio.uio_resid == prev_len && !iseof) { 35007c478bd9Sstevel@tonic-gate if (nents == 0) { 35017c478bd9Sstevel@tonic-gate kmem_free(data, args->dircount); 35027c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_TOOSMALL; 35037c478bd9Sstevel@tonic-gate goto out1; 35047c478bd9Sstevel@tonic-gate } 35057c478bd9Sstevel@tonic-gate 35067c478bd9Sstevel@tonic-gate /* 35077c478bd9Sstevel@tonic-gate * We could not get any more entries, so get the attributes 35087c478bd9Sstevel@tonic-gate * and filehandle for the entries already obtained. 35097c478bd9Sstevel@tonic-gate */ 35107c478bd9Sstevel@tonic-gate goto good; 35117c478bd9Sstevel@tonic-gate } 35127c478bd9Sstevel@tonic-gate 35137c478bd9Sstevel@tonic-gate /* 35147c478bd9Sstevel@tonic-gate * We estimate the size of the response by assuming the 35157c478bd9Sstevel@tonic-gate * entry exists and attributes and filehandle are also valid 35167c478bd9Sstevel@tonic-gate */ 35177c478bd9Sstevel@tonic-gate for (size = prev_len - uio.uio_resid; 35187c478bd9Sstevel@tonic-gate size > 0; 35197c478bd9Sstevel@tonic-gate size -= dp->d_reclen, dp = nextdp(dp)) { 35207c478bd9Sstevel@tonic-gate 35217c478bd9Sstevel@tonic-gate if (dp->d_ino == 0) { 35227c478bd9Sstevel@tonic-gate nents++; 35237c478bd9Sstevel@tonic-gate continue; 35247c478bd9Sstevel@tonic-gate } 35257c478bd9Sstevel@tonic-gate 35267c478bd9Sstevel@tonic-gate namlen[nents] = strlen(dp->d_name); 35277c478bd9Sstevel@tonic-gate entrysize = NFS3_READDIRPLUS_ENTRY(namlen[nents]); 35287c478bd9Sstevel@tonic-gate 35297c478bd9Sstevel@tonic-gate /* 35307c478bd9Sstevel@tonic-gate * We need to check to see if the number of bytes left 35317c478bd9Sstevel@tonic-gate * to go into the buffer will actually fit into the 35327c478bd9Sstevel@tonic-gate * buffer. This is calculated as the size of this 35337c478bd9Sstevel@tonic-gate * entry plus: 35347c478bd9Sstevel@tonic-gate * 1 for the true/false list indicator + 35357c478bd9Sstevel@tonic-gate * 1 for the eof indicator 35367c478bd9Sstevel@tonic-gate * times BYTES_PER_XDR_UNIT to convert from XDR units 35377c478bd9Sstevel@tonic-gate * to bytes. 35387c478bd9Sstevel@tonic-gate * 35397c478bd9Sstevel@tonic-gate * Also check the dircount limit against the first entry read 35407c478bd9Sstevel@tonic-gate * 35417c478bd9Sstevel@tonic-gate */ 35427c478bd9Sstevel@tonic-gate tofit = entrysize + (1 + 1) * BYTES_PER_XDR_UNIT; 35437c478bd9Sstevel@tonic-gate if (bufsize + tofit > args->maxcount) { 35447c478bd9Sstevel@tonic-gate /* 35457c478bd9Sstevel@tonic-gate * We make a check here to see if this was the 35467c478bd9Sstevel@tonic-gate * first entry being measured. If so, then maxcount 35477c478bd9Sstevel@tonic-gate * was too small to begin with and so we need to 35487c478bd9Sstevel@tonic-gate * return with NFS3ERR_TOOSMALL. 35497c478bd9Sstevel@tonic-gate */ 35507c478bd9Sstevel@tonic-gate if (nents == 0) { 35517c478bd9Sstevel@tonic-gate kmem_free(data, args->dircount); 35527c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_TOOSMALL; 35537c478bd9Sstevel@tonic-gate goto out1; 35547c478bd9Sstevel@tonic-gate } 35557c478bd9Sstevel@tonic-gate iseof = FALSE; 35567c478bd9Sstevel@tonic-gate goto good; 35577c478bd9Sstevel@tonic-gate } 35587c478bd9Sstevel@tonic-gate bufsize += entrysize; 35597c478bd9Sstevel@tonic-gate nents++; 35607c478bd9Sstevel@tonic-gate } 35617c478bd9Sstevel@tonic-gate 35627c478bd9Sstevel@tonic-gate /* 35637c478bd9Sstevel@tonic-gate * If there is enough room to fit at least 1 more entry including 35647c478bd9Sstevel@tonic-gate * post op attributes and filehandle in the buffer AND that we haven't 35657c478bd9Sstevel@tonic-gate * exceeded dircount then go back and get some more. 35667c478bd9Sstevel@tonic-gate */ 35677c478bd9Sstevel@tonic-gate if (!iseof && 35687c478bd9Sstevel@tonic-gate (args->maxcount - bufsize) >= NFS3_READDIRPLUS_ENTRY(MAXNAMELEN)) { 35697c478bd9Sstevel@tonic-gate space_left -= (prev_len - uio.uio_resid); 35707c478bd9Sstevel@tonic-gate if (space_left >= DIRENT64_RECLEN(MAXNAMELEN)) 35717c478bd9Sstevel@tonic-gate goto getmoredents; 35727c478bd9Sstevel@tonic-gate 35737c478bd9Sstevel@tonic-gate /* else, fall through */ 35747c478bd9Sstevel@tonic-gate } 35757c478bd9Sstevel@tonic-gate good: 35767c478bd9Sstevel@tonic-gate va.va_mask = AT_ALL; 3577da6c28aaSamw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 35787c478bd9Sstevel@tonic-gate 35797c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL); 35807c478bd9Sstevel@tonic-gate 35817c478bd9Sstevel@tonic-gate infop = kmem_alloc(nents * sizeof (struct entryplus3_info), KM_SLEEP); 35827c478bd9Sstevel@tonic-gate resp->resok.infop = infop; 35837c478bd9Sstevel@tonic-gate 35847c478bd9Sstevel@tonic-gate dp = (struct dirent64 *)data; 35857c478bd9Sstevel@tonic-gate for (i = 0; i < nents; i++) { 35867c478bd9Sstevel@tonic-gate 35877c478bd9Sstevel@tonic-gate if (dp->d_ino == 0) { 35887c478bd9Sstevel@tonic-gate infop[i].attr.attributes = FALSE; 35897c478bd9Sstevel@tonic-gate infop[i].fh.handle_follows = FALSE; 35907c478bd9Sstevel@tonic-gate dp = nextdp(dp); 35917c478bd9Sstevel@tonic-gate continue; 35927c478bd9Sstevel@tonic-gate } 35937c478bd9Sstevel@tonic-gate 35947c478bd9Sstevel@tonic-gate infop[i].namelen = namlen[i]; 35957c478bd9Sstevel@tonic-gate 3596da6c28aaSamw error = VOP_LOOKUP(vp, dp->d_name, &nvp, NULL, 0, NULL, cr, 3597da6c28aaSamw NULL, NULL, NULL); 35987c478bd9Sstevel@tonic-gate if (error) { 35997c478bd9Sstevel@tonic-gate infop[i].attr.attributes = FALSE; 36007c478bd9Sstevel@tonic-gate infop[i].fh.handle_follows = FALSE; 36017c478bd9Sstevel@tonic-gate dp = nextdp(dp); 36027c478bd9Sstevel@tonic-gate continue; 36037c478bd9Sstevel@tonic-gate } 36047c478bd9Sstevel@tonic-gate 36057c478bd9Sstevel@tonic-gate nva.va_mask = AT_ALL; 36067c478bd9Sstevel@tonic-gate nvap = rfs4_delegated_getattr(nvp, &nva, 0, cr) ? NULL : &nva; 360727246829SVitaliy Gusev 36082f172c55SRobert Thurlow /* Lie about the object type for a referral */ 36092f172c55SRobert Thurlow if (vn_is_nfs_reparse(nvp, cr)) 36102f172c55SRobert Thurlow nvap->va_type = VLNK; 36112f172c55SRobert Thurlow 36127c478bd9Sstevel@tonic-gate vattr_to_post_op_attr(nvap, &infop[i].attr); 36137c478bd9Sstevel@tonic-gate 36147c478bd9Sstevel@tonic-gate error = makefh3(&infop[i].fh.handle, nvp, exi); 36157c478bd9Sstevel@tonic-gate if (!error) 36167c478bd9Sstevel@tonic-gate infop[i].fh.handle_follows = TRUE; 36177c478bd9Sstevel@tonic-gate else 36187c478bd9Sstevel@tonic-gate infop[i].fh.handle_follows = FALSE; 36197c478bd9Sstevel@tonic-gate 36207c478bd9Sstevel@tonic-gate VN_RELE(nvp); 36217c478bd9Sstevel@tonic-gate dp = nextdp(dp); 36227c478bd9Sstevel@tonic-gate } 36237c478bd9Sstevel@tonic-gate 3624b89a8333Snatalie li - Sun Microsystems - Irvine United States ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 3625b89a8333Snatalie li - Sun Microsystems - Irvine United States ret = nfscmd_convdirplus(ca, exi, data, nents, args->dircount, &ndata); 3626b89a8333Snatalie li - Sun Microsystems - Irvine United States if (ndata == NULL) 3627b89a8333Snatalie li - Sun Microsystems - Irvine United States ndata = data; 3628b89a8333Snatalie li - Sun Microsystems - Irvine United States 3629b89a8333Snatalie li - Sun Microsystems - Irvine United States if (ret > 0) { 3630b89a8333Snatalie li - Sun Microsystems - Irvine United States /* 3631b89a8333Snatalie li - Sun Microsystems - Irvine United States * We had to drop one or more entries in order to fit 3632b89a8333Snatalie li - Sun Microsystems - Irvine United States * during the character conversion. We need to patch 3633b89a8333Snatalie li - Sun Microsystems - Irvine United States * up the size and eof info. 3634b89a8333Snatalie li - Sun Microsystems - Irvine United States */ 3635b89a8333Snatalie li - Sun Microsystems - Irvine United States if (iseof) 3636b89a8333Snatalie li - Sun Microsystems - Irvine United States iseof = FALSE; 3637b89a8333Snatalie li - Sun Microsystems - Irvine United States 3638b89a8333Snatalie li - Sun Microsystems - Irvine United States ret = nfscmd_dropped_entrysize((struct dirent64 *)data, 3639b89a8333Snatalie li - Sun Microsystems - Irvine United States nents, ret); 3640b89a8333Snatalie li - Sun Microsystems - Irvine United States } 3641b89a8333Snatalie li - Sun Microsystems - Irvine United States 3642b89a8333Snatalie li - Sun Microsystems - Irvine United States 36437c478bd9Sstevel@tonic-gate #if 0 /* notyet */ 36447c478bd9Sstevel@tonic-gate /* 36457c478bd9Sstevel@tonic-gate * Don't do this. It causes local disk writes when just 36467c478bd9Sstevel@tonic-gate * reading the file and the overhead is deemed larger 36477c478bd9Sstevel@tonic-gate * than the benefit. 36487c478bd9Sstevel@tonic-gate */ 36497c478bd9Sstevel@tonic-gate /* 36507c478bd9Sstevel@tonic-gate * Force modified metadata out to stable storage. 36517c478bd9Sstevel@tonic-gate */ 3652da6c28aaSamw (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL); 36537c478bd9Sstevel@tonic-gate #endif 36547c478bd9Sstevel@tonic-gate 36557c478bd9Sstevel@tonic-gate kmem_free(namlen, args->dircount); 36567c478bd9Sstevel@tonic-gate 36577c478bd9Sstevel@tonic-gate resp->status = NFS3_OK; 36587c478bd9Sstevel@tonic-gate vattr_to_post_op_attr(vap, &resp->resok.dir_attributes); 36597c478bd9Sstevel@tonic-gate resp->resok.cookieverf = 0; 3660b89a8333Snatalie li - Sun Microsystems - Irvine United States resp->resok.reply.entries = (entryplus3 *)ndata; 36617c478bd9Sstevel@tonic-gate resp->resok.reply.eof = iseof; 36627c478bd9Sstevel@tonic-gate resp->resok.size = nents; 3663b89a8333Snatalie li - Sun Microsystems - Irvine United States resp->resok.count = args->dircount - ret; 36647c478bd9Sstevel@tonic-gate resp->resok.maxcount = args->maxcount; 3665e1adf50cSahl 3666e1adf50cSahl DTRACE_NFSV3_4(op__readdirplus__done, struct svc_req *, req, 3667e1adf50cSahl cred_t *, cr, vnode_t *, vp, READDIRPLUS3res *, resp); 3668b89a8333Snatalie li - Sun Microsystems - Irvine United States if (ndata != data) 3669b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(data, args->dircount); 3670b89a8333Snatalie li - Sun Microsystems - Irvine United States 3671e1adf50cSahl 3672e1adf50cSahl VN_RELE(vp); 3673e1adf50cSahl 36747c478bd9Sstevel@tonic-gate return; 36757c478bd9Sstevel@tonic-gate 36767c478bd9Sstevel@tonic-gate out: 36777c478bd9Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK) { 36787c478bd9Sstevel@tonic-gate curthread->t_flag &= ~T_WOULDBLOCK; 36797c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX; 3680b89a8333Snatalie li - Sun Microsystems - Irvine United States } else { 36817c478bd9Sstevel@tonic-gate resp->status = puterrno3(error); 3682b89a8333Snatalie li - Sun Microsystems - Irvine United States } 36837c478bd9Sstevel@tonic-gate out1: 3684e1adf50cSahl DTRACE_NFSV3_4(op__readdirplus__done, struct svc_req *, req, 3685e1adf50cSahl cred_t *, cr, vnode_t *, vp, READDIRPLUS3res *, resp); 3686e1adf50cSahl 36877c478bd9Sstevel@tonic-gate if (vp != NULL) { 36887c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL); 36897c478bd9Sstevel@tonic-gate VN_RELE(vp); 36907c478bd9Sstevel@tonic-gate } 36917c478bd9Sstevel@tonic-gate 36927c478bd9Sstevel@tonic-gate if (namlen != NULL) 36937c478bd9Sstevel@tonic-gate kmem_free(namlen, args->dircount); 36947c478bd9Sstevel@tonic-gate 36957c478bd9Sstevel@tonic-gate vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes); 36967c478bd9Sstevel@tonic-gate } 36977c478bd9Sstevel@tonic-gate 369827242a7cSthurlow void * 36997c478bd9Sstevel@tonic-gate rfs3_readdirplus_getfh(READDIRPLUS3args *args) 37007c478bd9Sstevel@tonic-gate { 37017c478bd9Sstevel@tonic-gate 370227242a7cSthurlow return (&args->dir); 37037c478bd9Sstevel@tonic-gate } 37047c478bd9Sstevel@tonic-gate 37057c478bd9Sstevel@tonic-gate void 37067c478bd9Sstevel@tonic-gate rfs3_readdirplus_free(READDIRPLUS3res *resp) 37077c478bd9Sstevel@tonic-gate { 37087c478bd9Sstevel@tonic-gate 37097c478bd9Sstevel@tonic-gate if (resp->status == NFS3_OK) { 37107c478bd9Sstevel@tonic-gate kmem_free(resp->resok.reply.entries, resp->resok.count); 37117c478bd9Sstevel@tonic-gate kmem_free(resp->resok.infop, 37127c478bd9Sstevel@tonic-gate resp->resok.size * sizeof (struct entryplus3_info)); 37137c478bd9Sstevel@tonic-gate } 37147c478bd9Sstevel@tonic-gate } 37157c478bd9Sstevel@tonic-gate 37167c478bd9Sstevel@tonic-gate /* ARGSUSED */ 37177c478bd9Sstevel@tonic-gate void 37187c478bd9Sstevel@tonic-gate rfs3_fsstat(FSSTAT3args *args, FSSTAT3res *resp, struct exportinfo *exi, 37195cb0d679SMarcel Telka struct svc_req *req, cred_t *cr, bool_t ro) 37207c478bd9Sstevel@tonic-gate { 37217c478bd9Sstevel@tonic-gate int error; 37227c478bd9Sstevel@tonic-gate vnode_t *vp; 37237c478bd9Sstevel@tonic-gate struct vattr *vap; 37247c478bd9Sstevel@tonic-gate struct vattr va; 37257c478bd9Sstevel@tonic-gate struct statvfs64 sb; 37267c478bd9Sstevel@tonic-gate 37277c478bd9Sstevel@tonic-gate vap = NULL; 37287c478bd9Sstevel@tonic-gate 37297c478bd9Sstevel@tonic-gate vp = nfs3_fhtovp(&args->fsroot, exi); 3730e1adf50cSahl 3731e1adf50cSahl DTRACE_NFSV3_4(op__fsstat__start, struct svc_req *, req, 3732e1adf50cSahl cred_t *, cr, vnode_t *, vp, FSSTAT3args *, args); 3733e1adf50cSahl 37347c478bd9Sstevel@tonic-gate if (vp == NULL) { 37357c478bd9Sstevel@tonic-gate error = ESTALE; 37367c478bd9Sstevel@tonic-gate goto out; 37377c478bd9Sstevel@tonic-gate } 37387c478bd9Sstevel@tonic-gate 373903986916Sjarrett if (is_system_labeled()) { 374003986916Sjarrett bslabel_t *clabel = req->rq_label; 374103986916Sjarrett 374203986916Sjarrett ASSERT(clabel != NULL); 374303986916Sjarrett DTRACE_PROBE2(tx__rfs3__log__info__opfsstat__clabel, char *, 374403986916Sjarrett "got client label from request(1)", struct svc_req *, req); 374503986916Sjarrett 374603986916Sjarrett if (!blequal(&l_admin_low->tsl_label, clabel)) { 3747bd6f1640SJarrett Lu if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK, 3748bd6f1640SJarrett Lu exi)) { 374903986916Sjarrett resp->status = NFS3ERR_ACCES; 375003986916Sjarrett goto out1; 375103986916Sjarrett } 375203986916Sjarrett } 375303986916Sjarrett } 375403986916Sjarrett 37557c478bd9Sstevel@tonic-gate error = VFS_STATVFS(vp->v_vfsp, &sb); 37567c478bd9Sstevel@tonic-gate 37577c478bd9Sstevel@tonic-gate va.va_mask = AT_ALL; 3758da6c28aaSamw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 37597c478bd9Sstevel@tonic-gate 37607c478bd9Sstevel@tonic-gate if (error) 37617c478bd9Sstevel@tonic-gate goto out; 37627c478bd9Sstevel@tonic-gate 37637c478bd9Sstevel@tonic-gate resp->status = NFS3_OK; 37647c478bd9Sstevel@tonic-gate vattr_to_post_op_attr(vap, &resp->resok.obj_attributes); 37657c478bd9Sstevel@tonic-gate if (sb.f_blocks != (fsblkcnt64_t)-1) 37667c478bd9Sstevel@tonic-gate resp->resok.tbytes = (size3)sb.f_frsize * (size3)sb.f_blocks; 37677c478bd9Sstevel@tonic-gate else 37687c478bd9Sstevel@tonic-gate resp->resok.tbytes = (size3)sb.f_blocks; 37697c478bd9Sstevel@tonic-gate if (sb.f_bfree != (fsblkcnt64_t)-1) 37707c478bd9Sstevel@tonic-gate resp->resok.fbytes = (size3)sb.f_frsize * (size3)sb.f_bfree; 37717c478bd9Sstevel@tonic-gate else 37727c478bd9Sstevel@tonic-gate resp->resok.fbytes = (size3)sb.f_bfree; 37737c478bd9Sstevel@tonic-gate if (sb.f_bavail != (fsblkcnt64_t)-1) 37747c478bd9Sstevel@tonic-gate resp->resok.abytes = (size3)sb.f_frsize * (size3)sb.f_bavail; 37757c478bd9Sstevel@tonic-gate else 37767c478bd9Sstevel@tonic-gate resp->resok.abytes = (size3)sb.f_bavail; 37777c478bd9Sstevel@tonic-gate resp->resok.tfiles = (size3)sb.f_files; 37787c478bd9Sstevel@tonic-gate resp->resok.ffiles = (size3)sb.f_ffree; 37797c478bd9Sstevel@tonic-gate resp->resok.afiles = (size3)sb.f_favail; 37807c478bd9Sstevel@tonic-gate resp->resok.invarsec = 0; 3781e1adf50cSahl 3782e1adf50cSahl DTRACE_NFSV3_4(op__fsstat__done, struct svc_req *, req, 3783e1adf50cSahl cred_t *, cr, vnode_t *, vp, FSSTAT3res *, resp); 3784e1adf50cSahl VN_RELE(vp); 3785e1adf50cSahl 37867c478bd9Sstevel@tonic-gate return; 37877c478bd9Sstevel@tonic-gate 37887c478bd9Sstevel@tonic-gate out: 37897c478bd9Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK) { 37907c478bd9Sstevel@tonic-gate curthread->t_flag &= ~T_WOULDBLOCK; 37917c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX; 37927c478bd9Sstevel@tonic-gate } else 37937c478bd9Sstevel@tonic-gate resp->status = puterrno3(error); 379403986916Sjarrett out1: 3795e1adf50cSahl DTRACE_NFSV3_4(op__fsstat__done, struct svc_req *, req, 3796e1adf50cSahl cred_t *, cr, vnode_t *, vp, FSSTAT3res *, resp); 3797e1adf50cSahl 379803986916Sjarrett if (vp != NULL) 379903986916Sjarrett VN_RELE(vp); 38007c478bd9Sstevel@tonic-gate vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes); 38017c478bd9Sstevel@tonic-gate } 38027c478bd9Sstevel@tonic-gate 380327242a7cSthurlow void * 38047c478bd9Sstevel@tonic-gate rfs3_fsstat_getfh(FSSTAT3args *args) 38057c478bd9Sstevel@tonic-gate { 38067c478bd9Sstevel@tonic-gate 380727242a7cSthurlow return (&args->fsroot); 38087c478bd9Sstevel@tonic-gate } 38097c478bd9Sstevel@tonic-gate 38105cb0d679SMarcel Telka /* ARGSUSED */ 38117c478bd9Sstevel@tonic-gate void 38127c478bd9Sstevel@tonic-gate rfs3_fsinfo(FSINFO3args *args, FSINFO3res *resp, struct exportinfo *exi, 38135cb0d679SMarcel Telka struct svc_req *req, cred_t *cr, bool_t ro) 38147c478bd9Sstevel@tonic-gate { 38157c478bd9Sstevel@tonic-gate vnode_t *vp; 38167c478bd9Sstevel@tonic-gate struct vattr *vap; 38177c478bd9Sstevel@tonic-gate struct vattr va; 38187c478bd9Sstevel@tonic-gate uint32_t xfer_size; 38197c478bd9Sstevel@tonic-gate ulong_t l = 0; 38207c478bd9Sstevel@tonic-gate int error; 38217c478bd9Sstevel@tonic-gate 38227c478bd9Sstevel@tonic-gate vp = nfs3_fhtovp(&args->fsroot, exi); 3823e1adf50cSahl 3824e1adf50cSahl DTRACE_NFSV3_4(op__fsinfo__start, struct svc_req *, req, 3825e1adf50cSahl cred_t *, cr, vnode_t *, vp, FSINFO3args *, args); 3826e1adf50cSahl 38277c478bd9Sstevel@tonic-gate if (vp == NULL) { 38287c478bd9Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK) { 38297c478bd9Sstevel@tonic-gate curthread->t_flag &= ~T_WOULDBLOCK; 38307c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX; 38317c478bd9Sstevel@tonic-gate } else 38327c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_STALE; 38337c478bd9Sstevel@tonic-gate vattr_to_post_op_attr(NULL, &resp->resfail.obj_attributes); 3834e1adf50cSahl goto out; 38357c478bd9Sstevel@tonic-gate } 38367c478bd9Sstevel@tonic-gate 383703986916Sjarrett if (is_system_labeled()) { 383803986916Sjarrett bslabel_t *clabel = req->rq_label; 383903986916Sjarrett 384003986916Sjarrett ASSERT(clabel != NULL); 384103986916Sjarrett DTRACE_PROBE2(tx__rfs3__log__info__opfsinfo__clabel, char *, 384203986916Sjarrett "got client label from request(1)", struct svc_req *, req); 384303986916Sjarrett 384403986916Sjarrett if (!blequal(&l_admin_low->tsl_label, clabel)) { 3845bd6f1640SJarrett Lu if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK, 3846bd6f1640SJarrett Lu exi)) { 384703986916Sjarrett resp->status = NFS3ERR_STALE; 384803986916Sjarrett vattr_to_post_op_attr(NULL, 384903986916Sjarrett &resp->resfail.obj_attributes); 3850e1adf50cSahl goto out; 385103986916Sjarrett } 385203986916Sjarrett } 385303986916Sjarrett } 385403986916Sjarrett 38557c478bd9Sstevel@tonic-gate va.va_mask = AT_ALL; 3856da6c28aaSamw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 38577c478bd9Sstevel@tonic-gate 38587c478bd9Sstevel@tonic-gate resp->status = NFS3_OK; 38597c478bd9Sstevel@tonic-gate vattr_to_post_op_attr(vap, &resp->resok.obj_attributes); 38607c478bd9Sstevel@tonic-gate xfer_size = rfs3_tsize(req); 38617c478bd9Sstevel@tonic-gate resp->resok.rtmax = xfer_size; 38627c478bd9Sstevel@tonic-gate resp->resok.rtpref = xfer_size; 38637c478bd9Sstevel@tonic-gate resp->resok.rtmult = DEV_BSIZE; 38647c478bd9Sstevel@tonic-gate resp->resok.wtmax = xfer_size; 38657c478bd9Sstevel@tonic-gate resp->resok.wtpref = xfer_size; 38667c478bd9Sstevel@tonic-gate resp->resok.wtmult = DEV_BSIZE; 38677c478bd9Sstevel@tonic-gate resp->resok.dtpref = MAXBSIZE; 38687c478bd9Sstevel@tonic-gate 38697c478bd9Sstevel@tonic-gate /* 38707c478bd9Sstevel@tonic-gate * Large file spec: want maxfilesize based on limit of 38717c478bd9Sstevel@tonic-gate * underlying filesystem. We can guess 2^31-1 if need be. 38727c478bd9Sstevel@tonic-gate */ 3873da6c28aaSamw error = VOP_PATHCONF(vp, _PC_FILESIZEBITS, &l, cr, NULL); 3874710f82c5SPiyush Shivam if (error) { 3875710f82c5SPiyush Shivam resp->status = puterrno3(error); 3876710f82c5SPiyush Shivam goto out; 3877710f82c5SPiyush Shivam } 38787c478bd9Sstevel@tonic-gate 3879710f82c5SPiyush Shivam /* 3880710f82c5SPiyush Shivam * If the underlying file system does not support _PC_FILESIZEBITS, 3881710f82c5SPiyush Shivam * return a reasonable default. Note that error code on VOP_PATHCONF 3882710f82c5SPiyush Shivam * will be 0, even if the underlying file system does not support 3883710f82c5SPiyush Shivam * _PC_FILESIZEBITS. 3884710f82c5SPiyush Shivam */ 3885710f82c5SPiyush Shivam if (l == (ulong_t)-1) { 38867c478bd9Sstevel@tonic-gate resp->resok.maxfilesize = MAXOFF32_T; 3887710f82c5SPiyush Shivam } else { 3888710f82c5SPiyush Shivam if (l >= (sizeof (uint64_t) * 8)) 3889710f82c5SPiyush Shivam resp->resok.maxfilesize = INT64_MAX; 3890710f82c5SPiyush Shivam else 3891710f82c5SPiyush Shivam resp->resok.maxfilesize = (1LL << (l-1)) - 1; 3892710f82c5SPiyush Shivam } 38937c478bd9Sstevel@tonic-gate 38947c478bd9Sstevel@tonic-gate resp->resok.time_delta.seconds = 0; 38957c478bd9Sstevel@tonic-gate resp->resok.time_delta.nseconds = 1000; 38967c478bd9Sstevel@tonic-gate resp->resok.properties = FSF3_LINK | FSF3_SYMLINK | 38977c478bd9Sstevel@tonic-gate FSF3_HOMOGENEOUS | FSF3_CANSETTIME; 3898e1adf50cSahl 3899e1adf50cSahl DTRACE_NFSV3_4(op__fsinfo__done, struct svc_req *, req, 3900e1adf50cSahl cred_t *, cr, vnode_t *, vp, FSINFO3res *, resp); 3901e1adf50cSahl 3902e1adf50cSahl VN_RELE(vp); 3903e1adf50cSahl 3904e1adf50cSahl return; 3905e1adf50cSahl 3906e1adf50cSahl out: 3907e1adf50cSahl DTRACE_NFSV3_4(op__fsinfo__done, struct svc_req *, req, 3908e1adf50cSahl cred_t *, cr, vnode_t *, NULL, FSINFO3res *, resp); 3909e1adf50cSahl if (vp != NULL) 3910e1adf50cSahl VN_RELE(vp); 39117c478bd9Sstevel@tonic-gate } 39127c478bd9Sstevel@tonic-gate 391327242a7cSthurlow void * 39147c478bd9Sstevel@tonic-gate rfs3_fsinfo_getfh(FSINFO3args *args) 39157c478bd9Sstevel@tonic-gate { 391627242a7cSthurlow return (&args->fsroot); 39177c478bd9Sstevel@tonic-gate } 39187c478bd9Sstevel@tonic-gate 39197c478bd9Sstevel@tonic-gate /* ARGSUSED */ 39207c478bd9Sstevel@tonic-gate void 39217c478bd9Sstevel@tonic-gate rfs3_pathconf(PATHCONF3args *args, PATHCONF3res *resp, struct exportinfo *exi, 39225cb0d679SMarcel Telka struct svc_req *req, cred_t *cr, bool_t ro) 39237c478bd9Sstevel@tonic-gate { 39247c478bd9Sstevel@tonic-gate int error; 39257c478bd9Sstevel@tonic-gate vnode_t *vp; 39267c478bd9Sstevel@tonic-gate struct vattr *vap; 39277c478bd9Sstevel@tonic-gate struct vattr va; 39287c478bd9Sstevel@tonic-gate ulong_t val; 39297c478bd9Sstevel@tonic-gate 39307c478bd9Sstevel@tonic-gate vap = NULL; 39317c478bd9Sstevel@tonic-gate 39327c478bd9Sstevel@tonic-gate vp = nfs3_fhtovp(&args->object, exi); 3933e1adf50cSahl 3934e1adf50cSahl DTRACE_NFSV3_4(op__pathconf__start, struct svc_req *, req, 3935e1adf50cSahl cred_t *, cr, vnode_t *, vp, PATHCONF3args *, args); 3936e1adf50cSahl 39377c478bd9Sstevel@tonic-gate if (vp == NULL) { 39387c478bd9Sstevel@tonic-gate error = ESTALE; 39397c478bd9Sstevel@tonic-gate goto out; 39407c478bd9Sstevel@tonic-gate } 39417c478bd9Sstevel@tonic-gate 394203986916Sjarrett if (is_system_labeled()) { 394303986916Sjarrett bslabel_t *clabel = req->rq_label; 394403986916Sjarrett 394503986916Sjarrett ASSERT(clabel != NULL); 394603986916Sjarrett DTRACE_PROBE2(tx__rfs3__log__info__oppathconf__clabel, char *, 394703986916Sjarrett "got client label from request(1)", struct svc_req *, req); 394803986916Sjarrett 394903986916Sjarrett if (!blequal(&l_admin_low->tsl_label, clabel)) { 3950bd6f1640SJarrett Lu if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK, 3951bd6f1640SJarrett Lu exi)) { 395203986916Sjarrett resp->status = NFS3ERR_ACCES; 395303986916Sjarrett goto out1; 395403986916Sjarrett } 395503986916Sjarrett } 395603986916Sjarrett } 395703986916Sjarrett 39587c478bd9Sstevel@tonic-gate va.va_mask = AT_ALL; 3959da6c28aaSamw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; 39607c478bd9Sstevel@tonic-gate 3961da6c28aaSamw error = VOP_PATHCONF(vp, _PC_LINK_MAX, &val, cr, NULL); 39627c478bd9Sstevel@tonic-gate if (error) 39637c478bd9Sstevel@tonic-gate goto out; 39647c478bd9Sstevel@tonic-gate resp->resok.info.link_max = (uint32)val; 39657c478bd9Sstevel@tonic-gate 3966da6c28aaSamw error = VOP_PATHCONF(vp, _PC_NAME_MAX, &val, cr, NULL); 39677c478bd9Sstevel@tonic-gate if (error) 39687c478bd9Sstevel@tonic-gate goto out; 39697c478bd9Sstevel@tonic-gate resp->resok.info.name_max = (uint32)val; 39707c478bd9Sstevel@tonic-gate 3971da6c28aaSamw error = VOP_PATHCONF(vp, _PC_NO_TRUNC, &val, cr, NULL); 39727c478bd9Sstevel@tonic-gate if (error) 39737c478bd9Sstevel@tonic-gate goto out; 39747c478bd9Sstevel@tonic-gate if (val == 1) 39757c478bd9Sstevel@tonic-gate resp->resok.info.no_trunc = TRUE; 39767c478bd9Sstevel@tonic-gate else 39777c478bd9Sstevel@tonic-gate resp->resok.info.no_trunc = FALSE; 39787c478bd9Sstevel@tonic-gate 3979da6c28aaSamw error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &val, cr, NULL); 39807c478bd9Sstevel@tonic-gate if (error) 39817c478bd9Sstevel@tonic-gate goto out; 39827c478bd9Sstevel@tonic-gate if (val == 1) 39837c478bd9Sstevel@tonic-gate resp->resok.info.chown_restricted = TRUE; 39847c478bd9Sstevel@tonic-gate else 39857c478bd9Sstevel@tonic-gate resp->resok.info.chown_restricted = FALSE; 39867c478bd9Sstevel@tonic-gate 39877c478bd9Sstevel@tonic-gate resp->status = NFS3_OK; 39887c478bd9Sstevel@tonic-gate vattr_to_post_op_attr(vap, &resp->resok.obj_attributes); 39897c478bd9Sstevel@tonic-gate resp->resok.info.case_insensitive = FALSE; 39907c478bd9Sstevel@tonic-gate resp->resok.info.case_preserving = TRUE; 3991e1adf50cSahl DTRACE_NFSV3_4(op__pathconf__done, struct svc_req *, req, 3992e1adf50cSahl cred_t *, cr, vnode_t *, vp, PATHCONF3res *, resp); 3993e1adf50cSahl VN_RELE(vp); 39947c478bd9Sstevel@tonic-gate return; 39957c478bd9Sstevel@tonic-gate 39967c478bd9Sstevel@tonic-gate out: 39977c478bd9Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK) { 39987c478bd9Sstevel@tonic-gate curthread->t_flag &= ~T_WOULDBLOCK; 39997c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX; 40007c478bd9Sstevel@tonic-gate } else 40017c478bd9Sstevel@tonic-gate resp->status = puterrno3(error); 400203986916Sjarrett out1: 4003e1adf50cSahl DTRACE_NFSV3_4(op__pathconf__done, struct svc_req *, req, 4004e1adf50cSahl cred_t *, cr, vnode_t *, vp, PATHCONF3res *, resp); 40057c478bd9Sstevel@tonic-gate if (vp != NULL) 40067c478bd9Sstevel@tonic-gate VN_RELE(vp); 40077c478bd9Sstevel@tonic-gate vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes); 40087c478bd9Sstevel@tonic-gate } 40097c478bd9Sstevel@tonic-gate 401027242a7cSthurlow void * 40117c478bd9Sstevel@tonic-gate rfs3_pathconf_getfh(PATHCONF3args *args) 40127c478bd9Sstevel@tonic-gate { 40137c478bd9Sstevel@tonic-gate 401427242a7cSthurlow return (&args->object); 40157c478bd9Sstevel@tonic-gate } 40167c478bd9Sstevel@tonic-gate 40177c478bd9Sstevel@tonic-gate void 40187c478bd9Sstevel@tonic-gate rfs3_commit(COMMIT3args *args, COMMIT3res *resp, struct exportinfo *exi, 40195cb0d679SMarcel Telka struct svc_req *req, cred_t *cr, bool_t ro) 40207c478bd9Sstevel@tonic-gate { 40217c478bd9Sstevel@tonic-gate int error; 40227c478bd9Sstevel@tonic-gate vnode_t *vp; 40237c478bd9Sstevel@tonic-gate struct vattr *bvap; 40247c478bd9Sstevel@tonic-gate struct vattr bva; 40257c478bd9Sstevel@tonic-gate struct vattr *avap; 40267c478bd9Sstevel@tonic-gate struct vattr ava; 40277c478bd9Sstevel@tonic-gate 40287c478bd9Sstevel@tonic-gate bvap = NULL; 40297c478bd9Sstevel@tonic-gate avap = NULL; 40307c478bd9Sstevel@tonic-gate 40317c478bd9Sstevel@tonic-gate vp = nfs3_fhtovp(&args->file, exi); 4032e1adf50cSahl 4033e1adf50cSahl DTRACE_NFSV3_4(op__commit__start, struct svc_req *, req, 4034e1adf50cSahl cred_t *, cr, vnode_t *, vp, COMMIT3args *, args); 4035e1adf50cSahl 40367c478bd9Sstevel@tonic-gate if (vp == NULL) { 40377c478bd9Sstevel@tonic-gate error = ESTALE; 40387c478bd9Sstevel@tonic-gate goto out; 40397c478bd9Sstevel@tonic-gate } 40407c478bd9Sstevel@tonic-gate 40417c478bd9Sstevel@tonic-gate bva.va_mask = AT_ALL; 4042da6c28aaSamw error = VOP_GETATTR(vp, &bva, 0, cr, NULL); 40437c478bd9Sstevel@tonic-gate 40447c478bd9Sstevel@tonic-gate /* 40457c478bd9Sstevel@tonic-gate * If we can't get the attributes, then we can't do the 40467c478bd9Sstevel@tonic-gate * right access checking. So, we'll fail the request. 40477c478bd9Sstevel@tonic-gate */ 40487c478bd9Sstevel@tonic-gate if (error) 40497c478bd9Sstevel@tonic-gate goto out; 40507c478bd9Sstevel@tonic-gate 40517c478bd9Sstevel@tonic-gate bvap = &bva; 40527c478bd9Sstevel@tonic-gate 40535cb0d679SMarcel Telka if (rdonly(ro, vp)) { 40547c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_ROFS; 40557c478bd9Sstevel@tonic-gate goto out1; 40567c478bd9Sstevel@tonic-gate } 40577c478bd9Sstevel@tonic-gate 40587c478bd9Sstevel@tonic-gate if (vp->v_type != VREG) { 40597c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_INVAL; 40607c478bd9Sstevel@tonic-gate goto out1; 40617c478bd9Sstevel@tonic-gate } 40627c478bd9Sstevel@tonic-gate 406303986916Sjarrett if (is_system_labeled()) { 406403986916Sjarrett bslabel_t *clabel = req->rq_label; 406503986916Sjarrett 406603986916Sjarrett ASSERT(clabel != NULL); 406703986916Sjarrett DTRACE_PROBE2(tx__rfs3__log__info__opcommit__clabel, char *, 406803986916Sjarrett "got client label from request(1)", struct svc_req *, req); 406903986916Sjarrett 407003986916Sjarrett if (!blequal(&l_admin_low->tsl_label, clabel)) { 4071bd6f1640SJarrett Lu if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK, 4072bd6f1640SJarrett Lu exi)) { 407303986916Sjarrett resp->status = NFS3ERR_ACCES; 407403986916Sjarrett goto out1; 407503986916Sjarrett } 407603986916Sjarrett } 407703986916Sjarrett } 407803986916Sjarrett 40797c478bd9Sstevel@tonic-gate if (crgetuid(cr) != bva.va_uid && 4080da6c28aaSamw (error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL))) 40817c478bd9Sstevel@tonic-gate goto out; 40827c478bd9Sstevel@tonic-gate 4083f63200e6SJeff A. Smith error = VOP_FSYNC(vp, FSYNC, cr, NULL); 40847c478bd9Sstevel@tonic-gate 40857c478bd9Sstevel@tonic-gate ava.va_mask = AT_ALL; 4086da6c28aaSamw avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava; 40877c478bd9Sstevel@tonic-gate 40887c478bd9Sstevel@tonic-gate if (error) 40897c478bd9Sstevel@tonic-gate goto out; 40907c478bd9Sstevel@tonic-gate 40917c478bd9Sstevel@tonic-gate resp->status = NFS3_OK; 40927c478bd9Sstevel@tonic-gate vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc); 40937c478bd9Sstevel@tonic-gate resp->resok.verf = write3verf; 4094e1adf50cSahl 4095e1adf50cSahl DTRACE_NFSV3_4(op__commit__done, struct svc_req *, req, 4096e1adf50cSahl cred_t *, cr, vnode_t *, vp, COMMIT3res *, resp); 4097e1adf50cSahl 4098e1adf50cSahl VN_RELE(vp); 4099e1adf50cSahl 41007c478bd9Sstevel@tonic-gate return; 41017c478bd9Sstevel@tonic-gate 41027c478bd9Sstevel@tonic-gate out: 41037c478bd9Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK) { 41047c478bd9Sstevel@tonic-gate curthread->t_flag &= ~T_WOULDBLOCK; 41057c478bd9Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX; 41067c478bd9Sstevel@tonic-gate } else 41077c478bd9Sstevel@tonic-gate resp->status = puterrno3(error); 41087c478bd9Sstevel@tonic-gate out1: 4109e1adf50cSahl DTRACE_NFSV3_4(op__commit__done, struct svc_req *, req, 4110e1adf50cSahl cred_t *, cr, vnode_t *, vp, COMMIT3res *, resp); 4111e1adf50cSahl 41127c478bd9Sstevel@tonic-gate if (vp != NULL) 41137c478bd9Sstevel@tonic-gate VN_RELE(vp); 41147c478bd9Sstevel@tonic-gate vattr_to_wcc_data(bvap, avap, &resp->resfail.file_wcc); 41157c478bd9Sstevel@tonic-gate } 41167c478bd9Sstevel@tonic-gate 411727242a7cSthurlow void * 41187c478bd9Sstevel@tonic-gate rfs3_commit_getfh(COMMIT3args *args) 41197c478bd9Sstevel@tonic-gate { 41207c478bd9Sstevel@tonic-gate 412127242a7cSthurlow return (&args->file); 41227c478bd9Sstevel@tonic-gate } 41237c478bd9Sstevel@tonic-gate 41247c478bd9Sstevel@tonic-gate static int 41257c478bd9Sstevel@tonic-gate sattr3_to_vattr(sattr3 *sap, struct vattr *vap) 41267c478bd9Sstevel@tonic-gate { 41277c478bd9Sstevel@tonic-gate 41287c478bd9Sstevel@tonic-gate vap->va_mask = 0; 41297c478bd9Sstevel@tonic-gate 41307c478bd9Sstevel@tonic-gate if (sap->mode.set_it) { 41317c478bd9Sstevel@tonic-gate vap->va_mode = (mode_t)sap->mode.mode; 41327c478bd9Sstevel@tonic-gate vap->va_mask |= AT_MODE; 41337c478bd9Sstevel@tonic-gate } 41347c478bd9Sstevel@tonic-gate if (sap->uid.set_it) { 41357c478bd9Sstevel@tonic-gate vap->va_uid = (uid_t)sap->uid.uid; 41367c478bd9Sstevel@tonic-gate vap->va_mask |= AT_UID; 41377c478bd9Sstevel@tonic-gate } 41387c478bd9Sstevel@tonic-gate if (sap->gid.set_it) { 41397c478bd9Sstevel@tonic-gate vap->va_gid = (gid_t)sap->gid.gid; 41407c478bd9Sstevel@tonic-gate vap->va_mask |= AT_GID; 41417c478bd9Sstevel@tonic-gate } 41427c478bd9Sstevel@tonic-gate if (sap->size.set_it) { 41437c478bd9Sstevel@tonic-gate if (sap->size.size > (size3)((u_longlong_t)-1)) 41447c478bd9Sstevel@tonic-gate return (EINVAL); 41457c478bd9Sstevel@tonic-gate vap->va_size = sap->size.size; 41467c478bd9Sstevel@tonic-gate vap->va_mask |= AT_SIZE; 41477c478bd9Sstevel@tonic-gate } 41487c478bd9Sstevel@tonic-gate if (sap->atime.set_it == SET_TO_CLIENT_TIME) { 41497c478bd9Sstevel@tonic-gate #ifndef _LP64 41507c478bd9Sstevel@tonic-gate /* check time validity */ 41517c478bd9Sstevel@tonic-gate if (!NFS3_TIME_OK(sap->atime.atime.seconds)) 41527c478bd9Sstevel@tonic-gate return (EOVERFLOW); 41537c478bd9Sstevel@tonic-gate #endif 41547c478bd9Sstevel@tonic-gate /* 41557c478bd9Sstevel@tonic-gate * nfs protocol defines times as unsigned so don't extend sign, 41567c478bd9Sstevel@tonic-gate * unless sysadmin set nfs_allow_preepoch_time. 41577c478bd9Sstevel@tonic-gate */ 41587c478bd9Sstevel@tonic-gate NFS_TIME_T_CONVERT(vap->va_atime.tv_sec, 41597c478bd9Sstevel@tonic-gate sap->atime.atime.seconds); 41607c478bd9Sstevel@tonic-gate vap->va_atime.tv_nsec = (uint32_t)sap->atime.atime.nseconds; 41617c478bd9Sstevel@tonic-gate vap->va_mask |= AT_ATIME; 41627c478bd9Sstevel@tonic-gate } else if (sap->atime.set_it == SET_TO_SERVER_TIME) { 41637c478bd9Sstevel@tonic-gate gethrestime(&vap->va_atime); 41647c478bd9Sstevel@tonic-gate vap->va_mask |= AT_ATIME; 41657c478bd9Sstevel@tonic-gate } 41667c478bd9Sstevel@tonic-gate if (sap->mtime.set_it == SET_TO_CLIENT_TIME) { 41677c478bd9Sstevel@tonic-gate #ifndef _LP64 41687c478bd9Sstevel@tonic-gate /* check time validity */ 41697c478bd9Sstevel@tonic-gate if (!NFS3_TIME_OK(sap->mtime.mtime.seconds)) 41707c478bd9Sstevel@tonic-gate return (EOVERFLOW); 41717c478bd9Sstevel@tonic-gate #endif 41727c478bd9Sstevel@tonic-gate /* 41737c478bd9Sstevel@tonic-gate * nfs protocol defines times as unsigned so don't extend sign, 41747c478bd9Sstevel@tonic-gate * unless sysadmin set nfs_allow_preepoch_time. 41757c478bd9Sstevel@tonic-gate */ 41767c478bd9Sstevel@tonic-gate NFS_TIME_T_CONVERT(vap->va_mtime.tv_sec, 41777c478bd9Sstevel@tonic-gate sap->mtime.mtime.seconds); 41787c478bd9Sstevel@tonic-gate vap->va_mtime.tv_nsec = (uint32_t)sap->mtime.mtime.nseconds; 41797c478bd9Sstevel@tonic-gate vap->va_mask |= AT_MTIME; 41807c478bd9Sstevel@tonic-gate } else if (sap->mtime.set_it == SET_TO_SERVER_TIME) { 41817c478bd9Sstevel@tonic-gate gethrestime(&vap->va_mtime); 41827c478bd9Sstevel@tonic-gate vap->va_mask |= AT_MTIME; 41837c478bd9Sstevel@tonic-gate } 41847c478bd9Sstevel@tonic-gate 41857c478bd9Sstevel@tonic-gate return (0); 41867c478bd9Sstevel@tonic-gate } 41877c478bd9Sstevel@tonic-gate 41887c478bd9Sstevel@tonic-gate static ftype3 vt_to_nf3[] = { 41897c478bd9Sstevel@tonic-gate 0, NF3REG, NF3DIR, NF3BLK, NF3CHR, NF3LNK, NF3FIFO, 0, 0, NF3SOCK, 0 41907c478bd9Sstevel@tonic-gate }; 41917c478bd9Sstevel@tonic-gate 41927c478bd9Sstevel@tonic-gate static int 41937c478bd9Sstevel@tonic-gate vattr_to_fattr3(struct vattr *vap, fattr3 *fap) 41947c478bd9Sstevel@tonic-gate { 41957c478bd9Sstevel@tonic-gate 41967c478bd9Sstevel@tonic-gate ASSERT(vap->va_type >= VNON && vap->va_type <= VBAD); 41977c478bd9Sstevel@tonic-gate /* Return error if time or size overflow */ 41987c478bd9Sstevel@tonic-gate if (! (NFS_VAP_TIME_OK(vap) && NFS3_SIZE_OK(vap->va_size))) { 41997c478bd9Sstevel@tonic-gate return (EOVERFLOW); 42007c478bd9Sstevel@tonic-gate } 42017c478bd9Sstevel@tonic-gate fap->type = vt_to_nf3[vap->va_type]; 42027c478bd9Sstevel@tonic-gate fap->mode = (mode3)(vap->va_mode & MODEMASK); 42037c478bd9Sstevel@tonic-gate fap->nlink = (uint32)vap->va_nlink; 42047c478bd9Sstevel@tonic-gate if (vap->va_uid == UID_NOBODY) 42057c478bd9Sstevel@tonic-gate fap->uid = (uid3)NFS_UID_NOBODY; 42067c478bd9Sstevel@tonic-gate else 42077c478bd9Sstevel@tonic-gate fap->uid = (uid3)vap->va_uid; 42087c478bd9Sstevel@tonic-gate if (vap->va_gid == GID_NOBODY) 42097c478bd9Sstevel@tonic-gate fap->gid = (gid3)NFS_GID_NOBODY; 42107c478bd9Sstevel@tonic-gate else 42117c478bd9Sstevel@tonic-gate fap->gid = (gid3)vap->va_gid; 42127c478bd9Sstevel@tonic-gate fap->size = (size3)vap->va_size; 42137c478bd9Sstevel@tonic-gate fap->used = (size3)DEV_BSIZE * (size3)vap->va_nblocks; 42147c478bd9Sstevel@tonic-gate fap->rdev.specdata1 = (uint32)getmajor(vap->va_rdev); 42157c478bd9Sstevel@tonic-gate fap->rdev.specdata2 = (uint32)getminor(vap->va_rdev); 42167c478bd9Sstevel@tonic-gate fap->fsid = (uint64)vap->va_fsid; 42177c478bd9Sstevel@tonic-gate fap->fileid = (fileid3)vap->va_nodeid; 42187c478bd9Sstevel@tonic-gate fap->atime.seconds = vap->va_atime.tv_sec; 42197c478bd9Sstevel@tonic-gate fap->atime.nseconds = vap->va_atime.tv_nsec; 42207c478bd9Sstevel@tonic-gate fap->mtime.seconds = vap->va_mtime.tv_sec; 42217c478bd9Sstevel@tonic-gate fap->mtime.nseconds = vap->va_mtime.tv_nsec; 42227c478bd9Sstevel@tonic-gate fap->ctime.seconds = vap->va_ctime.tv_sec; 42237c478bd9Sstevel@tonic-gate fap->ctime.nseconds = vap->va_ctime.tv_nsec; 42247c478bd9Sstevel@tonic-gate return (0); 42257c478bd9Sstevel@tonic-gate } 42267c478bd9Sstevel@tonic-gate 42277c478bd9Sstevel@tonic-gate static int 42287c478bd9Sstevel@tonic-gate vattr_to_wcc_attr(struct vattr *vap, wcc_attr *wccap) 42297c478bd9Sstevel@tonic-gate { 42307c478bd9Sstevel@tonic-gate 42317c478bd9Sstevel@tonic-gate /* Return error if time or size overflow */ 42327c478bd9Sstevel@tonic-gate if (!(NFS_TIME_T_OK(vap->va_mtime.tv_sec) && 42337c478bd9Sstevel@tonic-gate NFS_TIME_T_OK(vap->va_ctime.tv_sec) && 42347c478bd9Sstevel@tonic-gate NFS3_SIZE_OK(vap->va_size))) { 42357c478bd9Sstevel@tonic-gate return (EOVERFLOW); 42367c478bd9Sstevel@tonic-gate } 42377c478bd9Sstevel@tonic-gate wccap->size = (size3)vap->va_size; 42387c478bd9Sstevel@tonic-gate wccap->mtime.seconds = vap->va_mtime.tv_sec; 42397c478bd9Sstevel@tonic-gate wccap->mtime.nseconds = vap->va_mtime.tv_nsec; 42407c478bd9Sstevel@tonic-gate wccap->ctime.seconds = vap->va_ctime.tv_sec; 42417c478bd9Sstevel@tonic-gate wccap->ctime.nseconds = vap->va_ctime.tv_nsec; 42427c478bd9Sstevel@tonic-gate return (0); 42437c478bd9Sstevel@tonic-gate } 42447c478bd9Sstevel@tonic-gate 42457c478bd9Sstevel@tonic-gate static void 42467c478bd9Sstevel@tonic-gate vattr_to_pre_op_attr(struct vattr *vap, pre_op_attr *poap) 42477c478bd9Sstevel@tonic-gate { 42487c478bd9Sstevel@tonic-gate 42497c478bd9Sstevel@tonic-gate /* don't return attrs if time overflow */ 42507c478bd9Sstevel@tonic-gate if ((vap != NULL) && !vattr_to_wcc_attr(vap, &poap->attr)) { 42517c478bd9Sstevel@tonic-gate poap->attributes = TRUE; 42527c478bd9Sstevel@tonic-gate } else 42537c478bd9Sstevel@tonic-gate poap->attributes = FALSE; 42547c478bd9Sstevel@tonic-gate } 42557c478bd9Sstevel@tonic-gate 42567c478bd9Sstevel@tonic-gate void 42577c478bd9Sstevel@tonic-gate vattr_to_post_op_attr(struct vattr *vap, post_op_attr *poap) 42587c478bd9Sstevel@tonic-gate { 42597c478bd9Sstevel@tonic-gate 42607c478bd9Sstevel@tonic-gate /* don't return attrs if time overflow */ 42617c478bd9Sstevel@tonic-gate if ((vap != NULL) && !vattr_to_fattr3(vap, &poap->attr)) { 42627c478bd9Sstevel@tonic-gate poap->attributes = TRUE; 42637c478bd9Sstevel@tonic-gate } else 42647c478bd9Sstevel@tonic-gate poap->attributes = FALSE; 42657c478bd9Sstevel@tonic-gate } 42667c478bd9Sstevel@tonic-gate 42677c478bd9Sstevel@tonic-gate static void 42687c478bd9Sstevel@tonic-gate vattr_to_wcc_data(struct vattr *bvap, struct vattr *avap, wcc_data *wccp) 42697c478bd9Sstevel@tonic-gate { 42707c478bd9Sstevel@tonic-gate 42717c478bd9Sstevel@tonic-gate vattr_to_pre_op_attr(bvap, &wccp->before); 42727c478bd9Sstevel@tonic-gate vattr_to_post_op_attr(avap, &wccp->after); 42737c478bd9Sstevel@tonic-gate } 42747c478bd9Sstevel@tonic-gate 42757c478bd9Sstevel@tonic-gate void 42767c478bd9Sstevel@tonic-gate rfs3_srvrinit(void) 42777c478bd9Sstevel@tonic-gate { 42787c478bd9Sstevel@tonic-gate struct rfs3_verf_overlay { 42797c478bd9Sstevel@tonic-gate uint_t id; /* a "unique" identifier */ 42807c478bd9Sstevel@tonic-gate int ts; /* a unique timestamp */ 42817c478bd9Sstevel@tonic-gate } *verfp; 42827c478bd9Sstevel@tonic-gate timestruc_t now; 42837c478bd9Sstevel@tonic-gate 42847c478bd9Sstevel@tonic-gate /* 42857c478bd9Sstevel@tonic-gate * The following algorithm attempts to find a unique verifier 42867c478bd9Sstevel@tonic-gate * to be used as the write verifier returned from the server 42877c478bd9Sstevel@tonic-gate * to the client. It is important that this verifier change 42887c478bd9Sstevel@tonic-gate * whenever the server reboots. Of secondary importance, it 42897c478bd9Sstevel@tonic-gate * is important for the verifier to be unique between two 42907c478bd9Sstevel@tonic-gate * different servers. 42917c478bd9Sstevel@tonic-gate * 42927c478bd9Sstevel@tonic-gate * Thus, an attempt is made to use the system hostid and the 42937c478bd9Sstevel@tonic-gate * current time in seconds when the nfssrv kernel module is 42947c478bd9Sstevel@tonic-gate * loaded. It is assumed that an NFS server will not be able 42957c478bd9Sstevel@tonic-gate * to boot and then to reboot in less than a second. If the 42967c478bd9Sstevel@tonic-gate * hostid has not been set, then the current high resolution 42977c478bd9Sstevel@tonic-gate * time is used. This will ensure different verifiers each 42987c478bd9Sstevel@tonic-gate * time the server reboots and minimize the chances that two 42997c478bd9Sstevel@tonic-gate * different servers will have the same verifier. 43007c478bd9Sstevel@tonic-gate */ 43017c478bd9Sstevel@tonic-gate 43027c478bd9Sstevel@tonic-gate #ifndef lint 43037c478bd9Sstevel@tonic-gate /* 43047c478bd9Sstevel@tonic-gate * We ASSERT that this constant logic expression is 43057c478bd9Sstevel@tonic-gate * always true because in the past, it wasn't. 43067c478bd9Sstevel@tonic-gate */ 43077c478bd9Sstevel@tonic-gate ASSERT(sizeof (*verfp) <= sizeof (write3verf)); 43087c478bd9Sstevel@tonic-gate #endif 43097c478bd9Sstevel@tonic-gate 43107c478bd9Sstevel@tonic-gate gethrestime(&now); 43117c478bd9Sstevel@tonic-gate verfp = (struct rfs3_verf_overlay *)&write3verf; 43127c478bd9Sstevel@tonic-gate verfp->ts = (int)now.tv_sec; 43135679c89fSjv227347 verfp->id = zone_get_hostid(NULL); 43147c478bd9Sstevel@tonic-gate 43157c478bd9Sstevel@tonic-gate if (verfp->id == 0) 43167c478bd9Sstevel@tonic-gate verfp->id = (uint_t)now.tv_nsec; 43177c478bd9Sstevel@tonic-gate 4318cfae96c2Sjwahlig nfs3_srv_caller_id = fs_new_caller_id(); 4319cfae96c2Sjwahlig 43207c478bd9Sstevel@tonic-gate } 43217c478bd9Sstevel@tonic-gate 43220a701b1eSRobert Gordon static int 43230a701b1eSRobert Gordon rdma_setup_read_data3(READ3args *args, READ3resok *rok) 43240a701b1eSRobert Gordon { 43250a701b1eSRobert Gordon struct clist *wcl; 4326f837ee4aSSiddheshwar Mahesh int wlist_len; 43270a701b1eSRobert Gordon count3 count = rok->count; 43280a701b1eSRobert Gordon 43290a701b1eSRobert Gordon wcl = args->wlist; 4330f837ee4aSSiddheshwar Mahesh if (rdma_setup_read_chunks(wcl, count, &wlist_len) == FALSE) { 43310a701b1eSRobert Gordon return (FALSE); 43320a701b1eSRobert Gordon } 43330a701b1eSRobert Gordon 43340a701b1eSRobert Gordon wcl = args->wlist; 4335f837ee4aSSiddheshwar Mahesh rok->wlist_len = wlist_len; 43360a701b1eSRobert Gordon rok->wlist = wcl; 43370a701b1eSRobert Gordon return (TRUE); 43380a701b1eSRobert Gordon } 43390a701b1eSRobert Gordon 43407c478bd9Sstevel@tonic-gate void 43417c478bd9Sstevel@tonic-gate rfs3_srvrfini(void) 43427c478bd9Sstevel@tonic-gate { 43437c478bd9Sstevel@tonic-gate /* Nothing to do */ 43447c478bd9Sstevel@tonic-gate } 4345