Home | History | Annotate | Download | only in nfs
      1   6741  th199096 /*
      2   6741  th199096  * CDDL HEADER START
      3   6741  th199096  *
      4   6741  th199096  * The contents of this file are subject to the terms of the
      5   6741  th199096  * Common Development and Distribution License (the "License").
      6   6741  th199096  * You may not use this file except in compliance with the License.
      7   6741  th199096  *
      8   6741  th199096  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9   6741  th199096  * or http://www.opensolaris.org/os/licensing.
     10   6741  th199096  * See the License for the specific language governing permissions
     11   6741  th199096  * and limitations under the License.
     12   6741  th199096  *
     13   6741  th199096  * When distributing Covered Code, include this CDDL HEADER in each
     14   6741  th199096  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15   6741  th199096  * If applicable, add the following below this CDDL HEADER, with the
     16   6741  th199096  * fields enclosed by brackets "[]" replaced with your own identifying
     17   6741  th199096  * information: Portions Copyright [yyyy] [name of copyright owner]
     18   6741  th199096  *
     19   6741  th199096  * CDDL HEADER END
     20   6741  th199096  */
     21   6741  th199096 /*
     22   8422     James  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23   6741  th199096  * Use is subject to license terms.
     24   6741  th199096  */
     25   6741  th199096 
     26   6741  th199096 /*
     27   6741  th199096  *	Copyright (c) 1983,1984,1985,1986,1987,1988,1989  AT&T.
     28   6741  th199096  *	All Rights Reserved
     29   6741  th199096  */
     30   6741  th199096 
     31   6741  th199096 #include <sys/param.h>
     32   6741  th199096 #include <sys/types.h>
     33   6741  th199096 #include <sys/systm.h>
     34   6741  th199096 #include <sys/cred.h>
     35   6741  th199096 #include <sys/buf.h>
     36   6741  th199096 #include <sys/vfs.h>
     37   6741  th199096 #include <sys/vnode.h>
     38   6741  th199096 #include <sys/uio.h>
     39   6741  th199096 #include <sys/errno.h>
     40   6741  th199096 #include <sys/sysmacros.h>
     41   6741  th199096 #include <sys/statvfs.h>
     42   6741  th199096 #include <sys/kmem.h>
     43   6741  th199096 #include <sys/dirent.h>
     44   6741  th199096 #include <sys/cmn_err.h>
     45   6741  th199096 #include <sys/disp.h>
     46   6741  th199096 #include <sys/debug.h>
     47   6741  th199096 #include <sys/systeminfo.h>
     48   6741  th199096 #include <sys/flock.h>
     49   6741  th199096 #include <sys/pathname.h>
     50   6741  th199096 #include <sys/nbmlock.h>
     51   6741  th199096 #include <sys/share.h>
     52   6741  th199096 #include <sys/atomic.h>
     53   6741  th199096 #include <sys/policy.h>
     54   6741  th199096 #include <sys/fem.h>
     55   6741  th199096 #include <sys/sdt.h>
     56   6741  th199096 #include <sys/ddi.h>
     57   7397      rick #include <sys/modctl.h>
     58   9396      rick #include <sys/timod.h>
     59  10016    Thomas #include <sys/id_space.h>
     60   6741  th199096 
     61   6741  th199096 #include <rpc/types.h>
     62   6741  th199096 #include <rpc/auth.h>
     63   6741  th199096 #include <rpc/rpcsec_gss.h>
     64   6741  th199096 #include <rpc/svc.h>
     65   6741  th199096 
     66   6741  th199096 #include <nfs/nfs.h>
     67   6741  th199096 #include <nfs/export.h>
     68   6741  th199096 #include <nfs/lm.h>
     69   6741  th199096 #include <nfs/nfs4.h>
     70   6741  th199096 
     71   6741  th199096 #include <sys/strsubr.h>
     72   6741  th199096 #include <sys/strsun.h>
     73   6741  th199096 
     74   6741  th199096 #include <inet/common.h>
     75   6741  th199096 #include <inet/ip.h>
     76   6741  th199096 #include <inet/ip6.h>
     77   6741  th199096 
     78   6741  th199096 #include <sys/tsol/label.h>
     79   6741  th199096 #include <sys/tsol/tndb.h>
     80   6741  th199096 
     81   6741  th199096 #include <nfs/nfs4_attrmap.h>
     82   6741  th199096 #include <nfs/nfs4_srv_attr.h>
     83   6741  th199096 #include <nfs/mds_state.h>
     84   8424      lisa #include <nfs/mds_odl.h>
     85   6741  th199096 
     86   6741  th199096 #include <nfs/nfs41_filehandle.h>
     87   8424      lisa #include <nfs/ctl_mds_clnt.h>
     88  10016    Thomas 
     89  10016    Thomas #include <nfs/spe_impl.h>
     90   6741  th199096 
     91   6741  th199096 #define	RFS4_MAXLOCK_TRIES 4	/* Try to get the lock this many times */
     92   6741  th199096 static int rfs4_maxlock_tries = RFS4_MAXLOCK_TRIES;
     93   6741  th199096 #define	RFS4_LOCK_DELAY 10	/* Milliseconds */
     94   6741  th199096 static clock_t rfs4_lock_delay = RFS4_LOCK_DELAY;
     95   6741  th199096 
     96   6741  th199096 int mds_strict_seqid = 0;
     97   6741  th199096 
     98   7739   jwahlig static void ping_cb_null_thr(mds_session_t *);
     99   6741  th199096 
    100   6741  th199096 /* End of Tunables */
    101   6741  th199096 
    102   6741  th199096 /*
    103   6741  th199096  * Used to bump the stateid4.seqid value and show changes in the stateid
    104   6741  th199096  */
    105   6741  th199096 #define	next_stateid(sp) (++(sp)->v41_bits.chgseq)
    106   6741  th199096 
    107   6741  th199096 /*
    108   6741  th199096  * RFS4_MINLEN_ENTRY4: XDR-encoded size of smallest possible dirent.
    109   6741  th199096  *	This is used to return NFS4ERR_TOOSMALL when clients specify
    110   6741  th199096  *	maxcount that isn't large enough to hold the smallest possible
    111   6741  th199096  *	XDR encoded dirent.
    112   6741  th199096  *
    113   6741  th199096  *	    sizeof cookie (8 bytes) +
    114   6741  th199096  *	    sizeof name_len (4 bytes) +
    115   6741  th199096  *	    sizeof smallest (padded) name (4 bytes) +
    116   6741  th199096  *	    sizeof bitmap4_len (12 bytes) +   NOTE: we always encode len=2 bm4
    117   6741  th199096  *	    sizeof attrlist4_len (4 bytes) +
    118   6741  th199096  *	    sizeof next boolean (4 bytes)
    119   6741  th199096  *
    120   6741  th199096  * RFS4_MINLEN_RDDIR4: XDR-encoded size of READDIR op reply containing
    121   6741  th199096  * the smallest possible entry4 (assumes no attrs requested).
    122   6741  th199096  *	sizeof nfsstat4 (4 bytes) +
    123   6741  th199096  *	sizeof verifier4 (8 bytes) +
    124   6741  th199096  *	sizeof entry4list bool (4 bytes) +
    125   6741  th199096  *	sizeof entry4 	(36 bytes) +
    126   6741  th199096  *	sizeof eof bool  (4 bytes)
    127   6741  th199096  *
    128   6741  th199096  * RFS4_MINLEN_RDDIR_BUF: minimum length of buffer server will provide to
    129   6741  th199096  *	VOP_READDIR.  Its value is the size of the maximum possible dirent
    130   6741  th199096  *	for solaris.  The DIRENT64_RECLEN macro returns	the size of dirent
    131   6741  th199096  *	required for a given name length.  MAXNAMELEN is the maximum
    132   6741  th199096  *	filename length allowed in Solaris.  The first two DIRENT64_RECLEN()
    133   6741  th199096  *	macros are to allow for . and .. entries -- just a minor tweak to try
    134   6741  th199096  *	and guarantee that buffer we give to VOP_READDIR will be large enough
    135   6741  th199096  *	to hold ., .., and the largest possible solaris dirent64.
    136   6741  th199096  */
    137   6741  th199096 #define	RFS4_MINLEN_ENTRY4 36
    138   6741  th199096 #define	RFS4_MINLEN_RDDIR4 (4 + NFS4_VERIFIER_SIZE + 4 + RFS4_MINLEN_ENTRY4 + 4)
    139   6741  th199096 #define	RFS4_MINLEN_RDDIR_BUF \
    140   6741  th199096 	(DIRENT64_RECLEN(1) + DIRENT64_RECLEN(2) + DIRENT64_RECLEN(MAXNAMELEN))
    141   6741  th199096 
    142   6741  th199096 /*
    143   6741  th199096  * It would be better to pad to 4 bytes since that's what XDR would do,
    144   6741  th199096  * but the dirents UFS gives us are already padded to 8, so just take
    145   6741  th199096  * what we're given.  Dircount is only a hint anyway.  Currently the
    146   6741  th199096  * solaris kernel is ASCII only, so there's no point in calling the
    147   6741  th199096  * UTF8 functions.
    148   6741  th199096  *
    149   6741  th199096  * dirent64: named padded to provide 8 byte struct alignment
    150   6741  th199096  *	d_ino(8) + d_off(8) + d_reclen(2) + d_name(namelen + null(1) + pad)
    151   6741  th199096  *
    152   6741  th199096  * cookie: uint64_t   +  utf8namelen: uint_t  +   utf8name padded to 8 bytes
    153   6741  th199096  *
    154   6741  th199096  */
    155   6741  th199096 #define	DIRENT64_TO_DIRCOUNT(dp) \
    156   6741  th199096 	(3 * BYTES_PER_XDR_UNIT + DIRENT64_NAMELEN((dp)->d_reclen))
    157   6741  th199096 
    158   6741  th199096 /*
    159   6741  th199096  * types of label comparison
    160   6741  th199096  */
    161   6741  th199096 #define	EQUALITY_CHECK	0
    162   6741  th199096 #define	DOMINANCE_CHECK	1
    163   6741  th199096 
    164   6741  th199096 static sysid_t lockt_sysid;		/* dummy sysid for all LOCKT calls */
    165   6741  th199096 
    166   7739   jwahlig void		rfs4_init_compound_state(struct compound_state *);
    167   6741  th199096 
    168   8023       Sam static void	nullfree(nfs_resop4 *, compound_state_t *);
    169   6741  th199096 static void	mds_op_inval(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    170   8023       Sam 			compound_state_t *);
    171   6741  th199096 static void	mds_op_notsup(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    172   8023       Sam 			compound_state_t *);
    173   6741  th199096 static void	mds_op_access(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    174   8023       Sam 			compound_state_t *);
    175   6741  th199096 static void	mds_op_close(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    176   8023       Sam 			compound_state_t *);
    177   6741  th199096 static void	mds_op_commit(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    178   8023       Sam 			compound_state_t *);
    179   6741  th199096 static void	mds_op_create(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    180   8023       Sam 			compound_state_t *);
    181   6741  th199096 static void	mds_op_create_free(nfs_resop4 *resop);
    182   6741  th199096 static void	mds_op_delegreturn(nfs_argop4 *, nfs_resop4 *,
    183   8023       Sam 				struct svc_req *, compound_state_t *);
    184   6741  th199096 static void	mds_op_getattr(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    185   8023       Sam 			compound_state_t *);
    186   8023       Sam static void	mds_op_getattr_free(nfs_resop4 *, compound_state_t *);
    187   6741  th199096 static void	mds_op_getfh(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    188   8023       Sam 			compound_state_t *);
    189   8023       Sam static void	mds_op_getfh_free(nfs_resop4 *, compound_state_t *);
    190   6741  th199096 static void	mds_op_link(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    191   8023       Sam 			compound_state_t *);
    192   6741  th199096 static void	mds_op_lock(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    193   8023       Sam 			compound_state_t *);
    194   8023       Sam static void	mds_lock_denied_free(nfs_resop4 *, compound_state_t *);
    195   6741  th199096 static void	mds_op_locku(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    196   8023       Sam 			compound_state_t *);
    197   6741  th199096 static void	mds_op_lockt(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    198   8023       Sam 			compound_state_t *);
    199   6741  th199096 static void	mds_op_lookup(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    200   8023       Sam 			compound_state_t *);
    201   6741  th199096 static void	mds_op_lookupp(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    202   8023       Sam 			compound_state_t *);
    203   6741  th199096 static void	mds_op_openattr(nfs_argop4 *argop, nfs_resop4 *resop,
    204   8023       Sam 				struct svc_req *req, compound_state_t *);
    205   6741  th199096 static void	mds_op_nverify(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    206   8023       Sam 			compound_state_t *);
    207   6741  th199096 static void	mds_op_open(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    208   8023       Sam 			compound_state_t *);
    209   6741  th199096 static void	mds_op_open_downgrade(nfs_argop4 *, nfs_resop4 *,
    210   8023       Sam 			struct svc_req *, compound_state_t *);
    211   6741  th199096 static void	mds_op_putfh(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    212   8023       Sam 			compound_state_t *);
    213   6741  th199096 static void	mds_op_putpubfh(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    214   8023       Sam 			compound_state_t *);
    215   6741  th199096 static void	mds_op_putrootfh(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    216   8023       Sam 			compound_state_t *);
    217   6741  th199096 static void	mds_op_read(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    218   8023       Sam 			compound_state_t *);
    219   8023       Sam static void	mds_op_read_free(nfs_resop4 *, compound_state_t *);
    220   6741  th199096 void		mds_op_readdir(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    221   8023       Sam 			compound_state_t *);
    222   8023       Sam static void	mds_op_readdir_free(nfs_resop4 *, compound_state_t *);
    223   6741  th199096 static void	mds_op_readlink(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    224   8023       Sam 			compound_state_t *);
    225   8023       Sam static void	mds_op_readlink_free(nfs_resop4 *, compound_state_t *);
    226   6741  th199096 static void	mds_op_release_lockowner(nfs_argop4 *, nfs_resop4 *,
    227   8023       Sam 			struct svc_req *, compound_state_t *);
    228   6741  th199096 static void	mds_op_remove(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    229   8023       Sam 			compound_state_t *);
    230   6741  th199096 static void	mds_op_rename(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    231   8023       Sam 			compound_state_t *);
    232   6741  th199096 static void	mds_op_renew(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    233   8023       Sam 			compound_state_t *);
    234   6741  th199096 static void	mds_op_restorefh(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    235   8023       Sam 			compound_state_t *);
    236   6741  th199096 static void	mds_op_savefh(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    237   8023       Sam 			compound_state_t *);
    238   6741  th199096 static void	mds_op_setattr(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    239   8023       Sam 			compound_state_t *);
    240   6741  th199096 static void	mds_op_verify(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    241   8023       Sam 			compound_state_t *);
    242   6741  th199096 static void	mds_op_write(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    243   8023       Sam 			compound_state_t *);
    244   6741  th199096 static void	mds_op_exchange_id(nfs_argop4 *, nfs_resop4 *,
    245   8023       Sam 			struct svc_req *, compound_state_t *);
    246   9396      rick static void	mds_op_exid_free(nfs_resop4 *, compound_state_t *);
    247   6741  th199096 static void	mds_op_secinfo(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    248   8023       Sam 			compound_state_t *);
    249   6741  th199096 static void	mds_op_secinfonn(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    250   8023       Sam 			compound_state_t *);
    251   6741  th199096 nfsstat4	do_rfs4_op_secinfo(struct compound_state *, char *, int,
    252   6741  th199096     SECINFO4res *);
    253   6741  th199096 
    254   8023       Sam static void	mds_op_secinfo_free(nfs_resop4 *, compound_state_t *);
    255   6741  th199096 
    256   6741  th199096 static void	mds_op_backchannel_ctl(nfs_argop4 *, nfs_resop4 *,
    257   8023       Sam 			struct svc_req *, compound_state_t *);
    258   6741  th199096 static void	mds_op_bind_conn_to_session(nfs_argop4 *, nfs_resop4 *,
    259   8023       Sam 			struct svc_req *, compound_state_t *);
    260   6741  th199096 static void	mds_op_create_clientid(nfs_argop4 *, nfs_resop4 *,
    261   8023       Sam 			struct svc_req *, compound_state_t *);
    262   6741  th199096 static void	mds_op_create_session(nfs_argop4 *, nfs_resop4 *,
    263   8023       Sam 			struct svc_req *, compound_state_t *);
    264   6741  th199096 static void	mds_op_destroy_session(nfs_argop4 *, nfs_resop4 *,
    265   8023       Sam 			struct svc_req *, compound_state_t *);
    266   6741  th199096 static void	mds_op_sequence(nfs_argop4 *, nfs_resop4 *,
    267   8023       Sam 			struct svc_req *, compound_state_t *);
    268   6741  th199096 
    269   6741  th199096 static void mds_op_get_devlist(nfs_argop4 *, nfs_resop4 *,
    270   8023       Sam 		struct svc_req *, compound_state_t *);
    271   6741  th199096 
    272   6741  th199096 static void mds_op_get_devinfo(nfs_argop4 *, nfs_resop4 *,
    273   8023       Sam 		struct svc_req *, compound_state_t *);
    274   6741  th199096 
    275   6741  th199096 static void mds_op_layout_get(nfs_argop4 *, nfs_resop4 *,
    276   8023       Sam 		struct svc_req *, compound_state_t *);
    277   9106    Piyush static void mds_op_layout_get_free(nfs_resop4 *, compound_state_t *);
    278   6741  th199096 
    279   6741  th199096 static void mds_op_layout_commit(nfs_argop4 *, nfs_resop4 *,
    280   8023       Sam 		struct svc_req *, compound_state_t *);
    281   6741  th199096 
    282   6741  th199096 static void mds_op_layout_return(nfs_argop4 *, nfs_resop4 *,
    283   8023       Sam 		struct svc_req *, compound_state_t *);
    284   7739   jwahlig 
    285   7739   jwahlig static void mds_op_reclaim_complete(nfs_argop4 *, nfs_resop4 *,
    286   8023       Sam     struct svc_req *, compound_state_t *);
    287   6741  th199096 
    288  10475      rick static int	seq_chk_limits(nfs_argop4 *, nfs_resop4 *, compound_state_t *);
    289  10475      rick 
    290   6741  th199096 nfsstat4 check_open_access(uint32_t,
    291   6741  th199096 			struct compound_state *, struct svc_req *);
    292   6741  th199096 nfsstat4 rfs4_client_sysid(rfs4_client_t *, sysid_t *);
    293   6741  th199096 
    294   8023       Sam static void	mds_free_reply(nfs_resop4 *, compound_state_t *);
    295   6741  th199096 
    296   6741  th199096 vnode_t *do_rfs4_op_mknod(CREATE4args *, CREATE4res *, struct svc_req *,
    297   6741  th199096 			struct compound_state *, vattr_t *, char *);
    298   6741  th199096 
    299   6741  th199096 nfsstat4 rfs4_do_lock(rfs4_lo_state_t *, nfs_lock_type4, seqid4,
    300   6741  th199096 		offset4, length4, cred_t *, nfs_resop4 *);
    301   6741  th199096 
    302   6741  th199096 rfs4_lo_state_t *mds_findlo_state_by_owner(rfs4_lockowner_t *,
    303   7739   jwahlig 	    rfs4_state_t *, bool_t *);
    304   6741  th199096 
    305   6741  th199096 bool_t in_flavor_list(int, int *, int);
    306   6741  th199096 
    307   6741  th199096 nfsstat4 attrmap4_to_vattrmask(attrmap4 *, struct nfs4_svgetit_arg *);
    308   6741  th199096 
    309   6741  th199096 nfsstat4 bitmap4_get_sysattrs(struct nfs4_svgetit_arg *);
    310   6741  th199096 
    311   6741  th199096 nfsstat4 do_rfs4_op_getattr(attrmap4 *, fattr4 *, struct nfs4_svgetit_arg *);
    312   6741  th199096 
    313   6741  th199096 nfsstat4 do_rfs4_op_lookup(char *, uint_t, struct svc_req *,
    314   6741  th199096 		struct compound_state *);
    315   6741  th199096 
    316   7739   jwahlig rfs4_lockowner_t *mds_findlockowner_by_pid(nfs_server_instance_t *, pid_t);
    317   7739   jwahlig 
    318   7739   jwahlig mds_session_t *mds_findsession_by_id(nfs_server_instance_t *, sessionid4);
    319   7739   jwahlig 
    320   7739   jwahlig rfs4_openowner_t *mds_findopenowner(nfs_server_instance_t *, open_owner4 *,
    321   7739   jwahlig     bool_t *);
    322   6741  th199096 
    323   6741  th199096 static void	mds_op_nverify(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    324   8023       Sam 			compound_state_t *);
    325   6741  th199096 
    326  10016    Thomas extern mds_mpd_t *mds_find_mpd(nfs_server_instance_t *, id_t);
    327   8035     James extern void rfs41_lo_seqid(stateid_t *);
    328   9215     James extern void mds_delete_layout(vnode_t *);
    329   9215     James extern void mds_clean_grants_by_fsid(rfs4_client_t *, vnode_t *);
    330  10016    Thomas extern mds_layout_t *mds_add_layout(layout_core_t *lc);
    331   6741  th199096 
    332   6741  th199096 nfsstat4
    333   6741  th199096 create_vnode(vnode_t *, char *,  vattr_t *, createmode4, timespec32_t *,
    334   6741  th199096     cred_t *, vnode_t **, bool_t *);
    335   6741  th199096 
    336   6741  th199096 
    337   6741  th199096 /* HACKERY */
    338   6741  th199096 nfsstat4 rfs4_get_all_state(struct compound_state *, stateid4 *,
    339   6741  th199096     rfs4_state_t **, rfs4_deleg_state_t **, rfs4_lo_state_t **);
    340   6741  th199096 
    341   7739   jwahlig void rfs4_ss_clid(struct compound_state *, rfs4_client_t *, struct svc_req *);
    342   7739   jwahlig void rfs4_ss_chkclid(struct compound_state *, rfs4_client_t *);
    343   8422     James 
    344   8422     James int layout_match(stateid_t, stateid4, nfsstat4 *);
    345   7739   jwahlig 
    346   6741  th199096 extern stateid4 special0;
    347   6741  th199096 extern stateid4 special1;
    348   6741  th199096 
    349   6741  th199096 #define	ISSPECIAL(id)  (stateid4_cmp(id, &special0) || \
    350   6741  th199096 			stateid4_cmp(id, &special1))
    351   6741  th199096 
    352   8023       Sam void rfs4_cn_release(compound_state_t *);
    353   7739   jwahlig 
    354   7739   jwahlig mds_layout_grant_t *rfs41_findlogrant(struct compound_state *,
    355   7739   jwahlig     rfs4_file_t *, rfs4_client_t *, bool_t *);
    356   7739   jwahlig void rfs41_lo_grant_rele(mds_layout_grant_t *);
    357   7812     James mds_ever_grant_t *rfs41_findevergrant(rfs4_client_t *, vnode_t *, bool_t *);
    358   7812     James void rfs41_ever_grant_rele(mds_ever_grant_t *);
    359   8415       Sam 
    360   8415       Sam static uint32_t compute_use_pnfs_flags(uint32_t);
    361   6741  th199096 
    362   6741  th199096 /* ARGSUSED */
    363   6741  th199096 static void
    364   6741  th199096 mds_op_notsup(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
    365   8023       Sam 	compound_state_t *cs)
    366   8023       Sam {
    367   7312    Danhua 	DTRACE_NFSV4_1(op__notsup__start,
    368   7312    Danhua 	    strcut compound_state *, cs);
    369   7312    Danhua 
    370   6741  th199096 	*cs->statusp = *((nfsstat4 *)&(resop)->nfs_resop4_u) = NFS4ERR_NOTSUPP;
    371   7312    Danhua 
    372   7312    Danhua 	DTRACE_NFSV4_1(op__notsup__done,
    373   7312    Danhua 	    struct compound_state *, cs);
    374   6741  th199096 }
    375  10475      rick 
    376   6741  th199096 /* ARGSUSED */
    377   6741  th199096 static void
    378   6741  th199096 mds_op_illegal(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
    379   8023       Sam 	compound_state_t *cs)
    380   8023       Sam {
    381   7312    Danhua 	DTRACE_NFSV4_1(op__illegal__start,
    382   7312    Danhua 	    struct compound_state *, cs);
    383   6741  th199096 
    384   6741  th199096 	*cs->statusp =
    385   6741  th199096 	    *((nfsstat4 *)&(resop)->nfs_resop4_u) = NFS4ERR_OP_ILLEGAL;
    386   7312    Danhua 
    387   7312    Danhua 	DTRACE_NFSV4_1(op__illegal__done,
    388   7312    Danhua 	    struct compound_state *, cs);
    389   6741  th199096 }
    390   6741  th199096 
    391   6741  th199096 /* ARGSUSED */
    392   6741  th199096 static void
    393   6741  th199096 mds_op_inval(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
    394   8023       Sam 	compound_state_t *cs)
    395   8023       Sam {
    396   7312    Danhua 	DTRACE_NFSV4_1(op__inval__start,
    397   7312    Danhua 	    struct compound_state *, cs);
    398   7312    Danhua 
    399   6741  th199096 	*cs->statusp = *((nfsstat4 *)&(resop)->nfs_resop4_u) = NFS4ERR_INVAL;
    400   7312    Danhua 
    401   7312    Danhua 	DTRACE_NFSV4_1(op__inval__done,
    402   7312    Danhua 	    struct compound_state *, cs);
    403   6741  th199096 }
    404   6741  th199096 
    405   6741  th199096 /*ARGSUSED*/
    406   6741  th199096 static void
    407   8023       Sam nullfree(nfs_resop4 *resop, compound_state_t *cs)
    408   8023       Sam {
    409   8023       Sam }
    410   8023       Sam 
    411   8023       Sam static op_disp_tbl_t mds_disptab[] = {
    412   6741  th199096 	{mds_op_illegal, nullfree, DISP_OP_BAD, "BAD Op 0"},
    413   6741  th199096 	{mds_op_illegal, nullfree, DISP_OP_BAD, "BAD Op 1"},
    414   6741  th199096 	{mds_op_illegal, nullfree, DISP_OP_BAD, "BAD Op 2"},
    415   6741  th199096 	{mds_op_access, nullfree, DISP_OP_MDS, "ACCESS"},
    416   6741  th199096 	{mds_op_close, nullfree, DISP_OP_MDS, "CLOSE"},
    417   8023       Sam 	{mds_op_commit, nullfree, DISP_OP_BOTH, "COMMIT"},
    418   6741  th199096 	{mds_op_create, nullfree, DISP_OP_MDS, "CREATE"},
    419   6741  th199096 	{mds_op_inval, nullfree, DISP_OP_BAD, "BAD Op 7"},
    420   6741  th199096 	{mds_op_delegreturn, nullfree, DISP_OP_MDS, "DELEGRETURN"},
    421   6741  th199096 	{mds_op_getattr, mds_op_getattr_free, DISP_OP_MDS, "GETATTR"},
    422   6741  th199096 	{mds_op_getfh, mds_op_getfh_free, DISP_OP_MDS, "GETFH"},
    423   6741  th199096 	{mds_op_link, nullfree, DISP_OP_MDS, "LINK"},
    424   6741  th199096 	{mds_op_lock, mds_lock_denied_free, DISP_OP_MDS, "LOCK"},
    425   6741  th199096 	{mds_op_lockt, mds_lock_denied_free,  DISP_OP_MDS, "LOCKT"},
    426   6741  th199096 	{mds_op_locku, nullfree,  DISP_OP_MDS, "LOCKU"},
    427   6741  th199096 	{mds_op_lookup, nullfree,  DISP_OP_MDS, "LOOKUP"},
    428   6741  th199096 	{mds_op_lookupp, nullfree,  DISP_OP_MDS, "LOOKUPP"},
    429   6741  th199096 	{mds_op_nverify, nullfree,  DISP_OP_MDS, "NVERIFY"},
    430   6741  th199096 	{mds_op_open, mds_free_reply,  DISP_OP_MDS, "OPEN"},
    431   6741  th199096 	{mds_op_openattr, nullfree,  DISP_OP_MDS, "OPENATTR"},
    432   6741  th199096 	{mds_op_notsup, nullfree,  DISP_OP_BAD, "BAD Op 20"},
    433   6741  th199096 	{mds_op_open_downgrade, nullfree,  DISP_OP_MDS, "OPEN_DOWNGRADE"},
    434   8023       Sam 	{mds_op_putfh, nullfree, DISP_OP_BOTH, "PUTFH"},
    435   6741  th199096 	{mds_op_putpubfh, nullfree,  DISP_OP_MDS, "PUTPUBFH"},
    436   6741  th199096 	{mds_op_putrootfh, nullfree,  DISP_OP_MDS, "PUTROOTFH"},
    437   8023       Sam 	{mds_op_read, mds_op_read_free, DISP_OP_BOTH, "READ"},
    438   6741  th199096 	{mds_op_readdir, mds_op_readdir_free,  DISP_OP_MDS, "READDIR"},
    439   6741  th199096 	{mds_op_readlink, mds_op_readlink_free,  DISP_OP_MDS, "READLINK"},
    440   6741  th199096 	{mds_op_remove, nullfree,  DISP_OP_MDS, "REMOVE"},
    441   6741  th199096 	{mds_op_rename, nullfree,  DISP_OP_MDS, "RENAME"},
    442   6741  th199096 	{mds_op_notsup, nullfree,  DISP_OP_BAD, "BAD Op 30"},
    443   6741  th199096 	{mds_op_restorefh, nullfree,  DISP_OP_MDS, "RESTOREFH"},
    444   6741  th199096 	{mds_op_savefh, nullfree,  DISP_OP_MDS, "SAVEFH"},
    445   6741  th199096 	{mds_op_secinfo, mds_op_secinfo_free,  DISP_OP_MDS, "SECINFO"},
    446   6741  th199096 	{mds_op_setattr, nullfree,  DISP_OP_MDS, "SETATTR"},
    447   6741  th199096 	{mds_op_notsup, nullfree,  DISP_OP_BAD, "BAD Op 35"},
    448   6741  th199096 	{mds_op_notsup, nullfree,  DISP_OP_BAD, "BAD Op 36"},
    449   6741  th199096 	{mds_op_verify, nullfree,  DISP_OP_MDS, "VERIFY"},
    450   8023       Sam 	{mds_op_write, nullfree, DISP_OP_BOTH, "WRITE"},
    451   6741  th199096 	{mds_op_notsup, nullfree,  DISP_OP_BAD, "BAD Op 39"},
    452   6741  th199096 	{mds_op_backchannel_ctl, nullfree,  DISP_OP_BOTH, "BACKCHANNEL_CTL"},
    453   6741  th199096 	{mds_op_bind_conn_to_session, nullfree,
    454   6741  th199096 	    DISP_OP_BOTH, "BIND_CONN_TO_SESS"},
    455   9396      rick 	{mds_op_exchange_id, mds_op_exid_free,  DISP_OP_BOTH, "EXCHANGE_ID"},
    456   6741  th199096 	{mds_op_create_session, nullfree,  DISP_OP_BOTH, "CREATE_SESS"},
    457   6741  th199096 	{mds_op_destroy_session, nullfree,  DISP_OP_BOTH, "DESTROY_SESS"},
    458   6741  th199096 	{mds_op_illegal, nullfree,  DISP_OP_MDS, "FREE_STATEID"},
    459   6741  th199096 	{mds_op_illegal, nullfree,  DISP_OP_MDS, "GET_DIR_DELEG"},
    460   6741  th199096 	{mds_op_get_devinfo, nullfree,  DISP_OP_MDS, "GET_DEVINFO"},
    461   6741  th199096 	{mds_op_get_devlist, nullfree,  DISP_OP_MDS, "GET_DEVLIST"},
    462   6741  th199096 	{mds_op_layout_commit, nullfree,  DISP_OP_MDS, "LAYOUT_COMMIT"},
    463   9106    Piyush 	{mds_op_layout_get, mds_op_layout_get_free,  DISP_OP_MDS, "LAYOUT_GET"},
    464   6741  th199096 	{mds_op_layout_return, nullfree,  DISP_OP_MDS, "LAYOUT_RETURN"},
    465   8023       Sam 	{mds_op_secinfonn, nullfree,
    466   6741  th199096 	    DISP_OP_BOTH, "SECINFO_NONAME"},
    467   6741  th199096 	{mds_op_sequence, nullfree,  DISP_OP_BOTH, "SEQUENCE"},
    468   6741  th199096 	{mds_op_notsup, nullfree,  DISP_OP_BOTH, "SET_SSV"},
    469   6741  th199096 	{mds_op_notsup, nullfree,  DISP_OP_MDS, "TEST_STATEID"},
    470   6741  th199096 	{mds_op_notsup, nullfree,  DISP_OP_MDS, "WANT_DELEG"},
    471   6741  th199096 	{mds_op_notsup, nullfree,  DISP_OP_BOTH, "DESTROY_CLIENTID"},
    472   7739   jwahlig 	{mds_op_reclaim_complete, nullfree,  DISP_OP_MDS, "RECLAIM_COMPLETE"}
    473   6741  th199096 };
    474   6741  th199096 
    475   6741  th199096 static uint_t mds_disp_cnt = sizeof (mds_disptab) / sizeof (mds_disptab[0]);
    476   6741  th199096 
    477   6741  th199096 #define	OP_ILLEGAL_IDX (mds_disp_cnt)
    478   6741  th199096 
    479   6741  th199096 extern size_t strlcpy(char *dst, const char *src, size_t dstsize);
    480   6741  th199096 
    481   6741  th199096 #ifdef	nextdp
    482   6741  th199096 #undef nextdp
    483   6741  th199096 #endif
    484   6741  th199096 #define	nextdp(dp)	((struct dirent64 *)((char *)(dp) + (dp)->d_reclen))
    485   6741  th199096 
    486   8023       Sam /*ARGSUSED*/
    487   8023       Sam static void
    488   8023       Sam mds_op_readdir_free(nfs_resop4 *resop, compound_state_t *cs)
    489   6741  th199096 {
    490   6741  th199096 	/* Common function used for NFSv4.0 and NFSv4.1 */
    491   6741  th199096 	rfs4_op_readdir_free(resop);
    492   6741  th199096 }
    493   6741  th199096 
    494   6741  th199096 /*ARGSUSED*/
    495   6741  th199096 static void
    496   8023       Sam mds_op_secinfo_free(nfs_resop4 *resop, compound_state_t *cs)
    497   6741  th199096 {
    498   6741  th199096 	/* Common function used for NFSv4.0 and NFSv4.1 */
    499   6741  th199096 	rfs4_op_secinfo_free(resop);
    500   6741  th199096 }
    501   6741  th199096 
    502   6741  th199096 /*
    503   6741  th199096  */
    504   6741  th199096 void
    505   6741  th199096 mds_srvrfini(void)
    506   6741  th199096 {
    507   6741  th199096 	/* some shutdown stuff for the minor verson 1 server */
    508   6741  th199096 }
    509   6741  th199096 
    510   6741  th199096 nfsstat4	rfs4_state_has_access(rfs4_state_t *, int, vnode_t *);
    511   6741  th199096 int		rfs4_verify_attr(struct nfs4_svgetit_arg *, attrmap4 *,
    512   6741  th199096 		    struct nfs4_ntov_table *);
    513   6741  th199096 
    514   6741  th199096 
    515   6741  th199096 /*
    516   6741  th199096  * Given the I/O mode (FREAD or FWRITE), the vnode, the stateid and whether
    517   6741  th199096  * the file is being truncated, return NFS4_OK if allowed or approriate
    518   6741  th199096  * V4 error if not. Note NFS4ERR_DELAY will be returned and a recall on
    519   6741  th199096  * the associated file will be done if the I/O is not consistent with any
    520   6741  th199096  * delegation in effect on the file. Should be holding VOP_RWLOCK, either
    521   6741  th199096  * as reader or writer as appropriate. rfs4_op_open will accquire the
    522   6741  th199096  * VOP_RWLOCK as writer when setting up delegation. If the stateid is bad
    523   6741  th199096  * this routine will return NFS4ERR_BAD_STATEID. In addition, through the
    524   6741  th199096  * deleg parameter, we will return whether a write delegation is held by
    525   6741  th199096  * the client associated with this stateid.
    526   6741  th199096  * If the server instance associated with the relevant client is in its
    527   6741  th199096  * grace period, return NFS4ERR_GRACE.
    528   6741  th199096  */
    529   6741  th199096 nfsstat4
    530   6741  th199096 mds_validate_stateid(int mode, struct compound_state *cs, vnode_t *vp,
    531   6741  th199096     stateid4 *stateid, bool_t trunc, bool_t *deleg, bool_t do_access)
    532   6741  th199096 {
    533   6741  th199096 	rfs4_file_t *fp;
    534   6741  th199096 	bool_t create = FALSE;
    535   6741  th199096 	rfs4_state_t *sp;
    536   6741  th199096 	rfs4_deleg_state_t *dsp;
    537   6741  th199096 	rfs4_lo_state_t *lsp;
    538   6741  th199096 	stateid_t *id = (stateid_t *)stateid;
    539   6741  th199096 	nfsstat4 stat = NFS4_OK;
    540   6741  th199096 
    541   6741  th199096 	if (ISSPECIAL(stateid)) {
    542   7739   jwahlig 		fp = rfs4_findfile(cs->instp, vp, NULL, &create);
    543   6741  th199096 		if (fp == NULL)
    544   6741  th199096 			return (NFS4_OK);
    545  10447    Thomas 		if (fp->rf_dinfo->rd_dtype == OPEN_DELEGATE_NONE) {
    546   6741  th199096 			rfs4_file_rele(fp);
    547   6741  th199096 			return (NFS4_OK);
    548   6741  th199096 		}
    549   6741  th199096 		if (mode == FWRITE ||
    550  10447    Thomas 		    fp->rf_dinfo->rd_dtype == OPEN_DELEGATE_WRITE) {
    551   6741  th199096 			rfs4_recall_deleg(fp, trunc, NULL);
    552   6741  th199096 			rfs4_file_rele(fp);
    553   6741  th199096 			return (NFS4ERR_DELAY);
    554   6741  th199096 		}
    555   6741  th199096 		rfs4_file_rele(fp);
    556   6741  th199096 		return (NFS4_OK);
    557   6741  th199096 	}
    558   6741  th199096 
    559   6741  th199096 	stat = rfs4_get_all_state(cs, stateid, &sp, &dsp, &lsp);
    560   6741  th199096 	if (stat != NFS4_OK)
    561   6741  th199096 		return (stat);
    562   6741  th199096 
    563   6741  th199096 	/*
    564   6741  th199096 	 * Ordering of the following 'if' statements is specific
    565   6741  th199096 	 * since rfs4_get_all_state() may return a value for sp and
    566   6741  th199096 	 * lsp. First we check lsp, then 'fall' through to sp.
    567   6741  th199096 	 */
    568   6741  th199096 	if (lsp != NULL) {
    569   6741  th199096 		/* Is associated server instance in its grace period? */
    570  10447    Thomas 		if (rfs4_clnt_in_grace(lsp->rls_locker->rl_client)) {
    571   6741  th199096 			rfs4_lo_state_rele(lsp, FALSE);
    572   6741  th199096 			if (sp != NULL)
    573  10447    Thomas 				rfs4_dbe_rele(sp->rs_dbe);
    574   6741  th199096 			return (NFS4ERR_GRACE);
    575   6741  th199096 		}
    576   6741  th199096 
    577  10447    Thomas 		if (lsp->rls_lockid.v41_bits.chgseq != 0) {
    578   6741  th199096 			/* Seqid in the future? - that's bad */
    579  10447    Thomas 			if (lsp->rls_lockid.v41_bits.chgseq <
    580   6741  th199096 			    id->v41_bits.chgseq) {
    581   6741  th199096 				rfs4_lo_state_rele(lsp, FALSE);
    582   6741  th199096 				if (sp != NULL)
    583  10447    Thomas 					rfs4_dbe_rele(sp->rs_dbe);
    584   6741  th199096 				return (NFS4ERR_BAD_STATEID);
    585   6741  th199096 			}
    586   6741  th199096 			/* Seqid in the past? - that's old */
    587  10447    Thomas 			if (lsp->rls_lockid.v41_bits.chgseq >
    588   6741  th199096 			    id->v41_bits.chgseq) {
    589   6741  th199096 				rfs4_lo_state_rele(lsp, FALSE);
    590   6741  th199096 				if (sp != NULL)
    591  10447    Thomas 					rfs4_dbe_rele(sp->rs_dbe);
    592   6741  th199096 				return (NFS4ERR_OLD_STATEID);
    593   6741  th199096 			}
    594   6741  th199096 		}
    595   6741  th199096 
    596   6741  th199096 		/* Ensure specified filehandle matches */
    597  10447    Thomas 		if (lsp->rls_state->rs_finfo->rf_vp != vp) {
    598   6741  th199096 			rfs4_lo_state_rele(lsp, FALSE);
    599   6741  th199096 			if (sp != NULL)
    600  10447    Thomas 				rfs4_dbe_rele(sp->rs_dbe);
    601   6741  th199096 			return (NFS4ERR_BAD_STATEID);
    602   6741  th199096 		}
    603   6741  th199096 		rfs4_lo_state_rele(lsp, FALSE);
    604   6741  th199096 	}
    605   6741  th199096 
    606   6741  th199096 	/*
    607   6741  th199096 	 * Stateid provided was an "open" or via the lock stateid
    608   6741  th199096 	 */
    609   6741  th199096 	if (sp != NULL) {
    610   6741  th199096 		/*
    611   6741  th199096 		 * only check if the passed in stateid was an OPENID,
    612   6741  th199096 		 * ie. Skip if we got here via the LOCKID.
    613   6741  th199096 		 */
    614   6741  th199096 		if (id->v41_bits.type == OPENID) {
    615   6741  th199096 			/* Is associated server instance in its grace period? */
    616  10447    Thomas 			if (rfs4_clnt_in_grace(sp->rs_owner->ro_client)) {
    617  10447    Thomas 				rfs4_dbe_rele(sp->rs_dbe);
    618   6741  th199096 				return (NFS4ERR_GRACE);
    619   6741  th199096 			}
    620   6741  th199096 
    621  10447    Thomas 			if (sp->rs_stateid.v41_bits.chgseq != 0) {
    622   6741  th199096 				/* Seqid in the future? - that's bad */
    623  10447    Thomas 				if (sp->rs_stateid.v41_bits.chgseq <
    624   6741  th199096 				    id->v41_bits.chgseq) {
    625  10447    Thomas 					rfs4_dbe_rele(sp->rs_dbe);
    626   6741  th199096 					return (NFS4ERR_BAD_STATEID);
    627   6741  th199096 				}
    628   6741  th199096 				/* Seqid in the past - that's old */
    629  10447    Thomas 				if (sp->rs_stateid.v41_bits.chgseq >
    630   6741  th199096 				    id->v41_bits.chgseq) {
    631  10447    Thomas 					rfs4_dbe_rele(sp->rs_dbe);
    632   6741  th199096 					return (NFS4ERR_OLD_STATEID);
    633   6741  th199096 				}
    634   6741  th199096 			}
    635   6741  th199096 
    636   6741  th199096 			/* Ensure specified filehandle matches */
    637  10447    Thomas 			if (sp->rs_finfo->rf_vp != vp) {
    638  10447    Thomas 				rfs4_dbe_rele(sp->rs_dbe);
    639   6741  th199096 				return (NFS4ERR_BAD_STATEID);
    640   6741  th199096 			}
    641   6741  th199096 		}
    642  10447    Thomas 		if (sp->rs_owner->ro_need_confirm) {
    643  10447    Thomas 			rfs4_dbe_rele(sp->rs_dbe);
    644   6741  th199096 			return (NFS4ERR_BAD_STATEID);
    645   6741  th199096 		}
    646   6741  th199096 
    647  10447    Thomas 		if (sp->rs_closed == TRUE) {
    648  10447    Thomas 			rfs4_dbe_rele(sp->rs_dbe);
    649   6741  th199096 			return (NFS4ERR_OLD_STATEID);
    650   6741  th199096 		}
    651   6741  th199096 
    652   6741  th199096 		if (do_access)
    653   6741  th199096 			stat = rfs4_state_has_access(sp, mode, vp);
    654   6741  th199096 		else
    655   6741  th199096 			stat = NFS4_OK;
    656   6741  th199096 
    657   6741  th199096 		/*
    658   6741  th199096 		 * Return whether this state has write
    659   6741  th199096 		 * delegation if desired
    660   6741  th199096 		 */
    661   6741  th199096 		if (deleg &&
    662  10447    Thomas 		    (sp->rs_finfo->rf_dinfo->rd_dtype == OPEN_DELEGATE_WRITE))
    663   6741  th199096 			*deleg = TRUE;
    664   6741  th199096 
    665   6741  th199096 		/*
    666   6741  th199096 		 * We got a valid stateid, so we update the
    667   6741  th199096 		 * lease on the client. Ideally we would like
    668   6741  th199096 		 * to do this after the calling op succeeds,
    669   6741  th199096 		 * but for now this will be good
    670   6741  th199096 		 * enough. Callers of this routine are
    671   6741  th199096 		 * currently insulated from the state stuff.
    672   6741  th199096 		 */
    673  10447    Thomas 		rfs4_update_lease(sp->rs_owner->ro_client);
    674   6741  th199096 
    675   6741  th199096 		/*
    676   6741  th199096 		 * If a delegation is present on this file and
    677   6741  th199096 		 * this is a WRITE, then update the lastwrite
    678   6741  th199096 		 * time to indicate that activity is present.
    679   6741  th199096 		 */
    680  10447    Thomas 		if (sp->rs_finfo->rf_dinfo->rd_dtype == OPEN_DELEGATE_WRITE &&
    681   6741  th199096 		    mode == FWRITE) {
    682  10447    Thomas 			sp->rs_finfo->rf_dinfo->rd_time_lastwrite =
    683   6741  th199096 			    gethrestime_sec();
    684   6741  th199096 		}
    685   6741  th199096 
    686  10447    Thomas 		rfs4_dbe_rele(sp->rs_dbe);
    687   6741  th199096 		return (stat);
    688   6741  th199096 	}
    689   6741  th199096 
    690   6741  th199096 	if (dsp != NULL) {
    691   6741  th199096 		/* Is associated server instance in its grace period? */
    692  10447    Thomas 		if (rfs4_clnt_in_grace(dsp->rds_client)) {
    693   6741  th199096 			rfs4_deleg_state_rele(dsp);
    694   6741  th199096 			return (NFS4ERR_GRACE);
    695   6741  th199096 		}
    696   6741  th199096 
    697  10447    Thomas 		if ((dsp->rds_delegid.v41_bits.chgseq != 0) &&
    698  10447    Thomas 		    (dsp->rds_delegid.v41_bits.chgseq != id->v41_bits.chgseq)) {
    699   6741  th199096 			rfs4_deleg_state_rele(dsp);
    700   6741  th199096 			return (NFS4ERR_BAD_STATEID);
    701   6741  th199096 		}
    702   6741  th199096 
    703   6741  th199096 		/* Ensure specified filehandle matches */
    704  10447    Thomas 		if (dsp->rds_finfo->rf_vp != vp) {
    705   6741  th199096 			rfs4_deleg_state_rele(dsp);
    706   6741  th199096 			return (NFS4ERR_BAD_STATEID);
    707   6741  th199096 		}
    708   6741  th199096 		/*
    709   6741  th199096 		 * Return whether this state has write
    710   6741  th199096 		 * delegation if desired
    711   6741  th199096 		 */
    712   6741  th199096 		if (deleg &&
    713  10447    Thomas 		    (dsp->rds_finfo->rf_dinfo->rd_dtype == OPEN_DELEGATE_WRITE))
    714   6741  th199096 			*deleg = TRUE;
    715   6741  th199096 
    716  10447    Thomas 		rfs4_update_lease(dsp->rds_client);
    717   6741  th199096 
    718   6741  th199096 		/*
    719   6741  th199096 		 * If a delegation is present on this file and
    720   6741  th199096 		 * this is a WRITE, then update the lastwrite
    721   6741  th199096 		 * time to indicate that activity is present.
    722   6741  th199096 		 */
    723  10447    Thomas 		if (dsp->rds_finfo->rf_dinfo->rd_dtype == OPEN_DELEGATE_WRITE &&
    724   6741  th199096 		    mode == FWRITE) {
    725  10447    Thomas 			dsp->rds_finfo->rf_dinfo->rd_time_lastwrite =
    726   6741  th199096 			    gethrestime_sec();
    727   6741  th199096 		}
    728   6741  th199096 
    729   6741  th199096 		/*
    730   6741  th199096 		 * XXX - what happens if this is a WRITE and the
    731   6741  th199096 		 * delegation type of for READ.
    732   6741  th199096 		 */
    733   6741  th199096 		rfs4_deleg_state_rele(dsp);
    734   6741  th199096 
    735   6741  th199096 		return (stat);
    736   6741  th199096 	}
    737   6741  th199096 	/*
    738   6741  th199096 	 * If we got this far, something bad happened
    739   6741  th199096 	 */
    740   6741  th199096 	return (NFS4ERR_BAD_STATEID);
    741   6741  th199096 }
    742   6741  th199096 
    743   6741  th199096 nfsstat4
    744   6741  th199096 mds_setattr(attrmap4 *resp, fattr4 *fattrp, struct compound_state *cs,
    745   6741  th199096     stateid4 *stateid)
    746   6741  th199096 {
    747   6741  th199096 	int error = 0;
    748   6741  th199096 	struct nfs4_svgetit_arg sarg;
    749   6741  th199096 	bool_t trunc;
    750   6741  th199096 
    751   6741  th199096 	nfsstat4 status = NFS4_OK;
    752   6741  th199096 	cred_t *cr = cs->cr;
    753   6741  th199096 	vnode_t *vp = cs->vp;
    754   6741  th199096 	struct nfs4_ntov_table ntov;
    755   6741  th199096 	struct statvfs64 sb;
    756   6741  th199096 	struct vattr bva;
    757   6741  th199096 	struct flock64 bf;
    758   6741  th199096 	int in_crit = 0;
    759   6741  th199096 	uint_t saved_mask = 0;
    760   6741  th199096 	caller_context_t ct;
    761   6741  th199096 	attrvers_t avers;
    762   6741  th199096 	struct nfs4_ntov_map *nvmap;
    763   6741  th199096 
    764   6741  th199096 	avers = RFS4_ATTRVERS(cs);
    765   6741  th199096 	nvmap = NFS4_NTOV_MAP(avers);
    766   6741  th199096 	*resp = NFS4_EMPTY_ATTRMAP(avers);
    767   6741  th199096 	sarg.sbp = &sb;
    768   6741  th199096 	nfs4_ntov_table_init(&ntov, avers);
    769   6741  th199096 	status = do_rfs4_set_attrs(resp, fattrp, cs, &sarg, &ntov,
    770   6741  th199096 	    NFS4ATTR_SETIT);
    771   6741  th199096 	if (status != NFS4_OK) {
    772   6741  th199096 		/*
    773   6741  th199096 		 * failed set attrs
    774   6741  th199096 		 */
    775   6741  th199096 		goto done;
    776   6741  th199096 	}
    777   6741  th199096 
    778   6741  th199096 	if (sarg.vap->va_mask == 0 && ! ATTR_ISSET(fattrp->attrmask, ACL) &&
    779   6741  th199096 	    ! ATTR_ISSET(fattrp->attrmask, LAYOUT_HINT)) {
    780   6741  th199096 		/*
    781   6741  th199096 		 * no further work to be done
    782   6741  th199096 		 */
    783   6741  th199096 		goto done;
    784   6741  th199096 	}
    785   6741  th199096 
    786   6741  th199096 	ct.cc_sysid = 0;
    787   6741  th199096 	ct.cc_pid = 0;
    788   7739   jwahlig 	ct.cc_caller_id = cs->instp->caller_id;
    789   7739   jwahlig 	ct.cc_flags = CC_DONTBLOCK;
    790   6741  th199096 
    791   6741  th199096 	/*
    792   6741  th199096 	 * If we got a request to set the ACL and the MODE, only
    793   6741  th199096 	 * allow changing VSUID, VSGID, and VSVTX.  Attempting
    794   6741  th199096 	 * to change any other bits, along with setting an ACL,
    795   6741  th199096 	 * gives NFS4ERR_INVAL.
    796   6741  th199096 	 */
    797   6741  th199096 	if (ATTR_ISSET(fattrp->attrmask, ACL) &&
    798   6741  th199096 	    ATTR_ISSET(fattrp->attrmask, MODE)) {
    799   6741  th199096 		vattr_t va;
    800   6741  th199096 
    801   6741  th199096 		va.va_mask = AT_MODE;
    802   6741  th199096 		error = VOP_GETATTR(vp, &va, 0, cs->cr, &ct);
    803   6741  th199096 		if (error) {
    804   6741  th199096 			status = puterrno4(error);
    805   6741  th199096 			goto done;
    806   6741  th199096 		}
    807   6741  th199096 		if ((sarg.vap->va_mode ^ va.va_mode) &
    808   6741  th199096 		    ~(VSUID | VSGID | VSVTX)) {
    809   6741  th199096 			status = NFS4ERR_INVAL;
    810   6741  th199096 			goto done;
    811   6741  th199096 		}
    812   6741  th199096 	}
    813   6741  th199096 
    814   6741  th199096 	/* Check stateid only if size has been set */
    815   6741  th199096 	if (sarg.vap->va_mask & AT_SIZE) {
    816   6741  th199096 		trunc = (sarg.vap->va_size == 0);
    817   6741  th199096 		status = mds_validate_stateid(FWRITE,
    818   6741  th199096 		    cs, cs->vp, stateid, trunc,
    819   6741  th199096 		    &cs->deleg, sarg.vap->va_mask & AT_SIZE);
    820   6741  th199096 		if (status != NFS4_OK)
    821   6741  th199096 			goto done;
    822   6741  th199096 	}
    823   6741  th199096 
    824   6741  th199096 	/* XXX start of possible race with delegations */
    825   6741  th199096 
    826   6741  th199096 	/*
    827   6741  th199096 	 * We need to specially handle size changes because it is
    828   6741  th199096 	 * possible for the client to create a file with read-only
    829   6741  th199096 	 * modes, but with the file opened for writing. If the client
    830   6741  th199096 	 * then tries to set the file size, e.g. ftruncate(3C),
    831   6741  th199096 	 * fcntl(F_FREESP), the normal access checking done in
    832   6741  th199096 	 * VOP_SETATTR would prevent the client from doing it even though
    833   6741  th199096 	 * it should be allowed to do so.  To get around this, we do the
    834   6741  th199096 	 * access checking for ourselves and use VOP_SPACE which doesn't
    835   6741  th199096 	 * do the access checking.
    836   6741  th199096 	 * Also the client should not be allowed to change the file
    837   6741  th199096 	 * size if there is a conflicting non-blocking mandatory lock in
    838   6741  th199096 	 * the region of the change.
    839   6741  th199096 	 */
    840   6741  th199096 	if (vp->v_type == VREG && (sarg.vap->va_mask & AT_SIZE)) {
    841   6741  th199096 		u_offset_t offset;
    842   6741  th199096 		ssize_t length;
    843   6741  th199096 
    844   6741  th199096 		/*
    845   6741  th199096 		 * ufs_setattr clears AT_SIZE from vap->va_mask, but
    846   6741  th199096 		 * before returning, sarg.vap->va_mask is used to
    847   6741  th199096 		 * generate the setattr reply bitmap.  We also clear
    848   6741  th199096 		 * AT_SIZE below before calling VOP_SPACE.  For both
    849   6741  th199096 		 * of these cases, the va_mask needs to be saved here
    850   6741  th199096 		 * and restored after calling VOP_SETATTR.
    851   6741  th199096 		 */
    852   6741  th199096 		saved_mask = sarg.vap->va_mask;
    853   6741  th199096 
    854   6741  th199096 		/*
    855   6741  th199096 		 * Check any possible conflict due to NBMAND locks.
    856   6741  th199096 		 * Get into critical region before VOP_GETATTR, so the
    857   6741  th199096 		 * size attribute is valid when checking conflicts.
    858   6741  th199096 		 */
    859   6741  th199096 		if (nbl_need_check(vp)) {
    860   6741  th199096 			nbl_start_crit(vp, RW_READER);
    861   6741  th199096 			in_crit = 1;
    862   6741  th199096 		}
    863   6741  th199096 
    864   6741  th199096 		bva.va_mask = AT_UID|AT_SIZE;
    865   6741  th199096 		if (error = VOP_GETATTR(vp, &bva, 0, cr, &ct)) {
    866   6741  th199096 			status = puterrno4(error);
    867   6741  th199096 			goto done;
    868   6741  th199096 		}
    869   6741  th199096 
    870   6741  th199096 		if (in_crit) {
    871   6741  th199096 			if (sarg.vap->va_size < bva.va_size) {
    872   6741  th199096 				offset = sarg.vap->va_size;
    873   6741  th199096 				length = bva.va_size - sarg.vap->va_size;
    874   6741  th199096 			} else {
    875   6741  th199096 				offset = bva.va_size;
    876   6741  th199096 				length = sarg.vap->va_size - bva.va_size;
    877   6741  th199096 			}
    878   6741  th199096 			if (nbl_conflict(vp, NBL_WRITE, offset, length, 0,
    879   6741  th199096 			    &ct)) {
    880   6741  th199096 				status = NFS4ERR_LOCKED;
    881   6741  th199096 				goto done;
    882   6741  th199096 			}
    883   6741  th199096 		}
    884   6741  th199096 
    885   6741  th199096 		if (crgetuid(cr) == bva.va_uid) {
    886   6741  th199096 			sarg.vap->va_mask &= ~AT_SIZE;
    887   6741  th199096 			bf.l_type = F_WRLCK;
    888   6741  th199096 			bf.l_whence = 0;
    889   6741  th199096 			bf.l_start = (off64_t)sarg.vap->va_size;
    890   6741  th199096 			bf.l_len = 0;
    891   6741  th199096 			bf.l_sysid = 0;
    892   6741  th199096 			bf.l_pid = 0;
    893   6741  th199096 			error = VOP_SPACE(vp, F_FREESP, &bf, FWRITE,
    894   6741  th199096 			    (offset_t)sarg.vap->va_size, cr, &ct);
    895   6741  th199096 		}
    896   6741  th199096 	}
    897   6741  th199096 
    898   6741  th199096 	if (!error && sarg.vap->va_mask != 0)
    899   6741  th199096 		error = VOP_SETATTR(vp, sarg.vap, sarg.flag, cr, &ct);
    900   6741  th199096 
    901   6741  th199096 	/* restore va_mask -- ufs_setattr clears AT_SIZE */
    902   6741  th199096 	if (saved_mask & AT_SIZE)
    903   6741  th199096 		sarg.vap->va_mask |= AT_SIZE;
    904   6741  th199096 
    905   6741  th199096 	/*
    906   6741  th199096 	 * If an ACL was being set, it has been delayed until now,
    907   6741  th199096 	 * in order to set the mode (via the VOP_SETATTR() above) first.
    908   6741  th199096 	 */
    909   6741  th199096 	if (! error && ATTR_ISSET(fattrp->attrmask, ACL)) {
    910   6741  th199096 		int i;
    911   6741  th199096 
    912   6741  th199096 		for (i = 0; i < ntov.attrcnt; i++)
    913   6741  th199096 			if (ntov.amap[i] == FATTR4_ACL)
    914   6741  th199096 				break;
    915   6741  th199096 		if (i < ntov.attrcnt) {
    916   6741  th199096 			error = (*nvmap[FATTR4_ACL].sv_getit)(NFS4ATTR_SETIT,
    917   6741  th199096 			    &sarg, &ntov.na[i]);
    918   6741  th199096 			if (error == 0) {
    919   6741  th199096 				ATTR_SET(*resp, ACL);
    920   6741  th199096 			} else if (error == ENOTSUP) {
    921   6741  th199096 				(void) rfs4_verify_attr(&sarg, resp, &ntov);
    922   6741  th199096 				status = NFS4ERR_ATTRNOTSUPP;
    923   6741  th199096 				goto done;
    924   6741  th199096 			}
    925   6741  th199096 		} else {
    926   6741  th199096 			error = EINVAL;
    927   6741  th199096 		}
    928   6741  th199096 	}
    929   6741  th199096 
    930   6741  th199096 	if (! error && ATTR_ISSET(fattrp->attrmask, LAYOUT_HINT)) {
    931   6741  th199096 		/*
    932   6741  th199096 		 * Store layout hint.  Layout hint will be stored
    933   6741  th199096 		 * in file struct (which means it can only be set
    934   6741  th199096 		 * when the file is open).  If layout hint is allowed
    935   6741  th199096 		 * for files not open, then it must be stored
    936   6741  th199096 		 * persistently.
    937   6741  th199096 		 *
    938   6741  th199096 		 * status assignment placates lint.  it will
    939   6741  th199096 		 * be replaced with code to store the layout
    940   6741  th199096 		 * hint.
    941   6741  th199096 		 */
    942   6741  th199096 		status = NFS4_OK;
    943   6741  th199096 	}
    944   6741  th199096 
    945   6741  th199096 	if (error) {
    946   6741  th199096 		/* check if a monitor detected a delegation conflict */
    947   6741  th199096 		if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK))
    948   6741  th199096 			status = NFS4ERR_DELAY;
    949   6741  th199096 		else
    950   6741  th199096 			status = puterrno4(error);
    951   6741  th199096 
    952   6741  th199096 		/*
    953   6741  th199096 		 * Set the response bitmap when setattr failed.
    954   6741  th199096 		 * If VOP_SETATTR partially succeeded, test by doing a
    955   6741  th199096 		 * VOP_GETATTR on the object and comparing the data
    956   6741  th199096 		 * to the setattr arguments.
    957   6741  th199096 		 */
    958   6741  th199096 		(void) rfs4_verify_attr(&sarg, resp, &ntov);
    959   6741  th199096 	} else {
    960   6741  th199096 		/*
    961   6741  th199096 		 * Force modified metadata out to stable storage.
    962   6741  th199096 		 */
    963   6741  th199096 		(void) VOP_FSYNC(vp, FNODSYNC, cr, &ct);
    964   6741  th199096 		/*
    965   6741  th199096 		 * Set response bitmap
    966   6741  th199096 		 */
    967   6741  th199096 		nfs4_vmask_to_nmask_set(sarg.vap->va_mask, resp);
    968   6741  th199096 	}
    969   6741  th199096 
    970   6741  th199096 	/* Return early and already have a NFSv4 error */
    971   6741  th199096 done:
    972   6741  th199096 	/*
    973   6741  th199096 	 * Except for nfs4_vmask_to_nmask_set(), vattr --> fattr
    974   6741  th199096 	 * conversion sets both readable and writeable NFS4 attrs
    975   6741  th199096 	 * for AT_MTIME and AT_ATIME.  The line below masks out
    976   6741  th199096 	 * unrequested attrs from the setattr result bitmap.  This
    977   6741  th199096 	 * is placed after the done: label to catch the ATTRNOTSUP
    978   6741  th199096 	 * case.
    979   6741  th199096 	 */
    980   6741  th199096 	ATTRMAP_MASK(*resp, fattrp->attrmask);
    981   6741  th199096 
    982   6741  th199096 	if (in_crit)
    983   6741  th199096 		nbl_end_crit(vp);
    984   6741  th199096 
    985   6741  th199096 	nfs4_ntov_table_free(&ntov, &sarg);
    986   6741  th199096 
    987   6741  th199096 	return (status);
    988   6741  th199096 }
    989   6741  th199096 
    990   6741  th199096 /* ARGSUSED */
    991   6741  th199096 void
    992   6741  th199096 mds_op_secinfonn(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
    993   8023       Sam     compound_state_t *cs)
    994   8023       Sam {
    995   6741  th199096 	SECINFO_NO_NAME4res *respnn;
    996   6741  th199096 	int dotdot;
    997   6741  th199096 
    998   7312    Danhua 	DTRACE_NFSV4_1(op__secinfo__no__name__start,
    999   7312    Danhua 	    struct compound_state *, cs);
   1000   7312    Danhua 
   1001   6741  th199096 	respnn = &resop->nfs_resop4_u.opsecinfo_no_name;
   1002   6741  th199096 
   1003   6741  th199096 	/*
   1004   6741  th199096 	 * Current file handle (cfh) should have been set before
   1005   6741  th199096 	 * getting into this function. If not, return error.
   1006   6741  th199096 	 */
   1007   6741  th199096 	if (cs->vp == NULL) {
   1008   6741  th199096 		*cs->statusp = respnn->status = NFS4ERR_NOFILEHANDLE;
   1009   7312    Danhua 		goto final;
   1010   6741  th199096 	}
   1011   6741  th199096 
   1012   6741  th199096 	dotdot =
   1013   6741  th199096 	    (argop->nfs_argop4_u.opsecinfo_no_name == SECINFO_STYLE4_PARENT);
   1014   6741  th199096 
   1015   6741  th199096 	*cs->statusp = respnn->status = do_rfs4_op_secinfo(cs, NULL,
   1016   6741  th199096 	    dotdot, (SECINFO4res *)respnn);
   1017   7312    Danhua 
   1018   7312    Danhua final:
   1019   7312    Danhua 	DTRACE_NFSV4_2(op__secinfo__no__name__done,
   1020   7312    Danhua 	    struct compound_state *, cs,
   1021   7312    Danhua 	    SECINFO_NO_NAME4res *, respnn);
   1022   6741  th199096 }
   1023   6741  th199096 
   1024   6741  th199096 /* ARGSUSED */
   1025   6741  th199096 void
   1026   6741  th199096 mds_op_secinfo(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
   1027   8023       Sam     compound_state_t *cs)
   1028   8023       Sam {
   1029   6741  th199096 	SECINFO4res *resp;
   1030   6741  th199096 	utf8string *utfnm;
   1031   6741  th199096 	uint_t len, dotdot;
   1032   6741  th199096 	char *nm;
   1033   6741  th199096 
   1034   7312    Danhua 	SECINFO4args *args = &argop->nfs_argop4_u.opsecinfo;
   1035   7312    Danhua 
   1036   7312    Danhua 	DTRACE_NFSV4_2(op__secinfo__start, struct compound_state *, cs,
   1037   7312    Danhua 	    SECINFO4args *, args);
   1038   7312    Danhua 
   1039   6741  th199096 	resp = &resop->nfs_resop4_u.opsecinfo;
   1040   6741  th199096 
   1041   6741  th199096 	/*
   1042   6741  th199096 	 * Current file handle (cfh) should have been set before
   1043   6741  th199096 	 * getting into this function. If not, return error.
   1044   6741  th199096 	 */
   1045   6741  th199096 	if (cs->vp == NULL) {
   1046   6741  th199096 		*cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
   1047   7312    Danhua 		goto final;
   1048   6741  th199096 	}
   1049   6741  th199096 	if (cs->vp->v_type != VDIR) {
   1050   6741  th199096 		*cs->statusp = resp->status = NFS4ERR_NOTDIR;
   1051   7312    Danhua 		goto final;
   1052   6741  th199096 	}
   1053   6741  th199096 
   1054   6741  th199096 	/*
   1055   6741  th199096 	 * Verify the component name. If failed, error out, but
   1056   6741  th199096 	 * do not error out if the component name is a "..".
   1057   6741  th199096 	 * SECINFO will return its parents secinfo data for SECINFO "..".
   1058   6741  th199096 	 */
   1059   6741  th199096 	utfnm = &argop->nfs_argop4_u.opsecinfo.name;
   1060   6741  th199096 	if (!utf8_dir_verify(utfnm)) {
   1061   6741  th199096 		if (utfnm->utf8string_len != 2 ||
   1062   6741  th199096 		    utfnm->utf8string_val[0] != '.' ||
   1063   6741  th199096 		    utfnm->utf8string_val[1] != '.') {
   1064   6741  th199096 			*cs->statusp = resp->status = NFS4ERR_INVAL;
   1065   7312    Danhua 			goto final;
   1066   6741  th199096 		}
   1067   6741  th199096 		dotdot = 1;
   1068   6741  th199096 	} else
   1069   6741  th199096 		dotdot = 0;
   1070   6741  th199096 
   1071   6741  th199096 	nm = utf8_to_str(utfnm, &len, NULL);
   1072   6741  th199096 	if (nm == NULL) {
   1073   6741  th199096 		*cs->statusp = resp->status = NFS4ERR_INVAL;
   1074   7312    Danhua 		goto final;
   1075   6741  th199096 	}
   1076   6741  th199096 
   1077   6741  th199096 	if (len > MAXNAMELEN) {
   1078   6741  th199096 		*cs->statusp = resp->status = NFS4ERR_NAMETOOLONG;
   1079   6741  th199096 		kmem_free(nm, len);
   1080   7312    Danhua 		goto final;
   1081   6741  th199096 	}
   1082   6741  th199096 
   1083   6741  th199096 	*cs->statusp = resp->status = do_rfs4_op_secinfo(cs, nm, dotdot, resp);
   1084   6741  th199096 
   1085   6741  th199096 	kmem_free(nm, len);
   1086   7312    Danhua 
   1087   7312    Danhua final:
   1088   7312    Danhua 	DTRACE_NFSV4_2(op__secinfo__done, struct compound_state *, cs,
   1089   7312    Danhua 	    SECINFO4res *, resp);
   1090   6741  th199096 }
   1091   6741  th199096 
   1092   6741  th199096 /*
   1093   6741  th199096  * verify and nverify are exactly the same, except that nverify
   1094   6741  th199096  * succeeds when some argument changed, and verify succeeds when
   1095   6741  th199096  * when none changed.
   1096   6741  th199096  */
   1097   6741  th199096 
   1098   6741  th199096 /* ARGSUSED */
   1099   6741  th199096 void
   1100   6741  th199096 mds_op_verify(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
   1101   8023       Sam     compound_state_t *cs)
   1102   8023       Sam {
   1103   6741  th199096 	VERIFY4args  *args = &argop->nfs_argop4_u.opverify;
   1104   6741  th199096 	VERIFY4res *resp = &resop->nfs_resop4_u.opverify;
   1105   6741  th199096 	int error;
   1106   6741  th199096 	struct nfs4_svgetit_arg sarg;
   1107   6741  th199096 	struct statvfs64 sb;
   1108   6741  th199096 	struct nfs4_ntov_table ntov;
   1109   6741  th199096 
   1110   7312    Danhua 	DTRACE_NFSV4_2(op__verify__start, struct compound_state *, cs,
   1111   7312    Danhua 	    VERIFY4args *, args);
   1112   7312    Danhua 
   1113   7312    Danhua 	if (cs->vp == NULL) {
   1114   7312    Danhua 		*cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
   1115   7312    Danhua 		goto final;
   1116   6741  th199096 	}
   1117   6741  th199096 
   1118   6741  th199096 	sarg.sbp = &sb;
   1119   6741  th199096 	nfs4_ntov_table_init(&ntov, RFS4_ATTRVERS(cs));
   1120   6741  th199096 	resp->status = do_rfs4_set_attrs(NULL, &args->obj_attributes, cs,
   1121   6741  th199096 	    &sarg, &ntov, NFS4ATTR_VERIT);
   1122   6741  th199096 	if (resp->status != NFS4_OK) {
   1123   6741  th199096 		/*
   1124   6741  th199096 		 * do_rfs4_set_attrs will try to verify systemwide attrs,
   1125   6741  th199096 		 * so could return -1 for "no match".
   1126   6741  th199096 		 */
   1127   6741  th199096 		if (resp->status == -1)
   1128   6741  th199096 			resp->status = NFS4ERR_NOT_SAME;
   1129   6741  th199096 		goto done;
   1130   6741  th199096 	}
   1131   6741  th199096 	error = rfs4_verify_attr(&sarg, NULL, &ntov);
   1132   6741  th199096 	switch (error) {
   1133   6741  th199096 	case 0:
   1134   6741  th199096 		resp->status = NFS4_OK;
   1135   6741  th199096 		break;
   1136   6741  th199096 	case -1:
   1137   6741  th199096 		resp->status = NFS4ERR_NOT_SAME;
   1138   6741  th199096 		break;
   1139   6741  th199096 	default:
   1140   6741  th199096 		resp->status = puterrno4(error);
   1141   6741  th199096 		break;
   1142   6741  th199096 	}
   1143   6741  th199096 done:
   1144   6741  th199096 	*cs->statusp = resp->status;
   1145   6741  th199096 	nfs4_ntov_table_free(&ntov, &sarg);
   1146   7312    Danhua 
   1147   7312    Danhua final:
   1148   7312    Danhua 	DTRACE_NFSV4_2(op__verify__done, struct compound_state *, cs,
   1149   7312    Danhua 	    VERIFY4res *, resp);
   1150   6741  th199096 }
   1151   6741  th199096 
   1152   6741  th199096 /* ARGSUSED */
   1153   6741  th199096 void
   1154   6741  th199096 mds_op_nverify(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
   1155   8023       Sam     compound_state_t *cs)
   1156   8023       Sam {
   1157   6741  th199096 	NVERIFY4args  *args = &argop->nfs_argop4_u.opnverify;
   1158   6741  th199096 	NVERIFY4res *resp = &resop->nfs_resop4_u.opnverify;
   1159   6741  th199096 	int error;
   1160   6741  th199096 	struct nfs4_svgetit_arg sarg;
   1161   6741  th199096 	struct statvfs64 sb;
   1162   6741  th199096 	struct nfs4_ntov_table ntov;
   1163   6741  th199096 
   1164   7312    Danhua 	DTRACE_NFSV4_2(op__nverify__start, struct compound_state *, cs,
   1165   7312    Danhua 	    NVERIFY4args *, args);
   1166   7312    Danhua 
   1167   7312    Danhua 	if (cs->vp == NULL) {
   1168   7312    Danhua 		*cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
   1169   7312    Danhua 		goto final;
   1170   6741  th199096 	}
   1171   6741  th199096 	sarg.sbp = &sb;
   1172   6741  th199096 	nfs4_ntov_table_init(&ntov, RFS4_ATTRVERS(cs));
   1173   6741  th199096 	resp->status = do_rfs4_set_attrs(NULL, &args->obj_attributes, cs,
   1174   6741  th199096 	    &sarg, &ntov, NFS4ATTR_VERIT);
   1175   6741  th199096 	if (resp->status != NFS4_OK) {
   1176   6741  th199096 		/*
   1177   6741  th199096 		 * do_rfs4_set_attrs will try to verify systemwide attrs,
   1178   6741  th199096 		 * so could return -1 for "no match".
   1179   6741  th199096 		 */
   1180   6741  th199096 		if (resp->status == -1)
   1181   6741  th199096 			resp->status = NFS4_OK;
   1182   6741  th199096 		goto done;
   1183   6741  th199096 	}
   1184   6741  th199096 	error = rfs4_verify_attr(&sarg, NULL, &ntov);
   1185   6741  th199096 	switch (error) {
   1186   6741  th199096 	case 0:
   1187   6741  th199096 		resp->status = NFS4ERR_SAME;
   1188   6741  th199096 		break;
   1189   6741  th199096 	case -1:
   1190   6741  th199096 		resp->status = NFS4_OK;
   1191   6741  th199096 		break;
   1192   6741  th199096 	default:
   1193   6741  th199096 		resp->status = puterrno4(error);
   1194   6741  th199096 		break;
   1195   6741  th199096 	}
   1196   6741  th199096 done:
   1197   6741  th199096 	*cs->statusp = resp->status;
   1198   6741  th199096 	nfs4_ntov_table_free(&ntov, &sarg);
   1199   7312    Danhua 
   1200   7312    Danhua final:
   1201   7312    Danhua 	DTRACE_NFSV4_2(op__nverify__done, struct compound_state *, cs,
   1202   7312    Danhua 	    NVERIFY4res *, resp);
   1203   7312    Danhua 
   1204   6741  th199096 }
   1205   6741  th199096 
   1206   6741  th199096 /* ARGSUSED */
   1207   6741  th199096 void
   1208   6741  th199096 mds_op_access(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
   1209   8023       Sam     compound_state_t *cs)
   1210   8023       Sam {
   1211   6741  th199096 	ACCESS4args *args = &argop->nfs_argop4_u.opaccess;
   1212   6741  th199096 	ACCESS4res *resp = &resop->nfs_resop4_u.opaccess;
   1213   6741  th199096 	int error;
   1214   6741  th199096 	vnode_t *vp;
   1215   6741  th199096 	struct vattr va;
   1216   6741  th199096 	int checkwriteperm;
   1217   6741  th199096 	cred_t *cr = cs->cr;
   1218   6741  th199096 	bslabel_t *clabel, *slabel;
   1219   6741  th199096 	ts_label_t *tslabel;
   1220   6741  th199096 	boolean_t admin_low_client;
   1221   6741  th199096 
   1222   7312    Danhua 	DTRACE_NFSV4_2(op__access__start, struct compound_state *, cs,
   1223   7312    Danhua 	    ACCESS4args *, args);
   1224   7312    Danhua 
   1225   7312    Danhua 	if (cs->vp == NULL) {
   1226   7312    Danhua 		*cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
   1227   7312    Danhua 		goto final;
   1228   6741  th199096 	}
   1229   6741  th199096 
   1230   6741  th199096 	ASSERT(cr != NULL);
   1231   6741  th199096 
   1232   6741  th199096 	vp = cs->vp;
   1233   6741  th199096 
   1234   6741  th199096 	/*
   1235   6741  th199096 	 * If the file system is exported read only, it is not appropriate
   1236   6741  th199096 	 * to check write permissions for regular files and directories.
   1237   6741  th199096 	 * Special files are interpreted by the client, so the underlying
   1238   6741  th199096 	 * permissions are sent back to the client for interpretation.
   1239   6741  th199096 	 */
   1240   6741  th199096 	if (rdonly4(cs->exi, cs->vp, req) &&
   1241   6741  th199096 	    (vp->v_type == VREG || vp->v_type == VDIR))
   1242   6741  th199096 		checkwriteperm = 0;
   1243   6741  th199096 	else
   1244   6741  th199096 		checkwriteperm = 1;
   1245   6741  th199096 
   1246   6741  th199096 	/*
   1247   6741  th199096 	 * XXX
   1248   6741  th199096 	 * We need the mode so that we can correctly determine access
   1249   6741  th199096 	 * permissions relative to a mandatory lock file.  Access to
   1250   6741  th199096 	 * mandatory lock files is denied on the server, so it might
   1251   6741  th199096 	 * as well be reflected to the server during the open.
   1252   6741  th199096 	 */
   1253   6741  th199096 	va.va_mask = AT_MODE;
   1254   6741  th199096 	error = VOP_GETATTR(vp, &va, 0, cr, NULL);
   1255   6741  th199096 	if (error) {
   1256   6741  th199096 		*cs->statusp = resp->status = puterrno4(error);
   1257   7312    Danhua 		goto final;
   1258   6741  th199096 	}
   1259   6741  th199096 	resp->access = 0;
   1260   6741  th199096 	resp->supported = 0;
   1261   6741  th199096 
   1262   6741  th199096 	if (is_system_labeled()) {
   1263   6741  th199096 		ASSERT(req->rq_label != NULL);
   1264   6741  th199096 		clabel = req->rq_label;
   1265   6741  th199096 		DTRACE_PROBE2(tx__rfs4__log__info__opaccess__clabel, char *,
   1266   6741  th199096 		    "got client label from request(1)",
   1267   6741  th199096 		    struct svc_req *, req);
   1268   6741  th199096 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
   1269  10447    Thomas 			if ((tslabel = nfs_getflabel(vp, cs->exi)) == NULL) {
   1270   6741  th199096 				*cs->statusp = resp->status = puterrno4(EACCES);
   1271   7312    Danhua 				goto final;
   1272   6741  th199096 			}
   1273   6741  th199096 			slabel = label2bslabel(tslabel);
   1274   6741  th199096 			DTRACE_PROBE3(tx__rfs4__log__info__opaccess__slabel,
   1275   6741  th199096 			    char *, "got server label(1) for vp(2)",
   1276   6741  th199096 			    bslabel_t *, slabel, vnode_t *, vp);
   1277   6741  th199096 
   1278   6741  th199096 			admin_low_client = B_FALSE;
   1279   6741  th199096 		} else
   1280   6741  th199096 			admin_low_client = B_TRUE;
   1281   6741  th199096 	}
   1282   6741  th199096 
   1283   6741  th199096 	if (args->access & ACCESS4_READ) {
   1284   6741  th199096 		error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
   1285   6741  th199096 		if (!error && !MANDLOCK(vp, va.va_mode) &&
   1286   6741  th199096 		    (!is_system_labeled() || admin_low_client ||
   1287   6741  th199096 		    bldominates(clabel, slabel)))
   1288   6741  th199096 			resp->access |= ACCESS4_READ;
   1289   6741  th199096 		resp->supported |= ACCESS4_READ;
   1290   6741  th199096 	}
   1291   6741  th199096 	if ((args->access & ACCESS4_LOOKUP) && vp->v_type == VDIR) {
   1292   6741  th199096 		error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL);
   1293   6741  th199096 		if (!error && (!is_system_labeled() || admin_low_client ||
   1294   6741  th199096 		    bldominates(clabel, slabel)))
   1295   6741  th199096 			resp->access |= ACCESS4_LOOKUP;
   1296   6741  th199096 		resp->supported |= ACCESS4_LOOKUP;
   1297   6741  th199096 	}
   1298   6741  th199096 	if (checkwriteperm &&
   1299   6741  th199096 	    (args->access & (ACCESS4_MODIFY|ACCESS4_EXTEND))) {
   1300   6741  th199096 		error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL);
   1301   6741  th199096 		if (!error && !MANDLOCK(vp, va.va_mode) &&
   1302   6741  th199096 		    (!is_system_labeled() || admin_low_client ||
   1303   6741  th199096 		    blequal(clabel, slabel)))
   1304   6741  th199096 			resp->access |=
   1305   6741  th199096 			    (args->access & (ACCESS4_MODIFY|ACCESS4_EXTEND));
   1306   6741  th199096 		resp->supported |= (ACCESS4_MODIFY|ACCESS4_EXTEND);
   1307   6741  th199096 	}
   1308   6741  th199096 
   1309   6741  th199096 	if (checkwriteperm &&
   1310   6741  th199096 	    (args->access & ACCESS4_DELETE) && vp->v_type == VDIR) {
   1311   6741  th199096 		error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL);
   1312   6741  th199096 		if (!error && (!is_system_labeled() || admin_low_client ||
   1313   6741  th199096 		    blequal(clabel, slabel)))
   1314   6741  th199096 			resp->access |= ACCESS4_DELETE;
   1315   6741  th199096 		resp->supported |= ACCESS4_DELETE;
   1316   6741  th199096 	}
   1317   6741  th199096 	if (args->access & ACCESS4_EXECUTE && vp->v_type != VDIR) {
   1318   6741  th199096 		error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL);
   1319   6741  th199096 		if (!error && !MANDLOCK(vp, va.va_mode) &&
   1320   6741  th199096 		    (!is_system_labeled() || admin_low_client ||
   1321   6741  th199096 		    bldominates(clabel, slabel)))
   1322   6741  th199096 			resp->access |= ACCESS4_EXECUTE;
   1323   6741  th199096 		resp->supported |= ACCESS4_EXECUTE;
   1324   6741  th199096 	}
   1325   6741  th199096 
   1326   6741  th199096 	if (is_system_labeled() && !admin_low_client)
   1327   6741  th199096 		label_rele(tslabel);
   1328   6741  th199096 
   1329   6741  th199096 	*cs->statusp = resp->status = NFS4_OK;
   1330   7312    Danhua 
   1331   7312    Danhua final:
   1332   7312    Danhua 	DTRACE_NFSV4_2(op__access__done, struct compound_state *, cs,
   1333   7312    Danhua 	    ACCESS4res *, resp);
   1334   6741  th199096 }
   1335   6741  th199096 
   1336   6741  th199096 /* ARGSUSED */
   1337   6741  th199096 static void
   1338   6741  th199096 mds_op_commit(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
   1339   8023       Sam 	compound_state_t *cs)
   1340   8023       Sam {
   1341   6741  th199096 	COMMIT4args *args = &argop->nfs_argop4_u.opcommit;
   1342   6741  th199096 	COMMIT4res *resp = &resop->nfs_resop4_u.opcommit;
   1343   6741  th199096 	int error;
   1344   6741  th199096 	vnode_t *vp = cs->vp;
   1345   6741  th199096 	cred_t *cr = cs->cr;
   1346   6741  th199096 	vattr_t va;
   1347   6741  th199096 	caller_context_t ct;
   1348   6741  th199096 
   1349   7312    Danhua 	DTRACE_NFSV4_2(op__commit__start, struct compound_state *, cs,
   1350   7312    Danhua 	    COMMIT4args *, args);
   1351   6741  th199096 
   1352   6741  th199096 	if (vp == NULL) {
   1353   8033       Sam 		/*
   1354   8033       Sam 		 * XXX kludge: fake the commit if we are a data server
   1355   8033       Sam 		 * This will be replaced once we have nnop_commit().
   1356   8033       Sam 		 */
   1357   8033       Sam 		if (cs->nn != NULL) {
   1358   8033       Sam 			*cs->statusp = resp->status = NFS4_OK;
   1359   8033       Sam 			resp->writeverf = cs->instp->Write4verf;
   1360   8033       Sam 		} else {
   1361   8033       Sam 			*cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
   1362   8033       Sam 		}
   1363   7312    Danhua 		goto final;
   1364   7312    Danhua 	}
   1365   7312    Danhua 	if (cs->access == CS_ACCESS_DENIED) {
   1366   7312    Danhua 		*cs->statusp = resp->status = NFS4ERR_ACCESS;
   1367   7312    Danhua 		goto final;
   1368   6741  th199096 	}
   1369   6741  th199096 
   1370   6741  th199096 	if (args->offset + args->count < args->offset) {
   1371   6741  th199096 		*cs->statusp = resp->status = NFS4ERR_INVAL;
   1372   7312    Danhua 		goto final;
   1373   6741  th199096 	}
   1374   6741  th199096 
   1375   6741  th199096 	ct.cc_sysid = 0;
   1376   6741  th199096 	ct.cc_pid = 0;
   1377   7739   jwahlig 	ct.cc_caller_id = cs->instp->caller_id;
   1378   7739   jwahlig 	ct.cc_flags = CC_DONTBLOCK;
   1379   6741  th199096 
   1380   6741  th199096 	va.va_mask = AT_UID;
   1381   6741  th199096 	error = VOP_GETATTR(vp, &va, 0, cr, &ct);
   1382   6741  th199096 
   1383   6741  th199096 	/*
   1384   6741  th199096 	 * If we can't get the attributes, then we can't do the
   1385   6741  th199096 	 * right access checking.  So, we'll fail the request.
   1386   6741  th199096 	 */
   1387   6741  th199096 	if (error) {
   1388   6741  th199096 		*cs->statusp = resp->status = puterrno4(error);
   1389   7312    Danhua 		goto final;
   1390   6741  th199096 	}
   1391   6741  th199096 	if (rdonly4(cs->exi, cs->vp, req)) {
   1392   6741  th199096 		*cs->statusp = resp->status = NFS4ERR_ROFS;
   1393   7312    Danhua 		goto final;
   1394   6741  th199096 	}
   1395   6741  th199096 
   1396   6741  th199096 	if (vp->v_type != VREG) {
   1397   6741  th199096 		if (vp->v_type == VDIR)
   1398   6741  th199096 			resp->status = NFS4ERR_ISDIR;
   1399   6741  th199096 		else
   1400   6741  th199096 			resp->status = NFS4ERR_INVAL;
   1401   6741  th199096 		*cs->statusp = resp->status;
   1402   7312    Danhua 		goto final;
   1403   6741  th199096 	}
   1404   6741  th199096 
   1405   6741  th199096 	if (crgetuid(cr) != va.va_uid &&
   1406   6741  th199096 	    (error = VOP_ACCESS(vp, VWRITE, 0, cs->cr, &ct))) {
   1407   6741  th199096 		*cs->statusp = resp->status = puterrno4(error);
   1408   7312    Danhua 		goto final;
   1409   6741  th199096 	}
   1410   6741  th199096 
   1411   6741  th199096 	error = VOP_PUTPAGE(vp, args->offset, args->count, 0, cr, &ct);
   1412   6741  th199096 	if (!error)
   1413   6741  th199096 		error = VOP_FSYNC(vp, FNODSYNC, cr, &ct);
   1414   6741  th199096 
   1415   6741  th199096 	if (error) {
   1416   6741  th199096 		*cs->statusp = resp->status = puterrno4(error);
   1417   7312    Danhua 		goto final;
   1418   6741  th199096 	}
   1419   6741  th199096 
   1420   6741  th199096 	*cs->statusp = resp->status = NFS4_OK;
   1421   6741  th199096 	resp->writeverf = cs->instp->Write4verf;
   1422   7312    Danhua 
   1423   7312    Danhua final:
   1424   7312    Danhua 	DTRACE_NFSV4_2(op__commit__done, struct compound_state *, cs,
   1425   7312    Danhua 	    COMMIT4res *, resp);
   1426   6741  th199096 }
   1427   6741  th199096 
   1428   6741  th199096 /*
   1429   6741  th199096  * rfs4_op_mknod is called from rfs4_op_create after all initial verification
   1430   6741  th199096  * was completed. It does the nfsv4 create for special files.
   1431   6741  th199096  *
   1432   6741  th199096  * nfsv4 create is used to create non-regular files. For regular files,
   1433   6741  th199096  * use nfsv4 open.
   1434   6741  th199096  */
   1435   6741  th199096 /* ARGSUSED */
   1436   6741  th199096 static void
   1437   6741  th199096 mds_op_create(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
   1438   8023       Sam 	compound_state_t *cs)
   1439   6741  th199096 {
   1440   6741  th199096 	CREATE4args *args = &argop->nfs_argop4_u.opcreate;
   1441   6741  th199096 	CREATE4res *resp = &resop->nfs_resop4_u.opcreate;
   1442   6741  th199096 	int error;
   1443   6741  th199096 	struct vattr bva, iva, iva2, ava, *vap;
   1444   6741  th199096 	cred_t *cr = cs->cr;
   1445   6741  th199096 	vnode_t *dvp = cs->vp;
   1446   6741  th199096 	vnode_t *vp = NULL;
   1447   9399    Thomas 	vnode_t *realvp;
   1448   6741  th199096 	char *nm, *lnm;
   1449   6741  th199096 	uint_t len, llen;
   1450   6741  th199096 	int syncval = 0;
   1451   6741  th199096 	struct nfs4_svgetit_arg sarg;
   1452   6741  th199096 	struct nfs4_ntov_table ntov;
   1453   6741  th199096 	struct statvfs64 sb;
   1454   6741  th199096 	nfsstat4 status;
   1455   6741  th199096 	caller_context_t ct;
   1456   6741  th199096 
   1457   7312    Danhua 	DTRACE_NFSV4_2(op__create__start, struct compound_state *, cs,
   1458   7312    Danhua 	    CREATE4args *, args);
   1459   7312    Danhua 
   1460   6741  th199096 	resp->attrset = NFS4_EMPTY_ATTRMAP(RFS4_ATTRVERS(cs));
   1461   6741  th199096 
   1462   6741  th199096 	if (dvp == NULL) {
   1463   6741  th199096 		*cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
   1464   7312    Danhua 		goto final;
   1465   6741  th199096 	}
   1466   6741  th199096 
   1467   6741  th199096 	/*
   1468   6741  th199096 	 * If there is an unshared filesystem mounted on this vnode,
   1469   6741  th199096 	 * do not allow to create an object in this directory.
   1470   6741  th199096 	 */
   1471   6741  th199096 	if (vn_ismntpt(dvp)) {
   1472   6741  th199096 		*cs->statusp = resp->status = NFS4ERR_ACCESS;
   1473   7312    Danhua 		goto final;
   1474   6741  th199096 	}
   1475   6741  th199096 
   1476   6741  th199096 	ct.cc_sysid = 0;
   1477   6741  th199096 	ct.cc_pid = 0;
   1478   7739   jwahlig 	ct.cc_caller_id = cs->instp->caller_id;
   1479   7739   jwahlig 	ct.cc_flags = CC_DONTBLOCK;
   1480   6741  th199096 
   1481   6741  th199096 	/* Verify that type is correct */
   1482   6741  th199096 	switch (args->type) {
   1483   6741  th199096 	case NF4LNK:
   1484   6741  th199096 	case NF4BLK:
   1485   6741  th199096 	case NF4CHR:
   1486   6741  th199096 	case NF4SOCK:
   1487   6741  th199096 	case NF4FIFO:
   1488   6741  th199096 	case NF4DIR:
   1489   6741  th199096 		break;
   1490   6741  th199096 	default:
   1491   6741  th199096 		*cs->statusp = resp->status = NFS4ERR_BADTYPE;
   1492   7312    Danhua 		goto final;
   1493   6741  th199096 	};
   1494   6741  th199096 
   1495   6741  th199096 	if (cs->access == CS_ACCESS_DENIED) {
   1496   6741  th199096 		*cs->statusp = resp->status = NFS4ERR_ACCESS;
   1497   7312    Danhua 		goto final;
   1498   6741  th199096 	}
   1499   6741  th199096 	if (dvp->v_type != VDIR) {
   1500   6741  th199096 		*cs->statusp = resp->status = NFS4ERR_NOTDIR;
   1501   7312    Danhua 		goto final;
   1502   6741  th199096 	}
   1503   6741  th199096 	if (!utf8_dir_verify(&args->objname)) {
   1504   6741  th199096 		*cs->statusp = resp->status = NFS4ERR_INVAL;
   1505   7312    Danhua 		goto final;
   1506   6741  th199096 	}
   1507   6741  th199096 
   1508   6741  th199096 	if (rdonly4(cs->exi, cs->vp, req)) {
   1509   6741  th199096 		*cs->statusp = resp->status = NFS4ERR_ROFS;
   1510   7312    Danhua 		goto final;
   1511   6741  th199096 	}
   1512   6741  th199096 
   1513   6741  th199096 	/*
   1514   6741  th199096 	 * Name of newly created object
   1515   6741  th199096 	 */
   1516   6741  th199096 	nm = utf8_to_fn(&args->objname, &len, NULL);
   1517   6741  th199096 	if (nm == NULL) {
   1518   6741  th199096 		*cs->statusp = resp->status = NFS4ERR_INVAL;
   1519   7312    Danhua 		goto final;
   1520   6741  th199096 	}
   1521   6741  th199096 
   1522   6741  th199096 	if (len > MAXNAMELEN) {
   1523   6741  th199096 		*cs->statusp = resp->status = NFS4ERR_NAMETOOLONG;
   1524   6741  th199096 		kmem_free(nm, len);
   1525   7312    Danhua 		goto final;
   1526   6741  th199096 	}
   1527   6741  th199096 
   1528   6741  th199096 	sarg.sbp = &sb;
   1529   6741  th199096 	nfs4_ntov_table_init(&ntov, RFS4_ATTRVERS(cs));
   1530   6741  th199096 
   1531   6741  th199096 	status = do_rfs4_set_attrs(&resp->attrset,
   1532   6741  th199096 	    &args->createattrs, cs, &sarg, &ntov, NFS4ATTR_SETIT);
   1533   6741  th199096 
   1534   6741  th199096 	if (sarg.vap->va_mask == 0 && status == NFS4_OK)
   1535   6741  th199096 		status = NFS4ERR_INVAL;
   1536   6741  th199096 
   1537   6741  th199096 	if (status != NFS4_OK) {
   1538   6741  th199096 		*cs->statusp = resp->status = status;
   1539   6741  th199096 		kmem_free(nm, len);
   1540   6741  th199096 		nfs4_ntov_table_free(&ntov, &sarg);
   1541   7312    Danhua 
   1542   6741  th199096 		resp->attrset = NFS4_EMPTY_ATTRMAP(RFS4_ATTRVERS(cs));
   1543   7312    Danhua 		goto final;
   1544   6741  th199096 	}
   1545   6741  th199096 
   1546   6741  th199096 	/* Get "before" change value */
   1547   6741  th199096 	bva.va_mask = AT_CTIME|AT_SEQ;
   1548   6741  th199096 	error = VOP_GETATTR(dvp, &bva, 0, cr, &ct);
   1549   6741  th199096 	if (error) {
   1550   6741  th199096 		*cs->statusp = resp->status = puterrno4(error);
   1551   6741  th199096 		kmem_free(nm, len);
   1552   6741  th199096 		nfs4_ntov_table_free(&ntov, &sarg);
   1553   7312    Danhua 
   1554   6741  th199096 		resp->attrset = NFS4_EMPTY_ATTRMAP(RFS4_ATTRVERS(cs));
   1555   7312    Danhua 		goto final;
   1556   6741  th199096 	}
   1557   6741  th199096 	NFS4_SET_FATTR4_CHANGE(resp->cinfo.before, bva.va_ctime)
   1558   6741  th199096 
   1559   6741  th199096 	vap = sarg.vap;
   1560   6741  th199096 
   1561   6741  th199096 	/*
   1562   6741  th199096 	 * Set default initial values for attributes when not specified
   1563   6741  th199096 	 * in createattrs.
   1564   6741  th199096 	 */
   1565   6741  th199096 	if ((vap->va_mask & AT_UID) == 0) {
   1566   6741  th199096 		vap->va_uid = crgetuid(cr);
   1567   6741  th199096 		vap->va_mask |= AT_UID;
   1568   6741  th199096 	}
   1569   6741  th199096 	if ((vap->va_mask & AT_GID) == 0) {
   1570   6741  th199096 		vap->va_gid = crgetgid(cr);
   1571   6741  th199096 		vap->va_mask |= AT_GID;
   1572   6741  th199096 	}
   1573   6741  th199096 
   1574   6741  th199096 	vap->va_mask |= AT_TYPE;
   1575   6741  th199096 	switch (args->type) {
   1576   6741  th199096 	case NF4DIR:
   1577   6741  th199096 		vap->va_type = VDIR;
   1578   6741  th199096 		if ((vap->va_mask & AT_MODE) == 0) {
   1579   6741  th199096 			vap->va_mode = 0700;	/* default: owner rwx only */
   1580   6741  th199096 			vap->va_mask |= AT_MODE;
   1581   6741  th199096 		}
   1582   6741  th199096 		error = VOP_MKDIR(dvp, nm, vap, &vp, cr, &ct, 0, NULL);
   1583   6741  th199096 		if (error)
   1584   6741  th199096 			break;
   1585   6741  th199096 
   1586   6741  th199096 		/*
   1587   6741  th199096 		 * Get the initial "after" sequence number, if it fails,
   1588   6741  th199096 		 * set to zero
   1589   6741  th199096 		 */
   1590   6741  th199096 		iva.va_mask = AT_SEQ;
   1591   6741  th199096 		if (VOP_GETATTR(dvp, &iva, 0, cs->cr, &ct))
   1592   6741  th199096 			iva.va_seq = 0;
   1593   6741  th199096 		break;
   1594   6741  th199096 	case NF4LNK:
   1595   6741  th199096 		vap->va_type = VLNK;
   1596   6741  th199096 		if ((vap->va_mask & AT_MODE) == 0) {
   1597   6741  th199096 			vap->va_mode = 0700;	/* default: owner rwx only */
   1598   6741  th199096 			vap->va_mask |= AT_MODE;
   1599   6741  th199096 		}
   1600   6741  th199096 
   1601   6741  th199096 		/*
   1602   6741  th199096 		 * symlink names must be treated as data
   1603   6741  th199096 		 */
   1604   6741  th199096 		lnm = utf8_to_str(&args->ftype4_u.linkdata, &llen, NULL);
   1605   6741  th199096 
   1606   6741  th199096 		if (lnm == NULL) {
   1607   6741  th199096 			*cs->statusp = resp->status = NFS4ERR_INVAL;
   1608   6741  th199096 			kmem_free(nm, len);
   1609   6741  th199096 			nfs4_ntov_table_free(&ntov, &sarg);
   1610   6741  th199096 			resp->attrset =
   1611   6741  th199096 			    NFS4_EMPTY_ATTRMAP(RFS4_ATTRVERS(cs));
   1612   7312    Danhua 			goto final;
   1613   6741  th199096 		}
   1614   6741  th199096 
   1615   6741  th199096 		if (llen > MAXPATHLEN) {
   1616   6741  th199096 			*cs->statusp = resp->status = NFS4ERR_NAMETOOLONG;
   1617   6741  th199096 			kmem_free(nm, len);
   1618   6741  th199096 			kmem_free(lnm, llen);
   1619   6741  th199096 			nfs4_ntov_table_free(&ntov, &sarg);
   1620   6741  th199096 			resp->attrset =
   1621   6741  th199096 			    NFS4_EMPTY_ATTRMAP(RFS4_ATTRVERS(cs));
   1622   7312    Danhua 			goto final;
   1623   6741  th199096 		}
   1624   6741  th199096 
   1625   6741  th199096 		error = VOP_SYMLINK(dvp, nm, vap, lnm, cr, &ct, 0);
   1626   6741  th199096 		if (lnm != NULL)
   1627   6741  th199096 			kmem_free(lnm, llen);
   1628   6741  th199096 		if (error)
   1629   6741  th199096 			break;
   1630   6741  th199096 
   1631   6741  th199096 		/*
   1632   6741  th199096 		 * Get the initial "after" sequence number, if it fails,
   1633   6741  th199096 		 * set to zero
   1634   6741  th199096 		 */
   1635   6741  th199096 		iva.va_mask = AT_SEQ;
   1636   6741  th199096 		if (VOP_GETATTR(dvp, &iva, 0, cs->cr, &ct))
   1637   6741  th199096 			iva.va_seq = 0;
   1638   6741  th199096 
   1639   6741  th199096 		error = VOP_LOOKUP(dvp, nm, &vp, NULL, 0, NULL, cr,
   1640   6741  th199096 		    &ct, 0, NULL);
   1641   6741  th199096 		if (error)
   1642   6741  th199096 			break;
   1643   6741  th199096 
   1644   6741  th199096 		/*
   1645   6741  th199096 		 * va_seq is not safe over VOP calls, check it again
   1646   6741  th199096 		 * if it has changed zero out iva to force atomic = FALSE.
   1647   6741  th199096 		 */
   1648   6741  th199096 		iva2.va_mask = AT_SEQ;
   1649   6741  th199096 		if (VOP_GETATTR(dvp, &iva2, 0, cs->cr, &ct) ||
   1650   6741  th199096 		    iva2.va_seq != iva.va_seq)
   1651   6741  th199096 			iva.va_seq = 0;
   1652   6741  th199096 		break;
   1653   6741  th199096 	default:
   1654   6741  th199096 		/*
   1655   6741  th199096 		 * probably a special file.
   1656   6741  th199096 		 */
   1657   6741  th199096 		if ((vap->va_mask & AT_MODE) == 0) {
   1658   6741  th199096 			vap->va_mode = 0600;	/* default: owner rw only */
   1659   6741  th199096 			vap->va_mask |= AT_MODE;
   1660   6741  th199096 		}
   1661   6741  th199096 		syncval = FNODSYNC;
   1662   6741  th199096 		/*
   1663   6741  th199096 		 * We know this will only generate one VOP call
   1664   6741  th199096 		 */
   1665   6741  th199096 		vp = do_rfs4_op_mknod(args, resp, req, cs, vap, nm);
   1666   6741  th199096 
   1667   6741  th199096 		if (vp == NULL) {
   1668   6741  th199096 			kmem_free(nm, len);
   1669   6741  th199096 			nfs4_ntov_table_free(&ntov, &sarg);
   1670   6741  th199096 			resp->attrset = NFS4_EMPTY_ATTRMAP(RFS4_ATTRVERS(cs));
   1671   7312    Danhua 			goto final;
   1672   6741  th199096 		}
   1673   6741  th199096 
   1674   6741  th199096 		/*
   1675   6741  th199096 		 * Get the initial "after" sequence number, if it fails,
   1676   6741  th199096 		 * set to zero
   1677   6741  th199096 		 */
   1678   6741  th199096 		iva.va_mask = AT_SEQ;
   1679   6741  th199096 		if (VOP_GETATTR(dvp, &iva, 0, cs->cr, &ct))
   1680   6741  th199096 			iva.va_seq = 0;
   1681   6741  th199096 
   1682   6741  th199096 		break;
   1683   6741  th199096 	}
   1684   6741  th199096 	kmem_free(nm, len);
   1685   6741  th199096 
   1686   6741  th199096 	if (error) {
   1687   6741  th199096 		*cs->statusp = resp->status = puterrno4(error);
   1688   6741  th199096 	}
   1689   6741  th199096 
   1690   6741  th199096 	/*
   1691   6741  th199096 	 * Force modified data and metadata out to stable storage.
   1692   6741  th199096 	 */
   1693   6741  th199096 	(void) VOP_FSYNC(dvp, 0, cr, &ct);
   1694   6741  th199096 
   1695   6741  th199096 	if (resp->status != NFS4_OK) {
   1696   6741  th199096 		if (vp != NULL)
   1697   6741  th199096 			VN_RELE(vp);
   1698   6741  th199096 		nfs4_ntov_table_free(&ntov, &sarg);
   1699   6741  th199096 		resp->attrset = NFS4_EMPTY_ATTRMAP(RFS4_ATTRVERS(cs));
   1700   7312    Danhua 		goto final;
   1701   6741  th199096 	}
   1702   6741  th199096 
   1703   6741  th199096 	/*
   1704   6741  th199096 	 * Finish setup of cinfo response, "before" value already set.
   1705   6741  th199096 	 * Get "after" change value, if it fails, simply return the
   1706   6741  th199096 	 * before value.
   1707   6741  th199096 	 */
   1708   6741  th199096 	ava.va_mask = AT_CTIME|AT_SEQ;
   1709   6741  th199096 	if (VOP_GETATTR(dvp, &ava, 0, cr, &ct)) {
   1710   6741  th199096 		ava.va_ctime = bva.va_ctime;
   1711   6741  th199096 		ava.va_seq = 0;
   1712   6741  th199096 	}
   1713   6741  th199096 	NFS4_SET_FATTR4_CHANGE(resp->cinfo.after, ava.va_ctime);
   1714   6741  th199096 
   1715   6741  th199096 	/*
   1716   6741  th199096 	 * True verification that object was created with correct
   1717   6741  th199096 	 * attrs is impossible.  The attrs could have been changed
   1718   6741  th199096 	 * immediately after object creation.  If attributes did
   1719   6741  th199096 	 * not verify, the only recourse for the server is to
   1720   6741  th199096 	 * destroy the object.  Maybe if some attrs (like gid)
   1721   6741  th199096 	 * are set incorrectly, the object should be destroyed;
   1722   6741  th199096 	 * however, seems bad as a default policy.  Do we really
   1723   6741  th199096 	 * want to destroy an object over one of the times not
   1724   6741  th199096 	 * verifying correctly?  For these reasons, the server
   1725   6741  th199096 	 * currently sets bits in attrset for createattrs
   1726   6741  th199096 	 * that were set; however, no verification is done.
   1727   6741  th199096 	 *
   1728   6741  th199096 	 * vmask_to_nmask accounts for vattr bits set on create
   1729   6741  th199096 	 *	[do_rfs4_set_attrs() only sets resp bits for
   1730   6741  th199096 	 *	 non-vattr/vfs bits.]
   1731   6741  th199096 	 * Mask off any bits set by default so as not to return
   1732   6741  th199096 	 * more attrset bits than were requested in createattrs
   1733   6741  th199096 	 */
   1734   6741  th199096 	nfs4_vmask_to_nmask(sarg.vap->va_mask, &resp->attrset,
   1735   6741  th199096 	    RFS4_ATTRVERS(cs));
   1736   6741  th199096 	ATTRMAP_MASK(resp->attrset, args->createattrs.attrmask);
   1737   6741  th199096 	nfs4_ntov_table_free(&ntov, &sarg);
   1738   6741  th199096 
   1739   6741  th199096 	error = mknfs41_fh(&cs->fh, vp, cs->exi);
   1740   6741  th199096 	if (error) {
   1741   6741  th199096 		*cs->statusp = resp->status = puterrno4(error);
   1742   6741  th199096 	}
   1743   6741  th199096 
   1744   6741  th199096 	/*
   1745   6741  th199096 	 * The cinfo.atomic = TRUE only if we got no errors, we have
   1746   6741  th199096 	 * non-zero va_seq's, and it has incremented by exactly one
   1747   6741  th199096 	 * during the creation and it didn't change during the VOP_LOOKUP
   1748   6741  th199096 	 * or VOP_FSYNC.
   1749   6741  th199096 	 */
   1750   6741  th199096 	if (!error && bva.va_seq && iva.va_seq && ava.va_seq &&
   1751   6741  th199096 	    iva.va_seq == (bva.va_seq + 1) &&
   1752   6741  th199096 	    iva.va_seq == ava.va_seq)
   1753   6741  th199096 		resp->cinfo.atomic = TRUE;
   1754   6741  th199096 	else
   1755   6741  th199096 		resp->cinfo.atomic = FALSE;
   1756   6741  th199096 
   1757   9399    Thomas 	/*
   1758   9399    Thomas 	 * Force modified metadata out to stable storage.
   1759   9399    Thomas 	 *
   1760   9399    Thomas 	 * if a underlying vp exists, pass it to VOP_FSYNC
   1761   9399    Thomas 	 */
   1762   9399    Thomas 	if (VOP_REALVP(vp, &realvp, &ct) == 0)
   1763   9399    Thomas 		(void) VOP_FSYNC(realvp, syncval, cr, &ct);
   1764   9399    Thomas 	else
   1765   9399    Thomas 		(void) VOP_FSYNC(vp, syncval, cr, &ct);
   1766   6741  th199096 
   1767   6741  th199096 	if (resp->status != NFS4_OK) {
   1768   6741  th199096 		VN_RELE(vp);
   1769   7312    Danhua 		goto final;
   1770   6741  th199096 	}
   1771   6741  th199096 	if (cs->vp)
   1772   6741  th199096 		VN_RELE(cs->vp);
   1773   6741  th199096 
   1774   6741  th199096 	cs->vp = vp;
   1775   6741  th199096 	*cs->statusp = resp->status = NFS4_OK;
   1776   7312    Danhua 
   1777   7312    Danhua final:
   1778   7312    Danhua 	DTRACE_NFSV4_2(op__create__done, struct compound_state *, cs,
   1779   7312    Danhua 	    CREATE4res *, resp);
   1780   6741  th199096 }
   1781   6741  th199096 
   1782   6741  th199096 
   1783   6741  th199096 /*ARGSUSED*/
   1784   6741  th199096 static void
   1785   6741  th199096 mds_op_delegreturn(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
   1786   8023       Sam 	compound_state_t *cs)
   1787   6741  th199096 {
   1788   6741  th199096 	DELEGRETURN4args *args = &argop->nfs_argop4_u.opdelegreturn;
   1789   6741  th199096 	DELEGRETURN4res *resp = &resop->nfs_resop4_u.opdelegreturn;
   1790   6741  th199096 	rfs4_deleg_state_t *dsp;
   1791   6741  th199096 	nfsstat4 status;
   1792   6741  th199096 
   1793   7312    Danhua 	DTRACE_NFSV4_2(op__delegreturn__start, struct compound_state *, cs,
   1794   7312    Danhua 	    DELEGRETURN4args *, args);
   1795   7312    Danhua 
   1796   6741  th199096 	status = rfs4_get_deleg_state(cs, &args->deleg_stateid, &dsp);
   1797   6741  th199096 	resp->status = *cs->statusp = status;
   1798   6741  th199096 	if (status != NFS4_OK)
   1799   7312    Danhua 		goto final;
   1800   6741  th199096 
   1801   6741  th199096 	/* Ensure specified filehandle matches */
   1802  10447    Thomas 	if (cs->vp != dsp->rds_finfo->rf_vp) {
   1803   6741  th199096 		resp->status = *cs->statusp = NFS4ERR_BAD_STATEID;
   1804   6741  th199096 	} else
   1805   6741  th199096 		rfs4_return_deleg(dsp, FALSE);
   1806   6741  th199096 
   1807  10447    Thomas 	rfs4_update_lease(dsp->rds_client);
   1808   6741  th199096 
   1809   6741  th199096 	rfs4_deleg_state_rele(dsp);
   1810   7312    Danhua 
   1811   7312    Danhua final:
   1812   7312    Danhua 	DTRACE_NFSV4_2(op__delegreturn__done, struct compound_state *, cs,
   1813   7312    Danhua 	    DELEGRETURN4res *, resp);
   1814   6741  th199096 }
   1815   6741  th199096 
   1816   6741  th199096 
   1817   6741  th199096 
   1818   6741  th199096 /* ARGSUSED */
   1819   6741  th199096 static void
   1820   6741  th199096 mds_op_getattr(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
   1821   8023       Sam 	compound_state_t *cs)
   1822   6741  th199096 {
   1823   6741  th199096 	GETATTR4args *args = &argop->nfs_argop4_u.opgetattr;
   1824   6741  th199096 	GETATTR4res *resp = &resop->nfs_resop4_u.opgetattr;
   1825   6741  th199096 	struct nfs4_svgetit_arg sarg;
   1826   6741  th199096 	struct statvfs64 sb;
   1827   6741  th199096 	nfsstat4 status;
   1828   6741  th199096 
   1829   7312    Danhua 	DTRACE_NFSV4_2(op__getattr__start, struct compound_state *, cs,
   1830   7312    Danhua 	    GETATTR4args *, args);
   1831   7312    Danhua 
   1832   7312    Danhua 	if (cs->vp == NULL) {
   1833   7312    Danhua 		*cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
   1834   7312    Danhua 		goto final;
   1835   7312    Danhua 	}
   1836   7312    Danhua 
   1837   7312    Danhua 	if (cs->access == CS_ACCESS_DENIED) {
   1838   7312    Danhua 		*cs->statusp = resp->status = NFS4ERR_ACCESS;
   1839   7312    Danhua 		goto final;
   1840   6741  th199096 	}
   1841   6741  th199096 
   1842   6741  th199096 	sarg.sbp = &sb;
   1843   6741  th199096 	sarg.cs = cs;
   1844   6741  th199096 
   1845   6741  th199096 	status = attrmap4_to_vattrmask(&args->attr_request, &sarg);
   1846   6741  th199096 	if (status == NFS4_OK) {
   1847   6741  th199096 		status = bitmap4_get_sysattrs(&sarg);
   1848   6741  th199096 		if (status == NFS4_OK)
   1849   6741  th199096 			status = do_rfs4_op_getattr(&args->attr_request,
   1850   6741  th199096 			    &resp->obj_attributes, &sarg);
   1851   6741  th199096 	}
   1852   6741  th199096 	*cs->statusp = resp->status = status;
   1853   7312    Danhua 
   1854   7312    Danhua final:
   1855   7312    Danhua 	DTRACE_NFSV4_2(op__getattr__done, struct compound_state *, cs,
   1856   7312    Danhua 	    GETATTR4res *, resp);
   1857   6741  th199096 }
   1858   6741  th199096 
   1859   6741  th199096 /*ARGSUSED*/
   1860   6741  th199096 void
   1861   8023       Sam mds_op_getattr_free(nfs_resop4 *resop, compound_state_t *cs)
   1862   6741  th199096 {
   1863   6741  th199096 	/* Common function for NFSv4.0 and NFSv4.1 */
   1864   6741  th199096 	rfs4_op_getattr_free(resop);
   1865   6741  th199096 }
   1866   6741  th199096 
   1867   6741  th199096 /* ARGSUSED */
   1868   6741  th199096 static void
   1869   6741  th199096 mds_op_getfh(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
   1870   8023       Sam 	compound_state_t *cs)
   1871   6741  th199096 {
   1872   6741  th199096 	GETFH4res *resp = &resop->nfs_resop4_u.opgetfh;
   1873   6741  th199096 
   1874   7312    Danhua 	DTRACE_NFSV4_1(op__getfh__start,
   1875   7312    Danhua 	    struct compound_state *, cs);
   1876   7312    Danhua 
   1877   7312    Danhua 	if (cs->vp == NULL) {
   1878   7312    Danhua 		*cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
   1879   7312    Danhua 		goto final;
   1880   7312    Danhua 	}
   1881   7312    Danhua 	if (cs->access == CS_ACCESS_DENIED) {
   1882   7312    Danhua 		*cs->statusp = resp->status = NFS4ERR_ACCESS;
   1883   7312    Danhua 		goto final;
   1884   6741  th199096 	}
   1885   6741  th199096 
   1886   6741  th199096 	resp->object.nfs_fh4_val =
   1887   6741  th199096 	    kmem_alloc(cs->fh.nfs_fh4_len, KM_SLEEP);
   1888   6741  th199096 	nfs_fh4_copy(&cs->fh, &resp->object);
   1889   6741  th199096 	*cs->statusp = resp->status = NFS4_OK;
   1890   7312    Danhua 
   1891   7312    Danhua final:
   1892   7312    Danhua 	DTRACE_NFSV4_2(op__getfh__done, struct compound_state *, cs,
   1893   7312    Danhua 	    GETFH4res *, resp);
   1894   6741  th199096 }
   1895   6741  th199096 
   1896   6741  th199096 /*ARGSUSED*/
   1897   6741  th199096 static void
   1898   8023       Sam mds_op_getfh_free(nfs_resop4 *resop, compound_state_t *cs)
   1899   6741  th199096 {
   1900   6741  th199096 	/* Common function for NFSv4.0 and NFSv4.1 */
   1901   6741  th199096 	rfs4_op_getfh_free(resop);
   1902   6741  th199096 }
   1903   6741  th199096 
   1904   6741  th199096 /*
   1905   6741  th199096  * link: args: SAVED_FH: file, CURRENT_FH: target directory
   1906   6741  th199096  *	 res: status. If success - CURRENT_FH unchanged, return change_info
   1907   6741  th199096  */
   1908   6741  th199096 /* ARGSUSED */
   1909   6741  th199096 static void
   1910   6741  th199096 mds_op_link(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
   1911   8023       Sam 	compound_state_t *cs)
   1912   6741  th199096 {
   1913   6741  th199096 	LINK4args *args = &argop->nfs_argop4_u.oplink;
   1914   6741  th199096 	LINK4res *resp = &resop->nfs_resop4_u.oplink;
   1915   6741  th199096 	int error;
   1916   6741  th199096 	vnode_t *vp;
   1917   6741  th199096 	vnode_t *dvp;
   1918   6741  th199096 	struct vattr bdva, idva, adva;
   1919   6741  th199096 	char *nm;
   1920   6741  th199096 	uint_t  len;
   1921   6741  th199096 	caller_context_t ct;
   1922   6741  th199096 
   1923   7312    Danhua 	DTRACE_NFSV4_2(op__link__start, struct compound_state *, cs,
   1924   7312    Danhua 	    LINK4args *, args);
   1925   7312    Danhua 
   1926   6741  th199096 	/* SAVED_FH: source object */
   1927   6741  th199096 	vp = cs->saved_vp;
   1928   6741  th199096 	if (vp == NULL) {
   1929   6741  th199096 		*cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
   1930   7312    Danhua 		goto final;
   1931   6741  th199096 	}
   1932   6741  th199096 
   1933   6741  th199096 	/* CURRENT_FH: target directory */
   1934   6741  th199096 	dvp = cs->vp;
   1935   6741  th199096 	if (dvp == NULL) {
   1936   6741  th199096 		*cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
   1937   7312    Danhua 		goto final;
   1938   6741  th199096 	}
   1939   6741  th199096 
   1940   6741  th199096 	/*
   1941   6741  th199096 	 * If there is a non-shared filesystem mounted on this vnode,
   1942   6741  th199096 	 * do not allow to link any file in this directory.
   1943   6741  th199096 	 */
   1944   6741  th199096 	if (vn_ismntpt(dvp)) {
   1945   6741  th199096 		*cs->statusp = resp->status = NFS4ERR_ACCESS;
   1946   7312    Danhua 		goto final;
   1947   7312    Danhua 	}
   1948   7312    Danhua 
   1949   7312    Danhua 	if (cs->access == CS_ACCESS_DENIED) {
   1950   7312    Danhua 		*cs->statusp = resp->status = NFS4ERR_ACCESS;
   1951   7312    Danhua 		goto final;
   1952   6741  th199096 	}
   1953   6741  th199096 
   1954   6741  th199096 	/* Check source object's type validity */
   1955   6741  th199096 	if (vp->v_type == VDIR) {
   1956   6741  th199096 		*cs->statusp = resp->status = NFS4ERR_ISDIR;
   1957   7312    Danhua 		goto final;
   1958   6741  th199096 	}
   1959   6741  th199096 
   1960   6741  th199096 	/* Check target directory's type */
   1961   6741  th199096 	if (dvp->v_type != VDIR) {
   1962   6741  th199096 		*cs->statusp = resp->status = NFS4ERR_NOTDIR;
   1963   7312    Danhua 		goto final;
   1964   6741  th199096 	}
   1965   6741  th199096 
   1966   6741  th199096 	if (cs->saved_exi != cs->exi) {
   1967   6741  th199096 		*cs->statusp = resp->status = NFS4ERR_XDEV;
   1968   7312    Danhua 		goto final;
   1969   6741  th199096 	}
   1970   6741  th199096 
   1971   6741  th199096 	if (!utf8_dir_verify(&args->newname)) {
   1972   6741  th199096 		*cs->statusp = resp->status = NFS4ERR_INVAL;
   1973   7312    Danhua 		goto final;
   1974   6741  th199096 	}
   1975   6741  th199096 
   1976   6741  th199096 	nm = utf8_to_fn(&args->newname, &len, NULL);
   1977   6741  th199096 	if (nm == NULL) {
   1978   6741  th199096 		*cs->statusp = resp->status = NFS4ERR_INVAL;
   1979   7312    Danhua 		goto final;
   1980   6741  th199096 	}
   1981   6741  th199096 
   1982   6741  th199096 	if (len > MAXNAMELEN) {
   1983   6741  th199096 		*cs->statusp = resp->status = NFS4ERR_NAMETOOLONG;
   1984   6741  th199096 		kmem_free(nm, len);
   1985   7312    Danhua 		goto final;
   1986   6741  th199096 	}
   1987   6741  th199096 
   1988   6741  th199096 	if (rdonly4(cs->exi, cs->vp, req)) {
   1989   6741  th199096 		*cs->statusp = resp->status = NFS4ERR_ROFS;
   1990   6741  th199096 		kmem_free(nm, len);
   1991   7312    Danhua 		goto final;
   1992   6741  th199096 	}
   1993   6741  th199096 
   1994   6741  th199096 	ct.cc_sysid = 0;
   1995   6741  th199096 	ct.cc_pid = 0;
   1996   7739   jwahlig 	ct.cc_caller_id = cs->instp->caller_id;
   1997   7739   jwahlig 	ct.cc_flags = CC_DONTBLOCK;
   1998   6741  th199096 
   1999   6741  th199096 	/* Get "before" change value */
   2000   6741  th199096 	bdva.va_mask = AT_CTIME|AT_SEQ;
   2001   6741  th199096 	error = VOP_GETATTR(dvp, &bdva, 0, cs->cr, &ct);
   2002   6741  th199096 	if (error) {
   2003   6741  th199096 		*cs->statusp = resp->status = puterrno4(error);
   2004   6741  th199096 		kmem_free(nm, len);
   2005   7312    Danhua 		goto final;
   2006   6741  th199096 	}
   2007   6741  th199096 
   2008   6741  th199096 	NFS4_SET_FATTR4_CHANGE(resp->cinfo.before, bdva.va_ctime)
   2009   6741  th199096 
   2010   6741  th199096 	error = VOP_LINK(dvp, vp, nm, cs->cr, &ct, 0);
   2011   6741  th199096 
   2012   6741  th199096 	kmem_free(nm, len);
   2013   6741  th199096 
   2014   6741  th199096 	/*
   2015   6741  th199096 	 * Get the initial "after" sequence number, if it fails, set to zero
   2016   6741  th199096 	 */
   2017   6741  th199096 	idva.va_mask = AT_SEQ;
   2018   6741  th199096 	if (VOP_GETATTR(dvp, &idva, 0, cs->cr, &ct))
   2019   6741  th199096 		idva.va_seq = 0;
   2020   6741  th199096 
   2021   6741  th199096 	/*
   2022   6741  th199096 	 * Force modified data and metadata out to stable storage.
   2023   6741  th199096 	 */
   2024   6741  th199096 	(void) VOP_FSYNC(vp, FNODSYNC, cs->cr, &ct);
   2025   6741  th199096 	(void) VOP_FSYNC(dvp, 0, cs->cr, &ct);
   2026   6741  th199096 
   2027   6741  th199096 	if (error) {
   2028   6741  th199096 		*cs->statusp = resp->status = puterrno4(error);
   2029   7312    Danhua 		goto final;
   2030   6741  th199096 	}
   2031   6741  th199096 
   2032   6741  th199096 	/*
   2033   6741  th199096 	 * Get "after" change value, if it fails, simply return the
   2034   6741  th199096 	 * before value.
   2035   6741  th199096 	 */
   2036   6741  th199096 	adva.va_mask = AT_CTIME|AT_SEQ;
   2037   6741  th199096 	if (VOP_GETATTR(dvp, &adva, 0, cs->cr, &ct)) {
   2038   6741  th199096 		adva.va_ctime = bdva.va_ctime;
   2039   6741  th199096 		adva.va_seq = 0;
   2040   6741  th199096 	}
   2041   6741  th199096 
   2042   6741  th199096 	NFS4_SET_FATTR4_CHANGE(resp->cinfo.after, adva.va_ctime)
   2043   6741  th199096 
   2044   6741  th199096 	/*
   2045   6741  th199096 	 * The cinfo.atomic = TRUE only if we have
   2046   6741  th199096 	 * non-zero va_seq's, and it has incremented by exactly one
   2047   6741  th199096 	 * during the VOP_LINK and it didn't change during the VOP_FSYNC.
   2048   6741  th199096 	 */
   2049   6741  th199096 	if (bdva.va_seq && idva.va_seq && adva.va_seq &&
   2050   6741  th199096 	    idva.va_seq == (bdva.va_seq + 1) &&
   2051   6741  th199096 	    idva.va_seq == adva.va_seq)
   2052   6741  th199096 		resp->cinfo.atomic = TRUE;
   2053   6741  th199096 	else
   2054   6741  th199096 		resp->cinfo.atomic = FALSE;
   2055   6741  th199096 
   2056   6741  th199096 	*cs->statusp = resp->status = NFS4_OK;
   2057   7312    Danhua 
   2058   7312    Danhua final:
   2059   7312    Danhua 	DTRACE_NFSV4_2(op__link__done, struct compound_state *, cs,
   2060   7312    Danhua 	    LINK4res *, resp);
   2061   6741  th199096 }
   2062   6741  th199096 
   2063   6741  th199096 /*
   2064   6741  th199096  * Used by mds_op_lookup and mds_op_lookupp to do the actual work.
   2065   6741  th199096  */
   2066   6741  th199096 
   2067   6741  th199096 /* ARGSUSED */
   2068   6741  th199096 static nfsstat4
   2069   6741  th199096 mds_do_lookup(char *nm, uint_t buflen, struct svc_req *req,
   2070   6741  th199096 	struct compound_state *cs)
   2071   6741  th199096 {
   2072   6741  th199096 	int error;
   2073   6741  th199096 	int different_export = 0;
   2074   6741  th199096 	vnode_t *vp, *tvp, *pre_tvp = NULL, *oldvp = NULL;
   2075   6741  th199096 	struct exportinfo *exi = NULL, *pre_exi = NULL;
   2076   6741  th199096 	nfsstat4 stat;
   2077   6741  th199096 	fid_t fid;
   2078   6741  th199096 	int attrdir, dotdot, walk;
   2079   6741  th199096 	bool_t is_newvp = FALSE;
   2080   6741  th199096 	caller_context_t ct;
   2081   6741  th199096 	nfs41_fh_fmt_t *fhp;
   2082   6741  th199096 
   2083   6741  th199096 	fhp = (nfs41_fh_fmt_t *)cs->fh.nfs_fh4_val;
   2084   6741  th199096 
   2085   6741  th199096 	attrdir = ((cs->vp->v_flag & V_XATTRDIR) == V_XATTRDIR)
   2086   6741  th199096 	    ? FH41_ATTRDIR : 0;
   2087   6741  th199096 
   2088   6741  th199096 	ASSERT(FH41_GET_FLAG(fhp, FH41_ATTRDIR) == attrdir);
   2089   6741  th199096 
   2090   6741  th199096 	dotdot = (nm[0] == '.' && nm[1] == '.' && nm[2] == '\0');
   2091   6741  th199096 
   2092   6741  th199096 	/*
   2093   6741  th199096 	 * If dotdotting, then need to check whether it's
   2094   6741  th199096 	 * above the root of a filesystem, or above an
   2095   6741  th199096 	 * export point.
   2096   6741  th199096 	 */
   2097   6741  th199096 	if (dotdot) {
   2098   6741  th199096 
   2099   6741  th199096 		/*
   2100   6741  th199096 		 * If dotdotting at the root of a filesystem, then
   2101   6741  th199096 		 * need to traverse back to the mounted-on filesystem
   2102   6741  th199096 		 * and do the dotdot lookup there.
   2103   6741  th199096 		 */
   2104   6741  th199096 		if (cs->vp->v_flag & VROOT) {
   2105   6741  th199096 
   2106   6741  th199096 			/*
   2107   6741  th199096 			 * If at the system root, then can
   2108   6741  th199096 			 * go up no further.
   2109   6741  th199096 			 */
   2110   6741  th199096 			if (VN_CMP(cs->vp, rootdir))
   2111   6741  th199096 				return (puterrno4(ENOENT));
   2112   6741  th199096 
   2113   6741  th199096 			/*
   2114   6741  th199096 			 * Traverse back to the mounted-on filesystem
   2115   6741  th199096 			 */
   2116   6741  th199096 			cs->vp = untraverse(cs->vp);
   2117   6741  th199096 
   2118   6741  th199096 			/*
   2119   6741  th199096 			 * Set the different_export flag so we remember
   2120   6741  th199096 			 * to pick up a new exportinfo entry for
   2121   6741  th199096 			 * this new filesystem.
   2122   6741  th199096 			 */
   2123   6741  th199096 			different_export = 1;
   2124   6741  th199096 		} else {
   2125   6741  th199096 
   2126   6741  th199096 			/*
   2127   6741  th199096 			 * If dotdotting above an export point then set
   2128   6741  th199096 			 * the different_export to get new export info.
   2129   6741  th199096 			 */
   2130   6741  th199096 			different_export = nfs_exported(cs->exi, cs->vp);
   2131   6741  th199096 		}
   2132   6741  th199096 	}
   2133   6741  th199096 
   2134   6741  th199096 	ct.cc_sysid = 0;
   2135   6741  th199096 	ct.cc_pid = 0;
   2136   7739   jwahlig 	ct.cc_caller_id = cs->instp->caller_id;
   2137   7739   jwahlig 	ct.cc_flags = CC_DONTBLOCK;
   2138   6741  th199096 
   2139   6741  th199096 	error = VOP_LOOKUP(cs->vp, nm, &vp, NULL, 0, NULL, cs->cr,
   2140   6741  th199096 	    &ct, 0, NULL);
   2141   6741  th199096 	if (error)
   2142   6741  th199096 		return (puterrno4(error));
   2143   6741  th199096 
   2144   6741  th199096 	/*
   2145   6741  th199096 	 * If the vnode is in a pseudo filesystem, check whether it is visible.
   2146   6741  th199096 	 *
   2147   6741  th199096 	 * XXX if the vnode is a symlink and it is not visible in
   2148   6741  th199096 	 * a pseudo filesystem, return ENOENT (not following symlink).
   2149   6741  th199096 	 * V4 client can not mount such symlink.
   2150   6741  th199096 	 *
   2151   6741  th199096 	 * In the same exported filesystem, if the security flavor used
   2152   6741  th199096 	 * is not an explicitly shared flavor, limit the view to the visible
   2153   6741  th199096 	 * list entries only. This is not a WRONGSEC case because it's already
   2154   6741  th199096 	 * checked via PUTROOTFH/PUTPUBFH or PUTFH.
   2155   6741  th199096 	 */
   2156   6741  th199096 	if (!different_export &&
   2157   6741  th199096 	    (PSEUDO(cs->exi) || ! is_exported_sec(cs->nfsflavor, cs->exi) ||
   2158   6741  th199096 	    cs->access & CS_ACCESS_LIMITED)) {
   2159   6741  th199096 		if (! nfs_visible(cs->exi, vp, &different_export)) {
   2160   6741  th199096 			VN_RELE(vp);
   2161   6741  th199096 			return (puterrno4(ENOENT));
   2162   6741  th199096 		}
   2163   6741  th199096 	}
   2164   6741  th199096 
   2165   6741  th199096 	/*
   2166   6741  th199096 	 * If it's a mountpoint, then traverse it.
   2167   6741  th199096 	 */
   2168   6741  th199096 	if (vn_ismntpt(vp)) {
   2169   6741  th199096 		pre_exi = cs->exi;	/* save pre-traversed exportinfo */
   2170   6741  th199096 		pre_tvp = vp;		/* save pre-traversed vnode	*/
   2171   6741  th199096 
   2172   6741  th199096 		/*
   2173   6741  th199096 		 * hold pre_tvp to counteract rele by traverse.  We will
   2174   6741  th199096 		 * need pre_tvp below if checkexport4 fails
   2175   6741  th199096 		 */
   2176   6741  th199096 		VN_HOLD(pre_tvp);
   2177   6741  th199096 		tvp = vp;
   2178   6741  th199096 		if ((error = traverse(&tvp)) != 0) {
   2179   6741  th199096 			VN_RELE(vp);
   2180   6741  th199096 			VN_RELE(pre_tvp);
   2181   6741  th199096 			return (puterrno4(error));
   2182   6741  th199096 		}
   2183   6741  th199096 		vp = tvp;
   2184   6741  th199096 		different_export = 1;
   2185   6741  th199096 
   2186   6741  th199096 	} else if (vp->v_vfsp != cs->vp->v_vfsp) {
   2187   6741  th199096 		/*
   2188   6741  th199096 		 * The vfsp comparison is to handle the case where
   2189   6741  th199096 		 * a LOFS mount is shared.  lo_lookup traverses mount points,
   2190   6741  th199096 		 * and NFS is unaware of local fs transistions because
   2191   6741  th199096 		 * v_vfsmountedhere isn't set.  For this special LOFS case,
   2192   6741  th199096 		 * the dir and the obj returned by lookup will have different
   2193   6741  th199096 		 * vfs ptrs.
   2194   6741  th199096 		 */
   2195   6741  th199096 		different_export = 1;
   2196   6741  th199096 	}
   2197   6741  th199096 
   2198   6741  th199096 	if (different_export) {
   2199   6741  th199096 		bzero(&fid, sizeof (fid));
   2200   6741  th199096 		fid.fid_len = MAXFIDSZ;
   2201   6741  th199096 		error = vop_fid_pseudo(vp, &fid);
   2202   6741  th199096 		if (error) {
   2203   6741  th199096 			VN_RELE(vp);
   2204   6741  th199096 			if (pre_tvp)
   2205   6741  th199096 				VN_RELE(pre_tvp);
   2206   6741  th199096 			return (puterrno4(error));
   2207   6741  th199096 		}
   2208   6741  th199096 
   2209   6741  th199096 		if (dotdot)
   2210   6741  th199096 			exi = nfs_vptoexi(NULL, vp, cs->cr, &walk, NULL, TRUE);
   2211   6741  th199096 		else
   2212   6741  th199096 			exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid, vp);
   2213   6741  th199096 
   2214   6741  th199096 		if (exi == NULL) {
   2215   6741  th199096 			if (pre_tvp) {
   2216   6741  th199096 				/*
   2217   6741  th199096 				 * If this vnode is a mounted-on vnode,
   2218   6741  th199096 				 * but the mounted-on file system is not
   2219   6741  th199096 				 * exported, send back the filehandle for
   2220   6741  th199096 				 * the mounted-on vnode, not the root of
   2221   6741  th199096 				 * the mounted-on file system.
   2222   6741  th199096 				 */
   2223   6741  th199096 				VN_RELE(vp);
   2224   6741  th199096 				vp = pre_tvp;
   2225   6741  th199096 				exi = pre_exi;
   2226   6741  th199096 			} else {
   2227   6741  th199096 				VN_RELE(vp);
   2228   6741  th199096 				return (puterrno4(EACCES));
   2229   6741  th199096 			}
   2230   6741  th199096 		} else if (pre_tvp) {
   2231   6741  th199096 			/* we're done with pre_tvp now. release extra hold */
   2232   6741  th199096 			VN_RELE(pre_tvp);
   2233   6741  th199096 		}
   2234   6741  th199096 
   2235   6741  th199096 		cs->exi = exi;
   2236   6741  th199096 
   2237   6741  th199096 		/*
   2238   6741  th199096 		 * Now do a checkauth4.
   2239   6741  th199096 		 *
   2240   6741  th199096 		 * Checking here since the client/principle may not have
   2241   6741  th199096 		 * access to the cs->exi exported file system.
   2242   6741  th199096 		 *
   2243   6741  th199096 		 * If the client has access we also need to validate
   2244   6741  th199096 		 * the principle since it may have been re-mapped.
   2245   6741  th199096 		 *
   2246   6741  th199096 		 * We start with a new credential as a previous call to
   2247   6741  th199096 		 * checkauth4(), via a PUT*FH operation, wrote over cs->cr.
   2248   6741  th199096 		 */
   2249   6741  th199096 		crfree(cs->cr);
   2250   6741  th199096 		cs->cr = crdup(cs->basecr);
   2251   6741  th199096 
   2252   6741  th199096 		if (cs->vp)
   2253   6741  th199096 			oldvp = cs->vp;
   2254   6741  th199096 		cs->vp = vp;
   2255   6741  th199096 		is_newvp = TRUE;
   2256   6741  th199096 
   2257   6741  th199096 		stat = call_checkauth4(cs, req);
   2258   6741  th199096 		if (stat != NFS4_OK) {
   2259   6741  th199096 			VN_RELE(cs->vp);
   2260   6741  th199096 			cs->vp = oldvp;
   2261   6741  th199096 			return (stat);
   2262   6741  th199096 		}
   2263   6741  th199096 	}
   2264   6741  th199096 
   2265   6741  th199096 	/*
   2266   6741  th199096 	 * After various NFS checks, do a label check on the path
   2267   6741  th199096 	 * component. The label on this path should either be the
   2268   6741  th199096 	 * global zone's label or a zone's label. We are only
   2269   6741  th199096 	 * interested in the zone's label because exported files
   2270   6741  th199096 	 * in global zone is accessible (though read-only) to
   2271   6741  th199096 	 * clients. The exportability/visibility check is already
   2272   6741  th199096 	 * done before reaching this code.
   2273   6741  th199096 	 */
   2274   6741  th199096 	if (is_system_labeled()) {
   2275   6741  th199096 		bslabel_t *clabel;
   2276   6741  th199096 
   2277   6741  th199096 		ASSERT(req->rq_label != NULL);
   2278   6741  th199096 		clabel = req->rq_label;
   2279   6741  th199096 		DTRACE_PROBE2(tx__rfs4__log__info__oplookup__clabel, char *,
   2280   6741  th199096 		    "got client label from request(1)", struct svc_req *, req);
   2281   6741  th199096 
   2282   6741  th199096 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
   2283  10447    Thomas 			if (!do_rfs_label_check(clabel, vp,
   2284  10447    Thomas 			    DOMINANCE_CHECK, cs->exi)) {
   2285   6741  th199096 				error = EACCES;
   2286   6741  th199096 				goto err_out;
   2287   6741  th199096 			}
   2288   6741  th199096 		} else {
   2289   6741  th199096 			/*
   2290   6741  th199096 			 * We grant access to admin_low label clients
   2291   6741  th199096 			 * only if the client is trusted, i.e. also
   2292   6741  th199096 			 * running Solaris Trusted Extension.
   2293   6741  th199096 			 */
   2294   6741  th199096 			struct sockaddr	*ca;
   2295   6741  th199096 			int		addr_type;
   2296   6741  th199096 			void		*ipaddr;
   2297   6741  th199096 			tsol_tpc_t	*tp;
   2298   6741  th199096 
   2299   6741  th199096 			ca = (struct sockaddr *)svc_getrpccaller(
   2300   6741  th199096 			    req->rq_xprt)->buf;
   2301   6741  th199096 			if (ca->sa_family == AF_INET) {
   2302   6741  th199096 				addr_type = IPV4_VERSION;
   2303   6741  th199096 				ipaddr = &((struct sockaddr_in *)ca)->sin_addr;
   2304   6741  th199096 			} else if (ca->sa_family == AF_INET6) {
   2305   6741  th199096 				addr_type = IPV6_VERSION;
   2306   6741  th199096 				ipaddr = &((struct sockaddr_in6 *)
   2307   6741  th199096 				    ca)->sin6_addr;
   2308   6741  th199096 			}
   2309   6741  th199096 			tp = find_tpc(ipaddr, addr_type, B_FALSE);
   2310   6741  th199096 			if (tp == NULL || tp->tpc_tp.tp_doi !=
   2311   6741  th199096 			    l_admin_low->tsl_doi || tp->tpc_tp.host_type !=
   2312   6741  th199096 			    SUN_CIPSO) {
   2313   6741  th199096 				error = EACCES;
   2314   6741  th199096 				goto err_out;
   2315   6741  th199096 			}
   2316   6741  th199096 		}
   2317   6741  th199096 	}
   2318   6741  th199096 
   2319   6741  th199096 	error = mknfs41_fh(&cs->fh, vp, cs->exi);
   2320   6741  th199096 
   2321   6741  th199096 err_out:
   2322   6741  th199096 	if (error) {
   2323   6741  th199096 		if (is_newvp) {
   2324   6741  th199096 			VN_RELE(cs->vp);
   2325   6741  th199096 			cs->vp = oldvp;
   2326   6741  th199096 		} else
   2327   6741  th199096 			VN_RELE(vp);
   2328   6741  th199096 		return (puterrno4(error));
   2329   6741  th199096 	}
   2330   6741  th199096 
   2331   6741  th199096 	if (!is_newvp) {
   2332   6741  th199096 		if (cs->vp)
   2333   6741  th199096 			VN_RELE(cs->vp);
   2334   6741  th199096 		cs->vp = vp;
   2335   6741  th199096 	} else if (oldvp)
   2336   6741  th199096 		VN_RELE(oldvp);
   2337   6741  th199096 
   2338   6741  th199096 	/*
   2339   6741  th199096 	 * if did lookup on attrdir and didn't lookup .., set named
   2340   6741  th199096 	 * attr fh flag
   2341   6741  th199096 	 */
   2342   6741  th199096 	if (attrdir && ! dotdot)
   2343   6741  th199096 		FH41_SET_FLAG(fhp, FH41_NAMEDATTR);
   2344   6741  th199096 
   2345   6741  th199096 	/* Assume false for now, open proc will set this */
   2346   6741  th199096 	cs->mandlock = FALSE;
   2347   6741  th199096 
   2348   6741  th199096 	return (NFS4_OK);
   2349   6741  th199096 }
   2350   6741  th199096 
   2351   6741  th199096 /* ARGSUSED */
   2352   6741  th199096 static void
   2353   6741  th199096 mds_op_lookup(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
   2354   8023       Sam 	compound_state_t *cs)
   2355   6741  th199096 {
   2356   6741  th199096 	LOOKUP4args *args = &argop->nfs_argop4_u.oplookup;
   2357   6741  th199096 	LOOKUP4res *resp = &resop->nfs_resop4_u.oplookup;
   2358   6741  th199096 	char *nm;
   2359   6741  th199096 	uint_t len;
   2360   6741  th199096 
   2361   7312    Danhua 	DTRACE_NFSV4_2(op__lookup__start, struct compound_state *, cs,
   2362   7312    Danhua 	    LOOKUP4args *, args);
   2363   7312    Danhua 
   2364   7312    Danhua 	if (cs->vp == NULL) {
   2365   7312    Danhua 		*cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
   2366   7312    Danhua 		goto final;
   2367   6741  th199096 	}
   2368   6741  th199096 
   2369   6741  th199096 	if (cs->vp->v_type == VLNK) {
   2370   6741  th199096 		*cs->statusp = resp->status = NFS4ERR_SYMLINK;
   2371   7312    Danhua 		goto final;
   2372   6741  th199096 	}
   2373   6741  th199096 
   2374   6741  th199096 	if (cs->vp->v_type != VDIR) {
   2375   6741  th199096 		*cs->statusp = resp->status = NFS4ERR_NOTDIR;
   2376   7312    Danhua 		goto final;
   2377   6741  th199096 	}
   2378   6741  th199096 
   2379   6741  th199096 	if (!utf8_dir_verify(&args->objname)) {
   2380   6741  th199096 		*cs->statusp = resp->status = NFS4ERR_INVAL;
   2381   7312    Danhua 		goto final;
   2382   6741  th199096 	}
   2383   6741  th199096 
   2384   6741  th199096 	nm = utf8_to_str(&args->objname, &len, NULL);
   2385   6741  th199096 	if (nm == NULL) {
   2386   6741  th199096 		*cs->statusp = resp->status = NFS4ERR_INVAL;
   2387   7312    Danhua 		goto final;
   2388   6741  th199096 	}
   2389   6741  th199096 
   2390   6741  th199096 	if (len > MAXNAMELEN) {
   2391   6741  th199096 		*cs->statusp = resp->status = NFS4ERR_NAMETOOLONG;
   2392   6741  th199096 		kmem_free(nm, len);
   2393   7312    Danhua 		goto final;
   2394   6741  th199096 	}
   2395   6741  th199096 
   2396   6741  th199096 	*cs->statusp = resp->status = mds_do_lookup(nm, len, req, cs);
   2397   6741  th199096 
   2398   6741  th199096 	kmem_free(nm, len);
   2399   7312    Danhua 
   2400   7312    Danhua final:
   2401   7312    Danhua 	DTRACE_NFSV4_2(op__lookup__done, struct compound_state *, cs,
   2402   7312    Danhua 	    LOOKUP4res *, resp);
   2403   6741  th199096 }
   2404   6741  th199096 
   2405   6741  th199096 /* ARGSUSED */
   2406   6741  th199096 static void
   2407   6741  th199096 mds_op_lookupp(nfs_argop4 *args, nfs_resop4 *resop, struct svc_req *req,
   2408   8023       Sam 	compound_state_t *cs)
   2409   6741  th199096 {
   2410   6741  th199096 	LOOKUPP4res *resp = &resop->nfs_resop4_u.oplookupp;
   2411   6741  th199096 
   2412   7312    Danhua 	DTRACE_NFSV4_1(op__lookupp__start, struct compound_state *, cs);
   2413   7312    Danhua 
   2414   7312    Danhua 	if (cs->vp == NULL) {
   2415   7312    Danhua 		*cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
   2416   7312    Danhua 		goto final;
   2417   6741  th199096 	}
   2418   6741  th199096 
   2419   6741  th199096 	if (cs->vp->v_type != VDIR) {
   2420   6741  th199096 		*cs->statusp = resp->status = NFS4ERR_NOTDIR;
   2421   7312    Danhua 		goto final;
   2422   6741  th199096 	}
   2423   6741  th199096 
   2424   6741  th199096 	*cs->statusp = resp->status = mds_do_lookup("..", 3, req, cs);
   2425   6741  th199096 
   2426   6741  th199096 	/*
   2427   6741  th199096 	 * From NFSV4 Specification, LOOKUPP should not check for
   2428   6741  th199096 	 * NFS4ERR_WRONGSEC. Retrun NFS4_OK instead.
   2429   6741  th199096 	 */
   2430   6741  th199096 	if (resp->status == NFS4ERR_WRONGSEC) {
   2431   6741  th199096 		*cs->statusp = resp->status = NFS4_OK;
   2432   6741  th199096 	}
   2433   7312    Danhua 
   2434   7312    Danhua final:
   2435   7312    Danhua 	DTRACE_NFSV4_2(op__lookupp__done, struct compound_state *, cs,
   2436   7312    Danhua 	    LOOKUPP4res *, resp);
   2437   6741  th199096 }
   2438   6741  th199096 
   2439   6741  th199096 
   2440   6741  th199096 /*ARGSUSED2*/
   2441   6741  th199096 static void
   2442   6741  th199096 mds_op_openattr(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
   2443   8023       Sam 	compound_state_t *cs)
   2444   6741  th199096 {
   2445   6741  th199096 	OPENATTR4args	*args = &argop->nfs_argop4_u.opopenattr;
   2446   6741  th199096 	OPENATTR4res	*resp = &resop->nfs_resop4_u.opopenattr;
   2447   6741  th199096 	vnode_t		*avp = NULL;
   2448   6741  th199096 	int		lookup_flags = LOOKUP_XATTR, error;
   2449   6741  th199096 	int		exp_ro = 0;
   2450   6741  th199096 	caller_context_t ct;
   2451   6741  th199096 
   2452   7312    Danhua 	DTRACE_NFSV4_2(op__openattr__start, struct compound_state *, cs,
   2453   7312    Danhua 	    OPENATTR4args *, args);
   2454   7312    Danhua 
   2455   7312    Danhua 	if (cs->vp == NULL) {
   2456   7312    Danhua 		*cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
   2457   7312    Danhua 		goto final;
   2458   6741  th199096 	}
   2459   6741  th199096 
   2460   6741  th199096 	/*
   2461   6741  th199096 	 * Make a couple of checks made by copen()
   2462   6741  th199096 	 *
   2463   6741  th199096 	 * Check to make sure underlying fs supports xattrs.  This
   2464   6741  th199096 	 * is required because solaris filesystem implementations
   2465   6741  th199096 	 * (UFS/TMPFS) don't enforce the noxattr mount option
   2466   6741  th199096 	 * in VOP_LOOKUP(LOOKUP_XATTR).  If fs doesn't support this
   2467   6741  th199096 	 * pathconf cmd or if fs supports cmd but doesn't claim
   2468   6741  th199096 	 * support for xattr, return NOTSUPP.  It would be better
   2469   6741  th199096 	 * to use VOP_PATHCONF( _PC_XATTR_ENABLED) for this; however,
   2470   6741  th199096 	 * that cmd is not available to VOP_PATHCONF interface
   2471   6741  th199096 	 * (it's only implemented inside pathconf syscall)...
   2472   6741  th199096 	 *
   2473   6741  th199096 	 * Verify permission to put attributes on files (access
   2474   6741  th199096 	 * checks from copen).
   2475   6741  th199096 	 */
   2476   6741  th199096 
   2477   6741  th199096 	if ((cs->vp->v_vfsp->vfs_flag & VFS_XATTR) == 0) {
   2478   6741  th199096 		error = ENOTSUP;
   2479   6741  th199096 		goto error_out;
   2480   6741  th199096 	}
   2481   6741  th199096 
   2482   6741  th199096 	ct.cc_sysid = 0;
   2483   6741  th199096 	ct.cc_pid = 0;
   2484   7739   jwahlig 	ct.cc_caller_id = cs->instp->caller_id;
   2485   7739   jwahlig 	ct.cc_flags = CC_DONTBLOCK;
   2486   6741  th199096 
   2487   6741  th199096 	if ((VOP_ACCESS(cs->vp, VREAD, 0, cs->cr, &ct) != 0) &&
   2488   6741  th199096 	    (VOP_ACCESS(cs->vp, VWRITE, 0, cs->cr, &ct) != 0) &&
   2489   6741  th199096 	    (VOP_ACCESS(cs->vp, VEXEC, 0, cs->cr, &ct) != 0)) {
   2490   6741  th199096 		error = EACCES;
   2491   6741  th199096 		goto error_out;
   2492   6741  th199096 	}
   2493   6741  th199096 
   2494   6741  th199096 	/*
   2495   6741  th199096 	 * The CREATE_XATTR_DIR VOP flag cannot be specified if
   2496   6741  th199096 	 * the file system is exported read-only -- regardless of
   2497   6741  th199096 	 * createdir flag.  Otherwise the attrdir would be created
   2498   6741  th199096 	 * (assuming server fs isn't mounted readonly locally).  If
   2499   6741  th199096 	 * VOP_LOOKUP returns ENOENT in this case, the error will
   2500   6741  th199096 	 * be translated into EROFS.  ENOSYS is mapped to ENOTSUP
   2501   6741  th199096 	 * because specfs has no VOP_LOOKUP op, so the macro would
   2502   6741  th199096 	 * return ENOSYS.  EINVAL is returned by all (current)
   2503   6741  th199096 	 * Solaris file system implementations when any of their
   2504   6741  th199096 	 * restrictions are violated (xattr(dir) can't have xattrdir).
   2505   6741  th199096 	 * Returning NOTSUPP is more appropriate in this case
   2506   6741  th199096 	 * because the object will never be able to have an attrdir.
   2507   6741  th199096 	 */
   2508   6741  th199096 	if (args->createdir && ! (exp_ro = rdonly4(cs->exi, cs->vp, req)))
   2509   6741  th199096 		lookup_flags |= CREATE_XATTR_DIR;
   2510   6741  th199096 
   2511   6741  th199096 	error = VOP_LOOKUP(cs->vp, "", &avp, NULL, lookup_flags, NULL,
   2512   6741  th199096 	    cs->cr, &ct, 0, NULL);
   2513   6741  th199096 
   2514   6741  th199096 	if (error) {
   2515   6741  th199096 		if (error == ENOENT && args->createdir && exp_ro)
   2516   6741  th199096 			error = EROFS;
   2517   6741  th199096 		else if (error == EINVAL || error == ENOSYS)
   2518   6741  th199096 			error = ENOTSUP;
   2519   6741  th199096 		goto error_out;
   2520   6741  th199096 	}
   2521   6741  th199096 
   2522   6741  th199096 	ASSERT(avp->v_flag & V_XATTRDIR);
   2523   6741  th199096 
   2524   6741  th199096 	error = mknfs41_fh(&cs->fh, avp, cs->exi);
   2525   6741  th199096 
   2526   6741  th199096 	if (error) {
   2527   6741  th199096 		VN_RELE(avp);
   2528   6741  th199096 		goto error_out;
   2529   6741  th199096 	}
   2530   6741  th199096 
   2531   6741  th199096 	VN_RELE(cs->vp);
   2532   6741  th199096 	cs->vp = avp;
   2533   6741  th199096 
   2534   6741  th199096 	/*
   2535   6741  th199096 	 * There is no requirement for an attrdir fh flag
   2536   6741  th199096 	 * because the attrdir has a vnode flag to distinguish
   2537   6741  th199096 	 * it from regular (non-xattr) directories.  The
   2538   6741  th199096 	 * FH41_ATTRDIR flag is set for future sanity checks.
   2539   6741  th199096 	 */
   2540   6741  th199096 	FH41_SET_FLAG((nfs41_fh_fmt_t *)cs->fh.nfs_fh4_val, FH41_ATTRDIR);
   2541   6741  th199096 	*cs->statusp = resp->status = NFS4_OK;
   2542   7312    Danhua 	goto final;
   2543   6741  th199096 
   2544   6741  th199096 error_out:
   2545   6741  th199096 
   2546   6741  th199096 	*cs->statusp = resp->status = puterrno4(error);
   2547   7312    Danhua 
   2548   7312    Danhua final:
   2549   7312    Danhua 	DTRACE_NFSV4_2(op__openattr__done, struct compound_state *, cs,
   2550   7312    Danhua 	    OPENATTR4res *, resp);
   2551   6741  th199096 }
   2552   6741  th199096 
   2553   6741  th199096 static int
   2554   7739   jwahlig do_io(int direction, vnode_t *vp, struct uio *uio, int ioflag, cred_t *cred,
   2555   7739   jwahlig     caller_context_t *ct)
   2556   6741  th199096 {
   2557   6741  th199096 	int error;
   2558   6741  th199096 	int i;
   2559   6741  th199096 	clock_t delaytime;
   2560   6741  th199096 
   2561   6741  th199096 	delaytime = MSEC_TO_TICK_ROUNDUP(rfs4_lock_delay);
   2562   6741  th199096 
   2563   6741  th199096 	/*
   2564   6741  th199096 	 * Don't block on mandatory locks. If this routine returns
   2565   6741  th199096 	 * EAGAIN, the caller should return NFS4ERR_LOCKED.
   2566   6741  th199096 	 */
   2567   6741  th199096 	uio->uio_fmode = FNONBLOCK;
   2568   6741  th199096 
   2569   6741  th199096 	for (i = 0; i < rfs4_maxlock_tries; i++) {
   2570   6741  th199096 		if (direction == FREAD) {
   2571   7739   jwahlig 			(void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, ct);
   2572   7739   jwahlig 			error = VOP_READ(vp, uio, ioflag, cred, ct);
   2573   7739   jwahlig 			VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, ct);
   2574   7739   jwahlig 		} else {
   2575   7739   jwahlig 			(void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, ct);
   2576   7739   jwahlig 			error = VOP_WRITE(vp, uio, ioflag, cred, ct);
   2577   7739   jwahlig 			VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, ct);
   2578   6741  th199096 		}
   2579   6741  th199096 
   2580   6741  th199096 		if (error != EAGAIN)
   2581   6741  th199096 			break;
   2582   6741  th199096 
   2583   6741  th199096 		if (i < rfs4_maxlock_tries - 1) {
   2584   6741  th199096 			delay(delaytime);
   2585   6741  th199096 			delaytime *= 2;
   2586   6741  th199096 		}
   2587   6741  th199096 	}
   2588   6741  th199096 
   2589   6741  th199096 	return (error);
   2590   6741  th199096 }
   2591   6741  th199096 
   2592   6741  th199096 /* ARGSUSED */
   2593   6741  th199096 static void
   2594   6741  th199096 mds_op_read(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
   2595   8023       Sam 	compound_state_t *cs)
   2596   8023       Sam {
   2597   6741  th199096 	READ4args *args = &argop->nfs_argop4_u.opread;
   2598   6741  th199096 	READ4res *resp = &resop->nfs_resop4_u.opread;
   2599   6741  th199096 	int error;
   2600   8023       Sam 	nnode_t *nn = NULL;
   2601   6741  th199096 	struct iovec iov;
   2602   6741  th199096 	struct uio uio;
   2603   6741  th199096 	bool_t *deleg = &cs->deleg;
   2604   6741  th199096 	nfsstat4 stat;
   2605   6741  th199096 	mblk_t *mp;
   2606   6741  th199096 	int alloc_err = 0;
   2607   6741  th199096 	caller_context_t ct;
   2608   8023       Sam 	uint32_t nnioflags = 0;
   2609   6741  th199096 
   2610   7312    Danhua 	DTRACE_NFSV4_2(op__read__start, struct compound_state *, cs,
   2611   7312    Danhua 	    READ4args, args);
   2612   6741  th199096 
   2613   8023       Sam 	nn = cs->nn;
   2614   8023       Sam 	if (nn == NULL) {
   2615   8023       Sam 		*cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
   2616   8023       Sam 		goto final;
   2617   8023       Sam 	}
   2618   8023       Sam 	if (cs->access == CS_ACCESS_DENIED) {
   2619   8023       Sam 		*cs->statusp = resp->status = NFS4ERR_ACCESS;
   2620   8023       Sam 		goto final;
   2621   8023       Sam 	}
   2622   8023       Sam 
   2623   8023       Sam 	if ((stat = nnop_check_stateid(nn, cs, FREAD, &args->stateid,
   2624   8431    Piyush 	    FALSE, deleg, TRUE, &ct, NULL)) != NFS4_OK) {
   2625   6741  th199096 		*cs->statusp = resp->status = stat;
   2626   8023       Sam 		goto final;
   2627   8023       Sam 	}
   2628   8023       Sam 
   2629   8023       Sam 	error = nnop_io_prep(nn, &nnioflags, cs->cr, &ct, args->offset,
   2630   8023       Sam 	    args->count, NULL);
   2631   8023       Sam 	if (error != 0) {
   2632   8023       Sam 		*cs->statusp = resp->status = nnode_stat4(error, 1);
   2633   8023       Sam 		goto out;
   2634   8023       Sam 	}
   2635   8023       Sam 
   2636   8023       Sam 	if (nnioflags & NNODE_IO_FLAG_PAST_EOF) {
   2637   6741  th199096 		*cs->statusp = resp->status = NFS4_OK;
   2638   6741  th199096 		resp->eof = TRUE;
   2639   6741  th199096 		resp->data_len = 0;
   2640   6741  th199096 		resp->data_val = NULL;
   2641   6741  th199096 		resp->mblk = NULL;
   2642   6741  th199096 		*cs->statusp = resp->status = NFS4_OK;
   2643   6741  th199096 		goto out;
   2644   6741  th199096 	}
   2645   6741  th199096 
   2646   6741  th199096 	if (args->count == 0) {
   2647   6741  th199096 		*cs->statusp = resp->status = NFS4_OK;
   2648   6741  th199096 		resp->eof = FALSE;
   2649   6741  th199096 		resp->data_len = 0;
   2650   6741  th199096 		resp->data_val = NULL;
   2651   6741  th199096 		resp->mblk = NULL;
   2652   6741  th199096 		goto out;
   2653   6741  th199096 	}
   2654   6741  th199096 
   2655   6741  th199096 	/*
   2656   6741  th199096 	 * Do not allocate memory more than maximum allowed
   2657   6741  th199096 	 * transfer size
   2658   6741  th199096 	 */
   2659   6741  th199096 	if (args->count > rfs4_tsize(req))
   2660   6741  th199096 		args->count = rfs4_tsize(req);
   2661   6741  th199096 
   2662   8023       Sam 	if (args->wlist) {
   2663   8023       Sam 		mp = NULL;
   2664   8023       Sam 		(void) rdma_get_wchunk(req, &iov, args->wlist);
   2665   8023       Sam 	} else {
   2666   8023       Sam 		/*
   2667   8023       Sam 		 * mp will contain the data to be sent out in the read reply.
   2668   8023       Sam 		 * It will be freed after the reply has been sent.
   2669   8023       Sam 		 * Let's roundup the data to a BYTES_PER_XDR_UNIT multiple,
   2670   8023       Sam 		 * so that the call to xdrmblk_putmblk() never fails.
   2671   8023       Sam 		 * If the first alloc of the requested size fails, then
   2672   8023       Sam 		 * decrease the size to something more reasonable and wait
   2673   8023       Sam 		 * for the allocation to occur.
   2674   8023       Sam 		 */
   2675   8023       Sam 		mp = allocb(RNDUP(args->count), BPRI_MED);
   2676   8023       Sam 		if (mp == NULL) {
   2677   8023       Sam 			if (args->count > MAXBSIZE)
   2678   8023       Sam 				args->count = MAXBSIZE;
   2679   8023       Sam 			mp = allocb_wait(RNDUP(args->count), BPRI_MED,
   2680   8023       Sam 			    STR_NOSIG, &alloc_err);
   2681   8023       Sam 		}
   2682   8023       Sam 		ASSERT(mp != NULL);
   2683   8023       Sam 		ASSERT(alloc_err == 0);
   2684   8023       Sam 
   2685   8023       Sam 		iov.iov_base = (caddr_t)mp->b_datap->db_base;
   2686   8023       Sam 		iov.iov_len = args->count;
   2687   8023       Sam 	}
   2688   8023       Sam 
   2689   6741  th199096 	uio.uio_iov = &iov;
   2690   6741  th199096 	uio.uio_iovcnt = 1;
   2691   6741  th199096 	uio.uio_segflg = UIO_SYSSPACE;
   2692   6741  th199096 	uio.uio_extflg = UIO_COPY_CACHED;
   2693   6741  th199096 	uio.uio_loffset = args->offset;
   2694   6741  th199096 	uio.uio_resid = args->count;
   2695   6741  th199096 
   2696   8023       Sam 	error = nnop_read(nn, &nnioflags, cs->cr, &ct, &uio, 0);
   2697   6741  th199096 	if (error) {
   2698   8028       Sam 		if (mp != NULL)
   2699   8028       Sam 			freeb(mp);
   2700   8023       Sam 		*cs->statusp = resp->status = nnode_stat4(error, 1);
   2701   6741  th199096 		goto out;
   2702   6741  th199096 	}
   2703   6741  th199096 
   2704   6741  th199096 	*cs->statusp = resp->status = NFS4_OK;
   2705   6741  th199096 
   2706   6741  th199096 	ASSERT(uio.uio_resid >= 0);
   2707   6741  th199096 	resp->data_len = args->count - uio.uio_resid;
   2708   6741  th199096 	resp->data_val = (char *)mp->b_datap->db_base;
   2709   6741  th199096 	resp->mblk = mp;
   2710   6741  th199096 
   2711   8023       Sam 	resp->eof = (nnioflags & NNODE_IO_FLAG_EOF) ? TRUE : FALSE;
   2712   8023       Sam 
   2713   8023       Sam out:
   2714   8023       Sam 	nnop_io_release(nn, nnioflags, &ct);
   2715   7312    Danhua 
   2716   7312    Danhua final:
   2717   7312    Danhua 	DTRACE_NFSV4_2(op__read__done, struct compound_state *, cs,
   2718   7312    Danhua 	    READ4res *, resp);
   2719   6741  th199096 }
   2720   6741  th199096 
   2721   6741  th199096 /*ARGSUSED*/
   2722   6741  th199096 static void
   2723   8023       Sam mds_op_read_free(nfs_resop4 *resop, compound_state_t *cs)
   2724   6741  th199096 {
   2725   6741  th199096 	/* Common function for NFSv4.0 and NFSv4.1 */
   2726   6741  th199096 	rfs4_op_read_free(resop);
   2727   6741  th199096 }
   2728   6741  th199096 
   2729   6741  th199096 /* ARGSUSED */
   2730   6741  th199096 static void
   2731   6741  th199096 mds_op_putpubfh(nfs_argop4 *args, nfs_resop4 *resop, struct svc_req *req,
   2732   8023       Sam 	compound_state_t *cs)
   2733   6741  th199096 {
   2734   6741  th199096 	PUTPUBFH4res *resp = &resop->nfs_resop4_u.opputpubfh;
   2735   6741  th199096 	int error;
   2736   6741  th199096 	vnode_t *vp;
   2737   6741  th199096 	struct exportinfo *exi, *sav_exi;
   2738   6741  th199096 	nfs41_fh_fmt_t *fhp;
   2739   6741  th199096 	fid_t exp_fid;
   2740   7312    Danhua 
   2741   7312    Danhua 	DTRACE_NFSV4_1(op__putpubfh__start, struct compound_state *, cs);
   2742   6741  th199096 
   2743   6741  th199096 	if (cs->vp) {
   2744   6741  th199096 		VN_RELE(cs->vp);
   2745   6741  th199096 		cs->vp = NULL;
   2746   6741  th199096 	}
   2747   6741  th199096 
   2748   6741  th199096 	if (cs->cr)
   2749   6741  th199096 		crfree(cs->cr);
   2750   6741  th199096 
   2751   6741  th199096 	cs->cr = crdup(cs->basecr);
   2752   6741  th199096 
   2753   6741  th199096 	vp = exi_public->exi_vp;
   2754   6741  th199096 	if (vp == NULL) {
   2755   6741  th199096 		*cs->statusp = resp->status = NFS4ERR_SERVERFAULT;
   2756   7312    Danhua 		goto final;
   2757   6741  th199096 	}
   2758   6741  th199096 
   2759   6741  th199096 	error = mknfs41_fh(&cs->fh, vp, exi_public);
   2760   6741  th199096 	if (error != 0) {
   2761   6741  th199096 		*cs->statusp = resp->status = puterrno4(error);
   2762   7312    Danhua 		goto final;
   2763   6741  th199096 	}
   2764   6741  th199096 	sav_exi = cs->exi;
   2765   6741  th199096 	if (exi_public == exi_root) {
   2766   6741  th199096 		/*
   2767   6741  th199096 		 * No filesystem is actually shared public, so we default
   2768   6741  th199096 		 * to exi_root. In this case, we must check whether root
   2769   6741  th199096 		 * is exported.
   2770   6741  th199096 		 */
   2771   6741  th199096 		fhp = (nfs41_fh_fmt_t *)cs->fh.nfs_fh4_val;
   2772   6741  th199096 
   2773   6741  th199096 		exp_fid.fid_len = fhp->fh.v1.export_fid.len;
   2774   6741  th199096 
   2775   6741  th199096 		bcopy(fhp->fh.v1.export_fid.val, exp_fid.fid_data,
   2776   6741  th199096 		    exp_fid.fid_len);
   2777   6741  th199096 
   2778   6741  th199096 		/*
   2779   6741  th199096 		 * if root filesystem is exported, the exportinfo struct that we
   2780   6741  th199096 		 * should use is what checkexport4 returns, because root_exi is
   2781   6741  th199096 		 * actually a mostly empty struct.
   2782   6741  th199096 		 */
   2783   6741  th199096 		exi = checkexport4(&fhp->fh.v1.export_fsid, &exp_fid, NULL);
   2784   6741  th199096 		cs->exi = ((exi != NULL) ? exi : exi_public);
   2785   6741  th199096 	} else {
   2786   6741  th199096 		/*
   2787   6741  th199096 		 * it's a properly shared filesystem
   2788   6741  th199096 		 */
   2789   6741  th199096 		cs->exi = exi_public;
   2790   6741  th199096 	}
   2791   6741  th199096 
   2792   6741  th199096 	VN_HOLD(vp);
   2793   6741  th199096 	cs->vp = vp;
   2794   6741  th199096 
   2795   6741  th199096 	if ((resp->status = call_checkauth4(cs, req)) != NFS4_OK) {
   2796   6741  th199096 		VN_RELE(cs->vp);
   2797   6741  th199096 		cs->vp = NULL;
   2798   6741  th199096 		cs->exi = sav_exi;
   2799   7312    Danhua 		goto final;
   2800   7312    Danhua 	}
   2801   7312    Danhua 
   2802   7312    Danhua 	*cs->statusp = resp->status = NFS4_OK;
   2803   7312    Danhua 
   2804   7312    Danhua final:
   2805   7312    Danhua 	DTRACE_NFSV4_2(op__putpubfh__done, struct compound_state *, cs,
   2806   7312    Danhua 	    PUTPUBFH4res *, resp);
   2807   6741  th199096 }
   2808   6741  th199096 
   2809   7739   jwahlig /*
   2810   7739   jwahlig  * XXX - issue with put*fh operations.
   2811   7739   jwahlig  *
   2812   7739   jwahlig  * let us assume that /export/home is shared via NFS and a NFS client
   2813   7739   jwahlig  * wishes to mount /export/home/joe.
   2814   7739   jwahlig  *
   2815   7739   jwahlig  * If /export, home, or joe have restrictive search permissions, then
   2816   7739   jwahlig  * the NFS Server should not return a filehandle to the client.
   2817   7739   jwahlig  *
   2818   7739   jwahlig  * This case is easy to enforce. However, the NFS Client does not know
   2819   7739   jwahlig  * which security flavor should be used until the pathname has been
   2820   7739   jwahlig  * fully resolved. In addition there is another complication for uid
   2821   7739   jwahlig  * mapping. If the credential being used is root, the default behaviour
   2822   7739   jwahlig  * will be to map it to the anonymous user. However the NFS Server can not
   2823   7739   jwahlig  * map it until the pathname has been fully resolved.
   2824   7739   jwahlig  *
   2825   7739   jwahlig  * XXX: JEFF:  Proposed solution.
   2826   7739   jwahlig  *
   2827   7739   jwahlig  * Luckily, SECINFO uses a full pathname.  So what we will
   2828   7739   jwahlig  * have to do in mds_op_lookup is check that flavor of
   2829   7739   jwahlig  * the target object matches that of the request, and if root was the
   2830   7739   jwahlig  * caller, check for the root= and anon= options, and if necessary,
   2831   7739   jwahlig  * repeat the lookup using the right cred_t.
   2832   7739   jwahlig  *
   2833   7739   jwahlig  * But that's not done yet.
   2834   7739   jwahlig  */
   2835   6741  th199096 /* ARGSUSED */
   2836   6741  th199096 static void
   2837   6741  th199096 mds_op_putfh(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
   2838   8023       Sam 	compound_state_t *cs)
   2839   6741  th199096 {
   2840   6741  th199096 	PUTFH4args *args = &argop->nfs_argop4_u.opputfh;
   2841   6741  th199096 	PUTFH4res *resp = &resop->nfs_resop4_u.opputfh;
   2842   8023       Sam 	nfs41_fh_fmt_t *fhp = NULL;
   2843   6741  th199096 	fid_t  exp_fid;
   2844   8023       Sam 	int error;
   2845   6741  th199096 
   2846   7312    Danhua 	DTRACE_NFSV4_2(op__putfh__start, struct compound_state *, cs,
   2847   7312    Danhua 	    PUTFH4args *, args);
   2848   7312    Danhua 
   2849   6741  th199096 	/*
   2850   8023       Sam 	 * release the old nnode, vnode and cred.
   2851   8023       Sam 	 */
   2852   8023       Sam 	if (cs->nn)
   2853   8023       Sam 		nnode_rele(&cs->nn);
   2854   6741  th199096 	if (cs->vp) {
   2855   6741  th199096 		VN_RELE(cs->vp);
   2856   6741  th199096 		cs->vp = NULL;
   2857   6741  th199096 	}
   2858   6741  th199096 	if (cs->cr) {
   2859   6741  th199096 		crfree(cs->cr);
   2860   6741  th199096 		cs->cr = NULL;
   2861   6741  th199096 	}
   2862   6741  th199096 
   2863   6741  th199096 
   2864   6741  th199096 	/*
   2865   8424      lisa 	 * Check exportinfo only if it's a FH41_TYPE_NFS filehandle.
   2866   8023       Sam 	 * If the filehandle is otherwise incorrect,
   2867   8023       Sam 	 * nnode_from_fh_v41() will return an error.
   2868   8023       Sam 	 */
   2869   8424      lisa 	fhp = (nfs41_fh_fmt_t *)args->object.nfs_fh4_val;
   2870   8424      lisa 	if (fhp->type == FH41_TYPE_NFS) {
   2871   8023       Sam