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 545916cd2Sjpk * Common Development and Distribution License (the "License"). 645916cd2Sjpk * 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 */ 216e062f4aSMarcel Telka 227c478bd9Sstevel@tonic-gate /* 23bffeae97SMarcel Telka * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. 2415721462SDaniil Lunev */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate /* 277c478bd9Sstevel@tonic-gate * Copyright (c) 1983,1984,1985,1986,1987,1988,1989 AT&T. 287c478bd9Sstevel@tonic-gate * All Rights Reserved 297c478bd9Sstevel@tonic-gate */ 307c478bd9Sstevel@tonic-gate 310dfe541eSEvan Layton /* 320dfe541eSEvan Layton * Copyright (c) 2012, 2016 by Delphix. All rights reserved. 330dfe541eSEvan Layton * Copyright 2019 Nexenta Systems, Inc. 340dfe541eSEvan Layton * Copyright 2019 Nexenta by DDN, Inc. 35214d537cSVitaliy Gusev * Copyright 2021 Racktop Systems, Inc. 360dfe541eSEvan Layton */ 370dfe541eSEvan Layton 387c478bd9Sstevel@tonic-gate #include <sys/param.h> 397c478bd9Sstevel@tonic-gate #include <sys/types.h> 407c478bd9Sstevel@tonic-gate #include <sys/systm.h> 417c478bd9Sstevel@tonic-gate #include <sys/cred.h> 427c478bd9Sstevel@tonic-gate #include <sys/buf.h> 437c478bd9Sstevel@tonic-gate #include <sys/vfs.h> 44aa59c4cbSrsb #include <sys/vfs_opreg.h> 457c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 467c478bd9Sstevel@tonic-gate #include <sys/uio.h> 477c478bd9Sstevel@tonic-gate #include <sys/errno.h> 487c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 497c478bd9Sstevel@tonic-gate #include <sys/statvfs.h> 507c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 517c478bd9Sstevel@tonic-gate #include <sys/dirent.h> 527c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 537c478bd9Sstevel@tonic-gate #include <sys/debug.h> 547c478bd9Sstevel@tonic-gate #include <sys/systeminfo.h> 557c478bd9Sstevel@tonic-gate #include <sys/flock.h> 567c478bd9Sstevel@tonic-gate #include <sys/pathname.h> 577c478bd9Sstevel@tonic-gate #include <sys/nbmlock.h> 587c478bd9Sstevel@tonic-gate #include <sys/share.h> 597c478bd9Sstevel@tonic-gate #include <sys/atomic.h> 607c478bd9Sstevel@tonic-gate #include <sys/policy.h> 617c478bd9Sstevel@tonic-gate #include <sys/fem.h> 6245916cd2Sjpk #include <sys/sdt.h> 63cee86682Scalum #include <sys/ddi.h> 645679c89fSjv227347 #include <sys/zone.h> 657c478bd9Sstevel@tonic-gate 662f172c55SRobert Thurlow #include <fs/fs_reparse.h> 672f172c55SRobert Thurlow 687c478bd9Sstevel@tonic-gate #include <rpc/types.h> 697c478bd9Sstevel@tonic-gate #include <rpc/auth.h> 707c478bd9Sstevel@tonic-gate #include <rpc/rpcsec_gss.h> 717c478bd9Sstevel@tonic-gate #include <rpc/svc.h> 727c478bd9Sstevel@tonic-gate 737c478bd9Sstevel@tonic-gate #include <nfs/nfs.h> 740dfe541eSEvan Layton #include <nfs/nfssys.h> 757c478bd9Sstevel@tonic-gate #include <nfs/export.h> 76b89a8333Snatalie li - Sun Microsystems - Irvine United States #include <nfs/nfs_cmd.h> 777c478bd9Sstevel@tonic-gate #include <nfs/lm.h> 787c478bd9Sstevel@tonic-gate #include <nfs/nfs4.h> 790dfe541eSEvan Layton #include <nfs/nfs4_drc.h> 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate #include <sys/strsubr.h> 827c478bd9Sstevel@tonic-gate #include <sys/strsun.h> 837c478bd9Sstevel@tonic-gate 847c478bd9Sstevel@tonic-gate #include <inet/common.h> 857c478bd9Sstevel@tonic-gate #include <inet/ip.h> 867c478bd9Sstevel@tonic-gate #include <inet/ip6.h> 877c478bd9Sstevel@tonic-gate 8845916cd2Sjpk #include <sys/tsol/label.h> 8945916cd2Sjpk #include <sys/tsol/tndb.h> 9045916cd2Sjpk 917c478bd9Sstevel@tonic-gate #define RFS4_MAXLOCK_TRIES 4 /* Try to get the lock this many times */ 927c478bd9Sstevel@tonic-gate static int rfs4_maxlock_tries = RFS4_MAXLOCK_TRIES; 937c478bd9Sstevel@tonic-gate #define RFS4_LOCK_DELAY 10 /* Milliseconds */ 947c478bd9Sstevel@tonic-gate static clock_t rfs4_lock_delay = RFS4_LOCK_DELAY; 950a701b1eSRobert Gordon extern struct svc_ops rdma_svc_ops; 96c242f9a0Schunli zhang - Sun Microsystems - Irvine United States extern int nfs_loaned_buffers; 97c242f9a0Schunli zhang - Sun Microsystems - Irvine United States /* End of Tunables */ 987c478bd9Sstevel@tonic-gate 990a701b1eSRobert Gordon static int rdma_setup_read_data4(READ4args *, READ4res *); 1000a701b1eSRobert Gordon 1017c478bd9Sstevel@tonic-gate /* 1027c478bd9Sstevel@tonic-gate * Used to bump the stateid4.seqid value and show changes in the stateid 1037c478bd9Sstevel@tonic-gate */ 1047c478bd9Sstevel@tonic-gate #define next_stateid(sp) (++(sp)->bits.chgseq) 1057c478bd9Sstevel@tonic-gate 1067c478bd9Sstevel@tonic-gate /* 1077c478bd9Sstevel@tonic-gate * RFS4_MINLEN_ENTRY4: XDR-encoded size of smallest possible dirent. 1087c478bd9Sstevel@tonic-gate * This is used to return NFS4ERR_TOOSMALL when clients specify 1097c478bd9Sstevel@tonic-gate * maxcount that isn't large enough to hold the smallest possible 1107c478bd9Sstevel@tonic-gate * XDR encoded dirent. 1117c478bd9Sstevel@tonic-gate * 1127c478bd9Sstevel@tonic-gate * sizeof cookie (8 bytes) + 1137c478bd9Sstevel@tonic-gate * sizeof name_len (4 bytes) + 1147c478bd9Sstevel@tonic-gate * sizeof smallest (padded) name (4 bytes) + 1157c478bd9Sstevel@tonic-gate * sizeof bitmap4_len (12 bytes) + NOTE: we always encode len=2 bm4 1167c478bd9Sstevel@tonic-gate * sizeof attrlist4_len (4 bytes) + 1177c478bd9Sstevel@tonic-gate * sizeof next boolean (4 bytes) 1187c478bd9Sstevel@tonic-gate * 1197c478bd9Sstevel@tonic-gate * RFS4_MINLEN_RDDIR4: XDR-encoded size of READDIR op reply containing 1207c478bd9Sstevel@tonic-gate * the smallest possible entry4 (assumes no attrs requested). 1217c478bd9Sstevel@tonic-gate * sizeof nfsstat4 (4 bytes) + 1227c478bd9Sstevel@tonic-gate * sizeof verifier4 (8 bytes) + 1237c478bd9Sstevel@tonic-gate * sizeof entry4list bool (4 bytes) + 1247c478bd9Sstevel@tonic-gate * sizeof entry4 (36 bytes) + 1257c478bd9Sstevel@tonic-gate * sizeof eof bool (4 bytes) 1267c478bd9Sstevel@tonic-gate * 1277c478bd9Sstevel@tonic-gate * RFS4_MINLEN_RDDIR_BUF: minimum length of buffer server will provide to 1287c478bd9Sstevel@tonic-gate * VOP_READDIR. Its value is the size of the maximum possible dirent 1297c478bd9Sstevel@tonic-gate * for solaris. The DIRENT64_RECLEN macro returns the size of dirent 1307c478bd9Sstevel@tonic-gate * required for a given name length. MAXNAMELEN is the maximum 1317c478bd9Sstevel@tonic-gate * filename length allowed in Solaris. The first two DIRENT64_RECLEN() 1327c478bd9Sstevel@tonic-gate * macros are to allow for . and .. entries -- just a minor tweak to try 1337c478bd9Sstevel@tonic-gate * and guarantee that buffer we give to VOP_READDIR will be large enough 1347c478bd9Sstevel@tonic-gate * to hold ., .., and the largest possible solaris dirent64. 1357c478bd9Sstevel@tonic-gate */ 1367c478bd9Sstevel@tonic-gate #define RFS4_MINLEN_ENTRY4 36 1377c478bd9Sstevel@tonic-gate #define RFS4_MINLEN_RDDIR4 (4 + NFS4_VERIFIER_SIZE + 4 + RFS4_MINLEN_ENTRY4 + 4) 1387c478bd9Sstevel@tonic-gate #define RFS4_MINLEN_RDDIR_BUF \ 1397c478bd9Sstevel@tonic-gate (DIRENT64_RECLEN(1) + DIRENT64_RECLEN(2) + DIRENT64_RECLEN(MAXNAMELEN)) 1407c478bd9Sstevel@tonic-gate 1417c478bd9Sstevel@tonic-gate /* 1427c478bd9Sstevel@tonic-gate * It would be better to pad to 4 bytes since that's what XDR would do, 1437c478bd9Sstevel@tonic-gate * but the dirents UFS gives us are already padded to 8, so just take 1447c478bd9Sstevel@tonic-gate * what we're given. Dircount is only a hint anyway. Currently the 1457c478bd9Sstevel@tonic-gate * solaris kernel is ASCII only, so there's no point in calling the 1467c478bd9Sstevel@tonic-gate * UTF8 functions. 1477c478bd9Sstevel@tonic-gate * 1487c478bd9Sstevel@tonic-gate * dirent64: named padded to provide 8 byte struct alignment 1497c478bd9Sstevel@tonic-gate * d_ino(8) + d_off(8) + d_reclen(2) + d_name(namelen + null(1) + pad) 1507c478bd9Sstevel@tonic-gate * 1517c478bd9Sstevel@tonic-gate * cookie: uint64_t + utf8namelen: uint_t + utf8name padded to 8 bytes 1527c478bd9Sstevel@tonic-gate * 1537c478bd9Sstevel@tonic-gate */ 1547c478bd9Sstevel@tonic-gate #define DIRENT64_TO_DIRCOUNT(dp) \ 1557c478bd9Sstevel@tonic-gate (3 * BYTES_PER_XDR_UNIT + DIRENT64_NAMELEN((dp)->d_reclen)) 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate static sysid_t lockt_sysid; /* dummy sysid for all LOCKT calls */ 1597c478bd9Sstevel@tonic-gate 1607c478bd9Sstevel@tonic-gate u_longlong_t nfs4_srv_caller_id; 1611b300de9Sjwahlig uint_t nfs4_srv_vkey = 0; 1627c478bd9Sstevel@tonic-gate 1637c478bd9Sstevel@tonic-gate void rfs4_init_compound_state(struct compound_state *); 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate static void nullfree(caddr_t); 1667c478bd9Sstevel@tonic-gate static void rfs4_op_inval(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 1677c478bd9Sstevel@tonic-gate struct compound_state *); 1687c478bd9Sstevel@tonic-gate static void rfs4_op_access(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 1697c478bd9Sstevel@tonic-gate struct compound_state *); 1707c478bd9Sstevel@tonic-gate static void rfs4_op_close(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 1717c478bd9Sstevel@tonic-gate struct compound_state *); 1727c478bd9Sstevel@tonic-gate static void rfs4_op_commit(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 1737c478bd9Sstevel@tonic-gate struct compound_state *); 1747c478bd9Sstevel@tonic-gate static void rfs4_op_create(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 1757c478bd9Sstevel@tonic-gate struct compound_state *); 1767c478bd9Sstevel@tonic-gate static void rfs4_op_delegreturn(nfs_argop4 *, nfs_resop4 *, 1777c478bd9Sstevel@tonic-gate struct svc_req *, struct compound_state *); 178f3b585ceSsamf static void rfs4_op_delegpurge(nfs_argop4 *, nfs_resop4 *, 179f3b585ceSsamf struct svc_req *, struct compound_state *); 1807c478bd9Sstevel@tonic-gate static void rfs4_op_getattr(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 1817c478bd9Sstevel@tonic-gate struct compound_state *); 1827c478bd9Sstevel@tonic-gate static void rfs4_op_getattr_free(nfs_resop4 *); 1837c478bd9Sstevel@tonic-gate static void rfs4_op_getfh(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 1847c478bd9Sstevel@tonic-gate struct compound_state *); 1857c478bd9Sstevel@tonic-gate static void rfs4_op_getfh_free(nfs_resop4 *); 1867c478bd9Sstevel@tonic-gate static void rfs4_op_illegal(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 1877c478bd9Sstevel@tonic-gate struct compound_state *); 188*f44e1126SVitaliy Gusev static void rfs4_op_notsup(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 189*f44e1126SVitaliy Gusev struct compound_state *); 1907c478bd9Sstevel@tonic-gate static void rfs4_op_link(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 1917c478bd9Sstevel@tonic-gate struct compound_state *); 1927c478bd9Sstevel@tonic-gate static void rfs4_op_lock(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 1937c478bd9Sstevel@tonic-gate struct compound_state *); 1947c478bd9Sstevel@tonic-gate static void lock_denied_free(nfs_resop4 *); 1957c478bd9Sstevel@tonic-gate static void rfs4_op_locku(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 1967c478bd9Sstevel@tonic-gate struct compound_state *); 1977c478bd9Sstevel@tonic-gate static void rfs4_op_lockt(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 1987c478bd9Sstevel@tonic-gate struct compound_state *); 1997c478bd9Sstevel@tonic-gate static void rfs4_op_lookup(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 2007c478bd9Sstevel@tonic-gate struct compound_state *); 2017c478bd9Sstevel@tonic-gate static void rfs4_op_lookupp(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 2027c478bd9Sstevel@tonic-gate struct compound_state *); 2037c478bd9Sstevel@tonic-gate static void rfs4_op_openattr(nfs_argop4 *argop, nfs_resop4 *resop, 2047c478bd9Sstevel@tonic-gate struct svc_req *req, struct compound_state *cs); 2057c478bd9Sstevel@tonic-gate static void rfs4_op_nverify(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 2067c478bd9Sstevel@tonic-gate struct compound_state *); 2077c478bd9Sstevel@tonic-gate static void rfs4_op_open(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 2087c478bd9Sstevel@tonic-gate struct compound_state *); 2097c478bd9Sstevel@tonic-gate static void rfs4_op_open_confirm(nfs_argop4 *, nfs_resop4 *, 2107c478bd9Sstevel@tonic-gate struct svc_req *, struct compound_state *); 2117c478bd9Sstevel@tonic-gate static void rfs4_op_open_downgrade(nfs_argop4 *, nfs_resop4 *, 2127c478bd9Sstevel@tonic-gate struct svc_req *, struct compound_state *); 2137c478bd9Sstevel@tonic-gate static void rfs4_op_putfh(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 2147c478bd9Sstevel@tonic-gate struct compound_state *); 2157c478bd9Sstevel@tonic-gate static void rfs4_op_putpubfh(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 2167c478bd9Sstevel@tonic-gate struct compound_state *); 2177c478bd9Sstevel@tonic-gate static void rfs4_op_putrootfh(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 2187c478bd9Sstevel@tonic-gate struct compound_state *); 2197c478bd9Sstevel@tonic-gate static void rfs4_op_read(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 2207c478bd9Sstevel@tonic-gate struct compound_state *); 2217c478bd9Sstevel@tonic-gate static void rfs4_op_read_free(nfs_resop4 *); 2227c478bd9Sstevel@tonic-gate static void rfs4_op_readdir_free(nfs_resop4 *resop); 2237c478bd9Sstevel@tonic-gate static void rfs4_op_readlink(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 2247c478bd9Sstevel@tonic-gate struct compound_state *); 2257c478bd9Sstevel@tonic-gate static void rfs4_op_readlink_free(nfs_resop4 *); 2267c478bd9Sstevel@tonic-gate static void rfs4_op_release_lockowner(nfs_argop4 *, nfs_resop4 *, 2277c478bd9Sstevel@tonic-gate struct svc_req *, struct compound_state *); 2287c478bd9Sstevel@tonic-gate static void rfs4_op_remove(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 2297c478bd9Sstevel@tonic-gate struct compound_state *); 2307c478bd9Sstevel@tonic-gate static void rfs4_op_rename(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 2317c478bd9Sstevel@tonic-gate struct compound_state *); 2327c478bd9Sstevel@tonic-gate static void rfs4_op_renew(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 2337c478bd9Sstevel@tonic-gate struct compound_state *); 2347c478bd9Sstevel@tonic-gate static void rfs4_op_restorefh(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 2357c478bd9Sstevel@tonic-gate struct compound_state *); 2367c478bd9Sstevel@tonic-gate static void rfs4_op_savefh(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 2377c478bd9Sstevel@tonic-gate struct compound_state *); 2387c478bd9Sstevel@tonic-gate static void rfs4_op_setattr(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 2397c478bd9Sstevel@tonic-gate struct compound_state *); 2407c478bd9Sstevel@tonic-gate static void rfs4_op_verify(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 2417c478bd9Sstevel@tonic-gate struct compound_state *); 2427c478bd9Sstevel@tonic-gate static void rfs4_op_write(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 2437c478bd9Sstevel@tonic-gate struct compound_state *); 2447c478bd9Sstevel@tonic-gate static void rfs4_op_setclientid(nfs_argop4 *, nfs_resop4 *, 2457c478bd9Sstevel@tonic-gate struct svc_req *, struct compound_state *); 2467c478bd9Sstevel@tonic-gate static void rfs4_op_setclientid_confirm(nfs_argop4 *, nfs_resop4 *, 2477c478bd9Sstevel@tonic-gate struct svc_req *req, struct compound_state *); 2487c478bd9Sstevel@tonic-gate static void rfs4_op_secinfo(nfs_argop4 *, nfs_resop4 *, struct svc_req *, 2497c478bd9Sstevel@tonic-gate struct compound_state *); 2507c478bd9Sstevel@tonic-gate static void rfs4_op_secinfo_free(nfs_resop4 *); 2517c478bd9Sstevel@tonic-gate 252*f44e1126SVitaliy Gusev void rfs4x_op_exchange_id(nfs_argop4 *argop, nfs_resop4 *resop, 253*f44e1126SVitaliy Gusev struct svc_req *req, struct compound_state *cs); 254*f44e1126SVitaliy Gusev void rfs4x_exchange_id_free(nfs_resop4 *); 255*f44e1126SVitaliy Gusev 256*f44e1126SVitaliy Gusev void rfs4x_op_create_session(nfs_argop4 *argop, nfs_resop4 *resop, 257*f44e1126SVitaliy Gusev struct svc_req *req, struct compound_state *cs); 258*f44e1126SVitaliy Gusev 259*f44e1126SVitaliy Gusev void rfs4x_op_destroy_session(nfs_argop4 *argop, nfs_resop4 *resop, 260*f44e1126SVitaliy Gusev struct svc_req *req, compound_state_t *cs); 261*f44e1126SVitaliy Gusev 262*f44e1126SVitaliy Gusev void rfs4x_op_sequence(nfs_argop4 *argop, nfs_resop4 *resop, 263*f44e1126SVitaliy Gusev struct svc_req *req, struct compound_state *cs); 264*f44e1126SVitaliy Gusev 265*f44e1126SVitaliy Gusev void rfs4x_op_reclaim_complete(nfs_argop4 *argop, nfs_resop4 *resop, 266*f44e1126SVitaliy Gusev struct svc_req *req, compound_state_t *cs); 267*f44e1126SVitaliy Gusev 268*f44e1126SVitaliy Gusev void rfs4x_op_destroy_clientid(nfs_argop4 *argop, nfs_resop4 *resop, 269*f44e1126SVitaliy Gusev struct svc_req *req, compound_state_t *cs); 270*f44e1126SVitaliy Gusev 271*f44e1126SVitaliy Gusev void rfs4x_op_bind_conn_to_session(nfs_argop4 *argop, nfs_resop4 *resop, 272*f44e1126SVitaliy Gusev struct svc_req *req, compound_state_t *cs); 273*f44e1126SVitaliy Gusev 274*f44e1126SVitaliy Gusev void rfs4x_op_secinfo_noname(nfs_argop4 *argop, nfs_resop4 *resop, 275*f44e1126SVitaliy Gusev struct svc_req *req, compound_state_t *cs); 276*f44e1126SVitaliy Gusev 2770dfe541eSEvan Layton static nfsstat4 check_open_access(uint32_t, struct compound_state *, 2780dfe541eSEvan Layton struct svc_req *); 2797c478bd9Sstevel@tonic-gate nfsstat4 rfs4_client_sysid(rfs4_client_t *, sysid_t *); 2800dfe541eSEvan Layton void rfs4_ss_clid(nfs4_srv_t *, rfs4_client_t *); 2810dfe541eSEvan Layton 2827c478bd9Sstevel@tonic-gate /* 2837c478bd9Sstevel@tonic-gate * translation table for attrs 2847c478bd9Sstevel@tonic-gate */ 2857c478bd9Sstevel@tonic-gate struct nfs4_ntov_table { 2867c478bd9Sstevel@tonic-gate union nfs4_attr_u *na; 2877c478bd9Sstevel@tonic-gate uint8_t amap[NFS4_MAXNUM_ATTRS]; 2887c478bd9Sstevel@tonic-gate int attrcnt; 2897c478bd9Sstevel@tonic-gate bool_t vfsstat; 2907c478bd9Sstevel@tonic-gate }; 2917c478bd9Sstevel@tonic-gate 2927c478bd9Sstevel@tonic-gate static void nfs4_ntov_table_init(struct nfs4_ntov_table *ntovp); 2937c478bd9Sstevel@tonic-gate static void nfs4_ntov_table_free(struct nfs4_ntov_table *ntovp, 2947c478bd9Sstevel@tonic-gate struct nfs4_svgetit_arg *sargp); 2957c478bd9Sstevel@tonic-gate 2967c478bd9Sstevel@tonic-gate static nfsstat4 do_rfs4_set_attrs(bitmap4 *resp, fattr4 *fattrp, 2977c478bd9Sstevel@tonic-gate struct compound_state *cs, struct nfs4_svgetit_arg *sargp, 2987c478bd9Sstevel@tonic-gate struct nfs4_ntov_table *ntovp, nfs4_attr_cmd_t cmd); 2997c478bd9Sstevel@tonic-gate 3000dfe541eSEvan Layton static void hanfsv4_failover(nfs4_srv_t *); 3010dfe541eSEvan Layton 3027c478bd9Sstevel@tonic-gate fem_t *deleg_rdops; 3037c478bd9Sstevel@tonic-gate fem_t *deleg_wrops; 3047c478bd9Sstevel@tonic-gate 3057c478bd9Sstevel@tonic-gate /* 3067c478bd9Sstevel@tonic-gate * NFS4 op dispatch table 3077c478bd9Sstevel@tonic-gate */ 3087c478bd9Sstevel@tonic-gate 3097c478bd9Sstevel@tonic-gate struct rfsv4disp { 3107c478bd9Sstevel@tonic-gate void (*dis_proc)(); /* proc to call */ 3117c478bd9Sstevel@tonic-gate void (*dis_resfree)(); /* frees space allocated by proc */ 3127c478bd9Sstevel@tonic-gate int dis_flags; /* RPC_IDEMPOTENT, etc... */ 3137c478bd9Sstevel@tonic-gate }; 3147c478bd9Sstevel@tonic-gate 3157c478bd9Sstevel@tonic-gate static struct rfsv4disp rfsv4disptab[] = { 3167c478bd9Sstevel@tonic-gate /* 3177c478bd9Sstevel@tonic-gate * NFS VERSION 4 3187c478bd9Sstevel@tonic-gate */ 3197c478bd9Sstevel@tonic-gate 3207c478bd9Sstevel@tonic-gate /* RFS_NULL = 0 */ 321f7877f5dSDan McDonald {rfs4_op_illegal, nullfree, 0}, 3227c478bd9Sstevel@tonic-gate 3237c478bd9Sstevel@tonic-gate /* UNUSED = 1 */ 324f7877f5dSDan McDonald {rfs4_op_illegal, nullfree, 0}, 3257c478bd9Sstevel@tonic-gate 3267c478bd9Sstevel@tonic-gate /* UNUSED = 2 */ 327f7877f5dSDan McDonald {rfs4_op_illegal, nullfree, 0}, 3287c478bd9Sstevel@tonic-gate 3297c478bd9Sstevel@tonic-gate /* OP_ACCESS = 3 */ 330f7877f5dSDan McDonald {rfs4_op_access, nullfree, RPC_IDEMPOTENT}, 3317c478bd9Sstevel@tonic-gate 3327c478bd9Sstevel@tonic-gate /* OP_CLOSE = 4 */ 333f7877f5dSDan McDonald {rfs4_op_close, nullfree, 0}, 3347c478bd9Sstevel@tonic-gate 3357c478bd9Sstevel@tonic-gate /* OP_COMMIT = 5 */ 336f7877f5dSDan McDonald {rfs4_op_commit, nullfree, RPC_IDEMPOTENT}, 3377c478bd9Sstevel@tonic-gate 3387c478bd9Sstevel@tonic-gate /* OP_CREATE = 6 */ 339f7877f5dSDan McDonald {rfs4_op_create, nullfree, 0}, 3407c478bd9Sstevel@tonic-gate 3417c478bd9Sstevel@tonic-gate /* OP_DELEGPURGE = 7 */ 342f7877f5dSDan McDonald {rfs4_op_delegpurge, nullfree, 0}, 3437c478bd9Sstevel@tonic-gate 3447c478bd9Sstevel@tonic-gate /* OP_DELEGRETURN = 8 */ 345f7877f5dSDan McDonald {rfs4_op_delegreturn, nullfree, 0}, 3467c478bd9Sstevel@tonic-gate 3477c478bd9Sstevel@tonic-gate /* OP_GETATTR = 9 */ 348f7877f5dSDan McDonald {rfs4_op_getattr, rfs4_op_getattr_free, RPC_IDEMPOTENT}, 3497c478bd9Sstevel@tonic-gate 3507c478bd9Sstevel@tonic-gate /* OP_GETFH = 10 */ 351f7877f5dSDan McDonald {rfs4_op_getfh, rfs4_op_getfh_free, RPC_ALL}, 3527c478bd9Sstevel@tonic-gate 3537c478bd9Sstevel@tonic-gate /* OP_LINK = 11 */ 354f7877f5dSDan McDonald {rfs4_op_link, nullfree, 0}, 3557c478bd9Sstevel@tonic-gate 3567c478bd9Sstevel@tonic-gate /* OP_LOCK = 12 */ 357f7877f5dSDan McDonald {rfs4_op_lock, lock_denied_free, 0}, 3587c478bd9Sstevel@tonic-gate 3597c478bd9Sstevel@tonic-gate /* OP_LOCKT = 13 */ 360f7877f5dSDan McDonald {rfs4_op_lockt, lock_denied_free, 0}, 3617c478bd9Sstevel@tonic-gate 3627c478bd9Sstevel@tonic-gate /* OP_LOCKU = 14 */ 363f7877f5dSDan McDonald {rfs4_op_locku, nullfree, 0}, 3647c478bd9Sstevel@tonic-gate 3657c478bd9Sstevel@tonic-gate /* OP_LOOKUP = 15 */ 366f7877f5dSDan McDonald {rfs4_op_lookup, nullfree, (RPC_IDEMPOTENT | RPC_PUBLICFH_OK)}, 3677c478bd9Sstevel@tonic-gate 3687c478bd9Sstevel@tonic-gate /* OP_LOOKUPP = 16 */ 369f7877f5dSDan McDonald {rfs4_op_lookupp, nullfree, (RPC_IDEMPOTENT | RPC_PUBLICFH_OK)}, 3707c478bd9Sstevel@tonic-gate 3717c478bd9Sstevel@tonic-gate /* OP_NVERIFY = 17 */ 372f7877f5dSDan McDonald {rfs4_op_nverify, nullfree, RPC_IDEMPOTENT}, 3737c478bd9Sstevel@tonic-gate 3747c478bd9Sstevel@tonic-gate /* OP_OPEN = 18 */ 375f7877f5dSDan McDonald {rfs4_op_open, rfs4_free_reply, 0}, 3767c478bd9Sstevel@tonic-gate 3777c478bd9Sstevel@tonic-gate /* OP_OPENATTR = 19 */ 378f7877f5dSDan McDonald {rfs4_op_openattr, nullfree, 0}, 3797c478bd9Sstevel@tonic-gate 3807c478bd9Sstevel@tonic-gate /* OP_OPEN_CONFIRM = 20 */ 381f7877f5dSDan McDonald {rfs4_op_open_confirm, nullfree, 0}, 3827c478bd9Sstevel@tonic-gate 3837c478bd9Sstevel@tonic-gate /* OP_OPEN_DOWNGRADE = 21 */ 384f7877f5dSDan McDonald {rfs4_op_open_downgrade, nullfree, 0}, 3857c478bd9Sstevel@tonic-gate 3867c478bd9Sstevel@tonic-gate /* OP_OPEN_PUTFH = 22 */ 387f7877f5dSDan McDonald {rfs4_op_putfh, nullfree, RPC_ALL}, 3887c478bd9Sstevel@tonic-gate 3897c478bd9Sstevel@tonic-gate /* OP_PUTPUBFH = 23 */ 390f7877f5dSDan McDonald {rfs4_op_putpubfh, nullfree, RPC_ALL}, 3917c478bd9Sstevel@tonic-gate 3927c478bd9Sstevel@tonic-gate /* OP_PUTROOTFH = 24 */ 393f7877f5dSDan McDonald {rfs4_op_putrootfh, nullfree, RPC_ALL}, 3947c478bd9Sstevel@tonic-gate 3957c478bd9Sstevel@tonic-gate /* OP_READ = 25 */ 396f7877f5dSDan McDonald {rfs4_op_read, rfs4_op_read_free, RPC_IDEMPOTENT}, 3977c478bd9Sstevel@tonic-gate 3987c478bd9Sstevel@tonic-gate /* OP_READDIR = 26 */ 399f7877f5dSDan McDonald {rfs4_op_readdir, rfs4_op_readdir_free, RPC_IDEMPOTENT}, 4007c478bd9Sstevel@tonic-gate 4017c478bd9Sstevel@tonic-gate /* OP_READLINK = 27 */ 402f7877f5dSDan McDonald {rfs4_op_readlink, rfs4_op_readlink_free, RPC_IDEMPOTENT}, 4037c478bd9Sstevel@tonic-gate 4047c478bd9Sstevel@tonic-gate /* OP_REMOVE = 28 */ 405f7877f5dSDan McDonald {rfs4_op_remove, nullfree, 0}, 4067c478bd9Sstevel@tonic-gate 4077c478bd9Sstevel@tonic-gate /* OP_RENAME = 29 */ 408f7877f5dSDan McDonald {rfs4_op_rename, nullfree, 0}, 4097c478bd9Sstevel@tonic-gate 4107c478bd9Sstevel@tonic-gate /* OP_RENEW = 30 */ 411f7877f5dSDan McDonald {rfs4_op_renew, nullfree, 0}, 4127c478bd9Sstevel@tonic-gate 4137c478bd9Sstevel@tonic-gate /* OP_RESTOREFH = 31 */ 414f7877f5dSDan McDonald {rfs4_op_restorefh, nullfree, RPC_ALL}, 4157c478bd9Sstevel@tonic-gate 4167c478bd9Sstevel@tonic-gate /* OP_SAVEFH = 32 */ 417f7877f5dSDan McDonald {rfs4_op_savefh, nullfree, RPC_ALL}, 4187c478bd9Sstevel@tonic-gate 4197c478bd9Sstevel@tonic-gate /* OP_SECINFO = 33 */ 420f7877f5dSDan McDonald {rfs4_op_secinfo, rfs4_op_secinfo_free, 0}, 4217c478bd9Sstevel@tonic-gate 4227c478bd9Sstevel@tonic-gate /* OP_SETATTR = 34 */ 423f7877f5dSDan McDonald {rfs4_op_setattr, nullfree, 0}, 4247c478bd9Sstevel@tonic-gate 4257c478bd9Sstevel@tonic-gate /* OP_SETCLIENTID = 35 */ 426f7877f5dSDan McDonald {rfs4_op_setclientid, nullfree, 0}, 4277c478bd9Sstevel@tonic-gate 4287c478bd9Sstevel@tonic-gate /* OP_SETCLIENTID_CONFIRM = 36 */ 429f7877f5dSDan McDonald {rfs4_op_setclientid_confirm, nullfree, 0}, 4307c478bd9Sstevel@tonic-gate 4317c478bd9Sstevel@tonic-gate /* OP_VERIFY = 37 */ 432f7877f5dSDan McDonald {rfs4_op_verify, nullfree, RPC_IDEMPOTENT}, 4337c478bd9Sstevel@tonic-gate 4347c478bd9Sstevel@tonic-gate /* OP_WRITE = 38 */ 435f7877f5dSDan McDonald {rfs4_op_write, nullfree, 0}, 4367c478bd9Sstevel@tonic-gate 4377c478bd9Sstevel@tonic-gate /* OP_RELEASE_LOCKOWNER = 39 */ 438f7877f5dSDan McDonald {rfs4_op_release_lockowner, nullfree, 0}, 439*f44e1126SVitaliy Gusev 440*f44e1126SVitaliy Gusev /* 441*f44e1126SVitaliy Gusev * NFSv4.1 operations 442*f44e1126SVitaliy Gusev */ 443*f44e1126SVitaliy Gusev 444*f44e1126SVitaliy Gusev /* OP_BACKCHANNEL_CTL = 40 */ 445*f44e1126SVitaliy Gusev {rfs4_op_notsup, nullfree, 0}, 446*f44e1126SVitaliy Gusev 447*f44e1126SVitaliy Gusev /* OP_BIND_CONN_TO_SESSION = 41 */ 448*f44e1126SVitaliy Gusev {rfs4x_op_bind_conn_to_session, nullfree, 0}, 449*f44e1126SVitaliy Gusev 450*f44e1126SVitaliy Gusev /* OP_EXCHANGE_ID = 42 */ 451*f44e1126SVitaliy Gusev {rfs4x_op_exchange_id, rfs4x_exchange_id_free, 0}, 452*f44e1126SVitaliy Gusev 453*f44e1126SVitaliy Gusev /* OP_CREATE_SESSION = 43 */ 454*f44e1126SVitaliy Gusev {rfs4x_op_create_session, nullfree, 0}, 455*f44e1126SVitaliy Gusev 456*f44e1126SVitaliy Gusev /* OP_DESTROY_SESSION = 44 */ 457*f44e1126SVitaliy Gusev {rfs4x_op_destroy_session, nullfree, 0}, 458*f44e1126SVitaliy Gusev 459*f44e1126SVitaliy Gusev /* OP_FREE_STATEID = 45 */ 460*f44e1126SVitaliy Gusev {rfs4_op_notsup, nullfree, 0}, 461*f44e1126SVitaliy Gusev 462*f44e1126SVitaliy Gusev /* OP_GET_DIR_DELEGATION = 46 */ 463*f44e1126SVitaliy Gusev {rfs4_op_notsup, nullfree, 0}, 464*f44e1126SVitaliy Gusev 465*f44e1126SVitaliy Gusev /* OP_GETDEVICEINFO = 47 */ 466*f44e1126SVitaliy Gusev {rfs4_op_notsup, nullfree, 0}, 467*f44e1126SVitaliy Gusev 468*f44e1126SVitaliy Gusev /* OP_GETDEVICELIST = 48 */ 469*f44e1126SVitaliy Gusev {rfs4_op_notsup, nullfree, 0}, 470*f44e1126SVitaliy Gusev 471*f44e1126SVitaliy Gusev /* OP_LAYOUTCOMMIT = 49 */ 472*f44e1126SVitaliy Gusev {rfs4_op_notsup, nullfree, 0}, 473*f44e1126SVitaliy Gusev 474*f44e1126SVitaliy Gusev /* OP_LAYOUTGET = 50 */ 475*f44e1126SVitaliy Gusev {rfs4_op_notsup, nullfree, 0}, 476*f44e1126SVitaliy Gusev 477*f44e1126SVitaliy Gusev /* OP_LAYOUTRETURN = 51 */ 478*f44e1126SVitaliy Gusev {rfs4_op_notsup, nullfree, 0}, 479*f44e1126SVitaliy Gusev 480*f44e1126SVitaliy Gusev /* OP_SECINFO_NO_NAME = 52 */ 481*f44e1126SVitaliy Gusev {rfs4x_op_secinfo_noname, rfs4_op_secinfo_free, 0}, 482*f44e1126SVitaliy Gusev 483*f44e1126SVitaliy Gusev /* OP_SEQUENCE = 53 */ 484*f44e1126SVitaliy Gusev {rfs4x_op_sequence, nullfree, 0}, 485*f44e1126SVitaliy Gusev 486*f44e1126SVitaliy Gusev /* OP_SET_SSV = 54 */ 487*f44e1126SVitaliy Gusev {rfs4_op_notsup, nullfree, 0}, 488*f44e1126SVitaliy Gusev 489*f44e1126SVitaliy Gusev /* OP_TEST_STATEID = 55 */ 490*f44e1126SVitaliy Gusev {rfs4_op_notsup, nullfree, 0}, 491*f44e1126SVitaliy Gusev 492*f44e1126SVitaliy Gusev /* OP_WANT_DELEGATION = 56 */ 493*f44e1126SVitaliy Gusev {rfs4_op_notsup, nullfree, 0}, 494*f44e1126SVitaliy Gusev 495*f44e1126SVitaliy Gusev /* OP_DESTROY_CLIENTID = 57 */ 496*f44e1126SVitaliy Gusev {rfs4x_op_destroy_clientid, nullfree, 0}, 497*f44e1126SVitaliy Gusev 498*f44e1126SVitaliy Gusev /* OP_RECLAIM_COMPLETE = 58 */ 499*f44e1126SVitaliy Gusev {rfs4x_op_reclaim_complete, nullfree, 0}, 5007c478bd9Sstevel@tonic-gate }; 5017c478bd9Sstevel@tonic-gate 5027c478bd9Sstevel@tonic-gate static uint_t rfsv4disp_cnt = sizeof (rfsv4disptab) / sizeof (rfsv4disptab[0]); 5037c478bd9Sstevel@tonic-gate 5047c478bd9Sstevel@tonic-gate #define OP_ILLEGAL_IDX (rfsv4disp_cnt) 5057c478bd9Sstevel@tonic-gate 5067c478bd9Sstevel@tonic-gate #ifdef DEBUG 5077c478bd9Sstevel@tonic-gate 5087c478bd9Sstevel@tonic-gate int rfs4_fillone_debug = 0; 5097c478bd9Sstevel@tonic-gate int rfs4_no_stub_access = 1; 5107c478bd9Sstevel@tonic-gate int rfs4_rddir_debug = 0; 5117c478bd9Sstevel@tonic-gate 5127c478bd9Sstevel@tonic-gate static char *rfs4_op_string[] = { 5137c478bd9Sstevel@tonic-gate "rfs4_op_null", 5147c478bd9Sstevel@tonic-gate "rfs4_op_1 unused", 5157c478bd9Sstevel@tonic-gate "rfs4_op_2 unused", 5167c478bd9Sstevel@tonic-gate "rfs4_op_access", 5177c478bd9Sstevel@tonic-gate "rfs4_op_close", 5187c478bd9Sstevel@tonic-gate "rfs4_op_commit", 5197c478bd9Sstevel@tonic-gate "rfs4_op_create", 5207c478bd9Sstevel@tonic-gate "rfs4_op_delegpurge", 5217c478bd9Sstevel@tonic-gate "rfs4_op_delegreturn", 5227c478bd9Sstevel@tonic-gate "rfs4_op_getattr", 5237c478bd9Sstevel@tonic-gate "rfs4_op_getfh", 5247c478bd9Sstevel@tonic-gate "rfs4_op_link", 5257c478bd9Sstevel@tonic-gate "rfs4_op_lock", 5267c478bd9Sstevel@tonic-gate "rfs4_op_lockt", 5277c478bd9Sstevel@tonic-gate "rfs4_op_locku", 5287c478bd9Sstevel@tonic-gate "rfs4_op_lookup", 5297c478bd9Sstevel@tonic-gate "rfs4_op_lookupp", 5307c478bd9Sstevel@tonic-gate "rfs4_op_nverify", 5317c478bd9Sstevel@tonic-gate "rfs4_op_open", 5327c478bd9Sstevel@tonic-gate "rfs4_op_openattr", 5337c478bd9Sstevel@tonic-gate "rfs4_op_open_confirm", 5347c478bd9Sstevel@tonic-gate "rfs4_op_open_downgrade", 5357c478bd9Sstevel@tonic-gate "rfs4_op_putfh", 5367c478bd9Sstevel@tonic-gate "rfs4_op_putpubfh", 5377c478bd9Sstevel@tonic-gate "rfs4_op_putrootfh", 5387c478bd9Sstevel@tonic-gate "rfs4_op_read", 5397c478bd9Sstevel@tonic-gate "rfs4_op_readdir", 5407c478bd9Sstevel@tonic-gate "rfs4_op_readlink", 5417c478bd9Sstevel@tonic-gate "rfs4_op_remove", 5427c478bd9Sstevel@tonic-gate "rfs4_op_rename", 5437c478bd9Sstevel@tonic-gate "rfs4_op_renew", 5447c478bd9Sstevel@tonic-gate "rfs4_op_restorefh", 5457c478bd9Sstevel@tonic-gate "rfs4_op_savefh", 5467c478bd9Sstevel@tonic-gate "rfs4_op_secinfo", 5477c478bd9Sstevel@tonic-gate "rfs4_op_setattr", 5487c478bd9Sstevel@tonic-gate "rfs4_op_setclientid", 5497c478bd9Sstevel@tonic-gate "rfs4_op_setclient_confirm", 5507c478bd9Sstevel@tonic-gate "rfs4_op_verify", 5517c478bd9Sstevel@tonic-gate "rfs4_op_write", 5527c478bd9Sstevel@tonic-gate "rfs4_op_release_lockowner", 553*f44e1126SVitaliy Gusev /* NFSv4.1 */ 554*f44e1126SVitaliy Gusev "backchannel_ctl", 555*f44e1126SVitaliy Gusev "bind_conn_to_session", 556*f44e1126SVitaliy Gusev "exchange_id", 557*f44e1126SVitaliy Gusev "create_session", 558*f44e1126SVitaliy Gusev "destroy_session", 559*f44e1126SVitaliy Gusev "free_stateid", 560*f44e1126SVitaliy Gusev "get_dir_delegation", 561*f44e1126SVitaliy Gusev "getdeviceinfo", 562*f44e1126SVitaliy Gusev "getdevicelist", 563*f44e1126SVitaliy Gusev "layoutcommit", 564*f44e1126SVitaliy Gusev "layoutget", 565*f44e1126SVitaliy Gusev "layoutreturn", 566*f44e1126SVitaliy Gusev "secinfo_no_name", 567*f44e1126SVitaliy Gusev "sequence", 568*f44e1126SVitaliy Gusev "set_ssv", 569*f44e1126SVitaliy Gusev "test_stateid", 570*f44e1126SVitaliy Gusev "want_delegation", 571*f44e1126SVitaliy Gusev "destroy_clientid", 572*f44e1126SVitaliy Gusev "reclaim_complete", 5737c478bd9Sstevel@tonic-gate "rfs4_op_illegal" 5747c478bd9Sstevel@tonic-gate }; 575*f44e1126SVitaliy Gusev 5767c478bd9Sstevel@tonic-gate #endif 5777c478bd9Sstevel@tonic-gate 5780dfe541eSEvan Layton void rfs4_ss_chkclid(nfs4_srv_t *, rfs4_client_t *); 5797c478bd9Sstevel@tonic-gate 580cee86682Scalum extern size_t strlcpy(char *dst, const char *src, size_t dstsize); 581cee86682Scalum 5822f172c55SRobert Thurlow extern void rfs4_free_fs_locations4(fs_locations4 *); 5832f172c55SRobert Thurlow 5847c478bd9Sstevel@tonic-gate #ifdef nextdp 5857c478bd9Sstevel@tonic-gate #undef nextdp 5867c478bd9Sstevel@tonic-gate #endif 5877c478bd9Sstevel@tonic-gate #define nextdp(dp) ((struct dirent64 *)((char *)(dp) + (dp)->d_reclen)) 5887c478bd9Sstevel@tonic-gate 5897c478bd9Sstevel@tonic-gate static const fs_operation_def_t nfs4_rd_deleg_tmpl[] = { 590cfae96c2Sjwahlig VOPNAME_OPEN, { .femop_open = deleg_rd_open }, 591cfae96c2Sjwahlig VOPNAME_WRITE, { .femop_write = deleg_rd_write }, 592cfae96c2Sjwahlig VOPNAME_SETATTR, { .femop_setattr = deleg_rd_setattr }, 593aa59c4cbSrsb VOPNAME_RWLOCK, { .femop_rwlock = deleg_rd_rwlock }, 594cfae96c2Sjwahlig VOPNAME_SPACE, { .femop_space = deleg_rd_space }, 595cfae96c2Sjwahlig VOPNAME_SETSECATTR, { .femop_setsecattr = deleg_rd_setsecattr }, 596cfae96c2Sjwahlig VOPNAME_VNEVENT, { .femop_vnevent = deleg_rd_vnevent }, 5977c478bd9Sstevel@tonic-gate NULL, NULL 5987c478bd9Sstevel@tonic-gate }; 5997c478bd9Sstevel@tonic-gate static const fs_operation_def_t nfs4_wr_deleg_tmpl[] = { 600cfae96c2Sjwahlig VOPNAME_OPEN, { .femop_open = deleg_wr_open }, 601cfae96c2Sjwahlig VOPNAME_READ, { .femop_read = deleg_wr_read }, 602cfae96c2Sjwahlig VOPNAME_WRITE, { .femop_write = deleg_wr_write }, 603cfae96c2Sjwahlig VOPNAME_SETATTR, { .femop_setattr = deleg_wr_setattr }, 604aa59c4cbSrsb VOPNAME_RWLOCK, { .femop_rwlock = deleg_wr_rwlock }, 605cfae96c2Sjwahlig VOPNAME_SPACE, { .femop_space = deleg_wr_space }, 606cfae96c2Sjwahlig VOPNAME_SETSECATTR, { .femop_setsecattr = deleg_wr_setsecattr }, 607cfae96c2Sjwahlig VOPNAME_VNEVENT, { .femop_vnevent = deleg_wr_vnevent }, 6087c478bd9Sstevel@tonic-gate NULL, NULL 6097c478bd9Sstevel@tonic-gate }; 6107c478bd9Sstevel@tonic-gate 6110dfe541eSEvan Layton nfs4_srv_t * 6120dfe541eSEvan Layton nfs4_get_srv(void) 6137c478bd9Sstevel@tonic-gate { 6140dfe541eSEvan Layton nfs_globals_t *ng = nfs_srv_getzg(); 6150dfe541eSEvan Layton nfs4_srv_t *srv = ng->nfs4_srv; 6160dfe541eSEvan Layton ASSERT(srv != NULL); 6170dfe541eSEvan Layton return (srv); 6180dfe541eSEvan Layton } 6190dfe541eSEvan Layton 6200dfe541eSEvan Layton void 6210dfe541eSEvan Layton rfs4_srv_zone_init(nfs_globals_t *ng) 6220dfe541eSEvan Layton { 6230dfe541eSEvan Layton nfs4_srv_t *nsrv4; 6247c478bd9Sstevel@tonic-gate timespec32_t verf; 6250dfe541eSEvan Layton 6260dfe541eSEvan Layton nsrv4 = kmem_zalloc(sizeof (*nsrv4), KM_SLEEP); 6277c478bd9Sstevel@tonic-gate 6287c478bd9Sstevel@tonic-gate /* 6297c478bd9Sstevel@tonic-gate * The following algorithm attempts to find a unique verifier 6307c478bd9Sstevel@tonic-gate * to be used as the write verifier returned from the server 6317c478bd9Sstevel@tonic-gate * to the client. It is important that this verifier change 6327c478bd9Sstevel@tonic-gate * whenever the server reboots. Of secondary importance, it 6337c478bd9Sstevel@tonic-gate * is important for the verifier to be unique between two 6347c478bd9Sstevel@tonic-gate * different servers. 6357c478bd9Sstevel@tonic-gate * 6367c478bd9Sstevel@tonic-gate * Thus, an attempt is made to use the system hostid and the 6377c478bd9Sstevel@tonic-gate * current time in seconds when the nfssrv kernel module is 6387c478bd9Sstevel@tonic-gate * loaded. It is assumed that an NFS server will not be able 6397c478bd9Sstevel@tonic-gate * to boot and then to reboot in less than a second. If the 6407c478bd9Sstevel@tonic-gate * hostid has not been set, then the current high resolution 6417c478bd9Sstevel@tonic-gate * time is used. This will ensure different verifiers each 6427c478bd9Sstevel@tonic-gate * time the server reboots and minimize the chances that two 6437c478bd9Sstevel@tonic-gate * different servers will have the same verifier. 6447c478bd9Sstevel@tonic-gate * XXX - this is broken on LP64 kernels. 6457c478bd9Sstevel@tonic-gate */ 6465679c89fSjv227347 verf.tv_sec = (time_t)zone_get_hostid(NULL); 6477c478bd9Sstevel@tonic-gate if (verf.tv_sec != 0) { 6487c478bd9Sstevel@tonic-gate verf.tv_nsec = gethrestime_sec(); 6497c478bd9Sstevel@tonic-gate } else { 6507c478bd9Sstevel@tonic-gate timespec_t tverf; 6517c478bd9Sstevel@tonic-gate 6527c478bd9Sstevel@tonic-gate gethrestime(&tverf); 6537c478bd9Sstevel@tonic-gate verf.tv_sec = (time_t)tverf.tv_sec; 6547c478bd9Sstevel@tonic-gate verf.tv_nsec = tverf.tv_nsec; 6557c478bd9Sstevel@tonic-gate } 6560dfe541eSEvan Layton nsrv4->write4verf = *(uint64_t *)&verf; 6577c478bd9Sstevel@tonic-gate 6587c478bd9Sstevel@tonic-gate /* Used to manage create/destroy of server state */ 6590dfe541eSEvan Layton nsrv4->nfs4_server_state = NULL; 6600dfe541eSEvan Layton nsrv4->nfs4_cur_servinst = NULL; 6610dfe541eSEvan Layton nsrv4->nfs4_deleg_policy = SRV_NEVER_DELEGATE; 6620dfe541eSEvan Layton mutex_init(&nsrv4->deleg_lock, NULL, MUTEX_DEFAULT, NULL); 6630dfe541eSEvan Layton mutex_init(&nsrv4->state_lock, NULL, MUTEX_DEFAULT, NULL); 6640dfe541eSEvan Layton mutex_init(&nsrv4->servinst_lock, NULL, MUTEX_DEFAULT, NULL); 6650dfe541eSEvan Layton rw_init(&nsrv4->deleg_policy_lock, NULL, RW_DEFAULT, NULL); 6667c478bd9Sstevel@tonic-gate 6670dfe541eSEvan Layton ng->nfs4_srv = nsrv4; 6680dfe541eSEvan Layton } 6697c478bd9Sstevel@tonic-gate 6700dfe541eSEvan Layton void 6710dfe541eSEvan Layton rfs4_srv_zone_fini(nfs_globals_t *ng) 6720dfe541eSEvan Layton { 6730dfe541eSEvan Layton nfs4_srv_t *nsrv4 = ng->nfs4_srv; 6747c478bd9Sstevel@tonic-gate 6750dfe541eSEvan Layton ng->nfs4_srv = NULL; 6760dfe541eSEvan Layton 6770dfe541eSEvan Layton mutex_destroy(&nsrv4->deleg_lock); 6780dfe541eSEvan Layton mutex_destroy(&nsrv4->state_lock); 6790dfe541eSEvan Layton mutex_destroy(&nsrv4->servinst_lock); 6800dfe541eSEvan Layton rw_destroy(&nsrv4->deleg_policy_lock); 6810dfe541eSEvan Layton 6820dfe541eSEvan Layton kmem_free(nsrv4, sizeof (*nsrv4)); 6830dfe541eSEvan Layton } 6840dfe541eSEvan Layton 6850dfe541eSEvan Layton void 6860dfe541eSEvan Layton rfs4_srvrinit(void) 6870dfe541eSEvan Layton { 6880dfe541eSEvan Layton extern void rfs4_attr_init(); 6890dfe541eSEvan Layton 6900dfe541eSEvan Layton rfs4_attr_init(); 6910dfe541eSEvan Layton 6920dfe541eSEvan Layton if (fem_create("deleg_rdops", nfs4_rd_deleg_tmpl, &deleg_rdops) != 0) { 6937c478bd9Sstevel@tonic-gate rfs4_disable_delegation(); 6940dfe541eSEvan Layton } else if (fem_create("deleg_wrops", nfs4_wr_deleg_tmpl, 6950dfe541eSEvan Layton &deleg_wrops) != 0) { 6967c478bd9Sstevel@tonic-gate rfs4_disable_delegation(); 6977c478bd9Sstevel@tonic-gate fem_free(deleg_rdops); 6987c478bd9Sstevel@tonic-gate } 6997c478bd9Sstevel@tonic-gate 7007c478bd9Sstevel@tonic-gate nfs4_srv_caller_id = fs_new_caller_id(); 7017c478bd9Sstevel@tonic-gate lockt_sysid = lm_alloc_sysidt(); 7021b300de9Sjwahlig vsd_create(&nfs4_srv_vkey, NULL); 7030dfe541eSEvan Layton rfs4_state_g_init(); 7047c478bd9Sstevel@tonic-gate } 7057c478bd9Sstevel@tonic-gate 7067c478bd9Sstevel@tonic-gate void 7077c478bd9Sstevel@tonic-gate rfs4_srvrfini(void) 7087c478bd9Sstevel@tonic-gate { 7097c478bd9Sstevel@tonic-gate if (lockt_sysid != LM_NOSYSID) { 7107c478bd9Sstevel@tonic-gate lm_free_sysidt(lockt_sysid); 7117c478bd9Sstevel@tonic-gate lockt_sysid = LM_NOSYSID; 7127c478bd9Sstevel@tonic-gate } 7137c478bd9Sstevel@tonic-gate 7140dfe541eSEvan Layton rfs4_state_g_fini(); 7157c478bd9Sstevel@tonic-gate 7167c478bd9Sstevel@tonic-gate fem_free(deleg_rdops); 7177c478bd9Sstevel@tonic-gate fem_free(deleg_wrops); 7187c478bd9Sstevel@tonic-gate } 7197c478bd9Sstevel@tonic-gate 7207c478bd9Sstevel@tonic-gate void 721*f44e1126SVitaliy Gusev rfs4_do_server_start(int server_upordown, int srv_delegation, 722*f44e1126SVitaliy Gusev nfs4_minor_t nfs4_minor_max, int cluster_booted) 7230dfe541eSEvan Layton { 7240dfe541eSEvan Layton nfs4_srv_t *nsrv4 = nfs4_get_srv(); 7250dfe541eSEvan Layton 7260dfe541eSEvan Layton /* Is this a warm start? */ 7270dfe541eSEvan Layton if (server_upordown == NFS_SERVER_QUIESCED) { 7280dfe541eSEvan Layton cmn_err(CE_NOTE, "nfs4_srv: " 7290dfe541eSEvan Layton "server was previously quiesced; " 7300dfe541eSEvan Layton "existing NFSv4 state will be re-used"); 7310dfe541eSEvan Layton 7320dfe541eSEvan Layton /* 7330dfe541eSEvan Layton * HA-NFSv4: this is also the signal 7340dfe541eSEvan Layton * that a Resource Group failover has 7350dfe541eSEvan Layton * occurred. 7360dfe541eSEvan Layton */ 7370dfe541eSEvan Layton if (cluster_booted) 7380dfe541eSEvan Layton hanfsv4_failover(nsrv4); 7390dfe541eSEvan Layton } else { 7400dfe541eSEvan Layton /* Cold start */ 7410dfe541eSEvan Layton nsrv4->rfs4_start_time = 0; 7420dfe541eSEvan Layton rfs4_state_zone_init(nsrv4); 7430dfe541eSEvan Layton nsrv4->nfs4_drc = rfs4_init_drc(nfs4_drc_max, 7440dfe541eSEvan Layton nfs4_drc_hash); 7450dfe541eSEvan Layton 7460dfe541eSEvan Layton /* 7470dfe541eSEvan Layton * The nfsd service was started with the -s option 7480dfe541eSEvan Layton * we need to pull in any state from the paths indicated. 7490dfe541eSEvan Layton */ 7500dfe541eSEvan Layton if (curzone == global_zone && rfs4_dss_numnewpaths > 0) { 7510dfe541eSEvan Layton /* read in the stable storage state from these paths */ 7520dfe541eSEvan Layton rfs4_dss_readstate(nsrv4, rfs4_dss_numnewpaths, 7530dfe541eSEvan Layton rfs4_dss_newpaths); 7540dfe541eSEvan Layton } 7550dfe541eSEvan Layton } 7560dfe541eSEvan Layton 757*f44e1126SVitaliy Gusev nsrv4->nfs4_minor_max = nfs4_minor_max; 758*f44e1126SVitaliy Gusev 7590dfe541eSEvan Layton /* Check if delegation is to be enabled */ 7600dfe541eSEvan Layton if (srv_delegation != FALSE) 7610dfe541eSEvan Layton rfs4_set_deleg_policy(nsrv4, SRV_NORMAL_DELEGATE); 7620dfe541eSEvan Layton } 7630dfe541eSEvan Layton 7640dfe541eSEvan Layton void 7657c478bd9Sstevel@tonic-gate rfs4_init_compound_state(struct compound_state *cs) 7667c478bd9Sstevel@tonic-gate { 7677c478bd9Sstevel@tonic-gate bzero(cs, sizeof (*cs)); 7687c478bd9Sstevel@tonic-gate cs->cont = TRUE; 7697c478bd9Sstevel@tonic-gate cs->access = CS_ACCESS_DENIED; 7707c478bd9Sstevel@tonic-gate cs->deleg = FALSE; 7717c478bd9Sstevel@tonic-gate cs->mandlock = FALSE; 7727c478bd9Sstevel@tonic-gate cs->fh.nfs_fh4_val = cs->fhbuf; 7737c478bd9Sstevel@tonic-gate } 7747c478bd9Sstevel@tonic-gate 775*f44e1126SVitaliy Gusev /* Do cleanup of the compound_state */ 776*f44e1126SVitaliy Gusev void 777*f44e1126SVitaliy Gusev rfs4_fini_compound_state(struct compound_state *cs) 778*f44e1126SVitaliy Gusev { 779*f44e1126SVitaliy Gusev if (cs->vp) { 780*f44e1126SVitaliy Gusev VN_RELE(cs->vp); 781*f44e1126SVitaliy Gusev } 782*f44e1126SVitaliy Gusev if (cs->saved_vp) { 783*f44e1126SVitaliy Gusev VN_RELE(cs->saved_vp); 784*f44e1126SVitaliy Gusev } 785*f44e1126SVitaliy Gusev if (cs->cr) { 786*f44e1126SVitaliy Gusev crfree(cs->cr); 787*f44e1126SVitaliy Gusev } 788*f44e1126SVitaliy Gusev if (cs->saved_fh.nfs_fh4_val) { 789*f44e1126SVitaliy Gusev kmem_free(cs->saved_fh.nfs_fh4_val, NFS4_FHSIZE); 790*f44e1126SVitaliy Gusev } 791*f44e1126SVitaliy Gusev if (cs->sp) { 792*f44e1126SVitaliy Gusev rfs4x_session_rele(cs->sp); 793*f44e1126SVitaliy Gusev } 794*f44e1126SVitaliy Gusev } 795*f44e1126SVitaliy Gusev 7967c478bd9Sstevel@tonic-gate void 7977c478bd9Sstevel@tonic-gate rfs4_grace_start(rfs4_servinst_t *sip) 7987c478bd9Sstevel@tonic-gate { 7997c478bd9Sstevel@tonic-gate rw_enter(&sip->rwlock, RW_WRITER); 800*f44e1126SVitaliy Gusev sip->start_time = nfs_sys_uptime(); 8017c478bd9Sstevel@tonic-gate sip->grace_period = rfs4_grace_period; 8027c478bd9Sstevel@tonic-gate rw_exit(&sip->rwlock); 8037c478bd9Sstevel@tonic-gate } 8047c478bd9Sstevel@tonic-gate 8057c478bd9Sstevel@tonic-gate /* 8067c478bd9Sstevel@tonic-gate * returns true if the instance's grace period has never been started 8077c478bd9Sstevel@tonic-gate */ 8087c478bd9Sstevel@tonic-gate int 8097c478bd9Sstevel@tonic-gate rfs4_servinst_grace_new(rfs4_servinst_t *sip) 8107c478bd9Sstevel@tonic-gate { 8117c478bd9Sstevel@tonic-gate time_t start_time; 8127c478bd9Sstevel@tonic-gate 8137c478bd9Sstevel@tonic-gate rw_enter(&sip->rwlock, RW_READER); 8147c478bd9Sstevel@tonic-gate start_time = sip->start_time; 8157c478bd9Sstevel@tonic-gate rw_exit(&sip->rwlock); 8167c478bd9Sstevel@tonic-gate 8177c478bd9Sstevel@tonic-gate return (start_time == 0); 8187c478bd9Sstevel@tonic-gate } 8197c478bd9Sstevel@tonic-gate 8207c478bd9Sstevel@tonic-gate /* 8217c478bd9Sstevel@tonic-gate * Indicates if server instance is within the 8227c478bd9Sstevel@tonic-gate * grace period. 8237c478bd9Sstevel@tonic-gate */ 8247c478bd9Sstevel@tonic-gate int 8257c478bd9Sstevel@tonic-gate rfs4_servinst_in_grace(rfs4_servinst_t *sip) 8267c478bd9Sstevel@tonic-gate { 8277c478bd9Sstevel@tonic-gate time_t grace_expiry; 8287c478bd9Sstevel@tonic-gate 829*f44e1126SVitaliy Gusev /* All clients called reclaim-complete */ 830*f44e1126SVitaliy Gusev if (sip->nreclaim == 0 || sip->grace_period == 0) 831*f44e1126SVitaliy Gusev return (0); 832*f44e1126SVitaliy Gusev 8337c478bd9Sstevel@tonic-gate rw_enter(&sip->rwlock, RW_READER); 8347c478bd9Sstevel@tonic-gate grace_expiry = sip->start_time + sip->grace_period; 8357c478bd9Sstevel@tonic-gate rw_exit(&sip->rwlock); 8367c478bd9Sstevel@tonic-gate 837*f44e1126SVitaliy Gusev if (nfs_sys_uptime() < grace_expiry) 838*f44e1126SVitaliy Gusev return (1); 839*f44e1126SVitaliy Gusev 840*f44e1126SVitaliy Gusev /* Once grace period ends, optimize next calls */ 841*f44e1126SVitaliy Gusev sip->grace_period = 0; 842*f44e1126SVitaliy Gusev return (0); 8437c478bd9Sstevel@tonic-gate } 8447c478bd9Sstevel@tonic-gate 8457c478bd9Sstevel@tonic-gate int 8467c478bd9Sstevel@tonic-gate rfs4_clnt_in_grace(rfs4_client_t *cp) 8477c478bd9Sstevel@tonic-gate { 848d216dff5SRobert Mastors ASSERT(rfs4_dbe_refcnt(cp->rc_dbe) > 0); 8497c478bd9Sstevel@tonic-gate 850d216dff5SRobert Mastors return (rfs4_servinst_in_grace(cp->rc_server_instance)); 8517c478bd9Sstevel@tonic-gate } 8527c478bd9Sstevel@tonic-gate 8537c478bd9Sstevel@tonic-gate /* 8547c478bd9Sstevel@tonic-gate * reset all currently active grace periods 8557c478bd9Sstevel@tonic-gate */ 8567c478bd9Sstevel@tonic-gate void 8570dfe541eSEvan Layton rfs4_grace_reset_all(nfs4_srv_t *nsrv4) 8587c478bd9Sstevel@tonic-gate { 8597c478bd9Sstevel@tonic-gate rfs4_servinst_t *sip; 8607c478bd9Sstevel@tonic-gate 8610dfe541eSEvan Layton mutex_enter(&nsrv4->servinst_lock); 8620dfe541eSEvan Layton for (sip = nsrv4->nfs4_cur_servinst; sip != NULL; sip = sip->prev) 863cee86682Scalum if (rfs4_servinst_in_grace(sip)) 8647c478bd9Sstevel@tonic-gate rfs4_grace_start(sip); 8650dfe541eSEvan Layton mutex_exit(&nsrv4->servinst_lock); 8667c478bd9Sstevel@tonic-gate } 8677c478bd9Sstevel@tonic-gate 8687c478bd9Sstevel@tonic-gate /* 8697c478bd9Sstevel@tonic-gate * start any new instances' grace periods 8707c478bd9Sstevel@tonic-gate */ 8717c478bd9Sstevel@tonic-gate void 8720dfe541eSEvan Layton rfs4_grace_start_new(nfs4_srv_t *nsrv4) 8737c478bd9Sstevel@tonic-gate { 8747c478bd9Sstevel@tonic-gate rfs4_servinst_t *sip; 8757c478bd9Sstevel@tonic-gate 8760dfe541eSEvan Layton mutex_enter(&nsrv4->servinst_lock); 8770dfe541eSEvan Layton for (sip = nsrv4->nfs4_cur_servinst; sip != NULL; sip = sip->prev) 8787c478bd9Sstevel@tonic-gate if (rfs4_servinst_grace_new(sip)) 8797c478bd9Sstevel@tonic-gate rfs4_grace_start(sip); 8800dfe541eSEvan Layton mutex_exit(&nsrv4->servinst_lock); 881cee86682Scalum } 8827c478bd9Sstevel@tonic-gate 883cee86682Scalum static rfs4_dss_path_t * 8840dfe541eSEvan Layton rfs4_dss_newpath(nfs4_srv_t *nsrv4, rfs4_servinst_t *sip, 8850dfe541eSEvan Layton char *path, unsigned index) 886cee86682Scalum { 887cee86682Scalum size_t len; 888cee86682Scalum rfs4_dss_path_t *dss_path; 889cee86682Scalum 890cee86682Scalum dss_path = kmem_alloc(sizeof (rfs4_dss_path_t), KM_SLEEP); 891cee86682Scalum 892cee86682Scalum /* 893cee86682Scalum * Take a copy of the string, since the original may be overwritten. 894cee86682Scalum * Sadly, no strdup() in the kernel. 895cee86682Scalum */ 896cee86682Scalum /* allow for NUL */ 897cee86682Scalum len = strlen(path) + 1; 898cee86682Scalum dss_path->path = kmem_alloc(len, KM_SLEEP); 899cee86682Scalum (void) strlcpy(dss_path->path, path, len); 900cee86682Scalum 901cee86682Scalum /* associate with servinst */ 902cee86682Scalum dss_path->sip = sip; 903cee86682Scalum dss_path->index = index; 904cee86682Scalum 905cee86682Scalum /* 906cee86682Scalum * Add to list of served paths. 907cee86682Scalum * No locking required, as we're only ever called at startup. 908cee86682Scalum */ 9090dfe541eSEvan Layton if (nsrv4->dss_pathlist == NULL) { 910cee86682Scalum /* this is the first dss_path_t */ 911cee86682Scalum 912cee86682Scalum /* needed for insque/remque */ 913cee86682Scalum dss_path->next = dss_path->prev = dss_path; 914cee86682Scalum 9150dfe541eSEvan Layton nsrv4->dss_pathlist = dss_path; 916cee86682Scalum } else { 9170dfe541eSEvan Layton insque(dss_path, nsrv4->dss_pathlist); 918cee86682Scalum } 919cee86682Scalum 920cee86682Scalum return (dss_path); 9217c478bd9Sstevel@tonic-gate } 9227c478bd9Sstevel@tonic-gate 9237c478bd9Sstevel@tonic-gate /* 9247c478bd9Sstevel@tonic-gate * Create a new server instance, and make it the currently active instance. 9257c478bd9Sstevel@tonic-gate * Note that starting the grace period too early will reduce the clients' 9267c478bd9Sstevel@tonic-gate * recovery window. 9277c478bd9Sstevel@tonic-gate */ 9287c478bd9Sstevel@tonic-gate void 9290dfe541eSEvan Layton rfs4_servinst_create(nfs4_srv_t *nsrv4, int start_grace, 9300dfe541eSEvan Layton int dss_npaths, char **dss_paths) 9317c478bd9Sstevel@tonic-gate { 932cee86682Scalum unsigned i; 9337c478bd9Sstevel@tonic-gate rfs4_servinst_t *sip; 934cee86682Scalum rfs4_oldstate_t *oldstate; 9357c478bd9Sstevel@tonic-gate 9367c478bd9Sstevel@tonic-gate sip = kmem_alloc(sizeof (rfs4_servinst_t), KM_SLEEP); 9377c478bd9Sstevel@tonic-gate rw_init(&sip->rwlock, NULL, RW_DEFAULT, NULL); 9387c478bd9Sstevel@tonic-gate 939*f44e1126SVitaliy Gusev sip->nreclaim = 0; 9407c478bd9Sstevel@tonic-gate sip->start_time = (time_t)0; 9417c478bd9Sstevel@tonic-gate sip->grace_period = (time_t)0; 9427c478bd9Sstevel@tonic-gate sip->next = NULL; 9437c478bd9Sstevel@tonic-gate sip->prev = NULL; 9447c478bd9Sstevel@tonic-gate 945cee86682Scalum rw_init(&sip->oldstate_lock, NULL, RW_DEFAULT, NULL); 946cee86682Scalum /* 947cee86682Scalum * This initial dummy entry is required to setup for insque/remque. 948cee86682Scalum * It must be skipped over whenever the list is traversed. 949cee86682Scalum */ 950cee86682Scalum oldstate = kmem_alloc(sizeof (rfs4_oldstate_t), KM_SLEEP); 951cee86682Scalum /* insque/remque require initial list entry to be self-terminated */ 952cee86682Scalum oldstate->next = oldstate; 953cee86682Scalum oldstate->prev = oldstate; 954cee86682Scalum sip->oldstate = oldstate; 955cee86682Scalum 956cee86682Scalum 957cee86682Scalum sip->dss_npaths = dss_npaths; 958cee86682Scalum sip->dss_paths = kmem_alloc(dss_npaths * 959cee86682Scalum sizeof (rfs4_dss_path_t *), KM_SLEEP); 960cee86682Scalum 961cee86682Scalum for (i = 0; i < dss_npaths; i++) { 9620dfe541eSEvan Layton sip->dss_paths[i] = 9630dfe541eSEvan Layton rfs4_dss_newpath(nsrv4, sip, dss_paths[i], i); 964cee86682Scalum } 965cee86682Scalum 9660dfe541eSEvan Layton mutex_enter(&nsrv4->servinst_lock); 9670dfe541eSEvan Layton if (nsrv4->nfs4_cur_servinst != NULL) { 9687c478bd9Sstevel@tonic-gate /* add to linked list */ 9690dfe541eSEvan Layton sip->prev = nsrv4->nfs4_cur_servinst; 9700dfe541eSEvan Layton nsrv4->nfs4_cur_servinst->next = sip; 9717c478bd9Sstevel@tonic-gate } 9727c478bd9Sstevel@tonic-gate if (start_grace) 9737c478bd9Sstevel@tonic-gate rfs4_grace_start(sip); 9747c478bd9Sstevel@tonic-gate /* make the new instance "current" */ 9750dfe541eSEvan Layton nsrv4->nfs4_cur_servinst = sip; 9767c478bd9Sstevel@tonic-gate 9770dfe541eSEvan Layton mutex_exit(&nsrv4->servinst_lock); 9787c478bd9Sstevel@tonic-gate } 9797c478bd9Sstevel@tonic-gate 9807c478bd9Sstevel@tonic-gate /* 9817c478bd9Sstevel@tonic-gate * In future, we might add a rfs4_servinst_destroy(sip) but, for now, destroy 9827c478bd9Sstevel@tonic-gate * all instances directly. 9837c478bd9Sstevel@tonic-gate */ 9847c478bd9Sstevel@tonic-gate void 9850dfe541eSEvan Layton rfs4_servinst_destroy_all(nfs4_srv_t *nsrv4) 9867c478bd9Sstevel@tonic-gate { 9877c478bd9Sstevel@tonic-gate rfs4_servinst_t *sip, *prev, *current; 9887c478bd9Sstevel@tonic-gate #ifdef DEBUG 9897c478bd9Sstevel@tonic-gate int n = 0; 9907c478bd9Sstevel@tonic-gate #endif 9917c478bd9Sstevel@tonic-gate 9920dfe541eSEvan Layton mutex_enter(&nsrv4->servinst_lock); 9930dfe541eSEvan Layton ASSERT(nsrv4->nfs4_cur_servinst != NULL); 9940dfe541eSEvan Layton current = nsrv4->nfs4_cur_servinst; 9950dfe541eSEvan Layton nsrv4->nfs4_cur_servinst = NULL; 9967c478bd9Sstevel@tonic-gate for (sip = current; sip != NULL; sip = prev) { 9977c478bd9Sstevel@tonic-gate prev = sip->prev; 9987c478bd9Sstevel@tonic-gate rw_destroy(&sip->rwlock); 999cee86682Scalum if (sip->oldstate) 1000cee86682Scalum kmem_free(sip->oldstate, sizeof (rfs4_oldstate_t)); 10010dfe541eSEvan Layton if (sip->dss_paths) { 10020dfe541eSEvan Layton int i = sip->dss_npaths; 10030dfe541eSEvan Layton 10040dfe541eSEvan Layton while (i > 0) { 10050dfe541eSEvan Layton i--; 10060dfe541eSEvan Layton if (sip->dss_paths[i] != NULL) { 10070dfe541eSEvan Layton char *path = sip->dss_paths[i]->path; 10080dfe541eSEvan Layton 10090dfe541eSEvan Layton if (path != NULL) { 10100dfe541eSEvan Layton kmem_free(path, 10110dfe541eSEvan Layton strlen(path) + 1); 10120dfe541eSEvan Layton } 10130dfe541eSEvan Layton kmem_free(sip->dss_paths[i], 10140dfe541eSEvan Layton sizeof (rfs4_dss_path_t)); 10150dfe541eSEvan Layton } 10160dfe541eSEvan Layton } 1017cee86682Scalum kmem_free(sip->dss_paths, 1018cee86682Scalum sip->dss_npaths * sizeof (rfs4_dss_path_t *)); 10190dfe541eSEvan Layton } 10207c478bd9Sstevel@tonic-gate kmem_free(sip, sizeof (rfs4_servinst_t)); 10217c478bd9Sstevel@tonic-gate #ifdef DEBUG 10227c478bd9Sstevel@tonic-gate n++; 10237c478bd9Sstevel@tonic-gate #endif 10247c478bd9Sstevel@tonic-gate } 10250dfe541eSEvan Layton mutex_exit(&nsrv4->servinst_lock); 10267c478bd9Sstevel@tonic-gate } 10277c478bd9Sstevel@tonic-gate 10287c478bd9Sstevel@tonic-gate /* 10297c478bd9Sstevel@tonic-gate * Assign the current server instance to a client_t. 1030d216dff5SRobert Mastors * Should be called with cp->rc_dbe held. 10317c478bd9Sstevel@tonic-gate */ 10327c478bd9Sstevel@tonic-gate void 10330dfe541eSEvan Layton rfs4_servinst_assign(nfs4_srv_t *nsrv4, rfs4_client_t *cp, 10340dfe541eSEvan Layton rfs4_servinst_t *sip) 10357c478bd9Sstevel@tonic-gate { 1036d216dff5SRobert Mastors ASSERT(rfs4_dbe_refcnt(cp->rc_dbe) > 0); 10377c478bd9Sstevel@tonic-gate 10387c478bd9Sstevel@tonic-gate /* 10397c478bd9Sstevel@tonic-gate * The lock ensures that if the current instance is in the process 10407c478bd9Sstevel@tonic-gate * of changing, we will see the new one. 10417c478bd9Sstevel@tonic-gate */ 10420dfe541eSEvan Layton mutex_enter(&nsrv4->servinst_lock); 1043d216dff5SRobert Mastors cp->rc_server_instance = sip; 10440dfe541eSEvan Layton mutex_exit(&nsrv4->servinst_lock); 10457c478bd9Sstevel@tonic-gate } 10467c478bd9Sstevel@tonic-gate 10477c478bd9Sstevel@tonic-gate rfs4_servinst_t * 10487c478bd9Sstevel@tonic-gate rfs4_servinst(rfs4_client_t *cp) 10497c478bd9Sstevel@tonic-gate { 1050d216dff5SRobert Mastors ASSERT(rfs4_dbe_refcnt(cp->rc_dbe) > 0); 10517c478bd9Sstevel@tonic-gate 1052d216dff5SRobert Mastors return (cp->rc_server_instance); 10537c478bd9Sstevel@tonic-gate } 10547c478bd9Sstevel@tonic-gate 10557c478bd9Sstevel@tonic-gate /* ARGSUSED */ 10567c478bd9Sstevel@tonic-gate static void 10577c478bd9Sstevel@tonic-gate nullfree(caddr_t resop) 10587c478bd9Sstevel@tonic-gate { 10597c478bd9Sstevel@tonic-gate } 10607c478bd9Sstevel@tonic-gate 10617c478bd9Sstevel@tonic-gate /* 10627c478bd9Sstevel@tonic-gate * This is a fall-through for invalid or not implemented (yet) ops 10637c478bd9Sstevel@tonic-gate */ 10647c478bd9Sstevel@tonic-gate /* ARGSUSED */ 10657c478bd9Sstevel@tonic-gate static void 10667c478bd9Sstevel@tonic-gate rfs4_op_inval(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req, 10677c478bd9Sstevel@tonic-gate struct compound_state *cs) 10687c478bd9Sstevel@tonic-gate { 10697c478bd9Sstevel@tonic-gate *cs->statusp = *((nfsstat4 *)&(resop)->nfs_resop4_u) = NFS4ERR_INVAL; 10707c478bd9Sstevel@tonic-gate } 10717c478bd9Sstevel@tonic-gate 10727c478bd9Sstevel@tonic-gate /* 10737c478bd9Sstevel@tonic-gate * Check if the security flavor, nfsnum, is in the flavor_list. 10747c478bd9Sstevel@tonic-gate */ 10757c478bd9Sstevel@tonic-gate bool_t 10767c478bd9Sstevel@tonic-gate in_flavor_list(int nfsnum, int *flavor_list, int count) 10777c478bd9Sstevel@tonic-gate { 10787c478bd9Sstevel@tonic-gate int i; 10797c478bd9Sstevel@tonic-gate 10807c478bd9Sstevel@tonic-gate for (i = 0; i < count; i++) { 10817c478bd9Sstevel@tonic-gate if (nfsnum == flavor_list[i]) 10827c478bd9Sstevel@tonic-gate return (TRUE); 10837c478bd9Sstevel@tonic-gate } 10847c478bd9Sstevel@tonic-gate return (FALSE); 10857c478bd9Sstevel@tonic-gate } 10867c478bd9Sstevel@tonic-gate 10877c478bd9Sstevel@tonic-gate /* 10887c478bd9Sstevel@tonic-gate * Used by rfs4_op_secinfo to get the security information from the 10897c478bd9Sstevel@tonic-gate * export structure associated with the component. 10907c478bd9Sstevel@tonic-gate */ 10917c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1092*f44e1126SVitaliy Gusev nfsstat4 10937c478bd9Sstevel@tonic-gate do_rfs4_op_secinfo(struct compound_state *cs, char *nm, SECINFO4res *resp) 10947c478bd9Sstevel@tonic-gate { 10957c478bd9Sstevel@tonic-gate int error, different_export = 0; 10966e062f4aSMarcel Telka vnode_t *dvp, *vp; 10970dfe541eSEvan Layton struct exportinfo *exi; 10987c478bd9Sstevel@tonic-gate fid_t fid; 10997c478bd9Sstevel@tonic-gate uint_t count, i; 11007c478bd9Sstevel@tonic-gate secinfo4 *resok_val; 11017c478bd9Sstevel@tonic-gate struct secinfo *secp; 11021b300de9Sjwahlig seconfig_t *si; 1103bffeae97SMarcel Telka bool_t did_traverse = FALSE; 11047c478bd9Sstevel@tonic-gate int dotdot, walk; 11050dfe541eSEvan Layton nfs_export_t *ne = nfs_get_export(); 11067c478bd9Sstevel@tonic-gate 11077c478bd9Sstevel@tonic-gate dvp = cs->vp; 11080dfe541eSEvan Layton exi = cs->exi; 11090dfe541eSEvan Layton ASSERT(exi != NULL); 11107c478bd9Sstevel@tonic-gate dotdot = (nm[0] == '.' && nm[1] == '.' && nm[2] == '\0'); 11117c478bd9Sstevel@tonic-gate 11127c478bd9Sstevel@tonic-gate /* 11137c478bd9Sstevel@tonic-gate * If dotdotting, then need to check whether it's above the 11147c478bd9Sstevel@tonic-gate * root of a filesystem, or above an export point. 11157c478bd9Sstevel@tonic-gate */ 11167c478bd9Sstevel@tonic-gate if (dotdot) { 11170dfe541eSEvan Layton vnode_t *zone_rootvp = ne->exi_root->exi_vp; 11187c478bd9Sstevel@tonic-gate 11190dfe541eSEvan Layton ASSERT3U(exi->exi_zoneid, ==, ne->exi_root->exi_zoneid); 11207c478bd9Sstevel@tonic-gate /* 11217c478bd9Sstevel@tonic-gate * If dotdotting at the root of a filesystem, then 11227c478bd9Sstevel@tonic-gate * need to traverse back to the mounted-on filesystem 11237c478bd9Sstevel@tonic-gate * and do the dotdot lookup there. 11247c478bd9Sstevel@tonic-gate */ 11250dfe541eSEvan Layton if ((dvp->v_flag & VROOT) || VN_CMP(dvp, zone_rootvp)) { 11267c478bd9Sstevel@tonic-gate 11277c478bd9Sstevel@tonic-gate /* 11287c478bd9Sstevel@tonic-gate * If at the system root, then can 11297c478bd9Sstevel@tonic-gate * go up no further. 11307c478bd9Sstevel@tonic-gate */ 11310dfe541eSEvan Layton if (VN_CMP(dvp, zone_rootvp)) 11327c478bd9Sstevel@tonic-gate return (puterrno4(ENOENT)); 11337c478bd9Sstevel@tonic-gate 11347c478bd9Sstevel@tonic-gate /* 11357c478bd9Sstevel@tonic-gate * Traverse back to the mounted-on filesystem 11367c478bd9Sstevel@tonic-gate */ 11370dfe541eSEvan Layton dvp = untraverse(dvp, zone_rootvp); 11387c478bd9Sstevel@tonic-gate 11397c478bd9Sstevel@tonic-gate /* 11407c478bd9Sstevel@tonic-gate * Set the different_export flag so we remember 11417c478bd9Sstevel@tonic-gate * to pick up a new exportinfo entry for 11427c478bd9Sstevel@tonic-gate * this new filesystem. 11437c478bd9Sstevel@tonic-gate */ 11447c478bd9Sstevel@tonic-gate different_export = 1; 11457c478bd9Sstevel@tonic-gate } else { 11467c478bd9Sstevel@tonic-gate 11477c478bd9Sstevel@tonic-gate /* 11487c478bd9Sstevel@tonic-gate * If dotdotting above an export point then set 11497c478bd9Sstevel@tonic-gate * the different_export to get new export info. 11507c478bd9Sstevel@tonic-gate */ 11510dfe541eSEvan Layton different_export = nfs_exported(exi, dvp); 11527c478bd9Sstevel@tonic-gate } 11537c478bd9Sstevel@tonic-gate } 11547c478bd9Sstevel@tonic-gate 11557c478bd9Sstevel@tonic-gate /* 11567c478bd9Sstevel@tonic-gate * Get the vnode for the component "nm". 11577c478bd9Sstevel@tonic-gate */ 1158da6c28aaSamw error = VOP_LOOKUP(dvp, nm, &vp, NULL, 0, NULL, cs->cr, 1159da6c28aaSamw NULL, NULL, NULL); 11607c478bd9Sstevel@tonic-gate if (error) 11617c478bd9Sstevel@tonic-gate return (puterrno4(error)); 11627c478bd9Sstevel@tonic-gate 11637c478bd9Sstevel@tonic-gate /* 11647c478bd9Sstevel@tonic-gate * If the vnode is in a pseudo filesystem, or if the security flavor 11657c478bd9Sstevel@tonic-gate * used in the request is valid but not an explicitly shared flavor, 11667c478bd9Sstevel@tonic-gate * or the access bit indicates that this is a limited access, 11677c478bd9Sstevel@tonic-gate * check whether this vnode is visible. 11687c478bd9Sstevel@tonic-gate */ 11697c478bd9Sstevel@tonic-gate if (!different_export && 11700dfe541eSEvan Layton (PSEUDO(exi) || !is_exported_sec(cs->nfsflavor, exi) || 11717c478bd9Sstevel@tonic-gate cs->access & CS_ACCESS_LIMITED)) { 11720dfe541eSEvan Layton if (! nfs_visible(exi, vp, &different_export)) { 11737c478bd9Sstevel@tonic-gate VN_RELE(vp); 11747c478bd9Sstevel@tonic-gate return (puterrno4(ENOENT)); 11757c478bd9Sstevel@tonic-gate } 11767c478bd9Sstevel@tonic-gate } 11777c478bd9Sstevel@tonic-gate 11787c478bd9Sstevel@tonic-gate /* 11797c478bd9Sstevel@tonic-gate * If it's a mountpoint, then traverse it. 11807c478bd9Sstevel@tonic-gate */ 11817c478bd9Sstevel@tonic-gate if (vn_ismntpt(vp)) { 11826e062f4aSMarcel Telka if ((error = traverse(&vp)) != 0) { 11837c478bd9Sstevel@tonic-gate VN_RELE(vp); 11847c478bd9Sstevel@tonic-gate return (puterrno4(error)); 11857c478bd9Sstevel@tonic-gate } 11867c478bd9Sstevel@tonic-gate /* remember that we had to traverse mountpoint */ 11877c478bd9Sstevel@tonic-gate did_traverse = TRUE; 11887c478bd9Sstevel@tonic-gate different_export = 1; 11897c478bd9Sstevel@tonic-gate } else if (vp->v_vfsp != dvp->v_vfsp) { 11907c478bd9Sstevel@tonic-gate /* 11917c478bd9Sstevel@tonic-gate * If vp isn't a mountpoint and the vfs ptrs aren't the same, 11927c478bd9Sstevel@tonic-gate * then vp is probably an LOFS object. We don't need the 11937c478bd9Sstevel@tonic-gate * realvp, we just need to know that we might have crossed 11947c478bd9Sstevel@tonic-gate * a server fs boundary and need to call checkexport4. 11957c478bd9Sstevel@tonic-gate * (LOFS lookup hides server fs mountpoints, and actually calls 11967c478bd9Sstevel@tonic-gate * traverse) 11977c478bd9Sstevel@tonic-gate */ 11987c478bd9Sstevel@tonic-gate different_export = 1; 11997c478bd9Sstevel@tonic-gate } 12007c478bd9Sstevel@tonic-gate 12017c478bd9Sstevel@tonic-gate /* 12027c478bd9Sstevel@tonic-gate * Get the export information for it. 12037c478bd9Sstevel@tonic-gate */ 12047c478bd9Sstevel@tonic-gate if (different_export) { 12057c478bd9Sstevel@tonic-gate 12067c478bd9Sstevel@tonic-gate bzero(&fid, sizeof (fid)); 12077c478bd9Sstevel@tonic-gate fid.fid_len = MAXFIDSZ; 12087c478bd9Sstevel@tonic-gate error = vop_fid_pseudo(vp, &fid); 12097c478bd9Sstevel@tonic-gate if (error) { 12107c478bd9Sstevel@tonic-gate VN_RELE(vp); 12117c478bd9Sstevel@tonic-gate return (puterrno4(error)); 12127c478bd9Sstevel@tonic-gate } 12137c478bd9Sstevel@tonic-gate 12140dfe541eSEvan Layton /* We'll need to reassign "exi". */ 12157c478bd9Sstevel@tonic-gate if (dotdot) 12167c478bd9Sstevel@tonic-gate exi = nfs_vptoexi(NULL, vp, cs->cr, &walk, NULL, TRUE); 12177c478bd9Sstevel@tonic-gate else 12187c478bd9Sstevel@tonic-gate exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid, vp); 12197c478bd9Sstevel@tonic-gate 12207c478bd9Sstevel@tonic-gate if (exi == NULL) { 12217c478bd9Sstevel@tonic-gate if (did_traverse == TRUE) { 12227c478bd9Sstevel@tonic-gate /* 12237c478bd9Sstevel@tonic-gate * If this vnode is a mounted-on vnode, 12247c478bd9Sstevel@tonic-gate * but the mounted-on file system is not 12257c478bd9Sstevel@tonic-gate * exported, send back the secinfo for 12267c478bd9Sstevel@tonic-gate * the exported node that the mounted-on 12277c478bd9Sstevel@tonic-gate * vnode lives in. 12287c478bd9Sstevel@tonic-gate */ 12297c478bd9Sstevel@tonic-gate exi = cs->exi; 12307c478bd9Sstevel@tonic-gate } else { 12317c478bd9Sstevel@tonic-gate VN_RELE(vp); 12327c478bd9Sstevel@tonic-gate return (puterrno4(EACCES)); 12337c478bd9Sstevel@tonic-gate } 12347c478bd9Sstevel@tonic-gate } 12357c478bd9Sstevel@tonic-gate } 12367c478bd9Sstevel@tonic-gate ASSERT(exi != NULL); 12377c478bd9Sstevel@tonic-gate 12387c478bd9Sstevel@tonic-gate 12397c478bd9Sstevel@tonic-gate /* 12407c478bd9Sstevel@tonic-gate * Create the secinfo result based on the security information 12417c478bd9Sstevel@tonic-gate * from the exportinfo structure (exi). 12427c478bd9Sstevel@tonic-gate * 12437c478bd9Sstevel@tonic-gate * Return all flavors for a pseudo node. 12447c478bd9Sstevel@tonic-gate * For a real export node, return the flavor that the client 12457c478bd9Sstevel@tonic-gate * has access with. 12467c478bd9Sstevel@tonic-gate */ 12470dfe541eSEvan Layton ASSERT(RW_LOCK_HELD(&ne->exported_lock)); 12487c478bd9Sstevel@tonic-gate if (PSEUDO(exi)) { 12497c478bd9Sstevel@tonic-gate count = exi->exi_export.ex_seccnt; /* total sec count */ 12507c478bd9Sstevel@tonic-gate resok_val = kmem_alloc(count * sizeof (secinfo4), KM_SLEEP); 12517c478bd9Sstevel@tonic-gate secp = exi->exi_export.ex_secinfo; 12527c478bd9Sstevel@tonic-gate 12537c478bd9Sstevel@tonic-gate for (i = 0; i < count; i++) { 12541b300de9Sjwahlig si = &secp[i].s_secinfo; 12551b300de9Sjwahlig resok_val[i].flavor = si->sc_rpcnum; 12567c478bd9Sstevel@tonic-gate if (resok_val[i].flavor == RPCSEC_GSS) { 12577c478bd9Sstevel@tonic-gate rpcsec_gss_info *info; 12587c478bd9Sstevel@tonic-gate 12597c478bd9Sstevel@tonic-gate info = &resok_val[i].flavor_info; 12601b300de9Sjwahlig info->qop = si->sc_qop; 12611b300de9Sjwahlig info->service = (rpc_gss_svc_t)si->sc_service; 12627c478bd9Sstevel@tonic-gate 12637c478bd9Sstevel@tonic-gate /* get oid opaque data */ 12647c478bd9Sstevel@tonic-gate info->oid.sec_oid4_len = 12651b300de9Sjwahlig si->sc_gss_mech_type->length; 12661b300de9Sjwahlig info->oid.sec_oid4_val = kmem_alloc( 12671b300de9Sjwahlig si->sc_gss_mech_type->length, KM_SLEEP); 12681b300de9Sjwahlig bcopy( 12691b300de9Sjwahlig si->sc_gss_mech_type->elements, 12701b300de9Sjwahlig info->oid.sec_oid4_val, 12711b300de9Sjwahlig info->oid.sec_oid4_len); 12727c478bd9Sstevel@tonic-gate } 12737c478bd9Sstevel@tonic-gate } 12747c478bd9Sstevel@tonic-gate resp->SECINFO4resok_len = count; 12757c478bd9Sstevel@tonic-gate resp->SECINFO4resok_val = resok_val; 12767c478bd9Sstevel@tonic-gate } else { 12777c478bd9Sstevel@tonic-gate int ret_cnt = 0, k = 0; 12787c478bd9Sstevel@tonic-gate int *flavor_list; 12797c478bd9Sstevel@tonic-gate 12807c478bd9Sstevel@tonic-gate count = exi->exi_export.ex_seccnt; /* total sec count */ 12817c478bd9Sstevel@tonic-gate secp = exi->exi_export.ex_secinfo; 12827c478bd9Sstevel@tonic-gate 12837c478bd9Sstevel@tonic-gate flavor_list = kmem_alloc(count * sizeof (int), KM_SLEEP); 12847c478bd9Sstevel@tonic-gate /* find out which flavors to return */ 12857c478bd9Sstevel@tonic-gate for (i = 0; i < count; i ++) { 12867c478bd9Sstevel@tonic-gate int access, flavor, perm; 12877c478bd9Sstevel@tonic-gate 12887c478bd9Sstevel@tonic-gate flavor = secp[i].s_secinfo.sc_nfsnum; 12897c478bd9Sstevel@tonic-gate perm = secp[i].s_flags; 12907c478bd9Sstevel@tonic-gate 12917c478bd9Sstevel@tonic-gate access = nfsauth4_secinfo_access(exi, cs->req, 12925cb0d679SMarcel Telka flavor, perm, cs->basecr); 12937c478bd9Sstevel@tonic-gate 12947c478bd9Sstevel@tonic-gate if (! (access & NFSAUTH_DENIED) && 12957c478bd9Sstevel@tonic-gate ! (access & NFSAUTH_WRONGSEC)) { 12967c478bd9Sstevel@tonic-gate flavor_list[ret_cnt] = flavor; 12977c478bd9Sstevel@tonic-gate ret_cnt++; 12987c478bd9Sstevel@tonic-gate } 12997c478bd9Sstevel@tonic-gate } 13007c478bd9Sstevel@tonic-gate 13017c478bd9Sstevel@tonic-gate /* Create the returning SECINFO value */ 13027c478bd9Sstevel@tonic-gate resok_val = kmem_alloc(ret_cnt * sizeof (secinfo4), KM_SLEEP); 13037c478bd9Sstevel@tonic-gate 13047c478bd9Sstevel@tonic-gate for (i = 0; i < count; i++) { 1305f3b585ceSsamf /* 1306f3b585ceSsamf * If the flavor is in the flavor list, 1307f3b585ceSsamf * fill in resok_val. 1308f3b585ceSsamf */ 13091b300de9Sjwahlig si = &secp[i].s_secinfo; 13101b300de9Sjwahlig if (in_flavor_list(si->sc_nfsnum, 13117c478bd9Sstevel@tonic-gate flavor_list, ret_cnt)) { 13121b300de9Sjwahlig resok_val[k].flavor = si->sc_rpcnum; 13137c478bd9Sstevel@tonic-gate if (resok_val[k].flavor == RPCSEC_GSS) { 13147c478bd9Sstevel@tonic-gate rpcsec_gss_info *info; 13157c478bd9Sstevel@tonic-gate 13167c478bd9Sstevel@tonic-gate info = &resok_val[k].flavor_info; 13171b300de9Sjwahlig info->qop = si->sc_qop; 13181b300de9Sjwahlig info->service = (rpc_gss_svc_t) 13191b300de9Sjwahlig si->sc_service; 13207c478bd9Sstevel@tonic-gate 13217c478bd9Sstevel@tonic-gate /* get oid opaque data */ 13227c478bd9Sstevel@tonic-gate info->oid.sec_oid4_len = 13231b300de9Sjwahlig si->sc_gss_mech_type->length; 13241b300de9Sjwahlig info->oid.sec_oid4_val = kmem_alloc( 13251b300de9Sjwahlig si->sc_gss_mech_type->length, 13267c478bd9Sstevel@tonic-gate KM_SLEEP); 13271b300de9Sjwahlig bcopy(si->sc_gss_mech_type->elements, 13281b300de9Sjwahlig info->oid.sec_oid4_val, 13291b300de9Sjwahlig info->oid.sec_oid4_len); 13307c478bd9Sstevel@tonic-gate } 13317c478bd9Sstevel@tonic-gate k++; 13327c478bd9Sstevel@tonic-gate } 13337c478bd9Sstevel@tonic-gate if (k >= ret_cnt) 13347c478bd9Sstevel@tonic-gate break; 13357c478bd9Sstevel@tonic-gate } 13367c478bd9Sstevel@tonic-gate resp->SECINFO4resok_len = ret_cnt; 13377c478bd9Sstevel@tonic-gate resp->SECINFO4resok_val = resok_val; 13387c478bd9Sstevel@tonic-gate kmem_free(flavor_list, count * sizeof (int)); 13397c478bd9Sstevel@tonic-gate } 13407c478bd9Sstevel@tonic-gate 13417c478bd9Sstevel@tonic-gate VN_RELE(vp); 13427c478bd9Sstevel@tonic-gate return (NFS4_OK); 13437c478bd9Sstevel@tonic-gate } 13447c478bd9Sstevel@tonic-gate 13457c478bd9Sstevel@tonic-gate /* 13467c478bd9Sstevel@tonic-gate * SECINFO (Operation 33): Obtain required security information on 13477c478bd9Sstevel@tonic-gate * the component name in the format of (security-mechanism-oid, qop, service) 13487c478bd9Sstevel@tonic-gate * triplets. 13497c478bd9Sstevel@tonic-gate */ 13507c478bd9Sstevel@tonic-gate /* ARGSUSED */ 13517c478bd9Sstevel@tonic-gate static void 13527c478bd9Sstevel@tonic-gate rfs4_op_secinfo(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req, 13537c478bd9Sstevel@tonic-gate struct compound_state *cs) 13547c478bd9Sstevel@tonic-gate { 1355f3b585ceSsamf SECINFO4args *args = &argop->nfs_argop4_u.opsecinfo; 13567c478bd9Sstevel@tonic-gate SECINFO4res *resp = &resop->nfs_resop4_u.opsecinfo; 1357f3b585ceSsamf utf8string *utfnm = &args->name; 13587c478bd9Sstevel@tonic-gate uint_t len; 13597c478bd9Sstevel@tonic-gate char *nm; 1360b89a8333Snatalie li - Sun Microsystems - Irvine United States struct sockaddr *ca; 1361b89a8333Snatalie li - Sun Microsystems - Irvine United States char *name = NULL; 136215721462SDaniil Lunev nfsstat4 status = NFS4_OK; 13637c478bd9Sstevel@tonic-gate 1364f3b585ceSsamf DTRACE_NFSV4_2(op__secinfo__start, struct compound_state *, cs, 1365f3b585ceSsamf SECINFO4args *, args); 1366f3b585ceSsamf 13677c478bd9Sstevel@tonic-gate /* 13687c478bd9Sstevel@tonic-gate * Current file handle (cfh) should have been set before getting 13697c478bd9Sstevel@tonic-gate * into this function. If not, return error. 13707c478bd9Sstevel@tonic-gate */ 13717c478bd9Sstevel@tonic-gate if (cs->vp == NULL) { 13727c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE; 1373f3b585ceSsamf goto out; 13747c478bd9Sstevel@tonic-gate } 13757c478bd9Sstevel@tonic-gate 13767c478bd9Sstevel@tonic-gate if (cs->vp->v_type != VDIR) { 13777c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_NOTDIR; 1378f3b585ceSsamf goto out; 13797c478bd9Sstevel@tonic-gate } 13807c478bd9Sstevel@tonic-gate 13817c478bd9Sstevel@tonic-gate /* 13827c478bd9Sstevel@tonic-gate * Verify the component name. If failed, error out, but 13837c478bd9Sstevel@tonic-gate * do not error out if the component name is a "..". 13847c478bd9Sstevel@tonic-gate * SECINFO will return its parents secinfo data for SECINFO "..". 13857c478bd9Sstevel@tonic-gate */ 138615721462SDaniil Lunev status = utf8_dir_verify(utfnm); 138715721462SDaniil Lunev if (status != NFS4_OK) { 13887c478bd9Sstevel@tonic-gate if (utfnm->utf8string_len != 2 || 13897c478bd9Sstevel@tonic-gate utfnm->utf8string_val[0] != '.' || 13907c478bd9Sstevel@tonic-gate utfnm->utf8string_val[1] != '.') { 139115721462SDaniil Lunev *cs->statusp = resp->status = status; 1392f3b585ceSsamf goto out; 13937c478bd9Sstevel@tonic-gate } 13947c478bd9Sstevel@tonic-gate } 13957c478bd9Sstevel@tonic-gate 13967c478bd9Sstevel@tonic-gate nm = utf8_to_str(utfnm, &len, NULL); 13977c478bd9Sstevel@tonic-gate if (nm == NULL) { 13987c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_INVAL; 1399f3b585ceSsamf goto out; 14007c478bd9Sstevel@tonic-gate } 14017c478bd9Sstevel@tonic-gate 14027c478bd9Sstevel@tonic-gate if (len > MAXNAMELEN) { 14037c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_NAMETOOLONG; 14047c478bd9Sstevel@tonic-gate kmem_free(nm, len); 1405f3b585ceSsamf goto out; 14067c478bd9Sstevel@tonic-gate } 14077c478bd9Sstevel@tonic-gate 1408b89a8333Snatalie li - Sun Microsystems - Irvine United States ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 1409b89a8333Snatalie li - Sun Microsystems - Irvine United States name = nfscmd_convname(ca, cs->exi, nm, NFSCMD_CONV_INBOUND, 1410b89a8333Snatalie li - Sun Microsystems - Irvine United States MAXPATHLEN + 1); 14117c478bd9Sstevel@tonic-gate 1412b89a8333Snatalie li - Sun Microsystems - Irvine United States if (name == NULL) { 1413b89a8333Snatalie li - Sun Microsystems - Irvine United States *cs->statusp = resp->status = NFS4ERR_INVAL; 1414b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(nm, len); 1415b89a8333Snatalie li - Sun Microsystems - Irvine United States goto out; 1416b89a8333Snatalie li - Sun Microsystems - Irvine United States } 1417b89a8333Snatalie li - Sun Microsystems - Irvine United States 141829c2b691SPatrick Mooney *cs->statusp = resp->status = do_rfs4_op_secinfo(cs, name, resp); 1419a57549b4SVitaliy Gusev 1420*f44e1126SVitaliy Gusev if (resp->status == NFS4_OK && rfs4_has_session(cs)) { 1421*f44e1126SVitaliy Gusev /* 1422*f44e1126SVitaliy Gusev * See rfc 5661 section 2.6.3.1.1.8 and 18.29.3 1423*f44e1126SVitaliy Gusev * 1424*f44e1126SVitaliy Gusev * 2.6.3.1.1.8 1425*f44e1126SVitaliy Gusev * SECINFO and SECINFO_NO_NAME consume the current 1426*f44e1126SVitaliy Gusev * filehandle (note that this is a change from NFSv4.0). 1427*f44e1126SVitaliy Gusev * 1428*f44e1126SVitaliy Gusev * 18.29.3 1429*f44e1126SVitaliy Gusev * On success, the current filehandle is consumed (see 1430*f44e1126SVitaliy Gusev * Section 2.6.3.1.1.8), and if the next operation after 1431*f44e1126SVitaliy Gusev * SECINFO tries to use the current filehandle, that 1432*f44e1126SVitaliy Gusev * operation will fail with the status 1433*f44e1126SVitaliy Gusev * NFS4ERR_NOFILEHANDLE. 1434*f44e1126SVitaliy Gusev */ 1435*f44e1126SVitaliy Gusev VN_RELE(cs->vp); 1436*f44e1126SVitaliy Gusev cs->vp = NULL; 1437*f44e1126SVitaliy Gusev } 1438*f44e1126SVitaliy Gusev 1439b89a8333Snatalie li - Sun Microsystems - Irvine United States if (name != nm) 1440b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(name, MAXPATHLEN + 1); 14417c478bd9Sstevel@tonic-gate kmem_free(nm, len); 1442f3b585ceSsamf 1443f3b585ceSsamf out: 1444f3b585ceSsamf DTRACE_NFSV4_2(op__secinfo__done, struct compound_state *, cs, 1445f3b585ceSsamf SECINFO4res *, resp); 14467c478bd9Sstevel@tonic-gate } 14477c478bd9Sstevel@tonic-gate 14487c478bd9Sstevel@tonic-gate /* 14497c478bd9Sstevel@tonic-gate * Free SECINFO result. 14507c478bd9Sstevel@tonic-gate */ 14517c478bd9Sstevel@tonic-gate /* ARGSUSED */ 14527c478bd9Sstevel@tonic-gate static void 14537c478bd9Sstevel@tonic-gate rfs4_op_secinfo_free(nfs_resop4 *resop) 14547c478bd9Sstevel@tonic-gate { 14557c478bd9Sstevel@tonic-gate SECINFO4res *resp = &resop->nfs_resop4_u.opsecinfo; 14567c478bd9Sstevel@tonic-gate int count, i; 14577c478bd9Sstevel@tonic-gate secinfo4 *resok_val; 14587c478bd9Sstevel@tonic-gate 14597c478bd9Sstevel@tonic-gate /* If this is not an Ok result, nothing to free. */ 14607c478bd9Sstevel@tonic-gate if (resp->status != NFS4_OK) { 14617c478bd9Sstevel@tonic-gate return; 14627c478bd9Sstevel@tonic-gate } 14637c478bd9Sstevel@tonic-gate 14647c478bd9Sstevel@tonic-gate count = resp->SECINFO4resok_len; 14657c478bd9Sstevel@tonic-gate resok_val = resp->SECINFO4resok_val; 14667c478bd9Sstevel@tonic-gate 14677c478bd9Sstevel@tonic-gate for (i = 0; i < count; i++) { 14687c478bd9Sstevel@tonic-gate if (resok_val[i].flavor == RPCSEC_GSS) { 14697c478bd9Sstevel@tonic-gate rpcsec_gss_info *info; 14707c478bd9Sstevel@tonic-gate 14717c478bd9Sstevel@tonic-gate info = &resok_val[i].flavor_info; 14721b300de9Sjwahlig kmem_free(info->oid.sec_oid4_val, 14731b300de9Sjwahlig info->oid.sec_oid4_len); 14747c478bd9Sstevel@tonic-gate } 14757c478bd9Sstevel@tonic-gate } 14767c478bd9Sstevel@tonic-gate kmem_free(resok_val, count * sizeof (secinfo4)); 14777c478bd9Sstevel@tonic-gate resp->SECINFO4resok_len = 0; 14787c478bd9Sstevel@tonic-gate resp->SECINFO4resok_val = NULL; 14797c478bd9Sstevel@tonic-gate } 14807c478bd9Sstevel@tonic-gate 14817c478bd9Sstevel@tonic-gate /* ARGSUSED */ 14827c478bd9Sstevel@tonic-gate static void 14837c478bd9Sstevel@tonic-gate rfs4_op_access(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req, 14847c478bd9Sstevel@tonic-gate struct compound_state *cs) 14857c478bd9Sstevel@tonic-gate { 14867c478bd9Sstevel@tonic-gate ACCESS4args *args = &argop->nfs_argop4_u.opaccess; 14877c478bd9Sstevel@tonic-gate ACCESS4res *resp = &resop->nfs_resop4_u.opaccess; 14887c478bd9Sstevel@tonic-gate int error; 14897c478bd9Sstevel@tonic-gate vnode_t *vp; 14907c478bd9Sstevel@tonic-gate struct vattr va; 14917c478bd9Sstevel@tonic-gate int checkwriteperm; 14927c478bd9Sstevel@tonic-gate cred_t *cr = cs->cr; 149345916cd2Sjpk bslabel_t *clabel, *slabel; 149445916cd2Sjpk ts_label_t *tslabel; 149545916cd2Sjpk boolean_t admin_low_client; 14967c478bd9Sstevel@tonic-gate 1497f3b585ceSsamf DTRACE_NFSV4_2(op__access__start, struct compound_state *, cs, 1498f3b585ceSsamf ACCESS4args *, args); 1499f3b585ceSsamf 15007c478bd9Sstevel@tonic-gate #if 0 /* XXX allow access even if !cs->access. Eventually only pseudo fs */ 15017c478bd9Sstevel@tonic-gate if (cs->access == CS_ACCESS_DENIED) { 15027c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_ACCESS; 1503f3b585ceSsamf goto out; 15047c478bd9Sstevel@tonic-gate } 15057c478bd9Sstevel@tonic-gate #endif 15067c478bd9Sstevel@tonic-gate if (cs->vp == NULL) { 15077c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE; 1508f3b585ceSsamf goto out; 15097c478bd9Sstevel@tonic-gate } 15107c478bd9Sstevel@tonic-gate 15117c478bd9Sstevel@tonic-gate ASSERT(cr != NULL); 15127c478bd9Sstevel@tonic-gate 15137c478bd9Sstevel@tonic-gate vp = cs->vp; 15147c478bd9Sstevel@tonic-gate 15157c478bd9Sstevel@tonic-gate /* 15167c478bd9Sstevel@tonic-gate * If the file system is exported read only, it is not appropriate 15177c478bd9Sstevel@tonic-gate * to check write permissions for regular files and directories. 15187c478bd9Sstevel@tonic-gate * Special files are interpreted by the client, so the underlying 15197c478bd9Sstevel@tonic-gate * permissions are sent back to the client for interpretation. 15207c478bd9Sstevel@tonic-gate */ 15215cb0d679SMarcel Telka if (rdonly4(req, cs) && 15227c478bd9Sstevel@tonic-gate (vp->v_type == VREG || vp->v_type == VDIR)) 15237c478bd9Sstevel@tonic-gate checkwriteperm = 0; 15247c478bd9Sstevel@tonic-gate else 15257c478bd9Sstevel@tonic-gate checkwriteperm = 1; 15267c478bd9Sstevel@tonic-gate 15277c478bd9Sstevel@tonic-gate /* 15287c478bd9Sstevel@tonic-gate * XXX 15297c478bd9Sstevel@tonic-gate * We need the mode so that we can correctly determine access 15307c478bd9Sstevel@tonic-gate * permissions relative to a mandatory lock file. Access to 15317c478bd9Sstevel@tonic-gate * mandatory lock files is denied on the server, so it might 15327c478bd9Sstevel@tonic-gate * as well be reflected to the server during the open. 15337c478bd9Sstevel@tonic-gate */ 15347c478bd9Sstevel@tonic-gate va.va_mask = AT_MODE; 1535da6c28aaSamw error = VOP_GETATTR(vp, &va, 0, cr, NULL); 15367c478bd9Sstevel@tonic-gate if (error) { 15377c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = puterrno4(error); 1538f3b585ceSsamf goto out; 15397c478bd9Sstevel@tonic-gate } 15407c478bd9Sstevel@tonic-gate resp->access = 0; 15417c478bd9Sstevel@tonic-gate resp->supported = 0; 15427c478bd9Sstevel@tonic-gate 154345916cd2Sjpk if (is_system_labeled()) { 154445916cd2Sjpk ASSERT(req->rq_label != NULL); 154545916cd2Sjpk clabel = req->rq_label; 154645916cd2Sjpk DTRACE_PROBE2(tx__rfs4__log__info__opaccess__clabel, char *, 154745916cd2Sjpk "got client label from request(1)", 154845916cd2Sjpk struct svc_req *, req); 154945916cd2Sjpk if (!blequal(&l_admin_low->tsl_label, clabel)) { 1550bd6f1640SJarrett Lu if ((tslabel = nfs_getflabel(vp, cs->exi)) == NULL) { 155145916cd2Sjpk *cs->statusp = resp->status = puterrno4(EACCES); 1552f3b585ceSsamf goto out; 155345916cd2Sjpk } 155445916cd2Sjpk slabel = label2bslabel(tslabel); 155545916cd2Sjpk DTRACE_PROBE3(tx__rfs4__log__info__opaccess__slabel, 155645916cd2Sjpk char *, "got server label(1) for vp(2)", 155745916cd2Sjpk bslabel_t *, slabel, vnode_t *, vp); 155845916cd2Sjpk 155945916cd2Sjpk admin_low_client = B_FALSE; 156045916cd2Sjpk } else 156145916cd2Sjpk admin_low_client = B_TRUE; 156245916cd2Sjpk } 156345916cd2Sjpk 15647c478bd9Sstevel@tonic-gate if (args->access & ACCESS4_READ) { 1565da6c28aaSamw error = VOP_ACCESS(vp, VREAD, 0, cr, NULL); 156645916cd2Sjpk if (!error && !MANDLOCK(vp, va.va_mode) && 156745916cd2Sjpk (!is_system_labeled() || admin_low_client || 156845916cd2Sjpk bldominates(clabel, slabel))) 15697c478bd9Sstevel@tonic-gate resp->access |= ACCESS4_READ; 15707c478bd9Sstevel@tonic-gate resp->supported |= ACCESS4_READ; 15717c478bd9Sstevel@tonic-gate } 15727c478bd9Sstevel@tonic-gate if ((args->access & ACCESS4_LOOKUP) && vp->v_type == VDIR) { 1573da6c28aaSamw error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL); 157445916cd2Sjpk if (!error && (!is_system_labeled() || admin_low_client || 157545916cd2Sjpk bldominates(clabel, slabel))) 15767c478bd9Sstevel@tonic-gate resp->access |= ACCESS4_LOOKUP; 15777c478bd9Sstevel@tonic-gate resp->supported |= ACCESS4_LOOKUP; 15787c478bd9Sstevel@tonic-gate } 15797c478bd9Sstevel@tonic-gate if (checkwriteperm && 15807c478bd9Sstevel@tonic-gate (args->access & (ACCESS4_MODIFY|ACCESS4_EXTEND))) { 1581da6c28aaSamw error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL); 158245916cd2Sjpk if (!error && !MANDLOCK(vp, va.va_mode) && 158345916cd2Sjpk (!is_system_labeled() || admin_low_client || 158445916cd2Sjpk blequal(clabel, slabel))) 15857c478bd9Sstevel@tonic-gate resp->access |= 15867c478bd9Sstevel@tonic-gate (args->access & (ACCESS4_MODIFY | ACCESS4_EXTEND)); 1587e4359d72SDaniil Lunev resp->supported |= 1588e4359d72SDaniil Lunev resp->access & (ACCESS4_MODIFY | ACCESS4_EXTEND); 15897c478bd9Sstevel@tonic-gate } 15907c478bd9Sstevel@tonic-gate 15917c478bd9Sstevel@tonic-gate if (checkwriteperm && 15927c478bd9Sstevel@tonic-gate (args->access & ACCESS4_DELETE) && vp->v_type == VDIR) { 1593da6c28aaSamw error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL); 159445916cd2Sjpk if (!error && (!is_system_labeled() || admin_low_client || 159545916cd2Sjpk blequal(clabel, slabel))) 15967c478bd9Sstevel@tonic-gate resp->access |= ACCESS4_DELETE; 15977c478bd9Sstevel@tonic-gate resp->supported |= ACCESS4_DELETE; 15987c478bd9Sstevel@tonic-gate } 15997c478bd9Sstevel@tonic-gate if (args->access & ACCESS4_EXECUTE && vp->v_type != VDIR) { 1600da6c28aaSamw error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL); 160145916cd2Sjpk if (!error && !MANDLOCK(vp, va.va_mode) && 160245916cd2Sjpk (!is_system_labeled() || admin_low_client || 160345916cd2Sjpk bldominates(clabel, slabel))) 16047c478bd9Sstevel@tonic-gate resp->access |= ACCESS4_EXECUTE; 16057c478bd9Sstevel@tonic-gate resp->supported |= ACCESS4_EXECUTE; 16067c478bd9Sstevel@tonic-gate } 16077c478bd9Sstevel@tonic-gate 160845916cd2Sjpk if (is_system_labeled() && !admin_low_client) 160945916cd2Sjpk label_rele(tslabel); 161045916cd2Sjpk 16117c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4_OK; 1612f3b585ceSsamf out: 1613f3b585ceSsamf DTRACE_NFSV4_2(op__access__done, struct compound_state *, cs, 1614f3b585ceSsamf ACCESS4res *, resp); 16157c478bd9Sstevel@tonic-gate } 16167c478bd9Sstevel@tonic-gate 16177c478bd9Sstevel@tonic-gate /* ARGSUSED */ 16187c478bd9Sstevel@tonic-gate static void 16197c478bd9Sstevel@tonic-gate rfs4_op_commit(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req, 16207c478bd9Sstevel@tonic-gate struct compound_state *cs) 16217c478bd9Sstevel@tonic-gate { 16227c478bd9Sstevel@tonic-gate COMMIT4args *args = &argop->nfs_argop4_u.opcommit; 16237c478bd9Sstevel@tonic-gate COMMIT4res *resp = &resop->nfs_resop4_u.opcommit; 16247c478bd9Sstevel@tonic-gate int error; 16257c478bd9Sstevel@tonic-gate vnode_t *vp = cs->vp; 16267c478bd9Sstevel@tonic-gate cred_t *cr = cs->cr; 16277c478bd9Sstevel@tonic-gate vattr_t va; 16280dfe541eSEvan Layton nfs4_srv_t *nsrv4; 16297c478bd9Sstevel@tonic-gate 1630f3b585ceSsamf DTRACE_NFSV4_2(op__commit__start, struct compound_state *, cs, 1631f3b585ceSsamf COMMIT4args *, args); 1632f3b585ceSsamf 16337c478bd9Sstevel@tonic-gate if (vp == NULL) { 16347c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE; 1635f3b585ceSsamf goto out; 16367c478bd9Sstevel@tonic-gate } 16377c478bd9Sstevel@tonic-gate if (cs->access == CS_ACCESS_DENIED) { 16387c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_ACCESS; 1639f3b585ceSsamf goto out; 16407c478bd9Sstevel@tonic-gate } 16417c478bd9Sstevel@tonic-gate 16427c478bd9Sstevel@tonic-gate if (args->offset + args->count < args->offset) { 16437c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_INVAL; 1644f3b585ceSsamf goto out; 16457c478bd9Sstevel@tonic-gate } 16467c478bd9Sstevel@tonic-gate 16477c478bd9Sstevel@tonic-gate va.va_mask = AT_UID; 1648da6c28aaSamw error = VOP_GETATTR(vp, &va, 0, cr, NULL); 16497c478bd9Sstevel@tonic-gate 16507c478bd9Sstevel@tonic-gate /* 16517c478bd9Sstevel@tonic-gate * If we can't get the attributes, then we can't do the 16527c478bd9Sstevel@tonic-gate * right access checking. So, we'll fail the request. 16537c478bd9Sstevel@tonic-gate */ 16547c478bd9Sstevel@tonic-gate if (error) { 16557c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = puterrno4(error); 1656f3b585ceSsamf goto out; 16577c478bd9Sstevel@tonic-gate } 16585cb0d679SMarcel Telka if (rdonly4(req, cs)) { 16597c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_ROFS; 1660f3b585ceSsamf goto out; 16617c478bd9Sstevel@tonic-gate } 16627c478bd9Sstevel@tonic-gate 16637c478bd9Sstevel@tonic-gate if (vp->v_type != VREG) { 16647c478bd9Sstevel@tonic-gate if (vp->v_type == VDIR) 16657c478bd9Sstevel@tonic-gate resp->status = NFS4ERR_ISDIR; 16667c478bd9Sstevel@tonic-gate else 16677c478bd9Sstevel@tonic-gate resp->status = NFS4ERR_INVAL; 16687c478bd9Sstevel@tonic-gate *cs->statusp = resp->status; 1669f3b585ceSsamf goto out; 16707c478bd9Sstevel@tonic-gate } 16717c478bd9Sstevel@tonic-gate 16727c478bd9Sstevel@tonic-gate if (crgetuid(cr) != va.va_uid && 1673da6c28aaSamw (error = VOP_ACCESS(vp, VWRITE, 0, cs->cr, NULL))) { 16747c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = puterrno4(error); 1675f3b585ceSsamf goto out; 16767c478bd9Sstevel@tonic-gate } 16777c478bd9Sstevel@tonic-gate 1678f63200e6SJeff A. Smith error = VOP_FSYNC(vp, FSYNC, cr, NULL); 16797c478bd9Sstevel@tonic-gate 16807c478bd9Sstevel@tonic-gate if (error) { 16817c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = puterrno4(error); 1682f3b585ceSsamf goto out; 16837c478bd9Sstevel@tonic-gate } 16847c478bd9Sstevel@tonic-gate 16850dfe541eSEvan Layton nsrv4 = nfs4_get_srv(); 16867c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4_OK; 16870dfe541eSEvan Layton resp->writeverf = nsrv4->write4verf; 1688f3b585ceSsamf out: 1689f3b585ceSsamf DTRACE_NFSV4_2(op__commit__done, struct compound_state *, cs, 1690f3b585ceSsamf COMMIT4res *, resp); 16917c478bd9Sstevel@tonic-gate } 16927c478bd9Sstevel@tonic-gate 16937c478bd9Sstevel@tonic-gate /* 16947c478bd9Sstevel@tonic-gate * rfs4_op_mknod is called from rfs4_op_create after all initial verification 16957c478bd9Sstevel@tonic-gate * was completed. It does the nfsv4 create for special files. 16967c478bd9Sstevel@tonic-gate */ 16977c478bd9Sstevel@tonic-gate /* ARGSUSED */ 16987c478bd9Sstevel@tonic-gate static vnode_t * 16997c478bd9Sstevel@tonic-gate do_rfs4_op_mknod(CREATE4args *args, CREATE4res *resp, struct svc_req *req, 17007c478bd9Sstevel@tonic-gate struct compound_state *cs, vattr_t *vap, char *nm) 17017c478bd9Sstevel@tonic-gate { 17027c478bd9Sstevel@tonic-gate int error; 17037c478bd9Sstevel@tonic-gate cred_t *cr = cs->cr; 17047c478bd9Sstevel@tonic-gate vnode_t *dvp = cs->vp; 17057c478bd9Sstevel@tonic-gate vnode_t *vp = NULL; 17067c478bd9Sstevel@tonic-gate int mode; 17077c478bd9Sstevel@tonic-gate enum vcexcl excl; 17087c478bd9Sstevel@tonic-gate 17097c478bd9Sstevel@tonic-gate switch (args->type) { 17107c478bd9Sstevel@tonic-gate case NF4CHR: 17117c478bd9Sstevel@tonic-gate case NF4BLK: 17127c478bd9Sstevel@tonic-gate if (secpolicy_sys_devices(cr) != 0) { 17137c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_PERM; 17147c478bd9Sstevel@tonic-gate return (NULL); 17157c478bd9Sstevel@tonic-gate } 17167c478bd9Sstevel@tonic-gate if (args->type == NF4CHR) 17177c478bd9Sstevel@tonic-gate vap->va_type = VCHR; 17187c478bd9Sstevel@tonic-gate else 17197c478bd9Sstevel@tonic-gate vap->va_type = VBLK; 17207c478bd9Sstevel@tonic-gate vap->va_rdev = makedevice(args->ftype4_u.devdata.specdata1, 17217c478bd9Sstevel@tonic-gate args->ftype4_u.devdata.specdata2); 17227c478bd9Sstevel@tonic-gate vap->va_mask |= AT_RDEV; 17237c478bd9Sstevel@tonic-gate break; 17247c478bd9Sstevel@tonic-gate case NF4SOCK: 17257c478bd9Sstevel@tonic-gate vap->va_type = VSOCK; 17267c478bd9Sstevel@tonic-gate break; 17277c478bd9Sstevel@tonic-gate case NF4FIFO: 17287c478bd9Sstevel@tonic-gate vap->va_type = VFIFO; 17297c478bd9Sstevel@tonic-gate break; 17307c478bd9Sstevel@tonic-gate default: 17317c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_BADTYPE; 17327c478bd9Sstevel@tonic-gate return (NULL); 17337c478bd9Sstevel@tonic-gate } 17347c478bd9Sstevel@tonic-gate 17357c478bd9Sstevel@tonic-gate /* 17367c478bd9Sstevel@tonic-gate * Must specify the mode. 17377c478bd9Sstevel@tonic-gate */ 17387c478bd9Sstevel@tonic-gate if (!(vap->va_mask & AT_MODE)) { 17397c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_INVAL; 17407c478bd9Sstevel@tonic-gate return (NULL); 17417c478bd9Sstevel@tonic-gate } 17427c478bd9Sstevel@tonic-gate 17437c478bd9Sstevel@tonic-gate excl = EXCL; 17447c478bd9Sstevel@tonic-gate 17457c478bd9Sstevel@tonic-gate mode = 0; 17467c478bd9Sstevel@tonic-gate 1747da6c28aaSamw error = VOP_CREATE(dvp, nm, vap, excl, mode, &vp, cr, 0, NULL, NULL); 17487c478bd9Sstevel@tonic-gate if (error) { 17497c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = puterrno4(error); 17507c478bd9Sstevel@tonic-gate return (NULL); 17517c478bd9Sstevel@tonic-gate } 17527c478bd9Sstevel@tonic-gate return (vp); 17537c478bd9Sstevel@tonic-gate } 17547c478bd9Sstevel@tonic-gate 17557c478bd9Sstevel@tonic-gate /* 17567c478bd9Sstevel@tonic-gate * nfsv4 create is used to create non-regular files. For regular files, 17577c478bd9Sstevel@tonic-gate * use nfsv4 open. 17587c478bd9Sstevel@tonic-gate */ 17597c478bd9Sstevel@tonic-gate /* ARGSUSED */ 17607c478bd9Sstevel@tonic-gate static void 17617c478bd9Sstevel@tonic-gate rfs4_op_create(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req, 17627c478bd9Sstevel@tonic-gate struct compound_state *cs) 17637c478bd9Sstevel@tonic-gate { 17647c478bd9Sstevel@tonic-gate CREATE4args *args = &argop->nfs_argop4_u.opcreate; 17657c478bd9Sstevel@tonic-gate CREATE4res *resp = &resop->nfs_resop4_u.opcreate; 17667c478bd9Sstevel@tonic-gate int error; 17677c478bd9Sstevel@tonic-gate struct vattr bva, iva, iva2, ava, *vap; 17687c478bd9Sstevel@tonic-gate cred_t *cr = cs->cr; 17697c478bd9Sstevel@tonic-gate vnode_t *dvp = cs->vp; 17707c478bd9Sstevel@tonic-gate vnode_t *vp = NULL; 1771fd7da618Sgt29601 vnode_t *realvp; 17727c478bd9Sstevel@tonic-gate char *nm, *lnm; 17737c478bd9Sstevel@tonic-gate uint_t len, llen; 17747c478bd9Sstevel@tonic-gate int syncval = 0; 17757c478bd9Sstevel@tonic-gate struct nfs4_svgetit_arg sarg; 17767c478bd9Sstevel@tonic-gate struct nfs4_ntov_table ntov; 17777c478bd9Sstevel@tonic-gate struct statvfs64 sb; 17787c478bd9Sstevel@tonic-gate nfsstat4 status; 1779b89a8333Snatalie li - Sun Microsystems - Irvine United States struct sockaddr *ca; 1780b89a8333Snatalie li - Sun Microsystems - Irvine United States char *name = NULL; 1781b89a8333Snatalie li - Sun Microsystems - Irvine United States char *lname = NULL; 17827c478bd9Sstevel@tonic-gate 1783f3b585ceSsamf DTRACE_NFSV4_2(op__create__start, struct compound_state *, cs, 1784f3b585ceSsamf CREATE4args *, args); 1785f3b585ceSsamf 17867c478bd9Sstevel@tonic-gate resp->attrset = 0; 17877c478bd9Sstevel@tonic-gate 17887c478bd9Sstevel@tonic-gate if (dvp == NULL) { 17897c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE; 1790f3b585ceSsamf goto out; 17917c478bd9Sstevel@tonic-gate } 17927c478bd9Sstevel@tonic-gate 17937c478bd9Sstevel@tonic-gate /* 17947c478bd9Sstevel@tonic-gate * If there is an unshared filesystem mounted on this vnode, 17957c478bd9Sstevel@tonic-gate * do not allow to create an object in this directory. 17967c478bd9Sstevel@tonic-gate */ 17977c478bd9Sstevel@tonic-gate if (vn_ismntpt(dvp)) { 17987c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_ACCESS; 1799f3b585ceSsamf goto out; 18007c478bd9Sstevel@tonic-gate } 18017c478bd9Sstevel@tonic-gate 18027c478bd9Sstevel@tonic-gate /* Verify that type is correct */ 18037c478bd9Sstevel@tonic-gate switch (args->type) { 18047c478bd9Sstevel@tonic-gate case NF4LNK: 18057c478bd9Sstevel@tonic-gate case NF4BLK: 18067c478bd9Sstevel@tonic-gate case NF4CHR: 18077c478bd9Sstevel@tonic-gate case NF4SOCK: 18087c478bd9Sstevel@tonic-gate case NF4FIFO: 18097c478bd9Sstevel@tonic-gate case NF4DIR: 18107c478bd9Sstevel@tonic-gate break; 18117c478bd9Sstevel@tonic-gate default: 18127c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_BADTYPE; 1813f3b585ceSsamf goto out; 18147c478bd9Sstevel@tonic-gate }; 18157c478bd9Sstevel@tonic-gate 18167c478bd9Sstevel@tonic-gate if (cs->access == CS_ACCESS_DENIED) { 18177c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_ACCESS; 1818f3b585ceSsamf goto out; 18197c478bd9Sstevel@tonic-gate } 18207c478bd9Sstevel@tonic-gate if (dvp->v_type != VDIR) { 18217c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_NOTDIR; 1822f3b585ceSsamf goto out; 18237c478bd9Sstevel@tonic-gate } 182415721462SDaniil Lunev status = utf8_dir_verify(&args->objname); 182515721462SDaniil Lunev if (status != NFS4_OK) { 182615721462SDaniil Lunev *cs->statusp = resp->status = status; 1827f3b585ceSsamf goto out; 18287c478bd9Sstevel@tonic-gate } 18297c478bd9Sstevel@tonic-gate 18305cb0d679SMarcel Telka if (rdonly4(req, cs)) { 18317c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_ROFS; 1832f3b585ceSsamf goto out; 18337c478bd9Sstevel@tonic-gate } 18347c478bd9Sstevel@tonic-gate 18357c478bd9Sstevel@tonic-gate /* 18367c478bd9Sstevel@tonic-gate * Name of newly created object 18377c478bd9Sstevel@tonic-gate */ 18387c478bd9Sstevel@tonic-gate nm = utf8_to_fn(&args->objname, &len, NULL); 18397c478bd9Sstevel@tonic-gate if (nm == NULL) { 18407c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_INVAL; 1841f3b585ceSsamf goto out; 18427c478bd9Sstevel@tonic-gate } 18437c478bd9Sstevel@tonic-gate 18447c478bd9Sstevel@tonic-gate if (len > MAXNAMELEN) { 18457c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_NAMETOOLONG; 18467c478bd9Sstevel@tonic-gate kmem_free(nm, len); 1847f3b585ceSsamf goto out; 18487c478bd9Sstevel@tonic-gate } 18497c478bd9Sstevel@tonic-gate 1850b89a8333Snatalie li - Sun Microsystems - Irvine United States ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 1851b89a8333Snatalie li - Sun Microsystems - Irvine United States name = nfscmd_convname(ca, cs->exi, nm, NFSCMD_CONV_INBOUND, 1852b89a8333Snatalie li - Sun Microsystems - Irvine United States MAXPATHLEN + 1); 1853b89a8333Snatalie li - Sun Microsystems - Irvine United States 1854b89a8333Snatalie li - Sun Microsystems - Irvine United States if (name == NULL) { 1855b89a8333Snatalie li - Sun Microsystems - Irvine United States *cs->statusp = resp->status = NFS4ERR_INVAL; 1856b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(nm, len); 1857b89a8333Snatalie li - Sun Microsystems - Irvine United States goto out; 1858b89a8333Snatalie li - Sun Microsystems - Irvine United States } 1859b89a8333Snatalie li - Sun Microsystems - Irvine United States 18607c478bd9Sstevel@tonic-gate resp->attrset = 0; 18617c478bd9Sstevel@tonic-gate 18627c478bd9Sstevel@tonic-gate sarg.sbp = &sb; 18632f172c55SRobert Thurlow sarg.is_referral = B_FALSE; 18647c478bd9Sstevel@tonic-gate nfs4_ntov_table_init(&ntov); 18657c478bd9Sstevel@tonic-gate 18667c478bd9Sstevel@tonic-gate status = do_rfs4_set_attrs(&resp->attrset, 18671b300de9Sjwahlig &args->createattrs, cs, &sarg, &ntov, NFS4ATTR_SETIT); 18687c478bd9Sstevel@tonic-gate 18697c478bd9Sstevel@tonic-gate if (sarg.vap->va_mask == 0 && status == NFS4_OK) 18707c478bd9Sstevel@tonic-gate status = NFS4ERR_INVAL; 18717c478bd9Sstevel@tonic-gate 18727c478bd9Sstevel@tonic-gate if (status != NFS4_OK) { 18737c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = status; 187459fb210bSJan Kryl if (name != nm) 187559fb210bSJan Kryl kmem_free(name, MAXPATHLEN + 1); 18767c478bd9Sstevel@tonic-gate kmem_free(nm, len); 18777c478bd9Sstevel@tonic-gate nfs4_ntov_table_free(&ntov, &sarg); 18787c478bd9Sstevel@tonic-gate resp->attrset = 0; 1879f3b585ceSsamf goto out; 18807c478bd9Sstevel@tonic-gate } 18817c478bd9Sstevel@tonic-gate 18827c478bd9Sstevel@tonic-gate /* Get "before" change value */ 1883e3c57d6aSGerald Thornbrugh bva.va_mask = AT_CTIME|AT_SEQ|AT_MODE; 1884da6c28aaSamw error = VOP_GETATTR(dvp, &bva, 0, cr, NULL); 18857c478bd9Sstevel@tonic-gate if (error) { 18867c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = puterrno4(error); 188759fb210bSJan Kryl if (name != nm) 188859fb210bSJan Kryl kmem_free(name, MAXPATHLEN + 1); 18897c478bd9Sstevel@tonic-gate kmem_free(nm, len); 18907c478bd9Sstevel@tonic-gate nfs4_ntov_table_free(&ntov, &sarg); 18917c478bd9Sstevel@tonic-gate resp->attrset = 0; 1892f3b585ceSsamf goto out; 18937c478bd9Sstevel@tonic-gate } 18947c478bd9Sstevel@tonic-gate NFS4_SET_FATTR4_CHANGE(resp->cinfo.before, bva.va_ctime) 18957c478bd9Sstevel@tonic-gate 18967c478bd9Sstevel@tonic-gate vap = sarg.vap; 18977c478bd9Sstevel@tonic-gate 18987c478bd9Sstevel@tonic-gate /* 1899e3c57d6aSGerald Thornbrugh * Set the default initial values for attributes when the parent 1900e3c57d6aSGerald Thornbrugh * directory does not have the VSUID/VSGID bit set and they have 1901e3c57d6aSGerald Thornbrugh * not been specified in createattrs. 19027c478bd9Sstevel@tonic-gate */ 1903e3c57d6aSGerald Thornbrugh if (!(bva.va_mode & VSUID) && (vap->va_mask & AT_UID) == 0) { 19047c478bd9Sstevel@tonic-gate vap->va_uid = crgetuid(cr); 19057c478bd9Sstevel@tonic-gate vap->va_mask |= AT_UID; 19067c478bd9Sstevel@tonic-gate } 1907e3c57d6aSGerald Thornbrugh if (!(bva.va_mode & VSGID) && (vap->va_mask & AT_GID) == 0) { 19087c478bd9Sstevel@tonic-gate vap->va_gid = crgetgid(cr); 19097c478bd9Sstevel@tonic-gate vap->va_mask |= AT_GID; 19107c478bd9Sstevel@tonic-gate } 19117c478bd9Sstevel@tonic-gate 19127c478bd9Sstevel@tonic-gate vap->va_mask |= AT_TYPE; 19137c478bd9Sstevel@tonic-gate switch (args->type) { 19147c478bd9Sstevel@tonic-gate case NF4DIR: 19157c478bd9Sstevel@tonic-gate vap->va_type = VDIR; 19167c478bd9Sstevel@tonic-gate if ((vap->va_mask & AT_MODE) == 0) { 19177c478bd9Sstevel@tonic-gate vap->va_mode = 0700; /* default: owner rwx only */ 19187c478bd9Sstevel@tonic-gate vap->va_mask |= AT_MODE; 19197c478bd9Sstevel@tonic-gate } 192059fb210bSJan Kryl error = VOP_MKDIR(dvp, name, vap, &vp, cr, NULL, 0, NULL); 19217c478bd9Sstevel@tonic-gate if (error) 19227c478bd9Sstevel@tonic-gate break; 19237c478bd9Sstevel@tonic-gate 19247c478bd9Sstevel@tonic-gate /* 19257c478bd9Sstevel@tonic-gate * Get the initial "after" sequence number, if it fails, 19267c478bd9Sstevel@tonic-gate * set to zero 19277c478bd9Sstevel@tonic-gate */ 19287c478bd9Sstevel@tonic-gate iva.va_mask = AT_SEQ; 1929da6c28aaSamw if (VOP_GETATTR(dvp, &iva, 0, cs->cr, NULL)) 19307c478bd9Sstevel@tonic-gate iva.va_seq = 0; 19317c478bd9Sstevel@tonic-gate break; 19327c478bd9Sstevel@tonic-gate case NF4LNK: 19337c478bd9Sstevel@tonic-gate vap->va_type = VLNK; 19347c478bd9Sstevel@tonic-gate if ((vap->va_mask & AT_MODE) == 0) { 19357c478bd9Sstevel@tonic-gate vap->va_mode = 0700; /* default: owner rwx only */ 19367c478bd9Sstevel@tonic-gate vap->va_mask |= AT_MODE; 19377c478bd9Sstevel@tonic-gate } 19387c478bd9Sstevel@tonic-gate 19397c478bd9Sstevel@tonic-gate /* 19407c478bd9Sstevel@tonic-gate * symlink names must be treated as data 19417c478bd9Sstevel@tonic-gate */ 1942bbe876c0SMarcel Telka lnm = utf8_to_str((utf8string *)&args->ftype4_u.linkdata, 1943bbe876c0SMarcel Telka &llen, NULL); 19447c478bd9Sstevel@tonic-gate 19457c478bd9Sstevel@tonic-gate if (lnm == NULL) { 19467c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_INVAL; 1947b89a8333Snatalie li - Sun Microsystems - Irvine United States if (name != nm) 1948b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(name, MAXPATHLEN + 1); 19497c478bd9Sstevel@tonic-gate kmem_free(nm, len); 19507c478bd9Sstevel@tonic-gate nfs4_ntov_table_free(&ntov, &sarg); 19517c478bd9Sstevel@tonic-gate resp->attrset = 0; 1952f3b585ceSsamf goto out; 19537c478bd9Sstevel@tonic-gate } 19547c478bd9Sstevel@tonic-gate 19557c478bd9Sstevel@tonic-gate if (llen > MAXPATHLEN) { 19567c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_NAMETOOLONG; 1957b89a8333Snatalie li - Sun Microsystems - Irvine United States if (name != nm) 1958b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(name, MAXPATHLEN + 1); 1959b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(nm, len); 1960b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(lnm, llen); 1961b89a8333Snatalie li - Sun Microsystems - Irvine United States nfs4_ntov_table_free(&ntov, &sarg); 1962b89a8333Snatalie li - Sun Microsystems - Irvine United States resp->attrset = 0; 1963b89a8333Snatalie li - Sun Microsystems - Irvine United States goto out; 1964b89a8333Snatalie li - Sun Microsystems - Irvine United States } 1965b89a8333Snatalie li - Sun Microsystems - Irvine United States 1966b89a8333Snatalie li - Sun Microsystems - Irvine United States lname = nfscmd_convname(ca, cs->exi, lnm, 1967b89a8333Snatalie li - Sun Microsystems - Irvine United States NFSCMD_CONV_INBOUND, MAXPATHLEN + 1); 1968b89a8333Snatalie li - Sun Microsystems - Irvine United States 1969b89a8333Snatalie li - Sun Microsystems - Irvine United States if (lname == NULL) { 1970b89a8333Snatalie li - Sun Microsystems - Irvine United States *cs->statusp = resp->status = NFS4ERR_SERVERFAULT; 1971b89a8333Snatalie li - Sun Microsystems - Irvine United States if (name != nm) 1972b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(name, MAXPATHLEN + 1); 19737c478bd9Sstevel@tonic-gate kmem_free(nm, len); 19747c478bd9Sstevel@tonic-gate kmem_free(lnm, llen); 19757c478bd9Sstevel@tonic-gate nfs4_ntov_table_free(&ntov, &sarg); 19767c478bd9Sstevel@tonic-gate resp->attrset = 0; 1977f3b585ceSsamf goto out; 19787c478bd9Sstevel@tonic-gate } 19797c478bd9Sstevel@tonic-gate 198059fb210bSJan Kryl error = VOP_SYMLINK(dvp, name, vap, lname, cr, NULL, 0); 1981b89a8333Snatalie li - Sun Microsystems - Irvine United States if (lname != lnm) 1982b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(lname, MAXPATHLEN + 1); 19837c478bd9Sstevel@tonic-gate kmem_free(lnm, llen); 19847c478bd9Sstevel@tonic-gate if (error) 19857c478bd9Sstevel@tonic-gate break; 19867c478bd9Sstevel@tonic-gate 19877c478bd9Sstevel@tonic-gate /* 19887c478bd9Sstevel@tonic-gate * Get the initial "after" sequence number, if it fails, 19897c478bd9Sstevel@tonic-gate * set to zero 19907c478bd9Sstevel@tonic-gate */ 19917c478bd9Sstevel@tonic-gate iva.va_mask = AT_SEQ; 1992da6c28aaSamw if (VOP_GETATTR(dvp, &iva, 0, cs->cr, NULL)) 19937c478bd9Sstevel@tonic-gate iva.va_seq = 0; 19947c478bd9Sstevel@tonic-gate 199559fb210bSJan Kryl error = VOP_LOOKUP(dvp, name, &vp, NULL, 0, NULL, cr, 1996da6c28aaSamw NULL, NULL, NULL); 19977c478bd9Sstevel@tonic-gate if (error) 19987c478bd9Sstevel@tonic-gate break; 19997c478bd9Sstevel@tonic-gate 20007c478bd9Sstevel@tonic-gate /* 20017c478bd9Sstevel@tonic-gate * va_seq is not safe over VOP calls, check it again 20027c478bd9Sstevel@tonic-gate * if it has changed zero out iva to force atomic = FALSE. 20037c478bd9Sstevel@tonic-gate */ 20047c478bd9Sstevel@tonic-gate iva2.va_mask = AT_SEQ; 2005da6c28aaSamw if (VOP_GETATTR(dvp, &iva2, 0, cs->cr, NULL) || 20067c478bd9Sstevel@tonic-gate iva2.va_seq != iva.va_seq) 20077c478bd9Sstevel@tonic-gate iva.va_seq = 0; 20087c478bd9Sstevel@tonic-gate break; 20097c478bd9Sstevel@tonic-gate default: 20107c478bd9Sstevel@tonic-gate /* 20117c478bd9Sstevel@tonic-gate * probably a special file. 20127c478bd9Sstevel@tonic-gate */ 20137c478bd9Sstevel@tonic-gate if ((vap->va_mask & AT_MODE) == 0) { 20147c478bd9Sstevel@tonic-gate vap->va_mode = 0600; /* default: owner rw only */ 20157c478bd9Sstevel@tonic-gate vap->va_mask |= AT_MODE; 20167c478bd9Sstevel@tonic-gate } 20177c478bd9Sstevel@tonic-gate syncval = FNODSYNC; 20187c478bd9Sstevel@tonic-gate /* 20197c478bd9Sstevel@tonic-gate * We know this will only generate one VOP call 20207c478bd9Sstevel@tonic-gate */ 202159fb210bSJan Kryl vp = do_rfs4_op_mknod(args, resp, req, cs, vap, name); 20227c478bd9Sstevel@tonic-gate 20237c478bd9Sstevel@tonic-gate if (vp == NULL) { 2024b89a8333Snatalie li - Sun Microsystems - Irvine United States if (name != nm) 2025b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(name, MAXPATHLEN + 1); 20267c478bd9Sstevel@tonic-gate kmem_free(nm, len); 20277c478bd9Sstevel@tonic-gate nfs4_ntov_table_free(&ntov, &sarg); 20287c478bd9Sstevel@tonic-gate resp->attrset = 0; 2029f3b585ceSsamf goto out; 20307c478bd9Sstevel@tonic-gate } 20317c478bd9Sstevel@tonic-gate 20327c478bd9Sstevel@tonic-gate /* 20337c478bd9Sstevel@tonic-gate * Get the initial "after" sequence number, if it fails, 20347c478bd9Sstevel@tonic-gate * set to zero 20357c478bd9Sstevel@tonic-gate */ 20367c478bd9Sstevel@tonic-gate iva.va_mask = AT_SEQ; 2037da6c28aaSamw if (VOP_GETATTR(dvp, &iva, 0, cs->cr, NULL)) 20387c478bd9Sstevel@tonic-gate iva.va_seq = 0; 20397c478bd9Sstevel@tonic-gate 20407c478bd9Sstevel@tonic-gate break; 20417c478bd9Sstevel@tonic-gate } 2042b89a8333Snatalie li - Sun Microsystems - Irvine United States if (name != nm) 2043b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(name, MAXPATHLEN + 1); 20447c478bd9Sstevel@tonic-gate kmem_free(nm, len); 20457c478bd9Sstevel@tonic-gate 20467c478bd9Sstevel@tonic-gate if (error) { 20477c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = puterrno4(error); 20487c478bd9Sstevel@tonic-gate } 20497c478bd9Sstevel@tonic-gate 20507c478bd9Sstevel@tonic-gate /* 20517c478bd9Sstevel@tonic-gate * Force modified data and metadata out to stable storage. 20527c478bd9Sstevel@tonic-gate */ 2053da6c28aaSamw (void) VOP_FSYNC(dvp, 0, cr, NULL); 20547c478bd9Sstevel@tonic-gate 20557c478bd9Sstevel@tonic-gate if (resp->status != NFS4_OK) { 20567c478bd9Sstevel@tonic-gate if (vp != NULL) 20577c478bd9Sstevel@tonic-gate VN_RELE(vp); 20587c478bd9Sstevel@tonic-gate nfs4_ntov_table_free(&ntov, &sarg); 20597c478bd9Sstevel@tonic-gate resp->attrset = 0; 2060f3b585ceSsamf goto out; 20617c478bd9Sstevel@tonic-gate } 20627c478bd9Sstevel@tonic-gate 20637c478bd9Sstevel@tonic-gate /* 20647c478bd9Sstevel@tonic-gate * Finish setup of cinfo response, "before" value already set. 20657c478bd9Sstevel@tonic-gate * Get "after" change value, if it fails, simply return the 20667c478bd9Sstevel@tonic-gate * before value. 20677c478bd9Sstevel@tonic-gate */ 20687c478bd9Sstevel@tonic-gate ava.va_mask = AT_CTIME|AT_SEQ; 2069da6c28aaSamw if (VOP_GETATTR(dvp, &ava, 0, cr, NULL)) { 20707c478bd9Sstevel@tonic-gate ava.va_ctime = bva.va_ctime; 20717c478bd9Sstevel@tonic-gate ava.va_seq = 0; 20727c478bd9Sstevel@tonic-gate } 20737c478bd9Sstevel@tonic-gate NFS4_SET_FATTR4_CHANGE(resp->cinfo.after, ava.va_ctime); 20747c478bd9Sstevel@tonic-gate 20757c478bd9Sstevel@tonic-gate /* 20767c478bd9Sstevel@tonic-gate * True verification that object was created with correct 20777c478bd9Sstevel@tonic-gate * attrs is impossible. The attrs could have been changed 20787c478bd9Sstevel@tonic-gate * immediately after object creation. If attributes did 20797c478bd9Sstevel@tonic-gate * not verify, the only recourse for the server is to 20807c478bd9Sstevel@tonic-gate * destroy the object. Maybe if some attrs (like gid) 20817c478bd9Sstevel@tonic-gate * are set incorrectly, the object should be destroyed; 20827c478bd9Sstevel@tonic-gate * however, seems bad as a default policy. Do we really 20837c478bd9Sstevel@tonic-gate * want to destroy an object over one of the times not 20847c478bd9Sstevel@tonic-gate * verifying correctly? For these reasons, the server 20857c478bd9Sstevel@tonic-gate * currently sets bits in attrset for createattrs 20867c478bd9Sstevel@tonic-gate * that were set; however, no verification is done. 20877c478bd9Sstevel@tonic-gate * 20887c478bd9Sstevel@tonic-gate * vmask_to_nmask accounts for vattr bits set on create 20897c478bd9Sstevel@tonic-gate * [do_rfs4_set_attrs() only sets resp bits for 20907c478bd9Sstevel@tonic-gate * non-vattr/vfs bits.] 20917c478bd9Sstevel@tonic-gate * Mask off any bits set by default so as not to return 20927c478bd9Sstevel@tonic-gate * more attrset bits than were requested in createattrs 20937c478bd9Sstevel@tonic-gate */ 20947c478bd9Sstevel@tonic-gate nfs4_vmask_to_nmask(sarg.vap->va_mask, &resp->attrset); 20957c478bd9Sstevel@tonic-gate resp->attrset &= args->createattrs.attrmask; 20967c478bd9Sstevel@tonic-gate nfs4_ntov_table_free(&ntov, &sarg); 20977c478bd9Sstevel@tonic-gate 20987c478bd9Sstevel@tonic-gate error = makefh4(&cs->fh, vp, cs->exi); 20997c478bd9Sstevel@tonic-gate if (error) { 21007c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = puterrno4(error); 21017c478bd9Sstevel@tonic-gate } 21027c478bd9Sstevel@tonic-gate 21037c478bd9Sstevel@tonic-gate /* 21047c478bd9Sstevel@tonic-gate * The cinfo.atomic = TRUE only if we got no errors, we have 21057c478bd9Sstevel@tonic-gate * non-zero va_seq's, and it has incremented by exactly one 21067c478bd9Sstevel@tonic-gate * during the creation and it didn't change during the VOP_LOOKUP 21077c478bd9Sstevel@tonic-gate * or VOP_FSYNC. 21087c478bd9Sstevel@tonic-gate */ 21097c478bd9Sstevel@tonic-gate if (!error && bva.va_seq && iva.va_seq && ava.va_seq && 21101b300de9Sjwahlig iva.va_seq == (bva.va_seq + 1) && iva.va_seq == ava.va_seq) 21117c478bd9Sstevel@tonic-gate resp->cinfo.atomic = TRUE; 21127c478bd9Sstevel@tonic-gate else 21137c478bd9Sstevel@tonic-gate resp->cinfo.atomic = FALSE; 21147c478bd9Sstevel@tonic-gate 2115fd7da618Sgt29601 /* 2116fd7da618Sgt29601 * Force modified metadata out to stable storage. 2117fd7da618Sgt29601 * 2118fd7da618Sgt29601 * if a underlying vp exists, pass it to VOP_FSYNC 2119fd7da618Sgt29601 */ 2120fd7da618Sgt29601 if (VOP_REALVP(vp, &realvp, NULL) == 0) 2121fd7da618Sgt29601 (void) VOP_FSYNC(realvp, syncval, cr, NULL); 2122fd7da618Sgt29601 else 2123da6c28aaSamw (void) VOP_FSYNC(vp, syncval, cr, NULL); 21247c478bd9Sstevel@tonic-gate 21257c478bd9Sstevel@tonic-gate if (resp->status != NFS4_OK) { 21267c478bd9Sstevel@tonic-gate VN_RELE(vp); 2127f3b585ceSsamf goto out; 21287c478bd9Sstevel@tonic-gate } 21297c478bd9Sstevel@tonic-gate if (cs->vp) 21307c478bd9Sstevel@tonic-gate VN_RELE(cs->vp); 21317c478bd9Sstevel@tonic-gate 21327c478bd9Sstevel@tonic-gate cs->vp = vp; 21337c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4_OK; 2134f3b585ceSsamf out: 2135f3b585ceSsamf DTRACE_NFSV4_2(op__create__done, struct compound_state *, cs, 2136f3b585ceSsamf CREATE4res *, resp); 21377c478bd9Sstevel@tonic-gate } 21387c478bd9Sstevel@tonic-gate 2139f3b585ceSsamf /*ARGSUSED*/ 2140f3b585ceSsamf static void 2141f3b585ceSsamf rfs4_op_delegpurge(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req, 2142f3b585ceSsamf struct compound_state *cs) 2143f3b585ceSsamf { 2144f3b585ceSsamf DTRACE_NFSV4_2(op__delegpurge__start, struct compound_state *, cs, 2145f3b585ceSsamf DELEGPURGE4args *, &argop->nfs_argop4_u.opdelegpurge); 2146f3b585ceSsamf 2147f3b585ceSsamf rfs4_op_inval(argop, resop, req, cs); 2148f3b585ceSsamf 2149f3b585ceSsamf DTRACE_NFSV4_2(op__delegpurge__done, struct compound_state *, cs, 2150f3b585ceSsamf DELEGPURGE4res *, &resop->nfs_resop4_u.opdelegpurge); 2151f3b585ceSsamf } 21527c478bd9Sstevel@tonic-gate 21537c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 21547c478bd9Sstevel@tonic-gate static void 21557c478bd9Sstevel@tonic-gate rfs4_op_delegreturn(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req, 21567c478bd9Sstevel@tonic-gate struct compound_state *cs) 21577c478bd9Sstevel@tonic-gate { 21587c478bd9Sstevel@tonic-gate DELEGRETURN4args *args = &argop->nfs_argop4_u.opdelegreturn; 21597c478bd9Sstevel@tonic-gate DELEGRETURN4res *resp = &resop->nfs_resop4_u.opdelegreturn; 21607c478bd9Sstevel@tonic-gate rfs4_deleg_state_t *dsp; 21617c478bd9Sstevel@tonic-gate nfsstat4 status; 21627c478bd9Sstevel@tonic-gate 2163f3b585ceSsamf DTRACE_NFSV4_2(op__delegreturn__start, struct compound_state *, cs, 2164f3b585ceSsamf DELEGRETURN4args *, args); 2165f3b585ceSsamf 21667c478bd9Sstevel@tonic-gate status = rfs4_get_deleg_state(&args->deleg_stateid, &dsp); 21677c478bd9Sstevel@tonic-gate resp->status = *cs->statusp = status; 21687c478bd9Sstevel@tonic-gate if (status != NFS4_OK) 2169f3b585ceSsamf goto out; 21707c478bd9Sstevel@tonic-gate 21717c478bd9Sstevel@tonic-gate /* Ensure specified filehandle matches */ 2172d216dff5SRobert Mastors if (cs->vp != dsp->rds_finfo->rf_vp) { 21737c478bd9Sstevel@tonic-gate resp->status = *cs->statusp = NFS4ERR_BAD_STATEID; 21747c478bd9Sstevel@tonic-gate } else 21757c478bd9Sstevel@tonic-gate rfs4_return_deleg(dsp, FALSE); 21767c478bd9Sstevel@tonic-gate 2177d216dff5SRobert Mastors rfs4_update_lease(dsp->rds_client); 21787c478bd9Sstevel@tonic-gate 21797c478bd9Sstevel@tonic-gate rfs4_deleg_state_rele(dsp); 2180f3b585ceSsamf out: 2181f3b585ceSsamf DTRACE_NFSV4_2(op__delegreturn__done, struct compound_state *, cs, 2182f3b585ceSsamf DELEGRETURN4res *, resp); 21837c478bd9Sstevel@tonic-gate } 21847c478bd9Sstevel@tonic-gate 21857c478bd9Sstevel@tonic-gate /* 21867c478bd9Sstevel@tonic-gate * Check to see if a given "flavor" is an explicitly shared flavor. 21877c478bd9Sstevel@tonic-gate * The assumption of this routine is the "flavor" is already a valid 21887c478bd9Sstevel@tonic-gate * flavor in the secinfo list of "exi". 21897c478bd9Sstevel@tonic-gate * 21907c478bd9Sstevel@tonic-gate * e.g. 21917c478bd9Sstevel@tonic-gate * # share -o sec=flavor1 /export 21927c478bd9Sstevel@tonic-gate * # share -o sec=flavor2 /export/home 21937c478bd9Sstevel@tonic-gate * 21947c478bd9Sstevel@tonic-gate * flavor2 is not an explicitly shared flavor for /export, 21957c478bd9Sstevel@tonic-gate * however it is in the secinfo list for /export thru the 21967c478bd9Sstevel@tonic-gate * server namespace setup. 21977c478bd9Sstevel@tonic-gate */ 21987c478bd9Sstevel@tonic-gate int 21997c478bd9Sstevel@tonic-gate is_exported_sec(int flavor, struct exportinfo *exi) 22007c478bd9Sstevel@tonic-gate { 22017c478bd9Sstevel@tonic-gate int i; 22027c478bd9Sstevel@tonic-gate struct secinfo *sp; 22037c478bd9Sstevel@tonic-gate 22047c478bd9Sstevel@tonic-gate sp = exi->exi_export.ex_secinfo; 22057c478bd9Sstevel@tonic-gate for (i = 0; i < exi->exi_export.ex_seccnt; i++) { 22067c478bd9Sstevel@tonic-gate if (flavor == sp[i].s_secinfo.sc_nfsnum || 22077c478bd9Sstevel@tonic-gate sp[i].s_secinfo.sc_nfsnum == AUTH_NONE) { 22087c478bd9Sstevel@tonic-gate return (SEC_REF_EXPORTED(&sp[i])); 22097c478bd9Sstevel@tonic-gate } 22107c478bd9Sstevel@tonic-gate } 22117c478bd9Sstevel@tonic-gate 22127c478bd9Sstevel@tonic-gate /* Should not reach this point based on the assumption */ 22137c478bd9Sstevel@tonic-gate return (0); 22147c478bd9Sstevel@tonic-gate } 22157c478bd9Sstevel@tonic-gate 22167c478bd9Sstevel@tonic-gate /* 22177c478bd9Sstevel@tonic-gate * Check if the security flavor used in the request matches what is 22187c478bd9Sstevel@tonic-gate * required at the export point or at the root pseudo node (exi_root). 22197c478bd9Sstevel@tonic-gate * 22207c478bd9Sstevel@tonic-gate * returns 1 if there's a match or if exported with AUTH_NONE; 0 otherwise. 22217c478bd9Sstevel@tonic-gate * 22227c478bd9Sstevel@tonic-gate */ 22237c478bd9Sstevel@tonic-gate static int 22247c478bd9Sstevel@tonic-gate secinfo_match_or_authnone(struct compound_state *cs) 22257c478bd9Sstevel@tonic-gate { 22267c478bd9Sstevel@tonic-gate int i; 22277c478bd9Sstevel@tonic-gate struct secinfo *sp; 22287c478bd9Sstevel@tonic-gate 22297c478bd9Sstevel@tonic-gate /* 22307c478bd9Sstevel@tonic-gate * Check cs->nfsflavor (from the request) against 22317c478bd9Sstevel@tonic-gate * the current export data in cs->exi. 22327c478bd9Sstevel@tonic-gate */ 22337c478bd9Sstevel@tonic-gate sp = cs->exi->exi_export.ex_secinfo; 22347c478bd9Sstevel@tonic-gate for (i = 0; i < cs->exi->exi_export.ex_seccnt; i++) { 22357c478bd9Sstevel@tonic-gate if (cs->nfsflavor == sp[i].s_secinfo.sc_nfsnum || 22367c478bd9Sstevel@tonic-gate sp[i].s_secinfo.sc_nfsnum == AUTH_NONE) 22377c478bd9Sstevel@tonic-gate return (1); 22387c478bd9Sstevel@tonic-gate } 22397c478bd9Sstevel@tonic-gate 22407c478bd9Sstevel@tonic-gate return (0); 22417c478bd9Sstevel@tonic-gate } 22427c478bd9Sstevel@tonic-gate 22437c478bd9Sstevel@tonic-gate /* 22447c478bd9Sstevel@tonic-gate * Check the access authority for the client and return the correct error. 22457c478bd9Sstevel@tonic-gate */ 22467c478bd9Sstevel@tonic-gate nfsstat4 22477c478bd9Sstevel@tonic-gate call_checkauth4(struct compound_state *cs, struct svc_req *req) 22487c478bd9Sstevel@tonic-gate { 22497c478bd9Sstevel@tonic-gate int authres; 22507c478bd9Sstevel@tonic-gate 22517c478bd9Sstevel@tonic-gate /* 22527c478bd9Sstevel@tonic-gate * First, check if the security flavor used in the request 22537c478bd9Sstevel@tonic-gate * are among the flavors set in the server namespace. 22547c478bd9Sstevel@tonic-gate */ 22557c478bd9Sstevel@tonic-gate if (!secinfo_match_or_authnone(cs)) { 22567c478bd9Sstevel@tonic-gate *cs->statusp = NFS4ERR_WRONGSEC; 22577c478bd9Sstevel@tonic-gate return (*cs->statusp); 22587c478bd9Sstevel@tonic-gate } 22597c478bd9Sstevel@tonic-gate 22607c478bd9Sstevel@tonic-gate authres = checkauth4(cs, req); 22617c478bd9Sstevel@tonic-gate 22627c478bd9Sstevel@tonic-gate if (authres > 0) { 22637c478bd9Sstevel@tonic-gate *cs->statusp = NFS4_OK; 22647c478bd9Sstevel@tonic-gate if (! (cs->access & CS_ACCESS_LIMITED)) 22657c478bd9Sstevel@tonic-gate cs->access = CS_ACCESS_OK; 22667c478bd9Sstevel@tonic-gate } else if (authres == 0) { 22677c478bd9Sstevel@tonic-gate *cs->statusp = NFS4ERR_ACCESS; 22687c478bd9Sstevel@tonic-gate } else if (authres == -2) { 22697c478bd9Sstevel@tonic-gate *cs->statusp = NFS4ERR_WRONGSEC; 22707c478bd9Sstevel@tonic-gate } else { 22717c478bd9Sstevel@tonic-gate *cs->statusp = NFS4ERR_DELAY; 22727c478bd9Sstevel@tonic-gate } 22737c478bd9Sstevel@tonic-gate return (*cs->statusp); 22747c478bd9Sstevel@tonic-gate } 22757c478bd9Sstevel@tonic-gate 22767c478bd9Sstevel@tonic-gate /* 22777c478bd9Sstevel@tonic-gate * bitmap4_to_attrmask is called by getattr and readdir. 22787c478bd9Sstevel@tonic-gate * It sets up the vattr mask and determines whether vfsstat call is needed 22797c478bd9Sstevel@tonic-gate * based on the input bitmap. 22807c478bd9Sstevel@tonic-gate * Returns nfsv4 status. 22817c478bd9Sstevel@tonic-gate */ 22827c478bd9Sstevel@tonic-gate static nfsstat4 22837c478bd9Sstevel@tonic-gate bitmap4_to_attrmask(bitmap4 breq, struct nfs4_svgetit_arg *sargp) 22847c478bd9Sstevel@tonic-gate { 22857c478bd9Sstevel@tonic-gate int i; 22867c478bd9Sstevel@tonic-gate uint_t va_mask; 22877c478bd9Sstevel@tonic-gate struct statvfs64 *sbp = sargp->sbp; 22887c478bd9Sstevel@tonic-gate 22897c478bd9Sstevel@tonic-gate sargp->sbp = NULL; 22907c478bd9Sstevel@tonic-gate sargp->flag = 0; 22917c478bd9Sstevel@tonic-gate sargp->rdattr_error = NFS4_OK; 22927c478bd9Sstevel@tonic-gate sargp->mntdfid_set = FALSE; 22937c478bd9Sstevel@tonic-gate if (sargp->cs->vp) 22947c478bd9Sstevel@tonic-gate sargp->xattr = get_fh4_flag(&sargp->cs->fh, 22957c478bd9Sstevel@tonic-gate FH4_ATTRDIR | FH4_NAMEDATTR); 22967c478bd9Sstevel@tonic-gate else 22977c478bd9Sstevel@tonic-gate sargp->xattr = 0; 22987c478bd9Sstevel@tonic-gate 22997c478bd9Sstevel@tonic-gate /* 23007c478bd9Sstevel@tonic-gate * Set rdattr_error_req to true if return error per 23017c478bd9Sstevel@tonic-gate * failed entry rather than fail the readdir. 23027c478bd9Sstevel@tonic-gate */ 23037c478bd9Sstevel@tonic-gate if (breq & FATTR4_RDATTR_ERROR_MASK) 23047c478bd9Sstevel@tonic-gate sargp->rdattr_error_req = 1; 23057c478bd9Sstevel@tonic-gate else 23067c478bd9Sstevel@tonic-gate sargp->rdattr_error_req = 0; 23077c478bd9Sstevel@tonic-gate 23087c478bd9Sstevel@tonic-gate /* 23097c478bd9Sstevel@tonic-gate * generate the va_mask 23107c478bd9Sstevel@tonic-gate * Handle the easy cases first 23117c478bd9Sstevel@tonic-gate */ 23127c478bd9Sstevel@tonic-gate switch (breq) { 23137c478bd9Sstevel@tonic-gate case NFS4_NTOV_ATTR_MASK: 23147c478bd9Sstevel@tonic-gate sargp->vap->va_mask = NFS4_NTOV_ATTR_AT_MASK; 23157c478bd9Sstevel@tonic-gate return (NFS4_OK); 23167c478bd9Sstevel@tonic-gate 23177c478bd9Sstevel@tonic-gate case NFS4_FS_ATTR_MASK: 23187c478bd9Sstevel@tonic-gate sargp->vap->va_mask = NFS4_FS_ATTR_AT_MASK; 23197c478bd9Sstevel@tonic-gate sargp->sbp = sbp; 23207c478bd9Sstevel@tonic-gate return (NFS4_OK); 23217c478bd9Sstevel@tonic-gate 23227c478bd9Sstevel@tonic-gate case NFS4_NTOV_ATTR_CACHE_MASK: 23237c478bd9Sstevel@tonic-gate sargp->vap->va_mask = NFS4_NTOV_ATTR_CACHE_AT_MASK; 23247c478bd9Sstevel@tonic-gate return (NFS4_OK); 23257c478bd9Sstevel@tonic-gate 23267c478bd9Sstevel@tonic-gate case FATTR4_LEASE_TIME_MASK: 23277c478bd9Sstevel@tonic-gate sargp->vap->va_mask = 0; 23287c478bd9Sstevel@tonic-gate return (NFS4_OK); 23297c478bd9Sstevel@tonic-gate 23307c478bd9Sstevel@tonic-gate default: 23317c478bd9Sstevel@tonic-gate va_mask = 0; 23327c478bd9Sstevel@tonic-gate for (i = 0; i < nfs4_ntov_map_size; i++) { 23337c478bd9Sstevel@tonic-gate if ((breq & nfs4_ntov_map[i].fbit) && 23347c478bd9Sstevel@tonic-gate nfs4_ntov_map[i].vbit) 23357c478bd9Sstevel@tonic-gate va_mask |= nfs4_ntov_map[i].vbit; 23367c478bd9Sstevel@tonic-gate } 23377c478bd9Sstevel@tonic-gate 23387c478bd9Sstevel@tonic-gate /* 23397c478bd9Sstevel@tonic-gate * Check is vfsstat is needed 23407c478bd9Sstevel@tonic-gate */ 23417c478bd9Sstevel@tonic-gate if (breq & NFS4_FS_ATTR_MASK) 23427c478bd9Sstevel@tonic-gate sargp->sbp = sbp; 23437c478bd9Sstevel@tonic-gate 23447c478bd9Sstevel@tonic-gate sargp->vap->va_mask = va_mask; 23457c478bd9Sstevel@tonic-gate return (NFS4_OK); 23467c478bd9Sstevel@tonic-gate } 23477c478bd9Sstevel@tonic-gate /* NOTREACHED */ 23487c478bd9Sstevel@tonic-gate } 23497c478bd9Sstevel@tonic-gate 23507c478bd9Sstevel@tonic-gate /* 23517c478bd9Sstevel@tonic-gate * bitmap4_get_sysattrs is called by getattr and readdir. 23527c478bd9Sstevel@tonic-gate * It calls both VOP_GETATTR and VFS_STATVFS calls to get the attrs. 23537c478bd9Sstevel@tonic-gate * Returns nfsv4 status. 23547c478bd9Sstevel@tonic-gate */ 23557c478bd9Sstevel@tonic-gate static nfsstat4 23567c478bd9Sstevel@tonic-gate bitmap4_get_sysattrs(struct nfs4_svgetit_arg *sargp) 23577c478bd9Sstevel@tonic-gate { 23587c478bd9Sstevel@tonic-gate int error; 23597c478bd9Sstevel@tonic-gate struct compound_state *cs = sargp->cs; 23607c478bd9Sstevel@tonic-gate vnode_t *vp = cs->vp; 23617c478bd9Sstevel@tonic-gate 23627c478bd9Sstevel@tonic-gate if (sargp->sbp != NULL) { 2363bd3561fbSToomas Soome error = VFS_STATVFS(vp->v_vfsp, sargp->sbp); 2364bd3561fbSToomas Soome if (error != 0) { 23657c478bd9Sstevel@tonic-gate sargp->sbp = NULL; /* to identify error */ 23667c478bd9Sstevel@tonic-gate return (puterrno4(error)); 23677c478bd9Sstevel@tonic-gate } 23687c478bd9Sstevel@tonic-gate } 23697c478bd9Sstevel@tonic-gate 23707c478bd9Sstevel@tonic-gate return (rfs4_vop_getattr(vp, sargp->vap, 0, cs->cr)); 23717c478bd9Sstevel@tonic-gate } 23727c478bd9Sstevel@tonic-gate 23737c478bd9Sstevel@tonic-gate static void 23747c478bd9Sstevel@tonic-gate nfs4_ntov_table_init(struct nfs4_ntov_table *ntovp) 23757c478bd9Sstevel@tonic-gate { 23767c478bd9Sstevel@tonic-gate ntovp->na = kmem_zalloc(sizeof (union nfs4_attr_u) * nfs4_ntov_map_size, 23777c478bd9Sstevel@tonic-gate KM_SLEEP); 23787c478bd9Sstevel@tonic-gate ntovp->attrcnt = 0; 23797c478bd9Sstevel@tonic-gate ntovp->vfsstat = FALSE; 23807c478bd9Sstevel@tonic-gate } 23817c478bd9Sstevel@tonic-gate 23827c478bd9Sstevel@tonic-gate static void 23837c478bd9Sstevel@tonic-gate nfs4_ntov_table_free(struct nfs4_ntov_table *ntovp, 23847c478bd9Sstevel@tonic-gate struct nfs4_svgetit_arg *sargp) 23857c478bd9Sstevel@tonic-gate { 23867c478bd9Sstevel@tonic-gate int i; 23877c478bd9Sstevel@tonic-gate union nfs4_attr_u *na; 23887c478bd9Sstevel@tonic-gate uint8_t *amap; 23897c478bd9Sstevel@tonic-gate 23907c478bd9Sstevel@tonic-gate /* 23917c478bd9Sstevel@tonic-gate * XXX Should do the same checks for whether the bit is set 23927c478bd9Sstevel@tonic-gate */ 23937c478bd9Sstevel@tonic-gate for (i = 0, na = ntovp->na, amap = ntovp->amap; 23947c478bd9Sstevel@tonic-gate i < ntovp->attrcnt; i++, na++, amap++) { 23957c478bd9Sstevel@tonic-gate (void) (*nfs4_ntov_map[*amap].sv_getit)( 23967c478bd9Sstevel@tonic-gate NFS4ATTR_FREEIT, sargp, na); 23977c478bd9Sstevel@tonic-gate } 23987c478bd9Sstevel@tonic-gate if ((sargp->op == NFS4ATTR_SETIT) || (sargp->op == NFS4ATTR_VERIT)) { 23997c478bd9Sstevel@tonic-gate /* 24007c478bd9Sstevel@tonic-gate * xdr_free for getattr will be done later 24017c478bd9Sstevel@tonic-gate */ 24027c478bd9Sstevel@tonic-gate for (i = 0, na = ntovp->na, amap = ntovp->amap; 24037c478bd9Sstevel@tonic-gate i < ntovp->attrcnt; i++, na++, amap++) { 24047c478bd9Sstevel@tonic-gate xdr_free(nfs4_ntov_map[*amap].xfunc, (caddr_t)na); 24057c478bd9Sstevel@tonic-gate } 24067c478bd9Sstevel@tonic-gate } 24077c478bd9Sstevel@tonic-gate kmem_free(ntovp->na, sizeof (union nfs4_attr_u) * nfs4_ntov_map_size); 24087c478bd9Sstevel@tonic-gate } 24097c478bd9Sstevel@tonic-gate 24107c478bd9Sstevel@tonic-gate /* 24117c478bd9Sstevel@tonic-gate * do_rfs4_op_getattr gets the system attrs and converts into fattr4. 24127c478bd9Sstevel@tonic-gate */ 24137c478bd9Sstevel@tonic-gate static nfsstat4 24147c478bd9Sstevel@tonic-gate do_rfs4_op_getattr(bitmap4 breq, fattr4 *fattrp, 24157c478bd9Sstevel@tonic-gate struct nfs4_svgetit_arg *sargp) 24167c478bd9Sstevel@tonic-gate { 24177c478bd9Sstevel@tonic-gate int error = 0; 24187c478bd9Sstevel@tonic-gate int i, k; 24197c478bd9Sstevel@tonic-gate struct nfs4_ntov_table ntov; 24207c478bd9Sstevel@tonic-gate XDR xdr; 24217c478bd9Sstevel@tonic-gate ulong_t xdr_size; 24227c478bd9Sstevel@tonic-gate char *xdr_attrs; 24237c478bd9Sstevel@tonic-gate nfsstat4 status = NFS4_OK; 24247c478bd9Sstevel@tonic-gate nfsstat4 prev_rdattr_error = sargp->rdattr_error; 24257c478bd9Sstevel@tonic-gate union nfs4_attr_u *na; 24267c478bd9Sstevel@tonic-gate uint8_t *amap; 24277c478bd9Sstevel@tonic-gate 24287c478bd9Sstevel@tonic-gate sargp->op = NFS4ATTR_GETIT; 24297c478bd9Sstevel@tonic-gate sargp->flag = 0; 24307c478bd9Sstevel@tonic-gate 24317c478bd9Sstevel@tonic-gate fattrp->attrmask = 0; 24327c478bd9Sstevel@tonic-gate /* if no bits requested, then return empty fattr4 */ 24337c478bd9Sstevel@tonic-gate if (breq == 0) { 24347c478bd9Sstevel@tonic-gate fattrp->attrlist4_len = 0; 24357c478bd9Sstevel@tonic-gate fattrp->attrlist4 = NULL; 24367c478bd9Sstevel@tonic-gate return (NFS4_OK); 24377c478bd9Sstevel@tonic-gate } 24387c478bd9Sstevel@tonic-gate 24397c478bd9Sstevel@tonic-gate /* 24407c478bd9Sstevel@tonic-gate * return NFS4ERR_INVAL when client requests write-only attrs 24417c478bd9Sstevel@tonic-gate */ 24427c478bd9Sstevel@tonic-gate if (breq & (FATTR4_TIME_ACCESS_SET_MASK | FATTR4_TIME_MODIFY_SET_MASK)) 24437c478bd9Sstevel@tonic-gate return (NFS4ERR_INVAL); 24447c478bd9Sstevel@tonic-gate 24457c478bd9Sstevel@tonic-gate nfs4_ntov_table_init(&ntov); 24467c478bd9Sstevel@tonic-gate na = ntov.na; 24477c478bd9Sstevel@tonic-gate amap = ntov.amap; 24487c478bd9Sstevel@tonic-gate 24497c478bd9Sstevel@tonic-gate /* 24507c478bd9Sstevel@tonic-gate * Now loop to get or verify the attrs 24517c478bd9Sstevel@tonic-gate */ 24527c478bd9Sstevel@tonic-gate for (i = 0; i < nfs4_ntov_map_size; i++) { 24537c478bd9Sstevel@tonic-gate if (breq & nfs4_ntov_map[i].fbit) { 24547c478bd9Sstevel@tonic-gate if ((*nfs4_ntov_map[i].sv_getit)( 24557c478bd9Sstevel@tonic-gate NFS4ATTR_SUPPORTED, sargp, NULL) == 0) { 24567c478bd9Sstevel@tonic-gate 24577c478bd9Sstevel@tonic-gate error = (*nfs4_ntov_map[i].sv_getit)( 24587c478bd9Sstevel@tonic-gate NFS4ATTR_GETIT, sargp, na); 24597c478bd9Sstevel@tonic-gate 24607c478bd9Sstevel@tonic-gate /* 24617c478bd9Sstevel@tonic-gate * Possible error values: 24627c478bd9Sstevel@tonic-gate * >0 if sv_getit failed to 24637c478bd9Sstevel@tonic-gate * get the attr; 0 if succeeded; 24647c478bd9Sstevel@tonic-gate * <0 if rdattr_error and the 24657c478bd9Sstevel@tonic-gate * attribute cannot be returned. 24667c478bd9Sstevel@tonic-gate */ 24677c478bd9Sstevel@tonic-gate if (error && !(sargp->rdattr_error_req)) 24687c478bd9Sstevel@tonic-gate goto done; 24697c478bd9Sstevel@tonic-gate /* 24707c478bd9Sstevel@tonic-gate * If error then just for entry 24717c478bd9Sstevel@tonic-gate */ 24727c478bd9Sstevel@tonic-gate if (error == 0) { 24737c478bd9Sstevel@tonic-gate fattrp->attrmask |= 24747c478bd9Sstevel@tonic-gate nfs4_ntov_map[i].fbit; 24757c478bd9Sstevel@tonic-gate *amap++ = 24767c478bd9Sstevel@tonic-gate (uint8_t)nfs4_ntov_map[i].nval; 24777c478bd9Sstevel@tonic-gate na++; 24787c478bd9Sstevel@tonic-gate (ntov.attrcnt)++; 24797c478bd9Sstevel@tonic-gate } else if ((error > 0) && 24807c478bd9Sstevel@tonic-gate (sargp->rdattr_error == NFS4_OK)) { 24817c478bd9Sstevel@tonic-gate sargp->rdattr_error = puterrno4(error); 24827c478bd9Sstevel@tonic-gate } 24837c478bd9Sstevel@tonic-gate error = 0; 24847c478bd9Sstevel@tonic-gate } 24857c478bd9Sstevel@tonic-gate } 24867c478bd9Sstevel@tonic-gate } 24877c478bd9Sstevel@tonic-gate 24887c478bd9Sstevel@tonic-gate /* 24897c478bd9Sstevel@tonic-gate * If rdattr_error was set after the return value for it was assigned, 24907c478bd9Sstevel@tonic-gate * update it. 24917c478bd9Sstevel@tonic-gate */ 24927c478bd9Sstevel@tonic-gate if (prev_rdattr_error != sargp->rdattr_error) { 24937c478bd9Sstevel@tonic-gate na = ntov.na; 24947c478bd9Sstevel@tonic-gate amap = ntov.amap; 24957c478bd9Sstevel@tonic-gate for (i = 0; i < ntov.attrcnt; i++, na++, amap++) { 24967c478bd9Sstevel@tonic-gate k = *amap; 24977c478bd9Sstevel@tonic-gate if (k < FATTR4_RDATTR_ERROR) { 24987c478bd9Sstevel@tonic-gate continue; 24997c478bd9Sstevel@tonic-gate } 25007c478bd9Sstevel@tonic-gate if ((k == FATTR4_RDATTR_ERROR) && 25017c478bd9Sstevel@tonic-gate ((*nfs4_ntov_map[k].sv_getit)( 25027c478bd9Sstevel@tonic-gate NFS4ATTR_SUPPORTED, sargp, NULL) == 0)) { 25037c478bd9Sstevel@tonic-gate 25047c478bd9Sstevel@tonic-gate (void) (*nfs4_ntov_map[k].sv_getit)( 25057c478bd9Sstevel@tonic-gate NFS4ATTR_GETIT, sargp, na); 25067c478bd9Sstevel@tonic-gate } 25077c478bd9Sstevel@tonic-gate break; 25087c478bd9Sstevel@tonic-gate } 25097c478bd9Sstevel@tonic-gate } 25107c478bd9Sstevel@tonic-gate 25117c478bd9Sstevel@tonic-gate xdr_size = 0; 25127c478bd9Sstevel@tonic-gate na = ntov.na; 25137c478bd9Sstevel@tonic-gate amap = ntov.amap; 25147c478bd9Sstevel@tonic-gate for (i = 0; i < ntov.attrcnt; i++, na++, amap++) { 25157c478bd9Sstevel@tonic-gate xdr_size += xdr_sizeof(nfs4_ntov_map[*amap].xfunc, na); 25167c478bd9Sstevel@tonic-gate } 25177c478bd9Sstevel@tonic-gate 25187c478bd9Sstevel@tonic-gate fattrp->attrlist4_len = xdr_size; 25197c478bd9Sstevel@tonic-gate if (xdr_size) { 25207c478bd9Sstevel@tonic-gate /* freed by rfs4_op_getattr_free() */ 25217c478bd9Sstevel@tonic-gate fattrp->attrlist4 = xdr_attrs = kmem_zalloc(xdr_size, KM_SLEEP); 25227c478bd9Sstevel@tonic-gate 25237c478bd9Sstevel@tonic-gate xdrmem_create(&xdr, xdr_attrs, xdr_size, XDR_ENCODE); 25247c478bd9Sstevel@tonic-gate 25257c478bd9Sstevel@tonic-gate na = ntov.na; 25267c478bd9Sstevel@tonic-gate amap = ntov.amap; 25277c478bd9Sstevel@tonic-gate for (i = 0; i < ntov.attrcnt; i++, na++, amap++) { 25287c478bd9Sstevel@tonic-gate if (!(*nfs4_ntov_map[*amap].xfunc)(&xdr, na)) { 25290a701b1eSRobert Gordon DTRACE_PROBE1(nfss__e__getattr4_encfail, 25300a701b1eSRobert Gordon int, *amap); 25317c478bd9Sstevel@tonic-gate status = NFS4ERR_SERVERFAULT; 25327c478bd9Sstevel@tonic-gate break; 25337c478bd9Sstevel@tonic-gate } 25347c478bd9Sstevel@tonic-gate } 25357c478bd9Sstevel@tonic-gate /* xdrmem_destroy(&xdrs); */ /* NO-OP */ 25367c478bd9Sstevel@tonic-gate } else { 25377c478bd9Sstevel@tonic-gate fattrp->attrlist4 = NULL; 25387c478bd9Sstevel@tonic-gate } 25397c478bd9Sstevel@tonic-gate done: 25407c478bd9Sstevel@tonic-gate 25417c478bd9Sstevel@tonic-gate nfs4_ntov_table_free(&ntov, sargp); 25427c478bd9Sstevel@tonic-gate 25437c478bd9Sstevel@tonic-gate if (error != 0) 25447c478bd9Sstevel@tonic-gate status = puterrno4(error); 25457c478bd9Sstevel@tonic-gate 25467c478bd9Sstevel@tonic-gate return (status); 25477c478bd9Sstevel@tonic-gate } 25487c478bd9Sstevel@tonic-gate 25497c478bd9Sstevel@tonic-gate /* ARGSUSED */ 25507c478bd9Sstevel@tonic-gate static void 25517c478bd9Sstevel@tonic-gate rfs4_op_getattr(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req, 25527c478bd9Sstevel@tonic-gate struct compound_state *cs) 25537c478bd9Sstevel@tonic-gate { 25547c478bd9Sstevel@tonic-gate GETATTR4args *args = &argop->nfs_argop4_u.opgetattr; 25557c478bd9Sstevel@tonic-gate GETATTR4res *resp = &resop->nfs_resop4_u.opgetattr; 25567c478bd9Sstevel@tonic-gate struct nfs4_svgetit_arg sarg; 25577c478bd9Sstevel@tonic-gate struct statvfs64 sb; 25587c478bd9Sstevel@tonic-gate nfsstat4 status; 25597c478bd9Sstevel@tonic-gate 2560f3b585ceSsamf DTRACE_NFSV4_2(op__getattr__start, struct compound_state *, cs, 2561f3b585ceSsamf GETATTR4args *, args); 2562f3b585ceSsamf 25637c478bd9Sstevel@tonic-gate if (cs->vp == NULL) { 25647c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE; 2565f3b585ceSsamf goto out; 25667c478bd9Sstevel@tonic-gate } 25677c478bd9Sstevel@tonic-gate 25687c478bd9Sstevel@tonic-gate if (cs->access == CS_ACCESS_DENIED) { 25697c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_ACCESS; 2570f3b585ceSsamf goto out; 25717c478bd9Sstevel@tonic-gate } 25727c478bd9Sstevel@tonic-gate 25737c478bd9Sstevel@tonic-gate sarg.sbp = &sb; 25747c478bd9Sstevel@tonic-gate sarg.cs = cs; 25752f172c55SRobert Thurlow sarg.is_referral = B_FALSE; 25767c478bd9Sstevel@tonic-gate 25777c478bd9Sstevel@tonic-gate status = bitmap4_to_attrmask(args->attr_request, &sarg); 25787c478bd9Sstevel@tonic-gate if (status == NFS4_OK) { 25792f172c55SRobert Thurlow 25807c478bd9Sstevel@tonic-gate status = bitmap4_get_sysattrs(&sarg); 25812f172c55SRobert Thurlow if (status == NFS4_OK) { 25822f172c55SRobert Thurlow 25832f172c55SRobert Thurlow /* Is this a referral? */ 25842f172c55SRobert Thurlow if (vn_is_nfs_reparse(cs->vp, cs->cr)) { 25852f172c55SRobert Thurlow /* Older V4 Solaris client sees a link */ 25862f172c55SRobert Thurlow if (client_is_downrev(req)) 25872f172c55SRobert Thurlow sarg.vap->va_type = VLNK; 25882f172c55SRobert Thurlow else 25892f172c55SRobert Thurlow sarg.is_referral = B_TRUE; 25902f172c55SRobert Thurlow } 25912f172c55SRobert Thurlow 25927c478bd9Sstevel@tonic-gate status = do_rfs4_op_getattr(args->attr_request, 25937c478bd9Sstevel@tonic-gate &resp->obj_attributes, &sarg); 25947c478bd9Sstevel@tonic-gate } 25952f172c55SRobert Thurlow } 25967c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = status; 2597f3b585ceSsamf out: 2598f3b585ceSsamf DTRACE_NFSV4_2(op__getattr__done, struct compound_state *, cs, 2599f3b585ceSsamf GETATTR4res *, resp); 26007c478bd9Sstevel@tonic-gate } 26017c478bd9Sstevel@tonic-gate 26027c478bd9Sstevel@tonic-gate static void 26037c478bd9Sstevel@tonic-gate rfs4_op_getattr_free(nfs_resop4 *resop) 26047c478bd9Sstevel@tonic-gate { 26057c478bd9Sstevel@tonic-gate GETATTR4res *resp = &resop->nfs_resop4_u.opgetattr; 26067c478bd9Sstevel@tonic-gate 26077c478bd9Sstevel@tonic-gate nfs4_fattr4_free(&resp->obj_attributes); 26087c478bd9Sstevel@tonic-gate } 26097c478bd9Sstevel@tonic-gate 26107c478bd9Sstevel@tonic-gate /* ARGSUSED */ 26117c478bd9Sstevel@tonic-gate static void 26127c478bd9Sstevel@tonic-gate rfs4_op_getfh(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req, 26137c478bd9Sstevel@tonic-gate struct compound_state *cs) 26147c478bd9Sstevel@tonic-gate { 26157c478bd9Sstevel@tonic-gate GETFH4res *resp = &resop->nfs_resop4_u.opgetfh; 26167c478bd9Sstevel@tonic-gate 2617f3b585ceSsamf DTRACE_NFSV4_1(op__getfh__start, struct compound_state *, cs); 2618f3b585ceSsamf 26197c478bd9Sstevel@tonic-gate if (cs->vp == NULL) { 26207c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE; 2621f3b585ceSsamf goto out; 26227c478bd9Sstevel@tonic-gate } 26237c478bd9Sstevel@tonic-gate if (cs->access == CS_ACCESS_DENIED) { 26247c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_ACCESS; 2625f3b585ceSsamf goto out; 26267c478bd9Sstevel@tonic-gate } 26277c478bd9Sstevel@tonic-gate 26282f172c55SRobert Thurlow /* check for reparse point at the share point */ 26292f172c55SRobert Thurlow if (cs->exi->exi_moved || vn_is_nfs_reparse(cs->exi->exi_vp, cs->cr)) { 26302f172c55SRobert Thurlow /* it's all bad */ 26312f172c55SRobert Thurlow cs->exi->exi_moved = 1; 26322f172c55SRobert Thurlow *cs->statusp = resp->status = NFS4ERR_MOVED; 26332f172c55SRobert Thurlow DTRACE_PROBE2(nfs4serv__func__referral__shared__moved, 26342f172c55SRobert Thurlow vnode_t *, cs->vp, char *, "rfs4_op_getfh"); 26352f172c55SRobert Thurlow return; 26362f172c55SRobert Thurlow } 26372f172c55SRobert Thurlow 26382f172c55SRobert Thurlow /* check for reparse point at vp */ 26392f172c55SRobert Thurlow if (vn_is_nfs_reparse(cs->vp, cs->cr) && !client_is_downrev(req)) { 26402f172c55SRobert Thurlow /* it's not all bad */ 26412f172c55SRobert Thurlow *cs->statusp = resp->status = NFS4ERR_MOVED; 26422f172c55SRobert Thurlow DTRACE_PROBE2(nfs4serv__func__referral__moved, 26432f172c55SRobert Thurlow vnode_t *, cs->vp, char *, "rfs4_op_getfh"); 26442f172c55SRobert Thurlow return; 26452f172c55SRobert Thurlow } 26462f172c55SRobert Thurlow 26477c478bd9Sstevel@tonic-gate resp->object.nfs_fh4_val = 26487c478bd9Sstevel@tonic-gate kmem_alloc(cs->fh.nfs_fh4_len, KM_SLEEP); 26497c478bd9Sstevel@tonic-gate nfs_fh4_copy(&cs->fh, &resp->object); 26507c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4_OK; 2651f3b585ceSsamf out: 2652f3b585ceSsamf DTRACE_NFSV4_2(op__getfh__done, struct compound_state *, cs, 2653f3b585ceSsamf GETFH4res *, resp); 26547c478bd9Sstevel@tonic-gate } 26557c478bd9Sstevel@tonic-gate 26567c478bd9Sstevel@tonic-gate static void 26577c478bd9Sstevel@tonic-gate rfs4_op_getfh_free(nfs_resop4 *resop) 26587c478bd9Sstevel@tonic-gate { 26597c478bd9Sstevel@tonic-gate GETFH4res *resp = &resop->nfs_resop4_u.opgetfh; 26607c478bd9Sstevel@tonic-gate 26617c478bd9Sstevel@tonic-gate if (resp->status == NFS4_OK && 26627c478bd9Sstevel@tonic-gate resp->object.nfs_fh4_val != NULL) { 26637c478bd9Sstevel@tonic-gate kmem_free(resp->object.nfs_fh4_val, resp->object.nfs_fh4_len); 26647c478bd9Sstevel@tonic-gate resp->object.nfs_fh4_val = NULL; 26657c478bd9Sstevel@tonic-gate resp->object.nfs_fh4_len = 0; 26667c478bd9Sstevel@tonic-gate } 26677c478bd9Sstevel@tonic-gate } 26687c478bd9Sstevel@tonic-gate 26697c478bd9Sstevel@tonic-gate /* 26707c478bd9Sstevel@tonic-gate * illegal: args: void 26717c478bd9Sstevel@tonic-gate * res : status (NFS4ERR_OP_ILLEGAL) 26727c478bd9Sstevel@tonic-gate */ 26737c478bd9Sstevel@tonic-gate /* ARGSUSED */ 26747c478bd9Sstevel@tonic-gate static void 26757c478bd9Sstevel@tonic-gate rfs4_op_illegal(nfs_argop4 *argop, nfs_resop4 *resop, 26767c478bd9Sstevel@tonic-gate struct svc_req *req, struct compound_state *cs) 26777c478bd9Sstevel@tonic-gate { 26787c478bd9Sstevel@tonic-gate ILLEGAL4res *resp = &resop->nfs_resop4_u.opillegal; 26797c478bd9Sstevel@tonic-gate 26807c478bd9Sstevel@tonic-gate resop->resop = OP_ILLEGAL; 26817c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_OP_ILLEGAL; 26827c478bd9Sstevel@tonic-gate } 26837c478bd9Sstevel@tonic-gate 2684*f44e1126SVitaliy Gusev /* ARGSUSED */ 2685*f44e1126SVitaliy Gusev static void 2686*f44e1126SVitaliy Gusev rfs4_op_notsup(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req, 2687*f44e1126SVitaliy Gusev struct compound_state *cs) 2688*f44e1126SVitaliy Gusev { 2689*f44e1126SVitaliy Gusev *cs->statusp = *((nfsstat4 *)&(resop)->nfs_resop4_u) = NFS4ERR_NOTSUPP; 2690*f44e1126SVitaliy Gusev } 2691*f44e1126SVitaliy Gusev 26927c478bd9Sstevel@tonic-gate /* 26937c478bd9Sstevel@tonic-gate * link: args: SAVED_FH: file, CURRENT_FH: target directory 26947c478bd9Sstevel@tonic-gate * res: status. If success - CURRENT_FH unchanged, return change_info 26957c478bd9Sstevel@tonic-gate */ 26967c478bd9Sstevel@tonic-gate /* ARGSUSED */ 26977c478bd9Sstevel@tonic-gate static void 26987c478bd9Sstevel@tonic-gate rfs4_op_link(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req, 26997c478bd9Sstevel@tonic-gate struct compound_state *cs) 27007c478bd9Sstevel@tonic-gate { 27017c478bd9Sstevel@tonic-gate LINK4args *args = &argop->nfs_argop4_u.oplink; 27027c478bd9Sstevel@tonic-gate LINK4res *resp = &resop->nfs_resop4_u.oplink; 27037c478bd9Sstevel@tonic-gate int error; 27047c478bd9Sstevel@tonic-gate vnode_t *vp; 27057c478bd9Sstevel@tonic-gate vnode_t *dvp; 27067c478bd9Sstevel@tonic-gate struct vattr bdva, idva, adva; 27077c478bd9Sstevel@tonic-gate char *nm; 27087c478bd9Sstevel@tonic-gate uint_t len; 2709b89a8333Snatalie li - Sun Microsystems - Irvine United States struct sockaddr *ca; 2710b89a8333Snatalie li - Sun Microsystems - Irvine United States char *name = NULL; 271115721462SDaniil Lunev nfsstat4 status; 27127c478bd9Sstevel@tonic-gate 2713f3b585ceSsamf DTRACE_NFSV4_2(op__link__start, struct compound_state *, cs, 2714f3b585ceSsamf LINK4args *, args); 2715f3b585ceSsamf 27167c478bd9Sstevel@tonic-gate /* SAVED_FH: source object */ 27177c478bd9Sstevel@tonic-gate vp = cs->saved_vp; 27187c478bd9Sstevel@tonic-gate if (vp == NULL) { 27197c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE; 2720f3b585ceSsamf goto out; 27217c478bd9Sstevel@tonic-gate } 27227c478bd9Sstevel@tonic-gate 27237c478bd9Sstevel@tonic-gate /* CURRENT_FH: target directory */ 27247c478bd9Sstevel@tonic-gate dvp = cs->vp; 27257c478bd9Sstevel@tonic-gate if (dvp == NULL) { 27267c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE; 2727f3b585ceSsamf goto out; 27287c478bd9Sstevel@tonic-gate } 27297c478bd9Sstevel@tonic-gate 27307c478bd9Sstevel@tonic-gate /* 27317c478bd9Sstevel@tonic-gate * If there is a non-shared filesystem mounted on this vnode, 27327c478bd9Sstevel@tonic-gate * do not allow to link any file in this directory. 27337c478bd9Sstevel@tonic-gate */ 27347c478bd9Sstevel@tonic-gate if (vn_ismntpt(dvp)) { 27357c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_ACCESS; 2736f3b585ceSsamf goto out; 27377c478bd9Sstevel@tonic-gate } 27387c478bd9Sstevel@tonic-gate 27397c478bd9Sstevel@tonic-gate if (cs->access == CS_ACCESS_DENIED) { 27407c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_ACCESS; 2741f3b585ceSsamf goto out; 27427c478bd9Sstevel@tonic-gate } 27437c478bd9Sstevel@tonic-gate 27447c478bd9Sstevel@tonic-gate /* Check source object's type validity */ 27457c478bd9Sstevel@tonic-gate if (vp->v_type == VDIR) { 27467c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_ISDIR; 2747f3b585ceSsamf goto out; 27487c478bd9Sstevel@tonic-gate } 27497c478bd9Sstevel@tonic-gate 27507c478bd9Sstevel@tonic-gate /* Check target directory's type */ 27517c478bd9Sstevel@tonic-gate if (dvp->v_type != VDIR) { 27527c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_NOTDIR; 2753f3b585ceSsamf goto out; 27547c478bd9Sstevel@tonic-gate } 27557c478bd9Sstevel@tonic-gate 27567c478bd9Sstevel@tonic-gate if (cs->saved_exi != cs->exi) { 27577c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_XDEV; 2758f3b585ceSsamf goto out; 27597c478bd9Sstevel@tonic-gate } 27607c478bd9Sstevel@tonic-gate 276115721462SDaniil Lunev status = utf8_dir_verify(&args->newname); 276215721462SDaniil Lunev if (status != NFS4_OK) { 276315721462SDaniil Lunev *cs->statusp = resp->status = status; 2764f3b585ceSsamf goto out; 27657c478bd9Sstevel@tonic-gate } 27667c478bd9Sstevel@tonic-gate 27677c478bd9Sstevel@tonic-gate nm = utf8_to_fn(&args->newname, &len, NULL); 27687c478bd9Sstevel@tonic-gate if (nm == NULL) { 27697c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_INVAL; 2770f3b585ceSsamf goto out; 27717c478bd9Sstevel@tonic-gate } 27727c478bd9Sstevel@tonic-gate 27737c478bd9Sstevel@tonic-gate if (len > MAXNAMELEN) { 27747c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_NAMETOOLONG; 27757c478bd9Sstevel@tonic-gate kmem_free(nm, len); 2776f3b585ceSsamf goto out; 27777c478bd9Sstevel@tonic-gate } 27787c478bd9Sstevel@tonic-gate 27795cb0d679SMarcel Telka if (rdonly4(req, cs)) { 27807c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_ROFS; 27817c478bd9Sstevel@tonic-gate kmem_free(nm, len); 2782f3b585ceSsamf goto out; 27837c478bd9Sstevel@tonic-gate } 27847c478bd9Sstevel@tonic-gate 27857c478bd9Sstevel@tonic-gate /* Get "before" change value */ 27867c478bd9Sstevel@tonic-gate bdva.va_mask = AT_CTIME|AT_SEQ; 2787da6c28aaSamw error = VOP_GETATTR(dvp, &bdva, 0, cs->cr, NULL); 27887c478bd9Sstevel@tonic-gate if (error) { 27897c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = puterrno4(error); 27907c478bd9Sstevel@tonic-gate kmem_free(nm, len); 2791f3b585ceSsamf goto out; 27927c478bd9Sstevel@tonic-gate } 27937c478bd9Sstevel@tonic-gate 2794b89a8333Snatalie li - Sun Microsystems - Irvine United States ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 2795b89a8333Snatalie li - Sun Microsystems - Irvine United States name = nfscmd_convname(ca, cs->exi, nm, NFSCMD_CONV_INBOUND, 2796b89a8333Snatalie li - Sun Microsystems - Irvine United States MAXPATHLEN + 1); 2797b89a8333Snatalie li - Sun Microsystems - Irvine United States 2798b89a8333Snatalie li - Sun Microsystems - Irvine United States if (name == NULL) { 2799b89a8333Snatalie li - Sun Microsystems - Irvine United States *cs->statusp = resp->status = NFS4ERR_INVAL; 2800b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(nm, len); 2801b89a8333Snatalie li - Sun Microsystems - Irvine United States goto out; 2802b89a8333Snatalie li - Sun Microsystems - Irvine United States } 2803b89a8333Snatalie li - Sun Microsystems - Irvine United States 28047c478bd9Sstevel@tonic-gate NFS4_SET_FATTR4_CHANGE(resp->cinfo.before, bdva.va_ctime) 28057c478bd9Sstevel@tonic-gate 2806b89a8333Snatalie li - Sun Microsystems - Irvine United States error = VOP_LINK(dvp, vp, name, cs->cr, NULL, 0); 28077c478bd9Sstevel@tonic-gate 2808b89a8333Snatalie li - Sun Microsystems - Irvine United States if (nm != name) 2809b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(name, MAXPATHLEN + 1); 28107c478bd9Sstevel@tonic-gate kmem_free(nm, len); 28117c478bd9Sstevel@tonic-gate 28127c478bd9Sstevel@tonic-gate /* 28137c478bd9Sstevel@tonic-gate * Get the initial "after" sequence number, if it fails, set to zero 28147c478bd9Sstevel@tonic-gate */ 28157c478bd9Sstevel@tonic-gate idva.va_mask = AT_SEQ; 2816da6c28aaSamw if (VOP_GETATTR(dvp, &idva, 0, cs->cr, NULL)) 28177c478bd9Sstevel@tonic-gate idva.va_seq = 0; 28187c478bd9Sstevel@tonic-gate 28197c478bd9Sstevel@tonic-gate /* 28207c478bd9Sstevel@tonic-gate * Force modified data and metadata out to stable storage. 28217c478bd9Sstevel@tonic-gate */ 2822da6c28aaSamw (void) VOP_FSYNC(vp, FNODSYNC, cs->cr, NULL); 2823da6c28aaSamw (void) VOP_FSYNC(dvp, 0, cs->cr, NULL); 28247c478bd9Sstevel@tonic-gate 28257c478bd9Sstevel@tonic-gate if (error) { 28267c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = puterrno4(error); 2827f3b585ceSsamf goto out; 28287c478bd9Sstevel@tonic-gate } 28297c478bd9Sstevel@tonic-gate 28307c478bd9Sstevel@tonic-gate /* 28317c478bd9Sstevel@tonic-gate * Get "after" change value, if it fails, simply return the 28327c478bd9Sstevel@tonic-gate * before value. 28337c478bd9Sstevel@tonic-gate */ 28347c478bd9Sstevel@tonic-gate adva.va_mask = AT_CTIME|AT_SEQ; 2835da6c28aaSamw if (VOP_GETATTR(dvp, &adva, 0, cs->cr, NULL)) { 28367c478bd9Sstevel@tonic-gate adva.va_ctime = bdva.va_ctime; 28377c478bd9Sstevel@tonic-gate adva.va_seq = 0; 28387c478bd9Sstevel@tonic-gate } 28397c478bd9Sstevel@tonic-gate 28407c478bd9Sstevel@tonic-gate NFS4_SET_FATTR4_CHANGE(resp->cinfo.after, adva.va_ctime) 28417c478bd9Sstevel@tonic-gate 28427c478bd9Sstevel@tonic-gate /* 28437c478bd9Sstevel@tonic-gate * The cinfo.atomic = TRUE only if we have 28447c478bd9Sstevel@tonic-gate * non-zero va_seq's, and it has incremented by exactly one 28457c478bd9Sstevel@tonic-gate * during the VOP_LINK and it didn't change during the VOP_FSYNC. 28467c478bd9Sstevel@tonic-gate */ 28477c478bd9Sstevel@tonic-gate if (bdva.va_seq && idva.va_seq && adva.va_seq && 28481b300de9Sjwahlig idva.va_seq == (bdva.va_seq + 1) && idva.va_seq == adva.va_seq) 28497c478bd9Sstevel@tonic-gate resp->cinfo.atomic = TRUE; 28507c478bd9Sstevel@tonic-gate else 28517c478bd9Sstevel@tonic-gate resp->cinfo.atomic = FALSE; 28527c478bd9Sstevel@tonic-gate 28537c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4_OK; 2854f3b585ceSsamf out: 2855f3b585ceSsamf DTRACE_NFSV4_2(op__link__done, struct compound_state *, cs, 2856f3b585ceSsamf LINK4res *, resp); 28577c478bd9Sstevel@tonic-gate } 28587c478bd9Sstevel@tonic-gate 28597c478bd9Sstevel@tonic-gate /* 28607c478bd9Sstevel@tonic-gate * Used by rfs4_op_lookup and rfs4_op_lookupp to do the actual work. 28617c478bd9Sstevel@tonic-gate */ 28627c478bd9Sstevel@tonic-gate 28637c478bd9Sstevel@tonic-gate /* ARGSUSED */ 28647c478bd9Sstevel@tonic-gate static nfsstat4 2865593cc11bSJan Kryl do_rfs4_op_lookup(char *nm, struct svc_req *req, struct compound_state *cs) 28667c478bd9Sstevel@tonic-gate { 28677c478bd9Sstevel@tonic-gate int error; 28687c478bd9Sstevel@tonic-gate int different_export = 0; 28696e062f4aSMarcel Telka vnode_t *vp, *pre_tvp = NULL, *oldvp = NULL; 28707c478bd9Sstevel@tonic-gate struct exportinfo *exi = NULL, *pre_exi = NULL; 28717c478bd9Sstevel@tonic-gate nfsstat4 stat; 28727c478bd9Sstevel@tonic-gate fid_t fid; 28737c478bd9Sstevel@tonic-gate int attrdir, dotdot, walk; 28747c478bd9Sstevel@tonic-gate bool_t is_newvp = FALSE; 28757c478bd9Sstevel@tonic-gate 28767c478bd9Sstevel@tonic-gate if (cs->vp->v_flag & V_XATTRDIR) { 28777c478bd9Sstevel@tonic-gate attrdir = 1; 28787c478bd9Sstevel@tonic-gate ASSERT(get_fh4_flag(&cs->fh, FH4_ATTRDIR)); 28797c478bd9Sstevel@tonic-gate } else { 28807c478bd9Sstevel@tonic-gate attrdir = 0; 28817c478bd9Sstevel@tonic-gate ASSERT(! get_fh4_flag(&cs->fh, FH4_ATTRDIR)); 28827c478bd9Sstevel@tonic-gate } 28837c478bd9Sstevel@tonic-gate 28847c478bd9Sstevel@tonic-gate dotdot = (nm[0] == '.' && nm[1] == '.' && nm[2] == '\0'); 28857c478bd9Sstevel@tonic-gate 28867c478bd9Sstevel@tonic-gate /* 28877c478bd9Sstevel@tonic-gate * If dotdotting, then need to check whether it's 28887c478bd9Sstevel@tonic-gate * above the root of a filesystem, or above an 28897c478bd9Sstevel@tonic-gate * export point. 28907c478bd9Sstevel@tonic-gate */ 28917c478bd9Sstevel@tonic-gate if (dotdot) { 28920dfe541eSEvan Layton vnode_t *zone_rootvp; 28937c478bd9Sstevel@tonic-gate 28940dfe541eSEvan Layton ASSERT(cs->exi != NULL); 28950dfe541eSEvan Layton zone_rootvp = cs->exi->exi_ne->exi_root->exi_vp; 28967c478bd9Sstevel@tonic-gate /* 28977c478bd9Sstevel@tonic-gate * If dotdotting at the root of a filesystem, then 28987c478bd9Sstevel@tonic-gate * need to traverse back to the mounted-on filesystem 28997c478bd9Sstevel@tonic-gate * and do the dotdot lookup there. 29007c478bd9Sstevel@tonic-gate */ 29010dfe541eSEvan Layton if ((cs->vp->v_flag & VROOT) || VN_CMP(cs->vp, zone_rootvp)) { 29027c478bd9Sstevel@tonic-gate 29037c478bd9Sstevel@tonic-gate /* 29047c478bd9Sstevel@tonic-gate * If at the system root, then can 29057c478bd9Sstevel@tonic-gate * go up no further. 29067c478bd9Sstevel@tonic-gate */ 29070dfe541eSEvan Layton if (VN_CMP(cs->vp, zone_rootvp)) 29087c478bd9Sstevel@tonic-gate return (puterrno4(ENOENT)); 29097c478bd9Sstevel@tonic-gate 29107c478bd9Sstevel@tonic-gate /* 29117c478bd9Sstevel@tonic-gate * Traverse back to the mounted-on filesystem 29127c478bd9Sstevel@tonic-gate */ 29130dfe541eSEvan Layton cs->vp = untraverse(cs->vp, zone_rootvp); 29147c478bd9Sstevel@tonic-gate 29157c478bd9Sstevel@tonic-gate /* 29167c478bd9Sstevel@tonic-gate * Set the different_export flag so we remember 29177c478bd9Sstevel@tonic-gate * to pick up a new exportinfo entry for 29187c478bd9Sstevel@tonic-gate * this new filesystem. 29197c478bd9Sstevel@tonic-gate */ 29207c478bd9Sstevel@tonic-gate different_export = 1; 29217c478bd9Sstevel@tonic-gate } else { 29227c478bd9Sstevel@tonic-gate 29237c478bd9Sstevel@tonic-gate /* 29247c478bd9Sstevel@tonic-gate * If dotdotting above an export point then set 29257c478bd9Sstevel@tonic-gate * the different_export to get new export info. 29267c478bd9Sstevel@tonic-gate */ 29277c478bd9Sstevel@tonic-gate different_export = nfs_exported(cs->exi, cs->vp); 29287c478bd9Sstevel@tonic-gate } 29297c478bd9Sstevel@tonic-gate } 29307c478bd9Sstevel@tonic-gate 2931da6c28aaSamw error = VOP_LOOKUP(cs->vp, nm, &vp, NULL, 0, NULL, cs->cr, 2932da6c28aaSamw NULL, NULL, NULL); 29337c478bd9Sstevel@tonic-gate if (error) 29347c478bd9Sstevel@tonic-gate return (puterrno4(error)); 29357c478bd9Sstevel@tonic-gate 29367c478bd9Sstevel@tonic-gate /* 29377c478bd9Sstevel@tonic-gate * If the vnode is in a pseudo filesystem, check whether it is visible. 29387c478bd9Sstevel@tonic-gate * 29397c478bd9Sstevel@tonic-gate * XXX if the vnode is a symlink and it is not visible in 29407c478bd9Sstevel@tonic-gate * a pseudo filesystem, return ENOENT (not following symlink). 29417c478bd9Sstevel@tonic-gate * V4 client can not mount such symlink. This is a regression 29427c478bd9Sstevel@tonic-gate * from V2/V3. 29437c478bd9Sstevel@tonic-gate * 29447c478bd9Sstevel@tonic-gate * In the same exported filesystem, if the security flavor used 29457c478bd9Sstevel@tonic-gate * is not an explicitly shared flavor, limit the view to the visible 29467c478bd9Sstevel@tonic-gate * list entries only. This is not a WRONGSEC case because it's already 29477c478bd9Sstevel@tonic-gate * checked via PUTROOTFH/PUTPUBFH or PUTFH. 29487c478bd9Sstevel@tonic-gate */ 29497c478bd9Sstevel@tonic-gate if (!different_export && 29507c478bd9Sstevel@tonic-gate (PSEUDO(cs->exi) || ! is_exported_sec(cs->nfsflavor, cs->exi) || 29517c478bd9Sstevel@tonic-gate cs->access & CS_ACCESS_LIMITED)) { 29527c478bd9Sstevel@tonic-gate if (! nfs_visible(cs->exi, vp, &different_export)) { 29537c478bd9Sstevel@tonic-gate VN_RELE(vp); 29547c478bd9Sstevel@tonic-gate return (puterrno4(ENOENT)); 29557c478bd9Sstevel@tonic-gate } 29567c478bd9Sstevel@tonic-gate } 29577c478bd9Sstevel@tonic-gate 29587c478bd9Sstevel@tonic-gate /* 29597c478bd9Sstevel@tonic-gate * If it's a mountpoint, then traverse it. 29607c478bd9Sstevel@tonic-gate */ 29617c478bd9Sstevel@tonic-gate if (vn_ismntpt(vp)) { 29627c478bd9Sstevel@tonic-gate pre_exi = cs->exi; /* save pre-traversed exportinfo */ 29637c478bd9Sstevel@tonic-gate pre_tvp = vp; /* save pre-traversed vnode */ 29647c478bd9Sstevel@tonic-gate 29657c478bd9Sstevel@tonic-gate /* 29667c478bd9Sstevel@tonic-gate * hold pre_tvp to counteract rele by traverse. We will 29677c478bd9Sstevel@tonic-gate * need pre_tvp below if checkexport4 fails 29687c478bd9Sstevel@tonic-gate */ 29697c478bd9Sstevel@tonic-gate VN_HOLD(pre_tvp); 29706e062f4aSMarcel Telka if ((error = traverse(&vp)) != 0) { 29717c478bd9Sstevel@tonic-gate VN_RELE(vp); 29727c478bd9Sstevel@tonic-gate VN_RELE(pre_tvp); 29737c478bd9Sstevel@tonic-gate return (puterrno4(error)); 29747c478bd9Sstevel@tonic-gate } 29757c478bd9Sstevel@tonic-gate different_export = 1; 29767c478bd9Sstevel@tonic-gate } else if (vp->v_vfsp != cs->vp->v_vfsp) { 29777c478bd9Sstevel@tonic-gate /* 29787c478bd9Sstevel@tonic-gate * The vfsp comparison is to handle the case where 29797c478bd9Sstevel@tonic-gate * a LOFS mount is shared. lo_lookup traverses mount points, 29807c478bd9Sstevel@tonic-gate * and NFS is unaware of local fs transistions because 29817c478bd9Sstevel@tonic-gate * v_vfsmountedhere isn't set. For this special LOFS case, 29827c478bd9Sstevel@tonic-gate * the dir and the obj returned by lookup will have different 29837c478bd9Sstevel@tonic-gate * vfs ptrs. 29847c478bd9Sstevel@tonic-gate */ 29857c478bd9Sstevel@tonic-gate different_export = 1; 29867c478bd9Sstevel@tonic-gate } 29877c478bd9Sstevel@tonic-gate 29887c478bd9Sstevel@tonic-gate if (different_export) { 29897c478bd9Sstevel@tonic-gate 29907c478bd9Sstevel@tonic-gate bzero(&fid, sizeof (fid)); 29917c478bd9Sstevel@tonic-gate fid.fid_len = MAXFIDSZ; 29927c478bd9Sstevel@tonic-gate error = vop_fid_pseudo(vp, &fid); 29937c478bd9Sstevel@tonic-gate if (error) { 29947c478bd9Sstevel@tonic-gate VN_RELE(vp); 29957c478bd9Sstevel@tonic-gate if (pre_tvp) 29967c478bd9Sstevel@tonic-gate VN_RELE(pre_tvp); 29977c478bd9Sstevel@tonic-gate return (puterrno4(error)); 29987c478bd9Sstevel@tonic-gate } 29997c478bd9Sstevel@tonic-gate 30007c478bd9Sstevel@tonic-gate if (dotdot) 30017c478bd9Sstevel@tonic-gate exi = nfs_vptoexi(NULL, vp, cs->cr, &walk, NULL, TRUE); 30027c478bd9Sstevel@tonic-gate else 30037c478bd9Sstevel@tonic-gate exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid, vp); 30047c478bd9Sstevel@tonic-gate 30057c478bd9Sstevel@tonic-gate if (exi == NULL) { 30067c478bd9Sstevel@tonic-gate if (pre_tvp) { 30077c478bd9Sstevel@tonic-gate /* 30087c478bd9Sstevel@tonic-gate * If this vnode is a mounted-on vnode, 30097c478bd9Sstevel@tonic-gate * but the mounted-on file system is not 30107c478bd9Sstevel@tonic-gate * exported, send back the filehandle for 30117c478bd9Sstevel@tonic-gate * the mounted-on vnode, not the root of 30127c478bd9Sstevel@tonic-gate * the mounted-on file system. 30137c478bd9Sstevel@tonic-gate */ 30147c478bd9Sstevel@tonic-gate VN_RELE(vp); 30157c478bd9Sstevel@tonic-gate vp = pre_tvp; 30167c478bd9Sstevel@tonic-gate exi = pre_exi; 30177c478bd9Sstevel@tonic-gate } else { 30187c478bd9Sstevel@tonic-gate VN_RELE(vp); 30197c478bd9Sstevel@tonic-gate return (puterrno4(EACCES)); 30207c478bd9Sstevel@tonic-gate } 30217c478bd9Sstevel@tonic-gate } else if (pre_tvp) { 30227c478bd9Sstevel@tonic-gate /* we're done with pre_tvp now. release extra hold */ 30237c478bd9Sstevel@tonic-gate VN_RELE(pre_tvp); 30247c478bd9Sstevel@tonic-gate } 30257c478bd9Sstevel@tonic-gate 30267c478bd9Sstevel@tonic-gate cs->exi = exi; 30277c478bd9Sstevel@tonic-gate 30287c478bd9Sstevel@tonic-gate /* 30297c478bd9Sstevel@tonic-gate * Now we do a checkauth4. The reason is that 30307c478bd9Sstevel@tonic-gate * this client/user may not have access to the new 303148bbca81SDaniel Hoffman * exported file system, and if they do, 30327c478bd9Sstevel@tonic-gate * the client/user may be mapped to a different uid. 30337c478bd9Sstevel@tonic-gate * 30347c478bd9Sstevel@tonic-gate * We start with a new cr, because the checkauth4 done 30357c478bd9Sstevel@tonic-gate * in the PUT*FH operation over wrote the cred's uid, 30367c478bd9Sstevel@tonic-gate * gid, etc, and we want the real thing before calling 30377c478bd9Sstevel@tonic-gate * checkauth4() 30387c478bd9Sstevel@tonic-gate */ 30397c478bd9Sstevel@tonic-gate crfree(cs->cr); 30407c478bd9Sstevel@tonic-gate cs->cr = crdup(cs->basecr); 30417c478bd9Sstevel@tonic-gate 30427c478bd9Sstevel@tonic-gate oldvp = cs->vp; 30437c478bd9Sstevel@tonic-gate cs->vp = vp; 30447c478bd9Sstevel@tonic-gate is_newvp = TRUE; 30457c478bd9Sstevel@tonic-gate 30467c478bd9Sstevel@tonic-gate stat = call_checkauth4(cs, req); 30477c478bd9Sstevel@tonic-gate if (stat != NFS4_OK) { 30487c478bd9Sstevel@tonic-gate VN_RELE(cs->vp); 30497c478bd9Sstevel@tonic-gate cs->vp = oldvp; 30507c478bd9Sstevel@tonic-gate return (stat); 30517c478bd9Sstevel@tonic-gate } 30527c478bd9Sstevel@tonic-gate } 30537c478bd9Sstevel@tonic-gate 305445916cd2Sjpk /* 305545916cd2Sjpk * After various NFS checks, do a label check on the path 305645916cd2Sjpk * component. The label on this path should either be the 305745916cd2Sjpk * global zone's label or a zone's label. We are only 305845916cd2Sjpk * interested in the zone's label because exported files 305945916cd2Sjpk * in global zone is accessible (though read-only) to 306045916cd2Sjpk * clients. The exportability/visibility check is already 306145916cd2Sjpk * done before reaching this code. 306245916cd2Sjpk */ 306345916cd2Sjpk if (is_system_labeled()) { 306445916cd2Sjpk bslabel_t *clabel; 306545916cd2Sjpk 306645916cd2Sjpk ASSERT(req->rq_label != NULL); 306745916cd2Sjpk clabel = req->rq_label; 306845916cd2Sjpk DTRACE_PROBE2(tx__rfs4__log__info__oplookup__clabel, char *, 306945916cd2Sjpk "got client label from request(1)", struct svc_req *, req); 307045916cd2Sjpk 307145916cd2Sjpk if (!blequal(&l_admin_low->tsl_label, clabel)) { 3072bd6f1640SJarrett Lu if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK, 3073bd6f1640SJarrett Lu cs->exi)) { 307445916cd2Sjpk error = EACCES; 307545916cd2Sjpk goto err_out; 307645916cd2Sjpk } 307745916cd2Sjpk } else { 307845916cd2Sjpk /* 307945916cd2Sjpk * We grant access to admin_low label clients 308045916cd2Sjpk * only if the client is trusted, i.e. also 308145916cd2Sjpk * running Solaris Trusted Extension. 308245916cd2Sjpk */ 308345916cd2Sjpk struct sockaddr *ca; 308445916cd2Sjpk int addr_type; 308545916cd2Sjpk void *ipaddr; 308645916cd2Sjpk tsol_tpc_t *tp; 308745916cd2Sjpk 308845916cd2Sjpk ca = (struct sockaddr *)svc_getrpccaller( 308945916cd2Sjpk req->rq_xprt)->buf; 309045916cd2Sjpk if (ca->sa_family == AF_INET) { 309145916cd2Sjpk addr_type = IPV4_VERSION; 309245916cd2Sjpk ipaddr = &((struct sockaddr_in *)ca)->sin_addr; 309345916cd2Sjpk } else if (ca->sa_family == AF_INET6) { 309445916cd2Sjpk addr_type = IPV6_VERSION; 309545916cd2Sjpk ipaddr = &((struct sockaddr_in6 *) 309645916cd2Sjpk ca)->sin6_addr; 309745916cd2Sjpk } 309845916cd2Sjpk tp = find_tpc(ipaddr, addr_type, B_FALSE); 309945916cd2Sjpk if (tp == NULL || tp->tpc_tp.tp_doi != 310045916cd2Sjpk l_admin_low->tsl_doi || tp->tpc_tp.host_type != 310145916cd2Sjpk SUN_CIPSO) { 310203986916Sjarrett if (tp != NULL) 310303986916Sjarrett TPC_RELE(tp); 310445916cd2Sjpk error = EACCES; 310545916cd2Sjpk goto err_out; 310645916cd2Sjpk } 310703986916Sjarrett TPC_RELE(tp); 310845916cd2Sjpk } 310945916cd2Sjpk } 311045916cd2Sjpk 31117c478bd9Sstevel@tonic-gate error = makefh4(&cs->fh, vp, cs->exi); 31127c478bd9Sstevel@tonic-gate 311345916cd2Sjpk err_out: 31147c478bd9Sstevel@tonic-gate if (error) { 31157c478bd9Sstevel@tonic-gate if (is_newvp) { 31167c478bd9Sstevel@tonic-gate VN_RELE(cs->vp); 31177c478bd9Sstevel@tonic-gate cs->vp = oldvp; 31187c478bd9Sstevel@tonic-gate } else 31197c478bd9Sstevel@tonic-gate VN_RELE(vp); 31207c478bd9Sstevel@tonic-gate return (puterrno4(error)); 31217c478bd9Sstevel@tonic-gate } 31227c478bd9Sstevel@tonic-gate 31237c478bd9Sstevel@tonic-gate if (!is_newvp) { 31247c478bd9Sstevel@tonic-gate if (cs->vp) 31257c478bd9Sstevel@tonic-gate VN_RELE(cs->vp); 31267c478bd9Sstevel@tonic-gate cs->vp = vp; 31277c478bd9Sstevel@tonic-gate } else if (oldvp) 31287c478bd9Sstevel@tonic-gate VN_RELE(oldvp); 31297c478bd9Sstevel@tonic-gate 31307c478bd9Sstevel@tonic-gate /* 31317c478bd9Sstevel@tonic-gate * if did lookup on attrdir and didn't lookup .., set named 31327c478bd9Sstevel@tonic-gate * attr fh flag 31337c478bd9Sstevel@tonic-gate */ 31347c478bd9Sstevel@tonic-gate if (attrdir && ! dotdot) 31357c478bd9Sstevel@tonic-gate set_fh4_flag(&cs->fh, FH4_NAMEDATTR); 31367c478bd9Sstevel@tonic-gate 31377c478bd9Sstevel@tonic-gate /* Assume false for now, open proc will set this */ 31387c478bd9Sstevel@tonic-gate cs->mandlock = FALSE; 31397c478bd9Sstevel@tonic-gate 31407c478bd9Sstevel@tonic-gate return (NFS4_OK); 31417c478bd9Sstevel@tonic-gate } 31427c478bd9Sstevel@tonic-gate 31437c478bd9Sstevel@tonic-gate /* ARGSUSED */ 31447c478bd9Sstevel@tonic-gate static void 31457c478bd9Sstevel@tonic-gate rfs4_op_lookup(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req, 31467c478bd9Sstevel@tonic-gate struct compound_state *cs) 31477c478bd9Sstevel@tonic-gate { 31487c478bd9Sstevel@tonic-gate LOOKUP4args *args = &argop->nfs_argop4_u.oplookup; 31497c478bd9Sstevel@tonic-gate LOOKUP4res *resp = &resop->nfs_resop4_u.oplookup; 31507c478bd9Sstevel@tonic-gate char *nm; 31517c478bd9Sstevel@tonic-gate uint_t len; 3152b89a8333Snatalie li - Sun Microsystems - Irvine United States struct sockaddr *ca; 3153b89a8333Snatalie li - Sun Microsystems - Irvine United States char *name = NULL; 315415721462SDaniil Lunev nfsstat4 status; 31557c478bd9Sstevel@tonic-gate 3156f3b585ceSsamf DTRACE_NFSV4_2(op__lookup__start, struct compound_state *, cs, 3157f3b585ceSsamf LOOKUP4args *, args); 3158f3b585ceSsamf 31597c478bd9Sstevel@tonic-gate if (cs->vp == NULL) { 31607c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE; 3161f3b585ceSsamf goto out; 31627c478bd9Sstevel@tonic-gate } 31637c478bd9Sstevel@tonic-gate 31647c478bd9Sstevel@tonic-gate if (cs->vp->v_type == VLNK) { 31657c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_SYMLINK; 3166f3b585ceSsamf goto out; 31677c478bd9Sstevel@tonic-gate } 31687c478bd9Sstevel@tonic-gate 31697c478bd9Sstevel@tonic-gate if (cs->vp->v_type != VDIR) { 31707c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_NOTDIR; 3171f3b585ceSsamf goto out; 31727c478bd9Sstevel@tonic-gate } 31737c478bd9Sstevel@tonic-gate 317415721462SDaniil Lunev status = utf8_dir_verify(&args->objname); 317515721462SDaniil Lunev if (status != NFS4_OK) { 317615721462SDaniil Lunev *cs->statusp = resp->status = status; 3177f3b585ceSsamf goto out; 31787c478bd9Sstevel@tonic-gate } 31797c478bd9Sstevel@tonic-gate 31807c478bd9Sstevel@tonic-gate nm = utf8_to_str(&args->objname, &len, NULL); 31817c478bd9Sstevel@tonic-gate if (nm == NULL) { 31827c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_INVAL; 3183f3b585ceSsamf goto out; 31847c478bd9Sstevel@tonic-gate } 31857c478bd9Sstevel@tonic-gate 31867c478bd9Sstevel@tonic-gate if (len > MAXNAMELEN) { 31877c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_NAMETOOLONG; 31887c478bd9Sstevel@tonic-gate kmem_free(nm, len); 3189f3b585ceSsamf goto out; 31907c478bd9Sstevel@tonic-gate } 31917c478bd9Sstevel@tonic-gate 3192b89a8333Snatalie li - Sun Microsystems - Irvine United States ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 3193b89a8333Snatalie li - Sun Microsystems - Irvine United States name = nfscmd_convname(ca, cs->exi, nm, NFSCMD_CONV_INBOUND, 3194b89a8333Snatalie li - Sun Microsystems - Irvine United States MAXPATHLEN + 1); 3195b89a8333Snatalie li - Sun Microsystems - Irvine United States 3196b89a8333Snatalie li - Sun Microsystems - Irvine United States if (name == NULL) { 3197b89a8333Snatalie li - Sun Microsystems - Irvine United States *cs->statusp = resp->status = NFS4ERR_INVAL; 3198b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(nm, len); 3199b89a8333Snatalie li - Sun Microsystems - Irvine United States goto out; 3200b89a8333Snatalie li - Sun Microsystems - Irvine United States } 3201b89a8333Snatalie li - Sun Microsystems - Irvine United States 3202593cc11bSJan Kryl *cs->statusp = resp->status = do_rfs4_op_lookup(name, req, cs); 3203b89a8333Snatalie li - Sun Microsystems - Irvine United States 3204b89a8333Snatalie li - Sun Microsystems - Irvine United States if (name != nm) 3205b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(name, MAXPATHLEN + 1); 32067c478bd9Sstevel@tonic-gate kmem_free(nm, len); 3207f3b585ceSsamf 3208f3b585ceSsamf out: 3209f3b585ceSsamf DTRACE_NFSV4_2(op__lookup__done, struct compound_state *, cs, 3210f3b585ceSsamf LOOKUP4res *, resp); 32117c478bd9Sstevel@tonic-gate } 32127c478bd9Sstevel@tonic-gate 32137c478bd9Sstevel@tonic-gate /* ARGSUSED */ 32147c478bd9Sstevel@tonic-gate static void 32157c478bd9Sstevel@tonic-gate rfs4_op_lookupp(nfs_argop4 *args, nfs_resop4 *resop, struct svc_req *req, 32167c478bd9Sstevel@tonic-gate struct compound_state *cs) 32177c478bd9Sstevel@tonic-gate { 32187c478bd9Sstevel@tonic-gate LOOKUPP4res *resp = &resop->nfs_resop4_u.oplookupp; 32197c478bd9Sstevel@tonic-gate 3220f3b585ceSsamf DTRACE_NFSV4_1(op__lookupp__start, struct compound_state *, cs); 3221f3b585ceSsamf 32227c478bd9Sstevel@tonic-gate if (cs->vp == NULL) { 32237c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE; 3224f3b585ceSsamf goto out; 32257c478bd9Sstevel@tonic-gate } 32267c478bd9Sstevel@tonic-gate 32277c478bd9Sstevel@tonic-gate if (cs->vp->v_type != VDIR) { 32287c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_NOTDIR; 3229f3b585ceSsamf goto out; 32307c478bd9Sstevel@tonic-gate } 32317c478bd9Sstevel@tonic-gate 3232593cc11bSJan Kryl *cs->statusp = resp->status = do_rfs4_op_lookup("..", req, cs); 32337c478bd9Sstevel@tonic-gate 32347c478bd9Sstevel@tonic-gate /* 32357c478bd9Sstevel@tonic-gate * From NFSV4 Specification, LOOKUPP should not check for 32367c478bd9Sstevel@tonic-gate * NFS4ERR_WRONGSEC. Retrun NFS4_OK instead. 32377c478bd9Sstevel@tonic-gate */ 32387c478bd9Sstevel@tonic-gate if (resp->status == NFS4ERR_WRONGSEC) { 32397c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4_OK; 32407c478bd9Sstevel@tonic-gate } 3241f3b585ceSsamf 3242f3b585ceSsamf out: 3243f3b585ceSsamf DTRACE_NFSV4_2(op__lookupp__done, struct compound_state *, cs, 3244f3b585ceSsamf LOOKUPP4res *, resp); 32457c478bd9Sstevel@tonic-gate } 32467c478bd9Sstevel@tonic-gate 32477c478bd9Sstevel@tonic-gate 32487c478bd9Sstevel@tonic-gate /*ARGSUSED2*/ 32497c478bd9Sstevel@tonic-gate static void 32507c478bd9Sstevel@tonic-gate rfs4_op_openattr(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req, 32517c478bd9Sstevel@tonic-gate struct compound_state *cs) 32527c478bd9Sstevel@tonic-gate { 32537c478bd9Sstevel@tonic-gate OPENATTR4args *args = &argop->nfs_argop4_u.opopenattr; 32547c478bd9Sstevel@tonic-gate OPENATTR4res *resp = &resop->nfs_resop4_u.opopenattr; 32557c478bd9Sstevel@tonic-gate vnode_t *avp = NULL; 32567c478bd9Sstevel@tonic-gate int lookup_flags = LOOKUP_XATTR, error; 32577c478bd9Sstevel@tonic-gate int exp_ro = 0; 32587c478bd9Sstevel@tonic-gate 3259f3b585ceSsamf DTRACE_NFSV4_2(op__openattr__start, struct compound_state *, cs, 3260f3b585ceSsamf OPENATTR4args *, args); 3261f3b585ceSsamf 32627c478bd9Sstevel@tonic-gate if (cs->vp == NULL) { 32637c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE; 3264f3b585ceSsamf goto out; 32657c478bd9Sstevel@tonic-gate } 32667c478bd9Sstevel@tonic-gate 3267da6c28aaSamw if ((cs->vp->v_vfsp->vfs_flag & VFS_XATTR) == 0 && 32689660e5cbSJanice Chang !vfs_has_feature(cs->vp->v_vfsp, VFSFT_SYSATTR_VIEWS)) { 3269f3b585ceSsamf *cs->statusp = resp->status = puterrno4(ENOTSUP); 3270f3b585ceSsamf goto out; 32717c478bd9Sstevel@tonic-gate } 32727c478bd9Sstevel@tonic-gate 327393aeed83Smarks /* 327493aeed83Smarks * If file system supports passing ACE mask to VOP_ACCESS then 327593aeed83Smarks * check for ACE_READ_NAMED_ATTRS, otherwise do legacy checks 327693aeed83Smarks */ 327793aeed83Smarks 327893aeed83Smarks if (vfs_has_feature(cs->vp->v_vfsp, VFSFT_ACEMASKONACCESS)) 327993aeed83Smarks error = VOP_ACCESS(cs->vp, ACE_READ_NAMED_ATTRS, 328093aeed83Smarks V_ACE_MASK, cs->cr, NULL); 328193aeed83Smarks else 328293aeed83Smarks error = ((VOP_ACCESS(cs->vp, VREAD, 0, cs->cr, NULL) != 0) && 3283da6c28aaSamw (VOP_ACCESS(cs->vp, VWRITE, 0, cs->cr, NULL) != 0) && 328493aeed83Smarks (VOP_ACCESS(cs->vp, VEXEC, 0, cs->cr, NULL) != 0)); 328593aeed83Smarks 328693aeed83Smarks if (error) { 3287f3b585ceSsamf *cs->statusp = resp->status = puterrno4(EACCES); 3288f3b585ceSsamf goto out; 32897c478bd9Sstevel@tonic-gate } 32907c478bd9Sstevel@tonic-gate 32917c478bd9Sstevel@tonic-gate /* 32927c478bd9Sstevel@tonic-gate * The CREATE_XATTR_DIR VOP flag cannot be specified if 32937c478bd9Sstevel@tonic-gate * the file system is exported read-only -- regardless of 32947c478bd9Sstevel@tonic-gate * createdir flag. Otherwise the attrdir would be created 32957c478bd9Sstevel@tonic-gate * (assuming server fs isn't mounted readonly locally). If 32967c478bd9Sstevel@tonic-gate * VOP_LOOKUP returns ENOENT in this case, the error will 32977c478bd9Sstevel@tonic-gate * be translated into EROFS. ENOSYS is mapped to ENOTSUP 32987c478bd9Sstevel@tonic-gate * because specfs has no VOP_LOOKUP op, so the macro would 32997c478bd9Sstevel@tonic-gate * return ENOSYS. EINVAL is returned by all (current) 33007c478bd9Sstevel@tonic-gate * Solaris file system implementations when any of their 33017c478bd9Sstevel@tonic-gate * restrictions are violated (xattr(dir) can't have xattrdir). 33027c478bd9Sstevel@tonic-gate * Returning NOTSUPP is more appropriate in this case 33037c478bd9Sstevel@tonic-gate * because the object will never be able to have an attrdir. 33047c478bd9Sstevel@tonic-gate */ 33055cb0d679SMarcel Telka if (args->createdir && ! (exp_ro = rdonly4(req, cs))) 33067c478bd9Sstevel@tonic-gate lookup_flags |= CREATE_XATTR_DIR; 33077c478bd9Sstevel@tonic-gate 3308da6c28aaSamw error = VOP_LOOKUP(cs->vp, "", &avp, NULL, lookup_flags, NULL, cs->cr, 3309da6c28aaSamw NULL, NULL, NULL); 33107c478bd9Sstevel@tonic-gate 33117c478bd9Sstevel@tonic-gate if (error) { 33127c478bd9Sstevel@tonic-gate if (error == ENOENT && args->createdir && exp_ro) 3313f3b585ceSsamf *cs->statusp = resp->status = puterrno4(EROFS); 33147c478bd9Sstevel@tonic-gate else if (error == EINVAL || error == ENOSYS) 3315f3b585ceSsamf *cs->statusp = resp->status = puterrno4(ENOTSUP); 3316f3b585ceSsamf else 3317f3b585ceSsamf *cs->statusp = resp->status = puterrno4(error); 3318f3b585ceSsamf goto out; 33197c478bd9Sstevel@tonic-gate } 33207c478bd9Sstevel@tonic-gate 33217c478bd9Sstevel@tonic-gate ASSERT(avp->v_flag & V_XATTRDIR); 33227c478bd9Sstevel@tonic-gate 33237c478bd9Sstevel@tonic-gate error = makefh4(&cs->fh, avp, cs->exi); 33247c478bd9Sstevel@tonic-gate 33257c478bd9Sstevel@tonic-gate if (error) { 33267c478bd9Sstevel@tonic-gate VN_RELE(avp); 3327f3b585ceSsamf *cs->statusp = resp->status = puterrno4(error); 3328f3b585ceSsamf goto out; 33297c478bd9Sstevel@tonic-gate } 33307c478bd9Sstevel@tonic-gate 33317c478bd9Sstevel@tonic-gate VN_RELE(cs->vp); 33327c478bd9Sstevel@tonic-gate cs->vp = avp; 33337c478bd9Sstevel@tonic-gate 33347c478bd9Sstevel@tonic-gate /* 33357c478bd9Sstevel@tonic-gate * There is no requirement for an attrdir fh flag 33367c478bd9Sstevel@tonic-gate * because the attrdir has a vnode flag to distinguish 33377c478bd9Sstevel@tonic-gate * it from regular (non-xattr) directories. The 33387c478bd9Sstevel@tonic-gate * FH4_ATTRDIR flag is set for future sanity checks. 33397c478bd9Sstevel@tonic-gate */ 33407c478bd9Sstevel@tonic-gate set_fh4_flag(&cs->fh, FH4_ATTRDIR); 33417c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4_OK; 33427c478bd9Sstevel@tonic-gate 3343f3b585ceSsamf out: 3344f3b585ceSsamf DTRACE_NFSV4_2(op__openattr__done, struct compound_state *, cs, 3345f3b585ceSsamf OPENATTR4res *, resp); 33467c478bd9Sstevel@tonic-gate } 33477c478bd9Sstevel@tonic-gate 33487c478bd9Sstevel@tonic-gate static int 3349da6c28aaSamw do_io(int direction, vnode_t *vp, struct uio *uio, int ioflag, cred_t *cred, 3350da6c28aaSamw caller_context_t *ct) 33517c478bd9Sstevel@tonic-gate { 33527c478bd9Sstevel@tonic-gate int error; 33537c478bd9Sstevel@tonic-gate int i; 33547c478bd9Sstevel@tonic-gate clock_t delaytime; 33557c478bd9Sstevel@tonic-gate 33567c478bd9Sstevel@tonic-gate delaytime = MSEC_TO_TICK_ROUNDUP(rfs4_lock_delay); 33577c478bd9Sstevel@tonic-gate 33587c478bd9Sstevel@tonic-gate /* 33597c478bd9Sstevel@tonic-gate * Don't block on mandatory locks. If this routine returns 33607c478bd9Sstevel@tonic-gate * EAGAIN, the caller should return NFS4ERR_LOCKED. 33617c478bd9Sstevel@tonic-gate */ 33627c478bd9Sstevel@tonic-gate uio->uio_fmode = FNONBLOCK; 33637c478bd9Sstevel@tonic-gate 33647c478bd9Sstevel@tonic-gate for (i = 0; i < rfs4_maxlock_tries; i++) { 33657c478bd9Sstevel@tonic-gate 33667c478bd9Sstevel@tonic-gate 33677c478bd9Sstevel@tonic-gate if (direction == FREAD) { 3368da6c28aaSamw (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, ct); 3369da6c28aaSamw error = VOP_READ(vp, uio, ioflag, cred, ct); 3370da6c28aaSamw VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, ct); 33717c478bd9Sstevel@tonic-gate } else { 3372da6c28aaSamw (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, ct); 3373da6c28aaSamw error = VOP_WRITE(vp, uio, ioflag, cred, ct); 3374da6c28aaSamw VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, ct); 33757c478bd9Sstevel@tonic-gate } 33767c478bd9Sstevel@tonic-gate 33777c478bd9Sstevel@tonic-gate if (error != EAGAIN) 33787c478bd9Sstevel@tonic-gate break; 33797c478bd9Sstevel@tonic-gate 33807c478bd9Sstevel@tonic-gate if (i < rfs4_maxlock_tries - 1) { 33817c478bd9Sstevel@tonic-gate delay(delaytime); 33827c478bd9Sstevel@tonic-gate delaytime *= 2; 33837c478bd9Sstevel@tonic-gate } 33847c478bd9Sstevel@tonic-gate } 33857c478bd9Sstevel@tonic-gate 33867c478bd9Sstevel@tonic-gate return (error); 33877c478bd9Sstevel@tonic-gate } 33887c478bd9Sstevel@tonic-gate 33897c478bd9Sstevel@tonic-gate /* ARGSUSED */ 33907c478bd9Sstevel@tonic-gate static void 33917c478bd9Sstevel@tonic-gate rfs4_op_read(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req, 33927c478bd9Sstevel@tonic-gate struct compound_state *cs) 33937c478bd9Sstevel@tonic-gate { 33947c478bd9Sstevel@tonic-gate READ4args *args = &argop->nfs_argop4_u.opread; 33957c478bd9Sstevel@tonic-gate READ4res *resp = &resop->nfs_resop4_u.opread; 33967c478bd9Sstevel@tonic-gate int error; 33977c478bd9Sstevel@tonic-gate int verror; 33987c478bd9Sstevel@tonic-gate vnode_t *vp; 33997c478bd9Sstevel@tonic-gate struct vattr va; 3400e36d7b11SSebastien Roy struct iovec iov, *iovp = NULL; 3401e36d7b11SSebastien Roy int iovcnt; 34027c478bd9Sstevel@tonic-gate struct uio uio; 34037c478bd9Sstevel@tonic-gate u_offset_t offset; 34047c478bd9Sstevel@tonic-gate bool_t *deleg = &cs->deleg; 34057c478bd9Sstevel@tonic-gate nfsstat4 stat; 34067c478bd9Sstevel@tonic-gate int in_crit = 0; 3407c242f9a0Schunli zhang - Sun Microsystems - Irvine United States mblk_t *mp = NULL; 34087c478bd9Sstevel@tonic-gate int alloc_err = 0; 3409c242f9a0Schunli zhang - Sun Microsystems - Irvine United States int rdma_used = 0; 3410c242f9a0Schunli zhang - Sun Microsystems - Irvine United States int loaned_buffers; 3411da6c28aaSamw caller_context_t ct; 3412c242f9a0Schunli zhang - Sun Microsystems - Irvine United States struct uio *uiop; 34137c478bd9Sstevel@tonic-gate 3414f3b585ceSsamf DTRACE_NFSV4_2(op__read__start, struct compound_state *, cs, 3415f3b585ceSsamf READ4args, args); 3416f3b585ceSsamf 34177c478bd9Sstevel@tonic-gate vp = cs->vp; 34187c478bd9Sstevel@tonic-gate if (vp == NULL) { 34197c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE; 3420f3b585ceSsamf goto out; 34217c478bd9Sstevel@tonic-gate } 34227c478bd9Sstevel@tonic-gate if (cs->access == CS_ACCESS_DENIED) { 34237c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_ACCESS; 3424f3b585ceSsamf goto out; 34257c478bd9Sstevel@tonic-gate } 34267c478bd9Sstevel@tonic-gate 3427da6c28aaSamw if ((stat = rfs4_check_stateid(FREAD, vp, &args->stateid, FALSE, 3428*f44e1126SVitaliy Gusev deleg, TRUE, &ct, cs)) != NFS4_OK) { 3429da6c28aaSamw *cs->statusp = resp->status = stat; 3430da6c28aaSamw goto out; 3431da6c28aaSamw } 3432da6c28aaSamw 34337c478bd9Sstevel@tonic-gate /* 34347c478bd9Sstevel@tonic-gate * Enter the critical region before calling VOP_RWLOCK 34357c478bd9Sstevel@tonic-gate * to avoid a deadlock with write requests. 34367c478bd9Sstevel@tonic-gate */ 34377c478bd9Sstevel@tonic-gate if (nbl_need_check(vp)) { 34387c478bd9Sstevel@tonic-gate nbl_start_crit(vp, RW_READER); 34397c478bd9Sstevel@tonic-gate in_crit = 1; 3440da6c28aaSamw if (nbl_conflict(vp, NBL_READ, args->offset, args->count, 0, 3441da6c28aaSamw &ct)) { 34427c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_LOCKED; 34437c478bd9Sstevel@tonic-gate goto out; 34447c478bd9Sstevel@tonic-gate } 34457c478bd9Sstevel@tonic-gate } 34467c478bd9Sstevel@tonic-gate 344735bbd688SKaren Rochford if (args->wlist) { 344835bbd688SKaren Rochford if (args->count > clist_len(args->wlist)) { 344935bbd688SKaren Rochford *cs->statusp = resp->status = NFS4ERR_INVAL; 345035bbd688SKaren Rochford goto out; 345135bbd688SKaren Rochford } 3452c242f9a0Schunli zhang - Sun Microsystems - Irvine United States rdma_used = 1; 345335bbd688SKaren Rochford } 3454c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 3455c242f9a0Schunli zhang - Sun Microsystems - Irvine United States /* use loaned buffers for TCP */ 3456c242f9a0Schunli zhang - Sun Microsystems - Irvine United States loaned_buffers = (nfs_loaned_buffers && !rdma_used) ? 1 : 0; 3457c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 34587c478bd9Sstevel@tonic-gate va.va_mask = AT_MODE|AT_SIZE|AT_UID; 3459da6c28aaSamw verror = VOP_GETATTR(vp, &va, 0, cs->cr, &ct); 34607c478bd9Sstevel@tonic-gate 34617c478bd9Sstevel@tonic-gate /* 34627c478bd9Sstevel@tonic-gate * If we can't get the attributes, then we can't do the 34637c478bd9Sstevel@tonic-gate * right access checking. So, we'll fail the request. 34647c478bd9Sstevel@tonic-gate */ 34657c478bd9Sstevel@tonic-gate if (verror) { 34667c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = puterrno4(verror); 34677c478bd9Sstevel@tonic-gate goto out; 34687c478bd9Sstevel@tonic-gate } 34697c478bd9Sstevel@tonic-gate 34707c478bd9Sstevel@tonic-gate if (vp->v_type != VREG) { 34717c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = 34727c478bd9Sstevel@tonic-gate ((vp->v_type == VDIR) ? NFS4ERR_ISDIR : NFS4ERR_INVAL); 34737c478bd9Sstevel@tonic-gate goto out; 34747c478bd9Sstevel@tonic-gate } 34757c478bd9Sstevel@tonic-gate 34767c478bd9Sstevel@tonic-gate if (crgetuid(cs->cr) != va.va_uid && 3477da6c28aaSamw (error = VOP_ACCESS(vp, VREAD, 0, cs->cr, &ct)) && 3478da6c28aaSamw (error = VOP_ACCESS(vp, VEXEC, 0, cs->cr, &ct))) { 34797c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = puterrno4(error); 34807c478bd9Sstevel@tonic-gate goto out; 34817c478bd9Sstevel@tonic-gate } 34827c478bd9Sstevel@tonic-gate 34837c478bd9Sstevel@tonic-gate if (MANDLOCK(vp, va.va_mode)) { /* XXX - V4 supports mand locking */ 34847c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_ACCESS; 34857c478bd9Sstevel@tonic-gate goto out; 34867c478bd9Sstevel@tonic-gate } 34877c478bd9Sstevel@tonic-gate 34887c478bd9Sstevel@tonic-gate offset = args->offset; 34897c478bd9Sstevel@tonic-gate if (offset >= va.va_size) { 34907c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4_OK; 34917c478bd9Sstevel@tonic-gate resp->eof = TRUE; 34927c478bd9Sstevel@tonic-gate resp->data_len = 0; 34937c478bd9Sstevel@tonic-gate resp->data_val = NULL; 34947c478bd9Sstevel@tonic-gate resp->mblk = NULL; 34950a701b1eSRobert Gordon /* RDMA */ 34960a701b1eSRobert Gordon resp->wlist = args->wlist; 34970a701b1eSRobert Gordon resp->wlist_len = resp->data_len; 34987c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4_OK; 3499f837ee4aSSiddheshwar Mahesh if (resp->wlist) 3500f837ee4aSSiddheshwar Mahesh clist_zero_len(resp->wlist); 35017c478bd9Sstevel@tonic-gate goto out; 35027c478bd9Sstevel@tonic-gate } 35037c478bd9Sstevel@tonic-gate 35047c478bd9Sstevel@tonic-gate if (args->count == 0) { 35057c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4_OK; 35067c478bd9Sstevel@tonic-gate resp->eof = FALSE; 35077c478bd9Sstevel@tonic-gate resp->data_len = 0; 35087c478bd9Sstevel@tonic-gate resp->data_val = NULL; 35097c478bd9Sstevel@tonic-gate resp->mblk = NULL; 35100a701b1eSRobert Gordon /* RDMA */ 35110a701b1eSRobert Gordon resp->wlist = args->wlist; 35120a701b1eSRobert Gordon resp->wlist_len = resp->data_len; 3513f837ee4aSSiddheshwar Mahesh if (resp->wlist) 3514f837ee4aSSiddheshwar Mahesh clist_zero_len(resp->wlist); 35157c478bd9Sstevel@tonic-gate goto out; 35167c478bd9Sstevel@tonic-gate } 35177c478bd9Sstevel@tonic-gate 35187c478bd9Sstevel@tonic-gate /* 35197c478bd9Sstevel@tonic-gate * Do not allocate memory more than maximum allowed 35207c478bd9Sstevel@tonic-gate * transfer size 35217c478bd9Sstevel@tonic-gate */ 35227c478bd9Sstevel@tonic-gate if (args->count > rfs4_tsize(req)) 35237c478bd9Sstevel@tonic-gate args->count = rfs4_tsize(req); 35247c478bd9Sstevel@tonic-gate 3525c242f9a0Schunli zhang - Sun Microsystems - Irvine United States if (loaned_buffers) { 3526c242f9a0Schunli zhang - Sun Microsystems - Irvine United States uiop = (uio_t *)rfs_setup_xuio(vp); 3527c242f9a0Schunli zhang - Sun Microsystems - Irvine United States ASSERT(uiop != NULL); 3528c242f9a0Schunli zhang - Sun Microsystems - Irvine United States uiop->uio_segflg = UIO_SYSSPACE; 3529c242f9a0Schunli zhang - Sun Microsystems - Irvine United States uiop->uio_loffset = args->offset; 3530c242f9a0Schunli zhang - Sun Microsystems - Irvine United States uiop->uio_resid = args->count; 3531c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 3532c242f9a0Schunli zhang - Sun Microsystems - Irvine United States /* Jump to do the read if successful */ 3533c242f9a0Schunli zhang - Sun Microsystems - Irvine United States if (!VOP_REQZCBUF(vp, UIO_READ, (xuio_t *)uiop, cs->cr, &ct)) { 3534c242f9a0Schunli zhang - Sun Microsystems - Irvine United States /* 3535c242f9a0Schunli zhang - Sun Microsystems - Irvine United States * Need to hold the vnode until after VOP_RETZCBUF() 3536c242f9a0Schunli zhang - Sun Microsystems - Irvine United States * is called. 3537c242f9a0Schunli zhang - Sun Microsystems - Irvine United States */ 3538c242f9a0Schunli zhang - Sun Microsystems - Irvine United States VN_HOLD(vp); 3539c242f9a0Schunli zhang - Sun Microsystems - Irvine United States goto doio_read; 3540c242f9a0Schunli zhang - Sun Microsystems - Irvine United States } 3541c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 3542c242f9a0Schunli zhang - Sun Microsystems - Irvine United States DTRACE_PROBE2(nfss__i__reqzcbuf_failed, int, 3543c242f9a0Schunli zhang - Sun Microsystems - Irvine United States uiop->uio_loffset, int, uiop->uio_resid); 3544c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 3545c242f9a0Schunli zhang - Sun Microsystems - Irvine United States uiop->uio_extflg = 0; 3546c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 3547c242f9a0Schunli zhang - Sun Microsystems - Irvine United States /* failure to setup for zero copy */ 3548c242f9a0Schunli zhang - Sun Microsystems - Irvine United States rfs_free_xuio((void *)uiop); 3549c242f9a0Schunli zhang - Sun Microsystems - Irvine United States loaned_buffers = 0; 3550c242f9a0Schunli zhang - Sun Microsystems - Irvine United States } 3551c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 35527c478bd9Sstevel@tonic-gate /* 35530a701b1eSRobert Gordon * If returning data via RDMA Write, then grab the chunk list. If we 35540a701b1eSRobert Gordon * aren't returning READ data w/RDMA_WRITE, then grab a mblk. 35550a701b1eSRobert Gordon */ 3556c242f9a0Schunli zhang - Sun Microsystems - Irvine United States if (rdma_used) { 35570a701b1eSRobert Gordon mp = NULL; 35580a701b1eSRobert Gordon (void) rdma_get_wchunk(req, &iov, args->wlist); 3559e36d7b11SSebastien Roy uio.uio_iov = &iov; 3560e36d7b11SSebastien Roy uio.uio_iovcnt = 1; 35610a701b1eSRobert Gordon } else { 35620a701b1eSRobert Gordon /* 35637c478bd9Sstevel@tonic-gate * mp will contain the data to be sent out in the read reply. 3564e36d7b11SSebastien Roy * It will be freed after the reply has been sent. 35657c478bd9Sstevel@tonic-gate */ 3566e36d7b11SSebastien Roy mp = rfs_read_alloc(args->count, &iovp, &iovcnt); 35677c478bd9Sstevel@tonic-gate ASSERT(mp != NULL); 35687c478bd9Sstevel@tonic-gate ASSERT(alloc_err == 0); 3569e36d7b11SSebastien Roy uio.uio_iov = iovp; 3570e36d7b11SSebastien Roy uio.uio_iovcnt = iovcnt; 35710a701b1eSRobert Gordon } 35720a701b1eSRobert Gordon 35737c478bd9Sstevel@tonic-gate uio.uio_segflg = UIO_SYSSPACE; 35747c478bd9Sstevel@tonic-gate uio.uio_extflg = UIO_COPY_CACHED; 35757c478bd9Sstevel@tonic-gate uio.uio_loffset = args->offset; 35767c478bd9Sstevel@tonic-gate uio.uio_resid = args->count; 3577c242f9a0Schunli zhang - Sun Microsystems - Irvine United States uiop = &uio; 35787c478bd9Sstevel@tonic-gate 3579c242f9a0Schunli zhang - Sun Microsystems - Irvine United States doio_read: 3580c242f9a0Schunli zhang - Sun Microsystems - Irvine United States error = do_io(FREAD, vp, uiop, 0, cs->cr, &ct); 35817c478bd9Sstevel@tonic-gate 35827c478bd9Sstevel@tonic-gate va.va_mask = AT_SIZE; 3583da6c28aaSamw verror = VOP_GETATTR(vp, &va, 0, cs->cr, &ct); 35847c478bd9Sstevel@tonic-gate 35857c478bd9Sstevel@tonic-gate if (error) { 3586c242f9a0Schunli zhang - Sun Microsystems - Irvine United States if (mp) 3587c242f9a0Schunli zhang - Sun Microsystems - Irvine United States freemsg(mp); 35887c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = puterrno4(error); 35897c478bd9Sstevel@tonic-gate goto out; 35907c478bd9Sstevel@tonic-gate } 35917c478bd9Sstevel@tonic-gate 3592c242f9a0Schunli zhang - Sun Microsystems - Irvine United States /* make mblk using zc buffers */ 3593c242f9a0Schunli zhang - Sun Microsystems - Irvine United States if (loaned_buffers) { 3594c242f9a0Schunli zhang - Sun Microsystems - Irvine United States mp = uio_to_mblk(uiop); 3595c242f9a0Schunli zhang - Sun Microsystems - Irvine United States ASSERT(mp != NULL); 3596c242f9a0Schunli zhang - Sun Microsystems - Irvine United States } 3597c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 35987c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4_OK; 35997c478bd9Sstevel@tonic-gate 3600c242f9a0Schunli zhang - Sun Microsystems - Irvine United States ASSERT(uiop->uio_resid >= 0); 3601c242f9a0Schunli zhang - Sun Microsystems - Irvine United States resp->data_len = args->count - uiop->uio_resid; 36020a701b1eSRobert Gordon if (mp) { 36037c478bd9Sstevel@tonic-gate resp->data_val = (char *)mp->b_datap->db_base; 3604c242f9a0Schunli zhang - Sun Microsystems - Irvine United States rfs_rndup_mblks(mp, resp->data_len, loaned_buffers); 36050a701b1eSRobert Gordon } else { 36060a701b1eSRobert Gordon resp->data_val = (caddr_t)iov.iov_base; 36070a701b1eSRobert Gordon } 3608c242f9a0Schunli zhang - Sun Microsystems - Irvine United States 36097c478bd9Sstevel@tonic-gate resp->mblk = mp; 36107c478bd9Sstevel@tonic-gate 36117c478bd9Sstevel@tonic-gate if (!verror && offset + resp->data_len == va.va_size) 36127c478bd9Sstevel@tonic-gate resp->eof = TRUE; 36137c478bd9Sstevel@tonic-gate else 36147c478bd9Sstevel@tonic-gate resp->eof = FALSE; 36157c478bd9Sstevel@tonic-gate 3616c242f9a0Schunli zhang - Sun Microsystems - Irvine United States if (rdma_used) { 36170a701b1eSRobert Gordon if (!rdma_setup_read_data4(args, resp)) { 36180a701b1eSRobert Gordon *cs->statusp = resp->status = NFS4ERR_INVAL; 36190a701b1eSRobert Gordon } 36200a701b1eSRobert Gordon } else { 36210a701b1eSRobert Gordon resp->wlist = NULL; 36220a701b1eSRobert Gordon } 36230a701b1eSRobert Gordon 36247c478bd9Sstevel@tonic-gate out: 36257c478bd9Sstevel@tonic-gate if (in_crit) 36267c478bd9Sstevel@tonic-gate nbl_end_crit(vp); 3627f3b585ceSsamf 3628e36d7b11SSebastien Roy if (iovp != NULL) 3629e36d7b11SSebastien Roy kmem_free(iovp, iovcnt * sizeof (struct iovec)); 3630e36d7b11SSebastien Roy 3631f3b585ceSsamf DTRACE_NFSV4_2(op__read__done, struct compound_state *, cs, 3632f3b585ceSsamf READ4res *, resp); 36337c478bd9Sstevel@tonic-gate } 36347c478bd9Sstevel@tonic-gate 36357c478bd9Sstevel@tonic-gate static void 36367c478bd9Sstevel@tonic-gate rfs4_op_read_free(nfs_resop4 *resop) 36377c478bd9Sstevel@tonic-gate { 36387c478bd9Sstevel@tonic-gate READ4res *resp = &resop->nfs_resop4_u.opread; 36397c478bd9Sstevel@tonic-gate 36407c478bd9Sstevel@tonic-gate if (resp->status == NFS4_OK && resp->mblk != NULL) { 3641c242f9a0Schunli zhang - Sun Microsystems - Irvine United States freemsg(resp->mblk); 36427c478bd9Sstevel@tonic-gate resp->mblk = NULL; 36437c478bd9Sstevel@tonic-gate resp->data_val = NULL; 36447c478bd9Sstevel@tonic-gate resp->data_len = 0; 36457c478bd9Sstevel@tonic-gate } 36467c478bd9Sstevel@tonic-gate } 36477c478bd9Sstevel@tonic-gate 36487c478bd9Sstevel@tonic-gate static void 36497c478bd9Sstevel@tonic-gate rfs4_op_readdir_free(nfs_resop4 * resop) 36507c478bd9Sstevel@tonic-gate { 36517c478bd9Sstevel@tonic-gate READDIR4res *resp = &resop->nfs_resop4_u.opreaddir; 36527c478bd9Sstevel@tonic-gate 36537c478bd9Sstevel@tonic-gate if (resp->status == NFS4_OK && resp->mblk != NULL) { 36547c478bd9Sstevel@tonic-gate freeb(resp->mblk); 36557c478bd9Sstevel@tonic-gate resp->mblk = NULL; 36567c478bd9Sstevel@tonic-gate resp->data_len = 0; 36577c478bd9Sstevel@tonic-gate } 36587c478bd9Sstevel@tonic-gate } 36597c478bd9Sstevel@tonic-gate 36607c478bd9Sstevel@tonic-gate 36617c478bd9Sstevel@tonic-gate /* ARGSUSED */ 36627c478bd9Sstevel@tonic-gate static void 36637c478bd9Sstevel@tonic-gate rfs4_op_putpubfh(nfs_argop4 *args, nfs_resop4 *resop, struct svc_req *req, 36647c478bd9Sstevel@tonic-gate struct compound_state *cs) 36657c478bd9Sstevel@tonic-gate { 36667c478bd9Sstevel@tonic-gate PUTPUBFH4res *resp = &resop->nfs_resop4_u.opputpubfh; 36677c478bd9Sstevel@tonic-gate int error; 36687c478bd9Sstevel@tonic-gate vnode_t *vp; 36697c478bd9Sstevel@tonic-gate struct exportinfo *exi, *sav_exi; 36707c478bd9Sstevel@tonic-gate nfs_fh4_fmt_t *fh_fmtp; 36710dfe541eSEvan Layton nfs_export_t *ne = nfs_get_export(); 36727c478bd9Sstevel@tonic-gate 3673f3b585ceSsamf DTRACE_NFSV4_1(op__putpubfh__start, struct compound_state *, cs); 3674f3b585ceSsamf 36757c478bd9Sstevel@tonic-gate if (cs->vp) { 36767c478bd9Sstevel@tonic-gate VN_RELE(cs->vp); 36777c478bd9Sstevel@tonic-gate cs->vp = NULL; 36787c478bd9Sstevel@tonic-gate } 36797c478bd9Sstevel@tonic-gate 36807c478bd9Sstevel@tonic-gate if (cs->cr) 36817c478bd9Sstevel@tonic-gate crfree(cs->cr); 36827c478bd9Sstevel@tonic-gate 36837c478bd9Sstevel@tonic-gate cs->cr = crdup(cs->basecr); 36847c478bd9Sstevel@tonic-gate 36850dfe541eSEvan Layton vp = ne->exi_public->exi_vp; 36867c478bd9Sstevel@tonic-gate if (vp == NULL) { 36877c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_SERVERFAULT; 3688f3b585ceSsamf goto out; 36897c478bd9Sstevel@tonic-gate } 36907c478bd9Sstevel@tonic-gate 36910dfe541eSEvan Layton error = makefh4(&cs->fh, vp, ne->exi_public); 36927c478bd9Sstevel@tonic-gate if (error != 0) { 36937c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = puterrno4(error); 3694f3b585ceSsamf goto out; 36957c478bd9Sstevel@tonic-gate } 36967c478bd9Sstevel@tonic-gate sav_exi = cs->exi; 36970dfe541eSEvan Layton if (ne->exi_public == ne->exi_root) { 36987c478bd9Sstevel@tonic-gate /* 36997c478bd9Sstevel@tonic-gate * No filesystem is actually shared public, so we default 37007c478bd9Sstevel@tonic-gate * to exi_root. In this case, we must check whether root 37017c478bd9Sstevel@tonic-gate * is exported. 37027c478bd9Sstevel@tonic-gate */ 37037c478bd9Sstevel@tonic-gate fh_fmtp = (nfs_fh4_fmt_t *)cs->fh.nfs_fh4_val; 37047c478bd9Sstevel@tonic-gate 37057c478bd9Sstevel@tonic-gate /* 37067c478bd9Sstevel@tonic-gate * if root filesystem is exported, the exportinfo struct that we 37077c478bd9Sstevel@tonic-gate * should use is what checkexport4 returns, because root_exi is 37087c478bd9Sstevel@tonic-gate * actually a mostly empty struct. 37097c478bd9Sstevel@tonic-gate */ 37107c478bd9Sstevel@tonic-gate exi = checkexport4(&fh_fmtp->fh4_fsid, 37117c478bd9Sstevel@tonic-gate (fid_t *)&fh_fmtp->fh4_xlen, NULL); 37120dfe541eSEvan Layton cs->exi = ((exi != NULL) ? exi : ne->exi_public); 37137c478bd9Sstevel@tonic-gate } else { 37147c478bd9Sstevel@tonic-gate /* 37157c478bd9Sstevel@tonic-gate * it's a properly shared filesystem 37167c478bd9Sstevel@tonic-gate */ 37170dfe541eSEvan Layton cs->exi = ne->exi_public; 37187c478bd9Sstevel@tonic-gate } 37197c478bd9Sstevel@tonic-gate 3720bd6f1640SJarrett Lu if (is_system_labeled()) { 3721bd6f1640SJarrett Lu bslabel_t *clabel; 3722bd6f1640SJarrett Lu 3723bd6f1640SJarrett Lu ASSERT(req->rq_label != NULL); 3724bd6f1640SJarrett Lu clabel = req->rq_label; 3725bd6f1640SJarrett Lu DTRACE_PROBE2(tx__rfs4__log__info__opputpubfh__clabel, char *, 3726bd6f1640SJarrett Lu "got client label from request(1)", 3727bd6f1640SJarrett Lu struct svc_req *, req); 3728bd6f1640SJarrett Lu if (!blequal(&l_admin_low->tsl_label, clabel)) { 3729bd6f1640SJarrett Lu if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK, 3730bd6f1640SJarrett Lu cs->exi)) { 3731bd6f1640SJarrett Lu *cs->statusp = resp->status = 3732bd6f1640SJarrett Lu NFS4ERR_SERVERFAULT; 3733bd6f1640SJarrett Lu goto out; 3734bd6f1640SJarrett Lu } 3735bd6f1640SJarrett Lu } 3736bd6f1640SJarrett Lu } 3737bd6f1640SJarrett Lu 37387c478bd9Sstevel@tonic-gate VN_HOLD(vp); 37397c478bd9Sstevel@tonic-gate cs->vp = vp; 37407c478bd9Sstevel@tonic-gate 37417c478bd9Sstevel@tonic-gate if ((resp->status = call_checkauth4(cs, req)) != NFS4_OK) { 37427c478bd9Sstevel@tonic-gate VN_RELE(cs->vp); 37437c478bd9Sstevel@tonic-gate cs->vp = NULL; 37447c478bd9Sstevel@tonic-gate cs->exi = sav_exi; 3745f3b585ceSsamf goto out; 37467c478bd9Sstevel@tonic-gate } 37477c478bd9Sstevel@tonic-gate 37487c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4_OK; 3749f3b585ceSsamf out: 3750f3b585ceSsamf DTRACE_NFSV4_2(op__putpubfh__done, struct compound_state *, cs, 3751f3b585ceSsamf PUTPUBFH4res *, resp); 37527c478bd9Sstevel@tonic-gate } 37537c478bd9Sstevel@tonic-gate 37547c478bd9Sstevel@tonic-gate /* 37557c478bd9Sstevel@tonic-gate * XXX - issue with put*fh operations. Suppose /export/home is exported. 37567c478bd9Sstevel@tonic-gate * Suppose an NFS client goes to mount /export/home/joe. If /export, home, 37577c478bd9Sstevel@tonic-gate * or joe have restrictive search permissions, then we shouldn't let 37587c478bd9Sstevel@tonic-gate * the client get a file handle. This is easy to enforce. However, we 37597c478bd9Sstevel@tonic-gate * don't know what security flavor should be used until we resolve the 37607c478bd9Sstevel@tonic-gate * path name. Another complication is uid mapping. If root is 37617c478bd9Sstevel@tonic-gate * the user, then it will be mapped to the anonymous user by default, 37627c478bd9Sstevel@tonic-gate * but we won't know that till we've resolved the path name. And we won't 37637c478bd9Sstevel@tonic-gate * know what the anonymous user is. 37647c478bd9Sstevel@tonic-gate * Luckily, SECINFO is specified to take a full filename. 37657c478bd9Sstevel@tonic-gate * So what we will have to in rfs4_op_lookup is check that flavor of 37667c478bd9Sstevel@tonic-gate * the target object matches that of the request, and if root was the 37677c478bd9Sstevel@tonic-gate * caller, check for the root= and anon= options, and if necessary, 37687c478bd9Sstevel@tonic-gate * repeat the lookup using the right cred_t. But that's not done yet. 37697c478bd9Sstevel@tonic-gate */ 37707c478bd9Sstevel@tonic-gate /* ARGSUSED */ 37717c478bd9Sstevel@tonic-gate static void 37727c478bd9Sstevel@tonic-gate rfs4_op_putfh(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req, 37737c478bd9Sstevel@tonic-gate struct compound_state *cs) 37747c478bd9Sstevel@tonic-gate { 37757c478bd9Sstevel@tonic-gate PUTFH4args *args = &argop->nfs_argop4_u.opputfh; 37767c478bd9Sstevel@tonic-gate PUTFH4res *resp = &resop->nfs_resop4_u.opputfh; 37777c478bd9Sstevel@tonic-gate nfs_fh4_fmt_t *fh_fmtp; 37787c478bd9Sstevel@tonic-gate 3779f3b585ceSsamf DTRACE_NFSV4_2(op__putfh__start, struct compound_state *, cs, 3780f3b585ceSsamf PUTFH4args *, args); 3781f3b585ceSsamf 37827c478bd9Sstevel@tonic-gate if (cs->vp) { 37837c478bd9Sstevel@tonic-gate VN_RELE(cs->vp); 37847c478bd9Sstevel@tonic-gate cs->vp = NULL; 37857c478bd9Sstevel@tonic-gate } 37867c478bd9Sstevel@tonic-gate 37877c478bd9Sstevel@tonic-gate if (cs->cr) { 37887c478bd9Sstevel@tonic-gate crfree(cs->cr); 37897c478bd9Sstevel@tonic-gate cs->cr = NULL; 37907c478bd9Sstevel@tonic-gate } 37917c478bd9Sstevel@tonic-gate 3792f7877f5dSDan McDonald 37937c478bd9Sstevel@tonic-gate if (args->object.nfs_fh4_len < NFS_FH4_LEN) { 37947c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_BADHANDLE; 3795f3b585ceSsamf goto out; 37967c478bd9Sstevel@tonic-gate } 37977c478bd9Sstevel@tonic-gate 37987c478bd9Sstevel@tonic-gate fh_fmtp = (nfs_fh4_fmt_t *)args->object.nfs_fh4_val; 37997c478bd9Sstevel@tonic-gate cs->exi = checkexport4(&fh_fmtp->fh4_fsid, (fid_t *)&fh_fmtp->fh4_xlen, 38007c478bd9Sstevel@tonic-gate NULL); 38017c478bd9Sstevel@tonic-gate 38027c478bd9Sstevel@tonic-gate if (cs->exi == NULL) { 38037c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_STALE; 3804f3b585ceSsamf goto out; 38057c478bd9Sstevel@tonic-gate } 38067c478bd9Sstevel@tonic-gate 38077c478bd9Sstevel@tonic-gate cs->cr = crdup(cs->basecr); 38087c478bd9Sstevel@tonic-gate 38097c478bd9Sstevel@tonic-gate ASSERT(cs->cr != NULL); 38107c478bd9Sstevel@tonic-gate 38117c478bd9Sstevel@tonic-gate if (! (cs->vp = nfs4_fhtovp(&args->object, cs->exi, &resp->status))) { 38127c478bd9Sstevel@tonic-gate *cs->statusp = resp->status; 3813f3b585ceSsamf goto out; 38147c478bd9Sstevel@tonic-gate } 38157c478bd9Sstevel@tonic-gate 38167c478bd9Sstevel@tonic-gate if ((resp->status = call_checkauth4(cs, req)) != NFS4_OK) { 38177c478bd9Sstevel@tonic-gate VN_RELE(cs->vp); 38187c478bd9Sstevel@tonic-gate cs->vp = NULL; 3819f3b585ceSsamf goto out; 38207c478bd9Sstevel@tonic-gate } 38217c478bd9Sstevel@tonic-gate 38227c478bd9Sstevel@tonic-gate nfs_fh4_copy(&args->object, &cs->fh); 38237c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4_OK; 38247c478bd9Sstevel@tonic-gate cs->deleg = FALSE; 3825f3b585ceSsamf 3826f3b585ceSsamf out: 3827f3b585ceSsamf DTRACE_NFSV4_2(op__putfh__done, struct compound_state *, cs, 3828f3b585ceSsamf PUTFH4res *, resp); 38297c478bd9Sstevel@tonic-gate } 38307c478bd9Sstevel@tonic-gate 38317c478bd9Sstevel@tonic-gate /* ARGSUSED */ 38327c478bd9Sstevel@tonic-gate static void 38337c478bd9Sstevel@tonic-gate rfs4_op_putrootfh(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req, 38347c478bd9Sstevel@tonic-gate struct compound_state *cs) 38357c478bd9Sstevel@tonic-gate { 38367c478bd9Sstevel@tonic-gate PUTROOTFH4res *resp = &resop->nfs_resop4_u.opputrootfh; 38377c478bd9Sstevel@tonic-gate int error; 38387c478bd9Sstevel@tonic-gate fid_t fid; 38397c478bd9Sstevel@tonic-gate struct exportinfo *exi, *sav_exi; 38407c478bd9Sstevel@tonic-gate 3841f3b585ceSsamf DTRACE_NFSV4_1(op__putrootfh__start, struct compound_state *, cs); 3842f3b585ceSsamf 38437c478bd9Sstevel@tonic-gate if (cs->vp) { 38447c478bd9Sstevel@tonic-gate VN_RELE(cs->vp); 38457c478bd9Sstevel@tonic-gate cs->vp = NULL; 38467c478bd9Sstevel@tonic-gate } 38477c478bd9Sstevel@tonic-gate 38487c478bd9Sstevel@tonic-gate if (cs->cr) 38497c478bd9Sstevel@tonic-gate crfree(cs->cr); 38507c478bd9Sstevel@tonic-gate 38517c478bd9Sstevel@tonic-gate cs->cr = crdup(cs->basecr); 38527c478bd9Sstevel@tonic-gate 38537c478bd9Sstevel@tonic-gate /* 38547c478bd9Sstevel@tonic-gate * Using rootdir, the system root vnode, 38557c478bd9Sstevel@tonic-gate * get its fid. 38567c478bd9Sstevel@tonic-gate */ 38577c478bd9Sstevel@tonic-gate bzero(&fid, sizeof (fid)); 38587c478bd9Sstevel@tonic-gate fid.fid_len = MAXFIDSZ; 38590dfe541eSEvan Layton error = vop_fid_pseudo(ZONE_ROOTVP(), &fid); 38607c478bd9Sstevel@tonic-gate if (error != 0) { 38617c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = puterrno4(error); 3862f3b585ceSsamf goto out; 38637c478bd9Sstevel@tonic-gate } 38647c478bd9Sstevel@tonic-gate 38657c478bd9Sstevel@tonic-gate /* 38667c478bd9Sstevel@tonic-gate * Then use the root fsid & fid it to find out if it's exported 38677c478bd9Sstevel@tonic-gate * 38687c478bd9Sstevel@tonic-gate * If the server root isn't exported directly, then 38697c478bd9Sstevel@tonic-gate * it should at least be a pseudo export based on 38707c478bd9Sstevel@tonic-gate * one or more exports further down in the server's 38717c478bd9Sstevel@tonic-gate * file tree. 38727c478bd9Sstevel@tonic-gate */ 38730dfe541eSEvan Layton exi = checkexport4(&ZONE_ROOTVP()->v_vfsp->vfs_fsid, &fid, NULL); 38747c478bd9Sstevel@tonic-gate if (exi == NULL || exi->exi_export.ex_flags & EX_PUBLIC) { 38757c478bd9Sstevel@tonic-gate NFS4_DEBUG(rfs4_debug, 38767c478bd9Sstevel@tonic-gate (CE_WARN, "rfs4_op_putrootfh: export check failure")); 38777c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_SERVERFAULT; 3878f3b585ceSsamf goto out; 38797c478bd9Sstevel@tonic-gate } 38807c478bd9Sstevel@tonic-gate 38817c478bd9Sstevel@tonic-gate /* 38827c478bd9Sstevel@tonic-gate * Now make a filehandle based on the root 38837c478bd9Sstevel@tonic-gate * export and root vnode. 38847c478bd9Sstevel@tonic-gate */ 38850dfe541eSEvan Layton error = makefh4(&cs->fh, ZONE_ROOTVP(), exi); 38867c478bd9Sstevel@tonic-gate if (error != 0) { 38877c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = puterrno4(error); 3888f3b585ceSsamf goto out; 38897c478bd9Sstevel@tonic-gate } 38907c478bd9Sstevel@tonic-gate 38917c478bd9Sstevel@tonic-gate sav_exi = cs->exi; 38927c478bd9Sstevel@tonic-gate cs->exi = exi; 38937c478bd9Sstevel@tonic-gate 38940dfe541eSEvan Layton VN_HOLD(ZONE_ROOTVP()); 38950dfe541eSEvan Layton cs->vp = ZONE_ROOTVP(); 38967c478bd9Sstevel@tonic-gate 38977c478bd9Sstevel@tonic-gate if ((resp->status = call_checkauth4(cs, req)) != NFS4_OK) { 38980dfe541eSEvan Layton VN_RELE(cs->vp); 38997c478bd9Sstevel@tonic-gate cs->vp = NULL; 39007c478bd9Sstevel@tonic-gate cs->exi = sav_exi; 3901f3b585ceSsamf goto out; 39027c478bd9Sstevel@tonic-gate } 39037c478bd9Sstevel@tonic-gate 39047c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4_OK; 39057c478bd9Sstevel@tonic-gate cs->deleg = FALSE; 3906f3b585ceSsamf out: 3907f3b585ceSsamf DTRACE_NFSV4_2(op__putrootfh__done, struct compound_state *, cs, 3908f3b585ceSsamf PUTROOTFH4res *, resp); 39097c478bd9Sstevel@tonic-gate } 39107c478bd9Sstevel@tonic-gate 39117c478bd9Sstevel@tonic-gate /* 39127c478bd9Sstevel@tonic-gate * readlink: args: CURRENT_FH. 39137c478bd9Sstevel@tonic-gate * res: status. If success - CURRENT_FH unchanged, return linktext. 39147c478bd9Sstevel@tonic-gate */ 39157c478bd9Sstevel@tonic-gate 39167c478bd9Sstevel@tonic-gate /* ARGSUSED */ 39177c478bd9Sstevel@tonic-gate static void 39187c478bd9Sstevel@tonic-gate rfs4_op_readlink(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req, 39197c478bd9Sstevel@tonic-gate struct compound_state *cs) 39207c478bd9Sstevel@tonic-gate { 39217c478bd9Sstevel@tonic-gate READLINK4res *resp = &resop->nfs_resop4_u.opreadlink; 39227c478bd9Sstevel@tonic-gate int error; 39237c478bd9Sstevel@tonic-gate vnode_t *vp; 39247c478bd9Sstevel@tonic-gate struct iovec iov; 39257c478bd9Sstevel@tonic-gate struct vattr va; 39267c478bd9Sstevel@tonic-gate struct uio uio; 39277c478bd9Sstevel@tonic-gate char *data; 3928b89a8333Snatalie li - Sun Microsystems - Irvine United States struct sockaddr *ca; 3929b89a8333Snatalie li - Sun Microsystems - Irvine United States char *name = NULL; 39302f172c55SRobert Thurlow int is_referral; 39317c478bd9Sstevel@tonic-gate 3932f3b585ceSsamf DTRACE_NFSV4_1(op__readlink__start, struct compound_state *, cs); 3933f3b585ceSsamf 39347c478bd9Sstevel@tonic-gate /* CURRENT_FH: directory */ 39357c478bd9Sstevel@tonic-gate vp = cs->vp; 39367c478bd9Sstevel@tonic-gate if (vp == NULL) { 39377c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE; 3938f3b585ceSsamf goto out; 39397c478bd9Sstevel@tonic-gate } 39407c478bd9Sstevel@tonic-gate 39417c478bd9Sstevel@tonic-gate if (cs->access == CS_ACCESS_DENIED) { 39427c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_ACCESS; 3943f3b585ceSsamf goto out; 39447c478bd9Sstevel@tonic-gate } 39457c478bd9Sstevel@tonic-gate 39462f172c55SRobert Thurlow /* Is it a referral? */ 39472f172c55SRobert Thurlow if (vn_is_nfs_reparse(vp, cs->cr) && client_is_downrev(req)) { 39482f172c55SRobert Thurlow 39492f172c55SRobert Thurlow is_referral = 1; 39502f172c55SRobert Thurlow 39512f172c55SRobert Thurlow } else { 39522f172c55SRobert Thurlow 39532f172c55SRobert Thurlow is_referral = 0; 39542f172c55SRobert Thurlow 39557c478bd9Sstevel@tonic-gate if (vp->v_type == VDIR) { 39567c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_ISDIR; 3957f3b585ceSsamf goto out; 39587c478bd9Sstevel@tonic-gate } 39597c478bd9Sstevel@tonic-gate 39607c478bd9Sstevel@tonic-gate if (vp->v_type != VLNK) { 39617c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_INVAL; 3962f3b585ceSsamf goto out; 39637c478bd9Sstevel@tonic-gate } 39647c478bd9Sstevel@tonic-gate 39652f172c55SRobert Thurlow } 39662f172c55SRobert Thurlow 39677c478bd9Sstevel@tonic-gate va.va_mask = AT_MODE; 3968da6c28aaSamw error = VOP_GETATTR(vp, &va, 0, cs->cr, NULL); 39697c478bd9Sstevel@tonic-gate if (error) { 39707c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = puterrno4(error); 3971f3b585ceSsamf goto out; 39727c478bd9Sstevel@tonic-gate } 39737c478bd9Sstevel@tonic-gate 39747c478bd9Sstevel@tonic-gate if (MANDLOCK(vp, va.va_mode)) { 39757c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_ACCESS; 3976f3b585ceSsamf goto out; 39777c478bd9Sstevel@tonic-gate } 39787c478bd9Sstevel@tonic-gate 39797c478bd9Sstevel@tonic-gate data = kmem_alloc(MAXPATHLEN + 1, KM_SLEEP); 39807c478bd9Sstevel@tonic-gate 39812f172c55SRobert Thurlow if (is_referral) { 39822f172c55SRobert Thurlow char *s; 39832f172c55SRobert Thurlow size_t strsz; 39840dfe541eSEvan Layton kstat_named_t *stat = 39850dfe541eSEvan Layton cs->exi->exi_ne->ne_globals->svstat[NFS_V4]; 39862f172c55SRobert Thurlow 39872f172c55SRobert Thurlow /* Get an artificial symlink based on a referral */ 39882f172c55SRobert Thurlow s = build_symlink(vp, cs->cr, &strsz); 39890dfe541eSEvan Layton stat[NFS_REFERLINKS].value.ui64++; 39902f172c55SRobert Thurlow DTRACE_PROBE2(nfs4serv__func__referral__reflink, 39912f172c55SRobert Thurlow vnode_t *, vp, char *, s); 39922f172c55SRobert Thurlow if (s == NULL) 39932f172c55SRobert Thurlow error = EINVAL; 39942f172c55SRobert Thurlow else { 39952f172c55SRobert Thurlow error = 0; 39962f172c55SRobert Thurlow (void) strlcpy(data, s, MAXPATHLEN + 1); 39972f172c55SRobert Thurlow kmem_free(s, strsz); 39982f172c55SRobert Thurlow } 39992f172c55SRobert Thurlow 40002f172c55SRobert Thurlow } else { 40012f172c55SRobert Thurlow 40027c478bd9Sstevel@tonic-gate iov.iov_base = data; 40037c478bd9Sstevel@tonic-gate iov.iov_len = MAXPATHLEN; 40047c478bd9Sstevel@tonic-gate uio.uio_iov = &iov; 40057c478bd9Sstevel@tonic-gate uio.uio_iovcnt = 1; 40067c478bd9Sstevel@tonic-gate uio.uio_segflg = UIO_SYSSPACE; 40077c478bd9Sstevel@tonic-gate uio.uio_extflg = UIO_COPY_CACHED; 40087c478bd9Sstevel@tonic-gate uio.uio_loffset = 0; 40097c478bd9Sstevel@tonic-gate uio.uio_resid = MAXPATHLEN; 40107c478bd9Sstevel@tonic-gate 4011da6c28aaSamw error = VOP_READLINK(vp, &uio, cs->cr, NULL); 40127c478bd9Sstevel@tonic-gate 40132f172c55SRobert Thurlow if (!error) 40142f172c55SRobert Thurlow *(data + MAXPATHLEN - uio.uio_resid) = '\0'; 40152f172c55SRobert Thurlow } 40162f172c55SRobert Thurlow 40177c478bd9Sstevel@tonic-gate if (error) { 40187c478bd9Sstevel@tonic-gate kmem_free((caddr_t)data, (uint_t)MAXPATHLEN + 1); 40197c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = puterrno4(error); 4020f3b585ceSsamf goto out; 40217c478bd9Sstevel@tonic-gate } 40227c478bd9Sstevel@tonic-gate 4023b89a8333Snatalie li - Sun Microsystems - Irvine United States ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 4024b89a8333Snatalie li - Sun Microsystems - Irvine United States name = nfscmd_convname(ca, cs->exi, data, NFSCMD_CONV_OUTBOUND, 4025b89a8333Snatalie li - Sun Microsystems - Irvine United States MAXPATHLEN + 1); 4026b89a8333Snatalie li - Sun Microsystems - Irvine United States 4027b89a8333Snatalie li - Sun Microsystems - Irvine United States if (name == NULL) { 4028b89a8333Snatalie li - Sun Microsystems - Irvine United States /* 4029b89a8333Snatalie li - Sun Microsystems - Irvine United States * Even though the conversion failed, we return 4030b89a8333Snatalie li - Sun Microsystems - Irvine United States * something. We just don't translate it. 4031b89a8333Snatalie li - Sun Microsystems - Irvine United States */ 4032b89a8333Snatalie li - Sun Microsystems - Irvine United States name = data; 4033b89a8333Snatalie li - Sun Microsystems - Irvine United States } 4034b89a8333Snatalie li - Sun Microsystems - Irvine United States 40357c478bd9Sstevel@tonic-gate /* 40367c478bd9Sstevel@tonic-gate * treat link name as data 40377c478bd9Sstevel@tonic-gate */ 4038bbe876c0SMarcel Telka (void) str_to_utf8(name, (utf8string *)&resp->link); 40397c478bd9Sstevel@tonic-gate 4040b89a8333Snatalie li - Sun Microsystems - Irvine United States if (name != data) 4041b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(name, MAXPATHLEN + 1); 40427c478bd9Sstevel@tonic-gate kmem_free((caddr_t)data, (uint_t)MAXPATHLEN + 1); 40437c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4_OK; 4044f3b585ceSsamf 4045f3b585ceSsamf out: 4046f3b585ceSsamf DTRACE_NFSV4_2(op__readlink__done, struct compound_state *, cs, 4047f3b585ceSsamf READLINK4res *, resp); 40487c478bd9Sstevel@tonic-gate } 40497c478bd9Sstevel@tonic-gate 40507c478bd9Sstevel@tonic-gate static void 40517c478bd9Sstevel@tonic-gate rfs4_op_readlink_free(nfs_resop4 *resop) 40527c478bd9Sstevel@tonic-gate { 40537c478bd9Sstevel@tonic-gate READLINK4res *resp = &resop->nfs_resop4_u.opreadlink; 4054bbe876c0SMarcel Telka utf8string *symlink = (utf8string *)&resp->link; 40557c478bd9Sstevel@tonic-gate 40567c478bd9Sstevel@tonic-gate if (symlink->utf8string_val) { 40577c478bd9Sstevel@tonic-gate UTF8STRING_FREE(*symlink) 40587c478bd9Sstevel@tonic-gate } 40597c478bd9Sstevel@tonic-gate } 40607c478bd9Sstevel@tonic-gate 40617c478bd9Sstevel@tonic-gate /* 40627c478bd9Sstevel@tonic-gate * release_lockowner: 40637c478bd9Sstevel@tonic-gate * Release any state associated with the supplied 40647c478bd9Sstevel@tonic-gate * lockowner. Note if any lo_state is holding locks we will not 40657c478bd9Sstevel@tonic-gate * rele that lo_state and thus the lockowner will not be destroyed. 40667c478bd9Sstevel@tonic-gate * A client using lock after the lock owner stateid has been released 40677c478bd9Sstevel@tonic-gate * will suffer the consequence of NFS4ERR_BAD_STATEID and would have 40687c478bd9Sstevel@tonic-gate * to reissue the lock with new_lock_owner set to TRUE. 40697c478bd9Sstevel@tonic-gate * args: lock_owner 40707c478bd9Sstevel@tonic-gate * res: status 40717c478bd9Sstevel@tonic-gate */ 40727c478bd9Sstevel@tonic-gate /* ARGSUSED */ 40737c478bd9Sstevel@tonic-gate static void 40747c478bd9Sstevel@tonic-gate rfs4_op_release_lockowner(nfs_argop4 *argop, nfs_resop4 *resop, 40757c478bd9Sstevel@tonic-gate struct svc_req *req, struct compound_state *cs) 40767c478bd9Sstevel@tonic-gate { 40777c478bd9Sstevel@tonic-gate RELEASE_LOCKOWNER4args *ap = &argop->nfs_argop4_u.oprelease_lockowner; 40787c478bd9Sstevel@tonic-gate RELEASE_LOCKOWNER4res *resp = &resop->nfs_resop4_u.oprelease_lockowner; 40797c478bd9Sstevel@tonic-gate rfs4_lockowner_t *lo; 4080d216dff5SRobert Mastors rfs4_openowner_t *oo; 40817c478bd9Sstevel@tonic-gate rfs4_state_t *sp; 40827c478bd9Sstevel@tonic-gate rfs4_lo_state_t *lsp; 40837c478bd9Sstevel@tonic-gate rfs4_client_t *cp; 40847c478bd9Sstevel@tonic-gate bool_t create = FALSE; 40857c478bd9Sstevel@tonic-gate locklist_t *llist; 40867c478bd9Sstevel@tonic-gate sysid_t sysid; 40877c478bd9Sstevel@tonic-gate 4088f3b585ceSsamf DTRACE_NFSV4_2(op__release__lockowner__start, struct compound_state *, 4089f3b585ceSsamf cs, RELEASE_LOCKOWNER4args *, ap); 4090f3b585ceSsamf 40917c478bd9Sstevel@tonic-gate /* Make sure there is a clientid around for this request */ 40927c478bd9Sstevel@tonic-gate cp = rfs4_findclient_by_id(ap->lock_owner.clientid, FALSE); 40937c478bd9Sstevel@tonic-gate 40947c478bd9Sstevel@tonic-gate if (cp == NULL) { 40957c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = 40967c478bd9Sstevel@tonic-gate rfs4_check_clientid(&ap->lock_owner.clientid, 0); 4097f3b585ceSsamf goto out; 40987c478bd9Sstevel@tonic-gate } 40997c478bd9Sstevel@tonic-gate rfs4_client_rele(cp); 41007c478bd9Sstevel@tonic-gate 41017c478bd9Sstevel@tonic-gate lo = rfs4_findlockowner(&ap->lock_owner, &create); 41027c478bd9Sstevel@tonic-gate if (lo == NULL) { 41037c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4_OK; 4104f3b585ceSsamf goto out; 41057c478bd9Sstevel@tonic-gate } 4106d216dff5SRobert Mastors ASSERT(lo->rl_client != NULL); 41077c478bd9Sstevel@tonic-gate 41087c478bd9Sstevel@tonic-gate /* 41097c478bd9Sstevel@tonic-gate * Check for EXPIRED client. If so will reap state with in a lease 41107c478bd9Sstevel@tonic-gate * period or on next set_clientid_confirm step 41117c478bd9Sstevel@tonic-gate */ 4112d216dff5SRobert Mastors if (rfs4_lease_expired(lo->rl_client)) { 41137c478bd9Sstevel@tonic-gate rfs4_lockowner_rele(lo); 41147c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_EXPIRED; 4115f3b585ceSsamf goto out; 41167c478bd9Sstevel@tonic-gate } 41177c478bd9Sstevel@tonic-gate 41187c478bd9Sstevel@tonic-gate /* 41197c478bd9Sstevel@tonic-gate * If no sysid has been assigned, then no locks exist; just return. 41207c478bd9Sstevel@tonic-gate */ 4121d216dff5SRobert Mastors rfs4_dbe_lock(lo->rl_client->rc_dbe); 4122d216dff5SRobert Mastors if (lo->rl_client->rc_sysidt == LM_NOSYSID) { 41237c478bd9Sstevel@tonic-gate rfs4_lockowner_rele(lo); 4124d216dff5SRobert Mastors rfs4_dbe_unlock(lo->rl_client->rc_dbe); 4125f3b585ceSsamf goto out; 41267c478bd9Sstevel@tonic-gate } 41277c478bd9Sstevel@tonic-gate 4128d216dff5SRobert Mastors sysid = lo->rl_client->rc_sysidt; 4129d216dff5SRobert Mastors rfs4_dbe_unlock(lo->rl_client->rc_dbe); 41307c478bd9Sstevel@tonic-gate 41317c478bd9Sstevel@tonic-gate /* 41327c478bd9Sstevel@tonic-gate * Mark the lockowner invalid. 41337c478bd9Sstevel@tonic-gate */ 4134d216dff5SRobert Mastors rfs4_dbe_hide(lo->rl_dbe); 41357c478bd9Sstevel@tonic-gate 41367c478bd9Sstevel@tonic-gate /* 41377c478bd9Sstevel@tonic-gate * sysid-pid pair should now not be used since the lockowner is 41387c478bd9Sstevel@tonic-gate * invalid. If the client were to instantiate the lockowner again 41397c478bd9Sstevel@tonic-gate * it would be assigned a new pid. Thus we can get the list of 41407c478bd9Sstevel@tonic-gate * current locks. 41417c478bd9Sstevel@tonic-gate */ 41427c478bd9Sstevel@tonic-gate 4143d216dff5SRobert Mastors llist = flk_get_active_locks(sysid, lo->rl_pid); 41447c478bd9Sstevel@tonic-gate /* If we are still holding locks fail */ 41457c478bd9Sstevel@tonic-gate if (llist != NULL) { 41467c478bd9Sstevel@tonic-gate 41477c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_LOCKS_HELD; 41487c478bd9Sstevel@tonic-gate 41497c478bd9Sstevel@tonic-gate flk_free_locklist(llist); 41507c478bd9Sstevel@tonic-gate /* 41517c478bd9Sstevel@tonic-gate * We need to unhide the lockowner so the client can 41527c478bd9Sstevel@tonic-gate * try it again. The bad thing here is if the client 41537c478bd9Sstevel@tonic-gate * has a logic error that took it here in the first place 415448bbca81SDaniel Hoffman * they probably have lost accounting of the locks that it 41557c478bd9Sstevel@tonic-gate * is holding. So we may have dangling state until the 41567c478bd9Sstevel@tonic-gate * open owner state is reaped via close. One scenario 41577c478bd9Sstevel@tonic-gate * that could possibly occur is that the client has 41587c478bd9Sstevel@tonic-gate * sent the unlock request(s) in separate threads 41597c478bd9Sstevel@tonic-gate * and has not waited for the replies before sending the 41607c478bd9Sstevel@tonic-gate * RELEASE_LOCKOWNER request. Presumably, it would expect 41617c478bd9Sstevel@tonic-gate * and deal appropriately with NFS4ERR_LOCKS_HELD, by 41627c478bd9Sstevel@tonic-gate * reissuing the request. 41637c478bd9Sstevel@tonic-gate */ 4164d216dff5SRobert Mastors rfs4_dbe_unhide(lo->rl_dbe); 41657c478bd9Sstevel@tonic-gate rfs4_lockowner_rele(lo); 4166f3b585ceSsamf goto out; 41677c478bd9Sstevel@tonic-gate } 41687c478bd9Sstevel@tonic-gate 41697c478bd9Sstevel@tonic-gate /* 41707c478bd9Sstevel@tonic-gate * For the corresponding client we need to check each open 41717c478bd9Sstevel@tonic-gate * owner for any opens that have lockowner state associated 41727c478bd9Sstevel@tonic-gate * with this lockowner. 41737c478bd9Sstevel@tonic-gate */ 41747c478bd9Sstevel@tonic-gate 4175d216dff5SRobert Mastors rfs4_dbe_lock(lo->rl_client->rc_dbe); 4176d216dff5SRobert Mastors for (oo = list_head(&lo->rl_client->rc_openownerlist); oo != NULL; 4177d216dff5SRobert Mastors oo = list_next(&lo->rl_client->rc_openownerlist, oo)) { 41787c478bd9Sstevel@tonic-gate 4179d216dff5SRobert Mastors rfs4_dbe_lock(oo->ro_dbe); 4180d216dff5SRobert Mastors for (sp = list_head(&oo->ro_statelist); sp != NULL; 4181d216dff5SRobert Mastors sp = list_next(&oo->ro_statelist, sp)) { 41827c478bd9Sstevel@tonic-gate 4183d216dff5SRobert Mastors rfs4_dbe_lock(sp->rs_dbe); 4184d216dff5SRobert Mastors for (lsp = list_head(&sp->rs_lostatelist); 4185d216dff5SRobert Mastors lsp != NULL; 4186d216dff5SRobert Mastors lsp = list_next(&sp->rs_lostatelist, lsp)) { 4187d216dff5SRobert Mastors if (lsp->rls_locker == lo) { 4188d216dff5SRobert Mastors rfs4_dbe_lock(lsp->rls_dbe); 4189d216dff5SRobert Mastors rfs4_dbe_invalidate(lsp->rls_dbe); 4190d216dff5SRobert Mastors rfs4_dbe_unlock(lsp->rls_dbe); 41917c478bd9Sstevel@tonic-gate } 41927c478bd9Sstevel@tonic-gate } 4193d216dff5SRobert Mastors rfs4_dbe_unlock(sp->rs_dbe); 41947c478bd9Sstevel@tonic-gate } 4195d216dff5SRobert Mastors rfs4_dbe_unlock(oo->ro_dbe); 41967c478bd9Sstevel@tonic-gate } 4197d216dff5SRobert Mastors rfs4_dbe_unlock(lo->rl_client->rc_dbe); 41987c478bd9Sstevel@tonic-gate 41997c478bd9Sstevel@tonic-gate rfs4_lockowner_rele(lo); 42007c478bd9Sstevel@tonic-gate 42017c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4_OK; 4202f3b585ceSsamf 4203f3b585ceSsamf out: 4204f3b585ceSsamf DTRACE_NFSV4_2(op__release__lockowner__done, struct compound_state *, 4205f3b585ceSsamf cs, RELEASE_LOCKOWNER4res *, resp); 42067c478bd9Sstevel@tonic-gate } 42077c478bd9Sstevel@tonic-gate 42087c478bd9Sstevel@tonic-gate /* 42097c478bd9Sstevel@tonic-gate * short utility function to lookup a file and recall the delegation 42107c478bd9Sstevel@tonic-gate */ 42117c478bd9Sstevel@tonic-gate static rfs4_file_t * 42127c478bd9Sstevel@tonic-gate rfs4_lookup_and_findfile(vnode_t *dvp, char *nm, vnode_t **vpp, 42137c478bd9Sstevel@tonic-gate int *lkup_error, cred_t *cr) 42147c478bd9Sstevel@tonic-gate { 42157c478bd9Sstevel@tonic-gate vnode_t *vp; 42167c478bd9Sstevel@tonic-gate rfs4_file_t *fp = NULL; 42177c478bd9Sstevel@tonic-gate bool_t fcreate = FALSE; 42187c478bd9Sstevel@tonic-gate int error; 42197c478bd9Sstevel@tonic-gate 42207c478bd9Sstevel@tonic-gate if (vpp) 42217c478bd9Sstevel@tonic-gate *vpp = NULL; 42227c478bd9Sstevel@tonic-gate 4223da6c28aaSamw if ((error = VOP_LOOKUP(dvp, nm, &vp, NULL, 0, NULL, cr, NULL, NULL, 4224da6c28aaSamw NULL)) == 0) { 42257c478bd9Sstevel@tonic-gate if (vp->v_type == VREG) 42267c478bd9Sstevel@tonic-gate fp = rfs4_findfile(vp, NULL, &fcreate); 42277c478bd9Sstevel@tonic-gate if (vpp) 42287c478bd9Sstevel@tonic-gate *vpp = vp; 42297c478bd9Sstevel@tonic-gate else 42307c478bd9Sstevel@tonic-gate VN_RELE(vp); 42317c478bd9Sstevel@tonic-gate } 42327c478bd9Sstevel@tonic-gate 42337c478bd9Sstevel@tonic-gate if (lkup_error) 42347c478bd9Sstevel@tonic-gate *lkup_error = error; 42357c478bd9Sstevel@tonic-gate 42367c478bd9Sstevel@tonic-gate return (fp); 42377c478bd9Sstevel@tonic-gate } 42387c478bd9Sstevel@tonic-gate 42397c478bd9Sstevel@tonic-gate /* 42407c478bd9Sstevel@tonic-gate * remove: args: CURRENT_FH: directory; name. 42417c478bd9Sstevel@tonic-gate * res: status. If success - CURRENT_FH unchanged, return change_info 42427c478bd9Sstevel@tonic-gate * for directory. 42437c478bd9Sstevel@tonic-gate */ 42447c478bd9Sstevel@tonic-gate /* ARGSUSED */ 42457c478bd9Sstevel@tonic-gate static void 42467c478bd9Sstevel@tonic-gate rfs4_op_remove(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req, 42477c478bd9Sstevel@tonic-gate struct compound_state *cs) 42487c478bd9Sstevel@tonic-gate { 42497c478bd9Sstevel@tonic-gate REMOVE4args *args = &argop->nfs_argop4_u.opremove; 42507c478bd9Sstevel@tonic-gate REMOVE4res *resp = &resop->nfs_resop4_u.opremove; 42517c478bd9Sstevel@tonic-gate int error; 42527c478bd9Sstevel@tonic-gate vnode_t *dvp, *vp; 42537c478bd9Sstevel@tonic-gate struct vattr bdva, idva, adva; 42547c478bd9Sstevel@tonic-gate char *nm; 42557c478bd9Sstevel@tonic-gate uint_t len; 42567c478bd9Sstevel@tonic-gate rfs4_file_t *fp; 42577c478bd9Sstevel@tonic-gate int in_crit = 0; 425845916cd2Sjpk bslabel_t *clabel; 4259b89a8333Snatalie li - Sun Microsystems - Irvine United States struct sockaddr *ca; 4260b89a8333Snatalie li - Sun Microsystems - Irvine United States char *name = NULL; 426115721462SDaniil Lunev nfsstat4 status; 42627c478bd9Sstevel@tonic-gate 4263f3b585ceSsamf DTRACE_NFSV4_2(op__remove__start, struct compound_state *, cs, 4264f3b585ceSsamf REMOVE4args *, args); 4265f3b585ceSsamf 42667c478bd9Sstevel@tonic-gate /* CURRENT_FH: directory */ 42677c478bd9Sstevel@tonic-gate dvp = cs->vp; 42687c478bd9Sstevel@tonic-gate if (dvp == NULL) { 42697c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE; 4270f3b585ceSsamf goto out; 42717c478bd9Sstevel@tonic-gate } 42727c478bd9Sstevel@tonic-gate 42737c478bd9Sstevel@tonic-gate if (cs->access == CS_ACCESS_DENIED) { 42747c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_ACCESS; 4275f3b585ceSsamf goto out; 42767c478bd9Sstevel@tonic-gate } 42777c478bd9Sstevel@tonic-gate 42787c478bd9Sstevel@tonic-gate /* 42797c478bd9Sstevel@tonic-gate * If there is an unshared filesystem mounted on this vnode, 42807c478bd9Sstevel@tonic-gate * Do not allow to remove anything in this directory. 42817c478bd9Sstevel@tonic-gate */ 42827c478bd9Sstevel@tonic-gate if (vn_ismntpt(dvp)) { 42837c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_ACCESS; 4284f3b585ceSsamf goto out; 42857c478bd9Sstevel@tonic-gate } 42867c478bd9Sstevel@tonic-gate 42877c478bd9Sstevel@tonic-gate if (dvp->v_type != VDIR) { 42887c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_NOTDIR; 4289f3b585ceSsamf goto out; 42907c478bd9Sstevel@tonic-gate } 42917c478bd9Sstevel@tonic-gate 429215721462SDaniil Lunev status = utf8_dir_verify(&args->target); 429315721462SDaniil Lunev if (status != NFS4_OK) { 429415721462SDaniil Lunev *cs->statusp = resp->status = status; 4295f3b585ceSsamf goto out; 42967c478bd9Sstevel@tonic-gate } 42977c478bd9Sstevel@tonic-gate 42987c478bd9Sstevel@tonic-gate /* 42997c478bd9Sstevel@tonic-gate * Lookup the file so that we can check if it's a directory 43007c478bd9Sstevel@tonic-gate */ 43017c478bd9Sstevel@tonic-gate nm = utf8_to_fn(&args->target, &len, NULL); 43027c478bd9Sstevel@tonic-gate if (nm == NULL) { 43037c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_INVAL; 4304f3b585ceSsamf goto out; 43057c478bd9Sstevel@tonic-gate } 43067c478bd9Sstevel@tonic-gate 43077c478bd9Sstevel@tonic-gate if (len > MAXNAMELEN) { 43087c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_NAMETOOLONG; 43097c478bd9Sstevel@tonic-gate kmem_free(nm, len); 4310f3b585ceSsamf goto out; 43117c478bd9Sstevel@tonic-gate } 43127c478bd9Sstevel@tonic-gate 43135cb0d679SMarcel Telka if (rdonly4(req, cs)) { 43147c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_ROFS; 43157c478bd9Sstevel@tonic-gate kmem_free(nm, len); 4316f3b585ceSsamf goto out; 43177c478bd9Sstevel@tonic-gate } 43187c478bd9Sstevel@tonic-gate 4319b89a8333Snatalie li - Sun Microsystems - Irvine United States ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 4320b89a8333Snatalie li - Sun Microsystems - Irvine United States name = nfscmd_convname(ca, cs->exi, nm, NFSCMD_CONV_INBOUND, 4321b89a8333Snatalie li - Sun Microsystems - Irvine United States MAXPATHLEN + 1); 4322b89a8333Snatalie li - Sun Microsystems - Irvine United States 4323b89a8333Snatalie li - Sun Microsystems - Irvine United States if (name == NULL) { 4324b89a8333Snatalie li - Sun Microsystems - Irvine United States *cs->statusp = resp->status = NFS4ERR_INVAL; 4325b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(nm, len); 4326b89a8333Snatalie li - Sun Microsystems - Irvine United States goto out; 4327b89a8333Snatalie li - Sun Microsystems - Irvine United States } 4328b89a8333Snatalie li - Sun Microsystems - Irvine United States 43297c478bd9Sstevel@tonic-gate /* 43307c478bd9Sstevel@tonic-gate * Lookup the file to determine type and while we are see if 43317c478bd9Sstevel@tonic-gate * there is a file struct around and check for delegation. 43327c478bd9Sstevel@tonic-gate * We don't need to acquire va_seq before this lookup, if 43337c478bd9Sstevel@tonic-gate * it causes an update, cinfo.before will not match, which will 43347c478bd9Sstevel@tonic-gate * trigger a cache flush even if atomic is TRUE. 43357c478bd9Sstevel@tonic-gate */ 4336bd3561fbSToomas Soome fp = rfs4_lookup_and_findfile(dvp, name, &vp, &error, cs->cr); 4337bd3561fbSToomas Soome if (fp != NULL) { 43387c478bd9Sstevel@tonic-gate if (rfs4_check_delegated_byfp(FWRITE, fp, TRUE, TRUE, TRUE, 43397c478bd9Sstevel@tonic-gate NULL)) { 43407c478bd9Sstevel@tonic-gate VN_RELE(vp); 43417c478bd9Sstevel@tonic-gate rfs4_file_rele(fp); 43427c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_DELAY; 4343b89a8333Snatalie li - Sun Microsystems - Irvine United States if (nm != name) 4344b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(name, MAXPATHLEN + 1); 43457c478bd9Sstevel@tonic-gate kmem_free(nm, len); 4346f3b585ceSsamf goto out; 43477c478bd9Sstevel@tonic-gate } 43487c478bd9Sstevel@tonic-gate } 43497c478bd9Sstevel@tonic-gate 43507c478bd9Sstevel@tonic-gate /* Didn't find anything to remove */ 43517c478bd9Sstevel@tonic-gate if (vp == NULL) { 43527c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = error; 4353b89a8333Snatalie li - Sun Microsystems - Irvine United States if (nm != name) 4354b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(name, MAXPATHLEN + 1); 43557c478bd9Sstevel@tonic-gate kmem_free(nm, len); 4356f3b585ceSsamf goto out; 43577c478bd9Sstevel@tonic-gate } 43587c478bd9Sstevel@tonic-gate 43597c478bd9Sstevel@tonic-gate if (nbl_need_check(vp)) { 43607c478bd9Sstevel@tonic-gate nbl_start_crit(vp, RW_READER); 43617c478bd9Sstevel@tonic-gate in_crit = 1; 4362da6c28aaSamw if (nbl_conflict(vp, NBL_REMOVE, 0, 0, 0, NULL)) { 43637c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_FILE_OPEN; 4364b89a8333Snatalie li - Sun Microsystems - Irvine United States if (nm != name) 4365b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(name, MAXPATHLEN + 1); 43667c478bd9Sstevel@tonic-gate kmem_free(nm, len); 43677c478bd9Sstevel@tonic-gate nbl_end_crit(vp); 43687c478bd9Sstevel@tonic-gate VN_RELE(vp); 43697c478bd9Sstevel@tonic-gate if (fp) { 43707c478bd9Sstevel@tonic-gate rfs4_clear_dont_grant(fp); 43717c478bd9Sstevel@tonic-gate rfs4_file_rele(fp); 43727c478bd9Sstevel@tonic-gate } 4373f3b585ceSsamf goto out; 43747c478bd9Sstevel@tonic-gate } 43757c478bd9Sstevel@tonic-gate } 43767c478bd9Sstevel@tonic-gate 437745916cd2Sjpk /* check label before allowing removal */ 437845916cd2Sjpk if (is_system_labeled()) { 437945916cd2Sjpk ASSERT(req->rq_label != NULL); 438045916cd2Sjpk clabel = req->rq_label; 438145916cd2Sjpk DTRACE_PROBE2(tx__rfs4__log__info__opremove__clabel, char *, 438245916cd2Sjpk "got client label from request(1)", 438345916cd2Sjpk struct svc_req *, req); 438445916cd2Sjpk if (!blequal(&l_admin_low->tsl_label, clabel)) { 4385bd6f1640SJarrett Lu if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK, 4386bd6f1640SJarrett Lu cs->exi)) { 438745916cd2Sjpk *cs->statusp = resp->status = NFS4ERR_ACCESS; 4388b89a8333Snatalie li - Sun Microsystems - Irvine United States if (name != nm) 4389b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(name, MAXPATHLEN + 1); 439045916cd2Sjpk kmem_free(nm, len); 439145916cd2Sjpk if (in_crit) 439245916cd2Sjpk nbl_end_crit(vp); 439345916cd2Sjpk VN_RELE(vp); 439445916cd2Sjpk if (fp) { 439545916cd2Sjpk rfs4_clear_dont_grant(fp); 439645916cd2Sjpk rfs4_file_rele(fp); 439745916cd2Sjpk } 4398f3b585ceSsamf goto out; 439945916cd2Sjpk } 440045916cd2Sjpk } 440145916cd2Sjpk } 440245916cd2Sjpk 44037c478bd9Sstevel@tonic-gate /* Get dir "before" change value */ 44047c478bd9Sstevel@tonic-gate bdva.va_mask = AT_CTIME|AT_SEQ; 4405da6c28aaSamw error = VOP_GETATTR(dvp, &bdva, 0, cs->cr, NULL); 44067c478bd9Sstevel@tonic-gate if (error) { 44077c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = puterrno4(error); 4408b89a8333Snatalie li - Sun Microsystems - Irvine United States if (nm != name) 4409b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(name, MAXPATHLEN + 1); 44107c478bd9Sstevel@tonic-gate kmem_free(nm, len); 4411a08f57bcSJames Wahlig if (in_crit) 4412a08f57bcSJames Wahlig nbl_end_crit(vp); 4413a08f57bcSJames Wahlig VN_RELE(vp); 4414a08f57bcSJames Wahlig if (fp) { 4415a08f57bcSJames Wahlig rfs4_clear_dont_grant(fp); 4416a08f57bcSJames Wahlig rfs4_file_rele(fp); 4417a08f57bcSJames Wahlig } 4418f3b585ceSsamf goto out; 44197c478bd9Sstevel@tonic-gate } 44207c478bd9Sstevel@tonic-gate NFS4_SET_FATTR4_CHANGE(resp->cinfo.before, bdva.va_ctime) 44217c478bd9Sstevel@tonic-gate 44227c478bd9Sstevel@tonic-gate /* Actually do the REMOVE operation */ 44237c478bd9Sstevel@tonic-gate if (vp->v_type == VDIR) { 44247c478bd9Sstevel@tonic-gate /* 44257c478bd9Sstevel@tonic-gate * Can't remove a directory that has a mounted-on filesystem. 44267c478bd9Sstevel@tonic-gate */ 44277c478bd9Sstevel@tonic-gate if (vn_ismntpt(vp)) { 44287c478bd9Sstevel@tonic-gate error = EACCES; 44297c478bd9Sstevel@tonic-gate } else { 44307c478bd9Sstevel@tonic-gate /* 44317c478bd9Sstevel@tonic-gate * System V defines rmdir to return EEXIST, 443259fb210bSJan Kryl * not ENOTEMPTY, if the directory is not 44337c478bd9Sstevel@tonic-gate * empty. A System V NFS server needs to map 44347c478bd9Sstevel@tonic-gate * NFS4ERR_EXIST to NFS4ERR_NOTEMPTY to 44357c478bd9Sstevel@tonic-gate * transmit over the wire. 44367c478bd9Sstevel@tonic-gate */ 44370dfe541eSEvan Layton if ((error = VOP_RMDIR(dvp, name, ZONE_ROOTVP(), cs->cr, 4438da6c28aaSamw NULL, 0)) == EEXIST) 44397c478bd9Sstevel@tonic-gate error = ENOTEMPTY; 44407c478bd9Sstevel@tonic-gate } 44417c478bd9Sstevel@tonic-gate } else { 4442b89a8333Snatalie li - Sun Microsystems - Irvine United States if ((error = VOP_REMOVE(dvp, name, cs->cr, NULL, 0)) == 0 && 44437c478bd9Sstevel@tonic-gate fp != NULL) { 44447c478bd9Sstevel@tonic-gate struct vattr va; 4445418d27f3Sshepler vnode_t *tvp; 44467c478bd9Sstevel@tonic-gate 4447d216dff5SRobert Mastors rfs4_dbe_lock(fp->rf_dbe); 4448d216dff5SRobert Mastors tvp = fp->rf_vp; 4449418d27f3Sshepler if (tvp) 4450418d27f3Sshepler VN_HOLD(tvp); 4451d216dff5SRobert Mastors rfs4_dbe_unlock(fp->rf_dbe); 4452418d27f3Sshepler 4453418d27f3Sshepler if (tvp) { 44547c478bd9Sstevel@tonic-gate /* 44557c478bd9Sstevel@tonic-gate * This is va_seq safe because we are not 44567c478bd9Sstevel@tonic-gate * manipulating dvp. 44577c478bd9Sstevel@tonic-gate */ 44587c478bd9Sstevel@tonic-gate va.va_mask = AT_NLINK; 4459da6c28aaSamw if (!VOP_GETATTR(tvp, &va, 0, cs->cr, NULL) && 44607c478bd9Sstevel@tonic-gate va.va_nlink == 0) { 4461418d27f3Sshepler /* Remove state on file remove */ 44627c478bd9Sstevel@tonic-gate if (in_crit) { 44637c478bd9Sstevel@tonic-gate nbl_end_crit(vp); 44647c478bd9Sstevel@tonic-gate in_crit = 0; 44657c478bd9Sstevel@tonic-gate } 44667c478bd9Sstevel@tonic-gate rfs4_close_all_state(fp); 44677c478bd9Sstevel@tonic-gate } 4468418d27f3Sshepler VN_RELE(tvp); 4469418d27f3Sshepler } 44707c478bd9Sstevel@tonic-gate } 44717c478bd9Sstevel@tonic-gate } 44727c478bd9Sstevel@tonic-gate 44737c478bd9Sstevel@tonic-gate if (in_crit) 44747c478bd9Sstevel@tonic-gate nbl_end_crit(vp); 44757c478bd9Sstevel@tonic-gate VN_RELE(vp); 44767c478bd9Sstevel@tonic-gate 44777c478bd9Sstevel@tonic-gate if (fp) { 44787c478bd9Sstevel@tonic-gate rfs4_clear_dont_grant(fp); 44797c478bd9Sstevel@tonic-gate rfs4_file_rele(fp); 44807c478bd9Sstevel@tonic-gate } 4481b89a8333Snatalie li - Sun Microsystems - Irvine United States if (nm != name) 4482b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(name, MAXPATHLEN + 1); 44837c478bd9Sstevel@tonic-gate kmem_free(nm, len); 44847c478bd9Sstevel@tonic-gate 44857c478bd9Sstevel@tonic-gate if (error) { 44867c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = puterrno4(error); 4487f3b585ceSsamf goto out; 44887c478bd9Sstevel@tonic-gate } 44897c478bd9Sstevel@tonic-gate 44907c478bd9Sstevel@tonic-gate /* 44917c478bd9Sstevel@tonic-gate * Get the initial "after" sequence number, if it fails, set to zero 44927c478bd9Sstevel@tonic-gate */ 44937c478bd9Sstevel@tonic-gate idva.va_mask = AT_SEQ; 4494da6c28aaSamw if (VOP_GETATTR(dvp, &idva, 0, cs->cr, NULL)) 44957c478bd9Sstevel@tonic-gate idva.va_seq = 0; 44967c478bd9Sstevel@tonic-gate 44977c478bd9Sstevel@tonic-gate /* 44987c478bd9Sstevel@tonic-gate * Force modified data and metadata out to stable storage. 44997c478bd9Sstevel@tonic-gate */ 4500da6c28aaSamw (void) VOP_FSYNC(dvp, 0, cs->cr, NULL); 45017c478bd9Sstevel@tonic-gate 45027c478bd9Sstevel@tonic-gate /* 45037c478bd9Sstevel@tonic-gate * Get "after" change value, if it fails, simply return the 45047c478bd9Sstevel@tonic-gate * before value. 45057c478bd9Sstevel@tonic-gate */ 45067c478bd9Sstevel@tonic-gate adva.va_mask = AT_CTIME|AT_SEQ; 4507da6c28aaSamw if (VOP_GETATTR(dvp, &adva, 0, cs->cr, NULL)) { 45087c478bd9Sstevel@tonic-gate adva.va_ctime = bdva.va_ctime; 45097c478bd9Sstevel@tonic-gate adva.va_seq = 0; 45107c478bd9Sstevel@tonic-gate } 45117c478bd9Sstevel@tonic-gate 45127c478bd9Sstevel@tonic-gate NFS4_SET_FATTR4_CHANGE(resp->cinfo.after, adva.va_ctime) 45137c478bd9Sstevel@tonic-gate 45147c478bd9Sstevel@tonic-gate /* 45157c478bd9Sstevel@tonic-gate * The cinfo.atomic = TRUE only if we have 45167c478bd9Sstevel@tonic-gate * non-zero va_seq's, and it has incremented by exactly one 45177c478bd9Sstevel@tonic-gate * during the VOP_REMOVE/RMDIR and it didn't change during 45187c478bd9Sstevel@tonic-gate * the VOP_FSYNC. 45197c478bd9Sstevel@tonic-gate */ 45207c478bd9Sstevel@tonic-gate if (bdva.va_seq && idva.va_seq && adva.va_seq && 45211b300de9Sjwahlig idva.va_seq == (bdva.va_seq + 1) && idva.va_seq == adva.va_seq) 45227c478bd9Sstevel@tonic-gate resp->cinfo.atomic = TRUE; 45237c478bd9Sstevel@tonic-gate else 45247c478bd9Sstevel@tonic-gate resp->cinfo.atomic = FALSE; 45257c478bd9Sstevel@tonic-gate 45267c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4_OK; 4527f3b585ceSsamf 4528f3b585ceSsamf out: 4529f3b585ceSsamf DTRACE_NFSV4_2(op__remove__done, struct compound_state *, cs, 4530f3b585ceSsamf REMOVE4res *, resp); 45317c478bd9Sstevel@tonic-gate } 45327c478bd9Sstevel@tonic-gate 45337c478bd9Sstevel@tonic-gate /* 45347c478bd9Sstevel@tonic-gate * rename: args: SAVED_FH: from directory, CURRENT_FH: target directory, 45357c478bd9Sstevel@tonic-gate * oldname and newname. 45367c478bd9Sstevel@tonic-gate * res: status. If success - CURRENT_FH unchanged, return change_info 45377c478bd9Sstevel@tonic-gate * for both from and target directories. 45387c478bd9Sstevel@tonic-gate */ 45397c478bd9Sstevel@tonic-gate /* ARGSUSED */ 45407c478bd9Sstevel@tonic-gate static void 45417c478bd9Sstevel@tonic-gate rfs4_op_rename(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req, 45427c478bd9Sstevel@tonic-gate struct compound_state *cs) 45437c478bd9Sstevel@tonic-gate { 45447c478bd9Sstevel@tonic-gate RENAME4args *args = &argop->nfs_argop4_u.oprename; 45457c478bd9Sstevel@tonic-gate RENAME4res *resp = &resop->nfs_resop4_u.oprename; 45467c478bd9Sstevel@tonic-gate int error; 45477c478bd9Sstevel@tonic-gate vnode_t *odvp; 45487c478bd9Sstevel@tonic-gate vnode_t *ndvp; 45490dfe541eSEvan Layton vnode_t *srcvp, *targvp, *tvp; 45507c478bd9Sstevel@tonic-gate struct vattr obdva, oidva, oadva; 45517c478bd9Sstevel@tonic-gate struct vattr nbdva, nidva, nadva; 45527c478bd9Sstevel@tonic-gate char *onm, *nnm; 45537c478bd9Sstevel@tonic-gate uint_t olen, nlen; 45547c478bd9Sstevel@tonic-gate rfs4_file_t *fp, *sfp; 45557c478bd9Sstevel@tonic-gate int in_crit_src, in_crit_targ; 45567c478bd9Sstevel@tonic-gate int fp_rele_grant_hold, sfp_rele_grant_hold; 45570dfe541eSEvan Layton int unlinked; 455845916cd2Sjpk bslabel_t *clabel; 4559b89a8333Snatalie li - Sun Microsystems - Irvine United States struct sockaddr *ca; 4560b89a8333Snatalie li - Sun Microsystems - Irvine United States char *converted_onm = NULL; 4561b89a8333Snatalie li - Sun Microsystems - Irvine United States char *converted_nnm = NULL; 456215721462SDaniil Lunev nfsstat4 status; 45637c478bd9Sstevel@tonic-gate 4564f3b585ceSsamf DTRACE_NFSV4_2(op__rename__start, struct compound_state *, cs, 4565f3b585ceSsamf RENAME4args *, args); 4566f3b585ceSsamf 45677c478bd9Sstevel@tonic-gate fp = sfp = NULL; 45680dfe541eSEvan Layton srcvp = targvp = tvp = NULL; 45697c478bd9Sstevel@tonic-gate in_crit_src = in_crit_targ = 0; 45707c478bd9Sstevel@tonic-gate fp_rele_grant_hold = sfp_rele_grant_hold = 0; 45710dfe541eSEvan Layton unlinked = 0; 45727c478bd9Sstevel@tonic-gate 45737c478bd9Sstevel@tonic-gate /* CURRENT_FH: target directory */ 45747c478bd9Sstevel@tonic-gate ndvp = cs->vp; 45757c478bd9Sstevel@tonic-gate if (ndvp == NULL) { 45767c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE; 4577f3b585ceSsamf goto out; 45787c478bd9Sstevel@tonic-gate } 45797c478bd9Sstevel@tonic-gate 45807c478bd9Sstevel@tonic-gate /* SAVED_FH: from directory */ 45817c478bd9Sstevel@tonic-gate odvp = cs->saved_vp; 45827c478bd9Sstevel@tonic-gate if (odvp == NULL) { 45837c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE; 4584f3b585ceSsamf goto out; 45857c478bd9Sstevel@tonic-gate } 45867c478bd9Sstevel@tonic-gate 45877c478bd9Sstevel@tonic-gate if (cs->access == CS_ACCESS_DENIED) { 45887c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_ACCESS; 4589f3b585ceSsamf goto out; 45907c478bd9Sstevel@tonic-gate } 45917c478bd9Sstevel@tonic-gate 45927c478bd9Sstevel@tonic-gate /* 45937c478bd9Sstevel@tonic-gate * If there is an unshared filesystem mounted on this vnode, 45947c478bd9Sstevel@tonic-gate * do not allow to rename objects in this directory. 45957c478bd9Sstevel@tonic-gate */ 45967c478bd9Sstevel@tonic-gate if (vn_ismntpt(odvp)) { 45977c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_ACCESS; 4598f3b585ceSsamf goto out; 45997c478bd9Sstevel@tonic-gate } 46007c478bd9Sstevel@tonic-gate 46017c478bd9Sstevel@tonic-gate /* 46027c478bd9Sstevel@tonic-gate * If there is an unshared filesystem mounted on this vnode, 46037c478bd9Sstevel@tonic-gate * do not allow to rename to this directory. 46047c478bd9Sstevel@tonic-gate */ 46057c478bd9Sstevel@tonic-gate if (vn_ismntpt(ndvp)) { 46067c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_ACCESS; 4607f3b585ceSsamf goto out; 46087c478bd9Sstevel@tonic-gate } 46097c478bd9Sstevel@tonic-gate 46107c478bd9Sstevel@tonic-gate if (odvp->v_type != VDIR || ndvp->v_type != VDIR) { 46117c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_NOTDIR; 4612f3b585ceSsamf goto out; 46137c478bd9Sstevel@tonic-gate } 46147c478bd9Sstevel@tonic-gate 46157c478bd9Sstevel@tonic-gate if (cs->saved_exi != cs->exi) { 46167c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_XDEV; 4617f3b585ceSsamf goto out; 46187c478bd9Sstevel@tonic-gate } 46197c478bd9Sstevel@tonic-gate 462015721462SDaniil Lunev status = utf8_dir_verify(&args->oldname); 462115721462SDaniil Lunev if (status != NFS4_OK) { 462215721462SDaniil Lunev *cs->statusp = resp->status = status; 4623f3b585ceSsamf goto out; 46247c478bd9Sstevel@tonic-gate } 46257c478bd9Sstevel@tonic-gate 462615721462SDaniil Lunev status = utf8_dir_verify(&args->newname); 462715721462SDaniil Lunev if (status != NFS4_OK) { 462815721462SDaniil Lunev *cs->statusp = resp->status = status; 4629f3b585ceSsamf goto out; 46307c478bd9Sstevel@tonic-gate } 46317c478bd9Sstevel@tonic-gate 46327c478bd9Sstevel@tonic-gate onm = utf8_to_fn(&args->oldname, &olen, NULL); 46337c478bd9Sstevel@tonic-gate if (onm == NULL) { 46347c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_INVAL; 4635f3b585ceSsamf goto out; 46367c478bd9Sstevel@tonic-gate } 4637b89a8333Snatalie li - Sun Microsystems - Irvine United States ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 4638b89a8333Snatalie li - Sun Microsystems - Irvine United States nlen = MAXPATHLEN + 1; 4639b89a8333Snatalie li - Sun Microsystems - Irvine United States converted_onm = nfscmd_convname(ca, cs->exi, onm, NFSCMD_CONV_INBOUND, 4640b89a8333Snatalie li - Sun Microsystems - Irvine United States nlen); 46417c478bd9Sstevel@tonic-gate 4642b89a8333Snatalie li - Sun Microsystems - Irvine United States if (converted_onm == NULL) { 46437c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_INVAL; 46447c478bd9Sstevel@tonic-gate kmem_free(onm, olen); 4645f3b585ceSsamf goto out; 46467c478bd9Sstevel@tonic-gate } 46477c478bd9Sstevel@tonic-gate 4648b89a8333Snatalie li - Sun Microsystems - Irvine United States nnm = utf8_to_fn(&args->newname, &nlen, NULL); 4649b89a8333Snatalie li - Sun Microsystems - Irvine United States if (nnm == NULL) { 4650b89a8333Snatalie li - Sun Microsystems - Irvine United States *cs->statusp = resp->status = NFS4ERR_INVAL; 4651b89a8333Snatalie li - Sun Microsystems - Irvine United States if (onm != converted_onm) 4652b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(converted_onm, MAXPATHLEN + 1); 4653b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(onm, olen); 4654b89a8333Snatalie li - Sun Microsystems - Irvine United States goto out; 4655b89a8333Snatalie li - Sun Microsystems - Irvine United States } 4656b89a8333Snatalie li - Sun Microsystems - Irvine United States converted_nnm = nfscmd_convname(ca, cs->exi, nnm, NFSCMD_CONV_INBOUND, 4657b89a8333Snatalie li - Sun Microsystems - Irvine United States MAXPATHLEN + 1); 4658b89a8333Snatalie li - Sun Microsystems - Irvine United States 4659b89a8333Snatalie li - Sun Microsystems - Irvine United States if (converted_nnm == NULL) { 4660b89a8333Snatalie li - Sun Microsystems - Irvine United States *cs->statusp = resp->status = NFS4ERR_INVAL; 4661b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(nnm, nlen); 4662b89a8333Snatalie li - Sun Microsystems - Irvine United States nnm = NULL; 4663b89a8333Snatalie li - Sun Microsystems - Irvine United States if (onm != converted_onm) 4664b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(converted_onm, MAXPATHLEN + 1); 4665b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(onm, olen); 4666b89a8333Snatalie li - Sun Microsystems - Irvine United States goto out; 4667b89a8333Snatalie li - Sun Microsystems - Irvine United States } 4668b89a8333Snatalie li - Sun Microsystems - Irvine United States 4669b89a8333Snatalie li - Sun Microsystems - Irvine United States 46707c478bd9Sstevel@tonic-gate if (olen > MAXNAMELEN || nlen > MAXNAMELEN) { 46717c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_NAMETOOLONG; 46727c478bd9Sstevel@tonic-gate kmem_free(onm, olen); 46737c478bd9Sstevel@tonic-gate kmem_free(nnm, nlen); 4674f3b585ceSsamf goto out; 46757c478bd9Sstevel@tonic-gate } 46767c478bd9Sstevel@tonic-gate 46777c478bd9Sstevel@tonic-gate 46785cb0d679SMarcel Telka if (rdonly4(req, cs)) { 46797c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_ROFS; 4680b89a8333Snatalie li - Sun Microsystems - Irvine United States if (onm != converted_onm) 4681b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(converted_onm, MAXPATHLEN + 1); 46827c478bd9Sstevel@tonic-gate kmem_free(onm, olen); 4683b89a8333Snatalie li - Sun Microsystems - Irvine United States if (nnm != converted_nnm) 4684b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(converted_nnm, MAXPATHLEN + 1); 46857c478bd9Sstevel@tonic-gate kmem_free(nnm, nlen); 4686f3b585ceSsamf goto out; 46877c478bd9Sstevel@tonic-gate } 46887c478bd9Sstevel@tonic-gate 468945916cd2Sjpk /* check label of the target dir */ 469045916cd2Sjpk if (is_system_labeled()) { 469145916cd2Sjpk ASSERT(req->rq_label != NULL); 469245916cd2Sjpk clabel = req->rq_label; 469345916cd2Sjpk DTRACE_PROBE2(tx__rfs4__log__info__oprename__clabel, char *, 469445916cd2Sjpk "got client label from request(1)", 469545916cd2Sjpk struct svc_req *, req); 469645916cd2Sjpk if (!blequal(&l_admin_low->tsl_label, clabel)) { 469703986916Sjarrett if (!do_rfs_label_check(clabel, ndvp, 4698bd6f1640SJarrett Lu EQUALITY_CHECK, cs->exi)) { 469945916cd2Sjpk *cs->statusp = resp->status = NFS4ERR_ACCESS; 4700b89a8333Snatalie li - Sun Microsystems - Irvine United States goto err_out; 470145916cd2Sjpk } 470245916cd2Sjpk } 470345916cd2Sjpk } 470445916cd2Sjpk 47057c478bd9Sstevel@tonic-gate /* 47067c478bd9Sstevel@tonic-gate * Is the source a file and have a delegation? 47077c478bd9Sstevel@tonic-gate * We don't need to acquire va_seq before these lookups, if 47087c478bd9Sstevel@tonic-gate * it causes an update, cinfo.before will not match, which will 47097c478bd9Sstevel@tonic-gate * trigger a cache flush even if atomic is TRUE. 47107c478bd9Sstevel@tonic-gate */ 4711bd3561fbSToomas Soome sfp = rfs4_lookup_and_findfile(odvp, converted_onm, &srcvp, 4712bd3561fbSToomas Soome &error, cs->cr); 4713bd3561fbSToomas Soome if (sfp != NULL) { 47147c478bd9Sstevel@tonic-gate if (rfs4_check_delegated_byfp(FWRITE, sfp, TRUE, TRUE, TRUE, 47157c478bd9Sstevel@tonic-gate NULL)) { 47167c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_DELAY; 47177c478bd9Sstevel@tonic-gate goto err_out; 47187c478bd9Sstevel@tonic-gate } 47197c478bd9Sstevel@tonic-gate } 47207c478bd9Sstevel@tonic-gate 47217c478bd9Sstevel@tonic-gate if (srcvp == NULL) { 47227c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = puterrno4(error); 4723b89a8333Snatalie li - Sun Microsystems - Irvine United States if (onm != converted_onm) 4724b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(converted_onm, MAXPATHLEN + 1); 47257c478bd9Sstevel@tonic-gate kmem_free(onm, olen); 4726b89a8333Snatalie li - Sun Microsystems - Irvine United States if (nnm != converted_nnm) 4727bffeae97SMarcel Telka kmem_free(converted_nnm, MAXPATHLEN + 1); 47287c478bd9Sstevel@tonic-gate kmem_free(nnm, nlen); 4729f3b585ceSsamf goto out; 47307c478bd9Sstevel@tonic-gate } 47317c478bd9Sstevel@tonic-gate 47327c478bd9Sstevel@tonic-gate sfp_rele_grant_hold = 1; 47337c478bd9Sstevel@tonic-gate 47347c478bd9Sstevel@tonic-gate /* Does the destination exist and a file and have a delegation? */ 4735bd3561fbSToomas Soome fp = rfs4_lookup_and_findfile(ndvp, converted_nnm, &targvp, NULL, 4736bd3561fbSToomas Soome cs->cr); 4737bd3561fbSToomas Soome if (fp != NULL) { 47387c478bd9Sstevel@tonic-gate if (rfs4_check_delegated_byfp(FWRITE, fp, TRUE, TRUE, TRUE, 47397c478bd9Sstevel@tonic-gate NULL)) { 47407c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_DELAY; 47417c478bd9Sstevel@tonic-gate goto err_out; 47427c478bd9Sstevel@tonic-gate } 47437c478bd9Sstevel@tonic-gate } 47447c478bd9Sstevel@tonic-gate fp_rele_grant_hold = 1; 47457c478bd9Sstevel@tonic-gate 47467c478bd9Sstevel@tonic-gate /* Check for NBMAND lock on both source and target */ 47477c478bd9Sstevel@tonic-gate if (nbl_need_check(srcvp)) { 47487c478bd9Sstevel@tonic-gate nbl_start_crit(srcvp, RW_READER); 47497c478bd9Sstevel@tonic-gate in_crit_src = 1; 4750da6c28aaSamw if (nbl_conflict(srcvp, NBL_RENAME, 0, 0, 0, NULL)) { 47517c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_FILE_OPEN; 47527c478bd9Sstevel@tonic-gate goto err_out; 47537c478bd9Sstevel@tonic-gate } 47547c478bd9Sstevel@tonic-gate } 47557c478bd9Sstevel@tonic-gate 47567c478bd9Sstevel@tonic-gate if (targvp && nbl_need_check(targvp)) { 47577c478bd9Sstevel@tonic-gate nbl_start_crit(targvp, RW_READER); 47587c478bd9Sstevel@tonic-gate in_crit_targ = 1; 4759da6c28aaSamw if (nbl_conflict(targvp, NBL_REMOVE, 0, 0, 0, NULL)) { 47607c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_FILE_OPEN; 47617c478bd9Sstevel@tonic-gate goto err_out; 47627c478bd9Sstevel@tonic-gate } 47637c478bd9Sstevel@tonic-gate } 47647c478bd9Sstevel@tonic-gate 47657c478bd9Sstevel@tonic-gate /* Get source "before" change value */ 47667c478bd9Sstevel@tonic-gate obdva.va_mask = AT_CTIME|AT_SEQ; 4767da6c28aaSamw error = VOP_GETATTR(odvp, &obdva, 0, cs->cr, NULL); 47687c478bd9Sstevel@tonic-gate if (!error) { 47697c478bd9Sstevel@tonic-gate nbdva.va_mask = AT_CTIME|AT_SEQ; 4770da6c28aaSamw error = VOP_GETATTR(ndvp, &nbdva, 0, cs->cr, NULL); 47717c478bd9Sstevel@tonic-gate } 47727c478bd9Sstevel@tonic-gate if (error) { 47737c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = puterrno4(error); 47747c478bd9Sstevel@tonic-gate goto err_out; 47757c478bd9Sstevel@tonic-gate } 47767c478bd9Sstevel@tonic-gate 47777c478bd9Sstevel@tonic-gate NFS4_SET_FATTR4_CHANGE(resp->source_cinfo.before, obdva.va_ctime) 47787c478bd9Sstevel@tonic-gate NFS4_SET_FATTR4_CHANGE(resp->target_cinfo.before, nbdva.va_ctime) 47797c478bd9Sstevel@tonic-gate 47800dfe541eSEvan Layton error = VOP_RENAME(odvp, converted_onm, ndvp, converted_nnm, cs->cr, 47810dfe541eSEvan Layton NULL, 0); 47827c478bd9Sstevel@tonic-gate 47830dfe541eSEvan Layton /* 47840dfe541eSEvan Layton * If target existed and was unlinked by VOP_RENAME, state will need 47850dfe541eSEvan Layton * closed. To avoid deadlock, rfs4_close_all_state will be done after 47860dfe541eSEvan Layton * any necessary nbl_end_crit on srcvp and tgtvp. 47870dfe541eSEvan Layton */ 47880dfe541eSEvan Layton if (error == 0 && fp != NULL) { 4789d216dff5SRobert Mastors rfs4_dbe_lock(fp->rf_dbe); 4790d216dff5SRobert Mastors tvp = fp->rf_vp; 4791418d27f3Sshepler if (tvp) 4792418d27f3Sshepler VN_HOLD(tvp); 4793d216dff5SRobert Mastors rfs4_dbe_unlock(fp->rf_dbe); 4794418d27f3Sshepler 4795418d27f3Sshepler if (tvp) { 47960dfe541eSEvan Layton struct vattr va; 47977c478bd9Sstevel@tonic-gate va.va_mask = AT_NLINK; 47980dfe541eSEvan Layton 4799da6c28aaSamw if (!VOP_GETATTR(tvp, &va, 0, cs->cr, NULL) && 48007c478bd9Sstevel@tonic-gate va.va_nlink == 0) { 48010dfe541eSEvan Layton unlinked = 1; 48020dfe541eSEvan Layton 48030dfe541eSEvan Layton /* DEBUG data */ 48040dfe541eSEvan Layton if ((srcvp == targvp) || (tvp != targvp)) { 48050dfe541eSEvan Layton cmn_err(CE_WARN, "rfs4_op_rename: " 48060dfe541eSEvan Layton "srcvp %p, targvp: %p, tvp: %p", 48070dfe541eSEvan Layton (void *)srcvp, (void *)targvp, 48080dfe541eSEvan Layton (void *)tvp); 48097c478bd9Sstevel@tonic-gate } 48100dfe541eSEvan Layton } else { 4811418d27f3Sshepler VN_RELE(tvp); 4812418d27f3Sshepler } 48137c478bd9Sstevel@tonic-gate } 48140dfe541eSEvan Layton } 481551ece835Seschrock if (error == 0) 481651ece835Seschrock vn_renamepath(ndvp, srcvp, nnm, nlen - 1); 48177c478bd9Sstevel@tonic-gate 48187c478bd9Sstevel@tonic-gate if (in_crit_src) 48197c478bd9Sstevel@tonic-gate nbl_end_crit(srcvp); 48207c478bd9Sstevel@tonic-gate if (srcvp) 48217c478bd9Sstevel@tonic-gate VN_RELE(srcvp); 48227c478bd9Sstevel@tonic-gate if (in_crit_targ) 48237c478bd9Sstevel@tonic-gate nbl_end_crit(targvp); 48247c478bd9Sstevel@tonic-gate if (targvp) 48257c478bd9Sstevel@tonic-gate VN_RELE(targvp); 48267c478bd9Sstevel@tonic-gate 48270dfe541eSEvan Layton if (unlinked) { 48280dfe541eSEvan Layton ASSERT(fp != NULL); 48290dfe541eSEvan Layton ASSERT(tvp != NULL); 48300dfe541eSEvan Layton 48310dfe541eSEvan Layton /* DEBUG data */ 48320dfe541eSEvan Layton if (RW_READ_HELD(&tvp->v_nbllock)) { 48330dfe541eSEvan Layton cmn_err(CE_WARN, "rfs4_op_rename: " 48340dfe541eSEvan Layton "RW_READ_HELD(%p)", (void *)tvp); 48350dfe541eSEvan Layton } 48360dfe541eSEvan Layton 48370dfe541eSEvan Layton /* The file is gone and so should the state */ 48380dfe541eSEvan Layton rfs4_close_all_state(fp); 48390dfe541eSEvan Layton VN_RELE(tvp); 48400dfe541eSEvan Layton } 48410dfe541eSEvan Layton 48427c478bd9Sstevel@tonic-gate if (sfp) { 48437c478bd9Sstevel@tonic-gate rfs4_clear_dont_grant(sfp); 48447c478bd9Sstevel@tonic-gate rfs4_file_rele(sfp); 48457c478bd9Sstevel@tonic-gate } 48467c478bd9Sstevel@tonic-gate if (fp) { 48477c478bd9Sstevel@tonic-gate rfs4_clear_dont_grant(fp); 48487c478bd9Sstevel@tonic-gate rfs4_file_rele(fp); 48497c478bd9Sstevel@tonic-gate } 48507c478bd9Sstevel@tonic-gate 4851b89a8333Snatalie li - Sun Microsystems - Irvine United States if (converted_onm != onm) 4852b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(converted_onm, MAXPATHLEN + 1); 48537c478bd9Sstevel@tonic-gate kmem_free(onm, olen); 4854b89a8333Snatalie li - Sun Microsystems - Irvine United States if (converted_nnm != nnm) 4855b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(converted_nnm, MAXPATHLEN + 1); 48567c478bd9Sstevel@tonic-gate kmem_free(nnm, nlen); 48577c478bd9Sstevel@tonic-gate 48587c478bd9Sstevel@tonic-gate /* 48597c478bd9Sstevel@tonic-gate * Get the initial "after" sequence number, if it fails, set to zero 48607c478bd9Sstevel@tonic-gate */ 48617c478bd9Sstevel@tonic-gate oidva.va_mask = AT_SEQ; 4862da6c28aaSamw if (VOP_GETATTR(odvp, &oidva, 0, cs->cr, NULL)) 48637c478bd9Sstevel@tonic-gate oidva.va_seq = 0; 48647c478bd9Sstevel@tonic-gate 48657c478bd9Sstevel@tonic-gate nidva.va_mask = AT_SEQ; 4866da6c28aaSamw if (VOP_GETATTR(ndvp, &nidva, 0, cs->cr, NULL)) 48677c478bd9Sstevel@tonic-gate nidva.va_seq = 0; 48687c478bd9Sstevel@tonic-gate 48697c478bd9Sstevel@tonic-gate /* 48707c478bd9Sstevel@tonic-gate * Force modified data and metadata out to stable storage. 48717c478bd9Sstevel@tonic-gate */ 4872da6c28aaSamw (void) VOP_FSYNC(odvp, 0, cs->cr, NULL); 4873da6c28aaSamw (void) VOP_FSYNC(ndvp, 0, cs->cr, NULL); 48747c478bd9Sstevel@tonic-gate 48757c478bd9Sstevel@tonic-gate if (error) { 48767c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = puterrno4(error); 4877f3b585ceSsamf goto out; 48787c478bd9Sstevel@tonic-gate } 48797c478bd9Sstevel@tonic-gate 48807c478bd9Sstevel@tonic-gate /* 48817c478bd9Sstevel@tonic-gate * Get "after" change values, if it fails, simply return the 48827c478bd9Sstevel@tonic-gate * before value. 48837c478bd9Sstevel@tonic-gate */ 48847c478bd9Sstevel@tonic-gate oadva.va_mask = AT_CTIME|AT_SEQ; 4885da6c28aaSamw if (VOP_GETATTR(odvp, &oadva, 0, cs->cr, NULL)) { 48867c478bd9Sstevel@tonic-gate oadva.va_ctime = obdva.va_ctime; 48877c478bd9Sstevel@tonic-gate oadva.va_seq = 0; 48887c478bd9Sstevel@tonic-gate } 48897c478bd9Sstevel@tonic-gate 48907c478bd9Sstevel@tonic-gate nadva.va_mask = AT_CTIME|AT_SEQ; 4891da6c28aaSamw if (VOP_GETATTR(odvp, &nadva, 0, cs->cr, NULL)) { 48927c478bd9Sstevel@tonic-gate nadva.va_ctime = nbdva.va_ctime; 48937c478bd9Sstevel@tonic-gate nadva.va_seq = 0; 48947c478bd9Sstevel@tonic-gate } 48957c478bd9Sstevel@tonic-gate 48967c478bd9Sstevel@tonic-gate NFS4_SET_FATTR4_CHANGE(resp->source_cinfo.after, oadva.va_ctime) 48977c478bd9Sstevel@tonic-gate NFS4_SET_FATTR4_CHANGE(resp->target_cinfo.after, nadva.va_ctime) 48987c478bd9Sstevel@tonic-gate 48997c478bd9Sstevel@tonic-gate /* 49007c478bd9Sstevel@tonic-gate * The cinfo.atomic = TRUE only if we have 49017c478bd9Sstevel@tonic-gate * non-zero va_seq's, and it has incremented by exactly one 49027c478bd9Sstevel@tonic-gate * during the VOP_RENAME and it didn't change during the VOP_FSYNC. 49037c478bd9Sstevel@tonic-gate */ 49047c478bd9Sstevel@tonic-gate if (obdva.va_seq && oidva.va_seq && oadva.va_seq && 49051b300de9Sjwahlig oidva.va_seq == (obdva.va_seq + 1) && oidva.va_seq == oadva.va_seq) 49067c478bd9Sstevel@tonic-gate resp->source_cinfo.atomic = TRUE; 49077c478bd9Sstevel@tonic-gate else 49087c478bd9Sstevel@tonic-gate resp->source_cinfo.atomic = FALSE; 49097c478bd9Sstevel@tonic-gate 49107c478bd9Sstevel@tonic-gate if (nbdva.va_seq && nidva.va_seq && nadva.va_seq && 49111b300de9Sjwahlig nidva.va_seq == (nbdva.va_seq + 1) && nidva.va_seq == nadva.va_seq) 49127c478bd9Sstevel@tonic-gate resp->target_cinfo.atomic = TRUE; 49137c478bd9Sstevel@tonic-gate else 49147c478bd9Sstevel@tonic-gate resp->target_cinfo.atomic = FALSE; 49157c478bd9Sstevel@tonic-gate 49167c478bd9Sstevel@tonic-gate #ifdef VOLATILE_FH_TEST 49177c478bd9Sstevel@tonic-gate { 49187c478bd9Sstevel@tonic-gate extern void add_volrnm_fh(struct exportinfo *, vnode_t *); 49197c478bd9Sstevel@tonic-gate 49207c478bd9Sstevel@tonic-gate /* 49217c478bd9Sstevel@tonic-gate * Add the renamed file handle to the volatile rename list 49227c478bd9Sstevel@tonic-gate */ 49237c478bd9Sstevel@tonic-gate if (cs->exi->exi_export.ex_flags & EX_VOLRNM) { 49247c478bd9Sstevel@tonic-gate /* file handles may expire on rename */ 49257c478bd9Sstevel@tonic-gate vnode_t *vp; 49267c478bd9Sstevel@tonic-gate 49277c478bd9Sstevel@tonic-gate nnm = utf8_to_fn(&args->newname, &nlen, NULL); 49287c478bd9Sstevel@tonic-gate /* 49297c478bd9Sstevel@tonic-gate * Already know that nnm will be a valid string 49307c478bd9Sstevel@tonic-gate */ 4931da6c28aaSamw error = VOP_LOOKUP(ndvp, nnm, &vp, NULL, 0, NULL, cs->cr, 4932da6c28aaSamw NULL, NULL, NULL); 49337c478bd9Sstevel@tonic-gate kmem_free(nnm, nlen); 49347c478bd9Sstevel@tonic-gate if (!error) { 49357c478bd9Sstevel@tonic-gate add_volrnm_fh(cs->exi, vp); 49367c478bd9Sstevel@tonic-gate VN_RELE(vp); 49377c478bd9Sstevel@tonic-gate } 49387c478bd9Sstevel@tonic-gate } 49397c478bd9Sstevel@tonic-gate } 49407c478bd9Sstevel@tonic-gate #endif /* VOLATILE_FH_TEST */ 49417c478bd9Sstevel@tonic-gate 49427c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4_OK; 4943f3b585ceSsamf out: 4944f3b585ceSsamf DTRACE_NFSV4_2(op__rename__done, struct compound_state *, cs, 4945f3b585ceSsamf RENAME4res *, resp); 49467c478bd9Sstevel@tonic-gate return; 49477c478bd9Sstevel@tonic-gate 49487c478bd9Sstevel@tonic-gate err_out: 4949b89a8333Snatalie li - Sun Microsystems - Irvine United States if (onm != converted_onm) 4950b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(converted_onm, MAXPATHLEN + 1); 4951b89a8333Snatalie li - Sun Microsystems - Irvine United States if (onm != NULL) 49527c478bd9Sstevel@tonic-gate kmem_free(onm, olen); 4953b89a8333Snatalie li - Sun Microsystems - Irvine United States if (nnm != converted_nnm) 4954b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(converted_nnm, MAXPATHLEN + 1); 4955b89a8333Snatalie li - Sun Microsystems - Irvine United States if (nnm != NULL) 49567c478bd9Sstevel@tonic-gate kmem_free(nnm, nlen); 49577c478bd9Sstevel@tonic-gate 49587c478bd9Sstevel@tonic-gate if (in_crit_src) nbl_end_crit(srcvp); 49597c478bd9Sstevel@tonic-gate if (in_crit_targ) nbl_end_crit(targvp); 49607c478bd9Sstevel@tonic-gate if (targvp) VN_RELE(targvp); 49617c478bd9Sstevel@tonic-gate if (srcvp) VN_RELE(srcvp); 49627c478bd9Sstevel@tonic-gate if (sfp) { 49637c478bd9Sstevel@tonic-gate if (sfp_rele_grant_hold) rfs4_clear_dont_grant(sfp); 49647c478bd9Sstevel@tonic-gate rfs4_file_rele(sfp); 49657c478bd9Sstevel@tonic-gate } 49667c478bd9Sstevel@tonic-gate if (fp) { 49677c478bd9Sstevel@tonic-gate if (fp_rele_grant_hold) rfs4_clear_dont_grant(fp); 49687c478bd9Sstevel@tonic-gate rfs4_file_rele(fp); 49697c478bd9Sstevel@tonic-gate } 4970f3b585ceSsamf 4971f3b585ceSsamf DTRACE_NFSV4_2(op__rename__done, struct compound_state *, cs, 4972f3b585ceSsamf RENAME4res *, resp); 49737c478bd9Sstevel@tonic-gate } 49747c478bd9Sstevel@tonic-gate 49757c478bd9Sstevel@tonic-gate /* ARGSUSED */ 49767c478bd9Sstevel@tonic-gate static void 49777c478bd9Sstevel@tonic-gate rfs4_op_renew(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req, 49787c478bd9Sstevel@tonic-gate struct compound_state *cs) 49797c478bd9Sstevel@tonic-gate { 49807c478bd9Sstevel@tonic-gate RENEW4args *args = &argop->nfs_argop4_u.oprenew; 49817c478bd9Sstevel@tonic-gate RENEW4res *resp = &resop->nfs_resop4_u.oprenew; 49827c478bd9Sstevel@tonic-gate rfs4_client_t *cp; 49837c478bd9Sstevel@tonic-gate 4984f3b585ceSsamf DTRACE_NFSV4_2(op__renew__start, struct compound_state *, cs, 4985f3b585ceSsamf RENEW4args *, args); 4986f3b585ceSsamf 49877c478bd9Sstevel@tonic-gate if ((cp = rfs4_findclient_by_id(args->clientid, FALSE)) == NULL) { 49887c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = 49897c478bd9Sstevel@tonic-gate rfs4_check_clientid(&args->clientid, 0); 4990f3b585ceSsamf goto out; 49917c478bd9Sstevel@tonic-gate } 49927c478bd9Sstevel@tonic-gate 49937c478bd9Sstevel@tonic-gate if (rfs4_lease_expired(cp)) { 49947c478bd9Sstevel@tonic-gate rfs4_client_rele(cp); 49957c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_EXPIRED; 4996f3b585ceSsamf goto out; 49977c478bd9Sstevel@tonic-gate } 49987c478bd9Sstevel@tonic-gate 49997c478bd9Sstevel@tonic-gate rfs4_update_lease(cp); 50007c478bd9Sstevel@tonic-gate 5001d216dff5SRobert Mastors mutex_enter(cp->rc_cbinfo.cb_lock); 5002d216dff5SRobert Mastors if (cp->rc_cbinfo.cb_notified_of_cb_path_down == FALSE) { 5003d216dff5SRobert Mastors cp->rc_cbinfo.cb_notified_of_cb_path_down = TRUE; 50047c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_CB_PATH_DOWN; 50057c478bd9Sstevel@tonic-gate } else { 50067c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4_OK; 50077c478bd9Sstevel@tonic-gate } 5008d216dff5SRobert Mastors mutex_exit(cp->rc_cbinfo.cb_lock); 50097c478bd9Sstevel@tonic-gate 50107c478bd9Sstevel@tonic-gate rfs4_client_rele(cp); 50117c478bd9Sstevel@tonic-gate 5012f3b585ceSsamf out: 5013f3b585ceSsamf DTRACE_NFSV4_2(op__renew__done, struct compound_state *, cs, 5014f3b585ceSsamf RENEW4res *, resp); 50157c478bd9Sstevel@tonic-gate } 50167c478bd9Sstevel@tonic-gate 50177c478bd9Sstevel@tonic-gate /* ARGSUSED */ 50187c478bd9Sstevel@tonic-gate static void 50197c478bd9Sstevel@tonic-gate rfs4_op_restorefh(nfs_argop4 *args, nfs_resop4 *resop, struct svc_req *req, 50207c478bd9Sstevel@tonic-gate struct compound_state *cs) 50217c478bd9Sstevel@tonic-gate { 50227c478bd9Sstevel@tonic-gate RESTOREFH4res *resp = &resop->nfs_resop4_u.oprestorefh; 50237c478bd9Sstevel@tonic-gate 5024f3b585ceSsamf DTRACE_NFSV4_1(op__restorefh__start, struct compound_state *, cs); 5025f3b585ceSsamf 50267c478bd9Sstevel@tonic-gate /* No need to check cs->access - we are not accessing any object */ 50277c478bd9Sstevel@tonic-gate if ((cs->saved_vp == NULL) || (cs->saved_fh.nfs_fh4_val == NULL)) { 50287c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_RESTOREFH; 5029f3b585ceSsamf goto out; 50307c478bd9Sstevel@tonic-gate } 50317c478bd9Sstevel@tonic-gate if (cs->vp != NULL) { 50327c478bd9Sstevel@tonic-gate VN_RELE(cs->vp); 50337c478bd9Sstevel@tonic-gate } 50347c478bd9Sstevel@tonic-gate cs->vp = cs->saved_vp; 50357c478bd9Sstevel@tonic-gate cs->saved_vp = NULL; 50367c478bd9Sstevel@tonic-gate cs->exi = cs->saved_exi; 50377c478bd9Sstevel@tonic-gate nfs_fh4_copy(&cs->saved_fh, &cs->fh); 50387c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4_OK; 50397c478bd9Sstevel@tonic-gate cs->deleg = FALSE; 5040f3b585ceSsamf 5041f3b585ceSsamf out: 5042f3b585ceSsamf DTRACE_NFSV4_2(op__restorefh__done, struct compound_state *, cs, 5043f3b585ceSsamf RESTOREFH4res *, resp); 50447c478bd9Sstevel@tonic-gate } 50457c478bd9Sstevel@tonic-gate 50467c478bd9Sstevel@tonic-gate /* ARGSUSED */ 50477c478bd9Sstevel@tonic-gate static void 50487c478bd9Sstevel@tonic-gate rfs4_op_savefh(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req, 50497c478bd9Sstevel@tonic-gate struct compound_state *cs) 50507c478bd9Sstevel@tonic-gate { 50517c478bd9Sstevel@tonic-gate SAVEFH4res *resp = &resop->nfs_resop4_u.opsavefh; 50527c478bd9Sstevel@tonic-gate 5053f3b585ceSsamf DTRACE_NFSV4_1(op__savefh__start, struct compound_state *, cs); 5054f3b585ceSsamf 50557c478bd9Sstevel@tonic-gate /* No need to check cs->access - we are not accessing any object */ 50567c478bd9Sstevel@tonic-gate if (cs->vp == NULL) { 50577c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE; 5058f3b585ceSsamf goto out; 50597c478bd9Sstevel@tonic-gate } 50607c478bd9Sstevel@tonic-gate if (cs->saved_vp != NULL) { 50617c478bd9Sstevel@tonic-gate VN_RELE(cs->saved_vp); 50627c478bd9Sstevel@tonic-gate } 50637c478bd9Sstevel@tonic-gate cs->saved_vp = cs->vp; 50647c478bd9Sstevel@tonic-gate VN_HOLD(cs->saved_vp); 50657c478bd9Sstevel@tonic-gate cs->saved_exi = cs->exi; 50667c478bd9Sstevel@tonic-gate /* 50677c478bd9Sstevel@tonic-gate * since SAVEFH is fairly rare, don't alloc space for its fh 50687c478bd9Sstevel@tonic-gate * unless necessary. 50697c478bd9Sstevel@tonic-gate */ 50707c478bd9Sstevel@tonic-gate if (cs->saved_fh.nfs_fh4_val == NULL) { 50717c478bd9Sstevel@tonic-gate cs->saved_fh.nfs_fh4_val = kmem_alloc(NFS4_FHSIZE, KM_SLEEP); 50727c478bd9Sstevel@tonic-gate } 50737c478bd9Sstevel@tonic-gate nfs_fh4_copy(&cs->fh, &cs->saved_fh); 50747c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4_OK; 5075f3b585ceSsamf 5076f3b585ceSsamf out: 5077f3b585ceSsamf DTRACE_NFSV4_2(op__savefh__done, struct compound_state *, cs, 5078f3b585ceSsamf SAVEFH4res *, resp); 50797c478bd9Sstevel@tonic-gate } 50807c478bd9Sstevel@tonic-gate 50817c478bd9Sstevel@tonic-gate /* 50827c478bd9Sstevel@tonic-gate * rfs4_verify_attr is called when nfsv4 Setattr failed, but we wish to 50837c478bd9Sstevel@tonic-gate * return the bitmap of attrs that were set successfully. It is also 50847c478bd9Sstevel@tonic-gate * called by Verify/Nverify to test the vattr/vfsstat attrs. It should 50857c478bd9Sstevel@tonic-gate * always be called only after rfs4_do_set_attrs(). 50867c478bd9Sstevel@tonic-gate * 50877c478bd9Sstevel@tonic-gate * Verify that the attributes are same as the expected ones. sargp->vap 50887c478bd9Sstevel@tonic-gate * and sargp->sbp contain the input attributes as translated from fattr4. 50897c478bd9Sstevel@tonic-gate * 50907c478bd9Sstevel@tonic-gate * This function verifies only the attrs that correspond to a vattr or 50917c478bd9Sstevel@tonic-gate * vfsstat struct. That is because of the extra step needed to get the 50927c478bd9Sstevel@tonic-gate * corresponding system structs. Other attributes have already been set or 50937c478bd9Sstevel@tonic-gate * verified by do_rfs4_set_attrs. 50947c478bd9Sstevel@tonic-gate * 50957c478bd9Sstevel@tonic-gate * Return 0 if all attrs match, -1 if some don't, error if error processing. 50967c478bd9Sstevel@tonic-gate */ 50977c478bd9Sstevel@tonic-gate static int 50987c478bd9Sstevel@tonic-gate rfs4_verify_attr(struct nfs4_svgetit_arg *sargp, 50997c478bd9Sstevel@tonic-gate bitmap4 *resp, struct nfs4_ntov_table *ntovp) 51007c478bd9Sstevel@tonic-gate { 51017c478bd9Sstevel@tonic-gate int error, ret_error = 0; 51027c478bd9Sstevel@tonic-gate int i, k; 51037c478bd9Sstevel@tonic-gate uint_t sva_mask = sargp->vap->va_mask; 51047c478bd9Sstevel@tonic-gate uint_t vbit; 51057c478bd9Sstevel@tonic-gate union nfs4_attr_u *na; 51067c478bd9Sstevel@tonic-gate uint8_t *amap; 51077c478bd9Sstevel@tonic-gate bool_t getsb = ntovp->vfsstat; 51087c478bd9Sstevel@tonic-gate 51097c478bd9Sstevel@tonic-gate if (sva_mask != 0) { 51107c478bd9Sstevel@tonic-gate /* 51117c478bd9Sstevel@tonic-gate * Okay to overwrite sargp->vap because we verify based 51127c478bd9Sstevel@tonic-gate * on the incoming values. 51137c478bd9Sstevel@tonic-gate */ 51147c478bd9Sstevel@tonic-gate ret_error = VOP_GETATTR(sargp->cs->vp, sargp->vap, 0, 5115da6c28aaSamw sargp->cs->cr, NULL); 51167c478bd9Sstevel@tonic-gate if (ret_error) { 51177c478bd9Sstevel@tonic-gate if (resp == NULL) 51187c478bd9Sstevel@tonic-gate return (ret_error); 51197c478bd9Sstevel@tonic-gate /* 51207c478bd9Sstevel@tonic-gate * Must return bitmap of successful attrs 51217c478bd9Sstevel@tonic-gate */ 51227c478bd9Sstevel@tonic-gate sva_mask = 0; /* to prevent checking vap later */ 51237c478bd9Sstevel@tonic-gate } else { 51247c478bd9Sstevel@tonic-gate /* 51257c478bd9Sstevel@tonic-gate * Some file systems clobber va_mask. it is probably 51267c478bd9Sstevel@tonic-gate * wrong of them to do so, nonethless we practice 51277c478bd9Sstevel@tonic-gate * defensive coding. 51287c478bd9Sstevel@tonic-gate * See bug id 4276830. 51297c478bd9Sstevel@tonic-gate */ 51307c478bd9Sstevel@tonic-gate sargp->vap->va_mask = sva_mask; 51317c478bd9Sstevel@tonic-gate } 51327c478bd9Sstevel@tonic-gate } 51337c478bd9Sstevel@tonic-gate 51347c478bd9Sstevel@tonic-gate if (getsb) { 51357c478bd9Sstevel@tonic-gate /* 51367c478bd9Sstevel@tonic-gate * Now get the superblock and loop on the bitmap, as there is 51377c478bd9Sstevel@tonic-gate * no simple way of translating from superblock to bitmap4. 51387c478bd9Sstevel@tonic-gate */ 51397c478bd9Sstevel@tonic-gate ret_error = VFS_STATVFS(sargp->cs->vp->v_vfsp, sargp->sbp); 51407c478bd9Sstevel@tonic-gate if (ret_error) { 51417c478bd9Sstevel@tonic-gate if (resp == NULL) 51427c478bd9Sstevel@tonic-gate goto errout; 51437c478bd9Sstevel@tonic-gate getsb = FALSE; 51447c478bd9Sstevel@tonic-gate } 51457c478bd9Sstevel@tonic-gate } 51467c478bd9Sstevel@tonic-gate 51477c478bd9Sstevel@tonic-gate /* 51487c478bd9Sstevel@tonic-gate * Now loop and verify each attribute which getattr returned 51497c478bd9Sstevel@tonic-gate * whether it's the same as the input. 51507c478bd9Sstevel@tonic-gate */ 51517c478bd9Sstevel@tonic-gate if (resp == NULL && !getsb && (sva_mask == 0)) 51527c478bd9Sstevel@tonic-gate goto errout; 51537c478bd9Sstevel@tonic-gate 51547c478bd9Sstevel@tonic-gate na = ntovp->na; 51557c478bd9Sstevel@tonic-gate amap = ntovp->amap; 51567c478bd9Sstevel@tonic-gate k = 0; 51577c478bd9Sstevel@tonic-gate for (i = 0; i < ntovp->attrcnt; i++, na++, amap++) { 51587c478bd9Sstevel@tonic-gate k = *amap; 51597c478bd9Sstevel@tonic-gate ASSERT(nfs4_ntov_map[k].nval == k); 51607c478bd9Sstevel@tonic-gate vbit = nfs4_ntov_map[k].vbit; 51617c478bd9Sstevel@tonic-gate 51627c478bd9Sstevel@tonic-gate /* 51637c478bd9Sstevel@tonic-gate * If vattr attribute but VOP_GETATTR failed, or it's 51647c478bd9Sstevel@tonic-gate * superblock attribute but VFS_STATVFS failed, skip 51657c478bd9Sstevel@tonic-gate */ 51667c478bd9Sstevel@tonic-gate if (vbit) { 51677c478bd9Sstevel@tonic-gate if ((vbit & sva_mask) == 0) 51687c478bd9Sstevel@tonic-gate continue; 51697c478bd9Sstevel@tonic-gate } else if (!(getsb && nfs4_ntov_map[k].vfsstat)) { 51707c478bd9Sstevel@tonic-gate continue; 51717c478bd9Sstevel@tonic-gate } 51721b300de9Sjwahlig error = (*nfs4_ntov_map[k].sv_getit)(NFS4ATTR_VERIT, sargp, na); 51737c478bd9Sstevel@tonic-gate if (resp != NULL) { 51747c478bd9Sstevel@tonic-gate if (error) 51757c478bd9Sstevel@tonic-gate ret_error = -1; /* not all match */ 51767c478bd9Sstevel@tonic-gate else /* update response bitmap */ 51777c478bd9Sstevel@tonic-gate *resp |= nfs4_ntov_map[k].fbit; 51787c478bd9Sstevel@tonic-gate continue; 51797c478bd9Sstevel@tonic-gate } 51807c478bd9Sstevel@tonic-gate if (error) { 51817c478bd9Sstevel@tonic-gate ret_error = -1; /* not all match */ 51827c478bd9Sstevel@tonic-gate break; 51837c478bd9Sstevel@tonic-gate } 51847c478bd9Sstevel@tonic-gate } 51857c478bd9Sstevel@tonic-gate errout: 51867c478bd9Sstevel@tonic-gate return (ret_error); 51877c478bd9Sstevel@tonic-gate } 51887c478bd9Sstevel@tonic-gate 51897c478bd9Sstevel@tonic-gate /* 51907c478bd9Sstevel@tonic-gate * Decode the attribute to be set/verified. If the attr requires a sys op 51917c478bd9Sstevel@tonic-gate * (VOP_GETATTR, VFS_VFSSTAT), and the request is to verify, then don't 51927c478bd9Sstevel@tonic-gate * call the sv_getit function for it, because the sys op hasn't yet been done. 51937c478bd9Sstevel@tonic-gate * Return 0 for success, error code if failed. 51947c478bd9Sstevel@tonic-gate * 51957c478bd9Sstevel@tonic-gate * Note: the decoded arg is not freed here but in nfs4_ntov_table_free. 51967c478bd9Sstevel@tonic-gate */ 51977c478bd9Sstevel@tonic-gate static int 51987c478bd9Sstevel@tonic-gate decode_fattr4_attr(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sargp, 51997c478bd9Sstevel@tonic-gate int k, XDR *xdrp, bitmap4 *resp_bval, union nfs4_attr_u *nap) 52007c478bd9Sstevel@tonic-gate { 52017c478bd9Sstevel@tonic-gate int error = 0; 52027c478bd9Sstevel@tonic-gate bool_t set_later; 52037c478bd9Sstevel@tonic-gate 52047c478bd9Sstevel@tonic-gate sargp->vap->va_mask |= nfs4_ntov_map[k].vbit; 52057c478bd9Sstevel@tonic-gate 52067c478bd9Sstevel@tonic-gate if ((*nfs4_ntov_map[k].xfunc)(xdrp, nap)) { 52077c478bd9Sstevel@tonic-gate set_later = nfs4_ntov_map[k].vbit || nfs4_ntov_map[k].vfsstat; 52087c478bd9Sstevel@tonic-gate /* 52097c478bd9Sstevel@tonic-gate * don't verify yet if a vattr or sb dependent attr, 52107c478bd9Sstevel@tonic-gate * because we don't have their sys values yet. 52117c478bd9Sstevel@tonic-gate * Will be done later. 52127c478bd9Sstevel@tonic-gate */ 52137c478bd9Sstevel@tonic-gate if (! (set_later && (cmd == NFS4ATTR_VERIT))) { 52147c478bd9Sstevel@tonic-gate /* 52157c478bd9Sstevel@tonic-gate * ACLs are a special case, since setting the MODE 52167c478bd9Sstevel@tonic-gate * conflicts with setting the ACL. We delay setting 52177c478bd9Sstevel@tonic-gate * the ACL until all other attributes have been set. 52187c478bd9Sstevel@tonic-gate * The ACL gets set in do_rfs4_op_setattr(). 52197c478bd9Sstevel@tonic-gate */ 52207c478bd9Sstevel@tonic-gate if (nfs4_ntov_map[k].fbit != FATTR4_ACL_MASK) { 52217c478bd9Sstevel@tonic-gate error = (*nfs4_ntov_map[k].sv_getit)(cmd, 52227c478bd9Sstevel@tonic-gate sargp, nap); 52237c478bd9Sstevel@tonic-gate if (error) { 52247c478bd9Sstevel@tonic-gate xdr_free(nfs4_ntov_map[k].xfunc, 52257c478bd9Sstevel@tonic-gate (caddr_t)nap); 52267c478bd9Sstevel@tonic-gate } 52277c478bd9Sstevel@tonic-gate } 52287c478bd9Sstevel@tonic-gate } 52297c478bd9Sstevel@tonic-gate } else { 52307c478bd9Sstevel@tonic-gate #ifdef DEBUG 52317c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "decode_fattr4_attr: error " 52327c478bd9Sstevel@tonic-gate "decoding attribute %d\n", k); 52337c478bd9Sstevel@tonic-gate #endif 52347c478bd9Sstevel@tonic-gate error = EINVAL; 52357c478bd9Sstevel@tonic-gate } 52367c478bd9Sstevel@tonic-gate if (!error && resp_bval && !set_later) { 52377c478bd9Sstevel@tonic-gate *resp_bval |= nfs4_ntov_map[k].fbit; 52387c478bd9Sstevel@tonic-gate } 52397c478bd9Sstevel@tonic-gate 52407c478bd9Sstevel@tonic-gate return (error); 52417c478bd9Sstevel@tonic-gate } 52427c478bd9Sstevel@tonic-gate 52437c478bd9Sstevel@tonic-gate /* 52447c478bd9Sstevel@tonic-gate * Set vattr based on incoming fattr4 attrs - used by setattr. 52457c478bd9Sstevel@tonic-gate * Set response mask. Ignore any values that are not writable vattr attrs. 52467c478bd9Sstevel@tonic-gate */ 52477c478bd9Sstevel@tonic-gate static nfsstat4 52487c478bd9Sstevel@tonic-gate do_rfs4_set_attrs(bitmap4 *resp, fattr4 *fattrp, struct compound_state *cs, 52497c478bd9Sstevel@tonic-gate struct nfs4_svgetit_arg *sargp, struct nfs4_ntov_table *ntovp, 52507c478bd9Sstevel@tonic-gate nfs4_attr_cmd_t cmd) 52517c478bd9Sstevel@tonic-gate { 52527c478bd9Sstevel@tonic-gate int error = 0; 52537c478bd9Sstevel@tonic-gate int i; 52547c478bd9Sstevel@tonic-gate char *attrs = fattrp->attrlist4; 52557c478bd9Sstevel@tonic-gate uint32_t attrslen = fattrp->attrlist4_len; 52567c478bd9Sstevel@tonic-gate XDR xdr; 52577c478bd9Sstevel@tonic-gate nfsstat4 status = NFS4_OK; 52587c478bd9Sstevel@tonic-gate vnode_t *vp = cs->vp; 52597c478bd9Sstevel@tonic-gate union nfs4_attr_u *na; 52607c478bd9Sstevel@tonic-gate uint8_t *amap; 52617c478bd9Sstevel@tonic-gate 52627c478bd9Sstevel@tonic-gate #ifndef lint 52637c478bd9Sstevel@tonic-gate /* 52647c478bd9Sstevel@tonic-gate * Make sure that maximum attribute number can be expressed as an 52657c478bd9Sstevel@tonic-gate * 8 bit quantity. 52667c478bd9Sstevel@tonic-gate */ 52677c478bd9Sstevel@tonic-gate ASSERT(NFS4_MAXNUM_ATTRS <= (UINT8_MAX + 1)); 52687c478bd9Sstevel@tonic-gate #endif 52697c478bd9Sstevel@tonic-gate 52707c478bd9Sstevel@tonic-gate if (vp == NULL) { 52717c478bd9Sstevel@tonic-gate if (resp) 52727c478bd9Sstevel@tonic-gate *resp = 0; 52737c478bd9Sstevel@tonic-gate return (NFS4ERR_NOFILEHANDLE); 52747c478bd9Sstevel@tonic-gate } 52757c478bd9Sstevel@tonic-gate if (cs->access == CS_ACCESS_DENIED) { 52767c478bd9Sstevel@tonic-gate if (resp) 52777c478bd9Sstevel@tonic-gate *resp = 0; 52787c478bd9Sstevel@tonic-gate return (NFS4ERR_ACCESS); 52797c478bd9Sstevel@tonic-gate } 52807c478bd9Sstevel@tonic-gate 52817c478bd9Sstevel@tonic-gate sargp->op = cmd; 52827c478bd9Sstevel@tonic-gate sargp->cs = cs; 52837c478bd9Sstevel@tonic-gate sargp->flag = 0; /* may be set later */ 52847c478bd9Sstevel@tonic-gate sargp->vap->va_mask = 0; 52857c478bd9Sstevel@tonic-gate sargp->rdattr_error = NFS4_OK; 52867c478bd9Sstevel@tonic-gate sargp->rdattr_error_req = FALSE; 52877c478bd9Sstevel@tonic-gate /* sargp->sbp is set by the caller */ 52887c478bd9Sstevel@tonic-gate 52897c478bd9Sstevel@tonic-gate xdrmem_create(&xdr, attrs, attrslen, XDR_DECODE); 52907c478bd9Sstevel@tonic-gate 52917c478bd9Sstevel@tonic-gate na = ntovp->na; 52927c478bd9Sstevel@tonic-gate amap = ntovp->amap; 52937c478bd9Sstevel@tonic-gate 52947c478bd9Sstevel@tonic-gate /* 52957c478bd9Sstevel@tonic-gate * The following loop iterates on the nfs4_ntov_map checking 52967c478bd9Sstevel@tonic-gate * if the fbit is set in the requested bitmap. 52977c478bd9Sstevel@tonic-gate * If set then we process the arguments using the 52987c478bd9Sstevel@tonic-gate * rfs4_fattr4 conversion functions to populate the setattr 52997c478bd9Sstevel@tonic-gate * vattr and va_mask. Any settable attrs that are not using vattr 53007c478bd9Sstevel@tonic-gate * will be set in this loop. 53017c478bd9Sstevel@tonic-gate */ 53027c478bd9Sstevel@tonic-gate for (i = 0; i < nfs4_ntov_map_size; i++) { 53037c478bd9Sstevel@tonic-gate if (!(fattrp->attrmask & nfs4_ntov_map[i].fbit)) { 53047c478bd9Sstevel@tonic-gate continue; 53057c478bd9Sstevel@tonic-gate } 53067c478bd9Sstevel@tonic-gate /* 53077c478bd9Sstevel@tonic-gate * If setattr, must be a writable attr. 53087c478bd9Sstevel@tonic-gate * If verify/nverify, must be a readable attr. 53097c478bd9Sstevel@tonic-gate */ 53107c478bd9Sstevel@tonic-gate if ((error = (*nfs4_ntov_map[i].sv_getit)( 53117c478bd9Sstevel@tonic-gate NFS4ATTR_SUPPORTED, sargp, NULL)) != 0) { 53127c478bd9Sstevel@tonic-gate /* 53137c478bd9Sstevel@tonic-gate * Client tries to set/verify an 53147c478bd9Sstevel@tonic-gate * unsupported attribute, tries to set 53157c478bd9Sstevel@tonic-gate * a read only attr or verify a write 53167c478bd9Sstevel@tonic-gate * only one - error! 53177c478bd9Sstevel@tonic-gate */ 53187c478bd9Sstevel@tonic-gate break; 53197c478bd9Sstevel@tonic-gate } 53207c478bd9Sstevel@tonic-gate /* 53217c478bd9Sstevel@tonic-gate * Decode the attribute to set/verify 53227c478bd9Sstevel@tonic-gate */ 53237c478bd9Sstevel@tonic-gate error = decode_fattr4_attr(cmd, sargp, nfs4_ntov_map[i].nval, 53247c478bd9Sstevel@tonic-gate &xdr, resp ? resp : NULL, na); 53257c478bd9Sstevel@tonic-gate if (error) 53267c478bd9Sstevel@tonic-gate break; 53277c478bd9Sstevel@tonic-gate *amap++ = (uint8_t)nfs4_ntov_map[i].nval; 53287c478bd9Sstevel@tonic-gate na++; 53297c478bd9Sstevel@tonic-gate (ntovp->attrcnt)++; 53307c478bd9Sstevel@tonic-gate if (nfs4_ntov_map[i].vfsstat) 53317c478bd9Sstevel@tonic-gate ntovp->vfsstat = TRUE; 53327c478bd9Sstevel@tonic-gate } 53337c478bd9Sstevel@tonic-gate 53347c478bd9Sstevel@tonic-gate if (error != 0) 53357c478bd9Sstevel@tonic-gate status = (error == ENOTSUP ? NFS4ERR_ATTRNOTSUPP : 53367c478bd9Sstevel@tonic-gate puterrno4(error)); 53377c478bd9Sstevel@tonic-gate /* xdrmem_destroy(&xdrs); */ /* NO-OP */ 53387c478bd9Sstevel@tonic-gate return (status); 53397c478bd9Sstevel@tonic-gate } 53407c478bd9Sstevel@tonic-gate 53417c478bd9Sstevel@tonic-gate static nfsstat4 53427c478bd9Sstevel@tonic-gate do_rfs4_op_setattr(bitmap4 *resp, fattr4 *fattrp, struct compound_state *cs, 53437c478bd9Sstevel@tonic-gate stateid4 *stateid) 53447c478bd9Sstevel@tonic-gate { 53457c478bd9Sstevel@tonic-gate int error = 0; 53467c478bd9Sstevel@tonic-gate struct nfs4_svgetit_arg sarg; 53477c478bd9Sstevel@tonic-gate bool_t trunc; 53487c478bd9Sstevel@tonic-gate 53497c478bd9Sstevel@tonic-gate nfsstat4 status = NFS4_OK; 53507c478bd9Sstevel@tonic-gate cred_t *cr = cs->cr; 53517c478bd9Sstevel@tonic-gate vnode_t *vp = cs->vp; 53527c478bd9Sstevel@tonic-gate struct nfs4_ntov_table ntov; 53537c478bd9Sstevel@tonic-gate struct statvfs64 sb; 53547c478bd9Sstevel@tonic-gate struct vattr bva; 53557c478bd9Sstevel@tonic-gate struct flock64 bf; 53567c478bd9Sstevel@tonic-gate int in_crit = 0; 53577c478bd9Sstevel@tonic-gate uint_t saved_mask = 0; 53587c478bd9Sstevel@tonic-gate caller_context_t ct; 53597c478bd9Sstevel@tonic-gate 53607c478bd9Sstevel@tonic-gate *resp = 0; 53617c478bd9Sstevel@tonic-gate sarg.sbp = &sb; 53622f172c55SRobert Thurlow sarg.is_referral = B_FALSE; 53637c478bd9Sstevel@tonic-gate nfs4_ntov_table_init(&ntov); 53647c478bd9Sstevel@tonic-gate status = do_rfs4_set_attrs(resp, fattrp, cs, &sarg, &ntov, 53657c478bd9Sstevel@tonic-gate NFS4ATTR_SETIT); 53667c478bd9Sstevel@tonic-gate if (status != NFS4_OK) { 53677c478bd9Sstevel@tonic-gate /* 53687c478bd9Sstevel@tonic-gate * failed set attrs 53697c478bd9Sstevel@tonic-gate */ 53707c478bd9Sstevel@tonic-gate goto done; 53717c478bd9Sstevel@tonic-gate } 5372*f44e1126SVitaliy Gusev 53737c478bd9Sstevel@tonic-gate if ((sarg.vap->va_mask == 0) && 53747c478bd9Sstevel@tonic-gate (! (fattrp->attrmask & FATTR4_ACL_MASK))) { 53757c478bd9Sstevel@tonic-gate /* 53767c478bd9Sstevel@tonic-gate * no further work to be done 53777c478bd9Sstevel@tonic-gate */ 53787c478bd9Sstevel@tonic-gate goto done; 53797c478bd9Sstevel@tonic-gate } 53807c478bd9Sstevel@tonic-gate 53817c478bd9Sstevel@tonic-gate /* 53827c478bd9Sstevel@tonic-gate * If we got a request to set the ACL and the MODE, only 53837c478bd9Sstevel@tonic-gate * allow changing VSUID, VSGID, and VSVTX. Attempting 53847c478bd9Sstevel@tonic-gate * to change any other bits, along with setting an ACL, 53857c478bd9Sstevel@tonic-gate * gives NFS4ERR_INVAL. 53867c478bd9Sstevel@tonic-gate */ 53877c478bd9Sstevel@tonic-gate if ((fattrp->attrmask & FATTR4_ACL_MASK) && 53887c478bd9Sstevel@tonic-gate (fattrp->attrmask & FATTR4_MODE_MASK)) { 53897c478bd9Sstevel@tonic-gate vattr_t va; 53907c478bd9Sstevel@tonic-gate 53917c478bd9Sstevel@tonic-gate va.va_mask = AT_MODE; 5392da6c28aaSamw error = VOP_GETATTR(vp, &va, 0, cs->cr, NULL); 53937c478bd9Sstevel@tonic-gate if (error) { 53947c478bd9Sstevel@tonic-gate status = puterrno4(error); 53957c478bd9Sstevel@tonic-gate goto done; 53967c478bd9Sstevel@tonic-gate } 53977c478bd9Sstevel@tonic-gate if ((sarg.vap->va_mode ^ va.va_mode) & 53987c478bd9Sstevel@tonic-gate ~(VSUID | VSGID | VSVTX)) { 53997c478bd9Sstevel@tonic-gate status = NFS4ERR_INVAL; 54007c478bd9Sstevel@tonic-gate goto done; 54017c478bd9Sstevel@tonic-gate } 54027c478bd9Sstevel@tonic-gate } 54037c478bd9Sstevel@tonic-gate 54047c478bd9Sstevel@tonic-gate /* Check stateid only if size has been set */ 54057c478bd9Sstevel@tonic-gate if (sarg.vap->va_mask & AT_SIZE) { 54067c478bd9Sstevel@tonic-gate trunc = (sarg.vap->va_size == 0); 54077c478bd9Sstevel@tonic-gate status = rfs4_check_stateid(FWRITE, cs->vp, stateid, 5408*f44e1126SVitaliy Gusev trunc, &cs->deleg, sarg.vap->va_mask & AT_SIZE, &ct, cs); 54097c478bd9Sstevel@tonic-gate if (status != NFS4_OK) 54107c478bd9Sstevel@tonic-gate goto done; 5411da6c28aaSamw } else { 54127c478bd9Sstevel@tonic-gate ct.cc_sysid = 0; 54137c478bd9Sstevel@tonic-gate ct.cc_pid = 0; 54147c478bd9Sstevel@tonic-gate ct.cc_caller_id = nfs4_srv_caller_id; 541562b9fcbeSjwahlig ct.cc_flags = CC_DONTBLOCK; 5416da6c28aaSamw } 54177c478bd9Sstevel@tonic-gate 54187c478bd9Sstevel@tonic-gate /* XXX start of possible race with delegations */ 54197c478bd9Sstevel@tonic-gate 54207c478bd9Sstevel@tonic-gate /* 54217c478bd9Sstevel@tonic-gate * We need to specially handle size changes because it is 54227c478bd9Sstevel@tonic-gate * possible for the client to create a file with read-only 54237c478bd9Sstevel@tonic-gate * modes, but with the file opened for writing. If the client 54247c478bd9Sstevel@tonic-gate * then tries to set the file size, e.g. ftruncate(3C), 54257c478bd9Sstevel@tonic-gate * fcntl(F_FREESP), the normal access checking done in 54267c478bd9Sstevel@tonic-gate * VOP_SETATTR would prevent the client from doing it even though 54277c478bd9Sstevel@tonic-gate * it should be allowed to do so. To get around this, we do the 54287c478bd9Sstevel@tonic-gate * access checking for ourselves and use VOP_SPACE which doesn't 54297c478bd9Sstevel@tonic-gate * do the access checking. 54307c478bd9Sstevel@tonic-gate * Also the client should not be allowed to change the file 54317c478bd9Sstevel@tonic-gate * size if there is a conflicting non-blocking mandatory lock in 54327c478bd9Sstevel@tonic-gate * the region of the change. 54337c478bd9Sstevel@tonic-gate */ 54347c478bd9Sstevel@tonic-gate if (vp->v_type == VREG && (sarg.vap->va_mask & AT_SIZE)) { 54357c478bd9Sstevel@tonic-gate u_offset_t offset; 54367c478bd9Sstevel@tonic-gate ssize_t length; 54377c478bd9Sstevel@tonic-gate 54387c478bd9Sstevel@tonic-gate /* 54399720e166Sjasmith * ufs_setattr clears AT_SIZE from vap->va_mask, but 54409720e166Sjasmith * before returning, sarg.vap->va_mask is used to 54419720e166Sjasmith * generate the setattr reply bitmap. We also clear 54429720e166Sjasmith * AT_SIZE below before calling VOP_SPACE. For both 54439720e166Sjasmith * of these cases, the va_mask needs to be saved here 54449720e166Sjasmith * and restored after calling VOP_SETATTR. 54459720e166Sjasmith */ 54469720e166Sjasmith saved_mask = sarg.vap->va_mask; 54479720e166Sjasmith 54489720e166Sjasmith /* 54497c478bd9Sstevel@tonic-gate * Check any possible conflict due to NBMAND locks. 54507c478bd9Sstevel@tonic-gate * Get into critical region before VOP_GETATTR, so the 54517c478bd9Sstevel@tonic-gate * size attribute is valid when checking conflicts. 54527c478bd9Sstevel@tonic-gate */ 54537c478bd9Sstevel@tonic-gate if (nbl_need_check(vp)) { 54547c478bd9Sstevel@tonic-gate nbl_start_crit(vp, RW_READER); 54557c478bd9Sstevel@tonic-gate in_crit = 1; 54567c478bd9Sstevel@tonic-gate } 54577c478bd9Sstevel@tonic-gate 54587c478bd9Sstevel@tonic-gate bva.va_mask = AT_UID|AT_SIZE; 5459bd3561fbSToomas Soome error = VOP_GETATTR(vp, &bva, 0, cr, &ct); 5460bd3561fbSToomas Soome if (error != 0) { 54617c478bd9Sstevel@tonic-gate status = puterrno4(error); 54627c478bd9Sstevel@tonic-gate goto done; 54637c478bd9Sstevel@tonic-gate } 54647c478bd9Sstevel@tonic-gate 54657c478bd9Sstevel@tonic-gate if (in_crit) { 54667c478bd9Sstevel@tonic-gate if (sarg.vap->va_size < bva.va_size) { 54677c478bd9Sstevel@tonic-gate offset = sarg.vap->va_size; 54687c478bd9Sstevel@tonic-gate length = bva.va_size - sarg.vap->va_size; 54697c478bd9Sstevel@tonic-gate } else { 54707c478bd9Sstevel@tonic-gate offset = bva.va_size; 54717c478bd9Sstevel@tonic-gate length = sarg.vap->va_size - bva.va_size; 54727c478bd9Sstevel@tonic-gate } 5473da6c28aaSamw if (nbl_conflict(vp, NBL_WRITE, offset, length, 0, 5474da6c28aaSamw &ct)) { 54757c478bd9Sstevel@tonic-gate status = NFS4ERR_LOCKED; 54767c478bd9Sstevel@tonic-gate goto done; 54777c478bd9Sstevel@tonic-gate } 54787c478bd9Sstevel@tonic-gate } 54797c478bd9Sstevel@tonic-gate 54807c478bd9Sstevel@tonic-gate if (crgetuid(cr) == bva.va_uid) { 54817c478bd9Sstevel@tonic-gate sarg.vap->va_mask &= ~AT_SIZE; 54827c478bd9Sstevel@tonic-gate bf.l_type = F_WRLCK; 54837c478bd9Sstevel@tonic-gate bf.l_whence = 0; 54847c478bd9Sstevel@tonic-gate bf.l_start = (off64_t)sarg.vap->va_size; 54857c478bd9Sstevel@tonic-gate bf.l_len = 0; 54867c478bd9Sstevel@tonic-gate bf.l_sysid = 0; 54877c478bd9Sstevel@tonic-gate bf.l_pid = 0; 54887c478bd9Sstevel@tonic-gate error = VOP_SPACE(vp, F_FREESP, &bf, FWRITE, 54897c478bd9Sstevel@tonic-gate (offset_t)sarg.vap->va_size, cr, &ct); 54907c478bd9Sstevel@tonic-gate } 54917c478bd9Sstevel@tonic-gate } 54927c478bd9Sstevel@tonic-gate 54937c478bd9Sstevel@tonic-gate if (!error && sarg.vap->va_mask != 0) 54947c478bd9Sstevel@tonic-gate error = VOP_SETATTR(vp, sarg.vap, sarg.flag, cr, &ct); 54957c478bd9Sstevel@tonic-gate 54969720e166Sjasmith /* restore va_mask -- ufs_setattr clears AT_SIZE */ 54977c478bd9Sstevel@tonic-gate if (saved_mask & AT_SIZE) 54987c478bd9Sstevel@tonic-gate sarg.vap->va_mask |= AT_SIZE; 54997c478bd9Sstevel@tonic-gate 55007c478bd9Sstevel@tonic-gate /* 55017c478bd9Sstevel@tonic-gate * If an ACL was being set, it has been delayed until now, 55027c478bd9Sstevel@tonic-gate * in order to set the mode (via the VOP_SETATTR() above) first. 55037c478bd9Sstevel@tonic-gate */ 55047c478bd9Sstevel@tonic-gate if ((! error) && (fattrp->attrmask & FATTR4_ACL_MASK)) { 55057c478bd9Sstevel@tonic-gate int i; 55067c478bd9Sstevel@tonic-gate 55077c478bd9Sstevel@tonic-gate for (i = 0; i < NFS4_MAXNUM_ATTRS; i++) 55087c478bd9Sstevel@tonic-gate if (ntov.amap[i] == FATTR4_ACL) 55097c478bd9Sstevel@tonic-gate break; 55107c478bd9Sstevel@tonic-gate if (i < NFS4_MAXNUM_ATTRS) { 55117c478bd9Sstevel@tonic-gate error = (*nfs4_ntov_map[FATTR4_ACL].sv_getit)( 55127c478bd9Sstevel@tonic-gate NFS4ATTR_SETIT, &sarg, &ntov.na[i]); 55137c478bd9Sstevel@tonic-gate if (error == 0) { 55147c478bd9Sstevel@tonic-gate *resp |= FATTR4_ACL_MASK; 55157c478bd9Sstevel@tonic-gate } else if (error == ENOTSUP) { 55167c478bd9Sstevel@tonic-gate (void) rfs4_verify_attr(&sarg, resp, &ntov); 55177c478bd9Sstevel@tonic-gate status = NFS4ERR_ATTRNOTSUPP; 55187c478bd9Sstevel@tonic-gate goto done; 55197c478bd9Sstevel@tonic-gate } 55207c478bd9Sstevel@tonic-gate } else { 55217c478bd9Sstevel@tonic-gate NFS4_DEBUG(rfs4_debug, 55227c478bd9Sstevel@tonic-gate (CE_NOTE, "do_rfs4_op_setattr: " 55237c478bd9Sstevel@tonic-gate "unable to find ACL in fattr4")); 55247c478bd9Sstevel@tonic-gate error = EINVAL; 55257c478bd9Sstevel@tonic-gate } 55267c478bd9Sstevel@tonic-gate } 55277c478bd9Sstevel@tonic-gate 55287c478bd9Sstevel@tonic-gate if (error) { 552962b9fcbeSjwahlig /* check if a monitor detected a delegation conflict */ 553062b9fcbeSjwahlig if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) 553162b9fcbeSjwahlig status = NFS4ERR_DELAY; 553262b9fcbeSjwahlig else 55337c478bd9Sstevel@tonic-gate status = puterrno4(error); 55347c478bd9Sstevel@tonic-gate 55357c478bd9Sstevel@tonic-gate /* 55367c478bd9Sstevel@tonic-gate * Set the response bitmap when setattr failed. 55377c478bd9Sstevel@tonic-gate * If VOP_SETATTR partially succeeded, test by doing a 55387c478bd9Sstevel@tonic-gate * VOP_GETATTR on the object and comparing the data 55397c478bd9Sstevel@tonic-gate * to the setattr arguments. 55407c478bd9Sstevel@tonic-gate */ 55417c478bd9Sstevel@tonic-gate (void) rfs4_verify_attr(&sarg, resp, &ntov); 55427c478bd9Sstevel@tonic-gate } else { 55437c478bd9Sstevel@tonic-gate /* 55447c478bd9Sstevel@tonic-gate * Force modified metadata out to stable storage. 55457c478bd9Sstevel@tonic-gate */ 5546da6c28aaSamw (void) VOP_FSYNC(vp, FNODSYNC, cr, &ct); 55477c478bd9Sstevel@tonic-gate /* 55487c478bd9Sstevel@tonic-gate * Set response bitmap 55497c478bd9Sstevel@tonic-gate */ 55509720e166Sjasmith nfs4_vmask_to_nmask_set(sarg.vap->va_mask, resp); 55517c478bd9Sstevel@tonic-gate } 55527c478bd9Sstevel@tonic-gate 55537c478bd9Sstevel@tonic-gate /* Return early and already have a NFSv4 error */ 55547c478bd9Sstevel@tonic-gate done: 55559720e166Sjasmith /* 55569720e166Sjasmith * Except for nfs4_vmask_to_nmask_set(), vattr --> fattr 55579720e166Sjasmith * conversion sets both readable and writeable NFS4 attrs 55589720e166Sjasmith * for AT_MTIME and AT_ATIME. The line below masks out 55599720e166Sjasmith * unrequested attrs from the setattr result bitmap. This 55609720e166Sjasmith * is placed after the done: label to catch the ATTRNOTSUP 55619720e166Sjasmith * case. 55629720e166Sjasmith */ 55639720e166Sjasmith *resp &= fattrp->attrmask; 55649720e166Sjasmith 55657c478bd9Sstevel@tonic-gate if (in_crit) 55667c478bd9Sstevel@tonic-gate nbl_end_crit(vp); 55677c478bd9Sstevel@tonic-gate 55687c478bd9Sstevel@tonic-gate nfs4_ntov_table_free(&ntov, &sarg); 55697c478bd9Sstevel@tonic-gate 55707c478bd9Sstevel@tonic-gate return (status); 55717c478bd9Sstevel@tonic-gate } 55727c478bd9Sstevel@tonic-gate 55737c478bd9Sstevel@tonic-gate /* ARGSUSED */ 55747c478bd9Sstevel@tonic-gate static void 55757c478bd9Sstevel@tonic-gate rfs4_op_setattr(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req, 55767c478bd9Sstevel@tonic-gate struct compound_state *cs) 55777c478bd9Sstevel@tonic-gate { 55787c478bd9Sstevel@tonic-gate SETATTR4args *args = &argop->nfs_argop4_u.opsetattr; 55797c478bd9Sstevel@tonic-gate SETATTR4res *resp = &resop->nfs_resop4_u.opsetattr; 558045916cd2Sjpk bslabel_t *clabel; 55817c478bd9Sstevel@tonic-gate 5582f3b585ceSsamf DTRACE_NFSV4_2(op__setattr__start, struct compound_state *, cs, 5583f3b585ceSsamf SETATTR4args *, args); 5584f3b585ceSsamf 55857c478bd9Sstevel@tonic-gate if (cs->vp == NULL) { 55867c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE; 5587f3b585ceSsamf goto out; 55887c478bd9Sstevel@tonic-gate } 55897c478bd9Sstevel@tonic-gate 55907c478bd9Sstevel@tonic-gate /* 55917c478bd9Sstevel@tonic-gate * If there is an unshared filesystem mounted on this vnode, 55927c478bd9Sstevel@tonic-gate * do not allow to setattr on this vnode. 55937c478bd9Sstevel@tonic-gate */ 55947c478bd9Sstevel@tonic-gate if (vn_ismntpt(cs->vp)) { 55957c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_ACCESS; 5596f3b585ceSsamf goto out; 55977c478bd9Sstevel@tonic-gate } 55987c478bd9Sstevel@tonic-gate 55997c478bd9Sstevel@tonic-gate resp->attrsset = 0; 56007c478bd9Sstevel@tonic-gate 56015cb0d679SMarcel Telka if (rdonly4(req, cs)) { 56027c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_ROFS; 5603f3b585ceSsamf goto out; 56047c478bd9Sstevel@tonic-gate } 56057c478bd9Sstevel@tonic-gate 560645916cd2Sjpk /* check label before setting attributes */ 560745916cd2Sjpk if (is_system_labeled()) { 560845916cd2Sjpk ASSERT(req->rq_label != NULL); 560945916cd2Sjpk clabel = req->rq_label; 561045916cd2Sjpk DTRACE_PROBE2(tx__rfs4__log__info__opsetattr__clabel, char *, 561145916cd2Sjpk "got client label from request(1)", 561245916cd2Sjpk struct svc_req *, req); 561345916cd2Sjpk if (!blequal(&l_admin_low->tsl_label, clabel)) { 561403986916Sjarrett if (!do_rfs_label_check(clabel, cs->vp, 5615bd6f1640SJarrett Lu EQUALITY_CHECK, cs->exi)) { 561645916cd2Sjpk *cs->statusp = resp->status = NFS4ERR_ACCESS; 5617f3b585ceSsamf goto out; 561845916cd2Sjpk } 561945916cd2Sjpk } 562045916cd2Sjpk } 562145916cd2Sjpk 56227c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = 56237c478bd9Sstevel@tonic-gate do_rfs4_op_setattr(&resp->attrsset, &args->obj_attributes, cs, 56247c478bd9Sstevel@tonic-gate &args->stateid); 5625f3b585ceSsamf 5626f3b585ceSsamf out: 5627f3b585ceSsamf DTRACE_NFSV4_2(op__setattr__done, struct compound_state *, cs, 5628f3b585ceSsamf SETATTR4res *, resp); 56297c478bd9Sstevel@tonic-gate } 56307c478bd9Sstevel@tonic-gate 56317c478bd9Sstevel@tonic-gate /* ARGSUSED */ 56327c478bd9Sstevel@tonic-gate static void 56337c478bd9Sstevel@tonic-gate rfs4_op_verify(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req, 56347c478bd9Sstevel@tonic-gate struct compound_state *cs) 56357c478bd9Sstevel@tonic-gate { 56367c478bd9Sstevel@tonic-gate /* 56377c478bd9Sstevel@tonic-gate * verify and nverify are exactly the same, except that nverify 56387c478bd9Sstevel@tonic-gate * succeeds when some argument changed, and verify succeeds when 56397c478bd9Sstevel@tonic-gate * when none changed. 56407c478bd9Sstevel@tonic-gate */ 56417c478bd9Sstevel@tonic-gate 56427c478bd9Sstevel@tonic-gate VERIFY4args *args = &argop->nfs_argop4_u.opverify; 56437c478bd9Sstevel@tonic-gate VERIFY4res *resp = &resop->nfs_resop4_u.opverify; 56447c478bd9Sstevel@tonic-gate 56457c478bd9Sstevel@tonic-gate int error; 56467c478bd9Sstevel@tonic-gate struct nfs4_svgetit_arg sarg; 56477c478bd9Sstevel@tonic-gate struct statvfs64 sb; 56487c478bd9Sstevel@tonic-gate struct nfs4_ntov_table ntov; 56497c478bd9Sstevel@tonic-gate 5650f3b585ceSsamf DTRACE_NFSV4_2(op__verify__start, struct compound_state *, cs, 5651f3b585ceSsamf VERIFY4args *, args); 5652f3b585ceSsamf 56537c478bd9Sstevel@tonic-gate if (cs->vp == NULL) { 56547c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE; 5655f3b585ceSsamf goto out; 56567c478bd9Sstevel@tonic-gate } 56577c478bd9Sstevel@tonic-gate 56587c478bd9Sstevel@tonic-gate sarg.sbp = &sb; 56592f172c55SRobert Thurlow sarg.is_referral = B_FALSE; 56607c478bd9Sstevel@tonic-gate nfs4_ntov_table_init(&ntov); 56617c478bd9Sstevel@tonic-gate resp->status = do_rfs4_set_attrs(NULL, &args->obj_attributes, cs, 56627c478bd9Sstevel@tonic-gate &sarg, &ntov, NFS4ATTR_VERIT); 56637c478bd9Sstevel@tonic-gate if (resp->status != NFS4_OK) { 56647c478bd9Sstevel@tonic-gate /* 56657c478bd9Sstevel@tonic-gate * do_rfs4_set_attrs will try to verify systemwide attrs, 56667c478bd9Sstevel@tonic-gate * so could return -1 for "no match". 56677c478bd9Sstevel@tonic-gate */ 56687c478bd9Sstevel@tonic-gate if (resp->status == -1) 56697c478bd9Sstevel@tonic-gate resp->status = NFS4ERR_NOT_SAME; 56707c478bd9Sstevel@tonic-gate goto done; 56717c478bd9Sstevel@tonic-gate } 56727c478bd9Sstevel@tonic-gate error = rfs4_verify_attr(&sarg, NULL, &ntov); 56737c478bd9Sstevel@tonic-gate switch (error) { 56747c478bd9Sstevel@tonic-gate case 0: 56757c478bd9Sstevel@tonic-gate resp->status = NFS4_OK; 56767c478bd9Sstevel@tonic-gate break; 56777c478bd9Sstevel@tonic-gate case -1: 56787c478bd9Sstevel@tonic-gate resp->status = NFS4ERR_NOT_SAME; 56797c478bd9Sstevel@tonic-gate break; 56807c478bd9Sstevel@tonic-gate default: 56817c478bd9Sstevel@tonic-gate resp->status = puterrno4(error); 56827c478bd9Sstevel@tonic-gate break; 56837c478bd9Sstevel@tonic-gate } 56847c478bd9Sstevel@tonic-gate done: 56857c478bd9Sstevel@tonic-gate *cs->statusp = resp->status; 56867c478bd9Sstevel@tonic-gate nfs4_ntov_table_free(&ntov, &sarg); 5687f3b585ceSsamf out: 5688f3b585ceSsamf DTRACE_NFSV4_2(op__verify__done, struct compound_state *, cs, 5689f3b585ceSsamf VERIFY4res *, resp); 56907c478bd9Sstevel@tonic-gate } 56917c478bd9Sstevel@tonic-gate 56927c478bd9Sstevel@tonic-gate /* ARGSUSED */ 56937c478bd9Sstevel@tonic-gate static void 56947c478bd9Sstevel@tonic-gate rfs4_op_nverify(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req, 56957c478bd9Sstevel@tonic-gate struct compound_state *cs) 56967c478bd9Sstevel@tonic-gate { 56977c478bd9Sstevel@tonic-gate /* 56987c478bd9Sstevel@tonic-gate * verify and nverify are exactly the same, except that nverify 56997c478bd9Sstevel@tonic-gate * succeeds when some argument changed, and verify succeeds when 57007c478bd9Sstevel@tonic-gate * when none changed. 57017c478bd9Sstevel@tonic-gate */ 57027c478bd9Sstevel@tonic-gate 57037c478bd9Sstevel@tonic-gate NVERIFY4args *args = &argop->nfs_argop4_u.opnverify; 57047c478bd9Sstevel@tonic-gate NVERIFY4res *resp = &resop->nfs_resop4_u.opnverify; 57057c478bd9Sstevel@tonic-gate 57067c478bd9Sstevel@tonic-gate int error; 57077c478bd9Sstevel@tonic-gate struct nfs4_svgetit_arg sarg; 57087c478bd9Sstevel@tonic-gate struct statvfs64 sb; 57097c478bd9Sstevel@tonic-gate struct nfs4_ntov_table ntov; 57107c478bd9Sstevel@tonic-gate 5711f3b585ceSsamf DTRACE_NFSV4_2(op__nverify__start, struct compound_state *, cs, 5712f3b585ceSsamf NVERIFY4args *, args); 5713f3b585ceSsamf 57147c478bd9Sstevel@tonic-gate if (cs->vp == NULL) { 57157c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE; 5716f3b585ceSsamf DTRACE_NFSV4_2(op__nverify__done, struct compound_state *, cs, 5717f3b585ceSsamf NVERIFY4res *, resp); 57187c478bd9Sstevel@tonic-gate return; 57197c478bd9Sstevel@tonic-gate } 57207c478bd9Sstevel@tonic-gate sarg.sbp = &sb; 57212f172c55SRobert Thurlow sarg.is_referral = B_FALSE; 57227c478bd9Sstevel@tonic-gate nfs4_ntov_table_init(&ntov); 57237c478bd9Sstevel@tonic-gate resp->status = do_rfs4_set_attrs(NULL, &args->obj_attributes, cs, 57247c478bd9Sstevel@tonic-gate &sarg, &ntov, NFS4ATTR_VERIT); 57257c478bd9Sstevel@tonic-gate if (resp->status != NFS4_OK) { 57267c478bd9Sstevel@tonic-gate /* 57277c478bd9Sstevel@tonic-gate * do_rfs4_set_attrs will try to verify systemwide attrs, 57287c478bd9Sstevel@tonic-gate * so could return -1 for "no match". 57297c478bd9Sstevel@tonic-gate */ 57307c478bd9Sstevel@tonic-gate if (resp->status == -1) 57317c478bd9Sstevel@tonic-gate resp->status = NFS4_OK; 57327c478bd9Sstevel@tonic-gate goto done; 57337c478bd9Sstevel@tonic-gate } 57347c478bd9Sstevel@tonic-gate error = rfs4_verify_attr(&sarg, NULL, &ntov); 57357c478bd9Sstevel@tonic-gate switch (error) { 57367c478bd9Sstevel@tonic-gate case 0: 57377c478bd9Sstevel@tonic-gate resp->status = NFS4ERR_SAME; 57387c478bd9Sstevel@tonic-gate break; 57397c478bd9Sstevel@tonic-gate case -1: 57407c478bd9Sstevel@tonic-gate resp->status = NFS4_OK; 57417c478bd9Sstevel@tonic-gate break; 57427c478bd9Sstevel@tonic-gate default: 57437c478bd9Sstevel@tonic-gate resp->status = puterrno4(error); 57447c478bd9Sstevel@tonic-gate break; 57457c478bd9Sstevel@tonic-gate } 57467c478bd9Sstevel@tonic-gate done: 57477c478bd9Sstevel@tonic-gate *cs->statusp = resp->status; 57487c478bd9Sstevel@tonic-gate nfs4_ntov_table_free(&ntov, &sarg); 5749f3b585ceSsamf 5750f3b585ceSsamf DTRACE_NFSV4_2(op__nverify__done, struct compound_state *, cs, 5751f3b585ceSsamf NVERIFY4res *, resp); 57527c478bd9Sstevel@tonic-gate } 57537c478bd9Sstevel@tonic-gate 57547c478bd9Sstevel@tonic-gate /* 57557c478bd9Sstevel@tonic-gate * XXX - This should live in an NFS header file. 57567c478bd9Sstevel@tonic-gate */ 57577c478bd9Sstevel@tonic-gate #define MAX_IOVECS 12 57587c478bd9Sstevel@tonic-gate 57597c478bd9Sstevel@tonic-gate /* ARGSUSED */ 57607c478bd9Sstevel@tonic-gate static void 57617c478bd9Sstevel@tonic-gate rfs4_op_write(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req, 57627c478bd9Sstevel@tonic-gate struct compound_state *cs) 57637c478bd9Sstevel@tonic-gate { 57647c478bd9Sstevel@tonic-gate WRITE4args *args = &argop->nfs_argop4_u.opwrite; 57657c478bd9Sstevel@tonic-gate WRITE4res *resp = &resop->nfs_resop4_u.opwrite; 57667c478bd9Sstevel@tonic-gate int error; 57677c478bd9Sstevel@tonic-gate vnode_t *vp; 57687c478bd9Sstevel@tonic-gate struct vattr bva; 57697c478bd9Sstevel@tonic-gate u_offset_t rlimit; 57707c478bd9Sstevel@tonic-gate struct uio uio; 57717c478bd9Sstevel@tonic-gate struct iovec iov[MAX_IOVECS]; 57727c478bd9Sstevel@tonic-gate struct iovec *iovp; 57737c478bd9Sstevel@tonic-gate int iovcnt; 57747c478bd9Sstevel@tonic-gate int ioflag; 57757c478bd9Sstevel@tonic-gate cred_t *savecred, *cr; 57767c478bd9Sstevel@tonic-gate bool_t *deleg = &cs->deleg; 57777c478bd9Sstevel@tonic-gate nfsstat4 stat; 57787c478bd9Sstevel@tonic-gate int in_crit = 0; 5779da6c28aaSamw caller_context_t ct; 57800dfe541eSEvan Layton nfs4_srv_t *nsrv4; 57817c478bd9Sstevel@tonic-gate 5782f3b585ceSsamf DTRACE_NFSV4_2(op__write__start, struct compound_state *, cs, 5783f3b585ceSsamf WRITE4args *, args); 5784f3b585ceSsamf 57857c478bd9Sstevel@tonic-gate vp = cs->vp; 57867c478bd9Sstevel@tonic-gate if (vp == NULL) { 57877c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE; 5788f3b585ceSsamf goto out; 57897c478bd9Sstevel@tonic-gate } 57907c478bd9Sstevel@tonic-gate if (cs->access == CS_ACCESS_DENIED) { 57917c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_ACCESS; 5792f3b585ceSsamf goto out; 57937c478bd9Sstevel@tonic-gate } 57947c478bd9Sstevel@tonic-gate 57957c478bd9Sstevel@tonic-gate cr = cs->cr; 57967c478bd9Sstevel@tonic-gate 5797da6c28aaSamw if ((stat = rfs4_check_stateid(FWRITE, vp, &args->stateid, FALSE, 5798*f44e1126SVitaliy Gusev deleg, TRUE, &ct, cs)) != NFS4_OK) { 5799da6c28aaSamw *cs->statusp = resp->status = stat; 5800da6c28aaSamw goto out; 5801da6c28aaSamw } 5802da6c28aaSamw 58037c478bd9Sstevel@tonic-gate /* 58047c478bd9Sstevel@tonic-gate * We have to enter the critical region before calling VOP_RWLOCK 58057c478bd9Sstevel@tonic-gate * to avoid a deadlock with ufs. 58067c478bd9Sstevel@tonic-gate */ 58077c478bd9Sstevel@tonic-gate if (nbl_need_check(vp)) { 58087c478bd9Sstevel@tonic-gate nbl_start_crit(vp, RW_READER); 58097c478bd9Sstevel@tonic-gate in_crit = 1; 58107c478bd9Sstevel@tonic-gate if (nbl_conflict(vp, NBL_WRITE, 5811da6c28aaSamw args->offset, args->data_len, 0, &ct)) { 58127c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_LOCKED; 58137c478bd9Sstevel@tonic-gate goto out; 58147c478bd9Sstevel@tonic-gate } 58157c478bd9Sstevel@tonic-gate } 58167c478bd9Sstevel@tonic-gate 58177c478bd9Sstevel@tonic-gate bva.va_mask = AT_MODE | AT_UID; 5818da6c28aaSamw error = VOP_GETATTR(vp, &bva, 0, cr, &ct); 58197c478bd9Sstevel@tonic-gate 58207c478bd9Sstevel@tonic-gate /* 58217c478bd9Sstevel@tonic-gate * If we can't get the attributes, then we can't do the 58227c478bd9Sstevel@tonic-gate * right access checking. So, we'll fail the request. 58237c478bd9Sstevel@tonic-gate */ 58247c478bd9Sstevel@tonic-gate if (error) { 58257c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = puterrno4(error); 58267c478bd9Sstevel@tonic-gate goto out; 58277c478bd9Sstevel@tonic-gate } 58287c478bd9Sstevel@tonic-gate 58295cb0d679SMarcel Telka if (rdonly4(req, cs)) { 58307c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_ROFS; 58317c478bd9Sstevel@tonic-gate goto out; 58327c478bd9Sstevel@tonic-gate } 58337c478bd9Sstevel@tonic-gate 58347c478bd9Sstevel@tonic-gate if (vp->v_type != VREG) { 58357c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = 58367c478bd9Sstevel@tonic-gate ((vp->v_type == VDIR) ? NFS4ERR_ISDIR : NFS4ERR_INVAL); 58377c478bd9Sstevel@tonic-gate goto out; 58387c478bd9Sstevel@tonic-gate } 58397c478bd9Sstevel@tonic-gate 58407c478bd9Sstevel@tonic-gate if (crgetuid(cr) != bva.va_uid && 5841da6c28aaSamw (error = VOP_ACCESS(vp, VWRITE, 0, cr, &ct))) { 58427c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = puterrno4(error); 58437c478bd9Sstevel@tonic-gate goto out; 58447c478bd9Sstevel@tonic-gate } 58457c478bd9Sstevel@tonic-gate 58467c478bd9Sstevel@tonic-gate if (MANDLOCK(vp, bva.va_mode)) { 58477c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_ACCESS; 58487c478bd9Sstevel@tonic-gate goto out; 58497c478bd9Sstevel@tonic-gate } 58507c478bd9Sstevel@tonic-gate 58510dfe541eSEvan Layton nsrv4 = nfs4_get_srv(); 58527c478bd9Sstevel@tonic-gate if (args->data_len == 0) { 58537c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4_OK; 58547c478bd9Sstevel@tonic-gate resp->count = 0; 58557c478bd9Sstevel@tonic-gate resp->committed = args->stable; 58560dfe541eSEvan Layton resp->writeverf = nsrv4->write4verf; 58577c478bd9Sstevel@tonic-gate goto out; 58587c478bd9Sstevel@tonic-gate } 58597c478bd9Sstevel@tonic-gate 58607c478bd9Sstevel@tonic-gate if (args->mblk != NULL) { 58617c478bd9Sstevel@tonic-gate mblk_t *m; 58627c478bd9Sstevel@tonic-gate uint_t bytes, round_len; 58637c478bd9Sstevel@tonic-gate 58647c478bd9Sstevel@tonic-gate iovcnt = 0; 58657c478bd9Sstevel@tonic-gate bytes = 0; 58667c478bd9Sstevel@tonic-gate round_len = roundup(args->data_len, BYTES_PER_XDR_UNIT); 58677c478bd9Sstevel@tonic-gate for (m = args->mblk; 58687c478bd9Sstevel@tonic-gate m != NULL && bytes < round_len; 58697c478bd9Sstevel@tonic-gate m = m->b_cont) { 58707c478bd9Sstevel@tonic-gate iovcnt++; 58717c478bd9Sstevel@tonic-gate bytes += MBLKL(m); 58727c478bd9Sstevel@tonic-gate } 58737c478bd9Sstevel@tonic-gate #ifdef DEBUG 58747c478bd9Sstevel@tonic-gate /* should have ended on an mblk boundary */ 58757c478bd9Sstevel@tonic-gate if (bytes != round_len) { 58767c478bd9Sstevel@tonic-gate printf("bytes=0x%x, round_len=0x%x, req len=0x%x\n", 58777c478bd9Sstevel@tonic-gate bytes, round_len, args->data_len); 58787c478bd9Sstevel@tonic-gate printf("args=%p, args->mblk=%p, m=%p", (void *)args, 58797c478bd9Sstevel@tonic-gate (void *)args->mblk, (void *)m); 58807c478bd9Sstevel@tonic-gate ASSERT(bytes == round_len); 58817c478bd9Sstevel@tonic-gate } 58827c478bd9Sstevel@tonic-gate #endif 58837c478bd9Sstevel@tonic-gate if (iovcnt <= MAX_IOVECS) { 58847c478bd9Sstevel@tonic-gate iovp = iov; 58857c478bd9Sstevel@tonic-gate } else { 58867c478bd9Sstevel@tonic-gate iovp = kmem_alloc(sizeof (*iovp) * iovcnt, KM_SLEEP); 58877c478bd9Sstevel@tonic-gate } 58887c478bd9Sstevel@tonic-gate mblk_to_iov(args->mblk, iovcnt, iovp); 58890a701b1eSRobert Gordon } else if (args->rlist != NULL) { 58900a701b1eSRobert Gordon iovcnt = 1; 58910a701b1eSRobert Gordon iovp = iov; 58920a701b1eSRobert Gordon iovp->iov_base = (char *)((args->rlist)->u.c_daddr3); 58930a701b1eSRobert Gordon iovp->iov_len = args->data_len; 58947c478bd9Sstevel@tonic-gate } else { 58957c478bd9Sstevel@tonic-gate iovcnt = 1; 58967c478bd9Sstevel@tonic-gate iovp = iov; 58977c478bd9Sstevel@tonic-gate iovp->iov_base = args->data_val; 58987c478bd9Sstevel@tonic-gate iovp->iov_len = args->data_len; 58997c478bd9Sstevel@tonic-gate } 59007c478bd9Sstevel@tonic-gate 59017c478bd9Sstevel@tonic-gate uio.uio_iov = iovp; 59027c478bd9Sstevel@tonic-gate uio.uio_iovcnt = iovcnt; 59037c478bd9Sstevel@tonic-gate 59047c478bd9Sstevel@tonic-gate uio.uio_segflg = UIO_SYSSPACE; 59057c478bd9Sstevel@tonic-gate uio.uio_extflg = UIO_COPY_DEFAULT; 59067c478bd9Sstevel@tonic-gate uio.uio_loffset = args->offset; 59077c478bd9Sstevel@tonic-gate uio.uio_resid = args->data_len; 59087c478bd9Sstevel@tonic-gate uio.uio_llimit = curproc->p_fsz_ctl; 59097c478bd9Sstevel@tonic-gate rlimit = uio.uio_llimit - args->offset; 59107c478bd9Sstevel@tonic-gate if (rlimit < (u_offset_t)uio.uio_resid) 59117c478bd9Sstevel@tonic-gate uio.uio_resid = (int)rlimit; 59127c478bd9Sstevel@tonic-gate 59137c478bd9Sstevel@tonic-gate if (args->stable == UNSTABLE4) 59147c478bd9Sstevel@tonic-gate ioflag = 0; 59157c478bd9Sstevel@tonic-gate else if (args->stable == FILE_SYNC4) 59167c478bd9Sstevel@tonic-gate ioflag = FSYNC; 59177c478bd9Sstevel@tonic-gate else if (args->stable == DATA_SYNC4) 59187c478bd9Sstevel@tonic-gate ioflag = FDSYNC; 59197c478bd9Sstevel@tonic-gate else { 59207c478bd9Sstevel@tonic-gate if (iovp != iov) 59217c478bd9Sstevel@tonic-gate kmem_free(iovp, sizeof (*iovp) * iovcnt); 59227c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_INVAL; 59237c478bd9Sstevel@tonic-gate goto out; 59247c478bd9Sstevel@tonic-gate } 59257c478bd9Sstevel@tonic-gate 59267c478bd9Sstevel@tonic-gate /* 59277c478bd9Sstevel@tonic-gate * We're changing creds because VM may fault and we need 59287c478bd9Sstevel@tonic-gate * the cred of the current thread to be used if quota 59297c478bd9Sstevel@tonic-gate * checking is enabled. 59307c478bd9Sstevel@tonic-gate */ 59317c478bd9Sstevel@tonic-gate savecred = curthread->t_cred; 59327c478bd9Sstevel@tonic-gate curthread->t_cred = cr; 5933da6c28aaSamw error = do_io(FWRITE, vp, &uio, ioflag, cr, &ct); 59347c478bd9Sstevel@tonic-gate curthread->t_cred = savecred; 59357c478bd9Sstevel@tonic-gate 59367c478bd9Sstevel@tonic-gate if (iovp != iov) 59377c478bd9Sstevel@tonic-gate kmem_free(iovp, sizeof (*iovp) * iovcnt); 59387c478bd9Sstevel@tonic-gate 59397c478bd9Sstevel@tonic-gate if (error) { 59407c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = puterrno4(error); 59417c478bd9Sstevel@tonic-gate goto out; 59427c478bd9Sstevel@tonic-gate } 59437c478bd9Sstevel@tonic-gate 59447c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4_OK; 59457c478bd9Sstevel@tonic-gate resp->count = args->data_len - uio.uio_resid; 59467c478bd9Sstevel@tonic-gate 59477c478bd9Sstevel@tonic-gate if (ioflag == 0) 59487c478bd9Sstevel@tonic-gate resp->committed = UNSTABLE4; 59497c478bd9Sstevel@tonic-gate else 59507c478bd9Sstevel@tonic-gate resp->committed = FILE_SYNC4; 59517c478bd9Sstevel@tonic-gate 59520dfe541eSEvan Layton resp->writeverf = nsrv4->write4verf; 59537c478bd9Sstevel@tonic-gate 59547c478bd9Sstevel@tonic-gate out: 59557c478bd9Sstevel@tonic-gate if (in_crit) 59567c478bd9Sstevel@tonic-gate nbl_end_crit(vp); 5957f3b585ceSsamf 5958f3b585ceSsamf DTRACE_NFSV4_2(op__write__done, struct compound_state *, cs, 5959f3b585ceSsamf WRITE4res *, resp); 59607c478bd9Sstevel@tonic-gate } 59617c478bd9Sstevel@tonic-gate 5962*f44e1126SVitaliy Gusev static inline int 5963*f44e1126SVitaliy Gusev rfs4_opnum_in_range(const compound_state_t *cs, int opnum) 5964*f44e1126SVitaliy Gusev { 5965*f44e1126SVitaliy Gusev if (opnum < FIRST_NFS4_OP || opnum > LAST_NFS4_OP) 5966*f44e1126SVitaliy Gusev return (0); 5967*f44e1126SVitaliy Gusev else if (cs->minorversion == 0 && opnum > LAST_NFS40_OP) 5968*f44e1126SVitaliy Gusev return (0); 5969*f44e1126SVitaliy Gusev else if (cs->minorversion == 1 && opnum > LAST_NFS41_OP) 5970*f44e1126SVitaliy Gusev return (0); 5971*f44e1126SVitaliy Gusev else if (cs->minorversion == 2 && opnum > LAST_NFS42_OP) 5972*f44e1126SVitaliy Gusev return (0); 5973*f44e1126SVitaliy Gusev return (1); 5974*f44e1126SVitaliy Gusev } 5975*f44e1126SVitaliy Gusev 59767c478bd9Sstevel@tonic-gate void 5977*f44e1126SVitaliy Gusev rfs4_compound(COMPOUND4args *args, COMPOUND4res *resp, compound_state_t *cs, 5978*f44e1126SVitaliy Gusev struct svc_req *req, int *rv) 59797c478bd9Sstevel@tonic-gate { 59807c478bd9Sstevel@tonic-gate uint_t i; 5981*f44e1126SVitaliy Gusev cred_t *cr; 59820dfe541eSEvan Layton nfs4_srv_t *nsrv4; 59830dfe541eSEvan Layton nfs_export_t *ne = nfs_get_export(); 59847c478bd9Sstevel@tonic-gate 59852e9d26a4Srmesta if (rv != NULL) 59862e9d26a4Srmesta *rv = 0; 59877c478bd9Sstevel@tonic-gate /* 59880dfe541eSEvan Layton * Form a reply tag by copying over the request tag. 59897c478bd9Sstevel@tonic-gate */ 59900dfe541eSEvan Layton resp->tag.utf8string_len = args->tag.utf8string_len; 59910dfe541eSEvan Layton if (args->tag.utf8string_len != 0) { 59927c478bd9Sstevel@tonic-gate resp->tag.utf8string_val = 59937c478bd9Sstevel@tonic-gate kmem_alloc(args->tag.utf8string_len, KM_SLEEP); 59947c478bd9Sstevel@tonic-gate bcopy(args->tag.utf8string_val, resp->tag.utf8string_val, 59957c478bd9Sstevel@tonic-gate resp->tag.utf8string_len); 59960dfe541eSEvan Layton } else { 59970dfe541eSEvan Layton resp->tag.utf8string_val = NULL; 59980dfe541eSEvan Layton } 59997c478bd9Sstevel@tonic-gate 6000*f44e1126SVitaliy Gusev cs->statusp = &resp->status; 6001*f44e1126SVitaliy Gusev cs->req = req; 6002*f44e1126SVitaliy Gusev cs->minorversion = args->minorversion; 6003945b8d40SDaniil Lunev resp->array = NULL; 6004945b8d40SDaniil Lunev resp->array_len = 0; 60057c478bd9Sstevel@tonic-gate 6006945b8d40SDaniil Lunev if (args->array_len == 0) { 6007945b8d40SDaniil Lunev resp->status = NFS4_OK; 6008945b8d40SDaniil Lunev return; 6009945b8d40SDaniil Lunev } 6010945b8d40SDaniil Lunev 6011214d537cSVitaliy Gusev cr = svc_xprt_cred(req->rq_xprt); 60127c478bd9Sstevel@tonic-gate ASSERT(cr != NULL); 60137c478bd9Sstevel@tonic-gate 6014*f44e1126SVitaliy Gusev if (sec_svc_getcred(req, cr, &cs->principal, &cs->nfsflavor) == 0) { 6015f3b585ceSsamf DTRACE_NFSV4_2(compound__start, struct compound_state *, 6016*f44e1126SVitaliy Gusev cs, COMPOUND4args *, args); 6017f3b585ceSsamf DTRACE_NFSV4_2(compound__done, struct compound_state *, 6018*f44e1126SVitaliy Gusev cs, COMPOUND4res *, resp); 60192e9d26a4Srmesta svcerr_badcred(req->rq_xprt); 60202e9d26a4Srmesta if (rv != NULL) 60212e9d26a4Srmesta *rv = 1; 60227c478bd9Sstevel@tonic-gate return; 60237c478bd9Sstevel@tonic-gate } 6024*f44e1126SVitaliy Gusev 60252e9d26a4Srmesta resp->array_len = args->array_len; 60262e9d26a4Srmesta resp->array = kmem_zalloc(args->array_len * sizeof (nfs_resop4), 60272e9d26a4Srmesta KM_SLEEP); 60287c478bd9Sstevel@tonic-gate 6029*f44e1126SVitaliy Gusev cs->op_len = args->array_len; 6030*f44e1126SVitaliy Gusev cs->basecr = cr; 60310dfe541eSEvan Layton nsrv4 = nfs4_get_srv(); 60327c478bd9Sstevel@tonic-gate 6033*f44e1126SVitaliy Gusev DTRACE_NFSV4_2(compound__start, struct compound_state *, cs, 6034f3b585ceSsamf COMPOUND4args *, args); 60357c478bd9Sstevel@tonic-gate 60367c478bd9Sstevel@tonic-gate /* 60377c478bd9Sstevel@tonic-gate * For now, NFS4 compound processing must be protected by 60387c478bd9Sstevel@tonic-gate * exported_lock because it can access more than one exportinfo 60397c478bd9Sstevel@tonic-gate * per compound and share/unshare can now change multiple 60407c478bd9Sstevel@tonic-gate * exinfo structs. The NFS2/3 code only refs 1 exportinfo 60417c478bd9Sstevel@tonic-gate * per proc (excluding public exinfo), and exi_count design 60427c478bd9Sstevel@tonic-gate * is sufficient to protect concurrent execution of NFS2/3 60437c478bd9Sstevel@tonic-gate * ops along with unexport. This lock will be removed as 60447c478bd9Sstevel@tonic-gate * part of the NFSv4 phase 2 namespace redesign work. 60457c478bd9Sstevel@tonic-gate */ 60460dfe541eSEvan Layton rw_enter(&ne->exported_lock, RW_READER); 60477c478bd9Sstevel@tonic-gate 60487c478bd9Sstevel@tonic-gate /* 60497c478bd9Sstevel@tonic-gate * If this is the first compound we've seen, we need to start all 60507c478bd9Sstevel@tonic-gate * new instances' grace periods. 60517c478bd9Sstevel@tonic-gate */ 60520dfe541eSEvan Layton if (nsrv4->seen_first_compound == 0) { 60530dfe541eSEvan Layton rfs4_grace_start_new(nsrv4); 60547c478bd9Sstevel@tonic-gate /* 60557c478bd9Sstevel@tonic-gate * This must be set after rfs4_grace_start_new(), otherwise 60567c478bd9Sstevel@tonic-gate * another thread could proceed past here before the former 60577c478bd9Sstevel@tonic-gate * is finished. 60587c478bd9Sstevel@tonic-gate */ 60590dfe541eSEvan Layton nsrv4->seen_first_compound = 1; 60607c478bd9Sstevel@tonic-gate } 60617c478bd9Sstevel@tonic-gate 6062*f44e1126SVitaliy Gusev for (i = 0; i < args->array_len && cs->cont; i++) { 60637c478bd9Sstevel@tonic-gate nfs_argop4 *argop; 60647c478bd9Sstevel@tonic-gate nfs_resop4 *resop; 60657c478bd9Sstevel@tonic-gate uint_t op; 60660dfe541eSEvan Layton kstat_named_t *stat = ne->ne_globals->rfsproccnt[NFS_V4]; 60677c478bd9Sstevel@tonic-gate 60687c478bd9Sstevel@tonic-gate argop = &args->array[i]; 60697c478bd9Sstevel@tonic-gate resop = &resp->array[i]; 60707c478bd9Sstevel@tonic-gate resop->resop = argop->argop; 60717c478bd9Sstevel@tonic-gate op = (uint_t)resop->resop; 60727c478bd9Sstevel@tonic-gate 6073*f44e1126SVitaliy Gusev cs->op_pos = i; 6074*f44e1126SVitaliy Gusev if (op < rfsv4disp_cnt && rfs4_opnum_in_range(cs, op)) { 60757c478bd9Sstevel@tonic-gate /* 60767c478bd9Sstevel@tonic-gate * Count the individual ops here; NULL and COMPOUND 60777c478bd9Sstevel@tonic-gate * are counted in common_dispatch() 60787c478bd9Sstevel@tonic-gate */ 60790dfe541eSEvan Layton stat[op].value.ui64++; 60807c478bd9Sstevel@tonic-gate 60817c478bd9Sstevel@tonic-gate NFS4_DEBUG(rfs4_debug > 1, 60827c478bd9Sstevel@tonic-gate (CE_NOTE, "Executing %s", rfs4_op_string[op])); 6083*f44e1126SVitaliy Gusev (*rfsv4disptab[op].dis_proc)(argop, resop, req, cs); 60841b300de9Sjwahlig NFS4_DEBUG(rfs4_debug > 1, (CE_NOTE, "%s returned %d", 6085*f44e1126SVitaliy Gusev rfs4_op_string[op], *cs->statusp)); 6086*f44e1126SVitaliy Gusev if (*cs->statusp != NFS4_OK) 6087*f44e1126SVitaliy Gusev cs->cont = FALSE; 60887c478bd9Sstevel@tonic-gate } else { 60897c478bd9Sstevel@tonic-gate /* 60907c478bd9Sstevel@tonic-gate * This is effectively dead code since XDR code 60917c478bd9Sstevel@tonic-gate * will have already returned BADXDR if op doesn't 60927c478bd9Sstevel@tonic-gate * decode to legal value. This only done for a 60937c478bd9Sstevel@tonic-gate * day when XDR code doesn't verify v4 opcodes. 60947c478bd9Sstevel@tonic-gate */ 60957c478bd9Sstevel@tonic-gate op = OP_ILLEGAL; 60960dfe541eSEvan Layton stat[OP_ILLEGAL_IDX].value.ui64++; 60977c478bd9Sstevel@tonic-gate 6098*f44e1126SVitaliy Gusev rfs4_op_illegal(argop, resop, req, cs); 6099*f44e1126SVitaliy Gusev cs->cont = FALSE; 61007c478bd9Sstevel@tonic-gate } 61017c478bd9Sstevel@tonic-gate 61027c478bd9Sstevel@tonic-gate /* 61037c478bd9Sstevel@tonic-gate * If not at last op, and if we are to stop, then 61047c478bd9Sstevel@tonic-gate * compact the results array. 61057c478bd9Sstevel@tonic-gate */ 6106*f44e1126SVitaliy Gusev if ((i + 1) < args->array_len && !cs->cont) { 61077c478bd9Sstevel@tonic-gate nfs_resop4 *new_res = kmem_alloc( 61087c478bd9Sstevel@tonic-gate (i+1) * sizeof (nfs_resop4), KM_SLEEP); 61097c478bd9Sstevel@tonic-gate bcopy(resp->array, 61107c478bd9Sstevel@tonic-gate new_res, (i+1) * sizeof (nfs_resop4)); 61117c478bd9Sstevel@tonic-gate kmem_free(resp->array, 61127c478bd9Sstevel@tonic-gate args->array_len * sizeof (nfs_resop4)); 61137c478bd9Sstevel@tonic-gate 61147c478bd9Sstevel@tonic-gate resp->array_len = i + 1; 61157c478bd9Sstevel@tonic-gate resp->array = new_res; 61167c478bd9Sstevel@tonic-gate } 61177c478bd9Sstevel@tonic-gate } 61187c478bd9Sstevel@tonic-gate 61190dfe541eSEvan Layton rw_exit(&ne->exported_lock); 61207c478bd9Sstevel@tonic-gate 6121*f44e1126SVitaliy Gusev DTRACE_NFSV4_2(compound__done, struct compound_state *, cs, 61220dfe541eSEvan Layton COMPOUND4res *, resp); 61230dfe541eSEvan Layton 612445916cd2Sjpk /* 612545916cd2Sjpk * done with this compound request, free the label 612645916cd2Sjpk */ 612745916cd2Sjpk 612845916cd2Sjpk if (req->rq_label != NULL) { 612945916cd2Sjpk kmem_free(req->rq_label, sizeof (bslabel_t)); 613045916cd2Sjpk req->rq_label = NULL; 613145916cd2Sjpk } 61327c478bd9Sstevel@tonic-gate } 61337c478bd9Sstevel@tonic-gate 61347c478bd9Sstevel@tonic-gate /* 61357c478bd9Sstevel@tonic-gate * XXX because of what appears to be duplicate calls to rfs4_compound_free 61367c478bd9Sstevel@tonic-gate * XXX zero out the tag and array values. Need to investigate why the 61377c478bd9Sstevel@tonic-gate * XXX calls occur, but at least prevent the panic for now. 61387c478bd9Sstevel@tonic-gate */ 61397c478bd9Sstevel@tonic-gate void 61407c478bd9Sstevel@tonic-gate rfs4_compound_free(COMPOUND4res *resp) 61417c478bd9Sstevel@tonic-gate { 61427c478bd9Sstevel@tonic-gate uint_t i; 61437c478bd9Sstevel@tonic-gate 61447c478bd9Sstevel@tonic-gate if (resp->tag.utf8string_val) { 61457c478bd9Sstevel@tonic-gate UTF8STRING_FREE(resp->tag) 61467c478bd9Sstevel@tonic-gate } 61477c478bd9Sstevel@tonic-gate 61487c478bd9Sstevel@tonic-gate for (i = 0; i < resp->array_len; i++) { 61497c478bd9Sstevel@tonic-gate nfs_resop4 *resop; 61507c478bd9Sstevel@tonic-gate uint_t op; 61517c478bd9Sstevel@tonic-gate 61527c478bd9Sstevel@tonic-gate resop = &resp->array[i]; 61537c478bd9Sstevel@tonic-gate op = (uint_t)resop->resop; 61547c478bd9Sstevel@tonic-gate if (op < rfsv4disp_cnt) { 61557c478bd9Sstevel@tonic-gate (*rfsv4disptab[op].dis_resfree)(resop); 61567c478bd9Sstevel@tonic-gate } 61577c478bd9Sstevel@tonic-gate } 61587c478bd9Sstevel@tonic-gate if (resp->array != NULL) { 61597c478bd9Sstevel@tonic-gate kmem_free(resp->array, resp->array_len * sizeof (nfs_resop4)); 61607c478bd9Sstevel@tonic-gate } 61617c478bd9Sstevel@tonic-gate } 61627c478bd9Sstevel@tonic-gate 61637c478bd9Sstevel@tonic-gate /* 61647c478bd9Sstevel@tonic-gate * Process the value of the compound request rpc flags, as a bit-AND 61657c478bd9Sstevel@tonic-gate * of the individual per-op flags (idempotent, allowork, publicfh_ok) 61667c478bd9Sstevel@tonic-gate */ 61677c478bd9Sstevel@tonic-gate void 61687c478bd9Sstevel@tonic-gate rfs4_compound_flagproc(COMPOUND4args *args, int *flagp) 61697c478bd9Sstevel@tonic-gate { 61707c478bd9Sstevel@tonic-gate int i; 61717c478bd9Sstevel@tonic-gate int flag = RPC_ALL; 61727c478bd9Sstevel@tonic-gate 61737c478bd9Sstevel@tonic-gate for (i = 0; flag && i < args->array_len; i++) { 61747c478bd9Sstevel@tonic-gate uint_t op; 61757c478bd9Sstevel@tonic-gate 61767c478bd9Sstevel@tonic-gate op = (uint_t)args->array[i].argop; 61777c478bd9Sstevel@tonic-gate 61787c478bd9Sstevel@tonic-gate if (op < rfsv4disp_cnt) 61797c478bd9Sstevel@tonic-gate flag &= rfsv4disptab[op].dis_flags; 61807c478bd9Sstevel@tonic-gate else 61817c478bd9Sstevel@tonic-gate flag = 0; 61827c478bd9Sstevel@tonic-gate } 61837c478bd9Sstevel@tonic-gate *flagp = flag; 61847c478bd9Sstevel@tonic-gate } 61857c478bd9Sstevel@tonic-gate 61867c478bd9Sstevel@tonic-gate nfsstat4 61877c478bd9Sstevel@tonic-gate rfs4_client_sysid(rfs4_client_t *cp, sysid_t *sp) 61887c478bd9Sstevel@tonic-gate { 61897c478bd9Sstevel@tonic-gate nfsstat4 e; 61907c478bd9Sstevel@tonic-gate 6191d216dff5SRobert Mastors rfs4_dbe_lock(cp->rc_dbe); 61927c478bd9Sstevel@tonic-gate 6193d216dff5SRobert Mastors if (cp->rc_sysidt != LM_NOSYSID) { 6194d216dff5SRobert Mastors *sp = cp->rc_sysidt; 61957c478bd9Sstevel@tonic-gate e = NFS4_OK; 61967c478bd9Sstevel@tonic-gate 6197d216dff5SRobert Mastors } else if ((cp->rc_sysidt = lm_alloc_sysidt()) != LM_NOSYSID) { 6198d216dff5SRobert Mastors *sp = cp->rc_sysidt; 61997c478bd9Sstevel@tonic-gate e = NFS4_OK; 62007c478bd9Sstevel@tonic-gate 62017c478bd9Sstevel@tonic-gate NFS4_DEBUG(rfs4_debug, (CE_NOTE, 62027c478bd9Sstevel@tonic-gate "rfs4_client_sysid: allocated 0x%x\n", *sp)); 62037c478bd9Sstevel@tonic-gate } else 62047c478bd9Sstevel@tonic-gate e = NFS4ERR_DELAY; 62057c478bd9Sstevel@tonic-gate 6206d216dff5SRobert Mastors rfs4_dbe_unlock(cp->rc_dbe); 62077c478bd9Sstevel@tonic-gate return (e); 62087c478bd9Sstevel@tonic-gate } 62097c478bd9Sstevel@tonic-gate 62107c478bd9Sstevel@tonic-gate #if defined(DEBUG) && ! defined(lint) 62117c478bd9Sstevel@tonic-gate static void lock_print(char *str, int operation, struct flock64 *flk) 62127c478bd9Sstevel@tonic-gate { 62137c478bd9Sstevel@tonic-gate char *op, *type; 62147c478bd9Sstevel@tonic-gate 62157c478bd9Sstevel@tonic-gate switch (operation) { 62167c478bd9Sstevel@tonic-gate case F_GETLK: op = "F_GETLK"; 62177c478bd9Sstevel@tonic-gate break; 62187c478bd9Sstevel@tonic-gate case F_SETLK: op = "F_SETLK"; 62197c478bd9Sstevel@tonic-gate break; 6220da6c28aaSamw case F_SETLK_NBMAND: op = "F_SETLK_NBMAND"; 6221da6c28aaSamw break; 62227c478bd9Sstevel@tonic-gate default: op = "F_UNKNOWN"; 62237c478bd9Sstevel@tonic-gate break; 62247c478bd9Sstevel@tonic-gate } 62257c478bd9Sstevel@tonic-gate switch (flk->l_type) { 62267c478bd9Sstevel@tonic-gate case F_UNLCK: type = "F_UNLCK"; 62277c478bd9Sstevel@tonic-gate break; 62287c478bd9Sstevel@tonic-gate case F_RDLCK: type = "F_RDLCK"; 62297c478bd9Sstevel@tonic-gate break; 62307c478bd9Sstevel@tonic-gate case F_WRLCK: type = "F_WRLCK"; 62317c478bd9Sstevel@tonic-gate break; 62327c478bd9Sstevel@tonic-gate default: type = "F_UNKNOWN"; 62337c478bd9Sstevel@tonic-gate break; 62347c478bd9Sstevel@tonic-gate } 62357c478bd9Sstevel@tonic-gate 62367c478bd9Sstevel@tonic-gate ASSERT(flk->l_whence == 0); 62377c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "%s: %s, type = %s, off = %llx len = %llx pid = %d", 62381b300de9Sjwahlig str, op, type, (longlong_t)flk->l_start, 62391b300de9Sjwahlig flk->l_len ? (longlong_t)flk->l_len : ~0LL, flk->l_pid); 62407c478bd9Sstevel@tonic-gate } 62417c478bd9Sstevel@tonic-gate 62427c478bd9Sstevel@tonic-gate #define LOCK_PRINT(d, s, t, f) if (d) lock_print(s, t, f) 62437c478bd9Sstevel@tonic-gate #else 62447c478bd9Sstevel@tonic-gate #define LOCK_PRINT(d, s, t, f) 62457c478bd9Sstevel@tonic-gate #endif 62467c478bd9Sstevel@tonic-gate 62477c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 62487c478bd9Sstevel@tonic-gate static bool_t 6249*f44e1126SVitaliy Gusev creds_ok(cred_set_t *cr_set, struct svc_req *req, struct compound_state *cs) 62507c478bd9Sstevel@tonic-gate { 62517c478bd9Sstevel@tonic-gate return (TRUE); 62527c478bd9Sstevel@tonic-gate } 62537c478bd9Sstevel@tonic-gate 62547c478bd9Sstevel@tonic-gate /* 62557c478bd9Sstevel@tonic-gate * Look up the pathname using the vp in cs as the directory vnode. 62567c478bd9Sstevel@tonic-gate * cs->vp will be the vnode for the file on success 62577c478bd9Sstevel@tonic-gate */ 62587c478bd9Sstevel@tonic-gate 62597c478bd9Sstevel@tonic-gate static nfsstat4 62607c478bd9Sstevel@tonic-gate rfs4_lookup(component4 *component, struct svc_req *req, 62617c478bd9Sstevel@tonic-gate struct compound_state *cs) 62627c478bd9Sstevel@tonic-gate { 62637c478bd9Sstevel@tonic-gate char *nm; 62647c478bd9Sstevel@tonic-gate uint32_t len; 62657c478bd9Sstevel@tonic-gate nfsstat4 status; 6266593cc11bSJan Kryl struct sockaddr *ca; 6267593cc11bSJan Kryl char *name; 62687c478bd9Sstevel@tonic-gate 62697c478bd9Sstevel@tonic-gate if (cs->vp == NULL) { 62707c478bd9Sstevel@tonic-gate return (NFS4ERR_NOFILEHANDLE); 62717c478bd9Sstevel@tonic-gate } 62727c478bd9Sstevel@tonic-gate if (cs->vp->v_type != VDIR) { 62737c478bd9Sstevel@tonic-gate return (NFS4ERR_NOTDIR); 62747c478bd9Sstevel@tonic-gate } 62757c478bd9Sstevel@tonic-gate 627615721462SDaniil Lunev status = utf8_dir_verify(component); 627715721462SDaniil Lunev if (status != NFS4_OK) 627815721462SDaniil Lunev return (status); 62797c478bd9Sstevel@tonic-gate 62807c478bd9Sstevel@tonic-gate nm = utf8_to_fn(component, &len, NULL); 62817c478bd9Sstevel@tonic-gate if (nm == NULL) { 62827c478bd9Sstevel@tonic-gate return (NFS4ERR_INVAL); 62837c478bd9Sstevel@tonic-gate } 62847c478bd9Sstevel@tonic-gate 62857c478bd9Sstevel@tonic-gate if (len > MAXNAMELEN) { 62867c478bd9Sstevel@tonic-gate kmem_free(nm, len); 62877c478bd9Sstevel@tonic-gate return (NFS4ERR_NAMETOOLONG); 62887c478bd9Sstevel@tonic-gate } 62897c478bd9Sstevel@tonic-gate 6290593cc11bSJan Kryl ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 6291593cc11bSJan Kryl name = nfscmd_convname(ca, cs->exi, nm, NFSCMD_CONV_INBOUND, 6292593cc11bSJan Kryl MAXPATHLEN + 1); 6293593cc11bSJan Kryl 6294593cc11bSJan Kryl if (name == NULL) { 6295593cc11bSJan Kryl kmem_free(nm, len); 6296593cc11bSJan Kryl return (NFS4ERR_INVAL); 6297593cc11bSJan Kryl } 6298593cc11bSJan Kryl 6299593cc11bSJan Kryl status = do_rfs4_op_lookup(name, req, cs); 6300593cc11bSJan Kryl 6301593cc11bSJan Kryl if (name != nm) 6302593cc11bSJan Kryl kmem_free(name, MAXPATHLEN + 1); 63037c478bd9Sstevel@tonic-gate 63047c478bd9Sstevel@tonic-gate kmem_free(nm, len); 63057c478bd9Sstevel@tonic-gate 63067c478bd9Sstevel@tonic-gate return (status); 63077c478bd9Sstevel@tonic-gate } 63087c478bd9Sstevel@tonic-gate 63097c478bd9Sstevel@tonic-gate static nfsstat4 63107c478bd9Sstevel@tonic-gate rfs4_lookupfile(component4 *component, struct svc_req *req, 6311d216dff5SRobert Mastors struct compound_state *cs, uint32_t access, change_info4 *cinfo) 63127c478bd9Sstevel@tonic-gate { 63137c478bd9Sstevel@tonic-gate nfsstat4 status; 63147c478bd9Sstevel@tonic-gate vnode_t *dvp = cs->vp; 63157c478bd9Sstevel@tonic-gate vattr_t bva, ava, fva; 63167c478bd9Sstevel@tonic-gate int error; 63177c478bd9Sstevel@tonic-gate 63187c478bd9Sstevel@tonic-gate /* Get "before" change value */ 63197c478bd9Sstevel@tonic-gate bva.va_mask = AT_CTIME|AT_SEQ; 6320da6c28aaSamw error = VOP_GETATTR(dvp, &bva, 0, cs->cr, NULL); 63217c478bd9Sstevel@tonic-gate if (error) 63227c478bd9Sstevel@tonic-gate return (puterrno4(error)); 63237c478bd9Sstevel@tonic-gate 63247c478bd9Sstevel@tonic-gate /* rfs4_lookup may VN_RELE directory */ 63257c478bd9Sstevel@tonic-gate VN_HOLD(dvp); 63267c478bd9Sstevel@tonic-gate 63277c478bd9Sstevel@tonic-gate status = rfs4_lookup(component, req, cs); 63287c478bd9Sstevel@tonic-gate if (status != NFS4_OK) { 63297c478bd9Sstevel@tonic-gate VN_RELE(dvp); 63307c478bd9Sstevel@tonic-gate return (status); 63317c478bd9Sstevel@tonic-gate } 63327c478bd9Sstevel@tonic-gate 63337c478bd9Sstevel@tonic-gate /* 63347c478bd9Sstevel@tonic-gate * Get "after" change value, if it fails, simply return the 63357c478bd9Sstevel@tonic-gate * before value. 63367c478bd9Sstevel@tonic-gate */ 63377c478bd9Sstevel@tonic-gate ava.va_mask = AT_CTIME|AT_SEQ; 6338da6c28aaSamw if (VOP_GETATTR(dvp, &ava, 0, cs->cr, NULL)) { 63397c478bd9Sstevel@tonic-gate ava.va_ctime = bva.va_ctime; 63407c478bd9Sstevel@tonic-gate ava.va_seq = 0; 63417c478bd9Sstevel@tonic-gate } 63427c478bd9Sstevel@tonic-gate VN_RELE(dvp); 63437c478bd9Sstevel@tonic-gate 63447c478bd9Sstevel@tonic-gate /* 63457c478bd9Sstevel@tonic-gate * Validate the file is a file 63467c478bd9Sstevel@tonic-gate */ 63477c478bd9Sstevel@tonic-gate fva.va_mask = AT_TYPE|AT_MODE; 6348da6c28aaSamw error = VOP_GETATTR(cs->vp, &fva, 0, cs->cr, NULL); 63497c478bd9Sstevel@tonic-gate if (error) 63507c478bd9Sstevel@tonic-gate return (puterrno4(error)); 63517c478bd9Sstevel@tonic-gate 63527c478bd9Sstevel@tonic-gate if (fva.va_type != VREG) { 63537c478bd9Sstevel@tonic-gate if (fva.va_type == VDIR) 63547c478bd9Sstevel@tonic-gate return (NFS4ERR_ISDIR); 63557c478bd9Sstevel@tonic-gate if (fva.va_type == VLNK) 63567c478bd9Sstevel@tonic-gate return (NFS4ERR_SYMLINK); 63577c478bd9Sstevel@tonic-gate return (NFS4ERR_INVAL); 63587c478bd9Sstevel@tonic-gate } 63597c478bd9Sstevel@tonic-gate 63607c478bd9Sstevel@tonic-gate NFS4_SET_FATTR4_CHANGE(cinfo->before, bva.va_ctime); 63617c478bd9Sstevel@tonic-gate NFS4_SET_FATTR4_CHANGE(cinfo->after, ava.va_ctime); 63627c478bd9Sstevel@tonic-gate 63637c478bd9Sstevel@tonic-gate /* 63647c478bd9Sstevel@tonic-gate * It is undefined if VOP_LOOKUP will change va_seq, so 63657c478bd9Sstevel@tonic-gate * cinfo.atomic = TRUE only if we have 63667c478bd9Sstevel@tonic-gate * non-zero va_seq's, and they have not changed. 63677c478bd9Sstevel@tonic-gate */ 63687c478bd9Sstevel@tonic-gate if (bva.va_seq && ava.va_seq && ava.va_seq == bva.va_seq) 63697c478bd9Sstevel@tonic-gate cinfo->atomic = TRUE; 63707c478bd9Sstevel@tonic-gate else 63717c478bd9Sstevel@tonic-gate cinfo->atomic = FALSE; 63727c478bd9Sstevel@tonic-gate 63737c478bd9Sstevel@tonic-gate /* Check for mandatory locking */ 63747c478bd9Sstevel@tonic-gate cs->mandlock = MANDLOCK(cs->vp, fva.va_mode); 63757c478bd9Sstevel@tonic-gate return (check_open_access(access, cs, req)); 63767c478bd9Sstevel@tonic-gate } 63777c478bd9Sstevel@tonic-gate 63787c478bd9Sstevel@tonic-gate static nfsstat4 63797c478bd9Sstevel@tonic-gate create_vnode(vnode_t *dvp, char *nm, vattr_t *vap, createmode4 mode, 638077e6f23fSVitaliy Gusev cred_t *cr, vnode_t **vpp, bool_t *created) 63817c478bd9Sstevel@tonic-gate { 63827c478bd9Sstevel@tonic-gate int error; 63837c478bd9Sstevel@tonic-gate nfsstat4 status = NFS4_OK; 63847c478bd9Sstevel@tonic-gate vattr_t va; 63857c478bd9Sstevel@tonic-gate 63867c478bd9Sstevel@tonic-gate tryagain: 63877c478bd9Sstevel@tonic-gate 63887c478bd9Sstevel@tonic-gate /* 63897c478bd9Sstevel@tonic-gate * The file open mode used is VWRITE. If the client needs 63907c478bd9Sstevel@tonic-gate * some other semantic, then it should do the access checking 63917c478bd9Sstevel@tonic-gate * itself. It would have been nice to have the file open mode 63927c478bd9Sstevel@tonic-gate * passed as part of the arguments. 63937c478bd9Sstevel@tonic-gate */ 63947c478bd9Sstevel@tonic-gate 63957c478bd9Sstevel@tonic-gate *created = TRUE; 6396da6c28aaSamw error = VOP_CREATE(dvp, nm, vap, EXCL, VWRITE, vpp, cr, 0, NULL, NULL); 63977c478bd9Sstevel@tonic-gate 63987c478bd9Sstevel@tonic-gate if (error) { 63997c478bd9Sstevel@tonic-gate *created = FALSE; 64007c478bd9Sstevel@tonic-gate 64017c478bd9Sstevel@tonic-gate /* 64027c478bd9Sstevel@tonic-gate * If we got something other than file already exists 64037c478bd9Sstevel@tonic-gate * then just return this error. Otherwise, we got 64047c478bd9Sstevel@tonic-gate * EEXIST. If we were doing a GUARDED create, then 64057c478bd9Sstevel@tonic-gate * just return this error. Otherwise, we need to 64067c478bd9Sstevel@tonic-gate * make sure that this wasn't a duplicate of an 64077c478bd9Sstevel@tonic-gate * exclusive create request. 64087c478bd9Sstevel@tonic-gate * 64097c478bd9Sstevel@tonic-gate * The assumption is made that a non-exclusive create 64107c478bd9Sstevel@tonic-gate * request will never return EEXIST. 64117c478bd9Sstevel@tonic-gate */ 64127c478bd9Sstevel@tonic-gate 64137c478bd9Sstevel@tonic-gate if (error != EEXIST || mode == GUARDED4) { 64147c478bd9Sstevel@tonic-gate status = puterrno4(error); 64157c478bd9Sstevel@tonic-gate return (status); 64167c478bd9Sstevel@tonic-gate } 6417da6c28aaSamw error = VOP_LOOKUP(dvp, nm, vpp, NULL, 0, NULL, cr, 6418da6c28aaSamw NULL, NULL, NULL); 64197c478bd9Sstevel@tonic-gate 64207c478bd9Sstevel@tonic-gate if (error) { 64217c478bd9Sstevel@tonic-gate /* 64227c478bd9Sstevel@tonic-gate * We couldn't find the file that we thought that 64237c478bd9Sstevel@tonic-gate * we just created. So, we'll just try creating 64247c478bd9Sstevel@tonic-gate * it again. 64257c478bd9Sstevel@tonic-gate */ 64267c478bd9Sstevel@tonic-gate if (error == ENOENT) 64277c478bd9Sstevel@tonic-gate goto tryagain; 64287c478bd9Sstevel@tonic-gate 64297c478bd9Sstevel@tonic-gate status = puterrno4(error); 64307c478bd9Sstevel@tonic-gate return (status); 64317c478bd9Sstevel@tonic-gate } 64327c478bd9Sstevel@tonic-gate 64337c478bd9Sstevel@tonic-gate if (mode == UNCHECKED4) { 64347c478bd9Sstevel@tonic-gate /* existing object must be regular file */ 64357c478bd9Sstevel@tonic-gate if ((*vpp)->v_type != VREG) { 64367c478bd9Sstevel@tonic-gate if ((*vpp)->v_type == VDIR) 64377c478bd9Sstevel@tonic-gate status = NFS4ERR_ISDIR; 64387c478bd9Sstevel@tonic-gate else if ((*vpp)->v_type == VLNK) 64397c478bd9Sstevel@tonic-gate status = NFS4ERR_SYMLINK; 64407c478bd9Sstevel@tonic-gate else 64417c478bd9Sstevel@tonic-gate status = NFS4ERR_INVAL; 64427c478bd9Sstevel@tonic-gate VN_RELE(*vpp); 64437c478bd9Sstevel@tonic-gate return (status); 64447c478bd9Sstevel@tonic-gate } 64457c478bd9Sstevel@tonic-gate 64467c478bd9Sstevel@tonic-gate return (NFS4_OK); 64477c478bd9Sstevel@tonic-gate } 64487c478bd9Sstevel@tonic-gate 64497c478bd9Sstevel@tonic-gate /* Check for duplicate request */ 64507c478bd9Sstevel@tonic-gate va.va_mask = AT_MTIME; 6451da6c28aaSamw error = VOP_GETATTR(*vpp, &va, 0, cr, NULL); 64527c478bd9Sstevel@tonic-gate if (!error) { 64537c478bd9Sstevel@tonic-gate /* We found the file */ 645477e6f23fSVitaliy Gusev const timestruc_t *mtime = &vap->va_mtime; 645577e6f23fSVitaliy Gusev 64567c478bd9Sstevel@tonic-gate if (va.va_mtime.tv_sec != mtime->tv_sec || 64577c478bd9Sstevel@tonic-gate va.va_mtime.tv_nsec != mtime->tv_nsec) { 64587c478bd9Sstevel@tonic-gate /* but its not our creation */ 64597c478bd9Sstevel@tonic-gate VN_RELE(*vpp); 64607c478bd9Sstevel@tonic-gate return (NFS4ERR_EXIST); 64617c478bd9Sstevel@tonic-gate } 64627c478bd9Sstevel@tonic-gate *created = TRUE; /* retrans of create == created */ 64637c478bd9Sstevel@tonic-gate return (NFS4_OK); 64647c478bd9Sstevel@tonic-gate } 64657c478bd9Sstevel@tonic-gate VN_RELE(*vpp); 64667c478bd9Sstevel@tonic-gate return (NFS4ERR_EXIST); 64677c478bd9Sstevel@tonic-gate } 64687c478bd9Sstevel@tonic-gate 64697c478bd9Sstevel@tonic-gate return (NFS4_OK); 64707c478bd9Sstevel@tonic-gate } 64717c478bd9Sstevel@tonic-gate 64727c478bd9Sstevel@tonic-gate static nfsstat4 6473d216dff5SRobert Mastors check_open_access(uint32_t access, struct compound_state *cs, 6474d216dff5SRobert Mastors struct svc_req *req) 64757c478bd9Sstevel@tonic-gate { 64767c478bd9Sstevel@tonic-gate int error; 64777c478bd9Sstevel@tonic-gate vnode_t *vp; 64787c478bd9Sstevel@tonic-gate bool_t readonly; 64797c478bd9Sstevel@tonic-gate cred_t *cr = cs->cr; 64807c478bd9Sstevel@tonic-gate 64817c478bd9Sstevel@tonic-gate /* For now we don't allow mandatory locking as per V2/V3 */ 64827c478bd9Sstevel@tonic-gate if (cs->access == CS_ACCESS_DENIED || cs->mandlock) { 64837c478bd9Sstevel@tonic-gate return (NFS4ERR_ACCESS); 64847c478bd9Sstevel@tonic-gate } 64857c478bd9Sstevel@tonic-gate 64867c478bd9Sstevel@tonic-gate vp = cs->vp; 64877c478bd9Sstevel@tonic-gate ASSERT(cr != NULL && vp->v_type == VREG); 64887c478bd9Sstevel@tonic-gate 64897c478bd9Sstevel@tonic-gate /* 64907c478bd9Sstevel@tonic-gate * If the file system is exported read only and we are trying 64917c478bd9Sstevel@tonic-gate * to open for write, then return NFS4ERR_ROFS 64927c478bd9Sstevel@tonic-gate */ 64937c478bd9Sstevel@tonic-gate 64945cb0d679SMarcel Telka readonly = rdonly4(req, cs); 64957c478bd9Sstevel@tonic-gate 64967c478bd9Sstevel@tonic-gate if ((access & OPEN4_SHARE_ACCESS_WRITE) && readonly) 64977c478bd9Sstevel@tonic-gate return (NFS4ERR_ROFS); 64987c478bd9Sstevel@tonic-gate 64997c478bd9Sstevel@tonic-gate if (access & OPEN4_SHARE_ACCESS_READ) { 6500da6c28aaSamw if ((VOP_ACCESS(vp, VREAD, 0, cr, NULL) != 0) && 6501da6c28aaSamw (VOP_ACCESS(vp, VEXEC, 0, cr, NULL) != 0)) { 65027c478bd9Sstevel@tonic-gate return (NFS4ERR_ACCESS); 65037c478bd9Sstevel@tonic-gate } 65047c478bd9Sstevel@tonic-gate } 65057c478bd9Sstevel@tonic-gate 65067c478bd9Sstevel@tonic-gate if (access & OPEN4_SHARE_ACCESS_WRITE) { 6507da6c28aaSamw error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL); 65087c478bd9Sstevel@tonic-gate if (error) 65097c478bd9Sstevel@tonic-gate return (NFS4ERR_ACCESS); 65107c478bd9Sstevel@tonic-gate } 65117c478bd9Sstevel@tonic-gate 65127c478bd9Sstevel@tonic-gate return (NFS4_OK); 65137c478bd9Sstevel@tonic-gate } 65147c478bd9Sstevel@tonic-gate 6515*f44e1126SVitaliy Gusev static void 6516*f44e1126SVitaliy Gusev rfs4_verifier_to_mtime(verifier4 v, timestruc_t *mtime) 6517*f44e1126SVitaliy Gusev { 6518*f44e1126SVitaliy Gusev timespec32_t *time = (timespec32_t *)&v; 6519*f44e1126SVitaliy Gusev 6520*f44e1126SVitaliy Gusev /* 6521*f44e1126SVitaliy Gusev * Ensure no time overflows. Assumes underlying 6522*f44e1126SVitaliy Gusev * filesystem supports at least 32 bits. 6523*f44e1126SVitaliy Gusev * Truncate nsec to usec resolution to allow valid 6524*f44e1126SVitaliy Gusev * compares even if the underlying filesystem truncates. 6525*f44e1126SVitaliy Gusev */ 6526*f44e1126SVitaliy Gusev mtime->tv_sec = time->tv_sec % TIME32_MAX; 6527*f44e1126SVitaliy Gusev mtime->tv_nsec = (time->tv_nsec / 1000) * 1000; 6528*f44e1126SVitaliy Gusev } 6529*f44e1126SVitaliy Gusev 65307c478bd9Sstevel@tonic-gate static nfsstat4 65317c478bd9Sstevel@tonic-gate rfs4_createfile(OPEN4args *args, struct svc_req *req, struct compound_state *cs, 65327c478bd9Sstevel@tonic-gate change_info4 *cinfo, bitmap4 *attrset, clientid4 clientid) 65337c478bd9Sstevel@tonic-gate { 65347c478bd9Sstevel@tonic-gate struct nfs4_svgetit_arg sarg; 65357c478bd9Sstevel@tonic-gate struct nfs4_ntov_table ntov; 65367c478bd9Sstevel@tonic-gate 65377c478bd9Sstevel@tonic-gate bool_t ntov_table_init = FALSE; 65387c478bd9Sstevel@tonic-gate struct statvfs64 sb; 65397c478bd9Sstevel@tonic-gate nfsstat4 status; 65407c478bd9Sstevel@tonic-gate vnode_t *vp; 65417c478bd9Sstevel@tonic-gate vattr_t bva, ava, iva, cva, *vap; 65427c478bd9Sstevel@tonic-gate vnode_t *dvp; 65437c478bd9Sstevel@tonic-gate char *nm = NULL; 65447c478bd9Sstevel@tonic-gate uint_t buflen; 65457c478bd9Sstevel@tonic-gate bool_t created; 65467c478bd9Sstevel@tonic-gate bool_t setsize = FALSE; 65477c478bd9Sstevel@tonic-gate len_t reqsize; 65487c478bd9Sstevel@tonic-gate int error; 65497c478bd9Sstevel@tonic-gate bool_t trunc; 65507c478bd9Sstevel@tonic-gate caller_context_t ct; 65517c478bd9Sstevel@tonic-gate component4 *component; 655245916cd2Sjpk bslabel_t *clabel; 6553b89a8333Snatalie li - Sun Microsystems - Irvine United States struct sockaddr *ca; 6554b89a8333Snatalie li - Sun Microsystems - Irvine United States char *name = NULL; 6555*f44e1126SVitaliy Gusev fattr4 *fattr = NULL; 6556*f44e1126SVitaliy Gusev 6557*f44e1126SVitaliy Gusev ASSERT(*attrset == 0); 65587c478bd9Sstevel@tonic-gate 65597c478bd9Sstevel@tonic-gate sarg.sbp = &sb; 65602f172c55SRobert Thurlow sarg.is_referral = B_FALSE; 65617c478bd9Sstevel@tonic-gate 65627c478bd9Sstevel@tonic-gate dvp = cs->vp; 65637c478bd9Sstevel@tonic-gate 65647c478bd9Sstevel@tonic-gate /* Check if the file system is read only */ 65655cb0d679SMarcel Telka if (rdonly4(req, cs)) 65667c478bd9Sstevel@tonic-gate return (NFS4ERR_ROFS); 65677c478bd9Sstevel@tonic-gate 656845916cd2Sjpk /* check the label of including directory */ 656945916cd2Sjpk if (is_system_labeled()) { 657045916cd2Sjpk ASSERT(req->rq_label != NULL); 657145916cd2Sjpk clabel = req->rq_label; 657245916cd2Sjpk DTRACE_PROBE2(tx__rfs4__log__info__opremove__clabel, char *, 657345916cd2Sjpk "got client label from request(1)", 657445916cd2Sjpk struct svc_req *, req); 657545916cd2Sjpk if (!blequal(&l_admin_low->tsl_label, clabel)) { 6576bd6f1640SJarrett Lu if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK, 6577bd6f1640SJarrett Lu cs->exi)) { 657845916cd2Sjpk return (NFS4ERR_ACCESS); 657945916cd2Sjpk } 658045916cd2Sjpk } 658145916cd2Sjpk } 658245916cd2Sjpk 6583*f44e1126SVitaliy Gusev if ((args->mode == EXCLUSIVE4 || args->mode == EXCLUSIVE4_1) && 6584*f44e1126SVitaliy Gusev dvp->v_flag & V_XATTRDIR) { 6585*f44e1126SVitaliy Gusev /* prohibit EXCL create of named attributes */ 6586*f44e1126SVitaliy Gusev return (NFS4ERR_INVAL); 6587*f44e1126SVitaliy Gusev } 6588*f44e1126SVitaliy Gusev 65897c478bd9Sstevel@tonic-gate /* 65907c478bd9Sstevel@tonic-gate * Get the last component of path name in nm. cs will reference 65917c478bd9Sstevel@tonic-gate * the including directory on success. 65927c478bd9Sstevel@tonic-gate */ 6593*f44e1126SVitaliy Gusev component = &args->claim.open_claim4_u.file; 659415721462SDaniil Lunev status = utf8_dir_verify(component); 659515721462SDaniil Lunev if (status != NFS4_OK) 659615721462SDaniil Lunev return (status); 65977c478bd9Sstevel@tonic-gate 65987c478bd9Sstevel@tonic-gate nm = utf8_to_fn(component, &buflen, NULL); 65997c478bd9Sstevel@tonic-gate 66007c478bd9Sstevel@tonic-gate if (nm == NULL) 66017c478bd9Sstevel@tonic-gate return (NFS4ERR_RESOURCE); 66027c478bd9Sstevel@tonic-gate 66037c478bd9Sstevel@tonic-gate if (buflen > MAXNAMELEN) { 66047c478bd9Sstevel@tonic-gate kmem_free(nm, buflen); 66057c478bd9Sstevel@tonic-gate return (NFS4ERR_NAMETOOLONG); 66067c478bd9Sstevel@tonic-gate } 66077c478bd9Sstevel@tonic-gate 66087c478bd9Sstevel@tonic-gate bva.va_mask = AT_TYPE|AT_CTIME|AT_SEQ; 6609da6c28aaSamw error = VOP_GETATTR(dvp, &bva, 0, cs->cr, NULL); 66107c478bd9Sstevel@tonic-gate if (error) { 66117c478bd9Sstevel@tonic-gate kmem_free(nm, buflen); 66127c478bd9Sstevel@tonic-gate return (puterrno4(error)); 66137c478bd9Sstevel@tonic-gate } 66147c478bd9Sstevel@tonic-gate 66157c478bd9Sstevel@tonic-gate if (bva.va_type != VDIR) { 66167c478bd9Sstevel@tonic-gate kmem_free(nm, buflen); 66177c478bd9Sstevel@tonic-gate return (NFS4ERR_NOTDIR); 66187c478bd9Sstevel@tonic-gate } 66197c478bd9Sstevel@tonic-gate 66207c478bd9Sstevel@tonic-gate NFS4_SET_FATTR4_CHANGE(cinfo->before, bva.va_ctime) 66217c478bd9Sstevel@tonic-gate 66227c478bd9Sstevel@tonic-gate switch (args->mode) { 66237c478bd9Sstevel@tonic-gate case GUARDED4: 66247c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/ 66257c478bd9Sstevel@tonic-gate case UNCHECKED4: 6626*f44e1126SVitaliy Gusev case EXCLUSIVE4_1: 66277c478bd9Sstevel@tonic-gate nfs4_ntov_table_init(&ntov); 66287c478bd9Sstevel@tonic-gate ntov_table_init = TRUE; 66297c478bd9Sstevel@tonic-gate 6630*f44e1126SVitaliy Gusev if (args->mode == EXCLUSIVE4_1) 6631*f44e1126SVitaliy Gusev fattr = &args->createhow4_u.ch_createboth.cva_attrs; 6632*f44e1126SVitaliy Gusev else 6633*f44e1126SVitaliy Gusev fattr = &args->createhow4_u.createattrs; 6634*f44e1126SVitaliy Gusev 66357c478bd9Sstevel@tonic-gate status = do_rfs4_set_attrs(attrset, 6636*f44e1126SVitaliy Gusev fattr, 66377c478bd9Sstevel@tonic-gate cs, &sarg, &ntov, NFS4ATTR_SETIT); 66387c478bd9Sstevel@tonic-gate 66397c478bd9Sstevel@tonic-gate if (status == NFS4_OK && (sarg.vap->va_mask & AT_TYPE) && 66407c478bd9Sstevel@tonic-gate sarg.vap->va_type != VREG) { 66417c478bd9Sstevel@tonic-gate if (sarg.vap->va_type == VDIR) 66427c478bd9Sstevel@tonic-gate status = NFS4ERR_ISDIR; 66437c478bd9Sstevel@tonic-gate else if (sarg.vap->va_type == VLNK) 66447c478bd9Sstevel@tonic-gate status = NFS4ERR_SYMLINK; 66457c478bd9Sstevel@tonic-gate else 66467c478bd9Sstevel@tonic-gate status = NFS4ERR_INVAL; 66477c478bd9Sstevel@tonic-gate } 66487c478bd9Sstevel@tonic-gate 66497c478bd9Sstevel@tonic-gate if (status != NFS4_OK) { 66507c478bd9Sstevel@tonic-gate kmem_free(nm, buflen); 66517c478bd9Sstevel@tonic-gate nfs4_ntov_table_free(&ntov, &sarg); 66527c478bd9Sstevel@tonic-gate *attrset = 0; 66537c478bd9Sstevel@tonic-gate return (status); 66547c478bd9Sstevel@tonic-gate } 66557c478bd9Sstevel@tonic-gate 66567c478bd9Sstevel@tonic-gate vap = sarg.vap; 66577c478bd9Sstevel@tonic-gate vap->va_type = VREG; 66587c478bd9Sstevel@tonic-gate vap->va_mask |= AT_TYPE; 66597c478bd9Sstevel@tonic-gate 66607c478bd9Sstevel@tonic-gate if ((vap->va_mask & AT_MODE) == 0) { 66617c478bd9Sstevel@tonic-gate vap->va_mask |= AT_MODE; 66627c478bd9Sstevel@tonic-gate vap->va_mode = (mode_t)0600; 66637c478bd9Sstevel@tonic-gate } 66647c478bd9Sstevel@tonic-gate 66657c478bd9Sstevel@tonic-gate if (vap->va_mask & AT_SIZE) { 66667c478bd9Sstevel@tonic-gate 66677c478bd9Sstevel@tonic-gate /* Disallow create with a non-zero size */ 66687c478bd9Sstevel@tonic-gate 66697c478bd9Sstevel@tonic-gate if ((reqsize = sarg.vap->va_size) != 0) { 66707c478bd9Sstevel@tonic-gate kmem_free(nm, buflen); 66717c478bd9Sstevel@tonic-gate nfs4_ntov_table_free(&ntov, &sarg); 66727c478bd9Sstevel@tonic-gate *attrset = 0; 66737c478bd9Sstevel@tonic-gate return (NFS4ERR_INVAL); 66747c478bd9Sstevel@tonic-gate } 66757c478bd9Sstevel@tonic-gate setsize = TRUE; 66767c478bd9Sstevel@tonic-gate } 6677*f44e1126SVitaliy Gusev if (args->mode == EXCLUSIVE4_1) { 6678*f44e1126SVitaliy Gusev rfs4_verifier_to_mtime( 6679*f44e1126SVitaliy Gusev args->createhow4_u.ch_createboth.cva_verf, 6680*f44e1126SVitaliy Gusev &vap->va_mtime); 6681*f44e1126SVitaliy Gusev /* attrset will be set later */ 6682*f44e1126SVitaliy Gusev fattr->attrmask |= FATTR4_TIME_MODIFY_MASK; 6683*f44e1126SVitaliy Gusev vap->va_mask |= AT_MTIME; 6684*f44e1126SVitaliy Gusev } 66857c478bd9Sstevel@tonic-gate break; 66867c478bd9Sstevel@tonic-gate 66877c478bd9Sstevel@tonic-gate case EXCLUSIVE4: 66887c478bd9Sstevel@tonic-gate cva.va_mask = AT_TYPE | AT_MTIME | AT_MODE; 66897c478bd9Sstevel@tonic-gate cva.va_type = VREG; 66907c478bd9Sstevel@tonic-gate cva.va_mode = (mode_t)0; 6691*f44e1126SVitaliy Gusev 6692*f44e1126SVitaliy Gusev rfs4_verifier_to_mtime(args->createhow4_u.createverf, 6693*f44e1126SVitaliy Gusev &cva.va_mtime); 6694*f44e1126SVitaliy Gusev 66957c478bd9Sstevel@tonic-gate vap = &cva; 6696476ea8c9SJeff A. Smith 6697476ea8c9SJeff A. Smith /* 6698476ea8c9SJeff A. Smith * For EXCL create, attrset is set to the server attr 6699476ea8c9SJeff A. Smith * used to cache the client's verifier. 6700476ea8c9SJeff A. Smith */ 6701476ea8c9SJeff A. Smith *attrset = FATTR4_TIME_MODIFY_MASK; 67027c478bd9Sstevel@tonic-gate break; 67037c478bd9Sstevel@tonic-gate } 67047c478bd9Sstevel@tonic-gate 6705b89a8333Snatalie li - Sun Microsystems - Irvine United States ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 6706b89a8333Snatalie li - Sun Microsystems - Irvine United States name = nfscmd_convname(ca, cs->exi, nm, NFSCMD_CONV_INBOUND, 6707b89a8333Snatalie li - Sun Microsystems - Irvine United States MAXPATHLEN + 1); 6708b89a8333Snatalie li - Sun Microsystems - Irvine United States 6709b89a8333Snatalie li - Sun Microsystems - Irvine United States if (name == NULL) { 6710b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(nm, buflen); 6711b89a8333Snatalie li - Sun Microsystems - Irvine United States return (NFS4ERR_SERVERFAULT); 6712b89a8333Snatalie li - Sun Microsystems - Irvine United States } 6713b89a8333Snatalie li - Sun Microsystems - Irvine United States 671477e6f23fSVitaliy Gusev status = create_vnode(dvp, name, vap, args->mode, 67157c478bd9Sstevel@tonic-gate cs->cr, &vp, &created); 6716b89a8333Snatalie li - Sun Microsystems - Irvine United States if (nm != name) 6717b89a8333Snatalie li - Sun Microsystems - Irvine United States kmem_free(name, MAXPATHLEN + 1); 67187c478bd9Sstevel@tonic-gate kmem_free(nm, buflen); 67197c478bd9Sstevel@tonic-gate 67207c478bd9Sstevel@tonic-gate if (status != NFS4_OK) { 67217c478bd9Sstevel@tonic-gate if (ntov_table_init) 67227c478bd9Sstevel@tonic-gate nfs4_ntov_table_free(&ntov, &sarg); 67237c478bd9Sstevel@tonic-gate *attrset = 0; 67247c478bd9Sstevel@tonic-gate return (status); 67257c478bd9Sstevel@tonic-gate } 67267c478bd9Sstevel@tonic-gate 67277c478bd9Sstevel@tonic-gate trunc = (setsize && !created); 67287c478bd9Sstevel@tonic-gate 67297c478bd9Sstevel@tonic-gate if (args->mode != EXCLUSIVE4) { 6730*f44e1126SVitaliy Gusev bitmap4 createmask = fattr->attrmask; 67317c478bd9Sstevel@tonic-gate 67327c478bd9Sstevel@tonic-gate /* 67337c478bd9Sstevel@tonic-gate * True verification that object was created with correct 67347c478bd9Sstevel@tonic-gate * attrs is impossible. The attrs could have been changed 67357c478bd9Sstevel@tonic-gate * immediately after object creation. If attributes did 67367c478bd9Sstevel@tonic-gate * not verify, the only recourse for the server is to 67377c478bd9Sstevel@tonic-gate * destroy the object. Maybe if some attrs (like gid) 67387c478bd9Sstevel@tonic-gate * are set incorrectly, the object should be destroyed; 67397c478bd9Sstevel@tonic-gate * however, seems bad as a default policy. Do we really 67407c478bd9Sstevel@tonic-gate * want to destroy an object over one of the times not 67417c478bd9Sstevel@tonic-gate * verifying correctly? For these reasons, the server 67427c478bd9Sstevel@tonic-gate * currently sets bits in attrset for createattrs 67437c478bd9Sstevel@tonic-gate * that were set; however, no verification is done. 67447c478bd9Sstevel@tonic-gate * 67457c478bd9Sstevel@tonic-gate * vmask_to_nmask accounts for vattr bits set on create 67467c478bd9Sstevel@tonic-gate * [do_rfs4_set_attrs() only sets resp bits for 67477c478bd9Sstevel@tonic-gate * non-vattr/vfs bits.] 67487c478bd9Sstevel@tonic-gate * Mask off any bits we set by default so as not to return 67497c478bd9Sstevel@tonic-gate * more attrset bits than were requested in createattrs 67507c478bd9Sstevel@tonic-gate */ 67517c478bd9Sstevel@tonic-gate if (created) { 67527c478bd9Sstevel@tonic-gate nfs4_vmask_to_nmask(sarg.vap->va_mask, attrset); 67537c478bd9Sstevel@tonic-gate *attrset &= createmask; 67547c478bd9Sstevel@tonic-gate } else { 67557c478bd9Sstevel@tonic-gate /* 67567c478bd9Sstevel@tonic-gate * We did not create the vnode (we tried but it 67577c478bd9Sstevel@tonic-gate * already existed). In this case, the only createattr 67587c478bd9Sstevel@tonic-gate * that the spec allows the server to set is size, 67597c478bd9Sstevel@tonic-gate * and even then, it can only be set if it is 0. 67607c478bd9Sstevel@tonic-gate */ 67617c478bd9Sstevel@tonic-gate *attrset = 0; 67627c478bd9Sstevel@tonic-gate if (trunc) 67637c478bd9Sstevel@tonic-gate *attrset = FATTR4_SIZE_MASK; 67647c478bd9Sstevel@tonic-gate } 67657c478bd9Sstevel@tonic-gate } 67667c478bd9Sstevel@tonic-gate if (ntov_table_init) 67677c478bd9Sstevel@tonic-gate nfs4_ntov_table_free(&ntov, &sarg); 67687c478bd9Sstevel@tonic-gate 67697c478bd9Sstevel@tonic-gate /* 67707c478bd9Sstevel@tonic-gate * Get the initial "after" sequence number, if it fails, 67717c478bd9Sstevel@tonic-gate * set to zero, time to before. 67727c478bd9Sstevel@tonic-gate */ 67737c478bd9Sstevel@tonic-gate iva.va_mask = AT_CTIME|AT_SEQ; 6774da6c28aaSamw if (VOP_GETATTR(dvp, &iva, 0, cs->cr, NULL)) { 67757c478bd9Sstevel@tonic-gate iva.va_seq = 0; 67767c478bd9Sstevel@tonic-gate iva.va_ctime = bva.va_ctime; 67777c478bd9Sstevel@tonic-gate } 67787c478bd9Sstevel@tonic-gate 67797c478bd9Sstevel@tonic-gate /* 67807c478bd9Sstevel@tonic-gate * create_vnode attempts to create the file exclusive, 67817c478bd9Sstevel@tonic-gate * if it already exists the VOP_CREATE will fail and 67827c478bd9Sstevel@tonic-gate * may not increase va_seq. It is atomic if 67837c478bd9Sstevel@tonic-gate * we haven't changed the directory, but if it has changed 67847c478bd9Sstevel@tonic-gate * we don't know what changed it. 67857c478bd9Sstevel@tonic-gate */ 67867c478bd9Sstevel@tonic-gate if (!created) { 67877c478bd9Sstevel@tonic-gate if (bva.va_seq && iva.va_seq && 67887c478bd9Sstevel@tonic-gate bva.va_seq == iva.va_seq) 67897c478bd9Sstevel@tonic-gate cinfo->atomic = TRUE; 67907c478bd9Sstevel@tonic-gate else 67917c478bd9Sstevel@tonic-gate cinfo->atomic = FALSE; 67927c478bd9Sstevel@tonic-gate NFS4_SET_FATTR4_CHANGE(cinfo->after, iva.va_ctime); 67937c478bd9Sstevel@tonic-gate } else { 67947c478bd9Sstevel@tonic-gate /* 67957c478bd9Sstevel@tonic-gate * The entry was created, we need to sync the 67967c478bd9Sstevel@tonic-gate * directory metadata. 67977c478bd9Sstevel@tonic-gate */ 6798da6c28aaSamw (void) VOP_FSYNC(dvp, 0, cs->cr, NULL); 67997c478bd9Sstevel@tonic-gate 68007c478bd9Sstevel@tonic-gate /* 68017c478bd9Sstevel@tonic-gate * Get "after" change value, if it fails, simply return the 68027c478bd9Sstevel@tonic-gate * before value. 68037c478bd9Sstevel@tonic-gate */ 68047c478bd9Sstevel@tonic-gate ava.va_mask = AT_CTIME|AT_SEQ; 6805da6c28aaSamw if (VOP_GETATTR(dvp, &ava, 0, cs->cr, NULL)) { 68067c478bd9Sstevel@tonic-gate ava.va_ctime = bva.va_ctime; 68077c478bd9Sstevel@tonic-gate ava.va_seq = 0; 68087c478bd9Sstevel@tonic-gate } 68097c478bd9Sstevel@tonic-gate 68107c478bd9Sstevel@tonic-gate NFS4_SET_FATTR4_CHANGE(cinfo->after, ava.va_ctime); 68117c478bd9Sstevel@tonic-gate 68127c478bd9Sstevel@tonic-gate /* 68137c478bd9Sstevel@tonic-gate * The cinfo->atomic = TRUE only if we have 68147c478bd9Sstevel@tonic-gate * non-zero va_seq's, and it has incremented by exactly one 68157c478bd9Sstevel@tonic-gate * during the create_vnode and it didn't 68167c478bd9Sstevel@tonic-gate * change during the VOP_FSYNC. 68177c478bd9Sstevel@tonic-gate */ 68187c478bd9Sstevel@tonic-gate if (bva.va_seq && iva.va_seq && ava.va_seq && 68191b300de9Sjwahlig iva.va_seq == (bva.va_seq + 1) && iva.va_seq == ava.va_seq) 68207c478bd9Sstevel@tonic-gate cinfo->atomic = TRUE; 68217c478bd9Sstevel@tonic-gate else 68227c478bd9Sstevel@tonic-gate cinfo->atomic = FALSE; 68237c478bd9Sstevel@tonic-gate } 68247c478bd9Sstevel@tonic-gate 68257c478bd9Sstevel@tonic-gate /* Check for mandatory locking and that the size gets set. */ 68267c478bd9Sstevel@tonic-gate cva.va_mask = AT_MODE; 68277c478bd9Sstevel@tonic-gate if (setsize) 68287c478bd9Sstevel@tonic-gate cva.va_mask |= AT_SIZE; 68297c478bd9Sstevel@tonic-gate 68307c478bd9Sstevel@tonic-gate /* Assume the worst */ 68317c478bd9Sstevel@tonic-gate cs->mandlock = TRUE; 68327c478bd9Sstevel@tonic-gate 6833da6c28aaSamw if (VOP_GETATTR(vp, &cva, 0, cs->cr, NULL) == 0) { 68347c478bd9Sstevel@tonic-gate cs->mandlock = MANDLOCK(cs->vp, cva.va_mode); 68357c478bd9Sstevel@tonic-gate 68367c478bd9Sstevel@tonic-gate /* 68377c478bd9Sstevel@tonic-gate * Truncate the file if necessary; this would be 68387c478bd9Sstevel@tonic-gate * the case for create over an existing file. 68397c478bd9Sstevel@tonic-gate */ 68407c478bd9Sstevel@tonic-gate 68417c478bd9Sstevel@tonic-gate if (trunc) { 68427c478bd9Sstevel@tonic-gate int in_crit = 0; 68437c478bd9Sstevel@tonic-gate rfs4_file_t *fp; 68440dfe541eSEvan Layton nfs4_srv_t *nsrv4; 68457c478bd9Sstevel@tonic-gate bool_t create = FALSE; 68467c478bd9Sstevel@tonic-gate 68477c478bd9Sstevel@tonic-gate /* 68487c478bd9Sstevel@tonic-gate * We are writing over an existing file. 68497c478bd9Sstevel@tonic-gate * Check to see if we need to recall a delegation. 68507c478bd9Sstevel@tonic-gate */ 68510dfe541eSEvan Layton nsrv4 = nfs4_get_srv(); 68520dfe541eSEvan Layton rfs4_hold_deleg_policy(nsrv4); 68537c478bd9Sstevel@tonic-gate if ((fp = rfs4_findfile(vp, NULL, &create)) != NULL) { 68547c478bd9Sstevel@tonic-gate if (rfs4_check_delegated_byfp(FWRITE, fp, 68551b300de9Sjwahlig (reqsize == 0), FALSE, FALSE, &clientid)) { 68567c478bd9Sstevel@tonic-gate rfs4_file_rele(fp); 68570dfe541eSEvan Layton rfs4_rele_deleg_policy(nsrv4); 68587c478bd9Sstevel@tonic-gate VN_RELE(vp); 68597c478bd9Sstevel@tonic-gate *attrset = 0; 68607c478bd9Sstevel@tonic-gate return (NFS4ERR_DELAY); 68617c478bd9Sstevel@tonic-gate } 68627c478bd9Sstevel@tonic-gate rfs4_file_rele(fp); 68637c478bd9Sstevel@tonic-gate } 68640dfe541eSEvan Layton rfs4_rele_deleg_policy(nsrv4); 68657c478bd9Sstevel@tonic-gate 68667c478bd9Sstevel@tonic-gate if (nbl_need_check(vp)) { 68677c478bd9Sstevel@tonic-gate in_crit = 1; 68687c478bd9Sstevel@tonic-gate 68697c478bd9Sstevel@tonic-gate ASSERT(reqsize == 0); 68707c478bd9Sstevel@tonic-gate 68717c478bd9Sstevel@tonic-gate nbl_start_crit(vp, RW_READER); 68727c478bd9Sstevel@tonic-gate if (nbl_conflict(vp, NBL_WRITE, 0, 6873da6c28aaSamw cva.va_size, 0, NULL)) { 68747c478bd9Sstevel@tonic-gate in_crit = 0; 68757c478bd9Sstevel@tonic-gate nbl_end_crit(vp); 68767c478bd9Sstevel@tonic-gate VN_RELE(vp); 68777c478bd9Sstevel@tonic-gate *attrset = 0; 68787c478bd9Sstevel@tonic-gate return (NFS4ERR_ACCESS); 68797c478bd9Sstevel@tonic-gate } 68807c478bd9Sstevel@tonic-gate } 68817c478bd9Sstevel@tonic-gate ct.cc_sysid = 0; 68827c478bd9Sstevel@tonic-gate ct.cc_pid = 0; 68837c478bd9Sstevel@tonic-gate ct.cc_caller_id = nfs4_srv_caller_id; 688462b9fcbeSjwahlig ct.cc_flags = CC_DONTBLOCK; 68857c478bd9Sstevel@tonic-gate 68867c478bd9Sstevel@tonic-gate cva.va_mask = AT_SIZE; 68877c478bd9Sstevel@tonic-gate cva.va_size = reqsize; 68887c478bd9Sstevel@tonic-gate (void) VOP_SETATTR(vp, &cva, 0, cs->cr, &ct); 68897c478bd9Sstevel@tonic-gate if (in_crit) 68907c478bd9Sstevel@tonic-gate nbl_end_crit(vp); 68917c478bd9Sstevel@tonic-gate } 68927c478bd9Sstevel@tonic-gate } 68937c478bd9Sstevel@tonic-gate 68947c478bd9Sstevel@tonic-gate error = makefh4(&cs->fh, vp, cs->exi); 68957c478bd9Sstevel@tonic-gate 68967c478bd9Sstevel@tonic-gate /* 68977c478bd9Sstevel@tonic-gate * Force modified data and metadata out to stable storage. 68987c478bd9Sstevel@tonic-gate */ 6899da6c28aaSamw (void) VOP_FSYNC(vp, FNODSYNC, cs->cr, NULL); 69007c478bd9Sstevel@tonic-gate 69017c478bd9Sstevel@tonic-gate if (error) { 69027c478bd9Sstevel@tonic-gate VN_RELE(vp); 69037c478bd9Sstevel@tonic-gate *attrset = 0; 69047c478bd9Sstevel@tonic-gate return (puterrno4(error)); 69057c478bd9Sstevel@tonic-gate } 69067c478bd9Sstevel@tonic-gate 69077c478bd9Sstevel@tonic-gate /* if parent dir is attrdir, set namedattr fh flag */ 69087c478bd9Sstevel@tonic-gate if (dvp->v_flag & V_XATTRDIR) 69097c478bd9Sstevel@tonic-gate set_fh4_flag(&cs->fh, FH4_NAMEDATTR); 69107c478bd9Sstevel@tonic-gate 69117c478bd9Sstevel@tonic-gate if (cs->vp) 69127c478bd9Sstevel@tonic-gate VN_RELE(cs->vp); 69137c478bd9Sstevel@tonic-gate 69147c478bd9Sstevel@tonic-gate cs->vp = vp; 69157c478bd9Sstevel@tonic-gate 69167c478bd9Sstevel@tonic-gate /* 69177c478bd9Sstevel@tonic-gate * if we did not create the file, we will need to check 69187c478bd9Sstevel@tonic-gate * the access bits on the file 69197c478bd9Sstevel@tonic-gate */ 69207c478bd9Sstevel@tonic-gate 69217c478bd9Sstevel@tonic-gate if (!created) { 69227c478bd9Sstevel@tonic-gate if (setsize) 69237c478bd9Sstevel@tonic-gate args->share_access |= OPEN4_SHARE_ACCESS_WRITE; 69247c478bd9Sstevel@tonic-gate status = check_open_access(args->share_access, cs, req); 69257c478bd9Sstevel@tonic-gate if (status != NFS4_OK) 69267c478bd9Sstevel@tonic-gate *attrset = 0; 69277c478bd9Sstevel@tonic-gate } 69287c478bd9Sstevel@tonic-gate return (status); 69297c478bd9Sstevel@tonic-gate } 69307c478bd9Sstevel@tonic-gate 69317c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 69327c478bd9Sstevel@tonic-gate static void 69337c478bd9Sstevel@tonic-gate rfs4_do_open(struct compound_state *cs, struct svc_req *req, 69347c478bd9Sstevel@tonic-gate rfs4_openowner_t *oo, delegreq_t deleg, 69357c478bd9Sstevel@tonic-gate uint32_t access, uint32_t deny, 6936da6c28aaSamw OPEN4res *resp, int deleg_cur) 69377c478bd9Sstevel@tonic-gate { 69387c478bd9Sstevel@tonic-gate /* XXX Currently not using req */ 6939d216dff5SRobert Mastors rfs4_state_t *sp; 6940d216dff5SRobert Mastors rfs4_file_t *fp; 69417c478bd9Sstevel@tonic-gate bool_t screate = TRUE; 69427c478bd9Sstevel@tonic-gate bool_t fcreate = TRUE; 694350956b22SJames Wahlig uint32_t open_a, share_a; 694450956b22SJames Wahlig uint32_t open_d, share_d; 69457c478bd9Sstevel@tonic-gate rfs4_deleg_state_t *dsp; 69467c478bd9Sstevel@tonic-gate sysid_t sysid; 69477c478bd9Sstevel@tonic-gate nfsstat4 status; 6948da6c28aaSamw caller_context_t ct; 69497c478bd9Sstevel@tonic-gate int fflags = 0; 69507c478bd9Sstevel@tonic-gate int recall = 0; 69517c478bd9Sstevel@tonic-gate int err; 6952d216dff5SRobert Mastors int first_open; 69537c478bd9Sstevel@tonic-gate 69547c478bd9Sstevel@tonic-gate /* get the file struct and hold a lock on it during initial open */ 6955d216dff5SRobert Mastors fp = rfs4_findfile_withlock(cs->vp, &cs->fh, &fcreate); 6956d216dff5SRobert Mastors if (fp == NULL) { 6957f6cf9e50SRick Mesta resp->status = NFS4ERR_RESOURCE; 6958f6cf9e50SRick Mesta DTRACE_PROBE1(nfss__e__do__open1, nfsstat4, resp->status); 69597c478bd9Sstevel@tonic-gate return; 69607c478bd9Sstevel@tonic-gate } 69617c478bd9Sstevel@tonic-gate 6962d216dff5SRobert Mastors sp = rfs4_findstate_by_owner_file(oo, fp, &screate); 6963d216dff5SRobert Mastors if (sp == NULL) { 69647c478bd9Sstevel@tonic-gate resp->status = NFS4ERR_RESOURCE; 6965f6cf9e50SRick Mesta DTRACE_PROBE1(nfss__e__do__open2, nfsstat4, resp->status); 69667c478bd9Sstevel@tonic-gate /* No need to keep any reference */ 6967d216dff5SRobert Mastors rw_exit(&fp->rf_file_rwlock); 6968d216dff5SRobert Mastors rfs4_file_rele(fp); 69697c478bd9Sstevel@tonic-gate return; 69707c478bd9Sstevel@tonic-gate } 69717c478bd9Sstevel@tonic-gate 6972fd93bfc3Sjwahlig /* try to get the sysid before continuing */ 6973d216dff5SRobert Mastors if ((status = rfs4_client_sysid(oo->ro_client, &sysid)) != NFS4_OK) { 69747c478bd9Sstevel@tonic-gate resp->status = status; 6975d216dff5SRobert Mastors rfs4_file_rele(fp); 69767c478bd9Sstevel@tonic-gate /* Not a fully formed open; "close" it */ 69777c478bd9Sstevel@tonic-gate if (screate == TRUE) 6978d216dff5SRobert Mastors rfs4_state_close(sp, FALSE, FALSE, cs->cr); 6979d216dff5SRobert Mastors rfs4_state_rele(sp); 69807c478bd9Sstevel@tonic-gate return; 69817c478bd9Sstevel@tonic-gate } 6982fd93bfc3Sjwahlig 6983da6c28aaSamw /* Calculate the fflags for this OPEN. */ 6984da6c28aaSamw if (access & OPEN4_SHARE_ACCESS_READ) 6985da6c28aaSamw fflags |= FREAD; 6986da6c28aaSamw if (access & OPEN4_SHARE_ACCESS_WRITE) 6987da6c28aaSamw fflags |= FWRITE; 6988da6c28aaSamw 6989d216dff5SRobert Mastors rfs4_dbe_lock(sp->rs_dbe); 6990d216dff5SRobert Mastors 6991fd93bfc3Sjwahlig /* 6992fd93bfc3Sjwahlig * Calculate the new deny and access mode that this open is adding to 6993fd93bfc3Sjwahlig * the file for this open owner; 6994fd93bfc3Sjwahlig */ 699550956b22SJames Wahlig open_d = (deny & ~sp->rs_open_deny); 699650956b22SJames Wahlig open_a = (access & ~sp->rs_open_access); 6997d216dff5SRobert Mastors 699850956b22SJames Wahlig /* 699950956b22SJames Wahlig * Calculate the new share access and share deny modes that this open 700050956b22SJames Wahlig * is adding to the file for this open owner; 700150956b22SJames Wahlig */ 700250956b22SJames Wahlig share_a = (access & ~sp->rs_share_access); 700350956b22SJames Wahlig share_d = (deny & ~sp->rs_share_deny); 700450956b22SJames Wahlig 700550956b22SJames Wahlig first_open = (sp->rs_open_access & OPEN4_SHARE_ACCESS_BOTH) == 0; 7006fd93bfc3Sjwahlig 7007fd93bfc3Sjwahlig /* 7008fd93bfc3Sjwahlig * Check to see the client has already sent an open for this 7009fd93bfc3Sjwahlig * open owner on this file with the same share/deny modes. 7010fd93bfc3Sjwahlig * If so, we don't need to check for a conflict and we don't 7011fd93bfc3Sjwahlig * need to add another shrlock. If not, then we need to 7012fd93bfc3Sjwahlig * check for conflicts in deny and access before checking for 7013fd93bfc3Sjwahlig * conflicts in delegation. We don't want to recall a 7014fd93bfc3Sjwahlig * delegation based on an open that will eventually fail based 7015fd93bfc3Sjwahlig * on shares modes. 7016fd93bfc3Sjwahlig */ 7017fd93bfc3Sjwahlig 701850956b22SJames Wahlig if (share_a || share_d) { 7019d216dff5SRobert Mastors if ((err = rfs4_share(sp, access, deny)) != 0) { 7020d216dff5SRobert Mastors rfs4_dbe_unlock(sp->rs_dbe); 7021d216dff5SRobert Mastors resp->status = err; 70227c478bd9Sstevel@tonic-gate 7023d216dff5SRobert Mastors rfs4_file_rele(fp); 70247c478bd9Sstevel@tonic-gate /* Not a fully formed open; "close" it */ 70257c478bd9Sstevel@tonic-gate if (screate == TRUE) 7026d216dff5SRobert Mastors rfs4_state_close(sp, FALSE, FALSE, cs->cr); 7027d216dff5SRobert Mastors rfs4_state_rele(sp); 70287c478bd9Sstevel@tonic-gate return; 70297c478bd9Sstevel@tonic-gate } 7030fd93bfc3Sjwahlig } 70317c478bd9Sstevel@tonic-gate 7032d216dff5SRobert Mastors rfs4_dbe_lock(fp->rf_dbe); 70337c478bd9Sstevel@tonic-gate 70347c478bd9Sstevel@tonic-gate /* 70357c478bd9Sstevel@tonic-gate * Check to see if this file is delegated and if so, if a 70367c478bd9Sstevel@tonic-gate * recall needs to be done. 70377c478bd9Sstevel@tonic-gate */ 7038d216dff5SRobert Mastors if (rfs4_check_recall(sp, access)) { 7039d216dff5SRobert Mastors rfs4_dbe_unlock(fp->rf_dbe); 7040d216dff5SRobert Mastors rfs4_dbe_unlock(sp->rs_dbe); 7041d216dff5SRobert Mastors rfs4_recall_deleg(fp, FALSE, sp->rs_owner->ro_client); 70427c478bd9Sstevel@tonic-gate delay(NFS4_DELEGATION_CONFLICT_DELAY); 7043d216dff5SRobert Mastors rfs4_dbe_lock(sp->rs_dbe); 704414f41b92SRobert Mastors 704514f41b92SRobert Mastors /* if state closed while lock was dropped */ 704614f41b92SRobert Mastors if (sp->rs_closed) { 704750956b22SJames Wahlig if (share_a || share_d) 704814f41b92SRobert Mastors (void) rfs4_unshare(sp); 704914f41b92SRobert Mastors rfs4_dbe_unlock(sp->rs_dbe); 705014f41b92SRobert Mastors rfs4_file_rele(fp); 705114f41b92SRobert Mastors /* Not a fully formed open; "close" it */ 705214f41b92SRobert Mastors if (screate == TRUE) 705314f41b92SRobert Mastors rfs4_state_close(sp, FALSE, FALSE, cs->cr); 705414f41b92SRobert Mastors rfs4_state_rele(sp); 705514f41b92SRobert Mastors resp->status = NFS4ERR_OLD_STATEID; 705614f41b92SRobert Mastors return; 705714f41b92SRobert Mastors } 705814f41b92SRobert Mastors 7059d216dff5SRobert Mastors rfs4_dbe_lock(fp->rf_dbe); 70607c478bd9Sstevel@tonic-gate /* Let's see if the delegation was returned */ 7061d216dff5SRobert Mastors if (rfs4_check_recall(sp, access)) { 7062d216dff5SRobert Mastors rfs4_dbe_unlock(fp->rf_dbe); 706350956b22SJames Wahlig if (share_a || share_d) 7064d216dff5SRobert Mastors (void) rfs4_unshare(sp); 7065d216dff5SRobert Mastors rfs4_dbe_unlock(sp->rs_dbe); 7066d216dff5SRobert Mastors rfs4_file_rele(fp); 7067d216dff5SRobert Mastors rfs4_update_lease(sp->rs_owner->ro_client); 7068d216dff5SRobert Mastors 70697c478bd9Sstevel@tonic-gate /* Not a fully formed open; "close" it */ 70707c478bd9Sstevel@tonic-gate if (screate == TRUE) 7071d216dff5SRobert Mastors rfs4_state_close(sp, FALSE, FALSE, cs->cr); 7072d216dff5SRobert Mastors rfs4_state_rele(sp); 70737c478bd9Sstevel@tonic-gate resp->status = NFS4ERR_DELAY; 70747c478bd9Sstevel@tonic-gate return; 70757c478bd9Sstevel@tonic-gate } 70767c478bd9Sstevel@tonic-gate } 7077da6c28aaSamw /* 7078da6c28aaSamw * the share check passed and any delegation conflict has been 7079da6c28aaSamw * taken care of, now call vop_open. 7080da6c28aaSamw * if this is the first open then call vop_open with fflags. 7081da6c28aaSamw * if not, call vn_open_upgrade with just the upgrade flags. 7082da6c28aaSamw * 7083da6c28aaSamw * if the file has been opened already, it will have the current 7084da6c28aaSamw * access mode in the state struct. if it has no share access, then 7085da6c28aaSamw * this is a new open. 7086da6c28aaSamw * 7087da6c28aaSamw * However, if this is open with CLAIM_DLEGATE_CUR, then don't 7088da6c28aaSamw * call VOP_OPEN(), just do the open upgrade. 7089da6c28aaSamw */ 7090d216dff5SRobert Mastors if (first_open && !deleg_cur) { 7091da6c28aaSamw ct.cc_sysid = sysid; 7092d216dff5SRobert Mastors ct.cc_pid = rfs4_dbe_getid(sp->rs_owner->ro_dbe); 7093da6c28aaSamw ct.cc_caller_id = nfs4_srv_caller_id; 709462b9fcbeSjwahlig ct.cc_flags = CC_DONTBLOCK; 7095da6c28aaSamw err = VOP_OPEN(&cs->vp, fflags, cs->cr, &ct); 7096da6c28aaSamw if (err) { 7097d216dff5SRobert Mastors rfs4_dbe_unlock(fp->rf_dbe); 709850956b22SJames Wahlig if (share_a || share_d) 7099d216dff5SRobert Mastors (void) rfs4_unshare(sp); 7100d216dff5SRobert Mastors rfs4_dbe_unlock(sp->rs_dbe); 7101d216dff5SRobert Mastors rfs4_file_rele(fp); 7102d216dff5SRobert Mastors 7103da6c28aaSamw /* Not a fully formed open; "close" it */ 7104da6c28aaSamw if (screate == TRUE) 7105d216dff5SRobert Mastors rfs4_state_close(sp, FALSE, FALSE, cs->cr); 7106d216dff5SRobert Mastors rfs4_state_rele(sp); 7107335fb9e6Sjwahlig /* check if a monitor detected a delegation conflict */ 7108335fb9e6Sjwahlig if (err == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) 7109335fb9e6Sjwahlig resp->status = NFS4ERR_DELAY; 7110335fb9e6Sjwahlig else 7111da6c28aaSamw resp->status = NFS4ERR_SERVERFAULT; 7112da6c28aaSamw return; 7113da6c28aaSamw } 7114da6c28aaSamw } else { /* open upgrade */ 7115da6c28aaSamw /* 7116da6c28aaSamw * calculate the fflags for the new mode that is being added 7117da6c28aaSamw * by this upgrade. 7118da6c28aaSamw */ 7119da6c28aaSamw fflags = 0; 712050956b22SJames Wahlig if (open_a & OPEN4_SHARE_ACCESS_READ) 7121da6c28aaSamw fflags |= FREAD; 712250956b22SJames Wahlig if (open_a & OPEN4_SHARE_ACCESS_WRITE) 7123da6c28aaSamw fflags |= FWRITE; 7124da6c28aaSamw vn_open_upgrade(cs->vp, fflags); 7125da6c28aaSamw } 712650956b22SJames Wahlig sp->rs_open_access |= access; 712750956b22SJames Wahlig sp->rs_open_deny |= deny; 71287c478bd9Sstevel@tonic-gate 712950956b22SJames Wahlig if (open_d & OPEN4_SHARE_DENY_READ) 7130d216dff5SRobert Mastors fp->rf_deny_read++; 713150956b22SJames Wahlig if (open_d & OPEN4_SHARE_DENY_WRITE) 7132d216dff5SRobert Mastors fp->rf_deny_write++; 7133d216dff5SRobert Mastors fp->rf_share_deny |= deny; 71347c478bd9Sstevel@tonic-gate 713550956b22SJames Wahlig if (open_a & OPEN4_SHARE_ACCESS_READ) 7136d216dff5SRobert Mastors fp->rf_access_read++; 713750956b22SJames Wahlig if (open_a & OPEN4_SHARE_ACCESS_WRITE) 7138d216dff5SRobert Mastors fp->rf_access_write++; 7139d216dff5SRobert Mastors fp->rf_share_access |= access; 71407c478bd9Sstevel@tonic-gate 71417c478bd9Sstevel@tonic-gate /* 71427c478bd9Sstevel@tonic-gate * Check for delegation here. if the deleg argument is not 71437c478bd9Sstevel@tonic-gate * DELEG_ANY, then this is a reclaim from a client and 71447c478bd9Sstevel@tonic-gate * we must honor the delegation requested. If necessary we can 71457c478bd9Sstevel@tonic-gate * set the recall flag. 71467c478bd9Sstevel@tonic-gate */ 71477c478bd9Sstevel@tonic-gate 7148d216dff5SRobert Mastors dsp = rfs4_grant_delegation(deleg, sp, &recall); 71497c478bd9Sstevel@tonic-gate 7150d216dff5SRobert Mastors cs->deleg = (fp->rf_dinfo.rd_dtype == OPEN_DELEGATE_WRITE); 71517c478bd9Sstevel@tonic-gate 7152d216dff5SRobert Mastors next_stateid(&sp->rs_stateid); 71537c478bd9Sstevel@tonic-gate 7154d216dff5SRobert Mastors resp->stateid = sp->rs_stateid.stateid; 71557c478bd9Sstevel@tonic-gate 7156d216dff5SRobert Mastors rfs4_dbe_unlock(fp->rf_dbe); 7157d216dff5SRobert Mastors rfs4_dbe_unlock(sp->rs_dbe); 71587c478bd9Sstevel@tonic-gate 71597c478bd9Sstevel@tonic-gate if (dsp) { 71607c478bd9Sstevel@tonic-gate rfs4_set_deleg_response(dsp, &resp->delegation, NULL, recall); 71617c478bd9Sstevel@tonic-gate rfs4_deleg_state_rele(dsp); 71627c478bd9Sstevel@tonic-gate } 71637c478bd9Sstevel@tonic-gate 7164d216dff5SRobert Mastors rfs4_file_rele(fp); 7165d216dff5SRobert Mastors rfs4_state_rele(sp); 71667c478bd9Sstevel@tonic-gate 71677c478bd9Sstevel@tonic-gate resp->status = NFS4_OK; 71687c478bd9Sstevel@tonic-gate } 71697c478bd9Sstevel@tonic-gate 71707c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 71717c478bd9Sstevel@tonic-gate static void 7172*f44e1126SVitaliy Gusev rfs4_do_openfh(struct compound_state *cs, struct svc_req *req, OPEN4args *args, 7173*f44e1126SVitaliy Gusev rfs4_openowner_t *oo, OPEN4res *resp) 7174*f44e1126SVitaliy Gusev { 7175*f44e1126SVitaliy Gusev /* cs->vp and cs->fh have been updated by putfh. */ 7176*f44e1126SVitaliy Gusev rfs4_do_open(cs, req, oo, DELEG_ANY, 7177*f44e1126SVitaliy Gusev (args->share_access & 0xff), args->share_deny, resp, 0); 7178*f44e1126SVitaliy Gusev } 7179*f44e1126SVitaliy Gusev 7180*f44e1126SVitaliy Gusev /*ARGSUSED*/ 7181*f44e1126SVitaliy Gusev static void 71827c478bd9Sstevel@tonic-gate rfs4_do_opennull(struct compound_state *cs, struct svc_req *req, 71837c478bd9Sstevel@tonic-gate OPEN4args *args, rfs4_openowner_t *oo, OPEN4res *resp) 71847c478bd9Sstevel@tonic-gate { 71857c478bd9Sstevel@tonic-gate change_info4 *cinfo = &resp->cinfo; 71867c478bd9Sstevel@tonic-gate bitmap4 *attrset = &resp->attrset; 71877c478bd9Sstevel@tonic-gate 71887c478bd9Sstevel@tonic-gate if (args->opentype == OPEN4_NOCREATE) 7189*f44e1126SVitaliy Gusev resp->status = rfs4_lookupfile(&args->claim.open_claim4_u.file, 71907c478bd9Sstevel@tonic-gate req, cs, args->share_access, cinfo); 71917c478bd9Sstevel@tonic-gate else { 71927c478bd9Sstevel@tonic-gate /* inhibit delegation grants during exclusive create */ 71937c478bd9Sstevel@tonic-gate 71947c478bd9Sstevel@tonic-gate if (args->mode == EXCLUSIVE4) 71957c478bd9Sstevel@tonic-gate rfs4_disable_delegation(); 71967c478bd9Sstevel@tonic-gate 71977c478bd9Sstevel@tonic-gate resp->status = rfs4_createfile(args, req, cs, cinfo, attrset, 7198d216dff5SRobert Mastors oo->ro_client->rc_clientid); 71997c478bd9Sstevel@tonic-gate } 72007c478bd9Sstevel@tonic-gate 72017c478bd9Sstevel@tonic-gate if (resp->status == NFS4_OK) { 72027c478bd9Sstevel@tonic-gate 72037c478bd9Sstevel@tonic-gate /* cs->vp cs->fh now reference the desired file */ 72047c478bd9Sstevel@tonic-gate 7205e228dd39SJames Wahlig rfs4_do_open(cs, req, oo, 7206e228dd39SJames Wahlig oo->ro_need_confirm ? DELEG_NONE : DELEG_ANY, 7207e228dd39SJames Wahlig args->share_access, args->share_deny, resp, 0); 72087c478bd9Sstevel@tonic-gate 72097c478bd9Sstevel@tonic-gate /* 72107c478bd9Sstevel@tonic-gate * If rfs4_createfile set attrset, we must 72117c478bd9Sstevel@tonic-gate * clear this attrset before the response is copied. 72127c478bd9Sstevel@tonic-gate */ 72137c478bd9Sstevel@tonic-gate if (resp->status != NFS4_OK && resp->attrset) { 72147c478bd9Sstevel@tonic-gate resp->attrset = 0; 72157c478bd9Sstevel@tonic-gate } 72167c478bd9Sstevel@tonic-gate } 72177c478bd9Sstevel@tonic-gate else 72187c478bd9Sstevel@tonic-gate *cs->statusp = resp->status; 72197c478bd9Sstevel@tonic-gate 72207c478bd9Sstevel@tonic-gate if (args->mode == EXCLUSIVE4) 72217c478bd9Sstevel@tonic-gate rfs4_enable_delegation(); 72227c478bd9Sstevel@tonic-gate } 72237c478bd9Sstevel@tonic-gate 72247c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 72257c478bd9Sstevel@tonic-gate static void 72267c478bd9Sstevel@tonic-gate rfs4_do_openprev(struct compound_state *cs, struct svc_req *req, 72277c478bd9Sstevel@tonic-gate OPEN4args *args, rfs4_openowner_t *oo, OPEN4res *resp) 72287c478bd9Sstevel@tonic-gate { 72297c478bd9Sstevel@tonic-gate change_info4 *cinfo = &resp->cinfo; 72307c478bd9Sstevel@tonic-gate vattr_t va; 72317c478bd9Sstevel@tonic-gate vtype_t v_type = cs->vp->v_type; 72327c478bd9Sstevel@tonic-gate int error = 0; 72337c478bd9Sstevel@tonic-gate 72347c478bd9Sstevel@tonic-gate /* Verify that we have a regular file */ 72357c478bd9Sstevel@tonic-gate if (v_type != VREG) { 72367c478bd9Sstevel@tonic-gate if (v_type == VDIR) 72377c478bd9Sstevel@tonic-gate resp->status = NFS4ERR_ISDIR; 72387c478bd9Sstevel@tonic-gate else if (v_type == VLNK) 72397c478bd9Sstevel@tonic-gate resp->status = NFS4ERR_SYMLINK; 72407c478bd9Sstevel@tonic-gate else 72417c478bd9Sstevel@tonic-gate resp->status = NFS4ERR_INVAL; 72427c478bd9Sstevel@tonic-gate return; 72437c478bd9Sstevel@tonic-gate } 72447c478bd9Sstevel@tonic-gate 72457c478bd9Sstevel@tonic-gate va.va_mask = AT_MODE|AT_UID; 7246da6c28aaSamw error = VOP_GETATTR(cs->vp, &va, 0, cs->cr, NULL); 72477c478bd9Sstevel@tonic-gate if (error) { 72487c478bd9Sstevel@tonic-gate resp->status = puterrno4(error); 72497c478bd9Sstevel@tonic-gate return; 72507c478bd9Sstevel@tonic-gate } 72517c478bd9Sstevel@tonic-gate 72527c478bd9Sstevel@tonic-gate cs->mandlock = MANDLOCK(cs->vp, va.va_mode); 72537c478bd9Sstevel@tonic-gate 72547c478bd9Sstevel@tonic-gate /* 72557c478bd9Sstevel@tonic-gate * Check if we have access to the file, Note the the file 72567c478bd9Sstevel@tonic-gate * could have originally been open UNCHECKED or GUARDED 72577c478bd9Sstevel@tonic-gate * with mode bits that will now fail, but there is nothing 72587c478bd9Sstevel@tonic-gate * we can really do about that except in the case that the 72597c478bd9Sstevel@tonic-gate * owner of the file is the one requesting the open. 72607c478bd9Sstevel@tonic-gate */ 72617c478bd9Sstevel@tonic-gate if (crgetuid(cs->cr) != va.va_uid) { 72627c478bd9Sstevel@tonic-gate resp->status = check_open_access(args->share_access, cs, req); 72637c478bd9Sstevel@tonic-gate if (resp->status != NFS4_OK) { 72647c478bd9Sstevel@tonic-gate return; 72657c478bd9Sstevel@tonic-gate } 72667c478bd9Sstevel@tonic-gate } 72677c478bd9Sstevel@tonic-gate 72687c478bd9Sstevel@tonic-gate /* 72697c478bd9Sstevel@tonic-gate * cinfo on a CLAIM_PREVIOUS is undefined, initialize to zero 72707c478bd9Sstevel@tonic-gate */ 72717c478bd9Sstevel@tonic-gate cinfo->before = 0; 72727c478bd9Sstevel@tonic-gate cinfo->after = 0; 72737c478bd9Sstevel@tonic-gate cinfo->atomic = FALSE; 72747c478bd9Sstevel@tonic-gate 72757c478bd9Sstevel@tonic-gate rfs4_do_open(cs, req, oo, 7276*f44e1126SVitaliy Gusev NFS4_DELEG4TYPE2REQTYPE(args->claim.open_claim4_u.delegate_type), 7277da6c28aaSamw args->share_access, args->share_deny, resp, 0); 72787c478bd9Sstevel@tonic-gate } 72797c478bd9Sstevel@tonic-gate 72807c478bd9Sstevel@tonic-gate static void 72817c478bd9Sstevel@tonic-gate rfs4_do_opendelcur(struct compound_state *cs, struct svc_req *req, 72827c478bd9Sstevel@tonic-gate OPEN4args *args, rfs4_openowner_t *oo, OPEN4res *resp) 72837c478bd9Sstevel@tonic-gate { 72847c478bd9Sstevel@tonic-gate int error; 72857c478bd9Sstevel@tonic-gate nfsstat4 status; 72867c478bd9Sstevel@tonic-gate stateid4 stateid = 7287*f44e1126SVitaliy Gusev args->claim.open_claim4_u.delegate_cur_info.delegate_stateid; 72887c478bd9Sstevel@tonic-gate rfs4_deleg_state_t *dsp; 72897c478bd9Sstevel@tonic-gate 72907c478bd9Sstevel@tonic-gate /* 72917c478bd9Sstevel@tonic-gate * Find the state info from the stateid and confirm that the 72927c478bd9Sstevel@tonic-gate * file is delegated. If the state openowner is the same as 72937c478bd9Sstevel@tonic-gate * the supplied openowner we're done. If not, get the file 72947c478bd9Sstevel@tonic-gate * info from the found state info. Use that file info to 72957c478bd9Sstevel@tonic-gate * create the state for this lock owner. Note solaris doen't 72967c478bd9Sstevel@tonic-gate * really need the pathname to find the file. We may want to 72977c478bd9Sstevel@tonic-gate * lookup the pathname and make sure that the vp exist and 72987c478bd9Sstevel@tonic-gate * matches the vp in the file structure. However it is 72997c478bd9Sstevel@tonic-gate * possible that the pathname nolonger exists (local process 73007c478bd9Sstevel@tonic-gate * unlinks the file), so this may not be that useful. 73017c478bd9Sstevel@tonic-gate */ 73027c478bd9Sstevel@tonic-gate 73037c478bd9Sstevel@tonic-gate status = rfs4_get_deleg_state(&stateid, &dsp); 73047c478bd9Sstevel@tonic-gate if (status != NFS4_OK) { 73057c478bd9Sstevel@tonic-gate resp->status = status; 73067c478bd9Sstevel@tonic-gate return; 73077c478bd9Sstevel@tonic-gate } 73087c478bd9Sstevel@tonic-gate 7309d216dff5SRobert Mastors ASSERT(dsp->rds_finfo->rf_dinfo.rd_dtype != OPEN_DELEGATE_NONE); 73107c478bd9Sstevel@tonic-gate 73117c478bd9Sstevel@tonic-gate /* 73127c478bd9Sstevel@tonic-gate * New lock owner, create state. Since this was probably called 73137c478bd9Sstevel@tonic-gate * in response to a CB_RECALL we set deleg to DELEG_NONE 73147c478bd9Sstevel@tonic-gate */ 73157c478bd9Sstevel@tonic-gate 73167c478bd9Sstevel@tonic-gate ASSERT(cs->vp != NULL); 73177c478bd9Sstevel@tonic-gate VN_RELE(cs->vp); 7318d216dff5SRobert Mastors VN_HOLD(dsp->rds_finfo->rf_vp); 7319d216dff5SRobert Mastors cs->vp = dsp->rds_finfo->rf_vp; 73207c478bd9Sstevel@tonic-gate 7321bd3561fbSToomas Soome error = makefh4(&cs->fh, cs->vp, cs->exi); 7322bd3561fbSToomas Soome if (error != 0) { 73237c478bd9Sstevel@tonic-gate rfs4_deleg_state_rele(dsp); 73247c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = puterrno4(error); 73257c478bd9Sstevel@tonic-gate return; 73267c478bd9Sstevel@tonic-gate } 73277c478bd9Sstevel@tonic-gate 73287c478bd9Sstevel@tonic-gate /* Mark progress for delegation returns */ 7329d216dff5SRobert Mastors dsp->rds_finfo->rf_dinfo.rd_time_lastwrite = gethrestime_sec(); 73307c478bd9Sstevel@tonic-gate rfs4_deleg_state_rele(dsp); 73317c478bd9Sstevel@tonic-gate rfs4_do_open(cs, req, oo, DELEG_NONE, 7332da6c28aaSamw args->share_access, args->share_deny, resp, 1); 73337c478bd9Sstevel@tonic-gate } 73347c478bd9Sstevel@tonic-gate 73357c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 73367c478bd9Sstevel@tonic-gate static void 73377c478bd9Sstevel@tonic-gate rfs4_do_opendelprev(struct compound_state *cs, struct svc_req *req, 73387c478bd9Sstevel@tonic-gate OPEN4args *args, rfs4_openowner_t *oo, OPEN4res *resp) 73397c478bd9Sstevel@tonic-gate { 73407c478bd9Sstevel@tonic-gate /* 73417c478bd9Sstevel@tonic-gate * Lookup the pathname, it must already exist since this file 73427c478bd9Sstevel@tonic-gate * was delegated. 73437c478bd9Sstevel@tonic-gate * 73447c478bd9Sstevel@tonic-gate * Find the file and state info for this vp and open owner pair. 73457c478bd9Sstevel@tonic-gate * check that they are in fact delegated. 73467c478bd9Sstevel@tonic-gate * check that the state access and deny modes are the same. 73477c478bd9Sstevel@tonic-gate * 73487c478bd9Sstevel@tonic-gate * Return the delgation possibly seting the recall flag. 73497c478bd9Sstevel@tonic-gate */ 7350d216dff5SRobert Mastors rfs4_file_t *fp; 7351d216dff5SRobert Mastors rfs4_state_t *sp; 73527c478bd9Sstevel@tonic-gate bool_t create = FALSE; 73537c478bd9Sstevel@tonic-gate bool_t dcreate = FALSE; 73547c478bd9Sstevel@tonic-gate rfs4_deleg_state_t *dsp; 73557c478bd9Sstevel@tonic-gate nfsace4 *ace; 73567c478bd9Sstevel@tonic-gate 73577c478bd9Sstevel@tonic-gate /* Note we ignore oflags */ 7358*f44e1126SVitaliy Gusev resp->status = rfs4_lookupfile( 7359*f44e1126SVitaliy Gusev &args->claim.open_claim4_u.file_delegate_prev, 73607c478bd9Sstevel@tonic-gate req, cs, args->share_access, &resp->cinfo); 73617c478bd9Sstevel@tonic-gate 73627c478bd9Sstevel@tonic-gate if (resp->status != NFS4_OK) { 73637c478bd9Sstevel@tonic-gate return; 73647c478bd9Sstevel@tonic-gate } 73657c478bd9Sstevel@tonic-gate 73667c478bd9Sstevel@tonic-gate /* get the file struct and hold a lock on it during initial open */ 7367d216dff5SRobert Mastors fp = rfs4_findfile_withlock(cs->vp, NULL, &create); 7368d216dff5SRobert Mastors if (fp == NULL) { 7369f6cf9e50SRick Mesta resp->status = NFS4ERR_RESOURCE; 7370f6cf9e50SRick Mesta DTRACE_PROBE1(nfss__e__do_opendelprev1, nfsstat4, resp->status); 73717c478bd9Sstevel@tonic-gate return; 73727c478bd9Sstevel@tonic-gate } 73737c478bd9Sstevel@tonic-gate 7374d216dff5SRobert Mastors sp = rfs4_findstate_by_owner_file(oo, fp, &create); 7375d216dff5SRobert Mastors if (sp == NULL) { 73767c478bd9Sstevel@tonic-gate resp->status = NFS4ERR_SERVERFAULT; 7377f6cf9e50SRick Mesta DTRACE_PROBE1(nfss__e__do_opendelprev2, nfsstat4, resp->status); 7378d216dff5SRobert Mastors rw_exit(&fp->rf_file_rwlock); 7379d216dff5SRobert Mastors rfs4_file_rele(fp); 73807c478bd9Sstevel@tonic-gate return; 73817c478bd9Sstevel@tonic-gate } 73827c478bd9Sstevel@tonic-gate 7383d216dff5SRobert Mastors rfs4_dbe_lock(sp->rs_dbe); 7384d216dff5SRobert Mastors rfs4_dbe_lock(fp->rf_dbe); 7385d216dff5SRobert Mastors if (args->share_access != sp->rs_share_access || 7386d216dff5SRobert Mastors args->share_deny != sp->rs_share_deny || 7387d216dff5SRobert Mastors sp->rs_finfo->rf_dinfo.rd_dtype == OPEN_DELEGATE_NONE) { 73887c478bd9Sstevel@tonic-gate NFS4_DEBUG(rfs4_debug, 73897c478bd9Sstevel@tonic-gate (CE_NOTE, "rfs4_do_opendelprev: state mixup")); 7390d216dff5SRobert Mastors rfs4_dbe_unlock(fp->rf_dbe); 7391d216dff5SRobert Mastors rfs4_dbe_unlock(sp->rs_dbe); 7392d216dff5SRobert Mastors rfs4_file_rele(fp); 7393d216dff5SRobert Mastors rfs4_state_rele(sp); 73947c478bd9Sstevel@tonic-gate resp->status = NFS4ERR_SERVERFAULT; 73957c478bd9Sstevel@tonic-gate return; 73967c478bd9Sstevel@tonic-gate } 7397d216dff5SRobert Mastors rfs4_dbe_unlock(fp->rf_dbe); 7398d216dff5SRobert Mastors rfs4_dbe_unlock(sp->rs_dbe); 73997c478bd9Sstevel@tonic-gate 7400d216dff5SRobert Mastors dsp = rfs4_finddeleg(sp, &dcreate); 74017c478bd9Sstevel@tonic-gate if (dsp == NULL) { 7402d216dff5SRobert Mastors rfs4_state_rele(sp); 7403d216dff5SRobert Mastors rfs4_file_rele(fp); 74047c478bd9Sstevel@tonic-gate resp->status = NFS4ERR_SERVERFAULT; 74057c478bd9Sstevel@tonic-gate return; 74067c478bd9Sstevel@tonic-gate } 74077c478bd9Sstevel@tonic-gate 7408d216dff5SRobert Mastors next_stateid(&sp->rs_stateid); 74097c478bd9Sstevel@tonic-gate 7410d216dff5SRobert Mastors resp->stateid = sp->rs_stateid.stateid; 74117c478bd9Sstevel@tonic-gate 7412d216dff5SRobert Mastors resp->delegation.delegation_type = dsp->rds_dtype; 74137c478bd9Sstevel@tonic-gate 7414d216dff5SRobert Mastors if (dsp->rds_dtype == OPEN_DELEGATE_READ) { 74157c478bd9Sstevel@tonic-gate open_read_delegation4 *rv = 74167c478bd9Sstevel@tonic-gate &resp->delegation.open_delegation4_u.read; 74177c478bd9Sstevel@tonic-gate 7418d216dff5SRobert Mastors rv->stateid = dsp->rds_delegid.stateid; 74197c478bd9Sstevel@tonic-gate rv->recall = FALSE; /* no policy in place to set to TRUE */ 74207c478bd9Sstevel@tonic-gate ace = &rv->permissions; 74217c478bd9Sstevel@tonic-gate } else { 74227c478bd9Sstevel@tonic-gate open_write_delegation4 *rv = 74237c478bd9Sstevel@tonic-gate &resp->delegation.open_delegation4_u.write; 74247c478bd9Sstevel@tonic-gate 7425d216dff5SRobert Mastors rv->stateid = dsp->rds_delegid.stateid; 74267c478bd9Sstevel@tonic-gate rv->recall = FALSE; /* no policy in place to set to TRUE */ 74277c478bd9Sstevel@tonic-gate ace = &rv->permissions; 74287c478bd9Sstevel@tonic-gate rv->space_limit.limitby = NFS_LIMIT_SIZE; 74297c478bd9Sstevel@tonic-gate rv->space_limit.nfs_space_limit4_u.filesize = UINT64_MAX; 74307c478bd9Sstevel@tonic-gate } 74317c478bd9Sstevel@tonic-gate 74327c478bd9Sstevel@tonic-gate /* XXX For now */ 74337c478bd9Sstevel@tonic-gate ace->type = ACE4_ACCESS_ALLOWED_ACE_TYPE; 74347c478bd9Sstevel@tonic-gate ace->flag = 0; 74357c478bd9Sstevel@tonic-gate ace->access_mask = 0; 74367c478bd9Sstevel@tonic-gate ace->who.utf8string_len = 0; 74377c478bd9Sstevel@tonic-gate ace->who.utf8string_val = 0; 74387c478bd9Sstevel@tonic-gate 74397c478bd9Sstevel@tonic-gate rfs4_deleg_state_rele(dsp); 7440d216dff5SRobert Mastors rfs4_state_rele(sp); 7441d216dff5SRobert Mastors rfs4_file_rele(fp); 74427c478bd9Sstevel@tonic-gate } 74437c478bd9Sstevel@tonic-gate 74447c478bd9Sstevel@tonic-gate typedef enum { 74457c478bd9Sstevel@tonic-gate NFS4_CHKSEQ_OKAY = 0, 74467c478bd9Sstevel@tonic-gate NFS4_CHKSEQ_REPLAY = 1, 74477c478bd9Sstevel@tonic-gate NFS4_CHKSEQ_BAD = 2 74487c478bd9Sstevel@tonic-gate } rfs4_chkseq_t; 74497c478bd9Sstevel@tonic-gate 74507c478bd9Sstevel@tonic-gate /* 74517c478bd9Sstevel@tonic-gate * Generic function for sequence number checks. 74527c478bd9Sstevel@tonic-gate */ 74537c478bd9Sstevel@tonic-gate static rfs4_chkseq_t 74547c478bd9Sstevel@tonic-gate rfs4_check_seqid(seqid4 seqid, nfs_resop4 *lastop, 74557c478bd9Sstevel@tonic-gate seqid4 rqst_seq, nfs_resop4 *resop, bool_t copyres) 74567c478bd9Sstevel@tonic-gate { 74577c478bd9Sstevel@tonic-gate /* Same sequence ids and matching operations? */ 74587c478bd9Sstevel@tonic-gate if (seqid == rqst_seq && resop->resop == lastop->resop) { 74597c478bd9Sstevel@tonic-gate if (copyres == TRUE) { 74607c478bd9Sstevel@tonic-gate rfs4_free_reply(resop); 74617c478bd9Sstevel@tonic-gate rfs4_copy_reply(resop, lastop); 74627c478bd9Sstevel@tonic-gate } 74637c478bd9Sstevel@tonic-gate NFS4_DEBUG(rfs4_debug, (CE_NOTE, 74647c478bd9Sstevel@tonic-gate "Replayed SEQID %d\n", seqid)); 74657c478bd9Sstevel@tonic-gate return (NFS4_CHKSEQ_REPLAY); 74667c478bd9Sstevel@tonic-gate } 74677c478bd9Sstevel@tonic-gate 74687c478bd9Sstevel@tonic-gate /* If the incoming sequence is not the next expected then it is bad */ 74697c478bd9Sstevel@tonic-gate if (rqst_seq != seqid + 1) { 74707c478bd9Sstevel@tonic-gate if (rqst_seq == seqid) { 74717c478bd9Sstevel@tonic-gate NFS4_DEBUG(rfs4_debug, 74727c478bd9Sstevel@tonic-gate (CE_NOTE, "BAD SEQID: Replayed sequence id " 74737c478bd9Sstevel@tonic-gate "but last op was %d current op is %d\n", 74747c478bd9Sstevel@tonic-gate lastop->resop, resop->resop)); 74757c478bd9Sstevel@tonic-gate return (NFS4_CHKSEQ_BAD); 74767c478bd9Sstevel@tonic-gate } 74777c478bd9Sstevel@tonic-gate NFS4_DEBUG(rfs4_debug, 74787c478bd9Sstevel@tonic-gate (CE_NOTE, "BAD SEQID: got %u expecting %u\n", 74797c478bd9Sstevel@tonic-gate rqst_seq, seqid)); 74807c478bd9Sstevel@tonic-gate return (NFS4_CHKSEQ_BAD); 74817c478bd9Sstevel@tonic-gate } 74827c478bd9Sstevel@tonic-gate 74837c478bd9Sstevel@tonic-gate /* Everything okay -- next expected */ 74847c478bd9Sstevel@tonic-gate return (NFS4_CHKSEQ_OKAY); 74857c478bd9Sstevel@tonic-gate } 74867c478bd9Sstevel@tonic-gate 74877c478bd9Sstevel@tonic-gate 74887c478bd9Sstevel@tonic-gate static rfs4_chkseq_t 7489*f44e1126SVitaliy Gusev rfs4_check_open_seqid(seqid4 seqid, rfs4_openowner_t *op, nfs_resop4 *resop, 7490*f44e1126SVitaliy Gusev const compound_state_t *cs) 74917c478bd9Sstevel@tonic-gate { 74927c478bd9Sstevel@tonic-gate rfs4_chkseq_t rc; 74937c478bd9Sstevel@tonic-gate 7494*f44e1126SVitaliy Gusev if (rfs4_has_session(cs)) 7495*f44e1126SVitaliy Gusev return (NFS4_CHKSEQ_OKAY); 7496*f44e1126SVitaliy Gusev 7497d216dff5SRobert Mastors rfs4_dbe_lock(op->ro_dbe); 7498d216dff5SRobert Mastors rc = rfs4_check_seqid(op->ro_open_seqid, &op->ro_reply, seqid, resop, 7499d216dff5SRobert Mastors TRUE); 7500d216dff5SRobert Mastors rfs4_dbe_unlock(op->ro_dbe); 75017c478bd9Sstevel@tonic-gate 75027c478bd9Sstevel@tonic-gate if (rc == NFS4_CHKSEQ_OKAY) 7503d216dff5SRobert Mastors rfs4_update_lease(op->ro_client); 75047c478bd9Sstevel@tonic-gate 75057c478bd9Sstevel@tonic-gate return (rc); 75067c478bd9Sstevel@tonic-gate } 75077c478bd9Sstevel@tonic-gate 75087c478bd9Sstevel@tonic-gate static rfs4_chkseq_t 7509d216dff5SRobert Mastors rfs4_check_olo_seqid(seqid4 olo_seqid, rfs4_openowner_t *op, nfs_resop4 *resop) 75107c478bd9Sstevel@tonic-gate { 75117c478bd9Sstevel@tonic-gate rfs4_chkseq_t rc; 75127c478bd9Sstevel@tonic-gate 7513d216dff5SRobert Mastors rfs4_dbe_lock(op->ro_dbe); 7514d216dff5SRobert Mastors rc = rfs4_check_seqid(op->ro_open_seqid, &op->ro_reply, 75157c478bd9Sstevel@tonic-gate olo_seqid, resop, FALSE); 7516d216dff5SRobert Mastors rfs4_dbe_unlock(op->ro_dbe); 75177c478bd9Sstevel@tonic-gate 75187c478bd9Sstevel@tonic-gate return (rc); 75197c478bd9Sstevel@tonic-gate } 75207c478bd9Sstevel@tonic-gate 75217c478bd9Sstevel@tonic-gate static rfs4_chkseq_t 7522d216dff5SRobert Mastors rfs4_check_lock_seqid(seqid4 seqid, rfs4_lo_state_t *lsp, nfs_resop4 *resop) 75237c478bd9Sstevel@tonic-gate { 75247c478bd9Sstevel@tonic-gate rfs4_chkseq_t rc = NFS4_CHKSEQ_OKAY; 75257c478bd9Sstevel@tonic-gate 7526d216dff5SRobert Mastors rfs4_dbe_lock(lsp->rls_dbe); 7527d216dff5SRobert Mastors if (!lsp->rls_skip_seqid_check) 7528d216dff5SRobert Mastors rc = rfs4_check_seqid(lsp->rls_seqid, &lsp->rls_reply, seqid, 7529d216dff5SRobert Mastors resop, TRUE); 7530d216dff5SRobert Mastors rfs4_dbe_unlock(lsp->rls_dbe); 75317c478bd9Sstevel@tonic-gate 75327c478bd9Sstevel@tonic-gate return (rc); 75337c478bd9Sstevel@tonic-gate } 75347c478bd9Sstevel@tonic-gate 75357c478bd9Sstevel@tonic-gate static void 75367c478bd9Sstevel@tonic-gate rfs4_op_open(nfs_argop4 *argop, nfs_resop4 *resop, 75377c478bd9Sstevel@tonic-gate struct svc_req *req, struct compound_state *cs) 75387c478bd9Sstevel@tonic-gate { 75397c478bd9Sstevel@tonic-gate OPEN4args *args = &argop->nfs_argop4_u.opopen; 75407c478bd9Sstevel@tonic-gate OPEN4res *resp = &resop->nfs_resop4_u.opopen; 75417c478bd9Sstevel@tonic-gate open_owner4 *owner = &args->owner; 7542*f44e1126SVitaliy Gusev open_claim_type4 claim = args->claim.claim; 75437c478bd9Sstevel@tonic-gate rfs4_client_t *cp; 75447c478bd9Sstevel@tonic-gate rfs4_openowner_t *oo; 75457c478bd9Sstevel@tonic-gate bool_t create; 75467c478bd9Sstevel@tonic-gate bool_t replay = FALSE; 75477c478bd9Sstevel@tonic-gate int can_reclaim; 75487c478bd9Sstevel@tonic-gate 7549f3b585ceSsamf DTRACE_NFSV4_2(op__open__start, struct compound_state *, cs, 7550f3b585ceSsamf OPEN4args *, args); 75517c478bd9Sstevel@tonic-gate 75527c478bd9Sstevel@tonic-gate if (cs->vp == NULL) { 75537c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE; 7554f3b585ceSsamf goto end; 75557c478bd9Sstevel@tonic-gate } 75567c478bd9Sstevel@tonic-gate 7557*f44e1126SVitaliy Gusev /* rfc5661 section 18.16.3 */ 7558*f44e1126SVitaliy Gusev if (rfs4_has_session(cs)) 7559*f44e1126SVitaliy Gusev owner->clientid = cs->client->rc_clientid; 7560*f44e1126SVitaliy Gusev 75617c478bd9Sstevel@tonic-gate /* 75627c478bd9Sstevel@tonic-gate * Need to check clientid and lease expiration first based on 75637c478bd9Sstevel@tonic-gate * error ordering and incrementing sequence id. 75647c478bd9Sstevel@tonic-gate */ 75657c478bd9Sstevel@tonic-gate cp = rfs4_findclient_by_id(owner->clientid, FALSE); 75667c478bd9Sstevel@tonic-gate if (cp == NULL) { 75677c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = 75687c478bd9Sstevel@tonic-gate rfs4_check_clientid(&owner->clientid, 0); 7569f3b585ceSsamf goto end; 75707c478bd9Sstevel@tonic-gate } 75717c478bd9Sstevel@tonic-gate 75727c478bd9Sstevel@tonic-gate if (rfs4_lease_expired(cp)) { 75737c478bd9Sstevel@tonic-gate rfs4_client_close(cp); 75747c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_EXPIRED; 7575f3b585ceSsamf goto end; 75767c478bd9Sstevel@tonic-gate } 7577d216dff5SRobert Mastors can_reclaim = cp->rc_can_reclaim; 75787c478bd9Sstevel@tonic-gate 75797c478bd9Sstevel@tonic-gate /* 75807c478bd9Sstevel@tonic-gate * Find the open_owner for use from this point forward. Take 75817c478bd9Sstevel@tonic-gate * care in updating the sequence id based on the type of error 75827c478bd9Sstevel@tonic-gate * being returned. 75837c478bd9Sstevel@tonic-gate */ 75847c478bd9Sstevel@tonic-gate retry: 75857c478bd9Sstevel@tonic-gate create = TRUE; 75867c478bd9Sstevel@tonic-gate oo = rfs4_findopenowner(owner, &create, args->seqid); 75877c478bd9Sstevel@tonic-gate if (oo == NULL) { 758811bb729eSMarcel Telka *cs->statusp = resp->status = NFS4ERR_RESOURCE; 75897c478bd9Sstevel@tonic-gate rfs4_client_rele(cp); 7590f3b585ceSsamf goto end; 75917c478bd9Sstevel@tonic-gate } 75927c478bd9Sstevel@tonic-gate 7593*f44e1126SVitaliy Gusev /* 7594*f44e1126SVitaliy Gusev * OPEN_CONFIRM must not be implemented in v4.1 7595*f44e1126SVitaliy Gusev */ 7596*f44e1126SVitaliy Gusev if (rfs4_has_session(cs)) { 7597*f44e1126SVitaliy Gusev oo->ro_need_confirm = FALSE; 7598*f44e1126SVitaliy Gusev } 7599*f44e1126SVitaliy Gusev 76007c478bd9Sstevel@tonic-gate /* Hold off access to the sequence space while the open is done */ 7601*f44e1126SVitaliy Gusev /* Workaround to avoid deadlock */ 7602*f44e1126SVitaliy Gusev if (!rfs4_has_session(cs)) 7603d216dff5SRobert Mastors rfs4_sw_enter(&oo->ro_sw); 76047c478bd9Sstevel@tonic-gate 76057c478bd9Sstevel@tonic-gate /* 76067c478bd9Sstevel@tonic-gate * If the open_owner existed before at the server, then check 76077c478bd9Sstevel@tonic-gate * the sequence id. 76087c478bd9Sstevel@tonic-gate */ 7609d216dff5SRobert Mastors if (!create && !oo->ro_postpone_confirm) { 7610*f44e1126SVitaliy Gusev switch (rfs4_check_open_seqid(args->seqid, oo, resop, cs)) { 76117c478bd9Sstevel@tonic-gate case NFS4_CHKSEQ_BAD: 7612*f44e1126SVitaliy Gusev ASSERT(!rfs4_has_session(cs)); 7613d216dff5SRobert Mastors if ((args->seqid > oo->ro_open_seqid) && 7614d216dff5SRobert Mastors oo->ro_need_confirm) { 76157c478bd9Sstevel@tonic-gate rfs4_free_opens(oo, TRUE, FALSE); 7616d216dff5SRobert Mastors rfs4_sw_exit(&oo->ro_sw); 76177c478bd9Sstevel@tonic-gate rfs4_openowner_rele(oo); 76187c478bd9Sstevel@tonic-gate goto retry; 76197c478bd9Sstevel@tonic-gate } 76207c478bd9Sstevel@tonic-gate resp->status = NFS4ERR_BAD_SEQID; 76217c478bd9Sstevel@tonic-gate goto out; 76227c478bd9Sstevel@tonic-gate case NFS4_CHKSEQ_REPLAY: /* replay of previous request */ 76237c478bd9Sstevel@tonic-gate replay = TRUE; 76247c478bd9Sstevel@tonic-gate goto out; 76257c478bd9Sstevel@tonic-gate default: 76267c478bd9Sstevel@tonic-gate break; 76277c478bd9Sstevel@tonic-gate } 76287c478bd9Sstevel@tonic-gate 76297c478bd9Sstevel@tonic-gate /* 76307c478bd9Sstevel@tonic-gate * Sequence was ok and open owner exists 76317c478bd9Sstevel@tonic-gate * check to see if we have yet to see an 76327c478bd9Sstevel@tonic-gate * open_confirm. 76337c478bd9Sstevel@tonic-gate */ 7634d216dff5SRobert Mastors if (oo->ro_need_confirm) { 76357c478bd9Sstevel@tonic-gate rfs4_free_opens(oo, TRUE, FALSE); 7636*f44e1126SVitaliy Gusev ASSERT(!rfs4_has_session(cs)); 7637d216dff5SRobert Mastors rfs4_sw_exit(&oo->ro_sw); 76387c478bd9Sstevel@tonic-gate rfs4_openowner_rele(oo); 76397c478bd9Sstevel@tonic-gate goto retry; 76407c478bd9Sstevel@tonic-gate } 76417c478bd9Sstevel@tonic-gate } 76427c478bd9Sstevel@tonic-gate /* Grace only applies to regular-type OPENs */ 76437c478bd9Sstevel@tonic-gate if (rfs4_clnt_in_grace(cp) && 7644*f44e1126SVitaliy Gusev (claim == CLAIM_NULL || claim == CLAIM_DELEGATE_CUR || 7645*f44e1126SVitaliy Gusev claim == CLAIM_FH)) { 76467c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_GRACE; 76477c478bd9Sstevel@tonic-gate goto out; 76487c478bd9Sstevel@tonic-gate } 76497c478bd9Sstevel@tonic-gate 76507c478bd9Sstevel@tonic-gate /* 76517c478bd9Sstevel@tonic-gate * If previous state at the server existed then can_reclaim 76527c478bd9Sstevel@tonic-gate * will be set. If not reply NFS4ERR_NO_GRACE to the 76537c478bd9Sstevel@tonic-gate * client. 76547c478bd9Sstevel@tonic-gate */ 76557c478bd9Sstevel@tonic-gate if (rfs4_clnt_in_grace(cp) && claim == CLAIM_PREVIOUS && !can_reclaim) { 76567c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_NO_GRACE; 76577c478bd9Sstevel@tonic-gate goto out; 76587c478bd9Sstevel@tonic-gate } 76597c478bd9Sstevel@tonic-gate 76607c478bd9Sstevel@tonic-gate 76617c478bd9Sstevel@tonic-gate /* 76627c478bd9Sstevel@tonic-gate * Reject the open if the client has missed the grace period 76637c478bd9Sstevel@tonic-gate */ 76647c478bd9Sstevel@tonic-gate if (!rfs4_clnt_in_grace(cp) && claim == CLAIM_PREVIOUS) { 76657c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_NO_GRACE; 76667c478bd9Sstevel@tonic-gate goto out; 76677c478bd9Sstevel@tonic-gate } 76687c478bd9Sstevel@tonic-gate 76697c478bd9Sstevel@tonic-gate /* Couple of up-front bookkeeping items */ 7670d216dff5SRobert Mastors if (oo->ro_need_confirm) { 76717c478bd9Sstevel@tonic-gate /* 76727c478bd9Sstevel@tonic-gate * If this is a reclaim OPEN then we should not ask 76737c478bd9Sstevel@tonic-gate * for a confirmation of the open_owner per the 76747c478bd9Sstevel@tonic-gate * protocol specification. 76757c478bd9Sstevel@tonic-gate */ 76767c478bd9Sstevel@tonic-gate if (claim == CLAIM_PREVIOUS) 7677d216dff5SRobert Mastors oo->ro_need_confirm = FALSE; 76787c478bd9Sstevel@tonic-gate else 76797c478bd9Sstevel@tonic-gate resp->rflags |= OPEN4_RESULT_CONFIRM; 76807c478bd9Sstevel@tonic-gate } 76817c478bd9Sstevel@tonic-gate resp->rflags |= OPEN4_RESULT_LOCKTYPE_POSIX; 76827c478bd9Sstevel@tonic-gate 76837c478bd9Sstevel@tonic-gate /* 76847c478bd9Sstevel@tonic-gate * If there is an unshared filesystem mounted on this vnode, 76857c478bd9Sstevel@tonic-gate * do not allow to open/create in this directory. 76867c478bd9Sstevel@tonic-gate */ 76877c478bd9Sstevel@tonic-gate if (vn_ismntpt(cs->vp)) { 76887c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_ACCESS; 76897c478bd9Sstevel@tonic-gate goto out; 76907c478bd9Sstevel@tonic-gate } 76917c478bd9Sstevel@tonic-gate 76927c478bd9Sstevel@tonic-gate /* 76937c478bd9Sstevel@tonic-gate * access must READ, WRITE, or BOTH. No access is invalid. 76947c478bd9Sstevel@tonic-gate * deny can be READ, WRITE, BOTH, or NONE. 76957c478bd9Sstevel@tonic-gate * bits not defined for access/deny are invalid. 76967c478bd9Sstevel@tonic-gate */ 76977c478bd9Sstevel@tonic-gate if (! (args->share_access & OPEN4_SHARE_ACCESS_BOTH) || 76987c478bd9Sstevel@tonic-gate (args->share_access & ~OPEN4_SHARE_ACCESS_BOTH) || 76997c478bd9Sstevel@tonic-gate (args->share_deny & ~OPEN4_SHARE_DENY_BOTH)) { 77007c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_INVAL; 77017c478bd9Sstevel@tonic-gate goto out; 77027c478bd9Sstevel@tonic-gate } 77037c478bd9Sstevel@tonic-gate 77047c478bd9Sstevel@tonic-gate 77057c478bd9Sstevel@tonic-gate /* 77067c478bd9Sstevel@tonic-gate * make sure attrset is zero before response is built. 77077c478bd9Sstevel@tonic-gate */ 77087c478bd9Sstevel@tonic-gate resp->attrset = 0; 77097c478bd9Sstevel@tonic-gate 77107c478bd9Sstevel@tonic-gate switch (claim) { 77117c478bd9Sstevel@tonic-gate case CLAIM_NULL: 77127c478bd9Sstevel@tonic-gate rfs4_do_opennull(cs, req, args, oo, resp); 77137c478bd9Sstevel@tonic-gate break; 77147c478bd9Sstevel@tonic-gate case CLAIM_PREVIOUS: 77157c478bd9Sstevel@tonic-gate rfs4_do_openprev(cs, req, args, oo, resp); 77167c478bd9Sstevel@tonic-gate break; 77177c478bd9Sstevel@tonic-gate case CLAIM_DELEGATE_CUR: 77187c478bd9Sstevel@tonic-gate rfs4_do_opendelcur(cs, req, args, oo, resp); 77197c478bd9Sstevel@tonic-gate break; 77207c478bd9Sstevel@tonic-gate case CLAIM_DELEGATE_PREV: 77217c478bd9Sstevel@tonic-gate rfs4_do_opendelprev(cs, req, args, oo, resp); 77227c478bd9Sstevel@tonic-gate break; 7723*f44e1126SVitaliy Gusev case CLAIM_FH: 7724*f44e1126SVitaliy Gusev rfs4_do_openfh(cs, req, args, oo, resp); 7725*f44e1126SVitaliy Gusev break; 77267c478bd9Sstevel@tonic-gate default: 77277c478bd9Sstevel@tonic-gate resp->status = NFS4ERR_INVAL; 77287c478bd9Sstevel@tonic-gate break; 77297c478bd9Sstevel@tonic-gate } 77307c478bd9Sstevel@tonic-gate 77317c478bd9Sstevel@tonic-gate out: 77327c478bd9Sstevel@tonic-gate rfs4_client_rele(cp); 77337c478bd9Sstevel@tonic-gate 77347c478bd9Sstevel@tonic-gate /* Catch sequence id handling here to make it a little easier */ 77357c478bd9Sstevel@tonic-gate switch (resp->status) { 77367c478bd9Sstevel@tonic-gate case NFS4ERR_BADXDR: 77377c478bd9Sstevel@tonic-gate case NFS4ERR_BAD_SEQID: 77387c478bd9Sstevel@tonic-gate case NFS4ERR_BAD_STATEID: 77397c478bd9Sstevel@tonic-gate case NFS4ERR_NOFILEHANDLE: 77407c478bd9Sstevel@tonic-gate case NFS4ERR_RESOURCE: 77417c478bd9Sstevel@tonic-gate case NFS4ERR_STALE_CLIENTID: 77427c478bd9Sstevel@tonic-gate case NFS4ERR_STALE_STATEID: 77437c478bd9Sstevel@tonic-gate /* 77447c478bd9Sstevel@tonic-gate * The protocol states that if any of these errors are 77457c478bd9Sstevel@tonic-gate * being returned, the sequence id should not be 77467c478bd9Sstevel@tonic-gate * incremented. Any other return requires an 77477c478bd9Sstevel@tonic-gate * increment. 77487c478bd9Sstevel@tonic-gate */ 77497c478bd9Sstevel@tonic-gate break; 77507c478bd9Sstevel@tonic-gate default: 77517c478bd9Sstevel@tonic-gate /* Always update the lease in this case */ 7752d216dff5SRobert Mastors rfs4_update_lease(oo->ro_client); 77537c478bd9Sstevel@tonic-gate 77547c478bd9Sstevel@tonic-gate /* Regular response - copy the result */ 77557c478bd9Sstevel@tonic-gate if (!replay) 77567c478bd9Sstevel@tonic-gate rfs4_update_open_resp(oo, resop, &cs->fh); 77577c478bd9Sstevel@tonic-gate 77587c478bd9Sstevel@tonic-gate /* 77597c478bd9Sstevel@tonic-gate * REPLAY case: Only if the previous response was OK 77607c478bd9Sstevel@tonic-gate * do we copy the filehandle. If not OK, no 77617c478bd9Sstevel@tonic-gate * filehandle to copy. 77627c478bd9Sstevel@tonic-gate */ 77637c478bd9Sstevel@tonic-gate if (replay == TRUE && 77647c478bd9Sstevel@tonic-gate resp->status == NFS4_OK && 7765d216dff5SRobert Mastors oo->ro_reply_fh.nfs_fh4_val) { 77667c478bd9Sstevel@tonic-gate /* 77677c478bd9Sstevel@tonic-gate * If this is a replay, we must restore the 77687c478bd9Sstevel@tonic-gate * current filehandle/vp to that of what was 77697c478bd9Sstevel@tonic-gate * returned originally. Try our best to do 77707c478bd9Sstevel@tonic-gate * it. 77717c478bd9Sstevel@tonic-gate */ 77727c478bd9Sstevel@tonic-gate nfs_fh4_fmt_t *fh_fmtp = 7773d216dff5SRobert Mastors (nfs_fh4_fmt_t *)oo->ro_reply_fh.nfs_fh4_val; 77747c478bd9Sstevel@tonic-gate 77757c478bd9Sstevel@tonic-gate cs->exi = checkexport4(&fh_fmtp->fh4_fsid, 77767c478bd9Sstevel@tonic-gate (fid_t *)&fh_fmtp->fh4_xlen, NULL); 77777c478bd9Sstevel@tonic-gate 77787c478bd9Sstevel@tonic-gate if (cs->exi == NULL) { 77797c478bd9Sstevel@tonic-gate resp->status = NFS4ERR_STALE; 77807c478bd9Sstevel@tonic-gate goto finish; 77817c478bd9Sstevel@tonic-gate } 77827c478bd9Sstevel@tonic-gate 77837c478bd9Sstevel@tonic-gate VN_RELE(cs->vp); 77847c478bd9Sstevel@tonic-gate 7785d216dff5SRobert Mastors cs->vp = nfs4_fhtovp(&oo->ro_reply_fh, cs->exi, 77867c478bd9Sstevel@tonic-gate &resp->status); 77877c478bd9Sstevel@tonic-gate 77887c478bd9Sstevel@tonic-gate if (cs->vp == NULL) 77897c478bd9Sstevel@tonic-gate goto finish; 77907c478bd9Sstevel@tonic-gate 7791d216dff5SRobert Mastors nfs_fh4_copy(&oo->ro_reply_fh, &cs->fh); 77927c478bd9Sstevel@tonic-gate } 77937c478bd9Sstevel@tonic-gate 77947c478bd9Sstevel@tonic-gate /* 77957c478bd9Sstevel@tonic-gate * If this was a replay, no need to update the 77967c478bd9Sstevel@tonic-gate * sequence id. If the open_owner was not created on 77977c478bd9Sstevel@tonic-gate * this pass, then update. The first use of an 77987c478bd9Sstevel@tonic-gate * open_owner will not bump the sequence id. 77997c478bd9Sstevel@tonic-gate */ 78007c478bd9Sstevel@tonic-gate if (replay == FALSE && !create) 78017c478bd9Sstevel@tonic-gate rfs4_update_open_sequence(oo); 78027c478bd9Sstevel@tonic-gate /* 78037c478bd9Sstevel@tonic-gate * If the client is receiving an error and the 78047c478bd9Sstevel@tonic-gate * open_owner needs to be confirmed, there is no way 78057c478bd9Sstevel@tonic-gate * to notify the client of this fact ignoring the fact 78067c478bd9Sstevel@tonic-gate * that the server has no method of returning a 78077c478bd9Sstevel@tonic-gate * stateid to confirm. Therefore, the server needs to 78087c478bd9Sstevel@tonic-gate * mark this open_owner in a way as to avoid the 78097c478bd9Sstevel@tonic-gate * sequence id checking the next time the client uses 78107c478bd9Sstevel@tonic-gate * this open_owner. 78117c478bd9Sstevel@tonic-gate */ 7812d216dff5SRobert Mastors if (resp->status != NFS4_OK && oo->ro_need_confirm) 7813d216dff5SRobert Mastors oo->ro_postpone_confirm = TRUE; 78147c478bd9Sstevel@tonic-gate /* 78157c478bd9Sstevel@tonic-gate * If OK response then clear the postpone flag and 78167c478bd9Sstevel@tonic-gate * reset the sequence id to keep in sync with the 78177c478bd9Sstevel@tonic-gate * client. 78187c478bd9Sstevel@tonic-gate */ 7819d216dff5SRobert Mastors if (resp->status == NFS4_OK && oo->ro_postpone_confirm) { 7820d216dff5SRobert Mastors oo->ro_postpone_confirm = FALSE; 7821d216dff5SRobert Mastors oo->ro_open_seqid = args->seqid; 78227c478bd9Sstevel@tonic-gate } 78237c478bd9Sstevel@tonic-gate break; 78247c478bd9Sstevel@tonic-gate } 78257c478bd9Sstevel@tonic-gate 78267c478bd9Sstevel@tonic-gate finish: 78277c478bd9Sstevel@tonic-gate *cs->statusp = resp->status; 78287c478bd9Sstevel@tonic-gate 7829*f44e1126SVitaliy Gusev if (!rfs4_has_session(cs)) 7830d216dff5SRobert Mastors rfs4_sw_exit(&oo->ro_sw); 78317c478bd9Sstevel@tonic-gate rfs4_openowner_rele(oo); 7832f3b585ceSsamf 7833f3b585ceSsamf end: 7834f3b585ceSsamf DTRACE_NFSV4_2(op__open__done, struct compound_state *, cs, 7835f3b585ceSsamf OPEN4res *, resp); 78367c478bd9Sstevel@tonic-gate } 78377c478bd9Sstevel@tonic-gate 78387c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 78397c478bd9Sstevel@tonic-gate void 78407c478bd9Sstevel@tonic-gate rfs4_op_open_confirm(nfs_argop4 *argop, nfs_resop4 *resop, 78417c478bd9Sstevel@tonic-gate struct svc_req *req, struct compound_state *cs) 78427c478bd9Sstevel@tonic-gate { 78437c478bd9Sstevel@tonic-gate OPEN_CONFIRM4args *args = &argop->nfs_argop4_u.opopen_confirm; 78447c478bd9Sstevel@tonic-gate OPEN_CONFIRM4res *resp = &resop->nfs_resop4_u.opopen_confirm; 78457c478bd9Sstevel@tonic-gate rfs4_state_t *sp; 78467c478bd9Sstevel@tonic-gate nfsstat4 status; 78477c478bd9Sstevel@tonic-gate 7848f3b585ceSsamf DTRACE_NFSV4_2(op__open__confirm__start, struct compound_state *, cs, 7849f3b585ceSsamf OPEN_CONFIRM4args *, args); 7850f3b585ceSsamf 7851*f44e1126SVitaliy Gusev ASSERT(!rfs4_has_session(cs)); 7852*f44e1126SVitaliy Gusev 78537c478bd9Sstevel@tonic-gate if (cs->vp == NULL) { 78547c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE; 7855f3b585ceSsamf goto out; 78567c478bd9Sstevel@tonic-gate } 78577c478bd9Sstevel@tonic-gate 7858447cd349SDaniil Lunev if (cs->vp->v_type != VREG) { 7859447cd349SDaniil Lunev *cs->statusp = resp->status = 7860447cd349SDaniil Lunev cs->vp->v_type == VDIR ? NFS4ERR_ISDIR : NFS4ERR_INVAL; 7861447cd349SDaniil Lunev return; 7862447cd349SDaniil Lunev } 7863447cd349SDaniil Lunev 78647c478bd9Sstevel@tonic-gate status = rfs4_get_state(&args->open_stateid, &sp, RFS4_DBS_VALID); 78657c478bd9Sstevel@tonic-gate if (status != NFS4_OK) { 78667c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = status; 7867f3b585ceSsamf goto out; 78687c478bd9Sstevel@tonic-gate } 78697c478bd9Sstevel@tonic-gate 78707c478bd9Sstevel@tonic-gate /* Ensure specified filehandle matches */ 7871d216dff5SRobert Mastors if (cs->vp != sp->rs_finfo->rf_vp) { 78727c478bd9Sstevel@tonic-gate rfs4_state_rele(sp); 78737c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_BAD_STATEID; 7874f3b585ceSsamf goto out; 78757c478bd9Sstevel@tonic-gate } 78767c478bd9Sstevel@tonic-gate 78777c478bd9Sstevel@tonic-gate /* hold off other access to open_owner while we tinker */ 7878d216dff5SRobert Mastors rfs4_sw_enter(&sp->rs_owner->ro_sw); 78797c478bd9Sstevel@tonic-gate 7880*f44e1126SVitaliy Gusev switch (rfs4_check_stateid_seqid(sp, &args->open_stateid, cs)) { 78817c478bd9Sstevel@tonic-gate case NFS4_CHECK_STATEID_OKAY: 7882d216dff5SRobert Mastors if (rfs4_check_open_seqid(args->seqid, sp->rs_owner, 7883*f44e1126SVitaliy Gusev resop, cs) != 0) { 78847c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_BAD_SEQID; 78857c478bd9Sstevel@tonic-gate break; 78867c478bd9Sstevel@tonic-gate } 78877c478bd9Sstevel@tonic-gate /* 78887c478bd9Sstevel@tonic-gate * If it is the appropriate stateid and determined to 78897c478bd9Sstevel@tonic-gate * be "OKAY" then this means that the stateid does not 78907c478bd9Sstevel@tonic-gate * need to be confirmed and the client is in error for 78917c478bd9Sstevel@tonic-gate * sending an OPEN_CONFIRM. 78927c478bd9Sstevel@tonic-gate */ 78937c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_BAD_STATEID; 78947c478bd9Sstevel@tonic-gate break; 78957c478bd9Sstevel@tonic-gate case NFS4_CHECK_STATEID_OLD: 78967c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_OLD_STATEID; 78977c478bd9Sstevel@tonic-gate break; 78987c478bd9Sstevel@tonic-gate case NFS4_CHECK_STATEID_BAD: 78997c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_BAD_STATEID; 79007c478bd9Sstevel@tonic-gate break; 79017c478bd9Sstevel@tonic-gate case NFS4_CHECK_STATEID_EXPIRED: 79027c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_EXPIRED; 79037c478bd9Sstevel@tonic-gate break; 79047c478bd9Sstevel@tonic-gate case NFS4_CHECK_STATEID_CLOSED: 79057c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_OLD_STATEID; 79067c478bd9Sstevel@tonic-gate break; 79077c478bd9Sstevel@tonic-gate case NFS4_CHECK_STATEID_REPLAY: 7908d216dff5SRobert Mastors switch (rfs4_check_open_seqid(args->seqid, sp->rs_owner, 7909*f44e1126SVitaliy Gusev resop, cs)) { 79107c478bd9Sstevel@tonic-gate case NFS4_CHKSEQ_OKAY: 79117c478bd9Sstevel@tonic-gate /* 79127c478bd9Sstevel@tonic-gate * This is replayed stateid; if seqid matches 79137c478bd9Sstevel@tonic-gate * next expected, then client is using wrong seqid. 79147c478bd9Sstevel@tonic-gate */ 79157c478bd9Sstevel@tonic-gate /* fall through */ 79167c478bd9Sstevel@tonic-gate case NFS4_CHKSEQ_BAD: 79177c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_BAD_SEQID; 79187c478bd9Sstevel@tonic-gate break; 79197c478bd9Sstevel@tonic-gate case NFS4_CHKSEQ_REPLAY: 79207c478bd9Sstevel@tonic-gate /* 79217c478bd9Sstevel@tonic-gate * Note this case is the duplicate case so 79227c478bd9Sstevel@tonic-gate * resp->status is already set. 79237c478bd9Sstevel@tonic-gate */ 79247c478bd9Sstevel@tonic-gate *cs->statusp = resp->status; 7925d216dff5SRobert Mastors rfs4_update_lease(sp->rs_owner->ro_client); 79267c478bd9Sstevel@tonic-gate break; 79277c478bd9Sstevel@tonic-gate } 79287c478bd9Sstevel@tonic-gate break; 79297c478bd9Sstevel@tonic-gate case NFS4_CHECK_STATEID_UNCONFIRMED: 7930d216dff5SRobert Mastors if (rfs4_check_open_seqid(args->seqid, sp->rs_owner, 7931*f44e1126SVitaliy Gusev resop, cs) != NFS4_CHKSEQ_OKAY) { 79327c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_BAD_SEQID; 79337c478bd9Sstevel@tonic-gate break; 79347c478bd9Sstevel@tonic-gate } 79357c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4_OK; 79367c478bd9Sstevel@tonic-gate 7937d216dff5SRobert Mastors next_stateid(&sp->rs_stateid); 7938d216dff5SRobert Mastors resp->open_stateid = sp->rs_stateid.stateid; 7939d216dff5SRobert Mastors sp->rs_owner->ro_need_confirm = FALSE; 7940d216dff5SRobert Mastors rfs4_update_lease(sp->rs_owner->ro_client); 7941d216dff5SRobert Mastors rfs4_update_open_sequence(sp->rs_owner); 7942d216dff5SRobert Mastors rfs4_update_open_resp(sp->rs_owner, resop, NULL); 79437c478bd9Sstevel@tonic-gate break; 79447c478bd9Sstevel@tonic-gate default: 79457c478bd9Sstevel@tonic-gate ASSERT(FALSE); 79467c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_SERVERFAULT; 79477c478bd9Sstevel@tonic-gate break; 79487c478bd9Sstevel@tonic-gate } 7949d216dff5SRobert Mastors rfs4_sw_exit(&sp->rs_owner->ro_sw); 79507c478bd9Sstevel@tonic-gate rfs4_state_rele(sp); 7951f3b585ceSsamf 7952f3b585ceSsamf out: 7953f3b585ceSsamf DTRACE_NFSV4_2(op__open__confirm__done, struct compound_state *, cs, 7954f3b585ceSsamf OPEN_CONFIRM4res *, resp); 79557c478bd9Sstevel@tonic-gate } 79567c478bd9Sstevel@tonic-gate 79577c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 79587c478bd9Sstevel@tonic-gate void 79597c478bd9Sstevel@tonic-gate rfs4_op_open_downgrade(nfs_argop4 *argop, nfs_resop4 *resop, 79607c478bd9Sstevel@tonic-gate struct svc_req *req, struct compound_state *cs) 79617c478bd9Sstevel@tonic-gate { 79627c478bd9Sstevel@tonic-gate OPEN_DOWNGRADE4args *args = &argop->nfs_argop4_u.opopen_downgrade; 79637c478bd9Sstevel@tonic-gate OPEN_DOWNGRADE4res *resp = &resop->nfs_resop4_u.opopen_downgrade; 79647c478bd9Sstevel@tonic-gate uint32_t access = args->share_access; 79657c478bd9Sstevel@tonic-gate uint32_t deny = args->share_deny; 79667c478bd9Sstevel@tonic-gate nfsstat4 status; 79677c478bd9Sstevel@tonic-gate rfs4_state_t *sp; 79687c478bd9Sstevel@tonic-gate rfs4_file_t *fp; 7969da6c28aaSamw int fflags = 0; 79707c478bd9Sstevel@tonic-gate 7971f3b585ceSsamf DTRACE_NFSV4_2(op__open__downgrade__start, struct compound_state *, cs, 7972f3b585ceSsamf OPEN_DOWNGRADE4args *, args); 7973f3b585ceSsamf 79747c478bd9Sstevel@tonic-gate if (cs->vp == NULL) { 79757c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE; 7976f3b585ceSsamf goto out; 79777c478bd9Sstevel@tonic-gate } 79787c478bd9Sstevel@tonic-gate 797921feb70aSDaniil Lunev if (cs->vp->v_type != VREG) { 798021feb70aSDaniil Lunev *cs->statusp = resp->status = NFS4ERR_INVAL; 798121feb70aSDaniil Lunev return; 798221feb70aSDaniil Lunev } 798321feb70aSDaniil Lunev 79847c478bd9Sstevel@tonic-gate status = rfs4_get_state(&args->open_stateid, &sp, RFS4_DBS_VALID); 79857c478bd9Sstevel@tonic-gate if (status != NFS4_OK) { 79867c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = status; 7987f3b585ceSsamf goto out; 79887c478bd9Sstevel@tonic-gate } 79897c478bd9Sstevel@tonic-gate 79907c478bd9Sstevel@tonic-gate /* Ensure specified filehandle matches */ 7991d216dff5SRobert Mastors if (cs->vp != sp->rs_finfo->rf_vp) { 79927c478bd9Sstevel@tonic-gate rfs4_state_rele(sp); 79937c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_BAD_STATEID; 7994f3b585ceSsamf goto out; 79957c478bd9Sstevel@tonic-gate } 79967c478bd9Sstevel@tonic-gate 79977c478bd9Sstevel@tonic-gate /* hold off other access to open_owner while we tinker */ 7998d216dff5SRobert Mastors rfs4_sw_enter(&sp->rs_owner->ro_sw); 79997c478bd9Sstevel@tonic-gate 8000*f44e1126SVitaliy Gusev switch (rfs4_check_stateid_seqid(sp, &args->open_stateid, cs)) { 80017c478bd9Sstevel@tonic-gate case NFS4_CHECK_STATEID_OKAY: 8002d216dff5SRobert Mastors if (rfs4_check_open_seqid(args->seqid, sp->rs_owner, 8003*f44e1126SVitaliy Gusev resop, cs) != NFS4_CHKSEQ_OKAY) { 80047c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_BAD_SEQID; 80057c478bd9Sstevel@tonic-gate goto end; 80067c478bd9Sstevel@tonic-gate } 80077c478bd9Sstevel@tonic-gate break; 80087c478bd9Sstevel@tonic-gate case NFS4_CHECK_STATEID_OLD: 80097c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_OLD_STATEID; 80107c478bd9Sstevel@tonic-gate goto end; 80117c478bd9Sstevel@tonic-gate case NFS4_CHECK_STATEID_BAD: 80127c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_BAD_STATEID; 80137c478bd9Sstevel@tonic-gate goto end; 80147c478bd9Sstevel@tonic-gate case NFS4_CHECK_STATEID_EXPIRED: 80157c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_EXPIRED; 80167c478bd9Sstevel@tonic-gate goto end; 80177c478bd9Sstevel@tonic-gate case NFS4_CHECK_STATEID_CLOSED: 80187c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_OLD_STATEID; 80197c478bd9Sstevel@tonic-gate goto end; 80207c478bd9Sstevel@tonic-gate case NFS4_CHECK_STATEID_UNCONFIRMED: 80217c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_BAD_STATEID; 80227c478bd9Sstevel@tonic-gate goto end; 80237c478bd9Sstevel@tonic-gate case NFS4_CHECK_STATEID_REPLAY: 8024*f44e1126SVitaliy Gusev ASSERT(!rfs4_has_session(cs)); 8025*f44e1126SVitaliy Gusev 80267c478bd9Sstevel@tonic-gate /* Check the sequence id for the open owner */ 8027d216dff5SRobert Mastors switch (rfs4_check_open_seqid(args->seqid, sp->rs_owner, 8028*f44e1126SVitaliy Gusev resop, cs)) { 80297c478bd9Sstevel@tonic-gate case NFS4_CHKSEQ_OKAY: 80307c478bd9Sstevel@tonic-gate /* 80317c478bd9Sstevel@tonic-gate * This is replayed stateid; if seqid matches 80327c478bd9Sstevel@tonic-gate * next expected, then client is using wrong seqid. 80337c478bd9Sstevel@tonic-gate */ 80347c478bd9Sstevel@tonic-gate /* fall through */ 80357c478bd9Sstevel@tonic-gate case NFS4_CHKSEQ_BAD: 80367c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_BAD_SEQID; 80377c478bd9Sstevel@tonic-gate goto end; 80387c478bd9Sstevel@tonic-gate case NFS4_CHKSEQ_REPLAY: 80397c478bd9Sstevel@tonic-gate /* 80407c478bd9Sstevel@tonic-gate * Note this case is the duplicate case so 80417c478bd9Sstevel@tonic-gate * resp->status is already set. 80427c478bd9Sstevel@tonic-gate */ 80437c478bd9Sstevel@tonic-gate *cs->statusp = resp->status; 8044d216dff5SRobert Mastors rfs4_update_lease(sp->rs_owner->ro_client); 80457c478bd9Sstevel@tonic-gate goto end; 80467c478bd9Sstevel@tonic-gate } 80477c478bd9Sstevel@tonic-gate break; 80487c478bd9Sstevel@tonic-gate default: 80497c478bd9Sstevel@tonic-gate ASSERT(FALSE); 80507c478bd9Sstevel@tonic-gate break; 80517c478bd9Sstevel@tonic-gate } 80527c478bd9Sstevel@tonic-gate 8053d216dff5SRobert Mastors rfs4_dbe_lock(sp->rs_dbe); 80547c478bd9Sstevel@tonic-gate /* 80557c478bd9Sstevel@tonic-gate * Check that the new access modes and deny modes are valid. 80567c478bd9Sstevel@tonic-gate * Check that no invalid bits are set. 80577c478bd9Sstevel@tonic-gate */ 80587c478bd9Sstevel@tonic-gate if ((access & ~(OPEN4_SHARE_ACCESS_READ | OPEN4_SHARE_ACCESS_WRITE)) || 8059da6c28aaSamw (deny & ~(OPEN4_SHARE_DENY_READ | OPEN4_SHARE_DENY_WRITE))) { 80607c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_INVAL; 8061d216dff5SRobert Mastors rfs4_update_open_sequence(sp->rs_owner); 8062d216dff5SRobert Mastors rfs4_dbe_unlock(sp->rs_dbe); 80637c478bd9Sstevel@tonic-gate goto end; 80647c478bd9Sstevel@tonic-gate } 80657c478bd9Sstevel@tonic-gate 80667c478bd9Sstevel@tonic-gate /* 80677c478bd9Sstevel@tonic-gate * The new modes must be a subset of the current modes and 80687c478bd9Sstevel@tonic-gate * the access must specify at least one mode. To test that 80697c478bd9Sstevel@tonic-gate * the new mode is a subset of the current modes we bitwise 80707c478bd9Sstevel@tonic-gate * AND them together and check that the result equals the new 80717c478bd9Sstevel@tonic-gate * mode. For example: 807250956b22SJames Wahlig * New mode, access == R and current mode, sp->rs_open_access == RW 807350956b22SJames Wahlig * access & sp->rs_open_access == R == access, so the new access mode 807450956b22SJames Wahlig * is valid. Consider access == RW, sp->rs_open_access = R 807550956b22SJames Wahlig * access & sp->rs_open_access == R != access, so the new access mode 80767c478bd9Sstevel@tonic-gate * is invalid. 80777c478bd9Sstevel@tonic-gate */ 807850956b22SJames Wahlig if ((access & sp->rs_open_access) != access || 807950956b22SJames Wahlig (deny & sp->rs_open_deny) != deny || 80807c478bd9Sstevel@tonic-gate (access & 80817c478bd9Sstevel@tonic-gate (OPEN4_SHARE_ACCESS_READ | OPEN4_SHARE_ACCESS_WRITE)) == 0) { 80827c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_INVAL; 8083d216dff5SRobert Mastors rfs4_update_open_sequence(sp->rs_owner); 8084d216dff5SRobert Mastors rfs4_dbe_unlock(sp->rs_dbe); 80857c478bd9Sstevel@tonic-gate goto end; 80867c478bd9Sstevel@tonic-gate } 80877c478bd9Sstevel@tonic-gate 80887c478bd9Sstevel@tonic-gate /* 80897c478bd9Sstevel@tonic-gate * Release any share locks associated with this stateID. 80907c478bd9Sstevel@tonic-gate * Strictly speaking, this violates the spec because the 80917c478bd9Sstevel@tonic-gate * spec effectively requires that open downgrade be atomic. 80927c478bd9Sstevel@tonic-gate * At present, fs_shrlock does not have this capability. 80937c478bd9Sstevel@tonic-gate */ 8094d216dff5SRobert Mastors (void) rfs4_unshare(sp); 80957c478bd9Sstevel@tonic-gate 809650956b22SJames Wahlig status = rfs4_share(sp, access, deny); 809750956b22SJames Wahlig if (status != NFS4_OK) { 809850956b22SJames Wahlig *cs->statusp = resp->status = NFS4ERR_SERVERFAULT; 809950956b22SJames Wahlig rfs4_update_open_sequence(sp->rs_owner); 810050956b22SJames Wahlig rfs4_dbe_unlock(sp->rs_dbe); 810150956b22SJames Wahlig goto end; 810250956b22SJames Wahlig } 810350956b22SJames Wahlig 8104d216dff5SRobert Mastors fp = sp->rs_finfo; 8105d216dff5SRobert Mastors rfs4_dbe_lock(fp->rf_dbe); 81067c478bd9Sstevel@tonic-gate 81077c478bd9Sstevel@tonic-gate /* 81087c478bd9Sstevel@tonic-gate * If the current mode has deny read and the new mode 81097c478bd9Sstevel@tonic-gate * does not, decrement the number of deny read mode bits 81107c478bd9Sstevel@tonic-gate * and if it goes to zero turn off the deny read bit 81117c478bd9Sstevel@tonic-gate * on the file. 81127c478bd9Sstevel@tonic-gate */ 811350956b22SJames Wahlig if ((sp->rs_open_deny & OPEN4_SHARE_DENY_READ) && 81147c478bd9Sstevel@tonic-gate (deny & OPEN4_SHARE_DENY_READ) == 0) { 8115d216dff5SRobert Mastors fp->rf_deny_read--; 8116d216dff5SRobert Mastors if (fp->rf_deny_read == 0) 8117d216dff5SRobert Mastors fp->rf_share_deny &= ~OPEN4_SHARE_DENY_READ; 81187c478bd9Sstevel@tonic-gate } 81197c478bd9Sstevel@tonic-gate 81207c478bd9Sstevel@tonic-gate /* 81217c478bd9Sstevel@tonic-gate * If the current mode has deny write and the new mode 81227c478bd9Sstevel@tonic-gate * does not, decrement the number of deny write mode bits 81237c478bd9Sstevel@tonic-gate * and if it goes to zero turn off the deny write bit 81247c478bd9Sstevel@tonic-gate * on the file. 81257c478bd9Sstevel@tonic-gate */ 812650956b22SJames Wahlig if ((sp->rs_open_deny & OPEN4_SHARE_DENY_WRITE) && 81277c478bd9Sstevel@tonic-gate (deny & OPEN4_SHARE_DENY_WRITE) == 0) { 8128d216dff5SRobert Mastors fp->rf_deny_write--; 8129d216dff5SRobert Mastors if (fp->rf_deny_write == 0) 8130d216dff5SRobert Mastors fp->rf_share_deny &= ~OPEN4_SHARE_DENY_WRITE; 81317c478bd9Sstevel@tonic-gate } 81327c478bd9Sstevel@tonic-gate 81337c478bd9Sstevel@tonic-gate /* 81347c478bd9Sstevel@tonic-gate * If the current mode has access read and the new mode 81357c478bd9Sstevel@tonic-gate * does not, decrement the number of access read mode bits 81367c478bd9Sstevel@tonic-gate * and if it goes to zero turn off the access read bit 8137da6c28aaSamw * on the file. set fflags to FREAD for the call to 8138da6c28aaSamw * vn_open_downgrade(). 81397c478bd9Sstevel@tonic-gate */ 814050956b22SJames Wahlig if ((sp->rs_open_access & OPEN4_SHARE_ACCESS_READ) && 81417c478bd9Sstevel@tonic-gate (access & OPEN4_SHARE_ACCESS_READ) == 0) { 8142d216dff5SRobert Mastors fp->rf_access_read--; 8143d216dff5SRobert Mastors if (fp->rf_access_read == 0) 8144d216dff5SRobert Mastors fp->rf_share_access &= ~OPEN4_SHARE_ACCESS_READ; 8145da6c28aaSamw fflags |= FREAD; 81467c478bd9Sstevel@tonic-gate } 81477c478bd9Sstevel@tonic-gate 81487c478bd9Sstevel@tonic-gate /* 81497c478bd9Sstevel@tonic-gate * If the current mode has access write and the new mode 81507c478bd9Sstevel@tonic-gate * does not, decrement the number of access write mode bits 81517c478bd9Sstevel@tonic-gate * and if it goes to zero turn off the access write bit 8152da6c28aaSamw * on the file. set fflags to FWRITE for the call to 8153da6c28aaSamw * vn_open_downgrade(). 81547c478bd9Sstevel@tonic-gate */ 815550956b22SJames Wahlig if ((sp->rs_open_access & OPEN4_SHARE_ACCESS_WRITE) && 81567c478bd9Sstevel@tonic-gate (access & OPEN4_SHARE_ACCESS_WRITE) == 0) { 8157d216dff5SRobert Mastors fp->rf_access_write--; 8158d216dff5SRobert Mastors if (fp->rf_access_write == 0) 8159d216dff5SRobert Mastors fp->rf_share_deny &= ~OPEN4_SHARE_ACCESS_WRITE; 8160da6c28aaSamw fflags |= FWRITE; 81617c478bd9Sstevel@tonic-gate } 81627c478bd9Sstevel@tonic-gate 81637c478bd9Sstevel@tonic-gate /* Check that the file is still accessible */ 8164d216dff5SRobert Mastors ASSERT(fp->rf_share_access); 81657c478bd9Sstevel@tonic-gate 8166d216dff5SRobert Mastors rfs4_dbe_unlock(fp->rf_dbe); 81677c478bd9Sstevel@tonic-gate 816850956b22SJames Wahlig /* now set the new open access and deny modes */ 816950956b22SJames Wahlig sp->rs_open_access = access; 817050956b22SJames Wahlig sp->rs_open_deny = deny; 81717c478bd9Sstevel@tonic-gate 8172da6c28aaSamw /* 8173da6c28aaSamw * we successfully downgraded the share lock, now we need to downgrade 8174da6c28aaSamw * the open. it is possible that the downgrade was only for a deny 8175da6c28aaSamw * mode and we have nothing else to do. 8176da6c28aaSamw */ 8177da6c28aaSamw if ((fflags & (FREAD|FWRITE)) != 0) 8178da6c28aaSamw vn_open_downgrade(cs->vp, fflags); 8179da6c28aaSamw 81807c478bd9Sstevel@tonic-gate /* Update the stateid */ 8181d216dff5SRobert Mastors next_stateid(&sp->rs_stateid); 8182d216dff5SRobert Mastors resp->open_stateid = sp->rs_stateid.stateid; 81837c478bd9Sstevel@tonic-gate 8184d216dff5SRobert Mastors rfs4_dbe_unlock(sp->rs_dbe); 81857c478bd9Sstevel@tonic-gate 81867c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4_OK; 81877c478bd9Sstevel@tonic-gate /* Update the lease */ 8188d216dff5SRobert Mastors rfs4_update_lease(sp->rs_owner->ro_client); 81897c478bd9Sstevel@tonic-gate /* And the sequence */ 8190d216dff5SRobert Mastors rfs4_update_open_sequence(sp->rs_owner); 8191d216dff5SRobert Mastors rfs4_update_open_resp(sp->rs_owner, resop, NULL); 81927c478bd9Sstevel@tonic-gate 81937c478bd9Sstevel@tonic-gate end: 8194d216dff5SRobert Mastors rfs4_sw_exit(&sp->rs_owner->ro_sw); 81957c478bd9Sstevel@tonic-gate rfs4_state_rele(sp); 8196f3b585ceSsamf out: 8197f3b585ceSsamf DTRACE_NFSV4_2(op__open__downgrade__done, struct compound_state *, cs, 8198f3b585ceSsamf OPEN_DOWNGRADE4res *, resp); 81997c478bd9Sstevel@tonic-gate } 82007c478bd9Sstevel@tonic-gate 82017c9adcc5SMarcel Telka static void * 82027c9adcc5SMarcel Telka memstr(const void *s1, const char *s2, size_t n) 82037c9adcc5SMarcel Telka { 82047c9adcc5SMarcel Telka size_t l = strlen(s2); 82057c9adcc5SMarcel Telka char *p = (char *)s1; 82067c9adcc5SMarcel Telka 82077c9adcc5SMarcel Telka while (n >= l) { 82087c9adcc5SMarcel Telka if (bcmp(p, s2, l) == 0) 82097c9adcc5SMarcel Telka return (p); 82107c9adcc5SMarcel Telka p++; 82117c9adcc5SMarcel Telka n--; 82127c9adcc5SMarcel Telka } 82137c9adcc5SMarcel Telka 82147c9adcc5SMarcel Telka return (NULL); 82157c9adcc5SMarcel Telka } 82167c9adcc5SMarcel Telka 82177c478bd9Sstevel@tonic-gate /* 82187c478bd9Sstevel@tonic-gate * The logic behind this function is detailed in the NFSv4 RFC in the 82197c478bd9Sstevel@tonic-gate * SETCLIENTID operation description under IMPLEMENTATION. Refer to 82207c478bd9Sstevel@tonic-gate * that section for explicit guidance to server behavior for 82217c478bd9Sstevel@tonic-gate * SETCLIENTID. 82227c478bd9Sstevel@tonic-gate */ 82237c478bd9Sstevel@tonic-gate void 82247c478bd9Sstevel@tonic-gate rfs4_op_setclientid(nfs_argop4 *argop, nfs_resop4 *resop, 82257c478bd9Sstevel@tonic-gate struct svc_req *req, struct compound_state *cs) 82267c478bd9Sstevel@tonic-gate { 82277c478bd9Sstevel@tonic-gate SETCLIENTID4args *args = &argop->nfs_argop4_u.opsetclientid; 82287c478bd9Sstevel@tonic-gate SETCLIENTID4res *res = &resop->nfs_resop4_u.opsetclientid; 82297c478bd9Sstevel@tonic-gate rfs4_client_t *cp, *newcp, *cp_confirmed, *cp_unconfirmed; 82302f172c55SRobert Thurlow rfs4_clntip_t *ci; 82312f172c55SRobert Thurlow bool_t create; 82327c478bd9Sstevel@tonic-gate char *addr, *netid; 82337c478bd9Sstevel@tonic-gate int len; 82347c478bd9Sstevel@tonic-gate 8235f3b585ceSsamf DTRACE_NFSV4_2(op__setclientid__start, struct compound_state *, cs, 8236f3b585ceSsamf SETCLIENTID4args *, args); 82377c478bd9Sstevel@tonic-gate retry: 82387c478bd9Sstevel@tonic-gate newcp = cp_confirmed = cp_unconfirmed = NULL; 82397c478bd9Sstevel@tonic-gate 82407c478bd9Sstevel@tonic-gate /* 82412f172c55SRobert Thurlow * Save the caller's IP address 82422f172c55SRobert Thurlow */ 82432f172c55SRobert Thurlow args->client.cl_addr = 82442f172c55SRobert Thurlow (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 82452f172c55SRobert Thurlow 82462f172c55SRobert Thurlow /* 82472f172c55SRobert Thurlow * Record if it is a Solaris client that cannot handle referrals. 82482f172c55SRobert Thurlow */ 82497c9adcc5SMarcel Telka if (memstr(args->client.id_val, "Solaris", args->client.id_len) && 82507c9adcc5SMarcel Telka !memstr(args->client.id_val, "+referrals", args->client.id_len)) { 82512f172c55SRobert Thurlow /* Add a "yes, it's downrev" record */ 82522f172c55SRobert Thurlow create = TRUE; 82532f172c55SRobert Thurlow ci = rfs4_find_clntip(args->client.cl_addr, &create); 82542f172c55SRobert Thurlow ASSERT(ci != NULL); 82552f172c55SRobert Thurlow rfs4_dbe_rele(ci->ri_dbe); 82562f172c55SRobert Thurlow } else { 82572f172c55SRobert Thurlow /* Remove any previous record */ 82582f172c55SRobert Thurlow rfs4_invalidate_clntip(args->client.cl_addr); 82592f172c55SRobert Thurlow } 82602f172c55SRobert Thurlow 82612f172c55SRobert Thurlow /* 82627c478bd9Sstevel@tonic-gate * In search of an EXISTING client matching the incoming 82637c478bd9Sstevel@tonic-gate * request to establish a new client identifier at the server 82647c478bd9Sstevel@tonic-gate */ 82657c478bd9Sstevel@tonic-gate create = TRUE; 82667c478bd9Sstevel@tonic-gate cp = rfs4_findclient(&args->client, &create, NULL); 82677c478bd9Sstevel@tonic-gate 82687c478bd9Sstevel@tonic-gate /* Should never happen */ 82697c478bd9Sstevel@tonic-gate ASSERT(cp != NULL); 82707c478bd9Sstevel@tonic-gate 82717c478bd9Sstevel@tonic-gate if (cp == NULL) { 82727c478bd9Sstevel@tonic-gate *cs->statusp = res->status = NFS4ERR_SERVERFAULT; 8273f3b585ceSsamf goto out; 82747c478bd9Sstevel@tonic-gate } 82757c478bd9Sstevel@tonic-gate 82767c478bd9Sstevel@tonic-gate /* 82777c478bd9Sstevel@tonic-gate * Easiest case. Client identifier is newly created and is 82787c478bd9Sstevel@tonic-gate * unconfirmed. Also note that for this case, no other 82797c478bd9Sstevel@tonic-gate * entries exist for the client identifier. Nothing else to 82807c478bd9Sstevel@tonic-gate * check. Just setup the response and respond. 82817c478bd9Sstevel@tonic-gate */ 82827c478bd9Sstevel@tonic-gate if (create) { 82837c478bd9Sstevel@tonic-gate *cs->statusp = res->status = NFS4_OK; 8284d216dff5SRobert Mastors res->SETCLIENTID4res_u.resok4.clientid = cp->rc_clientid; 82857c478bd9Sstevel@tonic-gate res->SETCLIENTID4res_u.resok4.setclientid_confirm = 8286d216dff5SRobert Mastors cp->rc_confirm_verf; 82877c478bd9Sstevel@tonic-gate /* Setup callback information; CB_NULL confirmation later */ 82887c478bd9Sstevel@tonic-gate rfs4_client_setcb(cp, &args->callback, args->callback_ident); 82897c478bd9Sstevel@tonic-gate 82907c478bd9Sstevel@tonic-gate rfs4_client_rele(cp); 8291f3b585ceSsamf goto out; 82927c478bd9Sstevel@tonic-gate } 82937c478bd9Sstevel@tonic-gate 82947c478bd9Sstevel@tonic-gate /* 82957c478bd9Sstevel@tonic-gate * An existing, confirmed client may exist but it may not have 82967c478bd9Sstevel@tonic-gate * been active for at least one lease period. If so, then 82977c478bd9Sstevel@tonic-gate * "close" the client and create a new client identifier 82987c478bd9Sstevel@tonic-gate */ 82997c478bd9Sstevel@tonic-gate if (rfs4_lease_expired(cp)) { 83007c478bd9Sstevel@tonic-gate rfs4_client_close(cp); 83017c478bd9Sstevel@tonic-gate goto retry; 83027c478bd9Sstevel@tonic-gate } 83037c478bd9Sstevel@tonic-gate 8304d216dff5SRobert Mastors if (cp->rc_need_confirm == TRUE) 83057c478bd9Sstevel@tonic-gate cp_unconfirmed = cp; 83067c478bd9Sstevel@tonic-gate else 83077c478bd9Sstevel@tonic-gate cp_confirmed = cp; 83087c478bd9Sstevel@tonic-gate 83097c478bd9Sstevel@tonic-gate cp = NULL; 83107c478bd9Sstevel@tonic-gate 83117c478bd9Sstevel@tonic-gate /* 83127c478bd9Sstevel@tonic-gate * We have a confirmed client, now check for an 83137c478bd9Sstevel@tonic-gate * unconfimred entry 83147c478bd9Sstevel@tonic-gate */ 83157c478bd9Sstevel@tonic-gate if (cp_confirmed) { 83167c478bd9Sstevel@tonic-gate /* If creds don't match then client identifier is inuse */ 8317*f44e1126SVitaliy Gusev if (!creds_ok(&cp_confirmed->rc_cr_set, req, cs)) { 83187c478bd9Sstevel@tonic-gate rfs4_cbinfo_t *cbp; 83197c478bd9Sstevel@tonic-gate /* 83207c478bd9Sstevel@tonic-gate * Some one else has established this client 83217c478bd9Sstevel@tonic-gate * id. Try and say * who they are. We will use 83227c478bd9Sstevel@tonic-gate * the call back address supplied by * the 83237c478bd9Sstevel@tonic-gate * first client. 83247c478bd9Sstevel@tonic-gate */ 83257c478bd9Sstevel@tonic-gate *cs->statusp = res->status = NFS4ERR_CLID_INUSE; 83267c478bd9Sstevel@tonic-gate 83277c478bd9Sstevel@tonic-gate addr = netid = NULL; 83287c478bd9Sstevel@tonic-gate 8329d216dff5SRobert Mastors cbp = &cp_confirmed->rc_cbinfo; 83307c478bd9Sstevel@tonic-gate if (cbp->cb_callback.cb_location.r_addr && 83317c478bd9Sstevel@tonic-gate cbp->cb_callback.cb_location.r_netid) { 83327c478bd9Sstevel@tonic-gate cb_client4 *cbcp = &cbp->cb_callback; 83337c478bd9Sstevel@tonic-gate 83347c478bd9Sstevel@tonic-gate len = strlen(cbcp->cb_location.r_addr)+1; 83357c478bd9Sstevel@tonic-gate addr = kmem_alloc(len, KM_SLEEP); 83367c478bd9Sstevel@tonic-gate bcopy(cbcp->cb_location.r_addr, addr, len); 83377c478bd9Sstevel@tonic-gate len = strlen(cbcp->cb_location.r_netid)+1; 83387c478bd9Sstevel@tonic-gate netid = kmem_alloc(len, KM_SLEEP); 83397c478bd9Sstevel@tonic-gate bcopy(cbcp->cb_location.r_netid, netid, len); 83407c478bd9Sstevel@tonic-gate } 83417c478bd9Sstevel@tonic-gate 83427c478bd9Sstevel@tonic-gate res->SETCLIENTID4res_u.client_using.r_addr = addr; 83437c478bd9Sstevel@tonic-gate res->SETCLIENTID4res_u.client_using.r_netid = netid; 83447c478bd9Sstevel@tonic-gate 83457c478bd9Sstevel@tonic-gate rfs4_client_rele(cp_confirmed); 83467c478bd9Sstevel@tonic-gate } 83477c478bd9Sstevel@tonic-gate 83487c478bd9Sstevel@tonic-gate /* 83497c478bd9Sstevel@tonic-gate * Confirmed, creds match, and verifier matches; must 83507c478bd9Sstevel@tonic-gate * be an update of the callback info 83517c478bd9Sstevel@tonic-gate */ 8352d216dff5SRobert Mastors if (cp_confirmed->rc_nfs_client.verifier == 83537c478bd9Sstevel@tonic-gate args->client.verifier) { 83547c478bd9Sstevel@tonic-gate /* Setup callback information */ 83557c478bd9Sstevel@tonic-gate rfs4_client_setcb(cp_confirmed, &args->callback, 83567c478bd9Sstevel@tonic-gate args->callback_ident); 83577c478bd9Sstevel@tonic-gate 83587c478bd9Sstevel@tonic-gate /* everything okay -- move ahead */ 83597c478bd9Sstevel@tonic-gate *cs->statusp = res->status = NFS4_OK; 83607c478bd9Sstevel@tonic-gate res->SETCLIENTID4res_u.resok4.clientid = 8361d216dff5SRobert Mastors cp_confirmed->rc_clientid; 83627c478bd9Sstevel@tonic-gate 83637c478bd9Sstevel@tonic-gate /* update the confirm_verifier and return it */ 83647c478bd9Sstevel@tonic-gate rfs4_client_scv_next(cp_confirmed); 83657c478bd9Sstevel@tonic-gate res->SETCLIENTID4res_u.resok4.setclientid_confirm = 8366d216dff5SRobert Mastors cp_confirmed->rc_confirm_verf; 83677c478bd9Sstevel@tonic-gate 83687c478bd9Sstevel@tonic-gate rfs4_client_rele(cp_confirmed); 8369f3b585ceSsamf goto out; 83707c478bd9Sstevel@tonic-gate } 83717c478bd9Sstevel@tonic-gate 83727c478bd9Sstevel@tonic-gate /* 83737c478bd9Sstevel@tonic-gate * Creds match but the verifier doesn't. Must search 83747c478bd9Sstevel@tonic-gate * for an unconfirmed client that would be replaced by 83757c478bd9Sstevel@tonic-gate * this request. 83767c478bd9Sstevel@tonic-gate */ 83777c478bd9Sstevel@tonic-gate create = FALSE; 83787c478bd9Sstevel@tonic-gate cp_unconfirmed = rfs4_findclient(&args->client, &create, 83797c478bd9Sstevel@tonic-gate cp_confirmed); 83807c478bd9Sstevel@tonic-gate } 83817c478bd9Sstevel@tonic-gate 83827c478bd9Sstevel@tonic-gate /* 83837c478bd9Sstevel@tonic-gate * At this point, we have taken care of the brand new client 83847c478bd9Sstevel@tonic-gate * struct, INUSE case, update of an existing, and confirmed 83857c478bd9Sstevel@tonic-gate * client struct. 83867c478bd9Sstevel@tonic-gate */ 83877c478bd9Sstevel@tonic-gate 83887c478bd9Sstevel@tonic-gate /* 83897c478bd9Sstevel@tonic-gate * check to see if things have changed while we originally 83907c478bd9Sstevel@tonic-gate * picked up the client struct. If they have, then return and 83917c478bd9Sstevel@tonic-gate * retry the processing of this SETCLIENTID request. 83927c478bd9Sstevel@tonic-gate */ 83937c478bd9Sstevel@tonic-gate if (cp_unconfirmed) { 8394d216dff5SRobert Mastors rfs4_dbe_lock(cp_unconfirmed->rc_dbe); 8395d216dff5SRobert Mastors if (!cp_unconfirmed->rc_need_confirm) { 8396d216dff5SRobert Mastors rfs4_dbe_unlock(cp_unconfirmed->rc_dbe); 83977c478bd9Sstevel@tonic-gate rfs4_client_rele(cp_unconfirmed); 83987c478bd9Sstevel@tonic-gate if (cp_confirmed) 83997c478bd9Sstevel@tonic-gate rfs4_client_rele(cp_confirmed); 84007c478bd9Sstevel@tonic-gate goto retry; 84017c478bd9Sstevel@tonic-gate } 84027c478bd9Sstevel@tonic-gate /* do away with the old unconfirmed one */ 8403d216dff5SRobert Mastors rfs4_dbe_invalidate(cp_unconfirmed->rc_dbe); 8404d216dff5SRobert Mastors rfs4_dbe_unlock(cp_unconfirmed->rc_dbe); 84057c478bd9Sstevel@tonic-gate rfs4_client_rele(cp_unconfirmed); 84067c478bd9Sstevel@tonic-gate cp_unconfirmed = NULL; 84077c478bd9Sstevel@tonic-gate } 84087c478bd9Sstevel@tonic-gate 84097c478bd9Sstevel@tonic-gate /* 84107c478bd9Sstevel@tonic-gate * This search will temporarily hide the confirmed client 84117c478bd9Sstevel@tonic-gate * struct while a new client struct is created as the 84127c478bd9Sstevel@tonic-gate * unconfirmed one. 84137c478bd9Sstevel@tonic-gate */ 84147c478bd9Sstevel@tonic-gate create = TRUE; 84157c478bd9Sstevel@tonic-gate newcp = rfs4_findclient(&args->client, &create, cp_confirmed); 84167c478bd9Sstevel@tonic-gate 84177c478bd9Sstevel@tonic-gate ASSERT(newcp != NULL); 84187c478bd9Sstevel@tonic-gate 84197c478bd9Sstevel@tonic-gate if (newcp == NULL) { 84207c478bd9Sstevel@tonic-gate *cs->statusp = res->status = NFS4ERR_SERVERFAULT; 84217c478bd9Sstevel@tonic-gate rfs4_client_rele(cp_confirmed); 8422f3b585ceSsamf goto out; 84237c478bd9Sstevel@tonic-gate } 84247c478bd9Sstevel@tonic-gate 84257c478bd9Sstevel@tonic-gate /* 84267c478bd9Sstevel@tonic-gate * If one was not created, then a similar request must be in 84277c478bd9Sstevel@tonic-gate * process so release and start over with this one 84287c478bd9Sstevel@tonic-gate */ 84297c478bd9Sstevel@tonic-gate if (create != TRUE) { 84307c478bd9Sstevel@tonic-gate rfs4_client_rele(newcp); 84317c478bd9Sstevel@tonic-gate if (cp_confirmed) 84327c478bd9Sstevel@tonic-gate rfs4_client_rele(cp_confirmed); 84337c478bd9Sstevel@tonic-gate goto retry; 84347c478bd9Sstevel@tonic-gate } 84357c478bd9Sstevel@tonic-gate 84367c478bd9Sstevel@tonic-gate *cs->statusp = res->status = NFS4_OK; 8437d216dff5SRobert Mastors res->SETCLIENTID4res_u.resok4.clientid = newcp->rc_clientid; 8438d216dff5SRobert Mastors res->SETCLIENTID4res_u.resok4.setclientid_confirm = 8439d216dff5SRobert Mastors newcp->rc_confirm_verf; 84407c478bd9Sstevel@tonic-gate /* Setup callback information; CB_NULL confirmation later */ 84411b300de9Sjwahlig rfs4_client_setcb(newcp, &args->callback, args->callback_ident); 84427c478bd9Sstevel@tonic-gate 8443d216dff5SRobert Mastors newcp->rc_cp_confirmed = cp_confirmed; 84447c478bd9Sstevel@tonic-gate 84457c478bd9Sstevel@tonic-gate rfs4_client_rele(newcp); 8446f3b585ceSsamf 8447f3b585ceSsamf out: 8448f3b585ceSsamf DTRACE_NFSV4_2(op__setclientid__done, struct compound_state *, cs, 8449f3b585ceSsamf SETCLIENTID4res *, res); 84507c478bd9Sstevel@tonic-gate } 84517c478bd9Sstevel@tonic-gate 84527c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 84537c478bd9Sstevel@tonic-gate void 84547c478bd9Sstevel@tonic-gate rfs4_op_setclientid_confirm(nfs_argop4 *argop, nfs_resop4 *resop, 84557c478bd9Sstevel@tonic-gate struct svc_req *req, struct compound_state *cs) 84567c478bd9Sstevel@tonic-gate { 84577c478bd9Sstevel@tonic-gate SETCLIENTID_CONFIRM4args *args = 84587c478bd9Sstevel@tonic-gate &argop->nfs_argop4_u.opsetclientid_confirm; 84597c478bd9Sstevel@tonic-gate SETCLIENTID_CONFIRM4res *res = 84607c478bd9Sstevel@tonic-gate &resop->nfs_resop4_u.opsetclientid_confirm; 84617c478bd9Sstevel@tonic-gate rfs4_client_t *cp, *cptoclose = NULL; 84620dfe541eSEvan Layton nfs4_srv_t *nsrv4; 84637c478bd9Sstevel@tonic-gate 8464f3b585ceSsamf DTRACE_NFSV4_2(op__setclientid__confirm__start, 8465f3b585ceSsamf struct compound_state *, cs, 8466f3b585ceSsamf SETCLIENTID_CONFIRM4args *, args); 8467f3b585ceSsamf 84680dfe541eSEvan Layton nsrv4 = nfs4_get_srv(); 84697c478bd9Sstevel@tonic-gate *cs->statusp = res->status = NFS4_OK; 84707c478bd9Sstevel@tonic-gate 84717c478bd9Sstevel@tonic-gate cp = rfs4_findclient_by_id(args->clientid, TRUE); 84727c478bd9Sstevel@tonic-gate 84737c478bd9Sstevel@tonic-gate if (cp == NULL) { 84747c478bd9Sstevel@tonic-gate *cs->statusp = res->status = 84757c478bd9Sstevel@tonic-gate rfs4_check_clientid(&args->clientid, 1); 8476f3b585ceSsamf goto out; 84777c478bd9Sstevel@tonic-gate } 84787c478bd9Sstevel@tonic-gate 8479*f44e1126SVitaliy Gusev if (!creds_ok(&cp->rc_cr_set, req, cs)) { 84807c478bd9Sstevel@tonic-gate *cs->statusp = res->status = NFS4ERR_CLID_INUSE; 84817c478bd9Sstevel@tonic-gate rfs4_client_rele(cp); 8482f3b585ceSsamf goto out; 84837c478bd9Sstevel@tonic-gate } 84847c478bd9Sstevel@tonic-gate 84857c478bd9Sstevel@tonic-gate /* If the verifier doesn't match, the record doesn't match */ 8486d216dff5SRobert Mastors if (cp->rc_confirm_verf != args->setclientid_confirm) { 84877c478bd9Sstevel@tonic-gate *cs->statusp = res->status = NFS4ERR_STALE_CLIENTID; 84887c478bd9Sstevel@tonic-gate rfs4_client_rele(cp); 8489f3b585ceSsamf goto out; 84907c478bd9Sstevel@tonic-gate } 84917c478bd9Sstevel@tonic-gate 8492d216dff5SRobert Mastors rfs4_dbe_lock(cp->rc_dbe); 8493d216dff5SRobert Mastors cp->rc_need_confirm = FALSE; 8494d216dff5SRobert Mastors if (cp->rc_cp_confirmed) { 8495d216dff5SRobert Mastors cptoclose = cp->rc_cp_confirmed; 8496d216dff5SRobert Mastors cptoclose->rc_ss_remove = 1; 8497d216dff5SRobert Mastors cp->rc_cp_confirmed = NULL; 84987c478bd9Sstevel@tonic-gate } 84997c478bd9Sstevel@tonic-gate 85007c478bd9Sstevel@tonic-gate /* 8501cee86682Scalum * Update the client's associated server instance, if it's changed 8502cee86682Scalum * since the client was created. 8503cee86682Scalum */ 85040dfe541eSEvan Layton if (rfs4_servinst(cp) != nsrv4->nfs4_cur_servinst) 85050dfe541eSEvan Layton rfs4_servinst_assign(nsrv4, cp, nsrv4->nfs4_cur_servinst); 8506cee86682Scalum 8507cee86682Scalum /* 8508cee86682Scalum * Record clientid in stable storage. 8509cee86682Scalum * Must be done after server instance has been assigned. 85107c478bd9Sstevel@tonic-gate */ 85110dfe541eSEvan Layton rfs4_ss_clid(nsrv4, cp); 85127c478bd9Sstevel@tonic-gate 8513d216dff5SRobert Mastors rfs4_dbe_unlock(cp->rc_dbe); 85147c478bd9Sstevel@tonic-gate 85157c478bd9Sstevel@tonic-gate if (cptoclose) 85167c478bd9Sstevel@tonic-gate /* don't need to rele, client_close does it */ 85177c478bd9Sstevel@tonic-gate rfs4_client_close(cptoclose); 85187c478bd9Sstevel@tonic-gate 85197c478bd9Sstevel@tonic-gate /* If needed, initiate CB_NULL call for callback path */ 85207c478bd9Sstevel@tonic-gate rfs4_deleg_cb_check(cp); 85217c478bd9Sstevel@tonic-gate rfs4_update_lease(cp); 85227c478bd9Sstevel@tonic-gate 85237c478bd9Sstevel@tonic-gate /* 85247c478bd9Sstevel@tonic-gate * Check to see if client can perform reclaims 85257c478bd9Sstevel@tonic-gate */ 85260dfe541eSEvan Layton rfs4_ss_chkclid(nsrv4, cp); 85277c478bd9Sstevel@tonic-gate 85287c478bd9Sstevel@tonic-gate rfs4_client_rele(cp); 8529f3b585ceSsamf 8530f3b585ceSsamf out: 8531f3b585ceSsamf DTRACE_NFSV4_2(op__setclientid__confirm__done, 8532f3b585ceSsamf struct compound_state *, cs, 8533f3b585ceSsamf SETCLIENTID_CONFIRM4 *, res); 85347c478bd9Sstevel@tonic-gate } 85357c478bd9Sstevel@tonic-gate 85367c478bd9Sstevel@tonic-gate 85377c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 85387c478bd9Sstevel@tonic-gate void 85397c478bd9Sstevel@tonic-gate rfs4_op_close(nfs_argop4 *argop, nfs_resop4 *resop, 85407c478bd9Sstevel@tonic-gate struct svc_req *req, struct compound_state *cs) 85417c478bd9Sstevel@tonic-gate { 85427c478bd9Sstevel@tonic-gate CLOSE4args *args = &argop->nfs_argop4_u.opclose; 85437c478bd9Sstevel@tonic-gate CLOSE4res *resp = &resop->nfs_resop4_u.opclose; 85447c478bd9Sstevel@tonic-gate rfs4_state_t *sp; 85457c478bd9Sstevel@tonic-gate nfsstat4 status; 85467c478bd9Sstevel@tonic-gate 8547f3b585ceSsamf DTRACE_NFSV4_2(op__close__start, struct compound_state *, cs, 8548f3b585ceSsamf CLOSE4args *, args); 8549f3b585ceSsamf 85507c478bd9Sstevel@tonic-gate if (cs->vp == NULL) { 85517c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE; 8552f3b585ceSsamf goto out; 85537c478bd9Sstevel@tonic-gate } 85547c478bd9Sstevel@tonic-gate 85557c478bd9Sstevel@tonic-gate status = rfs4_get_state(&args->open_stateid, &sp, RFS4_DBS_INVALID); 85567c478bd9Sstevel@tonic-gate if (status != NFS4_OK) { 85577c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = status; 8558f3b585ceSsamf goto out; 85597c478bd9Sstevel@tonic-gate } 85607c478bd9Sstevel@tonic-gate 85617c478bd9Sstevel@tonic-gate /* Ensure specified filehandle matches */ 8562d216dff5SRobert Mastors if (cs->vp != sp->rs_finfo->rf_vp) { 85637c478bd9Sstevel@tonic-gate rfs4_state_rele(sp); 85647c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_BAD_STATEID; 8565f3b585ceSsamf goto out; 85667c478bd9Sstevel@tonic-gate } 85677c478bd9Sstevel@tonic-gate 85687c478bd9Sstevel@tonic-gate /* hold off other access to open_owner while we tinker */ 8569d216dff5SRobert Mastors rfs4_sw_enter(&sp->rs_owner->ro_sw); 85707c478bd9Sstevel@tonic-gate 8571*f44e1126SVitaliy Gusev switch (rfs4_check_stateid_seqid(sp, &args->open_stateid, cs)) { 85727c478bd9Sstevel@tonic-gate case NFS4_CHECK_STATEID_OKAY: 8573d216dff5SRobert Mastors if (rfs4_check_open_seqid(args->seqid, sp->rs_owner, 8574*f44e1126SVitaliy Gusev resop, cs) != NFS4_CHKSEQ_OKAY) { 85757c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_BAD_SEQID; 85767c478bd9Sstevel@tonic-gate goto end; 85777c478bd9Sstevel@tonic-gate } 85787c478bd9Sstevel@tonic-gate break; 85797c478bd9Sstevel@tonic-gate case NFS4_CHECK_STATEID_OLD: 85807c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_OLD_STATEID; 85817c478bd9Sstevel@tonic-gate goto end; 85827c478bd9Sstevel@tonic-gate case NFS4_CHECK_STATEID_BAD: 85837c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_BAD_STATEID; 85847c478bd9Sstevel@tonic-gate goto end; 85857c478bd9Sstevel@tonic-gate case NFS4_CHECK_STATEID_EXPIRED: 85867c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_EXPIRED; 85877c478bd9Sstevel@tonic-gate goto end; 85887c478bd9Sstevel@tonic-gate case NFS4_CHECK_STATEID_CLOSED: 85897c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_OLD_STATEID; 85907c478bd9Sstevel@tonic-gate goto end; 85917c478bd9Sstevel@tonic-gate case NFS4_CHECK_STATEID_UNCONFIRMED: 85927c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_BAD_STATEID; 85937c478bd9Sstevel@tonic-gate goto end; 85947c478bd9Sstevel@tonic-gate case NFS4_CHECK_STATEID_REPLAY: 8595*f44e1126SVitaliy Gusev ASSERT(!rfs4_has_session(cs)); 8596*f44e1126SVitaliy Gusev 85977c478bd9Sstevel@tonic-gate /* Check the sequence id for the open owner */ 8598d216dff5SRobert Mastors switch (rfs4_check_open_seqid(args->seqid, sp->rs_owner, 8599*f44e1126SVitaliy Gusev resop, cs)) { 86007c478bd9Sstevel@tonic-gate case NFS4_CHKSEQ_OKAY: 86017c478bd9Sstevel@tonic-gate /* 86027c478bd9Sstevel@tonic-gate * This is replayed stateid; if seqid matches 86037c478bd9Sstevel@tonic-gate * next expected, then client is using wrong seqid. 86047c478bd9Sstevel@tonic-gate */ 86057c478bd9Sstevel@tonic-gate /* FALL THROUGH */ 86067c478bd9Sstevel@tonic-gate case NFS4_CHKSEQ_BAD: 86077c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_BAD_SEQID; 86087c478bd9Sstevel@tonic-gate goto end; 86097c478bd9Sstevel@tonic-gate case NFS4_CHKSEQ_REPLAY: 86107c478bd9Sstevel@tonic-gate /* 86117c478bd9Sstevel@tonic-gate * Note this case is the duplicate case so 86127c478bd9Sstevel@tonic-gate * resp->status is already set. 86137c478bd9Sstevel@tonic-gate */ 86147c478bd9Sstevel@tonic-gate *cs->statusp = resp->status; 8615d216dff5SRobert Mastors rfs4_update_lease(sp->rs_owner->ro_client); 86167c478bd9Sstevel@tonic-gate goto end; 86177c478bd9Sstevel@tonic-gate } 86187c478bd9Sstevel@tonic-gate break; 86197c478bd9Sstevel@tonic-gate default: 86207c478bd9Sstevel@tonic-gate ASSERT(FALSE); 86217c478bd9Sstevel@tonic-gate break; 86227c478bd9Sstevel@tonic-gate } 86237c478bd9Sstevel@tonic-gate 8624d216dff5SRobert Mastors rfs4_dbe_lock(sp->rs_dbe); 86257c478bd9Sstevel@tonic-gate 86267c478bd9Sstevel@tonic-gate /* Update the stateid. */ 8627d216dff5SRobert Mastors next_stateid(&sp->rs_stateid); 8628d216dff5SRobert Mastors resp->open_stateid = sp->rs_stateid.stateid; 86297c478bd9Sstevel@tonic-gate 8630d216dff5SRobert Mastors rfs4_dbe_unlock(sp->rs_dbe); 86317c478bd9Sstevel@tonic-gate 8632d216dff5SRobert Mastors rfs4_update_lease(sp->rs_owner->ro_client); 8633d216dff5SRobert Mastors rfs4_update_open_sequence(sp->rs_owner); 8634d216dff5SRobert Mastors rfs4_update_open_resp(sp->rs_owner, resop, NULL); 86357c478bd9Sstevel@tonic-gate 86367c478bd9Sstevel@tonic-gate rfs4_state_close(sp, FALSE, FALSE, cs->cr); 86377c478bd9Sstevel@tonic-gate 86387c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = status; 86397c478bd9Sstevel@tonic-gate 86407c478bd9Sstevel@tonic-gate end: 8641d216dff5SRobert Mastors rfs4_sw_exit(&sp->rs_owner->ro_sw); 86427c478bd9Sstevel@tonic-gate rfs4_state_rele(sp); 8643f3b585ceSsamf out: 8644f3b585ceSsamf DTRACE_NFSV4_2(op__close__done, struct compound_state *, cs, 8645f3b585ceSsamf CLOSE4res *, resp); 86467c478bd9Sstevel@tonic-gate } 86477c478bd9Sstevel@tonic-gate 86487c478bd9Sstevel@tonic-gate /* 86497c478bd9Sstevel@tonic-gate * Manage the counts on the file struct and close all file locks 86507c478bd9Sstevel@tonic-gate */ 86517c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 86527c478bd9Sstevel@tonic-gate void 86537c478bd9Sstevel@tonic-gate rfs4_release_share_lock_state(rfs4_state_t *sp, cred_t *cr, 86547c478bd9Sstevel@tonic-gate bool_t close_of_client) 86557c478bd9Sstevel@tonic-gate { 8656d216dff5SRobert Mastors rfs4_file_t *fp = sp->rs_finfo; 86577c478bd9Sstevel@tonic-gate rfs4_lo_state_t *lsp; 8658d216dff5SRobert Mastors int fflags = 0; 86597c478bd9Sstevel@tonic-gate 86607c478bd9Sstevel@tonic-gate /* 86617c478bd9Sstevel@tonic-gate * If this call is part of the larger closing down of client 86627c478bd9Sstevel@tonic-gate * state then it is just easier to release all locks 86637c478bd9Sstevel@tonic-gate * associated with this client instead of going through each 86647c478bd9Sstevel@tonic-gate * individual file and cleaning locks there. 86657c478bd9Sstevel@tonic-gate */ 86667c478bd9Sstevel@tonic-gate if (close_of_client) { 8667d216dff5SRobert Mastors if (sp->rs_owner->ro_client->rc_unlksys_completed == FALSE && 8668d216dff5SRobert Mastors !list_is_empty(&sp->rs_lostatelist) && 8669d216dff5SRobert Mastors sp->rs_owner->ro_client->rc_sysidt != LM_NOSYSID) { 86707c478bd9Sstevel@tonic-gate /* Is the PxFS kernel module loaded? */ 86717c478bd9Sstevel@tonic-gate if (lm_remove_file_locks != NULL) { 86727c478bd9Sstevel@tonic-gate int new_sysid; 86737c478bd9Sstevel@tonic-gate 86747c478bd9Sstevel@tonic-gate /* Encode the cluster nodeid in new sysid */ 8675d216dff5SRobert Mastors new_sysid = sp->rs_owner->ro_client->rc_sysidt; 86767c478bd9Sstevel@tonic-gate lm_set_nlmid_flk(&new_sysid); 86777c478bd9Sstevel@tonic-gate 86787c478bd9Sstevel@tonic-gate /* 86797c478bd9Sstevel@tonic-gate * This PxFS routine removes file locks for a 86807c478bd9Sstevel@tonic-gate * client over all nodes of a cluster. 86817c478bd9Sstevel@tonic-gate */ 86827c478bd9Sstevel@tonic-gate NFS4_DEBUG(rfs4_debug, (CE_NOTE, 86837c478bd9Sstevel@tonic-gate "lm_remove_file_locks(sysid=0x%x)\n", 86847c478bd9Sstevel@tonic-gate new_sysid)); 86857c478bd9Sstevel@tonic-gate (*lm_remove_file_locks)(new_sysid); 86867c478bd9Sstevel@tonic-gate } else { 86877c478bd9Sstevel@tonic-gate struct flock64 flk; 86887c478bd9Sstevel@tonic-gate 86897c478bd9Sstevel@tonic-gate /* Release all locks for this client */ 86907c478bd9Sstevel@tonic-gate flk.l_type = F_UNLKSYS; 86917c478bd9Sstevel@tonic-gate flk.l_whence = 0; 86927c478bd9Sstevel@tonic-gate flk.l_start = 0; 86937c478bd9Sstevel@tonic-gate flk.l_len = 0; 8694d216dff5SRobert Mastors flk.l_sysid = 8695d216dff5SRobert Mastors sp->rs_owner->ro_client->rc_sysidt; 86967c478bd9Sstevel@tonic-gate flk.l_pid = 0; 8697d216dff5SRobert Mastors (void) VOP_FRLOCK(sp->rs_finfo->rf_vp, F_SETLK, 8698d216dff5SRobert Mastors &flk, F_REMOTELOCK | FREAD | FWRITE, 8699da6c28aaSamw (u_offset_t)0, NULL, CRED(), NULL); 87007c478bd9Sstevel@tonic-gate } 87017c478bd9Sstevel@tonic-gate 8702d216dff5SRobert Mastors sp->rs_owner->ro_client->rc_unlksys_completed = TRUE; 87037c478bd9Sstevel@tonic-gate } 87047c478bd9Sstevel@tonic-gate } 87057c478bd9Sstevel@tonic-gate 87067c478bd9Sstevel@tonic-gate /* 87077c478bd9Sstevel@tonic-gate * Release all locks on this file by this lock owner or at 87087c478bd9Sstevel@tonic-gate * least mark the locks as having been released 87097c478bd9Sstevel@tonic-gate */ 8710d216dff5SRobert Mastors for (lsp = list_head(&sp->rs_lostatelist); lsp != NULL; 8711d216dff5SRobert Mastors lsp = list_next(&sp->rs_lostatelist, lsp)) { 8712d216dff5SRobert Mastors lsp->rls_locks_cleaned = TRUE; 87137c478bd9Sstevel@tonic-gate 87147c478bd9Sstevel@tonic-gate /* Was this already taken care of above? */ 87157c478bd9Sstevel@tonic-gate if (!close_of_client && 8716d216dff5SRobert Mastors sp->rs_owner->ro_client->rc_sysidt != LM_NOSYSID) 8717d216dff5SRobert Mastors (void) cleanlocks(sp->rs_finfo->rf_vp, 8718d216dff5SRobert Mastors lsp->rls_locker->rl_pid, 8719d216dff5SRobert Mastors lsp->rls_locker->rl_client->rc_sysidt); 87207c478bd9Sstevel@tonic-gate } 87217c478bd9Sstevel@tonic-gate 87227c478bd9Sstevel@tonic-gate /* 87237c478bd9Sstevel@tonic-gate * Release any shrlocks associated with this open state ID. 87247c478bd9Sstevel@tonic-gate * This must be done before the rfs4_state gets marked closed. 87257c478bd9Sstevel@tonic-gate */ 8726d216dff5SRobert Mastors if (sp->rs_owner->ro_client->rc_sysidt != LM_NOSYSID) 8727d216dff5SRobert Mastors (void) rfs4_unshare(sp); 8728da6c28aaSamw 872950956b22SJames Wahlig if (sp->rs_open_access) { 873050956b22SJames Wahlig rfs4_dbe_lock(fp->rf_dbe); 873150956b22SJames Wahlig 873214f41b92SRobert Mastors /* 873314f41b92SRobert Mastors * Decrement the count for each access and deny bit that this 873414f41b92SRobert Mastors * state has contributed to the file. 873514f41b92SRobert Mastors * If the file counts go to zero 873614f41b92SRobert Mastors * clear the appropriate bit in the appropriate mask. 873714f41b92SRobert Mastors */ 873850956b22SJames Wahlig if (sp->rs_open_access & OPEN4_SHARE_ACCESS_READ) { 873914f41b92SRobert Mastors fp->rf_access_read--; 874014f41b92SRobert Mastors fflags |= FREAD; 874114f41b92SRobert Mastors if (fp->rf_access_read == 0) 874214f41b92SRobert Mastors fp->rf_share_access &= ~OPEN4_SHARE_ACCESS_READ; 874314f41b92SRobert Mastors } 874450956b22SJames Wahlig if (sp->rs_open_access & OPEN4_SHARE_ACCESS_WRITE) { 874514f41b92SRobert Mastors fp->rf_access_write--; 874614f41b92SRobert Mastors fflags |= FWRITE; 874714f41b92SRobert Mastors if (fp->rf_access_write == 0) 874814f41b92SRobert Mastors fp->rf_share_access &= 874914f41b92SRobert Mastors ~OPEN4_SHARE_ACCESS_WRITE; 875014f41b92SRobert Mastors } 875150956b22SJames Wahlig if (sp->rs_open_deny & OPEN4_SHARE_DENY_READ) { 875214f41b92SRobert Mastors fp->rf_deny_read--; 875314f41b92SRobert Mastors if (fp->rf_deny_read == 0) 875414f41b92SRobert Mastors fp->rf_share_deny &= ~OPEN4_SHARE_DENY_READ; 875514f41b92SRobert Mastors } 875650956b22SJames Wahlig if (sp->rs_open_deny & OPEN4_SHARE_DENY_WRITE) { 875714f41b92SRobert Mastors fp->rf_deny_write--; 875814f41b92SRobert Mastors if (fp->rf_deny_write == 0) 875914f41b92SRobert Mastors fp->rf_share_deny &= ~OPEN4_SHARE_DENY_WRITE; 876014f41b92SRobert Mastors } 876114f41b92SRobert Mastors 8762d216dff5SRobert Mastors (void) VOP_CLOSE(fp->rf_vp, fflags, 1, (offset_t)0, cr, NULL); 876314f41b92SRobert Mastors 876450956b22SJames Wahlig rfs4_dbe_unlock(fp->rf_dbe); 876550956b22SJames Wahlig 876650956b22SJames Wahlig sp->rs_open_access = 0; 876750956b22SJames Wahlig sp->rs_open_deny = 0; 876814f41b92SRobert Mastors } 87697c478bd9Sstevel@tonic-gate } 87707c478bd9Sstevel@tonic-gate 87717c478bd9Sstevel@tonic-gate /* 87727c478bd9Sstevel@tonic-gate * lock_denied: Fill in a LOCK4deneid structure given an flock64 structure. 87737c478bd9Sstevel@tonic-gate */ 87747c478bd9Sstevel@tonic-gate static nfsstat4 87757c478bd9Sstevel@tonic-gate lock_denied(LOCK4denied *dp, struct flock64 *flk) 87767c478bd9Sstevel@tonic-gate { 87777c478bd9Sstevel@tonic-gate rfs4_lockowner_t *lo; 87787c478bd9Sstevel@tonic-gate rfs4_client_t *cp; 87797c478bd9Sstevel@tonic-gate uint32_t len; 87807c478bd9Sstevel@tonic-gate 87817c478bd9Sstevel@tonic-gate lo = rfs4_findlockowner_by_pid(flk->l_pid); 87827c478bd9Sstevel@tonic-gate if (lo != NULL) { 8783d216dff5SRobert Mastors cp = lo->rl_client; 87847c478bd9Sstevel@tonic-gate if (rfs4_lease_expired(cp)) { 87857c478bd9Sstevel@tonic-gate rfs4_lockowner_rele(lo); 8786d216dff5SRobert Mastors rfs4_dbe_hold(cp->rc_dbe); 87877c478bd9Sstevel@tonic-gate rfs4_client_close(cp); 87887c478bd9Sstevel@tonic-gate return (NFS4ERR_EXPIRED); 87897c478bd9Sstevel@tonic-gate } 8790d216dff5SRobert Mastors dp->owner.clientid = lo->rl_owner.clientid; 8791d216dff5SRobert Mastors len = lo->rl_owner.owner_len; 87927c478bd9Sstevel@tonic-gate dp->owner.owner_val = kmem_alloc(len, KM_SLEEP); 8793d216dff5SRobert Mastors bcopy(lo->rl_owner.owner_val, dp->owner.owner_val, len); 87947c478bd9Sstevel@tonic-gate dp->owner.owner_len = len; 87957c478bd9Sstevel@tonic-gate rfs4_lockowner_rele(lo); 87967c478bd9Sstevel@tonic-gate goto finish; 87977c478bd9Sstevel@tonic-gate } 87987c478bd9Sstevel@tonic-gate 87997c478bd9Sstevel@tonic-gate /* 88007c478bd9Sstevel@tonic-gate * Its not a NFS4 lock. We take advantage that the upper 32 bits 88017c478bd9Sstevel@tonic-gate * of the client id contain the boot time for a NFS4 lock. So we 88027c478bd9Sstevel@tonic-gate * fabricate and identity by setting clientid to the sysid, and 88037c478bd9Sstevel@tonic-gate * the lock owner to the pid. 88047c478bd9Sstevel@tonic-gate */ 88057c478bd9Sstevel@tonic-gate dp->owner.clientid = flk->l_sysid; 88067c478bd9Sstevel@tonic-gate len = sizeof (pid_t); 88077c478bd9Sstevel@tonic-gate dp->owner.owner_len = len; 88087c478bd9Sstevel@tonic-gate dp->owner.owner_val = kmem_alloc(len, KM_SLEEP); 88097c478bd9Sstevel@tonic-gate bcopy(&flk->l_pid, dp->owner.owner_val, len); 88107c478bd9Sstevel@tonic-gate finish: 88117c478bd9Sstevel@tonic-gate dp->offset = flk->l_start; 88127c478bd9Sstevel@tonic-gate dp->length = flk->l_len; 88137c478bd9Sstevel@tonic-gate 88147c478bd9Sstevel@tonic-gate if (flk->l_type == F_RDLCK) 88157c478bd9Sstevel@tonic-gate dp->locktype = READ_LT; 88167c478bd9Sstevel@tonic-gate else if (flk->l_type == F_WRLCK) 88177c478bd9Sstevel@tonic-gate dp->locktype = WRITE_LT; 88187c478bd9Sstevel@tonic-gate else 88197c478bd9Sstevel@tonic-gate return (NFS4ERR_INVAL); /* no mapping from POSIX ltype to v4 */ 88207c478bd9Sstevel@tonic-gate 88217c478bd9Sstevel@tonic-gate return (NFS4_OK); 88227c478bd9Sstevel@tonic-gate } 88237c478bd9Sstevel@tonic-gate 882455a4551dSMarcel Telka /* 882555a4551dSMarcel Telka * The NFSv4.0 LOCK operation does not support the blocking lock (at the 882655a4551dSMarcel Telka * NFSv4.0 protocol level) so the client needs to resend the LOCK request in a 882755a4551dSMarcel Telka * case the lock is denied by the NFSv4.0 server. NFSv4.0 clients are prepared 882855a4551dSMarcel Telka * for that (obviously); they are sending the LOCK requests with some delays 882955a4551dSMarcel Telka * between the attempts. See nfs4frlock() and nfs4_block_and_wait() for the 883055a4551dSMarcel Telka * locking and delay implementation at the client side. 883155a4551dSMarcel Telka * 883255a4551dSMarcel Telka * To make the life of the clients easier, the NFSv4.0 server tries to do some 883355a4551dSMarcel Telka * fast retries on its own (the for loop below) in a hope the lock will be 883455a4551dSMarcel Telka * available soon. And if not, the client won't need to resend the LOCK 883555a4551dSMarcel Telka * requests so fast to check the lock availability. This basically saves some 883655a4551dSMarcel Telka * network traffic and tries to make sure the client gets the lock ASAP. 883755a4551dSMarcel Telka */ 88387c478bd9Sstevel@tonic-gate static int 88397c478bd9Sstevel@tonic-gate setlock(vnode_t *vp, struct flock64 *flock, int flag, cred_t *cred) 88407c478bd9Sstevel@tonic-gate { 88417c478bd9Sstevel@tonic-gate int error; 88427c478bd9Sstevel@tonic-gate struct flock64 flk; 88437c478bd9Sstevel@tonic-gate int i; 88447c478bd9Sstevel@tonic-gate clock_t delaytime; 8845da6c28aaSamw int cmd; 884655a4551dSMarcel Telka int spin_cnt = 0; 88477c478bd9Sstevel@tonic-gate 8848da6c28aaSamw cmd = nbl_need_check(vp) ? F_SETLK_NBMAND : F_SETLK; 88497c478bd9Sstevel@tonic-gate retry: 88507c478bd9Sstevel@tonic-gate delaytime = MSEC_TO_TICK_ROUNDUP(rfs4_lock_delay); 88517c478bd9Sstevel@tonic-gate 88527c478bd9Sstevel@tonic-gate for (i = 0; i < rfs4_maxlock_tries; i++) { 8853da6c28aaSamw LOCK_PRINT(rfs4_debug, "setlock", cmd, flock); 8854da6c28aaSamw error = VOP_FRLOCK(vp, cmd, 8855da6c28aaSamw flock, flag, (u_offset_t)0, NULL, cred, NULL); 88567c478bd9Sstevel@tonic-gate 88577c478bd9Sstevel@tonic-gate if (error != EAGAIN && error != EACCES) 88587c478bd9Sstevel@tonic-gate break; 88597c478bd9Sstevel@tonic-gate 88607c478bd9Sstevel@tonic-gate if (i < rfs4_maxlock_tries - 1) { 88617c478bd9Sstevel@tonic-gate delay(delaytime); 88627c478bd9Sstevel@tonic-gate delaytime *= 2; 88637c478bd9Sstevel@tonic-gate } 88647c478bd9Sstevel@tonic-gate } 88657c478bd9Sstevel@tonic-gate 88667c478bd9Sstevel@tonic-gate if (error == EAGAIN || error == EACCES) { 88677c478bd9Sstevel@tonic-gate /* Get the owner of the lock */ 88687c478bd9Sstevel@tonic-gate flk = *flock; 88697c478bd9Sstevel@tonic-gate LOCK_PRINT(rfs4_debug, "setlock", F_GETLK, &flk); 887055a4551dSMarcel Telka if (VOP_FRLOCK(vp, F_GETLK, &flk, flag, 0, NULL, cred, 887155a4551dSMarcel Telka NULL) == 0) { 887255a4551dSMarcel Telka /* 887355a4551dSMarcel Telka * There's a race inherent in the current VOP_FRLOCK 887455a4551dSMarcel Telka * design where: 887555a4551dSMarcel Telka * a: "other guy" takes a lock that conflicts with a 887655a4551dSMarcel Telka * lock we want 887755a4551dSMarcel Telka * b: we attempt to take our lock (non-blocking) and 887855a4551dSMarcel Telka * the attempt fails. 887955a4551dSMarcel Telka * c: "other guy" releases the conflicting lock 888055a4551dSMarcel Telka * d: we ask what lock conflicts with the lock we want, 888155a4551dSMarcel Telka * getting F_UNLCK (no lock blocks us) 888255a4551dSMarcel Telka * 888355a4551dSMarcel Telka * If we retry the non-blocking lock attempt in this 888455a4551dSMarcel Telka * case (restart at step 'b') there's some possibility 888555a4551dSMarcel Telka * that many such attempts might fail. However a test 888655a4551dSMarcel Telka * designed to actually provoke this race shows that 888755a4551dSMarcel Telka * the vast majority of cases require no retry, and 888855a4551dSMarcel Telka * only a few took as many as three retries. Here's 888955a4551dSMarcel Telka * the test outcome: 889055a4551dSMarcel Telka * 889155a4551dSMarcel Telka * number of retries how many times we needed 889255a4551dSMarcel Telka * that many retries 889355a4551dSMarcel Telka * 0 79461 889455a4551dSMarcel Telka * 1 862 889555a4551dSMarcel Telka * 2 49 889655a4551dSMarcel Telka * 3 5 889755a4551dSMarcel Telka * 889855a4551dSMarcel Telka * Given those empirical results, we arbitrarily limit 889955a4551dSMarcel Telka * the retry count to ten. 890055a4551dSMarcel Telka * 890155a4551dSMarcel Telka * If we actually make to ten retries and give up, 890255a4551dSMarcel Telka * nothing catastrophic happens, but we're unable to 890355a4551dSMarcel Telka * return the information about the conflicting lock to 890455a4551dSMarcel Telka * the NFS client. That's an acceptable trade off vs. 890555a4551dSMarcel Telka * letting this retry loop run forever. 890655a4551dSMarcel Telka */ 89077c478bd9Sstevel@tonic-gate if (flk.l_type == F_UNLCK) { 890855a4551dSMarcel Telka if (spin_cnt++ < 10) { 89097c478bd9Sstevel@tonic-gate /* No longer locked, retry */ 89107c478bd9Sstevel@tonic-gate goto retry; 89117c478bd9Sstevel@tonic-gate } 891255a4551dSMarcel Telka } else { 89137c478bd9Sstevel@tonic-gate *flock = flk; 89147c478bd9Sstevel@tonic-gate LOCK_PRINT(rfs4_debug, "setlock(blocking lock)", 89157c478bd9Sstevel@tonic-gate F_GETLK, &flk); 89167c478bd9Sstevel@tonic-gate } 89177c478bd9Sstevel@tonic-gate } 891855a4551dSMarcel Telka } 89197c478bd9Sstevel@tonic-gate 89207c478bd9Sstevel@tonic-gate return (error); 89217c478bd9Sstevel@tonic-gate } 89227c478bd9Sstevel@tonic-gate 89237c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 89247c478bd9Sstevel@tonic-gate static nfsstat4 8925d216dff5SRobert Mastors rfs4_do_lock(rfs4_lo_state_t *lsp, nfs_lock_type4 locktype, 8926d216dff5SRobert Mastors offset4 offset, length4 length, cred_t *cred, nfs_resop4 *resop) 89277c478bd9Sstevel@tonic-gate { 89287c478bd9Sstevel@tonic-gate nfsstat4 status; 8929d216dff5SRobert Mastors rfs4_lockowner_t *lo = lsp->rls_locker; 8930d216dff5SRobert Mastors rfs4_state_t *sp = lsp->rls_state; 89317c478bd9Sstevel@tonic-gate struct flock64 flock; 89327c478bd9Sstevel@tonic-gate int16_t ltype; 89337c478bd9Sstevel@tonic-gate int flag; 89347c478bd9Sstevel@tonic-gate int error; 89357c478bd9Sstevel@tonic-gate sysid_t sysid; 89367c478bd9Sstevel@tonic-gate LOCK4res *lres; 89373a36268eSMarcel Telka vnode_t *vp; 89387c478bd9Sstevel@tonic-gate 8939d216dff5SRobert Mastors if (rfs4_lease_expired(lo->rl_client)) { 89407c478bd9Sstevel@tonic-gate return (NFS4ERR_EXPIRED); 89417c478bd9Sstevel@tonic-gate } 89427c478bd9Sstevel@tonic-gate 8943d216dff5SRobert Mastors if ((status = rfs4_client_sysid(lo->rl_client, &sysid)) != NFS4_OK) 89447c478bd9Sstevel@tonic-gate return (status); 89457c478bd9Sstevel@tonic-gate 89467c478bd9Sstevel@tonic-gate /* Check for zero length. To lock to end of file use all ones for V4 */ 89477c478bd9Sstevel@tonic-gate if (length == 0) 89487c478bd9Sstevel@tonic-gate return (NFS4ERR_INVAL); 89497c478bd9Sstevel@tonic-gate else if (length == (length4)(~0)) 89507c478bd9Sstevel@tonic-gate length = 0; /* Posix to end of file */ 89517c478bd9Sstevel@tonic-gate 89527c478bd9Sstevel@tonic-gate retry: 8953d216dff5SRobert Mastors rfs4_dbe_lock(sp->rs_dbe); 89543a36268eSMarcel Telka if (sp->rs_closed == TRUE) { 8955d216dff5SRobert Mastors rfs4_dbe_unlock(sp->rs_dbe); 8956d216dff5SRobert Mastors return (NFS4ERR_OLD_STATEID); 8957d216dff5SRobert Mastors } 89587c478bd9Sstevel@tonic-gate 89597c478bd9Sstevel@tonic-gate if (resop->resop != OP_LOCKU) { 89607c478bd9Sstevel@tonic-gate switch (locktype) { 89617c478bd9Sstevel@tonic-gate case READ_LT: 89627c478bd9Sstevel@tonic-gate case READW_LT: 8963d216dff5SRobert Mastors if ((sp->rs_share_access 89647c478bd9Sstevel@tonic-gate & OPEN4_SHARE_ACCESS_READ) == 0) { 8965d216dff5SRobert Mastors rfs4_dbe_unlock(sp->rs_dbe); 89667c478bd9Sstevel@tonic-gate 89677c478bd9Sstevel@tonic-gate return (NFS4ERR_OPENMODE); 89687c478bd9Sstevel@tonic-gate } 89697c478bd9Sstevel@tonic-gate ltype = F_RDLCK; 89707c478bd9Sstevel@tonic-gate break; 89717c478bd9Sstevel@tonic-gate case WRITE_LT: 89727c478bd9Sstevel@tonic-gate case WRITEW_LT: 8973d216dff5SRobert Mastors if ((sp->rs_share_access 89747c478bd9Sstevel@tonic-gate & OPEN4_SHARE_ACCESS_WRITE) == 0) { 8975d216dff5SRobert Mastors rfs4_dbe_unlock(sp->rs_dbe); 89767c478bd9Sstevel@tonic-gate 89777c478bd9Sstevel@tonic-gate return (NFS4ERR_OPENMODE); 89787c478bd9Sstevel@tonic-gate } 89797c478bd9Sstevel@tonic-gate ltype = F_WRLCK; 89807c478bd9Sstevel@tonic-gate break; 89817c478bd9Sstevel@tonic-gate } 89827c478bd9Sstevel@tonic-gate } else 89837c478bd9Sstevel@tonic-gate ltype = F_UNLCK; 89847c478bd9Sstevel@tonic-gate 89857c478bd9Sstevel@tonic-gate flock.l_type = ltype; 89867c478bd9Sstevel@tonic-gate flock.l_whence = 0; /* SEEK_SET */ 89877c478bd9Sstevel@tonic-gate flock.l_start = offset; 89887c478bd9Sstevel@tonic-gate flock.l_len = length; 89897c478bd9Sstevel@tonic-gate flock.l_sysid = sysid; 8990d216dff5SRobert Mastors flock.l_pid = lsp->rls_locker->rl_pid; 89917c478bd9Sstevel@tonic-gate 89927c478bd9Sstevel@tonic-gate /* Note that length4 is uint64_t but l_len and l_start are off64_t */ 89937c478bd9Sstevel@tonic-gate if (flock.l_len < 0 || flock.l_start < 0) { 8994d216dff5SRobert Mastors rfs4_dbe_unlock(sp->rs_dbe); 89957c478bd9Sstevel@tonic-gate return (NFS4ERR_INVAL); 89967c478bd9Sstevel@tonic-gate } 89977c478bd9Sstevel@tonic-gate 89987c478bd9Sstevel@tonic-gate /* 89997c478bd9Sstevel@tonic-gate * N.B. FREAD has the same value as OPEN4_SHARE_ACCESS_READ and 90007c478bd9Sstevel@tonic-gate * FWRITE has the same value as OPEN4_SHARE_ACCESS_WRITE. 90017c478bd9Sstevel@tonic-gate */ 9002d216dff5SRobert Mastors flag = (int)sp->rs_share_access | F_REMOTELOCK; 90037c478bd9Sstevel@tonic-gate 90043a36268eSMarcel Telka vp = sp->rs_finfo->rf_vp; 90053a36268eSMarcel Telka VN_HOLD(vp); 90063a36268eSMarcel Telka 90073a36268eSMarcel Telka /* 90083a36268eSMarcel Telka * We need to unlock sp before we call the underlying filesystem to 90093a36268eSMarcel Telka * acquire the file lock. 90103a36268eSMarcel Telka */ 90113a36268eSMarcel Telka rfs4_dbe_unlock(sp->rs_dbe); 90123a36268eSMarcel Telka 90133a36268eSMarcel Telka error = setlock(vp, &flock, flag, cred); 90143a36268eSMarcel Telka 90153a36268eSMarcel Telka /* 90163a36268eSMarcel Telka * Make sure the file is still open. In a case the file was closed in 90173a36268eSMarcel Telka * the meantime, clean the lock we acquired using the setlock() call 90183a36268eSMarcel Telka * above, and return the appropriate error. 90193a36268eSMarcel Telka */ 90203a36268eSMarcel Telka rfs4_dbe_lock(sp->rs_dbe); 90213a36268eSMarcel Telka if (sp->rs_closed == TRUE) { 90223a36268eSMarcel Telka cleanlocks(vp, lsp->rls_locker->rl_pid, sysid); 90233a36268eSMarcel Telka rfs4_dbe_unlock(sp->rs_dbe); 90243a36268eSMarcel Telka 90253a36268eSMarcel Telka VN_RELE(vp); 90263a36268eSMarcel Telka 90273a36268eSMarcel Telka return (NFS4ERR_OLD_STATEID); 90283a36268eSMarcel Telka } 90293a36268eSMarcel Telka rfs4_dbe_unlock(sp->rs_dbe); 90303a36268eSMarcel Telka 90313a36268eSMarcel Telka VN_RELE(vp); 90323a36268eSMarcel Telka 90337c478bd9Sstevel@tonic-gate if (error == 0) { 9034d216dff5SRobert Mastors rfs4_dbe_lock(lsp->rls_dbe); 9035d216dff5SRobert Mastors next_stateid(&lsp->rls_lockid); 9036d216dff5SRobert Mastors rfs4_dbe_unlock(lsp->rls_dbe); 90377c478bd9Sstevel@tonic-gate } 90387c478bd9Sstevel@tonic-gate 90397c478bd9Sstevel@tonic-gate /* 90407c478bd9Sstevel@tonic-gate * N.B. We map error values to nfsv4 errors. This is differrent 90417c478bd9Sstevel@tonic-gate * than puterrno4 routine. 90427c478bd9Sstevel@tonic-gate */ 90437c478bd9Sstevel@tonic-gate switch (error) { 90447c478bd9Sstevel@tonic-gate case 0: 90457c478bd9Sstevel@tonic-gate status = NFS4_OK; 90467c478bd9Sstevel@tonic-gate break; 90477c478bd9Sstevel@tonic-gate case EAGAIN: 90487c478bd9Sstevel@tonic-gate case EACCES: /* Old value */ 90497c478bd9Sstevel@tonic-gate /* Can only get here if op is OP_LOCK */ 90507c478bd9Sstevel@tonic-gate ASSERT(resop->resop == OP_LOCK); 90517c478bd9Sstevel@tonic-gate lres = &resop->nfs_resop4_u.oplock; 90527c478bd9Sstevel@tonic-gate status = NFS4ERR_DENIED; 90537c478bd9Sstevel@tonic-gate if (lock_denied(&lres->LOCK4res_u.denied, &flock) 90547c478bd9Sstevel@tonic-gate == NFS4ERR_EXPIRED) 90557c478bd9Sstevel@tonic-gate goto retry; 90567c478bd9Sstevel@tonic-gate break; 90577c478bd9Sstevel@tonic-gate case ENOLCK: 90587c478bd9Sstevel@tonic-gate status = NFS4ERR_DELAY; 90597c478bd9Sstevel@tonic-gate break; 90607c478bd9Sstevel@tonic-gate case EOVERFLOW: 90617c478bd9Sstevel@tonic-gate status = NFS4ERR_INVAL; 90627c478bd9Sstevel@tonic-gate break; 90637c478bd9Sstevel@tonic-gate case EINVAL: 90647c478bd9Sstevel@tonic-gate status = NFS4ERR_NOTSUPP; 90657c478bd9Sstevel@tonic-gate break; 90667c478bd9Sstevel@tonic-gate default: 90677c478bd9Sstevel@tonic-gate status = NFS4ERR_SERVERFAULT; 90687c478bd9Sstevel@tonic-gate break; 90697c478bd9Sstevel@tonic-gate } 90707c478bd9Sstevel@tonic-gate 90717c478bd9Sstevel@tonic-gate return (status); 90727c478bd9Sstevel@tonic-gate } 90737c478bd9Sstevel@tonic-gate 90747c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 90757c478bd9Sstevel@tonic-gate void 90767c478bd9Sstevel@tonic-gate rfs4_op_lock(nfs_argop4 *argop, nfs_resop4 *resop, 90777c478bd9Sstevel@tonic-gate struct svc_req *req, struct compound_state *cs) 90787c478bd9Sstevel@tonic-gate { 90797c478bd9Sstevel@tonic-gate LOCK4args *args = &argop->nfs_argop4_u.oplock; 90807c478bd9Sstevel@tonic-gate LOCK4res *resp = &resop->nfs_resop4_u.oplock; 90817c478bd9Sstevel@tonic-gate nfsstat4 status; 90827c478bd9Sstevel@tonic-gate stateid4 *stateid; 90837c478bd9Sstevel@tonic-gate rfs4_lockowner_t *lo; 90847c478bd9Sstevel@tonic-gate rfs4_client_t *cp; 90857c478bd9Sstevel@tonic-gate rfs4_state_t *sp = NULL; 90867c478bd9Sstevel@tonic-gate rfs4_lo_state_t *lsp = NULL; 90877c478bd9Sstevel@tonic-gate bool_t ls_sw_held = FALSE; 90887c478bd9Sstevel@tonic-gate bool_t create = TRUE; 90897c478bd9Sstevel@tonic-gate bool_t lcreate = TRUE; 90907c478bd9Sstevel@tonic-gate bool_t dup_lock = FALSE; 90917c478bd9Sstevel@tonic-gate int rc; 90927c478bd9Sstevel@tonic-gate 9093f3b585ceSsamf DTRACE_NFSV4_2(op__lock__start, struct compound_state *, cs, 9094f3b585ceSsamf LOCK4args *, args); 9095f3b585ceSsamf 90967c478bd9Sstevel@tonic-gate if (cs->vp == NULL) { 90977c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE; 9098f3b585ceSsamf DTRACE_NFSV4_2(op__lock__done, struct compound_state *, 9099f3b585ceSsamf cs, LOCK4res *, resp); 91007c478bd9Sstevel@tonic-gate return; 91017c478bd9Sstevel@tonic-gate } 91027c478bd9Sstevel@tonic-gate 91037c478bd9Sstevel@tonic-gate if (args->locker.new_lock_owner) { 91047c478bd9Sstevel@tonic-gate /* Create a new lockowner for this instance */ 91057c478bd9Sstevel@tonic-gate open_to_lock_owner4 *olo = &args->locker.locker4_u.open_owner; 91067c478bd9Sstevel@tonic-gate 91077c478bd9Sstevel@tonic-gate NFS4_DEBUG(rfs4_debug, (CE_NOTE, "Creating new lock owner")); 91087c478bd9Sstevel@tonic-gate 91097c478bd9Sstevel@tonic-gate stateid = &olo->open_stateid; 91107c478bd9Sstevel@tonic-gate status = rfs4_get_state(stateid, &sp, RFS4_DBS_VALID); 91117c478bd9Sstevel@tonic-gate if (status != NFS4_OK) { 91127c478bd9Sstevel@tonic-gate NFS4_DEBUG(rfs4_debug, 91131b300de9Sjwahlig (CE_NOTE, "Get state failed in lock %d", status)); 91147c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = status; 9115f3b585ceSsamf DTRACE_NFSV4_2(op__lock__done, struct compound_state *, 9116f3b585ceSsamf cs, LOCK4res *, resp); 91177c478bd9Sstevel@tonic-gate return; 91187c478bd9Sstevel@tonic-gate } 91197c478bd9Sstevel@tonic-gate 91207c478bd9Sstevel@tonic-gate /* Ensure specified filehandle matches */ 9121d216dff5SRobert Mastors if (cs->vp != sp->rs_finfo->rf_vp) { 91227c478bd9Sstevel@tonic-gate rfs4_state_rele(sp); 91237c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_BAD_STATEID; 9124f3b585ceSsamf DTRACE_NFSV4_2(op__lock__done, struct compound_state *, 9125f3b585ceSsamf cs, LOCK4res *, resp); 91267c478bd9Sstevel@tonic-gate return; 91277c478bd9Sstevel@tonic-gate } 91287c478bd9Sstevel@tonic-gate 91297c478bd9Sstevel@tonic-gate /* hold off other access to open_owner while we tinker */ 9130d216dff5SRobert Mastors rfs4_sw_enter(&sp->rs_owner->ro_sw); 91317c478bd9Sstevel@tonic-gate 9132*f44e1126SVitaliy Gusev switch (rc = rfs4_check_stateid_seqid(sp, stateid, cs)) { 91337c478bd9Sstevel@tonic-gate case NFS4_CHECK_STATEID_OLD: 91347c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_OLD_STATEID; 91357c478bd9Sstevel@tonic-gate goto end; 91367c478bd9Sstevel@tonic-gate case NFS4_CHECK_STATEID_BAD: 91377c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_BAD_STATEID; 91387c478bd9Sstevel@tonic-gate goto end; 91397c478bd9Sstevel@tonic-gate case NFS4_CHECK_STATEID_EXPIRED: 91407c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_EXPIRED; 91417c478bd9Sstevel@tonic-gate goto end; 91427c478bd9Sstevel@tonic-gate case NFS4_CHECK_STATEID_UNCONFIRMED: 91437c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_BAD_STATEID; 91447c478bd9Sstevel@tonic-gate goto end; 91457c478bd9Sstevel@tonic-gate case NFS4_CHECK_STATEID_CLOSED: 91467c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_OLD_STATEID; 91477c478bd9Sstevel@tonic-gate goto end; 91487c478bd9Sstevel@tonic-gate case NFS4_CHECK_STATEID_OKAY: 9149*f44e1126SVitaliy Gusev if (rfs4_has_session(cs)) 9150*f44e1126SVitaliy Gusev break; 9151*f44e1126SVitaliy Gusev /* FALLTHROUGH */ 91527c478bd9Sstevel@tonic-gate case NFS4_CHECK_STATEID_REPLAY: 9153*f44e1126SVitaliy Gusev ASSERT(!rfs4_has_session(cs)); 9154*f44e1126SVitaliy Gusev 91557c478bd9Sstevel@tonic-gate switch (rfs4_check_olo_seqid(olo->open_seqid, 9156d216dff5SRobert Mastors sp->rs_owner, resop)) { 91577c478bd9Sstevel@tonic-gate case NFS4_CHKSEQ_OKAY: 91587c478bd9Sstevel@tonic-gate if (rc == NFS4_CHECK_STATEID_OKAY) 91597c478bd9Sstevel@tonic-gate break; 91607c478bd9Sstevel@tonic-gate /* 91617c478bd9Sstevel@tonic-gate * This is replayed stateid; if seqid 91627c478bd9Sstevel@tonic-gate * matches next expected, then client 91637c478bd9Sstevel@tonic-gate * is using wrong seqid. 91647c478bd9Sstevel@tonic-gate */ 91657c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 91667c478bd9Sstevel@tonic-gate case NFS4_CHKSEQ_BAD: 91671b300de9Sjwahlig *cs->statusp = resp->status = NFS4ERR_BAD_SEQID; 91687c478bd9Sstevel@tonic-gate goto end; 91697c478bd9Sstevel@tonic-gate case NFS4_CHKSEQ_REPLAY: 91707c478bd9Sstevel@tonic-gate /* This is a duplicate LOCK request */ 91717c478bd9Sstevel@tonic-gate dup_lock = TRUE; 91727c478bd9Sstevel@tonic-gate 91737c478bd9Sstevel@tonic-gate /* 91747c478bd9Sstevel@tonic-gate * For a duplicate we do not want to 91757c478bd9Sstevel@tonic-gate * create a new lockowner as it should 91767c478bd9Sstevel@tonic-gate * already exist. 91777c478bd9Sstevel@tonic-gate * Turn off the lockowner create flag. 91787c478bd9Sstevel@tonic-gate */ 91797c478bd9Sstevel@tonic-gate lcreate = FALSE; 91807c478bd9Sstevel@tonic-gate } 91817c478bd9Sstevel@tonic-gate break; 91827c478bd9Sstevel@tonic-gate } 91837c478bd9Sstevel@tonic-gate 91847c478bd9Sstevel@tonic-gate lo = rfs4_findlockowner(&olo->lock_owner, &lcreate); 91857c478bd9Sstevel@tonic-gate if (lo == NULL) { 91867c478bd9Sstevel@tonic-gate NFS4_DEBUG(rfs4_debug, 91877c478bd9Sstevel@tonic-gate (CE_NOTE, "rfs4_op_lock: no lock owner")); 91887c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_RESOURCE; 91897c478bd9Sstevel@tonic-gate goto end; 91907c478bd9Sstevel@tonic-gate } 91917c478bd9Sstevel@tonic-gate 91927c478bd9Sstevel@tonic-gate lsp = rfs4_findlo_state_by_owner(lo, sp, &create); 91937c478bd9Sstevel@tonic-gate if (lsp == NULL) { 9194d216dff5SRobert Mastors rfs4_update_lease(sp->rs_owner->ro_client); 91957c478bd9Sstevel@tonic-gate /* 91967c478bd9Sstevel@tonic-gate * Only update theh open_seqid if this is not 91977c478bd9Sstevel@tonic-gate * a duplicate request 91987c478bd9Sstevel@tonic-gate */ 91997c478bd9Sstevel@tonic-gate if (dup_lock == FALSE) { 9200d216dff5SRobert Mastors rfs4_update_open_sequence(sp->rs_owner); 92017c478bd9Sstevel@tonic-gate } 92027c478bd9Sstevel@tonic-gate 92037c478bd9Sstevel@tonic-gate NFS4_DEBUG(rfs4_debug, 92047c478bd9Sstevel@tonic-gate (CE_NOTE, "rfs4_op_lock: no state")); 92057c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_SERVERFAULT; 9206d216dff5SRobert Mastors rfs4_update_open_resp(sp->rs_owner, resop, NULL); 92077c478bd9Sstevel@tonic-gate rfs4_lockowner_rele(lo); 92087c478bd9Sstevel@tonic-gate goto end; 92097c478bd9Sstevel@tonic-gate } 92107c478bd9Sstevel@tonic-gate 92117c478bd9Sstevel@tonic-gate /* 92127c478bd9Sstevel@tonic-gate * This is the new_lock_owner branch and the client is 92137c478bd9Sstevel@tonic-gate * supposed to be associating a new lock_owner with 92147c478bd9Sstevel@tonic-gate * the open file at this point. If we find that a 92157c478bd9Sstevel@tonic-gate * lock_owner/state association already exists and a 92167c478bd9Sstevel@tonic-gate * successful LOCK request was returned to the client, 92177c478bd9Sstevel@tonic-gate * an error is returned to the client since this is 92187c478bd9Sstevel@tonic-gate * not appropriate. The client should be using the 92197c478bd9Sstevel@tonic-gate * existing lock_owner branch. 92207c478bd9Sstevel@tonic-gate */ 9221*f44e1126SVitaliy Gusev if (!rfs4_has_session(cs) && !dup_lock && !create) { 9222d216dff5SRobert Mastors if (lsp->rls_lock_completed == TRUE) { 92237c478bd9Sstevel@tonic-gate *cs->statusp = 92247c478bd9Sstevel@tonic-gate resp->status = NFS4ERR_BAD_SEQID; 92257c478bd9Sstevel@tonic-gate rfs4_lockowner_rele(lo); 92267c478bd9Sstevel@tonic-gate goto end; 92277c478bd9Sstevel@tonic-gate } 92287c478bd9Sstevel@tonic-gate } 92297c478bd9Sstevel@tonic-gate 9230d216dff5SRobert Mastors rfs4_update_lease(sp->rs_owner->ro_client); 92317c478bd9Sstevel@tonic-gate 92327c478bd9Sstevel@tonic-gate /* 92337c478bd9Sstevel@tonic-gate * Only update theh open_seqid if this is not 92347c478bd9Sstevel@tonic-gate * a duplicate request 92357c478bd9Sstevel@tonic-gate */ 92367c478bd9Sstevel@tonic-gate if (dup_lock == FALSE) { 9237d216dff5SRobert Mastors rfs4_update_open_sequence(sp->rs_owner); 92387c478bd9Sstevel@tonic-gate } 92397c478bd9Sstevel@tonic-gate 92407c478bd9Sstevel@tonic-gate /* 92417c478bd9Sstevel@tonic-gate * If this is a duplicate lock request, just copy the 92427c478bd9Sstevel@tonic-gate * previously saved reply and return. 92437c478bd9Sstevel@tonic-gate */ 92447c478bd9Sstevel@tonic-gate if (dup_lock == TRUE) { 92457c478bd9Sstevel@tonic-gate /* verify that lock_seqid's match */ 9246d216dff5SRobert Mastors if (lsp->rls_seqid != olo->lock_seqid) { 92477c478bd9Sstevel@tonic-gate NFS4_DEBUG(rfs4_debug, 92487c478bd9Sstevel@tonic-gate (CE_NOTE, "rfs4_op_lock: Dup-Lock seqid bad" 92497c478bd9Sstevel@tonic-gate "lsp->seqid=%d old->seqid=%d", 9250d216dff5SRobert Mastors lsp->rls_seqid, olo->lock_seqid)); 92517c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_BAD_SEQID; 92527c478bd9Sstevel@tonic-gate } else { 9253d216dff5SRobert Mastors rfs4_copy_reply(resop, &lsp->rls_reply); 92547c478bd9Sstevel@tonic-gate /* 92557c478bd9Sstevel@tonic-gate * Make sure to copy the just 92567c478bd9Sstevel@tonic-gate * retrieved reply status into the 92577c478bd9Sstevel@tonic-gate * overall compound status 92587c478bd9Sstevel@tonic-gate */ 92597c478bd9Sstevel@tonic-gate *cs->statusp = resp->status; 92607c478bd9Sstevel@tonic-gate } 92617c478bd9Sstevel@tonic-gate rfs4_lockowner_rele(lo); 92627c478bd9Sstevel@tonic-gate goto end; 92637c478bd9Sstevel@tonic-gate } 92647c478bd9Sstevel@tonic-gate 9265d216dff5SRobert Mastors rfs4_dbe_lock(lsp->rls_dbe); 92667c478bd9Sstevel@tonic-gate 92677c478bd9Sstevel@tonic-gate /* Make sure to update the lock sequence id */ 9268d216dff5SRobert Mastors lsp->rls_seqid = olo->lock_seqid; 92697c478bd9Sstevel@tonic-gate 92707c478bd9Sstevel@tonic-gate NFS4_DEBUG(rfs4_debug, 9271d216dff5SRobert Mastors (CE_NOTE, "Lock seqid established as %d", lsp->rls_seqid)); 92727c478bd9Sstevel@tonic-gate 92737c478bd9Sstevel@tonic-gate /* 92747c478bd9Sstevel@tonic-gate * This is used to signify the newly created lockowner 92757c478bd9Sstevel@tonic-gate * stateid and its sequence number. The checks for 92767c478bd9Sstevel@tonic-gate * sequence number and increment don't occur on the 92777c478bd9Sstevel@tonic-gate * very first lock request for a lockowner. 92787c478bd9Sstevel@tonic-gate */ 9279d216dff5SRobert Mastors lsp->rls_skip_seqid_check = TRUE; 92807c478bd9Sstevel@tonic-gate 92817c478bd9Sstevel@tonic-gate /* hold off other access to lsp while we tinker */ 9282d216dff5SRobert Mastors rfs4_sw_enter(&lsp->rls_sw); 92837c478bd9Sstevel@tonic-gate ls_sw_held = TRUE; 92847c478bd9Sstevel@tonic-gate 9285d216dff5SRobert Mastors rfs4_dbe_unlock(lsp->rls_dbe); 92867c478bd9Sstevel@tonic-gate 92877c478bd9Sstevel@tonic-gate rfs4_lockowner_rele(lo); 92887c478bd9Sstevel@tonic-gate } else { 92897c478bd9Sstevel@tonic-gate stateid = &args->locker.locker4_u.lock_owner.lock_stateid; 92907c478bd9Sstevel@tonic-gate /* get lsp and hold the lock on the underlying file struct */ 92917c478bd9Sstevel@tonic-gate if ((status = rfs4_get_lo_state(stateid, &lsp, TRUE)) 92927c478bd9Sstevel@tonic-gate != NFS4_OK) { 92937c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = status; 9294f3b585ceSsamf DTRACE_NFSV4_2(op__lock__done, struct compound_state *, 9295f3b585ceSsamf cs, LOCK4res *, resp); 92967c478bd9Sstevel@tonic-gate return; 92977c478bd9Sstevel@tonic-gate } 92987c478bd9Sstevel@tonic-gate create = FALSE; /* We didn't create lsp */ 92997c478bd9Sstevel@tonic-gate 93007c478bd9Sstevel@tonic-gate /* Ensure specified filehandle matches */ 9301d216dff5SRobert Mastors if (cs->vp != lsp->rls_state->rs_finfo->rf_vp) { 93027c478bd9Sstevel@tonic-gate rfs4_lo_state_rele(lsp, TRUE); 93037c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_BAD_STATEID; 9304f3b585ceSsamf DTRACE_NFSV4_2(op__lock__done, struct compound_state *, 9305f3b585ceSsamf cs, LOCK4res *, resp); 93067c478bd9Sstevel@tonic-gate return; 93077c478bd9Sstevel@tonic-gate } 93087c478bd9Sstevel@tonic-gate 93097c478bd9Sstevel@tonic-gate /* hold off other access to lsp while we tinker */ 9310d216dff5SRobert Mastors rfs4_sw_enter(&lsp->rls_sw); 93117c478bd9Sstevel@tonic-gate ls_sw_held = TRUE; 93127c478bd9Sstevel@tonic-gate 9313*f44e1126SVitaliy Gusev switch (rfs4_check_lo_stateid_seqid(lsp, stateid, cs)) { 93147c478bd9Sstevel@tonic-gate /* 93157c478bd9Sstevel@tonic-gate * The stateid looks like it was okay (expected to be 93167c478bd9Sstevel@tonic-gate * the next one) 93177c478bd9Sstevel@tonic-gate */ 93187c478bd9Sstevel@tonic-gate case NFS4_CHECK_STATEID_OKAY: 9319*f44e1126SVitaliy Gusev if (rfs4_has_session(cs)) 9320*f44e1126SVitaliy Gusev break; 9321*f44e1126SVitaliy Gusev 93227c478bd9Sstevel@tonic-gate /* 93237c478bd9Sstevel@tonic-gate * The sequence id is now checked. Determine 93247c478bd9Sstevel@tonic-gate * if this is a replay or if it is in the 93257c478bd9Sstevel@tonic-gate * expected (next) sequence. In the case of a 93267c478bd9Sstevel@tonic-gate * replay, there are two replay conditions 93277c478bd9Sstevel@tonic-gate * that may occur. The first is the normal 93287c478bd9Sstevel@tonic-gate * condition where a LOCK is done with a 93297c478bd9Sstevel@tonic-gate * NFS4_OK response and the stateid is 93307c478bd9Sstevel@tonic-gate * updated. That case is handled below when 93317c478bd9Sstevel@tonic-gate * the stateid is identified as a REPLAY. The 93327c478bd9Sstevel@tonic-gate * second is the case where an error is 93337c478bd9Sstevel@tonic-gate * returned, like NFS4ERR_DENIED, and the 93347c478bd9Sstevel@tonic-gate * sequence number is updated but the stateid 93357c478bd9Sstevel@tonic-gate * is not updated. This second case is dealt 93367c478bd9Sstevel@tonic-gate * with here. So it may seem odd that the 93377c478bd9Sstevel@tonic-gate * stateid is okay but the sequence id is a 93387c478bd9Sstevel@tonic-gate * replay but it is okay. 93397c478bd9Sstevel@tonic-gate */ 93407c478bd9Sstevel@tonic-gate switch (rfs4_check_lock_seqid( 93417c478bd9Sstevel@tonic-gate args->locker.locker4_u.lock_owner.lock_seqid, 93427c478bd9Sstevel@tonic-gate lsp, resop)) { 93437c478bd9Sstevel@tonic-gate case NFS4_CHKSEQ_REPLAY: 93447c478bd9Sstevel@tonic-gate if (resp->status != NFS4_OK) { 93457c478bd9Sstevel@tonic-gate /* 93467c478bd9Sstevel@tonic-gate * Here is our replay and need 93477c478bd9Sstevel@tonic-gate * to verify that the last 93487c478bd9Sstevel@tonic-gate * response was an error. 93497c478bd9Sstevel@tonic-gate */ 93507c478bd9Sstevel@tonic-gate *cs->statusp = resp->status; 93517c478bd9Sstevel@tonic-gate goto end; 93527c478bd9Sstevel@tonic-gate } 93537c478bd9Sstevel@tonic-gate /* 93547c478bd9Sstevel@tonic-gate * This is done since the sequence id 93557c478bd9Sstevel@tonic-gate * looked like a replay but it didn't 93567c478bd9Sstevel@tonic-gate * pass our check so a BAD_SEQID is 93577c478bd9Sstevel@tonic-gate * returned as a result. 93587c478bd9Sstevel@tonic-gate */ 93597c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/ 93607c478bd9Sstevel@tonic-gate case NFS4_CHKSEQ_BAD: 93611b300de9Sjwahlig *cs->statusp = resp->status = NFS4ERR_BAD_SEQID; 93627c478bd9Sstevel@tonic-gate goto end; 93637c478bd9Sstevel@tonic-gate case NFS4_CHKSEQ_OKAY: 93647c478bd9Sstevel@tonic-gate /* Everything looks okay move ahead */ 93657c478bd9Sstevel@tonic-gate break; 93667c478bd9Sstevel@tonic-gate } 93677c478bd9Sstevel@tonic-gate break; 93687c478bd9Sstevel@tonic-gate case NFS4_CHECK_STATEID_OLD: 93697c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_OLD_STATEID; 93707c478bd9Sstevel@tonic-gate goto end; 93717c478bd9Sstevel@tonic-gate case NFS4_CHECK_STATEID_BAD: 93727c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_BAD_STATEID; 93737c478bd9Sstevel@tonic-gate goto end; 93747c478bd9Sstevel@tonic-gate case NFS4_CHECK_STATEID_EXPIRED: 93757c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_EXPIRED; 93767c478bd9Sstevel@tonic-gate goto end; 93777c478bd9Sstevel@tonic-gate case NFS4_CHECK_STATEID_CLOSED: 93787c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_OLD_STATEID; 93797c478bd9Sstevel@tonic-gate goto end; 93807c478bd9Sstevel@tonic-gate case NFS4_CHECK_STATEID_REPLAY: 9381*f44e1126SVitaliy Gusev ASSERT(!rfs4_has_session(cs)); 9382*f44e1126SVitaliy Gusev 93837c478bd9Sstevel@tonic-gate switch (rfs4_check_lock_seqid( 93847c478bd9Sstevel@tonic-gate args->locker.locker4_u.lock_owner.lock_seqid, 93857c478bd9Sstevel@tonic-gate lsp, resop)) { 93867c478bd9Sstevel@tonic-gate case NFS4_CHKSEQ_OKAY: 93877c478bd9Sstevel@tonic-gate /* 93887c478bd9Sstevel@tonic-gate * This is a replayed stateid; if 93897c478bd9Sstevel@tonic-gate * seqid matches the next expected, 93907c478bd9Sstevel@tonic-gate * then client is using wrong seqid. 93917c478bd9Sstevel@tonic-gate */ 93927c478bd9Sstevel@tonic-gate case NFS4_CHKSEQ_BAD: 93931b300de9Sjwahlig *cs->statusp = resp->status = NFS4ERR_BAD_SEQID; 93947c478bd9Sstevel@tonic-gate goto end; 93957c478bd9Sstevel@tonic-gate case NFS4_CHKSEQ_REPLAY: 9396d216dff5SRobert Mastors rfs4_update_lease(lsp->rls_locker->rl_client); 93977c478bd9Sstevel@tonic-gate *cs->statusp = status = resp->status; 93987c478bd9Sstevel@tonic-gate goto end; 93997c478bd9Sstevel@tonic-gate } 94007c478bd9Sstevel@tonic-gate break; 94017c478bd9Sstevel@tonic-gate default: 94027c478bd9Sstevel@tonic-gate ASSERT(FALSE); 94037c478bd9Sstevel@tonic-gate break; 94047c478bd9Sstevel@tonic-gate } 94057c478bd9Sstevel@tonic-gate 94067c478bd9Sstevel@tonic-gate rfs4_update_lock_sequence(lsp); 9407d216dff5SRobert Mastors rfs4_update_lease(lsp->rls_locker->rl_client); 94087c478bd9Sstevel@tonic-gate } 94097c478bd9Sstevel@tonic-gate 94107c478bd9Sstevel@tonic-gate /* 94117c478bd9Sstevel@tonic-gate * NFS4 only allows locking on regular files, so 94127c478bd9Sstevel@tonic-gate * verify type of object. 94137c478bd9Sstevel@tonic-gate */ 94147c478bd9Sstevel@tonic-gate if (cs->vp->v_type != VREG) { 94157c478bd9Sstevel@tonic-gate if (cs->vp->v_type == VDIR) 94167c478bd9Sstevel@tonic-gate status = NFS4ERR_ISDIR; 94177c478bd9Sstevel@tonic-gate else 94187c478bd9Sstevel@tonic-gate status = NFS4ERR_INVAL; 94197c478bd9Sstevel@tonic-gate goto out; 94207c478bd9Sstevel@tonic-gate } 94217c478bd9Sstevel@tonic-gate 9422d216dff5SRobert Mastors cp = lsp->rls_state->rs_owner->ro_client; 94237c478bd9Sstevel@tonic-gate 94247c478bd9Sstevel@tonic-gate if (rfs4_clnt_in_grace(cp) && !args->reclaim) { 94257c478bd9Sstevel@tonic-gate status = NFS4ERR_GRACE; 94267c478bd9Sstevel@tonic-gate goto out; 94277c478bd9Sstevel@tonic-gate } 94287c478bd9Sstevel@tonic-gate 9429d216dff5SRobert Mastors if (rfs4_clnt_in_grace(cp) && args->reclaim && !cp->rc_can_reclaim) { 94307c478bd9Sstevel@tonic-gate status = NFS4ERR_NO_GRACE; 94317c478bd9Sstevel@tonic-gate goto out; 94327c478bd9Sstevel@tonic-gate } 94337c478bd9Sstevel@tonic-gate 94347c478bd9Sstevel@tonic-gate if (!rfs4_clnt_in_grace(cp) && args->reclaim) { 94357c478bd9Sstevel@tonic-gate status = NFS4ERR_NO_GRACE; 94367c478bd9Sstevel@tonic-gate goto out; 94377c478bd9Sstevel@tonic-gate } 94387c478bd9Sstevel@tonic-gate 9439d216dff5SRobert Mastors if (lsp->rls_state->rs_finfo->rf_dinfo.rd_dtype == OPEN_DELEGATE_WRITE) 94407c478bd9Sstevel@tonic-gate cs->deleg = TRUE; 94417c478bd9Sstevel@tonic-gate 94427c478bd9Sstevel@tonic-gate status = rfs4_do_lock(lsp, args->locktype, 94431b300de9Sjwahlig args->offset, args->length, cs->cr, resop); 94447c478bd9Sstevel@tonic-gate 94457c478bd9Sstevel@tonic-gate out: 9446d216dff5SRobert Mastors lsp->rls_skip_seqid_check = FALSE; 94477c478bd9Sstevel@tonic-gate 94487c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = status; 94497c478bd9Sstevel@tonic-gate 94507c478bd9Sstevel@tonic-gate if (status == NFS4_OK) { 9451d216dff5SRobert Mastors resp->LOCK4res_u.lock_stateid = lsp->rls_lockid.stateid; 9452d216dff5SRobert Mastors lsp->rls_lock_completed = TRUE; 94537c478bd9Sstevel@tonic-gate } 94547c478bd9Sstevel@tonic-gate /* 94557c478bd9Sstevel@tonic-gate * Only update the "OPEN" response here if this was a new 94567c478bd9Sstevel@tonic-gate * lock_owner 94577c478bd9Sstevel@tonic-gate */ 94587c478bd9Sstevel@tonic-gate if (sp) 9459d216dff5SRobert Mastors rfs4_update_open_resp(sp->rs_owner, resop, NULL); 94607c478bd9Sstevel@tonic-gate 94617c478bd9Sstevel@tonic-gate rfs4_update_lock_resp(lsp, resop); 94627c478bd9Sstevel@tonic-gate 94637c478bd9Sstevel@tonic-gate end: 94647c478bd9Sstevel@tonic-gate if (lsp) { 94657c478bd9Sstevel@tonic-gate if (ls_sw_held) 9466d216dff5SRobert Mastors rfs4_sw_exit(&lsp->rls_sw); 94677c478bd9Sstevel@tonic-gate /* 94687c478bd9Sstevel@tonic-gate * If an sp obtained, then the lsp does not represent 94697c478bd9Sstevel@tonic-gate * a lock on the file struct. 94707c478bd9Sstevel@tonic-gate */ 94717c478bd9Sstevel@tonic-gate if (sp != NULL) 94727c478bd9Sstevel@tonic-gate rfs4_lo_state_rele(lsp, FALSE); 94737c478bd9Sstevel@tonic-gate else 94747c478bd9Sstevel@tonic-gate rfs4_lo_state_rele(lsp, TRUE); 94757c478bd9Sstevel@tonic-gate } 94767c478bd9Sstevel@tonic-gate if (sp) { 9477d216dff5SRobert Mastors rfs4_sw_exit(&sp->rs_owner->ro_sw); 94787c478bd9Sstevel@tonic-gate rfs4_state_rele(sp); 94797c478bd9Sstevel@tonic-gate } 9480f3b585ceSsamf 9481f3b585ceSsamf DTRACE_NFSV4_2(op__lock__done, struct compound_state *, cs, 9482f3b585ceSsamf LOCK4res *, resp); 94837c478bd9Sstevel@tonic-gate } 94847c478bd9Sstevel@tonic-gate 94857c478bd9Sstevel@tonic-gate /* free function for LOCK/LOCKT */ 94867c478bd9Sstevel@tonic-gate static void 94877c478bd9Sstevel@tonic-gate lock_denied_free(nfs_resop4 *resop) 94887c478bd9Sstevel@tonic-gate { 94897c478bd9Sstevel@tonic-gate LOCK4denied *dp = NULL; 94907c478bd9Sstevel@tonic-gate 94917c478bd9Sstevel@tonic-gate switch (resop->resop) { 94927c478bd9Sstevel@tonic-gate case OP_LOCK: 94937c478bd9Sstevel@tonic-gate if (resop->nfs_resop4_u.oplock.status == NFS4ERR_DENIED) 94947c478bd9Sstevel@tonic-gate dp = &resop->nfs_resop4_u.oplock.LOCK4res_u.denied; 94957c478bd9Sstevel@tonic-gate break; 94967c478bd9Sstevel@tonic-gate case OP_LOCKT: 94977c478bd9Sstevel@tonic-gate if (resop->nfs_resop4_u.oplockt.status == NFS4ERR_DENIED) 94987c478bd9Sstevel@tonic-gate dp = &resop->nfs_resop4_u.oplockt.denied; 94997c478bd9Sstevel@tonic-gate break; 95007c478bd9Sstevel@tonic-gate default: 95017c478bd9Sstevel@tonic-gate break; 95027c478bd9Sstevel@tonic-gate } 95037c478bd9Sstevel@tonic-gate 95047c478bd9Sstevel@tonic-gate if (dp) 95057c478bd9Sstevel@tonic-gate kmem_free(dp->owner.owner_val, dp->owner.owner_len); 95067c478bd9Sstevel@tonic-gate } 95077c478bd9Sstevel@tonic-gate 95087c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 95097c478bd9Sstevel@tonic-gate void 95107c478bd9Sstevel@tonic-gate rfs4_op_locku(nfs_argop4 *argop, nfs_resop4 *resop, 95117c478bd9Sstevel@tonic-gate struct svc_req *req, struct compound_state *cs) 95127c478bd9Sstevel@tonic-gate { 95137c478bd9Sstevel@tonic-gate LOCKU4args *args = &argop->nfs_argop4_u.oplocku; 95147c478bd9Sstevel@tonic-gate LOCKU4res *resp = &resop->nfs_resop4_u.oplocku; 95157c478bd9Sstevel@tonic-gate nfsstat4 status; 95167c478bd9Sstevel@tonic-gate stateid4 *stateid = &args->lock_stateid; 95177c478bd9Sstevel@tonic-gate rfs4_lo_state_t *lsp; 95187c478bd9Sstevel@tonic-gate 9519f3b585ceSsamf DTRACE_NFSV4_2(op__locku__start, struct compound_state *, cs, 9520f3b585ceSsamf LOCKU4args *, args); 9521f3b585ceSsamf 95227c478bd9Sstevel@tonic-gate if (cs->vp == NULL) { 95237c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE; 9524f3b585ceSsamf DTRACE_NFSV4_2(op__locku__done, struct compound_state *, cs, 9525f3b585ceSsamf LOCKU4res *, resp); 95267c478bd9Sstevel@tonic-gate return; 95277c478bd9Sstevel@tonic-gate } 95287c478bd9Sstevel@tonic-gate 95297c478bd9Sstevel@tonic-gate if ((status = rfs4_get_lo_state(stateid, &lsp, TRUE)) != NFS4_OK) { 95307c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = status; 9531f3b585ceSsamf DTRACE_NFSV4_2(op__locku__done, struct compound_state *, cs, 9532f3b585ceSsamf LOCKU4res *, resp); 95337c478bd9Sstevel@tonic-gate return; 95347c478bd9Sstevel@tonic-gate } 95357c478bd9Sstevel@tonic-gate 95367c478bd9Sstevel@tonic-gate /* Ensure specified filehandle matches */ 9537d216dff5SRobert Mastors if (cs->vp != lsp->rls_state->rs_finfo->rf_vp) { 95387c478bd9Sstevel@tonic-gate rfs4_lo_state_rele(lsp, TRUE); 95397c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_BAD_STATEID; 9540f3b585ceSsamf DTRACE_NFSV4_2(op__locku__done, struct compound_state *, cs, 9541f3b585ceSsamf LOCKU4res *, resp); 95427c478bd9Sstevel@tonic-gate return; 95437c478bd9Sstevel@tonic-gate } 95447c478bd9Sstevel@tonic-gate 95457c478bd9Sstevel@tonic-gate /* hold off other access to lsp while we tinker */ 9546d216dff5SRobert Mastors rfs4_sw_enter(&lsp->rls_sw); 95477c478bd9Sstevel@tonic-gate 9548*f44e1126SVitaliy Gusev switch (rfs4_check_lo_stateid_seqid(lsp, stateid, cs)) { 95497c478bd9Sstevel@tonic-gate case NFS4_CHECK_STATEID_OKAY: 9550*f44e1126SVitaliy Gusev if (rfs4_has_session(cs)) 9551*f44e1126SVitaliy Gusev break; 9552*f44e1126SVitaliy Gusev 95537c478bd9Sstevel@tonic-gate if (rfs4_check_lock_seqid(args->seqid, lsp, resop) 95547c478bd9Sstevel@tonic-gate != NFS4_CHKSEQ_OKAY) { 95557c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_BAD_SEQID; 95567c478bd9Sstevel@tonic-gate goto end; 95577c478bd9Sstevel@tonic-gate } 95587c478bd9Sstevel@tonic-gate break; 95597c478bd9Sstevel@tonic-gate case NFS4_CHECK_STATEID_OLD: 95607c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_OLD_STATEID; 95617c478bd9Sstevel@tonic-gate goto end; 95627c478bd9Sstevel@tonic-gate case NFS4_CHECK_STATEID_BAD: 95637c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_BAD_STATEID; 95647c478bd9Sstevel@tonic-gate goto end; 95657c478bd9Sstevel@tonic-gate case NFS4_CHECK_STATEID_EXPIRED: 95667c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_EXPIRED; 95677c478bd9Sstevel@tonic-gate goto end; 95687c478bd9Sstevel@tonic-gate case NFS4_CHECK_STATEID_CLOSED: 95697c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_OLD_STATEID; 95707c478bd9Sstevel@tonic-gate goto end; 95717c478bd9Sstevel@tonic-gate case NFS4_CHECK_STATEID_REPLAY: 9572*f44e1126SVitaliy Gusev ASSERT(!rfs4_has_session(cs)); 9573*f44e1126SVitaliy Gusev 95747c478bd9Sstevel@tonic-gate switch (rfs4_check_lock_seqid(args->seqid, lsp, resop)) { 95757c478bd9Sstevel@tonic-gate case NFS4_CHKSEQ_OKAY: 95767c478bd9Sstevel@tonic-gate /* 95777c478bd9Sstevel@tonic-gate * This is a replayed stateid; if 95787c478bd9Sstevel@tonic-gate * seqid matches the next expected, 95797c478bd9Sstevel@tonic-gate * then client is using wrong seqid. 95807c478bd9Sstevel@tonic-gate */ 95817c478bd9Sstevel@tonic-gate case NFS4_CHKSEQ_BAD: 95821b300de9Sjwahlig *cs->statusp = resp->status = NFS4ERR_BAD_SEQID; 95837c478bd9Sstevel@tonic-gate goto end; 95847c478bd9Sstevel@tonic-gate case NFS4_CHKSEQ_REPLAY: 9585d216dff5SRobert Mastors rfs4_update_lease(lsp->rls_locker->rl_client); 95867c478bd9Sstevel@tonic-gate *cs->statusp = status = resp->status; 95877c478bd9Sstevel@tonic-gate goto end; 95887c478bd9Sstevel@tonic-gate } 95897c478bd9Sstevel@tonic-gate break; 95907c478bd9Sstevel@tonic-gate default: 95917c478bd9Sstevel@tonic-gate ASSERT(FALSE); 95927c478bd9Sstevel@tonic-gate break; 95937c478bd9Sstevel@tonic-gate } 95947c478bd9Sstevel@tonic-gate 95957c478bd9Sstevel@tonic-gate rfs4_update_lock_sequence(lsp); 9596d216dff5SRobert Mastors rfs4_update_lease(lsp->rls_locker->rl_client); 95977c478bd9Sstevel@tonic-gate 95987c478bd9Sstevel@tonic-gate /* 95997c478bd9Sstevel@tonic-gate * NFS4 only allows locking on regular files, so 96007c478bd9Sstevel@tonic-gate * verify type of object. 96017c478bd9Sstevel@tonic-gate */ 96027c478bd9Sstevel@tonic-gate if (cs->vp->v_type != VREG) { 96037c478bd9Sstevel@tonic-gate if (cs->vp->v_type == VDIR) 96047c478bd9Sstevel@tonic-gate status = NFS4ERR_ISDIR; 96057c478bd9Sstevel@tonic-gate else 96067c478bd9Sstevel@tonic-gate status = NFS4ERR_INVAL; 96077c478bd9Sstevel@tonic-gate goto out; 96087c478bd9Sstevel@tonic-gate } 96097c478bd9Sstevel@tonic-gate 9610d216dff5SRobert Mastors if (rfs4_clnt_in_grace(lsp->rls_state->rs_owner->ro_client)) { 96117c478bd9Sstevel@tonic-gate status = NFS4ERR_GRACE; 96127c478bd9Sstevel@tonic-gate goto out; 96137c478bd9Sstevel@tonic-gate } 96147c478bd9Sstevel@tonic-gate 96157c478bd9Sstevel@tonic-gate status = rfs4_do_lock(lsp, args->locktype, 9616d216dff5SRobert Mastors args->offset, args->length, cs->cr, resop); 96177c478bd9Sstevel@tonic-gate 96187c478bd9Sstevel@tonic-gate out: 96197c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = status; 96207c478bd9Sstevel@tonic-gate 96217c478bd9Sstevel@tonic-gate if (status == NFS4_OK) 9622d216dff5SRobert Mastors resp->lock_stateid = lsp->rls_lockid.stateid; 96237c478bd9Sstevel@tonic-gate 96247c478bd9Sstevel@tonic-gate rfs4_update_lock_resp(lsp, resop); 96257c478bd9Sstevel@tonic-gate 96267c478bd9Sstevel@tonic-gate end: 9627d216dff5SRobert Mastors rfs4_sw_exit(&lsp->rls_sw); 96287c478bd9Sstevel@tonic-gate rfs4_lo_state_rele(lsp, TRUE); 9629f3b585ceSsamf 9630f3b585ceSsamf DTRACE_NFSV4_2(op__locku__done, struct compound_state *, cs, 9631f3b585ceSsamf LOCKU4res *, resp); 96327c478bd9Sstevel@tonic-gate } 96337c478bd9Sstevel@tonic-gate 96347c478bd9Sstevel@tonic-gate /* 96357c478bd9Sstevel@tonic-gate * LOCKT is a best effort routine, the client can not be guaranteed that 96367c478bd9Sstevel@tonic-gate * the status return is still in effect by the time the reply is received. 96377c478bd9Sstevel@tonic-gate * They are numerous race conditions in this routine, but we are not required 96387c478bd9Sstevel@tonic-gate * and can not be accurate. 96397c478bd9Sstevel@tonic-gate */ 96407c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 96417c478bd9Sstevel@tonic-gate void 96427c478bd9Sstevel@tonic-gate rfs4_op_lockt(nfs_argop4 *argop, nfs_resop4 *resop, 96437c478bd9Sstevel@tonic-gate struct svc_req *req, struct compound_state *cs) 96447c478bd9Sstevel@tonic-gate { 96457c478bd9Sstevel@tonic-gate LOCKT4args *args = &argop->nfs_argop4_u.oplockt; 96467c478bd9Sstevel@tonic-gate LOCKT4res *resp = &resop->nfs_resop4_u.oplockt; 96477c478bd9Sstevel@tonic-gate rfs4_lockowner_t *lo; 96487c478bd9Sstevel@tonic-gate rfs4_client_t *cp; 96497c478bd9Sstevel@tonic-gate bool_t create = FALSE; 96507c478bd9Sstevel@tonic-gate struct flock64 flk; 96517c478bd9Sstevel@tonic-gate int error; 96527c478bd9Sstevel@tonic-gate int flag = FREAD | FWRITE; 96537c478bd9Sstevel@tonic-gate int ltype; 96547c478bd9Sstevel@tonic-gate length4 posix_length; 96557c478bd9Sstevel@tonic-gate sysid_t sysid; 96567c478bd9Sstevel@tonic-gate pid_t pid; 96577c478bd9Sstevel@tonic-gate 9658f3b585ceSsamf DTRACE_NFSV4_2(op__lockt__start, struct compound_state *, cs, 9659f3b585ceSsamf LOCKT4args *, args); 9660f3b585ceSsamf 96617c478bd9Sstevel@tonic-gate if (cs->vp == NULL) { 96627c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE; 9663f3b585ceSsamf goto out; 96647c478bd9Sstevel@tonic-gate } 96657c478bd9Sstevel@tonic-gate 96667c478bd9Sstevel@tonic-gate /* 96677c478bd9Sstevel@tonic-gate * NFS4 only allows locking on regular files, so 96687c478bd9Sstevel@tonic-gate * verify type of object. 96697c478bd9Sstevel@tonic-gate */ 96707c478bd9Sstevel@tonic-gate if (cs->vp->v_type != VREG) { 96717c478bd9Sstevel@tonic-gate if (cs->vp->v_type == VDIR) 96727c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_ISDIR; 96737c478bd9Sstevel@tonic-gate else 96747c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_INVAL; 9675f3b585ceSsamf goto out; 96767c478bd9Sstevel@tonic-gate } 96777c478bd9Sstevel@tonic-gate 96787c478bd9Sstevel@tonic-gate /* 96797c478bd9Sstevel@tonic-gate * Check out the clientid to ensure the server knows about it 96807c478bd9Sstevel@tonic-gate * so that we correctly inform the client of a server reboot. 96817c478bd9Sstevel@tonic-gate */ 96827c478bd9Sstevel@tonic-gate if ((cp = rfs4_findclient_by_id(args->owner.clientid, FALSE)) 96837c478bd9Sstevel@tonic-gate == NULL) { 96847c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = 96857c478bd9Sstevel@tonic-gate rfs4_check_clientid(&args->owner.clientid, 0); 9686f3b585ceSsamf goto out; 96877c478bd9Sstevel@tonic-gate } 96887c478bd9Sstevel@tonic-gate if (rfs4_lease_expired(cp)) { 96897c478bd9Sstevel@tonic-gate rfs4_client_close(cp); 96907c478bd9Sstevel@tonic-gate /* 96917c478bd9Sstevel@tonic-gate * Protocol doesn't allow returning NFS4ERR_STALE as 96927c478bd9Sstevel@tonic-gate * other operations do on this check so STALE_CLIENTID 96937c478bd9Sstevel@tonic-gate * is returned instead 96947c478bd9Sstevel@tonic-gate */ 96957c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_STALE_CLIENTID; 9696f3b585ceSsamf goto out; 96977c478bd9Sstevel@tonic-gate } 96987c478bd9Sstevel@tonic-gate 9699d216dff5SRobert Mastors if (rfs4_clnt_in_grace(cp) && !(cp->rc_can_reclaim)) { 97007c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_GRACE; 9701661cedadSvv149972 rfs4_client_rele(cp); 9702f3b585ceSsamf goto out; 97037c478bd9Sstevel@tonic-gate } 97047c478bd9Sstevel@tonic-gate rfs4_client_rele(cp); 97057c478bd9Sstevel@tonic-gate 97067c478bd9Sstevel@tonic-gate resp->status = NFS4_OK; 97077c478bd9Sstevel@tonic-gate 97087c478bd9Sstevel@tonic-gate switch (args->locktype) { 97097c478bd9Sstevel@tonic-gate case READ_LT: 97107c478bd9Sstevel@tonic-gate case READW_LT: 97117c478bd9Sstevel@tonic-gate ltype = F_RDLCK; 97127c478bd9Sstevel@tonic-gate break; 97137c478bd9Sstevel@tonic-gate case WRITE_LT: 97147c478bd9Sstevel@tonic-gate case WRITEW_LT: 97157c478bd9Sstevel@tonic-gate ltype = F_WRLCK; 97167c478bd9Sstevel@tonic-gate break; 97177c478bd9Sstevel@tonic-gate } 97187c478bd9Sstevel@tonic-gate 97197c478bd9Sstevel@tonic-gate posix_length = args->length; 97207c478bd9Sstevel@tonic-gate /* Check for zero length. To lock to end of file use all ones for V4 */ 97217c478bd9Sstevel@tonic-gate if (posix_length == 0) { 97227c478bd9Sstevel@tonic-gate *cs->statusp = resp->status = NFS4ERR_INVAL; 9723f3b585ceSsamf goto out; 97247c478bd9Sstevel@tonic-gate } else if (posix_length == (length4)(~0)) { 97257c478bd9Sstevel@tonic-gate posix_length = 0; /* Posix to end of file */ 97267c478bd9Sstevel@tonic-gate } 97277c478bd9Sstevel@tonic-gate 97287c478bd9Sstevel@tonic-gate /* Find or create a lockowner */ 97297c478bd9Sstevel@tonic-gate lo = rfs4_findlockowner(&args->owner, &create); 97307c478bd9Sstevel@tonic-gate 97317c478bd9Sstevel@tonic-gate if (lo) { 9732d216dff5SRobert Mastors pid = lo->rl_pid; 97337c478bd9Sstevel@tonic-gate if ((resp->status = 9734d216dff5SRobert Mastors rfs4_client_sysid(lo->rl_client, &sysid)) != NFS4_OK) 9735f3b585ceSsamf goto err; 97367c478bd9Sstevel@tonic-gate } else { 97377c478bd9Sstevel@tonic-gate pid = 0; 97387c478bd9Sstevel@tonic-gate sysid = lockt_sysid; 97397c478bd9Sstevel@tonic-gate } 97407c478bd9Sstevel@tonic-gate retry: 97417c478bd9Sstevel@tonic-gate flk.l_type = ltype; 97427c478bd9Sstevel@tonic-gate flk.l_whence = 0; /* SEEK_SET */ 97437c478bd9Sstevel@tonic-gate flk.l_start = args->offset; 97447c478bd9Sstevel@tonic-gate flk.l_len = posix_length; 97457c478bd9Sstevel@tonic-gate flk.l_sysid = sysid; 97467c478bd9Sstevel@tonic-gate flk.l_pid = pid; 97477c478bd9Sstevel@tonic-gate flag |= F_REMOTELOCK; 97487c478bd9Sstevel@tonic-gate 97497c478bd9Sstevel@tonic-gate LOCK_PRINT(rfs4_debug, "rfs4_op_lockt", F_GETLK, &flk); 97507c478bd9Sstevel@tonic-gate 97517c478bd9Sstevel@tonic-gate /* Note that length4 is uint64_t but l_len and l_start are off64_t */ 97527c478bd9Sstevel@tonic-gate if (flk.l_len < 0 || flk.l_start < 0) { 97537c478bd9Sstevel@tonic-gate resp->status = NFS4ERR_INVAL; 9754f3b585ceSsamf goto err; 97557c478bd9Sstevel@tonic-gate } 97567c478bd9Sstevel@tonic-gate error = VOP_FRLOCK(cs->vp, F_GETLK, &flk, flag, (u_offset_t)0, 9757da6c28aaSamw NULL, cs->cr, NULL); 97587c478bd9Sstevel@tonic-gate 97597c478bd9Sstevel@tonic-gate /* 97607c478bd9Sstevel@tonic-gate * N.B. We map error values to nfsv4 errors. This is differrent 97617c478bd9Sstevel@tonic-gate * than puterrno4 routine. 97627c478bd9Sstevel@tonic-gate */ 97637c478bd9Sstevel@tonic-gate switch (error) { 97647c478bd9Sstevel@tonic-gate case 0: 97657c478bd9Sstevel@tonic-gate if (flk.l_type == F_UNLCK) 97667c478bd9Sstevel@tonic-gate resp->status = NFS4_OK; 97677c478bd9Sstevel@tonic-gate else { 97687c478bd9Sstevel@tonic-gate if (lock_denied(&resp->denied, &flk) == NFS4ERR_EXPIRED) 97697c478bd9Sstevel@tonic-gate goto retry; 97707c478bd9Sstevel@tonic-gate resp->status = NFS4ERR_DENIED; 97717c478bd9Sstevel@tonic-gate } 97727c478bd9Sstevel@tonic-gate break; 97737c478bd9Sstevel@tonic-gate case EOVERFLOW: 97747c478bd9Sstevel@tonic-gate resp->status = NFS4ERR_INVAL; 97757c478bd9Sstevel@tonic-gate break; 97767c478bd9Sstevel@tonic-gate case EINVAL: 97777c478bd9Sstevel@tonic-gate resp->status = NFS4ERR_NOTSUPP; 97787c478bd9Sstevel@tonic-gate break; 97797c478bd9Sstevel@tonic-gate default: 97807c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "rfs4_op_lockt: unexpected errno (%d)", 97817c478bd9Sstevel@tonic-gate error); 97827c478bd9Sstevel@tonic-gate resp->status = NFS4ERR_SERVERFAULT; 97837c478bd9Sstevel@tonic-gate break; 97847c478bd9Sstevel@tonic-gate } 97857c478bd9Sstevel@tonic-gate 9786f3b585ceSsamf err: 97877c478bd9Sstevel@tonic-gate if (lo) 97887c478bd9Sstevel@tonic-gate rfs4_lockowner_rele(lo); 97897c478bd9Sstevel@tonic-gate *cs->statusp = resp->status; 9790f3b585ceSsamf out: 9791f3b585ceSsamf DTRACE_NFSV4_2(op__lockt__done, struct compound_state *, cs, 9792f3b585ceSsamf LOCKT4res *, resp); 97937c478bd9Sstevel@tonic-gate } 97947c478bd9Sstevel@tonic-gate 9795d216dff5SRobert Mastors int 9796d216dff5SRobert Mastors rfs4_share(rfs4_state_t *sp, uint32_t access, uint32_t deny) 97977c478bd9Sstevel@tonic-gate { 97987c478bd9Sstevel@tonic-gate int err; 9799d216dff5SRobert Mastors int cmd; 9800d216dff5SRobert Mastors vnode_t *vp; 98017c478bd9Sstevel@tonic-gate struct shrlock shr; 98027c478bd9Sstevel@tonic-gate struct shr_locowner shr_loco; 9803d216dff5SRobert Mastors int fflags = 0; 98047c478bd9Sstevel@tonic-gate 9805d216dff5SRobert Mastors ASSERT(rfs4_dbe_islocked(sp->rs_dbe)); 9806d216dff5SRobert Mastors ASSERT(sp->rs_owner->ro_client->rc_sysidt != LM_NOSYSID); 98077c478bd9Sstevel@tonic-gate 9808d216dff5SRobert Mastors if (sp->rs_closed) 9809d216dff5SRobert Mastors return (NFS4ERR_OLD_STATEID); 9810d216dff5SRobert Mastors 9811d216dff5SRobert Mastors vp = sp->rs_finfo->rf_vp; 9812d216dff5SRobert Mastors ASSERT(vp); 9813d216dff5SRobert Mastors 9814d216dff5SRobert Mastors shr.s_access = shr.s_deny = 0; 9815d216dff5SRobert Mastors 9816d216dff5SRobert Mastors if (access & OPEN4_SHARE_ACCESS_READ) { 98177c478bd9Sstevel@tonic-gate fflags |= FREAD; 98187c478bd9Sstevel@tonic-gate shr.s_access |= F_RDACC; 98197c478bd9Sstevel@tonic-gate } 9820d216dff5SRobert Mastors if (access & OPEN4_SHARE_ACCESS_WRITE) { 98217c478bd9Sstevel@tonic-gate fflags |= FWRITE; 98227c478bd9Sstevel@tonic-gate shr.s_access |= F_WRACC; 98237c478bd9Sstevel@tonic-gate } 9824d216dff5SRobert Mastors ASSERT(shr.s_access); 9825d216dff5SRobert Mastors 9826d216dff5SRobert Mastors if (deny & OPEN4_SHARE_DENY_READ) 98277c478bd9Sstevel@tonic-gate shr.s_deny |= F_RDDNY; 9828d216dff5SRobert Mastors if (deny & OPEN4_SHARE_DENY_WRITE) 98297c478bd9Sstevel@tonic-gate shr.s_deny |= F_WRDNY; 98307c478bd9Sstevel@tonic-gate 9831d216dff5SRobert Mastors shr.s_pid = rfs4_dbe_getid(sp->rs_owner->ro_dbe); 9832d216dff5SRobert Mastors shr.s_sysid = sp->rs_owner->ro_client->rc_sysidt; 98337c478bd9Sstevel@tonic-gate shr_loco.sl_pid = shr.s_pid; 98347c478bd9Sstevel@tonic-gate shr_loco.sl_id = shr.s_sysid; 98357c478bd9Sstevel@tonic-gate shr.s_owner = (caddr_t)&shr_loco; 98367c478bd9Sstevel@tonic-gate shr.s_own_len = sizeof (shr_loco); 9837d216dff5SRobert Mastors 9838d216dff5SRobert Mastors cmd = nbl_need_check(vp) ? F_SHARE_NBMAND : F_SHARE; 9839d216dff5SRobert Mastors 9840d216dff5SRobert Mastors err = VOP_SHRLOCK(vp, cmd, &shr, fflags, CRED(), NULL); 9841d216dff5SRobert Mastors if (err != 0) { 9842d216dff5SRobert Mastors if (err == EAGAIN) 9843d216dff5SRobert Mastors err = NFS4ERR_SHARE_DENIED; 9844d216dff5SRobert Mastors else 9845d216dff5SRobert Mastors err = puterrno4(err); 9846d216dff5SRobert Mastors return (err); 98477c478bd9Sstevel@tonic-gate } 98487c478bd9Sstevel@tonic-gate 9849d216dff5SRobert Mastors sp->rs_share_access |= access; 9850d216dff5SRobert Mastors sp->rs_share_deny |= deny; 9851d216dff5SRobert Mastors 9852d216dff5SRobert Mastors return (0); 98537c478bd9Sstevel@tonic-gate } 98547c478bd9Sstevel@tonic-gate 9855d216dff5SRobert Mastors int 98567c478bd9Sstevel@tonic-gate rfs4_unshare(rfs4_state_t *sp) 98577c478bd9Sstevel@tonic-gate { 9858d216dff5SRobert Mastors int err; 9859d216dff5SRobert Mastors struct shrlock shr; 9860d216dff5SRobert Mastors struct shr_locowner shr_loco; 9861d216dff5SRobert Mastors 9862d216dff5SRobert Mastors ASSERT(rfs4_dbe_islocked(sp->rs_dbe)); 9863d216dff5SRobert Mastors 9864d216dff5SRobert Mastors if (sp->rs_closed || sp->rs_share_access == 0) 9865d216dff5SRobert Mastors return (0); 9866d216dff5SRobert Mastors 9867d216dff5SRobert Mastors ASSERT(sp->rs_owner->ro_client->rc_sysidt != LM_NOSYSID); 9868d216dff5SRobert Mastors ASSERT(sp->rs_finfo->rf_vp); 9869d216dff5SRobert Mastors 9870d216dff5SRobert Mastors shr.s_access = shr.s_deny = 0; 9871d216dff5SRobert Mastors shr.s_pid = rfs4_dbe_getid(sp->rs_owner->ro_dbe); 9872d216dff5SRobert Mastors shr.s_sysid = sp->rs_owner->ro_client->rc_sysidt; 9873d216dff5SRobert Mastors shr_loco.sl_pid = shr.s_pid; 9874d216dff5SRobert Mastors shr_loco.sl_id = shr.s_sysid; 9875d216dff5SRobert Mastors shr.s_owner = (caddr_t)&shr_loco; 9876d216dff5SRobert Mastors shr.s_own_len = sizeof (shr_loco); 9877d216dff5SRobert Mastors 9878d216dff5SRobert Mastors err = VOP_SHRLOCK(sp->rs_finfo->rf_vp, F_UNSHARE, &shr, 0, CRED(), 9879d216dff5SRobert Mastors NULL); 9880d216dff5SRobert Mastors if (err != 0) { 9881d216dff5SRobert Mastors err = puterrno4(err); 9882d216dff5SRobert Mastors return (err); 9883d216dff5SRobert Mastors } 9884d216dff5SRobert Mastors 9885d216dff5SRobert Mastors sp->rs_share_access = 0; 9886d216dff5SRobert Mastors sp->rs_share_deny = 0; 9887d216dff5SRobert Mastors 9888d216dff5SRobert Mastors return (0); 9889d216dff5SRobert Mastors 98907c478bd9Sstevel@tonic-gate } 98910a701b1eSRobert Gordon 98920a701b1eSRobert Gordon static int 98930a701b1eSRobert Gordon rdma_setup_read_data4(READ4args *args, READ4res *rok) 98940a701b1eSRobert Gordon { 98950a701b1eSRobert Gordon struct clist *wcl; 98960a701b1eSRobert Gordon count4 count = rok->data_len; 9897f837ee4aSSiddheshwar Mahesh int wlist_len; 98980a701b1eSRobert Gordon 98990a701b1eSRobert Gordon wcl = args->wlist; 9900f837ee4aSSiddheshwar Mahesh if (rdma_setup_read_chunks(wcl, count, &wlist_len) == FALSE) { 99010a701b1eSRobert Gordon return (FALSE); 99020a701b1eSRobert Gordon } 99030a701b1eSRobert Gordon wcl = args->wlist; 9904f837ee4aSSiddheshwar Mahesh rok->wlist_len = wlist_len; 99050a701b1eSRobert Gordon rok->wlist = wcl; 99060a701b1eSRobert Gordon return (TRUE); 99070a701b1eSRobert Gordon } 99082f172c55SRobert Thurlow 99092f172c55SRobert Thurlow /* tunable to disable server referrals */ 99102f172c55SRobert Thurlow int rfs4_no_referrals = 0; 99112f172c55SRobert Thurlow 99122f172c55SRobert Thurlow /* 99132f172c55SRobert Thurlow * Find an NFS record in reparse point data. 99142f172c55SRobert Thurlow * Returns 0 for success and <0 or an errno value on failure. 99152f172c55SRobert Thurlow */ 99162f172c55SRobert Thurlow int 99172f172c55SRobert Thurlow vn_find_nfs_record(vnode_t *vp, nvlist_t **nvlp, char **svcp, char **datap) 99182f172c55SRobert Thurlow { 99192f172c55SRobert Thurlow int err; 99202f172c55SRobert Thurlow char *stype, *val; 99212f172c55SRobert Thurlow nvlist_t *nvl; 99222f172c55SRobert Thurlow nvpair_t *curr; 99232f172c55SRobert Thurlow 99242f172c55SRobert Thurlow if ((nvl = reparse_init()) == NULL) 99252f172c55SRobert Thurlow return (-1); 99262f172c55SRobert Thurlow 99272f172c55SRobert Thurlow if ((err = reparse_vnode_parse(vp, nvl)) != 0) { 99282f172c55SRobert Thurlow reparse_free(nvl); 99292f172c55SRobert Thurlow return (err); 99302f172c55SRobert Thurlow } 99312f172c55SRobert Thurlow 99322f172c55SRobert Thurlow curr = NULL; 99332f172c55SRobert Thurlow while ((curr = nvlist_next_nvpair(nvl, curr)) != NULL) { 99342f172c55SRobert Thurlow if ((stype = nvpair_name(curr)) == NULL) { 99352f172c55SRobert Thurlow reparse_free(nvl); 99362f172c55SRobert Thurlow return (-2); 99372f172c55SRobert Thurlow } 99382f172c55SRobert Thurlow if (strncasecmp(stype, "NFS", 3) == 0) 99392f172c55SRobert Thurlow break; 99402f172c55SRobert Thurlow } 99412f172c55SRobert Thurlow 99422f172c55SRobert Thurlow if ((curr == NULL) || 99432f172c55SRobert Thurlow (nvpair_value_string(curr, &val))) { 99442f172c55SRobert Thurlow reparse_free(nvl); 99452f172c55SRobert Thurlow return (-3); 99462f172c55SRobert Thurlow } 99472f172c55SRobert Thurlow *nvlp = nvl; 99482f172c55SRobert Thurlow *svcp = stype; 99492f172c55SRobert Thurlow *datap = val; 99502f172c55SRobert Thurlow return (0); 99512f172c55SRobert Thurlow } 99522f172c55SRobert Thurlow 99532f172c55SRobert Thurlow int 99542f172c55SRobert Thurlow vn_is_nfs_reparse(vnode_t *vp, cred_t *cr) 99552f172c55SRobert Thurlow { 99562f172c55SRobert Thurlow nvlist_t *nvl; 99572f172c55SRobert Thurlow char *s, *d; 99582f172c55SRobert Thurlow 99592f172c55SRobert Thurlow if (rfs4_no_referrals != 0) 99602f172c55SRobert Thurlow return (B_FALSE); 99612f172c55SRobert Thurlow 99622f172c55SRobert Thurlow if (vn_is_reparse(vp, cr, NULL) == B_FALSE) 99632f172c55SRobert Thurlow return (B_FALSE); 99642f172c55SRobert Thurlow 99652f172c55SRobert Thurlow if (vn_find_nfs_record(vp, &nvl, &s, &d) != 0) 99662f172c55SRobert Thurlow return (B_FALSE); 99672f172c55SRobert Thurlow 99682f172c55SRobert Thurlow reparse_free(nvl); 99692f172c55SRobert Thurlow 99702f172c55SRobert Thurlow return (B_TRUE); 99712f172c55SRobert Thurlow } 99722f172c55SRobert Thurlow 99732f172c55SRobert Thurlow /* 99742f172c55SRobert Thurlow * There is a user-level copy of this routine in ref_subr.c. 99752f172c55SRobert Thurlow * Changes should be kept in sync. 99762f172c55SRobert Thurlow */ 99772f172c55SRobert Thurlow static int 99782f172c55SRobert Thurlow nfs4_create_components(char *path, component4 *comp4) 99792f172c55SRobert Thurlow { 99802f172c55SRobert Thurlow int slen, plen, ncomp; 99812f172c55SRobert Thurlow char *ori_path, *nxtc, buf[MAXNAMELEN]; 99822f172c55SRobert Thurlow 99832f172c55SRobert Thurlow if (path == NULL) 99842f172c55SRobert Thurlow return (0); 99852f172c55SRobert Thurlow 99862f172c55SRobert Thurlow plen = strlen(path) + 1; /* include the terminator */ 99872f172c55SRobert Thurlow ori_path = path; 99882f172c55SRobert Thurlow ncomp = 0; 99892f172c55SRobert Thurlow 99902f172c55SRobert Thurlow /* count number of components in the path */ 99912f172c55SRobert Thurlow for (nxtc = path; nxtc < ori_path + plen; nxtc++) { 99922f172c55SRobert Thurlow if (*nxtc == '/' || *nxtc == '\0' || *nxtc == '\n') { 99932f172c55SRobert Thurlow if ((slen = nxtc - path) == 0) { 99942f172c55SRobert Thurlow path = nxtc + 1; 99952f172c55SRobert Thurlow continue; 99962f172c55SRobert Thurlow } 99972f172c55SRobert Thurlow 99982f172c55SRobert Thurlow if (comp4 != NULL) { 99992f172c55SRobert Thurlow bcopy(path, buf, slen); 100002f172c55SRobert Thurlow buf[slen] = '\0'; 100015301ec54SRobert Thurlow (void) str_to_utf8(buf, &comp4[ncomp]); 100022f172c55SRobert Thurlow } 100032f172c55SRobert Thurlow 100042f172c55SRobert Thurlow ncomp++; /* 1 valid component */ 100052f172c55SRobert Thurlow path = nxtc + 1; 100062f172c55SRobert Thurlow } 100072f172c55SRobert Thurlow if (*nxtc == '\0' || *nxtc == '\n') 100082f172c55SRobert Thurlow break; 100092f172c55SRobert Thurlow } 100102f172c55SRobert Thurlow 100112f172c55SRobert Thurlow return (ncomp); 100122f172c55SRobert Thurlow } 100132f172c55SRobert Thurlow 100142f172c55SRobert Thurlow /* 100152f172c55SRobert Thurlow * There is a user-level copy of this routine in ref_subr.c. 100162f172c55SRobert Thurlow * Changes should be kept in sync. 100172f172c55SRobert Thurlow */ 100182f172c55SRobert Thurlow static int 100192f172c55SRobert Thurlow make_pathname4(char *path, pathname4 *pathname) 100202f172c55SRobert Thurlow { 100212f172c55SRobert Thurlow int ncomp; 100222f172c55SRobert Thurlow component4 *comp4; 100232f172c55SRobert Thurlow 100242f172c55SRobert Thurlow if (pathname == NULL) 100252f172c55SRobert Thurlow return (0); 100262f172c55SRobert Thurlow 100272f172c55SRobert Thurlow if (path == NULL) { 100282f172c55SRobert Thurlow pathname->pathname4_val = NULL; 100292f172c55SRobert Thurlow pathname->pathname4_len = 0; 100302f172c55SRobert Thurlow return (0); 100312f172c55SRobert Thurlow } 100322f172c55SRobert Thurlow 100332f172c55SRobert Thurlow /* count number of components to alloc buffer */ 100342f172c55SRobert Thurlow if ((ncomp = nfs4_create_components(path, NULL)) == 0) { 100352f172c55SRobert Thurlow pathname->pathname4_val = NULL; 100362f172c55SRobert Thurlow pathname->pathname4_len = 0; 100372f172c55SRobert Thurlow return (0); 100382f172c55SRobert Thurlow } 100392f172c55SRobert Thurlow comp4 = kmem_zalloc(ncomp * sizeof (component4), KM_SLEEP); 100402f172c55SRobert Thurlow 100412f172c55SRobert Thurlow /* copy components into allocated buffer */ 100422f172c55SRobert Thurlow ncomp = nfs4_create_components(path, comp4); 100432f172c55SRobert Thurlow 100442f172c55SRobert Thurlow pathname->pathname4_val = comp4; 100452f172c55SRobert Thurlow pathname->pathname4_len = ncomp; 100462f172c55SRobert Thurlow 100472f172c55SRobert Thurlow return (ncomp); 100482f172c55SRobert Thurlow } 100492f172c55SRobert Thurlow 100502f172c55SRobert Thurlow #define xdr_fs_locations4 xdr_fattr4_fs_locations 100512f172c55SRobert Thurlow 100522f172c55SRobert Thurlow fs_locations4 * 100532f172c55SRobert Thurlow fetch_referral(vnode_t *vp, cred_t *cr) 100542f172c55SRobert Thurlow { 100552f172c55SRobert Thurlow nvlist_t *nvl; 100562f172c55SRobert Thurlow char *stype, *sdata; 100572f172c55SRobert Thurlow fs_locations4 *result; 100582f172c55SRobert Thurlow char buf[1024]; 100592f172c55SRobert Thurlow size_t bufsize; 100602f172c55SRobert Thurlow XDR xdr; 100612f172c55SRobert Thurlow int err; 100622f172c55SRobert Thurlow 100632f172c55SRobert Thurlow /* 100642f172c55SRobert Thurlow * Check attrs to ensure it's a reparse point 100652f172c55SRobert Thurlow */ 100662f172c55SRobert Thurlow if (vn_is_reparse(vp, cr, NULL) == B_FALSE) 100672f172c55SRobert Thurlow return (NULL); 100682f172c55SRobert Thurlow 100692f172c55SRobert Thurlow /* 100702f172c55SRobert Thurlow * Look for an NFS record and get the type and data 100712f172c55SRobert Thurlow */ 100722f172c55SRobert Thurlow if (vn_find_nfs_record(vp, &nvl, &stype, &sdata) != 0) 100732f172c55SRobert Thurlow return (NULL); 100742f172c55SRobert Thurlow 100752f172c55SRobert Thurlow /* 100762f172c55SRobert Thurlow * With the type and data, upcall to get the referral 100772f172c55SRobert Thurlow */ 100782f172c55SRobert Thurlow bufsize = sizeof (buf); 100792f172c55SRobert Thurlow bzero(buf, sizeof (buf)); 100802f172c55SRobert Thurlow err = reparse_kderef((const char *)stype, (const char *)sdata, 100812f172c55SRobert Thurlow buf, &bufsize); 100822f172c55SRobert Thurlow reparse_free(nvl); 100832f172c55SRobert Thurlow 100842f172c55SRobert Thurlow DTRACE_PROBE4(nfs4serv__func__referral__upcall, 100852f172c55SRobert Thurlow char *, stype, char *, sdata, char *, buf, int, err); 100862f172c55SRobert Thurlow if (err) { 100872f172c55SRobert Thurlow cmn_err(CE_NOTE, 100882f172c55SRobert Thurlow "reparsed daemon not running: unable to get referral (%d)", 100892f172c55SRobert Thurlow err); 100902f172c55SRobert Thurlow return (NULL); 100912f172c55SRobert Thurlow } 100922f172c55SRobert Thurlow 100932f172c55SRobert Thurlow /* 100942f172c55SRobert Thurlow * We get an XDR'ed record back from the kderef call 100952f172c55SRobert Thurlow */ 100962f172c55SRobert Thurlow xdrmem_create(&xdr, buf, bufsize, XDR_DECODE); 100972f172c55SRobert Thurlow result = kmem_alloc(sizeof (fs_locations4), KM_SLEEP); 100982f172c55SRobert Thurlow err = xdr_fs_locations4(&xdr, result); 100992f172c55SRobert Thurlow XDR_DESTROY(&xdr); 101002f172c55SRobert Thurlow if (err != TRUE) { 101012f172c55SRobert Thurlow DTRACE_PROBE1(nfs4serv__func__referral__upcall__xdrfail, 101022f172c55SRobert Thurlow int, err); 101032f172c55SRobert Thurlow return (NULL); 101042f172c55SRobert Thurlow } 101052f172c55SRobert Thurlow 101062f172c55SRobert Thurlow /* 101072f172c55SRobert Thurlow * Look at path to recover fs_root, ignoring the leading '/' 101082f172c55SRobert Thurlow */ 101092f172c55SRobert Thurlow (void) make_pathname4(vp->v_path, &result->fs_root); 101102f172c55SRobert Thurlow 101112f172c55SRobert Thurlow return (result); 101122f172c55SRobert Thurlow } 101132f172c55SRobert Thurlow 101142f172c55SRobert Thurlow char * 101152f172c55SRobert Thurlow build_symlink(vnode_t *vp, cred_t *cr, size_t *strsz) 101162f172c55SRobert Thurlow { 101172f172c55SRobert Thurlow fs_locations4 *fsl; 101182f172c55SRobert Thurlow fs_location4 *fs; 101192f172c55SRobert Thurlow char *server, *path, *symbuf; 101202f172c55SRobert Thurlow static char *prefix = "/net/"; 101212f172c55SRobert Thurlow int i, size, npaths; 101222f172c55SRobert Thurlow uint_t len; 101232f172c55SRobert Thurlow 101242f172c55SRobert Thurlow /* Get the referral */ 101252f172c55SRobert Thurlow if ((fsl = fetch_referral(vp, cr)) == NULL) 101262f172c55SRobert Thurlow return (NULL); 101272f172c55SRobert Thurlow 101282f172c55SRobert Thurlow /* Deal with only the first location and first server */ 101292f172c55SRobert Thurlow fs = &fsl->locations_val[0]; 101302f172c55SRobert Thurlow server = utf8_to_str(&fs->server_val[0], &len, NULL); 101312f172c55SRobert Thurlow if (server == NULL) { 101322f172c55SRobert Thurlow rfs4_free_fs_locations4(fsl); 101332f172c55SRobert Thurlow kmem_free(fsl, sizeof (fs_locations4)); 101342f172c55SRobert Thurlow return (NULL); 101352f172c55SRobert Thurlow } 101362f172c55SRobert Thurlow 101372f172c55SRobert Thurlow /* Figure out size for "/net/" + host + /path/path/path + NULL */ 101382f172c55SRobert Thurlow size = strlen(prefix) + len; 101392f172c55SRobert Thurlow for (i = 0; i < fs->rootpath.pathname4_len; i++) 101402f172c55SRobert Thurlow size += fs->rootpath.pathname4_val[i].utf8string_len + 1; 101412f172c55SRobert Thurlow 101422f172c55SRobert Thurlow /* Allocate the symlink buffer and fill it */ 101432f172c55SRobert Thurlow symbuf = kmem_zalloc(size, KM_SLEEP); 101442f172c55SRobert Thurlow (void) strcat(symbuf, prefix); 101452f172c55SRobert Thurlow (void) strcat(symbuf, server); 101462f172c55SRobert Thurlow kmem_free(server, len); 101472f172c55SRobert Thurlow 101482f172c55SRobert Thurlow npaths = 0; 101492f172c55SRobert Thurlow for (i = 0; i < fs->rootpath.pathname4_len; i++) { 101502f172c55SRobert Thurlow path = utf8_to_str(&fs->rootpath.pathname4_val[i], &len, NULL); 101512f172c55SRobert Thurlow if (path == NULL) 101522f172c55SRobert Thurlow continue; 101532f172c55SRobert Thurlow (void) strcat(symbuf, "/"); 101542f172c55SRobert Thurlow (void) strcat(symbuf, path); 101552f172c55SRobert Thurlow npaths++; 101562f172c55SRobert Thurlow kmem_free(path, len); 101572f172c55SRobert Thurlow } 101582f172c55SRobert Thurlow 101592f172c55SRobert Thurlow rfs4_free_fs_locations4(fsl); 101602f172c55SRobert Thurlow kmem_free(fsl, sizeof (fs_locations4)); 101612f172c55SRobert Thurlow 101622f172c55SRobert Thurlow if (strsz != NULL) 101632f172c55SRobert Thurlow *strsz = size; 101642f172c55SRobert Thurlow return (symbuf); 101652f172c55SRobert Thurlow } 101662f172c55SRobert Thurlow 101672f172c55SRobert Thurlow /* 101682f172c55SRobert Thurlow * Check to see if we have a downrev Solaris client, so that we 101692f172c55SRobert Thurlow * can send it a symlink instead of a referral. 101702f172c55SRobert Thurlow */ 101712f172c55SRobert Thurlow int 101722f172c55SRobert Thurlow client_is_downrev(struct svc_req *req) 101732f172c55SRobert Thurlow { 101742f172c55SRobert Thurlow struct sockaddr *ca; 101752f172c55SRobert Thurlow rfs4_clntip_t *ci; 101762f172c55SRobert Thurlow bool_t create = FALSE; 101772f172c55SRobert Thurlow int is_downrev; 101782f172c55SRobert Thurlow 101792f172c55SRobert Thurlow ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; 101802f172c55SRobert Thurlow ASSERT(ca); 101812f172c55SRobert Thurlow ci = rfs4_find_clntip(ca, &create); 101822f172c55SRobert Thurlow if (ci == NULL) 101832f172c55SRobert Thurlow return (0); 101842f172c55SRobert Thurlow is_downrev = ci->ri_no_referrals; 101852f172c55SRobert Thurlow rfs4_dbe_rele(ci->ri_dbe); 101862f172c55SRobert Thurlow return (is_downrev); 101872f172c55SRobert Thurlow } 101880dfe541eSEvan Layton 101890dfe541eSEvan Layton /* 101900dfe541eSEvan Layton * Do the main work of handling HA-NFSv4 Resource Group failover on 101910dfe541eSEvan Layton * Sun Cluster. 101920dfe541eSEvan Layton * We need to detect whether any RG admin paths have been added or removed, 101930dfe541eSEvan Layton * and adjust resources accordingly. 101940dfe541eSEvan Layton * Currently we're using a very inefficient algorithm, ~ 2 * O(n**2). In 101950dfe541eSEvan Layton * order to scale, the list and array of paths need to be held in more 101960dfe541eSEvan Layton * suitable data structures. 101970dfe541eSEvan Layton */ 101980dfe541eSEvan Layton static void 101990dfe541eSEvan Layton hanfsv4_failover(nfs4_srv_t *nsrv4) 102000dfe541eSEvan Layton { 102010dfe541eSEvan Layton int i, start_grace, numadded_paths = 0; 102020dfe541eSEvan Layton char **added_paths = NULL; 102030dfe541eSEvan Layton rfs4_dss_path_t *dss_path; 102040dfe541eSEvan Layton 102050dfe541eSEvan Layton /* 102060dfe541eSEvan Layton * Note: currently, dss_pathlist cannot be NULL, since 102070dfe541eSEvan Layton * it will always include an entry for NFS4_DSS_VAR_DIR. If we 102080dfe541eSEvan Layton * make the latter dynamically specified too, the following will 102090dfe541eSEvan Layton * need to be adjusted. 102100dfe541eSEvan Layton */ 102110dfe541eSEvan Layton 102120dfe541eSEvan Layton /* 102130dfe541eSEvan Layton * First, look for removed paths: RGs that have been failed-over 102140dfe541eSEvan Layton * away from this node. 102150dfe541eSEvan Layton * Walk the "currently-serving" dss_pathlist and, for each 102160dfe541eSEvan Layton * path, check if it is on the "passed-in" rfs4_dss_newpaths array 102170dfe541eSEvan Layton * from nfsd. If not, that RG path has been removed. 102180dfe541eSEvan Layton * 102190dfe541eSEvan Layton * Note that nfsd has sorted rfs4_dss_newpaths for us, and removed 102200dfe541eSEvan Layton * any duplicates. 102210dfe541eSEvan Layton */ 102220dfe541eSEvan Layton dss_path = nsrv4->dss_pathlist; 102230dfe541eSEvan Layton do { 102240dfe541eSEvan Layton int found = 0; 102250dfe541eSEvan Layton char *path = dss_path->path; 102260dfe541eSEvan Layton 102270dfe541eSEvan Layton /* used only for non-HA so may not be removed */ 102280dfe541eSEvan Layton if (strcmp(path, NFS4_DSS_VAR_DIR) == 0) { 102290dfe541eSEvan Layton dss_path = dss_path->next; 102300dfe541eSEvan Layton continue; 102310dfe541eSEvan Layton } 102320dfe541eSEvan Layton 102330dfe541eSEvan Layton for (i = 0; i < rfs4_dss_numnewpaths; i++) { 102340dfe541eSEvan Layton int cmpret; 102350dfe541eSEvan Layton char *newpath = rfs4_dss_newpaths[i]; 102360dfe541eSEvan Layton 102370dfe541eSEvan Layton /* 102380dfe541eSEvan Layton * Since nfsd has sorted rfs4_dss_newpaths for us, 102390dfe541eSEvan Layton * once the return from strcmp is negative we know 102400dfe541eSEvan Layton * we've passed the point where "path" should be, 102410dfe541eSEvan Layton * and can stop searching: "path" has been removed. 102420dfe541eSEvan Layton */ 102430dfe541eSEvan Layton cmpret = strcmp(path, newpath); 102440dfe541eSEvan Layton if (cmpret < 0) 102450dfe541eSEvan Layton break; 102460dfe541eSEvan Layton if (cmpret == 0) { 102470dfe541eSEvan Layton found = 1; 102480dfe541eSEvan Layton break; 102490dfe541eSEvan Layton } 102500dfe541eSEvan Layton } 102510dfe541eSEvan Layton 102520dfe541eSEvan Layton if (found == 0) { 102530dfe541eSEvan Layton unsigned index = dss_path->index; 102540dfe541eSEvan Layton rfs4_servinst_t *sip = dss_path->sip; 102550dfe541eSEvan Layton rfs4_dss_path_t *path_next = dss_path->next; 102560dfe541eSEvan Layton 102570dfe541eSEvan Layton /* 102580dfe541eSEvan Layton * This path has been removed. 102590dfe541eSEvan Layton * We must clear out the servinst reference to 102600dfe541eSEvan Layton * it, since it's now owned by another 102610dfe541eSEvan Layton * node: we should not attempt to touch it. 102620dfe541eSEvan Layton */ 102630dfe541eSEvan Layton ASSERT(dss_path == sip->dss_paths[index]); 102640dfe541eSEvan Layton sip->dss_paths[index] = NULL; 102650dfe541eSEvan Layton 102660dfe541eSEvan Layton /* remove from "currently-serving" list, and destroy */ 102670dfe541eSEvan Layton remque(dss_path); 102680dfe541eSEvan Layton /* allow for NUL */ 102690dfe541eSEvan Layton kmem_free(dss_path->path, strlen(dss_path->path) + 1); 102700dfe541eSEvan Layton kmem_free(dss_path, sizeof (rfs4_dss_path_t)); 102710dfe541eSEvan Layton 102720dfe541eSEvan Layton dss_path = path_next; 102730dfe541eSEvan Layton } else { 102740dfe541eSEvan Layton /* path was found; not removed */ 102750dfe541eSEvan Layton dss_path = dss_path->next; 102760dfe541eSEvan Layton } 102770dfe541eSEvan Layton } while (dss_path != nsrv4->dss_pathlist); 102780dfe541eSEvan Layton 102790dfe541eSEvan Layton /* 102800dfe541eSEvan Layton * Now, look for added paths: RGs that have been failed-over 102810dfe541eSEvan Layton * to this node. 102820dfe541eSEvan Layton * Walk the "passed-in" rfs4_dss_newpaths array from nfsd and, 102830dfe541eSEvan Layton * for each path, check if it is on the "currently-serving" 102840dfe541eSEvan Layton * dss_pathlist. If not, that RG path has been added. 102850dfe541eSEvan Layton * 102860dfe541eSEvan Layton * Note: we don't do duplicate detection here; nfsd does that for us. 102870dfe541eSEvan Layton * 102880dfe541eSEvan Layton * Note: numadded_paths <= rfs4_dss_numnewpaths, which gives us 102890dfe541eSEvan Layton * an upper bound for the size needed for added_paths[numadded_paths]. 102900dfe541eSEvan Layton */ 102910dfe541eSEvan Layton 102920dfe541eSEvan Layton /* probably more space than we need, but guaranteed to be enough */ 102930dfe541eSEvan Layton if (rfs4_dss_numnewpaths > 0) { 102940dfe541eSEvan Layton size_t sz = rfs4_dss_numnewpaths * sizeof (char *); 102950dfe541eSEvan Layton added_paths = kmem_zalloc(sz, KM_SLEEP); 102960dfe541eSEvan Layton } 102970dfe541eSEvan Layton 102980dfe541eSEvan Layton /* walk the "passed-in" rfs4_dss_newpaths array from nfsd */ 102990dfe541eSEvan Layton for (i = 0; i < rfs4_dss_numnewpaths; i++) { 103000dfe541eSEvan Layton int found = 0; 103010dfe541eSEvan Layton char *newpath = rfs4_dss_newpaths[i]; 103020dfe541eSEvan Layton 103030dfe541eSEvan Layton dss_path = nsrv4->dss_pathlist; 103040dfe541eSEvan Layton do { 103050dfe541eSEvan Layton char *path = dss_path->path; 103060dfe541eSEvan Layton 103070dfe541eSEvan Layton /* used only for non-HA */ 103080dfe541eSEvan Layton if (strcmp(path, NFS4_DSS_VAR_DIR) == 0) { 103090dfe541eSEvan Layton dss_path = dss_path->next; 103100dfe541eSEvan Layton continue; 103110dfe541eSEvan Layton } 103120dfe541eSEvan Layton 103130dfe541eSEvan Layton if (strncmp(path, newpath, strlen(path)) == 0) { 103140dfe541eSEvan Layton found = 1; 103150dfe541eSEvan Layton break; 103160dfe541eSEvan Layton } 103170dfe541eSEvan Layton 103180dfe541eSEvan Layton dss_path = dss_path->next; 103190dfe541eSEvan Layton } while (dss_path != nsrv4->dss_pathlist); 103200dfe541eSEvan Layton 103210dfe541eSEvan Layton if (found == 0) { 103220dfe541eSEvan Layton added_paths[numadded_paths] = newpath; 103230dfe541eSEvan Layton numadded_paths++; 103240dfe541eSEvan Layton } 103250dfe541eSEvan Layton } 103260dfe541eSEvan Layton 103270dfe541eSEvan Layton /* did we find any added paths? */ 103280dfe541eSEvan Layton if (numadded_paths > 0) { 103290dfe541eSEvan Layton 103300dfe541eSEvan Layton /* create a new server instance, and start its grace period */ 103310dfe541eSEvan Layton start_grace = 1; 103320dfe541eSEvan Layton /* CSTYLED */ 103330dfe541eSEvan Layton rfs4_servinst_create(nsrv4, start_grace, numadded_paths, added_paths); 103340dfe541eSEvan Layton 103350dfe541eSEvan Layton /* read in the stable storage state from these paths */ 103360dfe541eSEvan Layton rfs4_dss_readstate(nsrv4, numadded_paths, added_paths); 103370dfe541eSEvan Layton 103380dfe541eSEvan Layton /* 103390dfe541eSEvan Layton * Multiple failovers during a grace period will cause 103400dfe541eSEvan Layton * clients of the same resource group to be partitioned 103410dfe541eSEvan Layton * into different server instances, with different 103420dfe541eSEvan Layton * grace periods. Since clients of the same resource 103430dfe541eSEvan Layton * group must be subject to the same grace period, 103440dfe541eSEvan Layton * we need to reset all currently active grace periods. 103450dfe541eSEvan Layton */ 103460dfe541eSEvan Layton rfs4_grace_reset_all(nsrv4); 103470dfe541eSEvan Layton } 103480dfe541eSEvan Layton 103490dfe541eSEvan Layton if (rfs4_dss_numnewpaths > 0) 103500dfe541eSEvan Layton kmem_free(added_paths, rfs4_dss_numnewpaths * sizeof (char *)); 103510dfe541eSEvan Layton } 10352