Print this page
    
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/uts/common/fs/nfs/nfs4_vnops.c
          +++ new/usr/src/uts/common/fs/nfs/nfs4_vnops.c
   1    1  /*
   2    2   * CDDL HEADER START
   3    3   *
   4    4   * The contents of this file are subject to the terms of the
   5    5   * Common Development and Distribution License (the "License").
   6    6   * You may not use this file except in compliance with the License.
   7    7   *
   8    8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9    9   * or http://www.opensolaris.org/os/licensing.
  10   10   * See the License for the specific language governing permissions
  11   11   * and limitations under the License.
  12   12   *
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  
  22   22  /*
  23   23   * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
  24   24   */
  25   25  
  26   26  /*
  27   27   * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  28   28   * Use is subject to license terms.
  29   29   */
  30   30  
  31   31  /*
  32   32   *      Copyright 1983,1984,1985,1986,1987,1988,1989 AT&T.
  33   33   *      All Rights Reserved
  34   34   */
  35   35  
  36   36  /*
  37   37   * Copyright (c) 2014, Joyent, Inc. All rights reserved.
  38   38   */
  39   39  
  40   40  #include <sys/param.h>
  41   41  #include <sys/types.h>
  42   42  #include <sys/systm.h>
  43   43  #include <sys/cred.h>
  44   44  #include <sys/time.h>
  45   45  #include <sys/vnode.h>
  46   46  #include <sys/vfs.h>
  47   47  #include <sys/vfs_opreg.h>
  48   48  #include <sys/file.h>
  49   49  #include <sys/filio.h>
  50   50  #include <sys/uio.h>
  51   51  #include <sys/buf.h>
  52   52  #include <sys/mman.h>
  53   53  #include <sys/pathname.h>
  54   54  #include <sys/dirent.h>
  55   55  #include <sys/debug.h>
  56   56  #include <sys/vmsystm.h>
  57   57  #include <sys/fcntl.h>
  58   58  #include <sys/flock.h>
  59   59  #include <sys/swap.h>
  60   60  #include <sys/errno.h>
  61   61  #include <sys/strsubr.h>
  62   62  #include <sys/sysmacros.h>
  63   63  #include <sys/kmem.h>
  64   64  #include <sys/cmn_err.h>
  65   65  #include <sys/pathconf.h>
  66   66  #include <sys/utsname.h>
  67   67  #include <sys/dnlc.h>
  68   68  #include <sys/acl.h>
  69   69  #include <sys/systeminfo.h>
  70   70  #include <sys/policy.h>
  71   71  #include <sys/sdt.h>
  72   72  #include <sys/list.h>
  73   73  #include <sys/stat.h>
  74   74  #include <sys/zone.h>
  75   75  
  76   76  #include <rpc/types.h>
  77   77  #include <rpc/auth.h>
  78   78  #include <rpc/clnt.h>
  79   79  
  80   80  #include <nfs/nfs.h>
  81   81  #include <nfs/nfs_clnt.h>
  82   82  #include <nfs/nfs_acl.h>
  83   83  #include <nfs/lm.h>
  84   84  #include <nfs/nfs4.h>
  85   85  #include <nfs/nfs4_kprot.h>
  86   86  #include <nfs/rnode4.h>
  87   87  #include <nfs/nfs4_clnt.h>
  88   88  
  89   89  #include <vm/hat.h>
  90   90  #include <vm/as.h>
  91   91  #include <vm/page.h>
  92   92  #include <vm/pvn.h>
  93   93  #include <vm/seg.h>
  94   94  #include <vm/seg_map.h>
  95   95  #include <vm/seg_kpm.h>
  96   96  #include <vm/seg_vn.h>
  97   97  
  98   98  #include <fs/fs_subr.h>
  99   99  
 100  100  #include <sys/ddi.h>
 101  101  #include <sys/int_fmtio.h>
 102  102  #include <sys/fs/autofs.h>
 103  103  
 104  104  typedef struct {
 105  105          nfs4_ga_res_t   *di_garp;
 106  106          cred_t          *di_cred;
 107  107          hrtime_t        di_time_call;
 108  108  } dirattr_info_t;
 109  109  
 110  110  typedef enum nfs4_acl_op {
 111  111          NFS4_ACL_GET,
 112  112          NFS4_ACL_SET
 113  113  } nfs4_acl_op_t;
 114  114  
 115  115  static struct lm_sysid *nfs4_find_sysid(mntinfo4_t *mi);
 116  116  
 117  117  static void     nfs4_update_dircaches(change_info4 *, vnode_t *, vnode_t *,
 118  118                          char *, dirattr_info_t *);
 119  119  
 120  120  static void     nfs4close_otw(rnode4_t *, cred_t *, nfs4_open_owner_t *,
 121  121                      nfs4_open_stream_t *, int *, int *, nfs4_close_type_t,
 122  122                      nfs4_error_t *, int *);
 123  123  static int      nfs4_rdwrlbn(vnode_t *, page_t *, u_offset_t, size_t, int,
 124  124                          cred_t *);
 125  125  static int      nfs4write(vnode_t *, caddr_t, u_offset_t, int, cred_t *,
 126  126                          stable_how4 *);
 127  127  static int      nfs4read(vnode_t *, caddr_t, offset_t, int, size_t *,
 128  128                          cred_t *, bool_t, struct uio *);
 129  129  static int      nfs4setattr(vnode_t *, struct vattr *, int, cred_t *,
 130  130                          vsecattr_t *);
 131  131  static int      nfs4openattr(vnode_t *, vnode_t **, int, cred_t *);
 132  132  static int      nfs4lookup(vnode_t *, char *, vnode_t **, cred_t *, int);
 133  133  static int      nfs4lookup_xattr(vnode_t *, char *, vnode_t **, int, cred_t *);
 134  134  static int      nfs4lookupvalidate_otw(vnode_t *, char *, vnode_t **, cred_t *);
 135  135  static int      nfs4lookupnew_otw(vnode_t *, char *, vnode_t **, cred_t *);
 136  136  static int      nfs4mknod(vnode_t *, char *, struct vattr *, enum vcexcl,
 137  137                          int, vnode_t **, cred_t *);
 138  138  static int      nfs4open_otw(vnode_t *, char *, struct vattr *, vnode_t **,
 139  139                          cred_t *, int, int, enum createmode4, int);
 140  140  static int      nfs4rename(vnode_t *, char *, vnode_t *, char *, cred_t *,
 141  141                          caller_context_t *);
 142  142  static int      nfs4rename_persistent_fh(vnode_t *, char *, vnode_t *,
 143  143                          vnode_t *, char *, cred_t *, nfsstat4 *);
 144  144  static int      nfs4rename_volatile_fh(vnode_t *, char *, vnode_t *,
 145  145                          vnode_t *, char *, cred_t *, nfsstat4 *);
 146  146  static int      do_nfs4readdir(vnode_t *, rddir4_cache *, cred_t *);
 147  147  static void     nfs4readdir(vnode_t *, rddir4_cache *, cred_t *);
 148  148  static int      nfs4_bio(struct buf *, stable_how4 *, cred_t *, bool_t);
 149  149  static int      nfs4_getapage(vnode_t *, u_offset_t, size_t, uint_t *,
 150  150                          page_t *[], size_t, struct seg *, caddr_t,
 151  151                          enum seg_rw, cred_t *);
 152  152  static void     nfs4_readahead(vnode_t *, u_offset_t, caddr_t, struct seg *,
 153  153                          cred_t *);
 154  154  static int      nfs4_sync_putapage(vnode_t *, page_t *, u_offset_t, size_t,
 155  155                          int, cred_t *);
 156  156  static int      nfs4_sync_pageio(vnode_t *, page_t *, u_offset_t, size_t,
 157  157                          int, cred_t *);
 158  158  static int      nfs4_commit(vnode_t *, offset4, count4, cred_t *);
 159  159  static void     nfs4_set_mod(vnode_t *);
 160  160  static void     nfs4_get_commit(vnode_t *);
 161  161  static void     nfs4_get_commit_range(vnode_t *, u_offset_t, size_t);
 162  162  static int      nfs4_putpage_commit(vnode_t *, offset_t, size_t, cred_t *);
 163  163  static int      nfs4_commit_vp(vnode_t *, u_offset_t, size_t, cred_t *, int);
 164  164  static int      nfs4_sync_commit(vnode_t *, page_t *, offset3, count3,
 165  165                          cred_t *);
 166  166  static void     do_nfs4_async_commit(vnode_t *, page_t *, offset3, count3,
 167  167                          cred_t *);
 168  168  static int      nfs4_update_attrcache(nfsstat4, nfs4_ga_res_t *,
 169  169                          hrtime_t, vnode_t *, cred_t *);
 170  170  static int      nfs4_open_non_reg_file(vnode_t **, int, cred_t *);
 171  171  static int      nfs4_safelock(vnode_t *, const struct flock64 *, cred_t *);
 172  172  static void     nfs4_register_lock_locally(vnode_t *, struct flock64 *, int,
 173  173                          u_offset_t);
 174  174  static int      nfs4_lockrelease(vnode_t *, int, offset_t, cred_t *);
 175  175  static int      nfs4_block_and_wait(clock_t *, rnode4_t *);
 176  176  static cred_t  *state_to_cred(nfs4_open_stream_t *);
 177  177  static void     denied_to_flk(LOCK4denied *, flock64_t *, LOCKT4args *);
 178  178  static pid_t    lo_to_pid(lock_owner4 *);
 179  179  static void     nfs4_reinstitute_local_lock_state(vnode_t *, flock64_t *,
 180  180                          cred_t *, nfs4_lock_owner_t *);
 181  181  static void     push_reinstate(vnode_t *, int, flock64_t *, cred_t *,
 182  182                          nfs4_lock_owner_t *);
 183  183  static int      open_and_get_osp(vnode_t *, cred_t *, nfs4_open_stream_t **);
 184  184  static void     nfs4_delmap_callback(struct as *, void *, uint_t);
 185  185  static void     nfs4_free_delmapcall(nfs4_delmapcall_t *);
 186  186  static nfs4_delmapcall_t        *nfs4_init_delmapcall();
 187  187  static int      nfs4_find_and_delete_delmapcall(rnode4_t *, int *);
 188  188  static int      nfs4_is_acl_mask_valid(uint_t, nfs4_acl_op_t);
 189  189  static int      nfs4_create_getsecattr_return(vsecattr_t *, vsecattr_t *,
 190  190                          uid_t, gid_t, int);
 191  191  
 192  192  /*
 193  193   * Routines that implement the setting of v4 args for the misc. ops
 194  194   */
 195  195  static void     nfs4args_lock_free(nfs_argop4 *);
 196  196  static void     nfs4args_lockt_free(nfs_argop4 *);
 197  197  static void     nfs4args_setattr(nfs_argop4 *, vattr_t *, vsecattr_t *,
 198  198                          int, rnode4_t *, cred_t *, bitmap4, int *,
 199  199                          nfs4_stateid_types_t *);
 200  200  static void     nfs4args_setattr_free(nfs_argop4 *);
 201  201  static int      nfs4args_verify(nfs_argop4 *, vattr_t *, enum nfs_opnum4,
 202  202                          bitmap4);
 203  203  static void     nfs4args_verify_free(nfs_argop4 *);
 204  204  static void     nfs4args_write(nfs_argop4 *, stable_how4, rnode4_t *, cred_t *,
 205  205                          WRITE4args **, nfs4_stateid_types_t *);
 206  206  
 207  207  /*
 208  208   * These are the vnode ops functions that implement the vnode interface to
 209  209   * the networked file system.  See more comments below at nfs4_vnodeops.
 210  210   */
 211  211  static int      nfs4_open(vnode_t **, int, cred_t *, caller_context_t *);
 212  212  static int      nfs4_close(vnode_t *, int, int, offset_t, cred_t *,
 213  213                          caller_context_t *);
 214  214  static int      nfs4_read(vnode_t *, struct uio *, int, cred_t *,
 215  215                          caller_context_t *);
 216  216  static int      nfs4_write(vnode_t *, struct uio *, int, cred_t *,
 217  217                          caller_context_t *);
 218  218  static int      nfs4_ioctl(vnode_t *, int, intptr_t, int, cred_t *, int *,
 219  219                          caller_context_t *);
 220  220  static int      nfs4_setattr(vnode_t *, struct vattr *, int, cred_t *,
 221  221                          caller_context_t *);
 222  222  static int      nfs4_access(vnode_t *, int, int, cred_t *, caller_context_t *);
 223  223  static int      nfs4_readlink(vnode_t *, struct uio *, cred_t *,
 224  224                          caller_context_t *);
 225  225  static int      nfs4_fsync(vnode_t *, int, cred_t *, caller_context_t *);
 226  226  static int      nfs4_create(vnode_t *, char *, struct vattr *, enum vcexcl,
 227  227                          int, vnode_t **, cred_t *, int, caller_context_t *,
 228  228                          vsecattr_t *);
 229  229  static int      nfs4_remove(vnode_t *, char *, cred_t *, caller_context_t *,
 230  230                          int);
 231  231  static int      nfs4_link(vnode_t *, vnode_t *, char *, cred_t *,
 232  232                          caller_context_t *, int);
 233  233  static int      nfs4_rename(vnode_t *, char *, vnode_t *, char *, cred_t *,
 234  234                          caller_context_t *, int);
 235  235  static int      nfs4_mkdir(vnode_t *, char *, struct vattr *, vnode_t **,
 236  236                          cred_t *, caller_context_t *, int, vsecattr_t *);
 237  237  static int      nfs4_rmdir(vnode_t *, char *, vnode_t *, cred_t *,
 238  238                          caller_context_t *, int);
 239  239  static int      nfs4_symlink(vnode_t *, char *, struct vattr *, char *,
 240  240                          cred_t *, caller_context_t *, int);
 241  241  static int      nfs4_readdir(vnode_t *, struct uio *, cred_t *, int *,
 242  242                          caller_context_t *, int);
 243  243  static int      nfs4_seek(vnode_t *, offset_t, offset_t *, caller_context_t *);
 244  244  static int      nfs4_getpage(vnode_t *, offset_t, size_t, uint_t *,
 245  245                          page_t *[], size_t, struct seg *, caddr_t,
 246  246                          enum seg_rw, cred_t *, caller_context_t *);
 247  247  static int      nfs4_putpage(vnode_t *, offset_t, size_t, int, cred_t *,
 248  248                          caller_context_t *);
 249  249  static int      nfs4_map(vnode_t *, offset_t, struct as *, caddr_t *, size_t,
 250  250                          uchar_t, uchar_t, uint_t, cred_t *, caller_context_t *);
 251  251  static int      nfs4_addmap(vnode_t *, offset_t, struct as *, caddr_t, size_t,
 252  252                          uchar_t, uchar_t, uint_t, cred_t *, caller_context_t *);
 253  253  static int      nfs4_cmp(vnode_t *, vnode_t *, caller_context_t *);
 254  254  static int      nfs4_frlock(vnode_t *, int, struct flock64 *, int, offset_t,
 255  255                          struct flk_callback *, cred_t *, caller_context_t *);
 256  256  static int      nfs4_space(vnode_t *, int, struct flock64 *, int, offset_t,
 257  257                          cred_t *, caller_context_t *);
 258  258  static int      nfs4_delmap(vnode_t *, offset_t, struct as *, caddr_t, size_t,
 259  259                          uint_t, uint_t, uint_t, cred_t *, caller_context_t *);
 260  260  static int      nfs4_pageio(vnode_t *, page_t *, u_offset_t, size_t, int,
 261  261                          cred_t *, caller_context_t *);
 262  262  static void     nfs4_dispose(vnode_t *, page_t *, int, int, cred_t *,
 263  263                          caller_context_t *);
 264  264  static int      nfs4_setsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
 265  265                          caller_context_t *);
 266  266  /*
 267  267   * These vnode ops are required to be called from outside this source file,
 268  268   * e.g. by ephemeral mount stub vnode ops, and so may not be declared
 269  269   * as static.
 270  270   */
 271  271  int     nfs4_getattr(vnode_t *, struct vattr *, int, cred_t *,
 272  272              caller_context_t *);
 273  273  void    nfs4_inactive(vnode_t *, cred_t *, caller_context_t *);
 274  274  int     nfs4_lookup(vnode_t *, char *, vnode_t **,
 275  275              struct pathname *, int, vnode_t *, cred_t *,
 276  276              caller_context_t *, int *, pathname_t *);
 277  277  int     nfs4_fid(vnode_t *, fid_t *, caller_context_t *);
 278  278  int     nfs4_rwlock(vnode_t *, int, caller_context_t *);
 279  279  void    nfs4_rwunlock(vnode_t *, int, caller_context_t *);
 280  280  int     nfs4_realvp(vnode_t *, vnode_t **, caller_context_t *);
 281  281  int     nfs4_pathconf(vnode_t *, int, ulong_t *, cred_t *,
 282  282              caller_context_t *);
 283  283  int     nfs4_getsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
 284  284              caller_context_t *);
 285  285  int     nfs4_shrlock(vnode_t *, int, struct shrlock *, int, cred_t *,
 286  286              caller_context_t *);
 287  287  
 288  288  /*
 289  289   * Used for nfs4_commit_vp() to indicate if we should
 290  290   * wait on pending writes.
 291  291   */
 292  292  #define NFS4_WRITE_NOWAIT       0
 293  293  #define NFS4_WRITE_WAIT         1
 294  294  
 295  295  #define NFS4_BASE_WAIT_TIME 1   /* 1 second */
 296  296  
 297  297  /*
 298  298   * Error flags used to pass information about certain special errors
 299  299   * which need to be handled specially.
 300  300   */
 301  301  #define NFS_EOF                 -98
 302  302  #define NFS_VERF_MISMATCH       -97
 303  303  
 304  304  /*
 305  305   * Flags used to differentiate between which operation drove the
 306  306   * potential CLOSE OTW. (see nfs4_close_otw_if_necessary)
 307  307   */
 308  308  #define NFS4_CLOSE_OP           0x1
 309  309  #define NFS4_DELMAP_OP          0x2
 310  310  #define NFS4_INACTIVE_OP        0x3
 311  311  
 312  312  #define ISVDEV(t) ((t == VBLK) || (t == VCHR) || (t == VFIFO))
 313  313  
 314  314  /* ALIGN64 aligns the given buffer and adjust buffer size to 64 bit */
 315  315  #define ALIGN64(x, ptr, sz)                                             \
 316  316          x = ((uintptr_t)(ptr)) & (sizeof (uint64_t) - 1);               \
 317  317          if (x) {                                                        \
 318  318                  x = sizeof (uint64_t) - (x);                            \
 319  319                  sz -= (x);                                              \
 320  320                  ptr += (x);                                             \
 321  321          }
 322  322  
 323  323  #ifdef DEBUG
 324  324  int nfs4_client_attr_debug = 0;
 325  325  int nfs4_client_state_debug = 0;
 326  326  int nfs4_client_shadow_debug = 0;
 327  327  int nfs4_client_lock_debug = 0;
 328  328  int nfs4_seqid_sync = 0;
 329  329  int nfs4_client_map_debug = 0;
 330  330  static int nfs4_pageio_debug = 0;
 331  331  int nfs4_client_inactive_debug = 0;
 332  332  int nfs4_client_recov_debug = 0;
 333  333  int nfs4_client_failover_debug = 0;
 334  334  int nfs4_client_call_debug = 0;
 335  335  int nfs4_client_lookup_debug = 0;
 336  336  int nfs4_client_zone_debug = 0;
 337  337  int nfs4_lost_rqst_debug = 0;
 338  338  int nfs4_rdattrerr_debug = 0;
 339  339  int nfs4_open_stream_debug = 0;
 340  340  
 341  341  int nfs4read_error_inject;
 342  342  
 343  343  static int nfs4_create_misses = 0;
 344  344  
 345  345  static int nfs4_readdir_cache_shorts = 0;
 346  346  static int nfs4_readdir_readahead = 0;
 347  347  
 348  348  static int nfs4_bio_do_stop = 0;
 349  349  
 350  350  static int nfs4_lostpage = 0;   /* number of times we lost original page */
 351  351  
 352  352  int nfs4_mmap_debug = 0;
 353  353  
 354  354  static int nfs4_pathconf_cache_hits = 0;
 355  355  static int nfs4_pathconf_cache_misses = 0;
 356  356  
 357  357  int nfs4close_all_cnt;
 358  358  int nfs4close_one_debug = 0;
 359  359  int nfs4close_notw_debug = 0;
 360  360  
 361  361  int denied_to_flk_debug = 0;
 362  362  void *lockt_denied_debug;
 363  363  
 364  364  #endif
 365  365  
 366  366  /*
 367  367   * How long to wait before trying again if OPEN_CONFIRM gets ETIMEDOUT
 368  368   * or NFS4ERR_RESOURCE.
 369  369   */
 370  370  static int confirm_retry_sec = 30;
 371  371  
 372  372  static int nfs4_lookup_neg_cache = 1;
 373  373  
 374  374  /*
 375  375   * number of pages to read ahead
 376  376   * optimized for 100 base-T.
 377  377   */
 378  378  static int nfs4_nra = 4;
 379  379  
 380  380  static int nfs4_do_symlink_cache = 1;
 381  381  
 382  382  static int nfs4_pathconf_disable_cache = 0;
 383  383  
 384  384  /*
 385  385   * These are the vnode ops routines which implement the vnode interface to
 386  386   * the networked file system.  These routines just take their parameters,
 387  387   * make them look networkish by putting the right info into interface structs,
 388  388   * and then calling the appropriate remote routine(s) to do the work.
 389  389   *
 390  390   * Note on directory name lookup cacheing:  If we detect a stale fhandle,
 391  391   * we purge the directory cache relative to that vnode.  This way, the
 392  392   * user won't get burned by the cache repeatedly.  See <nfs/rnode4.h> for
 393  393   * more details on rnode locking.
 394  394   */
 395  395  
 396  396  struct vnodeops *nfs4_vnodeops;
 397  397  
 398  398  const fs_operation_def_t nfs4_vnodeops_template[] = {
 399  399          VOPNAME_OPEN,           { .vop_open = nfs4_open },
 400  400          VOPNAME_CLOSE,          { .vop_close = nfs4_close },
 401  401          VOPNAME_READ,           { .vop_read = nfs4_read },
 402  402          VOPNAME_WRITE,          { .vop_write = nfs4_write },
 403  403          VOPNAME_IOCTL,          { .vop_ioctl = nfs4_ioctl },
 404  404          VOPNAME_GETATTR,        { .vop_getattr = nfs4_getattr },
 405  405          VOPNAME_SETATTR,        { .vop_setattr = nfs4_setattr },
 406  406          VOPNAME_ACCESS,         { .vop_access = nfs4_access },
 407  407          VOPNAME_LOOKUP,         { .vop_lookup = nfs4_lookup },
 408  408          VOPNAME_CREATE,         { .vop_create = nfs4_create },
 409  409          VOPNAME_REMOVE,         { .vop_remove = nfs4_remove },
 410  410          VOPNAME_LINK,           { .vop_link = nfs4_link },
 411  411          VOPNAME_RENAME,         { .vop_rename = nfs4_rename },
 412  412          VOPNAME_MKDIR,          { .vop_mkdir = nfs4_mkdir },
 413  413          VOPNAME_RMDIR,          { .vop_rmdir = nfs4_rmdir },
 414  414          VOPNAME_READDIR,        { .vop_readdir = nfs4_readdir },
 415  415          VOPNAME_SYMLINK,        { .vop_symlink = nfs4_symlink },
 416  416          VOPNAME_READLINK,       { .vop_readlink = nfs4_readlink },
 417  417          VOPNAME_FSYNC,          { .vop_fsync = nfs4_fsync },
 418  418          VOPNAME_INACTIVE,       { .vop_inactive = nfs4_inactive },
 419  419          VOPNAME_FID,            { .vop_fid = nfs4_fid },
 420  420          VOPNAME_RWLOCK,         { .vop_rwlock = nfs4_rwlock },
 421  421          VOPNAME_RWUNLOCK,       { .vop_rwunlock = nfs4_rwunlock },
 422  422          VOPNAME_SEEK,           { .vop_seek = nfs4_seek },
 423  423          VOPNAME_FRLOCK,         { .vop_frlock = nfs4_frlock },
 424  424          VOPNAME_SPACE,          { .vop_space = nfs4_space },
 425  425          VOPNAME_REALVP,         { .vop_realvp = nfs4_realvp },
 426  426          VOPNAME_GETPAGE,        { .vop_getpage = nfs4_getpage },
 427  427          VOPNAME_PUTPAGE,        { .vop_putpage = nfs4_putpage },
 428  428          VOPNAME_MAP,            { .vop_map = nfs4_map },
 429  429          VOPNAME_ADDMAP,         { .vop_addmap = nfs4_addmap },
 430  430          VOPNAME_DELMAP,         { .vop_delmap = nfs4_delmap },
 431  431          /* no separate nfs4_dump */
 432  432          VOPNAME_DUMP,           { .vop_dump = nfs_dump },
 433  433          VOPNAME_PATHCONF,       { .vop_pathconf = nfs4_pathconf },
 434  434          VOPNAME_PAGEIO,         { .vop_pageio = nfs4_pageio },
 435  435          VOPNAME_DISPOSE,        { .vop_dispose = nfs4_dispose },
 436  436          VOPNAME_SETSECATTR,     { .vop_setsecattr = nfs4_setsecattr },
 437  437          VOPNAME_GETSECATTR,     { .vop_getsecattr = nfs4_getsecattr },
 438  438          VOPNAME_SHRLOCK,        { .vop_shrlock = nfs4_shrlock },
 439  439          VOPNAME_VNEVENT,        { .vop_vnevent = fs_vnevent_support },
 440  440          NULL,                   NULL
 441  441  };
 442  442  
 443  443  /*
 444  444   * The following are subroutines and definitions to set args or get res
 445  445   * for the different nfsv4 ops
 446  446   */
 447  447  
 448  448  void
 449  449  nfs4args_lookup_free(nfs_argop4 *argop, int arglen)
 450  450  {
 451  451          int             i;
 452  452  
 453  453          for (i = 0; i < arglen; i++) {
 454  454                  if (argop[i].argop == OP_LOOKUP) {
 455  455                          kmem_free(
 456  456                              argop[i].nfs_argop4_u.oplookup.
 457  457                              objname.utf8string_val,
 458  458                              argop[i].nfs_argop4_u.oplookup.
 459  459                              objname.utf8string_len);
 460  460                  }
 461  461          }
 462  462  }
 463  463  
 464  464  static void
 465  465  nfs4args_lock_free(nfs_argop4 *argop)
 466  466  {
 467  467          locker4 *locker = &argop->nfs_argop4_u.oplock.locker;
 468  468  
 469  469          if (locker->new_lock_owner == TRUE) {
 470  470                  open_to_lock_owner4 *open_owner;
 471  471  
 472  472                  open_owner = &locker->locker4_u.open_owner;
 473  473                  if (open_owner->lock_owner.owner_val != NULL) {
 474  474                          kmem_free(open_owner->lock_owner.owner_val,
 475  475                              open_owner->lock_owner.owner_len);
 476  476                  }
 477  477          }
 478  478  }
 479  479  
 480  480  static void
 481  481  nfs4args_lockt_free(nfs_argop4 *argop)
 482  482  {
 483  483          lock_owner4 *lowner = &argop->nfs_argop4_u.oplockt.owner;
 484  484  
 485  485          if (lowner->owner_val != NULL) {
 486  486                  kmem_free(lowner->owner_val, lowner->owner_len);
 487  487          }
 488  488  }
 489  489  
 490  490  static void
 491  491  nfs4args_setattr(nfs_argop4 *argop, vattr_t *vap, vsecattr_t *vsap, int flags,
 492  492      rnode4_t *rp, cred_t *cr, bitmap4 supp, int *error,
 493  493      nfs4_stateid_types_t *sid_types)
 494  494  {
 495  495          fattr4          *attr = &argop->nfs_argop4_u.opsetattr.obj_attributes;
 496  496          mntinfo4_t      *mi;
 497  497  
 498  498          argop->argop = OP_SETATTR;
 499  499          /*
 500  500           * The stateid is set to 0 if client is not modifying the size
 501  501           * and otherwise to whatever nfs4_get_stateid() returns.
 502  502           *
 503  503           * XXX Note: nfs4_get_stateid() returns 0 if no lockowner and/or no
 504  504           * state struct could be found for the process/file pair.  We may
 505  505           * want to change this in the future (by OPENing the file).  See
 506  506           * bug # 4474852.
 507  507           */
 508  508          if (vap->va_mask & AT_SIZE) {
 509  509  
 510  510                  ASSERT(rp != NULL);
 511  511                  mi = VTOMI4(RTOV4(rp));
 512  512  
 513  513                  argop->nfs_argop4_u.opsetattr.stateid =
 514  514                      nfs4_get_stateid(cr, rp, curproc->p_pidp->pid_id, mi,
 515  515                      OP_SETATTR, sid_types, FALSE);
 516  516          } else {
 517  517                  bzero(&argop->nfs_argop4_u.opsetattr.stateid,
 518  518                      sizeof (stateid4));
 519  519          }
 520  520  
 521  521          *error = vattr_to_fattr4(vap, vsap, attr, flags, OP_SETATTR, supp);
 522  522          if (*error)
 523  523                  bzero(attr, sizeof (*attr));
 524  524  }
 525  525  
 526  526  static void
 527  527  nfs4args_setattr_free(nfs_argop4 *argop)
 528  528  {
 529  529          nfs4_fattr4_free(&argop->nfs_argop4_u.opsetattr.obj_attributes);
 530  530  }
 531  531  
 532  532  static int
 533  533  nfs4args_verify(nfs_argop4 *argop, vattr_t *vap, enum nfs_opnum4 op,
 534  534      bitmap4 supp)
 535  535  {
 536  536          fattr4 *attr;
 537  537          int error = 0;
 538  538  
 539  539          argop->argop = op;
 540  540          switch (op) {
 541  541          case OP_VERIFY:
 542  542                  attr = &argop->nfs_argop4_u.opverify.obj_attributes;
 543  543                  break;
 544  544          case OP_NVERIFY:
 545  545                  attr = &argop->nfs_argop4_u.opnverify.obj_attributes;
 546  546                  break;
 547  547          default:
 548  548                  return (EINVAL);
 549  549          }
 550  550          if (!error)
 551  551                  error = vattr_to_fattr4(vap, NULL, attr, 0, op, supp);
 552  552          if (error)
 553  553                  bzero(attr, sizeof (*attr));
 554  554          return (error);
 555  555  }
 556  556  
 557  557  static void
 558  558  nfs4args_verify_free(nfs_argop4 *argop)
 559  559  {
 560  560          switch (argop->argop) {
 561  561          case OP_VERIFY:
 562  562                  nfs4_fattr4_free(&argop->nfs_argop4_u.opverify.obj_attributes);
 563  563                  break;
 564  564          case OP_NVERIFY:
 565  565                  nfs4_fattr4_free(&argop->nfs_argop4_u.opnverify.obj_attributes);
 566  566                  break;
 567  567          default:
 568  568                  break;
 569  569          }
 570  570  }
 571  571  
 572  572  static void
 573  573  nfs4args_write(nfs_argop4 *argop, stable_how4 stable, rnode4_t *rp, cred_t *cr,
 574  574      WRITE4args **wargs_pp, nfs4_stateid_types_t *sid_tp)
 575  575  {
 576  576          WRITE4args *wargs = &argop->nfs_argop4_u.opwrite;
 577  577          mntinfo4_t *mi = VTOMI4(RTOV4(rp));
 578  578  
 579  579          argop->argop = OP_WRITE;
 580  580          wargs->stable = stable;
 581  581          wargs->stateid = nfs4_get_w_stateid(cr, rp, curproc->p_pidp->pid_id,
 582  582              mi, OP_WRITE, sid_tp);
 583  583          wargs->mblk = NULL;
 584  584          *wargs_pp = wargs;
 585  585  }
 586  586  
 587  587  void
 588  588  nfs4args_copen_free(OPEN4cargs *open_args)
 589  589  {
 590  590          if (open_args->owner.owner_val) {
 591  591                  kmem_free(open_args->owner.owner_val,
 592  592                      open_args->owner.owner_len);
 593  593          }
 594  594          if ((open_args->opentype == OPEN4_CREATE) &&
 595  595              (open_args->mode != EXCLUSIVE4)) {
 596  596                  nfs4_fattr4_free(&open_args->createhow4_u.createattrs);
 597  597          }
 598  598  }
 599  599  
 600  600  /*
 601  601   * XXX:  This is referenced in modstubs.s
 602  602   */
 603  603  struct vnodeops *
 604  604  nfs4_getvnodeops(void)
 605  605  {
 606  606          return (nfs4_vnodeops);
 607  607  }
 608  608  
 609  609  /*
 610  610   * The OPEN operation opens a regular file.
 611  611   */
 612  612  /*ARGSUSED3*/
 613  613  static int
 614  614  nfs4_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
 615  615  {
 616  616          vnode_t *dvp = NULL;
 617  617          rnode4_t *rp, *drp;
 618  618          int error;
 619  619          int just_been_created;
 620  620          char fn[MAXNAMELEN];
 621  621  
 622  622          NFS4_DEBUG(nfs4_client_state_debug, (CE_NOTE, "nfs4_open: "));
 623  623          if (nfs_zone() != VTOMI4(*vpp)->mi_zone)
 624  624                  return (EIO);
 625  625          rp = VTOR4(*vpp);
 626  626  
 627  627          /*
 628  628           * Check to see if opening something besides a regular file;
 629  629           * if so skip the OTW call
 630  630           */
 631  631          if ((*vpp)->v_type != VREG) {
 632  632                  error = nfs4_open_non_reg_file(vpp, flag, cr);
 633  633                  return (error);
 634  634          }
 635  635  
 636  636          /*
 637  637           * XXX - would like a check right here to know if the file is
 638  638           * executable or not, so as to skip OTW
 639  639           */
 640  640  
 641  641          if ((error = vtodv(*vpp, &dvp, cr, TRUE)) != 0)
 642  642                  return (error);
 643  643  
 644  644          drp = VTOR4(dvp);
 645  645          if (nfs_rw_enter_sig(&drp->r_rwlock, RW_READER, INTR4(dvp)))
 646  646                  return (EINTR);
 647  647  
 648  648          if ((error = vtoname(*vpp, fn, MAXNAMELEN)) != 0) {
 649  649                  nfs_rw_exit(&drp->r_rwlock);
 650  650                  return (error);
 651  651          }
 652  652  
 653  653          /*
 654  654           * See if this file has just been CREATEd.
 655  655           * If so, clear the flag and update the dnlc, which was previously
 656  656           * skipped in nfs4_create.
 657  657           * XXX need better serilization on this.
 658  658           * XXX move this into the nf4open_otw call, after we have
 659  659           * XXX acquired the open owner seqid sync.
 660  660           */
 661  661          mutex_enter(&rp->r_statev4_lock);
 662  662          if (rp->created_v4) {
 663  663                  rp->created_v4 = 0;
 664  664                  mutex_exit(&rp->r_statev4_lock);
 665  665  
 666  666                  dnlc_update(dvp, fn, *vpp);
 667  667                  /* This is needed so we don't bump the open ref count */
 668  668                  just_been_created = 1;
 669  669          } else {
 670  670                  mutex_exit(&rp->r_statev4_lock);
 671  671                  just_been_created = 0;
 672  672          }
 673  673  
 674  674          /*
 675  675           * If caller specified O_TRUNC/FTRUNC, then be sure to set
 676  676           * FWRITE (to drive successful setattr(size=0) after open)
 677  677           */
 678  678          if (flag & FTRUNC)
 679  679                  flag |= FWRITE;
 680  680  
 681  681          error = nfs4open_otw(dvp, fn, NULL, vpp, cr, 0, flag, 0,
 682  682              just_been_created);
 683  683  
 684  684          if (!error && !((*vpp)->v_flag & VROOT))
 685  685                  dnlc_update(dvp, fn, *vpp);
 686  686  
 687  687          nfs_rw_exit(&drp->r_rwlock);
 688  688  
 689  689          /* release the hold from vtodv */
 690  690          VN_RELE(dvp);
 691  691  
 692  692          /* exchange the shadow for the master vnode, if needed */
 693  693  
 694  694          if (error == 0 && IS_SHADOW(*vpp, rp))
 695  695                  sv_exchange(vpp);
 696  696  
 697  697          return (error);
 698  698  }
 699  699  
 700  700  /*
 701  701   * See if there's a "lost open" request to be saved and recovered.
 702  702   */
 703  703  static void
 704  704  nfs4open_save_lost_rqst(int error, nfs4_lost_rqst_t *lost_rqstp,
 705  705      nfs4_open_owner_t *oop, cred_t *cr, vnode_t *vp,
 706  706      vnode_t *dvp, OPEN4cargs *open_args)
 707  707  {
 708  708          vfs_t *vfsp;
 709  709          char *srccfp;
 710  710  
 711  711          vfsp = (dvp ? dvp->v_vfsp : vp->v_vfsp);
 712  712  
 713  713          if (error != ETIMEDOUT && error != EINTR &&
 714  714              !NFS4_FRC_UNMT_ERR(error, vfsp)) {
 715  715                  lost_rqstp->lr_op = 0;
 716  716                  return;
 717  717          }
 718  718  
 719  719          NFS4_DEBUG(nfs4_lost_rqst_debug, (CE_NOTE,
 720  720              "nfs4open_save_lost_rqst: error %d", error));
 721  721  
 722  722          lost_rqstp->lr_op = OP_OPEN;
 723  723  
 724  724          /*
 725  725           * The vp (if it is not NULL) and dvp are held and rele'd via
 726  726           * the recovery code.  See nfs4_save_lost_rqst.
 727  727           */
 728  728          lost_rqstp->lr_vp = vp;
 729  729          lost_rqstp->lr_dvp = dvp;
 730  730          lost_rqstp->lr_oop = oop;
 731  731          lost_rqstp->lr_osp = NULL;
 732  732          lost_rqstp->lr_lop = NULL;
 733  733          lost_rqstp->lr_cr = cr;
 734  734          lost_rqstp->lr_flk = NULL;
 735  735          lost_rqstp->lr_oacc = open_args->share_access;
 736  736          lost_rqstp->lr_odeny = open_args->share_deny;
 737  737          lost_rqstp->lr_oclaim = open_args->claim;
 738  738          if (open_args->claim == CLAIM_DELEGATE_CUR) {
 739  739                  lost_rqstp->lr_ostateid =
 740  740                      open_args->open_claim4_u.delegate_cur_info.delegate_stateid;
 741  741                  srccfp = open_args->open_claim4_u.delegate_cur_info.cfile;
 742  742          } else {
 743  743                  srccfp = open_args->open_claim4_u.cfile;
 744  744          }
 745  745          lost_rqstp->lr_ofile.utf8string_len = 0;
 746  746          lost_rqstp->lr_ofile.utf8string_val = NULL;
 747  747          (void) str_to_utf8(srccfp, &lost_rqstp->lr_ofile);
 748  748          lost_rqstp->lr_putfirst = FALSE;
 749  749  }
 750  750  
 751  751  struct nfs4_excl_time {
 752  752          uint32 seconds;
 753  753          uint32 nseconds;
 754  754  };
 755  755  
 756  756  /*
 757  757   * The OPEN operation creates and/or opens a regular file
 758  758   *
 759  759   * ARGSUSED
 760  760   */
 761  761  static int
 762  762  nfs4open_otw(vnode_t *dvp, char *file_name, struct vattr *in_va,
 763  763      vnode_t **vpp, cred_t *cr, int create_flag, int open_flag,
 764  764      enum createmode4 createmode, int file_just_been_created)
 765  765  {
 766  766          rnode4_t *rp;
 767  767          rnode4_t *drp = VTOR4(dvp);
 768  768          vnode_t *vp = NULL;
 769  769          vnode_t *vpi = *vpp;
 770  770          bool_t needrecov = FALSE;
 771  771  
 772  772          int doqueue = 1;
 773  773  
 774  774          COMPOUND4args_clnt args;
 775  775          COMPOUND4res_clnt res;
 776  776          nfs_argop4 *argop;
 777  777          nfs_resop4 *resop;
 778  778          int argoplist_size;
 779  779          int idx_open, idx_fattr;
 780  780  
 781  781          GETFH4res *gf_res = NULL;
 782  782          OPEN4res *op_res = NULL;
 783  783          nfs4_ga_res_t *garp;
 784  784          fattr4 *attr = NULL;
 785  785          struct nfs4_excl_time verf;
 786  786          bool_t did_excl_setup = FALSE;
 787  787          int created_osp;
 788  788  
 789  789          OPEN4cargs *open_args;
 790  790          nfs4_open_owner_t       *oop = NULL;
 791  791          nfs4_open_stream_t      *osp = NULL;
 792  792          seqid4 seqid = 0;
 793  793          bool_t retry_open = FALSE;
 794  794          nfs4_recov_state_t recov_state;
 795  795          nfs4_lost_rqst_t lost_rqst;
 796  796          nfs4_error_t e = { 0, NFS4_OK, RPC_SUCCESS };
 797  797          hrtime_t t;
 798  798          int acc = 0;
 799  799          cred_t *cred_otw = NULL;        /* cred used to do the RPC call */
 800  800          cred_t *ncr = NULL;
 801  801  
 802  802          nfs4_sharedfh_t *otw_sfh;
 803  803          nfs4_sharedfh_t *orig_sfh;
 804  804          int fh_differs = 0;
 805  805          int numops, setgid_flag;
 806  806          int num_bseqid_retry = NFS4_NUM_RETRY_BAD_SEQID + 1;
 807  807  
 808  808          /*
 809  809           * Make sure we properly deal with setting the right gid on
 810  810           * a newly created file to reflect the parent's setgid bit
 811  811           */
 812  812          setgid_flag = 0;
 813  813          if (create_flag && in_va) {
 814  814  
 815  815                  /*
 816  816                   * If there is grpid mount flag used or
 817  817                   * the parent's directory has the setgid bit set
 818  818                   * _and_ the client was able to get a valid mapping
 819  819                   * for the parent dir's owner_group, we want to
 820  820                   * append NVERIFY(owner_group == dva.va_gid) and
 821  821                   * SETATTR to the CREATE compound.
 822  822                   */
 823  823                  mutex_enter(&drp->r_statelock);
 824  824                  if ((VTOMI4(dvp)->mi_flags & MI4_GRPID ||
 825  825                      drp->r_attr.va_mode & VSGID) &&
 826  826                      drp->r_attr.va_gid != GID_NOBODY) {
 827  827                          in_va->va_mask |= AT_GID;
 828  828                          in_va->va_gid = drp->r_attr.va_gid;
 829  829                          setgid_flag = 1;
 830  830                  }
 831  831                  mutex_exit(&drp->r_statelock);
 832  832          }
 833  833  
 834  834          /*
 835  835           * Normal/non-create compound:
 836  836           * PUTFH(dfh) + OPEN(create) + GETFH + GETATTR(new)
 837  837           *
 838  838           * Open(create) compound no setgid:
 839  839           * PUTFH(dfh) + SAVEFH + OPEN(create) + GETFH + GETATTR(new) +
 840  840           * RESTOREFH + GETATTR
 841  841           *
 842  842           * Open(create) setgid:
 843  843           * PUTFH(dfh) + OPEN(create) + GETFH + GETATTR(new) +
 844  844           * SAVEFH + PUTFH(dfh) + GETATTR(dvp) + RESTOREFH +
 845  845           * NVERIFY(grp) + SETATTR
 846  846           */
 847  847          if (setgid_flag) {
 848  848                  numops = 10;
 849  849                  idx_open = 1;
 850  850                  idx_fattr = 3;
 851  851          } else if (create_flag) {
 852  852                  numops = 7;
 853  853                  idx_open = 2;
 854  854                  idx_fattr = 4;
 855  855          } else {
 856  856                  numops = 4;
 857  857                  idx_open = 1;
 858  858                  idx_fattr = 3;
 859  859          }
 860  860  
 861  861          args.array_len = numops;
 862  862          argoplist_size = numops * sizeof (nfs_argop4);
 863  863          argop = kmem_alloc(argoplist_size, KM_SLEEP);
 864  864  
 865  865          NFS4_DEBUG(nfs4_client_state_debug, (CE_NOTE, "nfs4open_otw: "
 866  866              "open %s open flag 0x%x cred %p", file_name, open_flag,
 867  867              (void *)cr));
 868  868  
 869  869          ASSERT(nfs_zone() == VTOMI4(dvp)->mi_zone);
 870  870          if (create_flag) {
 871  871                  /*
 872  872                   * We are to create a file.  Initialize the passed in vnode
 873  873                   * pointer.
 874  874                   */
 875  875                  vpi = NULL;
 876  876          } else {
 877  877                  /*
 878  878                   * Check to see if the client owns a read delegation and is
 879  879                   * trying to open for write.  If so, then return the delegation
 880  880                   * to avoid the server doing a cb_recall and returning DELAY.
 881  881                   * NB - we don't use the statev4_lock here because we'd have
 882  882                   * to drop the lock anyway and the result would be stale.
 883  883                   */
 884  884                  if ((open_flag & FWRITE) &&
 885  885                      VTOR4(vpi)->r_deleg_type == OPEN_DELEGATE_READ)
 886  886                          (void) nfs4delegreturn(VTOR4(vpi), NFS4_DR_REOPEN);
 887  887  
 888  888                  /*
 889  889                   * If the file has a delegation, then do an access check up
 890  890                   * front.  This avoids having to an access check later after
 891  891                   * we've already done start_op, which could deadlock.
 892  892                   */
 893  893                  if (VTOR4(vpi)->r_deleg_type != OPEN_DELEGATE_NONE) {
 894  894                          if (open_flag & FREAD &&
 895  895                              nfs4_access(vpi, VREAD, 0, cr, NULL) == 0)
 896  896                                  acc |= VREAD;
 897  897                          if (open_flag & FWRITE &&
 898  898                              nfs4_access(vpi, VWRITE, 0, cr, NULL) == 0)
 899  899                                  acc |= VWRITE;
 900  900                  }
 901  901          }
 902  902  
 903  903          drp = VTOR4(dvp);
 904  904  
 905  905          recov_state.rs_flags = 0;
 906  906          recov_state.rs_num_retry_despite_err = 0;
 907  907          cred_otw = cr;
 908  908  
 909  909  recov_retry:
 910  910          fh_differs = 0;
 911  911          nfs4_error_zinit(&e);
 912  912  
 913  913          e.error = nfs4_start_op(VTOMI4(dvp), dvp, vpi, &recov_state);
 914  914          if (e.error) {
 915  915                  if (ncr != NULL)
 916  916                          crfree(ncr);
 917  917                  kmem_free(argop, argoplist_size);
 918  918                  return (e.error);
 919  919          }
 920  920  
 921  921          args.ctag = TAG_OPEN;
 922  922          args.array_len = numops;
 923  923          args.array = argop;
 924  924  
 925  925          /* putfh directory fh */
 926  926          argop[0].argop = OP_CPUTFH;
 927  927          argop[0].nfs_argop4_u.opcputfh.sfh = drp->r_fh;
 928  928  
 929  929          /* OPEN: either op 1 or op 2 depending upon create/setgid flags */
 930  930          argop[idx_open].argop = OP_COPEN;
 931  931          open_args = &argop[idx_open].nfs_argop4_u.opcopen;
 932  932          open_args->claim = CLAIM_NULL;
 933  933  
 934  934          /* name of file */
 935  935          open_args->open_claim4_u.cfile = file_name;
 936  936          open_args->owner.owner_len = 0;
 937  937          open_args->owner.owner_val = NULL;
 938  938  
 939  939          if (create_flag) {
 940  940                  /* CREATE a file */
 941  941                  open_args->opentype = OPEN4_CREATE;
 942  942                  open_args->mode = createmode;
 943  943                  if (createmode == EXCLUSIVE4) {
 944  944                          if (did_excl_setup == FALSE) {
 945  945                                  verf.seconds = zone_get_hostid(NULL);
 946  946                                  if (verf.seconds != 0)
 947  947                                          verf.nseconds = newnum();
 948  948                                  else {
 949  949                                          timestruc_t now;
 950  950  
 951  951                                          gethrestime(&now);
 952  952                                          verf.seconds = now.tv_sec;
 953  953                                          verf.nseconds = now.tv_nsec;
 954  954                                  }
 955  955                                  /*
 956  956                                   * Since the server will use this value for the
 957  957                                   * mtime, make sure that it can't overflow. Zero
 958  958                                   * out the MSB. The actual value does not matter
 959  959                                   * here, only its uniqeness.
 960  960                                   */
 961  961                                  verf.seconds &= INT32_MAX;
 962  962                                  did_excl_setup = TRUE;
 963  963                          }
 964  964  
 965  965                          /* Now copy over verifier to OPEN4args. */
 966  966                          open_args->createhow4_u.createverf = *(uint64_t *)&verf;
 967  967                  } else {
 968  968                          int v_error;
 969  969                          bitmap4 supp_attrs;
 970  970                          servinfo4_t *svp;
 971  971  
 972  972                          attr = &open_args->createhow4_u.createattrs;
 973  973  
 974  974                          svp = drp->r_server;
 975  975                          (void) nfs_rw_enter_sig(&svp->sv_lock, RW_READER, 0);
 976  976                          supp_attrs = svp->sv_supp_attrs;
 977  977                          nfs_rw_exit(&svp->sv_lock);
 978  978  
 979  979                          /* GUARDED4 or UNCHECKED4 */
 980  980                          v_error = vattr_to_fattr4(in_va, NULL, attr, 0, OP_OPEN,
 981  981                              supp_attrs);
 982  982                          if (v_error) {
 983  983                                  bzero(attr, sizeof (*attr));
 984  984                                  nfs4args_copen_free(open_args);
 985  985                                  nfs4_end_op(VTOMI4(dvp), dvp, vpi,
 986  986                                      &recov_state, FALSE);
 987  987                                  if (ncr != NULL)
 988  988                                          crfree(ncr);
 989  989                                  kmem_free(argop, argoplist_size);
 990  990                                  return (v_error);
 991  991                          }
 992  992                  }
 993  993          } else {
 994  994                  /* NO CREATE */
 995  995                  open_args->opentype = OPEN4_NOCREATE;
 996  996          }
 997  997  
 998  998          if (recov_state.rs_sp != NULL) {
 999  999                  mutex_enter(&recov_state.rs_sp->s_lock);
1000 1000                  open_args->owner.clientid = recov_state.rs_sp->clientid;
1001 1001                  mutex_exit(&recov_state.rs_sp->s_lock);
1002 1002          } else {
1003 1003                  /* XXX should we just fail here? */
1004 1004                  open_args->owner.clientid = 0;
1005 1005          }
1006 1006  
1007 1007          /*
1008 1008           * This increments oop's ref count or creates a temporary 'just_created'
1009 1009           * open owner that will become valid when this OPEN/OPEN_CONFIRM call
1010 1010           * completes.
1011 1011           */
1012 1012          mutex_enter(&VTOMI4(dvp)->mi_lock);
1013 1013  
1014 1014          /* See if a permanent or just created open owner exists */
1015 1015          oop = find_open_owner_nolock(cr, NFS4_JUST_CREATED, VTOMI4(dvp));
1016 1016          if (!oop) {
1017 1017                  /*
1018 1018                   * This open owner does not exist so create a temporary
1019 1019                   * just created one.
1020 1020                   */
1021 1021                  oop = create_open_owner(cr, VTOMI4(dvp));
1022 1022                  ASSERT(oop != NULL);
1023 1023          }
1024 1024          mutex_exit(&VTOMI4(dvp)->mi_lock);
1025 1025  
1026 1026          /* this length never changes, do alloc before seqid sync */
1027 1027          open_args->owner.owner_len = sizeof (oop->oo_name);
1028 1028          open_args->owner.owner_val =
1029 1029              kmem_alloc(open_args->owner.owner_len, KM_SLEEP);
1030 1030  
1031 1031          e.error = nfs4_start_open_seqid_sync(oop, VTOMI4(dvp));
1032 1032          if (e.error == EAGAIN) {
1033 1033                  open_owner_rele(oop);
1034 1034                  nfs4args_copen_free(open_args);
1035 1035                  nfs4_end_op(VTOMI4(dvp), dvp, vpi, &recov_state, TRUE);
1036 1036                  if (ncr != NULL) {
1037 1037                          crfree(ncr);
1038 1038                          ncr = NULL;
1039 1039                  }
1040 1040                  goto recov_retry;
1041 1041          }
1042 1042  
1043 1043          /* Check to see if we need to do the OTW call */
1044 1044          if (!create_flag) {
1045 1045                  if (!nfs4_is_otw_open_necessary(oop, open_flag, vpi,
1046 1046                      file_just_been_created, &e.error, acc, &recov_state)) {
1047 1047  
1048 1048                          /*
1049 1049                           * The OTW open is not necessary.  Either
1050 1050                           * the open can succeed without it (eg.
1051 1051                           * delegation, error == 0) or the open
1052 1052                           * must fail due to an access failure
1053 1053                           * (error != 0).  In either case, tidy
1054 1054                           * up and return.
1055 1055                           */
1056 1056  
1057 1057                          nfs4_end_open_seqid_sync(oop);
1058 1058                          open_owner_rele(oop);
1059 1059                          nfs4args_copen_free(open_args);
1060 1060                          nfs4_end_op(VTOMI4(dvp), dvp, vpi, &recov_state, FALSE);
1061 1061                          if (ncr != NULL)
1062 1062                                  crfree(ncr);
1063 1063                          kmem_free(argop, argoplist_size);
1064 1064                          return (e.error);
1065 1065                  }
1066 1066          }
1067 1067  
1068 1068          bcopy(&oop->oo_name, open_args->owner.owner_val,
1069 1069              open_args->owner.owner_len);
1070 1070  
1071 1071          seqid = nfs4_get_open_seqid(oop) + 1;
1072 1072          open_args->seqid = seqid;
1073 1073          open_args->share_access = 0;
1074 1074          if (open_flag & FREAD)
1075 1075                  open_args->share_access |= OPEN4_SHARE_ACCESS_READ;
1076 1076          if (open_flag & FWRITE)
1077 1077                  open_args->share_access |= OPEN4_SHARE_ACCESS_WRITE;
1078 1078          open_args->share_deny = OPEN4_SHARE_DENY_NONE;
1079 1079  
1080 1080  
1081 1081  
1082 1082          /*
1083 1083           * getfh w/sanity check for idx_open/idx_fattr
1084 1084           */
1085 1085          ASSERT((idx_open + 1) == (idx_fattr - 1));
1086 1086          argop[idx_open + 1].argop = OP_GETFH;
1087 1087  
1088 1088          /* getattr */
1089 1089          argop[idx_fattr].argop = OP_GETATTR;
1090 1090          argop[idx_fattr].nfs_argop4_u.opgetattr.attr_request = NFS4_VATTR_MASK;
1091 1091          argop[idx_fattr].nfs_argop4_u.opgetattr.mi = VTOMI4(dvp);
1092 1092  
1093 1093          if (setgid_flag) {
1094 1094                  vattr_t _v;
1095 1095                  servinfo4_t *svp;
1096 1096                  bitmap4 supp_attrs;
1097 1097  
1098 1098                  svp = drp->r_server;
1099 1099                  (void) nfs_rw_enter_sig(&svp->sv_lock, RW_READER, 0);
1100 1100                  supp_attrs = svp->sv_supp_attrs;
1101 1101                  nfs_rw_exit(&svp->sv_lock);
1102 1102  
1103 1103                  /*
1104 1104                   * For setgid case, we need to:
1105 1105                   * 4:savefh(new) 5:putfh(dir) 6:getattr(dir) 7:restorefh(new)
1106 1106                   */
1107 1107                  argop[4].argop = OP_SAVEFH;
1108 1108  
1109 1109                  argop[5].argop = OP_CPUTFH;
1110 1110                  argop[5].nfs_argop4_u.opcputfh.sfh = drp->r_fh;
1111 1111  
1112 1112                  argop[6].argop = OP_GETATTR;
1113 1113                  argop[6].nfs_argop4_u.opgetattr.attr_request = NFS4_VATTR_MASK;
1114 1114                  argop[6].nfs_argop4_u.opgetattr.mi = VTOMI4(dvp);
1115 1115  
1116 1116                  argop[7].argop = OP_RESTOREFH;
1117 1117  
1118 1118                  /*
1119 1119                   * nverify
1120 1120                   */
1121 1121                  _v.va_mask = AT_GID;
1122 1122                  _v.va_gid = in_va->va_gid;
1123 1123                  if (!(e.error = nfs4args_verify(&argop[8], &_v, OP_NVERIFY,
1124 1124                      supp_attrs))) {
1125 1125  
1126 1126                          /*
1127 1127                           * setattr
1128 1128                           *
1129 1129                           * We _know_ we're not messing with AT_SIZE or
1130 1130                           * AT_XTIME, so no need for stateid or flags.
1131 1131                           * Also we specify NULL rp since we're only
1132 1132                           * interested in setting owner_group attributes.
1133 1133                           */
1134 1134                          nfs4args_setattr(&argop[9], &_v, NULL, 0, NULL, cr,
1135 1135                              supp_attrs, &e.error, 0);
1136 1136                          if (e.error)
1137 1137                                  nfs4args_verify_free(&argop[8]);
1138 1138                  }
1139 1139  
1140 1140                  if (e.error) {
1141 1141                          /*
1142 1142                           * XXX - Revisit the last argument to nfs4_end_op()
1143 1143                           *       once 5020486 is fixed.
1144 1144                           */
1145 1145                          nfs4_end_open_seqid_sync(oop);
1146 1146                          open_owner_rele(oop);
1147 1147                          nfs4args_copen_free(open_args);
1148 1148                          nfs4_end_op(VTOMI4(dvp), dvp, vpi, &recov_state, TRUE);
1149 1149                          if (ncr != NULL)
1150 1150                                  crfree(ncr);
1151 1151                          kmem_free(argop, argoplist_size);
1152 1152                          return (e.error);
1153 1153                  }
1154 1154          } else if (create_flag) {
1155 1155                  argop[1].argop = OP_SAVEFH;
1156 1156  
1157 1157                  argop[5].argop = OP_RESTOREFH;
1158 1158  
1159 1159                  argop[6].argop = OP_GETATTR;
1160 1160                  argop[6].nfs_argop4_u.opgetattr.attr_request = NFS4_VATTR_MASK;
1161 1161                  argop[6].nfs_argop4_u.opgetattr.mi = VTOMI4(dvp);
1162 1162          }
1163 1163  
1164 1164          NFS4_DEBUG(nfs4_client_call_debug, (CE_NOTE,
1165 1165              "nfs4open_otw: %s call, nm %s, rp %s",
1166 1166              needrecov ? "recov" : "first", file_name,
1167 1167              rnode4info(VTOR4(dvp))));
1168 1168  
1169 1169          t = gethrtime();
1170 1170  
1171 1171          rfs4call(VTOMI4(dvp), &args, &res, cred_otw, &doqueue, 0, &e);
1172 1172  
1173 1173          if (!e.error && nfs4_need_to_bump_seqid(&res))
1174 1174                  nfs4_set_open_seqid(seqid, oop, args.ctag);
1175 1175  
1176 1176          needrecov = nfs4_needs_recovery(&e, TRUE, dvp->v_vfsp);
1177 1177  
1178 1178          if (e.error || needrecov) {
1179 1179                  bool_t abort = FALSE;
1180 1180  
1181 1181                  if (needrecov) {
1182 1182                          nfs4_bseqid_entry_t *bsep = NULL;
1183 1183  
1184 1184                          nfs4open_save_lost_rqst(e.error, &lost_rqst, oop,
1185 1185                              cred_otw, vpi, dvp, open_args);
1186 1186  
1187 1187                          if (!e.error && res.status == NFS4ERR_BAD_SEQID) {
1188 1188                                  bsep = nfs4_create_bseqid_entry(oop, NULL,
1189 1189                                      vpi, 0, args.ctag, open_args->seqid);
1190 1190                                  num_bseqid_retry--;
1191 1191                          }
1192 1192  
1193 1193                          abort = nfs4_start_recovery(&e, VTOMI4(dvp), dvp, vpi,
1194 1194                              NULL, lost_rqst.lr_op == OP_OPEN ?
1195 1195                              &lost_rqst : NULL, OP_OPEN, bsep, NULL, NULL);
1196 1196  
1197 1197                          if (bsep)
1198 1198                                  kmem_free(bsep, sizeof (*bsep));
1199 1199                          /* give up if we keep getting BAD_SEQID */
1200 1200                          if (num_bseqid_retry == 0)
1201 1201                                  abort = TRUE;
1202 1202                          if (abort == TRUE && e.error == 0)
1203 1203                                  e.error = geterrno4(res.status);
1204 1204                  }
1205 1205                  nfs4_end_open_seqid_sync(oop);
1206 1206                  open_owner_rele(oop);
1207 1207                  nfs4_end_op(VTOMI4(dvp), dvp, vpi, &recov_state, needrecov);
1208 1208                  nfs4args_copen_free(open_args);
1209 1209                  if (setgid_flag) {
1210 1210                          nfs4args_verify_free(&argop[8]);
1211 1211                          nfs4args_setattr_free(&argop[9]);
1212 1212                  }
1213 1213                  if (!e.error)
1214 1214                          (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
1215 1215                  if (ncr != NULL) {
1216 1216                          crfree(ncr);
1217 1217                          ncr = NULL;
1218 1218                  }
1219 1219                  if (!needrecov || abort == TRUE || e.error == EINTR ||
1220 1220                      NFS4_FRC_UNMT_ERR(e.error, dvp->v_vfsp)) {
1221 1221                          kmem_free(argop, argoplist_size);
1222 1222                          return (e.error);
1223 1223                  }
1224 1224                  goto recov_retry;
1225 1225          }
1226 1226  
1227 1227          /*
1228 1228           * Will check and update lease after checking the rflag for
1229 1229           * OPEN_CONFIRM in the successful OPEN call.
1230 1230           */
1231 1231          if (res.status != NFS4_OK && res.array_len <= idx_fattr + 1) {
1232 1232  
1233 1233                  /*
1234 1234                   * XXX what if we're crossing mount points from server1:/drp
1235 1235                   * to server2:/drp/rp.
1236 1236                   */
1237 1237  
1238 1238                  /* Signal our end of use of the open seqid */
1239 1239                  nfs4_end_open_seqid_sync(oop);
1240 1240  
1241 1241                  /*
1242 1242                   * This will destroy the open owner if it was just created,
1243 1243                   * and no one else has put a reference on it.
1244 1244                   */
1245 1245                  open_owner_rele(oop);
1246 1246                  if (create_flag && (createmode != EXCLUSIVE4) &&
1247 1247                      res.status == NFS4ERR_BADOWNER)
1248 1248                          nfs4_log_badowner(VTOMI4(dvp), OP_OPEN);
1249 1249  
1250 1250                  e.error = geterrno4(res.status);
1251 1251                  nfs4args_copen_free(open_args);
1252 1252                  if (setgid_flag) {
1253 1253                          nfs4args_verify_free(&argop[8]);
1254 1254                          nfs4args_setattr_free(&argop[9]);
1255 1255                  }
1256 1256                  (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
1257 1257                  nfs4_end_op(VTOMI4(dvp), dvp, vpi, &recov_state, needrecov);
1258 1258                  /*
1259 1259                   * If the reply is NFS4ERR_ACCESS, it may be because
1260 1260                   * we are root (no root net access).  If the real uid
1261 1261                   * is not root, then retry with the real uid instead.
1262 1262                   */
1263 1263                  if (ncr != NULL) {
1264 1264                          crfree(ncr);
1265 1265                          ncr = NULL;
1266 1266                  }
1267 1267                  if (res.status == NFS4ERR_ACCESS &&
1268 1268                      (ncr = crnetadjust(cred_otw)) != NULL) {
1269 1269                          cred_otw = ncr;
1270 1270                          goto recov_retry;
1271 1271                  }
1272 1272                  kmem_free(argop, argoplist_size);
1273 1273                  return (e.error);
1274 1274          }
1275 1275  
1276 1276          resop = &res.array[idx_open];  /* open res */
1277 1277          op_res = &resop->nfs_resop4_u.opopen;
1278 1278  
1279 1279  #ifdef DEBUG
1280 1280          /*
1281 1281           * verify attrset bitmap
1282 1282           */
1283 1283          if (create_flag &&
1284 1284              (createmode == UNCHECKED4 || createmode == GUARDED4)) {
1285 1285                  /* make sure attrset returned is what we asked for */
1286 1286                  /* XXX Ignore this 'error' for now */
1287 1287                  if (attr->attrmask != op_res->attrset)
1288 1288                          /* EMPTY */;
1289 1289          }
1290 1290  #endif
1291 1291  
1292 1292          if (op_res->rflags & OPEN4_RESULT_LOCKTYPE_POSIX) {
1293 1293                  mutex_enter(&VTOMI4(dvp)->mi_lock);
1294 1294                  VTOMI4(dvp)->mi_flags |= MI4_POSIX_LOCK;
1295 1295                  mutex_exit(&VTOMI4(dvp)->mi_lock);
1296 1296          }
1297 1297  
1298 1298          resop = &res.array[idx_open + 1];  /* getfh res */
1299 1299          gf_res = &resop->nfs_resop4_u.opgetfh;
1300 1300  
1301 1301          otw_sfh = sfh4_get(&gf_res->object, VTOMI4(dvp));
1302 1302  
1303 1303          /*
1304 1304           * The open stateid has been updated on the server but not
1305 1305           * on the client yet.  There is a path: makenfs4node->nfs4_attr_cache->
1306 1306           * flush_pages->VOP_PUTPAGE->...->nfs4write where we will issue an OTW
1307 1307           * WRITE call.  That, however, will use the old stateid, so go ahead
1308 1308           * and upate the open stateid now, before any call to makenfs4node.
1309 1309           */
1310 1310          if (vpi) {
1311 1311                  nfs4_open_stream_t      *tmp_osp;
1312 1312                  rnode4_t                *tmp_rp = VTOR4(vpi);
1313 1313  
1314 1314                  tmp_osp = find_open_stream(oop, tmp_rp);
1315 1315                  if (tmp_osp) {
1316 1316                          tmp_osp->open_stateid = op_res->stateid;
1317 1317                          mutex_exit(&tmp_osp->os_sync_lock);
1318 1318                          open_stream_rele(tmp_osp, tmp_rp);
1319 1319                  }
1320 1320  
1321 1321                  /*
1322 1322                   * We must determine if the file handle given by the otw open
1323 1323                   * is the same as the file handle which was passed in with
1324 1324                   * *vpp.  This case can be reached if the file we are trying
1325 1325                   * to open has been removed and another file has been created
1326 1326                   * having the same file name.  The passed in vnode is released
1327 1327                   * later.
1328 1328                   */
1329 1329                  orig_sfh = VTOR4(vpi)->r_fh;
1330 1330                  fh_differs = nfs4cmpfh(&orig_sfh->sfh_fh, &otw_sfh->sfh_fh);
1331 1331          }
1332 1332  
1333 1333          garp = &res.array[idx_fattr].nfs_resop4_u.opgetattr.ga_res;
1334 1334  
1335 1335          if (create_flag || fh_differs) {
1336 1336                  int rnode_err = 0;
1337 1337  
1338 1338                  vp = makenfs4node(otw_sfh, garp, dvp->v_vfsp, t, cr,
1339 1339                      dvp, fn_get(VTOSV(dvp)->sv_name, file_name, otw_sfh));
1340 1340  
1341 1341                  if (e.error)
1342 1342                          PURGE_ATTRCACHE4(vp);
1343 1343                  /*
1344 1344                   * For the newly created vp case, make sure the rnode
1345 1345                   * isn't bad before using it.
1346 1346                   */
1347 1347                  mutex_enter(&(VTOR4(vp))->r_statelock);
1348 1348                  if (VTOR4(vp)->r_flags & R4RECOVERR)
1349 1349                          rnode_err = EIO;
1350 1350                  mutex_exit(&(VTOR4(vp))->r_statelock);
1351 1351  
1352 1352                  if (rnode_err) {
1353 1353                          nfs4_end_open_seqid_sync(oop);
1354 1354                          nfs4args_copen_free(open_args);
1355 1355                          if (setgid_flag) {
1356 1356                                  nfs4args_verify_free(&argop[8]);
1357 1357                                  nfs4args_setattr_free(&argop[9]);
1358 1358                          }
1359 1359                          (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
1360 1360                          nfs4_end_op(VTOMI4(dvp), dvp, vpi, &recov_state,
1361 1361                              needrecov);
1362 1362                          open_owner_rele(oop);
1363 1363                          VN_RELE(vp);
1364 1364                          if (ncr != NULL)
1365 1365                                  crfree(ncr);
1366 1366                          sfh4_rele(&otw_sfh);
1367 1367                          kmem_free(argop, argoplist_size);
1368 1368                          return (EIO);
1369 1369                  }
1370 1370          } else {
1371 1371                  vp = vpi;
1372 1372          }
1373 1373          sfh4_rele(&otw_sfh);
1374 1374  
1375 1375          /*
1376 1376           * It seems odd to get a full set of attrs and then not update
1377 1377           * the object's attrcache in the non-create case.  Create case uses
1378 1378           * the attrs since makenfs4node checks to see if the attrs need to
1379 1379           * be updated (and then updates them).  The non-create case should
1380 1380           * update attrs also.
1381 1381           */
1382 1382          if (! create_flag && ! fh_differs && !e.error) {
1383 1383                  nfs4_attr_cache(vp, garp, t, cr, TRUE, NULL);
1384 1384          }
1385 1385  
1386 1386          nfs4_error_zinit(&e);
1387 1387          if (op_res->rflags & OPEN4_RESULT_CONFIRM) {
1388 1388                  /* This does not do recovery for vp explicitly. */
1389 1389                  nfs4open_confirm(vp, &seqid, &op_res->stateid, cred_otw, FALSE,
1390 1390                      &retry_open, oop, FALSE, &e, &num_bseqid_retry);
1391 1391  
1392 1392                  if (e.error || e.stat) {
1393 1393                          nfs4_end_open_seqid_sync(oop);
1394 1394                          nfs4args_copen_free(open_args);
1395 1395                          if (setgid_flag) {
1396 1396                                  nfs4args_verify_free(&argop[8]);
1397 1397                                  nfs4args_setattr_free(&argop[9]);
1398 1398                          }
1399 1399                          (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
1400 1400                          nfs4_end_op(VTOMI4(dvp), dvp, vpi, &recov_state,
1401 1401                              needrecov);
1402 1402                          open_owner_rele(oop);
1403 1403                          if (create_flag || fh_differs) {
1404 1404                                  /* rele the makenfs4node */
1405 1405                                  VN_RELE(vp);
1406 1406                          }
1407 1407                          if (ncr != NULL) {
1408 1408                                  crfree(ncr);
1409 1409                                  ncr = NULL;
1410 1410                          }
1411 1411                          if (retry_open == TRUE) {
1412 1412                                  NFS4_DEBUG(nfs4_client_recov_debug, (CE_NOTE,
1413 1413                                      "nfs4open_otw: retry the open since OPEN "
1414 1414                                      "CONFIRM failed with error %d stat %d",
1415 1415                                      e.error, e.stat));
1416 1416                                  if (create_flag && createmode == GUARDED4) {
1417 1417                                          NFS4_DEBUG(nfs4_client_recov_debug,
1418 1418                                              (CE_NOTE, "nfs4open_otw: switch "
1419 1419                                              "createmode from GUARDED4 to "
1420 1420                                              "UNCHECKED4"));
1421 1421                                          createmode = UNCHECKED4;
1422 1422                                  }
1423 1423                                  goto recov_retry;
1424 1424                          }
1425 1425                          if (!e.error) {
1426 1426                                  if (create_flag && (createmode != EXCLUSIVE4) &&
1427 1427                                      e.stat == NFS4ERR_BADOWNER)
1428 1428                                          nfs4_log_badowner(VTOMI4(dvp), OP_OPEN);
1429 1429  
1430 1430                                  e.error = geterrno4(e.stat);
1431 1431                          }
1432 1432                          kmem_free(argop, argoplist_size);
1433 1433                          return (e.error);
1434 1434                  }
1435 1435          }
1436 1436  
1437 1437          rp = VTOR4(vp);
1438 1438  
1439 1439          mutex_enter(&rp->r_statev4_lock);
1440 1440          if (create_flag)
1441 1441                  rp->created_v4 = 1;
1442 1442          mutex_exit(&rp->r_statev4_lock);
1443 1443  
1444 1444          mutex_enter(&oop->oo_lock);
1445 1445          /* Doesn't matter if 'oo_just_created' already was set as this */
1446 1446          oop->oo_just_created = NFS4_PERM_CREATED;
1447 1447          if (oop->oo_cred_otw)
1448 1448                  crfree(oop->oo_cred_otw);
1449 1449          oop->oo_cred_otw = cred_otw;
1450 1450          crhold(oop->oo_cred_otw);
1451 1451          mutex_exit(&oop->oo_lock);
1452 1452  
1453 1453          /* returns with 'os_sync_lock' held */
1454 1454          osp = find_or_create_open_stream(oop, rp, &created_osp);
1455 1455          if (!osp) {
1456 1456                  NFS4_DEBUG(nfs4_client_state_debug, (CE_NOTE,
1457 1457                      "nfs4open_otw: failed to create an open stream"));
1458 1458                  NFS4_DEBUG(nfs4_seqid_sync, (CE_NOTE, "nfs4open_otw: "
1459 1459                      "signal our end of use of the open seqid"));
1460 1460  
1461 1461                  nfs4_end_open_seqid_sync(oop);
1462 1462                  open_owner_rele(oop);
1463 1463                  nfs4args_copen_free(open_args);
1464 1464                  if (setgid_flag) {
1465 1465                          nfs4args_verify_free(&argop[8]);
1466 1466                          nfs4args_setattr_free(&argop[9]);
1467 1467                  }
1468 1468                  (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
1469 1469                  nfs4_end_op(VTOMI4(dvp), dvp, vpi, &recov_state, needrecov);
1470 1470                  if (create_flag || fh_differs)
1471 1471                          VN_RELE(vp);
1472 1472                  if (ncr != NULL)
1473 1473                          crfree(ncr);
1474 1474  
1475 1475                  kmem_free(argop, argoplist_size);
1476 1476                  return (EINVAL);
1477 1477  
1478 1478          }
1479 1479  
1480 1480          osp->open_stateid = op_res->stateid;
1481 1481  
1482 1482          if (open_flag & FREAD)
1483 1483                  osp->os_share_acc_read++;
1484 1484          if (open_flag & FWRITE)
1485 1485                  osp->os_share_acc_write++;
1486 1486          osp->os_share_deny_none++;
1487 1487  
1488 1488          /*
1489 1489           * Need to reset this bitfield for the possible case where we were
1490 1490           * going to OTW CLOSE the file, got a non-recoverable error, and before
1491 1491           * we could retry the CLOSE, OPENed the file again.
1492 1492           */
1493 1493          ASSERT(osp->os_open_owner->oo_seqid_inuse);
1494 1494          osp->os_final_close = 0;
1495 1495          osp->os_force_close = 0;
1496 1496  #ifdef DEBUG
1497 1497          if (osp->os_failed_reopen)
1498 1498                  NFS4_DEBUG(nfs4_open_stream_debug, (CE_NOTE, "nfs4open_otw:"
1499 1499                      " clearing os_failed_reopen for osp %p, cr %p, rp %s",
1500 1500                      (void *)osp, (void *)cr, rnode4info(rp)));
1501 1501  #endif
1502 1502          osp->os_failed_reopen = 0;
1503 1503  
1504 1504          mutex_exit(&osp->os_sync_lock);
1505 1505  
1506 1506          nfs4_end_open_seqid_sync(oop);
1507 1507  
1508 1508          if (created_osp && recov_state.rs_sp != NULL) {
1509 1509                  mutex_enter(&recov_state.rs_sp->s_lock);
1510 1510                  nfs4_inc_state_ref_count_nolock(recov_state.rs_sp, VTOMI4(dvp));
1511 1511                  mutex_exit(&recov_state.rs_sp->s_lock);
1512 1512          }
1513 1513  
1514 1514          /* get rid of our reference to find oop */
1515 1515          open_owner_rele(oop);
1516 1516  
1517 1517          open_stream_rele(osp, rp);
1518 1518  
1519 1519          /* accept delegation, if any */
1520 1520          nfs4_delegation_accept(rp, CLAIM_NULL, op_res, garp, cred_otw);
1521 1521  
1522 1522          nfs4_end_op(VTOMI4(dvp), dvp, vpi, &recov_state, needrecov);
1523 1523  
1524 1524          if (createmode == EXCLUSIVE4 &&
1525 1525              (in_va->va_mask & ~(AT_GID | AT_SIZE))) {
1526 1526                  NFS4_DEBUG(nfs4_client_state_debug, (CE_NOTE, "nfs4open_otw:"
1527 1527                      " EXCLUSIVE4: sending a SETATTR"));
1528 1528                  /*
1529 1529                   * If doing an exclusive create, then generate
1530 1530                   * a SETATTR to set the initial attributes.
1531 1531                   * Try to set the mtime and the atime to the
1532 1532                   * server's current time.  It is somewhat
1533 1533                   * expected that these fields will be used to
1534 1534                   * store the exclusive create cookie.  If not,
1535 1535                   * server implementors will need to know that
1536 1536                   * a SETATTR will follow an exclusive create
1537 1537                   * and the cookie should be destroyed if
1538 1538                   * appropriate.
1539 1539                   *
1540 1540                   * The AT_GID and AT_SIZE bits are turned off
1541 1541                   * so that the SETATTR request will not attempt
1542 1542                   * to process these.  The gid will be set
1543 1543                   * separately if appropriate.  The size is turned
1544 1544                   * off because it is assumed that a new file will
1545 1545                   * be created empty and if the file wasn't empty,
1546 1546                   * then the exclusive create will have failed
1547 1547                   * because the file must have existed already.
1548 1548                   * Therefore, no truncate operation is needed.
1549 1549                   */
1550 1550                  in_va->va_mask &= ~(AT_GID | AT_SIZE);
1551 1551                  in_va->va_mask |= (AT_MTIME | AT_ATIME);
1552 1552  
1553 1553                  e.error = nfs4setattr(vp, in_va, 0, cr, NULL);
1554 1554                  if (e.error) {
1555 1555                          /*
1556 1556                           * Couldn't correct the attributes of
1557 1557                           * the newly created file and the
1558 1558                           * attributes are wrong.  Remove the
1559 1559                           * file and return an error to the
1560 1560                           * application.
1561 1561                           */
1562 1562                          /* XXX will this take care of client state ? */
1563 1563                          NFS4_DEBUG(nfs4_client_state_debug, (CE_NOTE,
1564 1564                              "nfs4open_otw: EXCLUSIVE4: error %d on SETATTR:"
1565 1565                              " remove file", e.error));
1566 1566                          VN_RELE(vp);
1567 1567                          (void) nfs4_remove(dvp, file_name, cr, NULL, 0);
1568 1568                          /*
1569 1569                           * Since we've reled the vnode and removed
1570 1570                           * the file we now need to return the error.
1571 1571                           * At this point we don't want to update the
1572 1572                           * dircaches, call nfs4_waitfor_purge_complete
1573 1573                           * or set vpp to vp so we need to skip these
1574 1574                           * as well.
1575 1575                           */
1576 1576                          goto skip_update_dircaches;
1577 1577                  }
1578 1578          }
1579 1579  
1580 1580          /*
1581 1581           * If we created or found the correct vnode, due to create_flag or
1582 1582           * fh_differs being set, then update directory cache attribute, readdir
1583 1583           * and dnlc caches.
1584 1584           */
1585 1585          if (create_flag || fh_differs) {
1586 1586                  dirattr_info_t dinfo, *dinfop;
1587 1587  
1588 1588                  /*
1589 1589                   * Make sure getattr succeeded before using results.
1590 1590                   * note: op 7 is getattr(dir) for both flavors of
1591 1591                   * open(create).
1592 1592                   */
1593 1593                  if (create_flag && res.status == NFS4_OK) {
1594 1594                          dinfo.di_time_call = t;
1595 1595                          dinfo.di_cred = cr;
1596 1596                          dinfo.di_garp =
1597 1597                              &res.array[6].nfs_resop4_u.opgetattr.ga_res;
1598 1598                          dinfop = &dinfo;
1599 1599                  } else {
1600 1600                          dinfop = NULL;
1601 1601                  }
1602 1602  
1603 1603                  nfs4_update_dircaches(&op_res->cinfo, dvp, vp, file_name,
1604 1604                      dinfop);
1605 1605          }
1606 1606  
1607 1607          /*
1608 1608           * If the page cache for this file was flushed from actions
1609 1609           * above, it was done asynchronously and if that is true,
1610 1610           * there is a need to wait here for it to complete.  This must
1611 1611           * be done outside of start_fop/end_fop.
1612 1612           */
1613 1613          (void) nfs4_waitfor_purge_complete(vp);
1614 1614  
1615 1615          /*
1616 1616           * It is implicit that we are in the open case (create_flag == 0) since
1617 1617           * fh_differs can only be set to a non-zero value in the open case.
1618 1618           */
1619 1619          if (fh_differs != 0 && vpi != NULL)
1620 1620                  VN_RELE(vpi);
1621 1621  
1622 1622          /*
1623 1623           * Be sure to set *vpp to the correct value before returning.
1624 1624           */
1625 1625          *vpp = vp;
1626 1626  
1627 1627  skip_update_dircaches:
1628 1628  
1629 1629          nfs4args_copen_free(open_args);
1630 1630          if (setgid_flag) {
1631 1631                  nfs4args_verify_free(&argop[8]);
1632 1632                  nfs4args_setattr_free(&argop[9]);
1633 1633          }
1634 1634          (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
1635 1635  
1636 1636          if (ncr)
1637 1637                  crfree(ncr);
1638 1638          kmem_free(argop, argoplist_size);
1639 1639          return (e.error);
1640 1640  }
1641 1641  
1642 1642  /*
1643 1643   * Reopen an open instance.  cf. nfs4open_otw().
1644 1644   *
1645 1645   * Errors are returned by the nfs4_error_t parameter.
1646 1646   * - ep->error contains an errno value or zero.
1647 1647   * - if it is zero, ep->stat is set to an NFS status code, if any.
1648 1648   *   If the file could not be reopened, but the caller should continue, the
1649 1649   *   file is marked dead and no error values are returned.  If the caller
1650 1650   *   should stop recovering open files and start over, either the ep->error
1651 1651   *   value or ep->stat will indicate an error (either something that requires
1652 1652   *   recovery or EAGAIN).  Note that some recovery (e.g., expired volatile
1653 1653   *   filehandles) may be handled silently by this routine.
1654 1654   * - if it is EINTR, ETIMEDOUT, or NFS4_FRC_UNMT_ERR, recovery for lost state
1655 1655   *   will be started, so the caller should not do it.
1656 1656   *
1657 1657   * Gotos:
1658 1658   * - kill_file : reopen failed in such a fashion to constitute marking the
1659 1659   *    file dead and setting the open stream's 'os_failed_reopen' as 1.  This
1660 1660   *   is for cases where recovery is not possible.
1661 1661   * - failed_reopen : same as above, except that the file has already been
1662 1662   *   marked dead, so no need to do it again.
1663 1663   * - bailout : reopen failed but we are able to recover and retry the reopen -
1664 1664   *   either within this function immediately or via the calling function.
1665 1665   */
1666 1666  
1667 1667  void
1668 1668  nfs4_reopen(vnode_t *vp, nfs4_open_stream_t *osp, nfs4_error_t *ep,
1669 1669      open_claim_type4 claim, bool_t frc_use_claim_previous,
1670 1670      bool_t is_recov)
1671 1671  {
1672 1672          COMPOUND4args_clnt args;
1673 1673          COMPOUND4res_clnt res;
1674 1674          nfs_argop4 argop[4];
1675 1675          nfs_resop4 *resop;
1676 1676          OPEN4res *op_res = NULL;
1677 1677          OPEN4cargs *open_args;
1678 1678          GETFH4res *gf_res;
1679 1679          rnode4_t *rp = VTOR4(vp);
1680 1680          int doqueue = 1;
1681 1681          cred_t *cr = NULL, *cred_otw = NULL;
1682 1682          nfs4_open_owner_t *oop = NULL;
1683 1683          seqid4 seqid;
1684 1684          nfs4_ga_res_t *garp;
1685 1685          char fn[MAXNAMELEN];
1686 1686          nfs4_recov_state_t recov = {NULL, 0};
1687 1687          nfs4_lost_rqst_t lost_rqst;
1688 1688          mntinfo4_t *mi = VTOMI4(vp);
1689 1689          bool_t abort;
1690 1690          char *failed_msg = "";
1691 1691          int fh_different;
1692 1692          hrtime_t t;
1693 1693          nfs4_bseqid_entry_t *bsep = NULL;
1694 1694  
1695 1695          ASSERT(nfs4_consistent_type(vp));
1696 1696          ASSERT(nfs_zone() == mi->mi_zone);
1697 1697  
1698 1698          nfs4_error_zinit(ep);
1699 1699  
1700 1700          /* this is the cred used to find the open owner */
1701 1701          cr = state_to_cred(osp);
1702 1702          if (cr == NULL) {
1703 1703                  failed_msg = "Couldn't reopen: no cred";
1704 1704                  goto kill_file;
1705 1705          }
1706 1706          /* use this cred for OTW operations */
1707 1707          cred_otw = nfs4_get_otw_cred(cr, mi, osp->os_open_owner);
1708 1708  
1709 1709  top:
1710 1710          nfs4_error_zinit(ep);
1711 1711  
1712 1712          if (mi->mi_vfsp->vfs_flag & VFS_UNMOUNTED) {
1713 1713                  /* File system has been unmounted, quit */
1714 1714                  ep->error = EIO;
1715 1715                  failed_msg = "Couldn't reopen: file system has been unmounted";
1716 1716                  goto kill_file;
1717 1717          }
1718 1718  
1719 1719          oop = osp->os_open_owner;
1720 1720  
1721 1721          ASSERT(oop != NULL);
1722 1722          if (oop == NULL) {      /* be defensive in non-DEBUG */
1723 1723                  failed_msg = "can't reopen: no open owner";
1724 1724                  goto kill_file;
1725 1725          }
1726 1726          open_owner_hold(oop);
1727 1727  
1728 1728          ep->error = nfs4_start_open_seqid_sync(oop, mi);
1729 1729          if (ep->error) {
1730 1730                  open_owner_rele(oop);
1731 1731                  oop = NULL;
1732 1732                  goto bailout;
1733 1733          }
1734 1734  
1735 1735          /*
1736 1736           * If the rnode has a delegation and the delegation has been
1737 1737           * recovered and the server didn't request a recall and the caller
1738 1738           * didn't specifically ask for CLAIM_PREVIOUS (nfs4frlock during
1739 1739           * recovery) and the rnode hasn't been marked dead, then install
1740 1740           * the delegation stateid in the open stream.  Otherwise, proceed
1741 1741           * with a CLAIM_PREVIOUS or CLAIM_NULL OPEN.
1742 1742           */
1743 1743          mutex_enter(&rp->r_statev4_lock);
1744 1744          if (rp->r_deleg_type != OPEN_DELEGATE_NONE &&
1745 1745              !rp->r_deleg_return_pending &&
1746 1746              (rp->r_deleg_needs_recovery == OPEN_DELEGATE_NONE) &&
1747 1747              !rp->r_deleg_needs_recall &&
1748 1748              claim != CLAIM_DELEGATE_CUR && !frc_use_claim_previous &&
1749 1749              !(rp->r_flags & R4RECOVERR)) {
1750 1750                  mutex_enter(&osp->os_sync_lock);
1751 1751                  osp->os_delegation = 1;
1752 1752                  osp->open_stateid = rp->r_deleg_stateid;
1753 1753                  mutex_exit(&osp->os_sync_lock);
1754 1754                  mutex_exit(&rp->r_statev4_lock);
1755 1755                  goto bailout;
1756 1756          }
1757 1757          mutex_exit(&rp->r_statev4_lock);
1758 1758  
1759 1759          /*
1760 1760           * If the file failed recovery, just quit.  This failure need not
1761 1761           * affect other reopens, so don't return an error.
1762 1762           */
1763 1763          mutex_enter(&rp->r_statelock);
1764 1764          if (rp->r_flags & R4RECOVERR) {
1765 1765                  mutex_exit(&rp->r_statelock);
1766 1766                  ep->error = 0;
1767 1767                  goto failed_reopen;
1768 1768          }
1769 1769          mutex_exit(&rp->r_statelock);
1770 1770  
1771 1771          /*
1772 1772           * argop is empty here
1773 1773           *
1774 1774           * PUTFH, OPEN, GETATTR
1775 1775           */
1776 1776          args.ctag = TAG_REOPEN;
1777 1777          args.array_len = 4;
1778 1778          args.array = argop;
1779 1779  
1780 1780          NFS4_DEBUG(nfs4_client_failover_debug, (CE_NOTE,
1781 1781              "nfs4_reopen: file is type %d, id %s",
1782 1782              vp->v_type, rnode4info(VTOR4(vp))));
1783 1783  
1784 1784          argop[0].argop = OP_CPUTFH;
1785 1785  
1786 1786          if (claim != CLAIM_PREVIOUS) {
1787 1787                  /*
1788 1788                   * if this is a file mount then
1789 1789                   * use the mntinfo parentfh
1790 1790                   */
1791 1791                  argop[0].nfs_argop4_u.opcputfh.sfh =
1792 1792                      (vp->v_flag & VROOT) ? mi->mi_srvparentfh :
1793 1793                      VTOSV(vp)->sv_dfh;
1794 1794          } else {
1795 1795                  /* putfh fh to reopen */
1796 1796                  argop[0].nfs_argop4_u.opcputfh.sfh = rp->r_fh;
1797 1797          }
1798 1798  
1799 1799          argop[1].argop = OP_COPEN;
1800 1800          open_args = &argop[1].nfs_argop4_u.opcopen;
1801 1801          open_args->claim = claim;
1802 1802  
1803 1803          if (claim == CLAIM_NULL) {
1804 1804  
1805 1805                  if ((ep->error = vtoname(vp, fn, MAXNAMELEN)) != 0) {
1806 1806                          nfs_cmn_err(ep->error, CE_WARN, "nfs4_reopen: vtoname "
1807 1807                              "failed for vp 0x%p for CLAIM_NULL with %m",
1808 1808                              (void *)vp);
1809 1809                          failed_msg = "Couldn't reopen: vtoname failed for "
1810 1810                              "CLAIM_NULL";
1811 1811                          /* nothing allocated yet */
1812 1812                          goto kill_file;
1813 1813                  }
1814 1814  
1815 1815                  open_args->open_claim4_u.cfile = fn;
1816 1816          } else if (claim == CLAIM_PREVIOUS) {
1817 1817  
1818 1818                  /*
1819 1819                   * We have two cases to deal with here:
1820 1820                   * 1) We're being called to reopen files in order to satisfy
1821 1821                   *    a lock operation request which requires us to explicitly
1822 1822                   *    reopen files which were opened under a delegation.  If
1823 1823                   *    we're in recovery, we *must* use CLAIM_PREVIOUS.  In
1824 1824                   *    that case, frc_use_claim_previous is TRUE and we must
1825 1825                   *    use the rnode's current delegation type (r_deleg_type).
1826 1826                   * 2) We're reopening files during some form of recovery.
1827 1827                   *    In this case, frc_use_claim_previous is FALSE and we
1828 1828                   *    use the delegation type appropriate for recovery
1829 1829                   *    (r_deleg_needs_recovery).
1830 1830                   */
1831 1831                  mutex_enter(&rp->r_statev4_lock);
1832 1832                  open_args->open_claim4_u.delegate_type =
1833 1833                      frc_use_claim_previous ?
1834 1834                      rp->r_deleg_type :
1835 1835                      rp->r_deleg_needs_recovery;
1836 1836                  mutex_exit(&rp->r_statev4_lock);
1837 1837  
1838 1838          } else if (claim == CLAIM_DELEGATE_CUR) {
1839 1839  
1840 1840                  if ((ep->error = vtoname(vp, fn, MAXNAMELEN)) != 0) {
1841 1841                          nfs_cmn_err(ep->error, CE_WARN, "nfs4_reopen: vtoname "
1842 1842                              "failed for vp 0x%p for CLAIM_DELEGATE_CUR "
1843 1843                              "with %m", (void *)vp);
1844 1844                          failed_msg = "Couldn't reopen: vtoname failed for "
1845 1845                              "CLAIM_DELEGATE_CUR";
1846 1846                          /* nothing allocated yet */
1847 1847                          goto kill_file;
1848 1848                  }
1849 1849  
1850 1850                  mutex_enter(&rp->r_statev4_lock);
1851 1851                  open_args->open_claim4_u.delegate_cur_info.delegate_stateid =
1852 1852                      rp->r_deleg_stateid;
1853 1853                  mutex_exit(&rp->r_statev4_lock);
1854 1854  
1855 1855                  open_args->open_claim4_u.delegate_cur_info.cfile = fn;
1856 1856          }
1857 1857          open_args->opentype = OPEN4_NOCREATE;
1858 1858          open_args->owner.clientid = mi2clientid(mi);
1859 1859          open_args->owner.owner_len = sizeof (oop->oo_name);
1860 1860          open_args->owner.owner_val =
1861 1861              kmem_alloc(open_args->owner.owner_len, KM_SLEEP);
1862 1862          bcopy(&oop->oo_name, open_args->owner.owner_val,
1863 1863              open_args->owner.owner_len);
1864 1864          open_args->share_access = 0;
1865 1865          open_args->share_deny = 0;
1866 1866  
1867 1867          mutex_enter(&osp->os_sync_lock);
1868 1868          NFS4_DEBUG(nfs4_client_recov_debug, (CE_NOTE, "nfs4_reopen: osp %p rp "
1869 1869              "%p: read acc %"PRIu64" write acc %"PRIu64": open ref count %d: "
1870 1870              "mmap read %"PRIu64" mmap write %"PRIu64" claim %d ",
1871 1871              (void *)osp, (void *)rp, osp->os_share_acc_read,
1872 1872              osp->os_share_acc_write, osp->os_open_ref_count,
1873 1873              osp->os_mmap_read, osp->os_mmap_write, claim));
1874 1874  
1875 1875          if (osp->os_share_acc_read || osp->os_mmap_read)
1876 1876                  open_args->share_access |= OPEN4_SHARE_ACCESS_READ;
1877 1877          if (osp->os_share_acc_write || osp->os_mmap_write)
1878 1878                  open_args->share_access |= OPEN4_SHARE_ACCESS_WRITE;
1879 1879          if (osp->os_share_deny_read)
1880 1880                  open_args->share_deny |= OPEN4_SHARE_DENY_READ;
1881 1881          if (osp->os_share_deny_write)
1882 1882                  open_args->share_deny |= OPEN4_SHARE_DENY_WRITE;
1883 1883          mutex_exit(&osp->os_sync_lock);
1884 1884  
1885 1885          seqid = nfs4_get_open_seqid(oop) + 1;
1886 1886          open_args->seqid = seqid;
1887 1887  
1888 1888          /* Construct the getfh part of the compound */
1889 1889          argop[2].argop = OP_GETFH;
1890 1890  
1891 1891          /* Construct the getattr part of the compound */
1892 1892          argop[3].argop = OP_GETATTR;
1893 1893          argop[3].nfs_argop4_u.opgetattr.attr_request = NFS4_VATTR_MASK;
1894 1894          argop[3].nfs_argop4_u.opgetattr.mi = mi;
1895 1895  
1896 1896          t = gethrtime();
1897 1897  
1898 1898          rfs4call(mi, &args, &res, cred_otw, &doqueue, 0, ep);
1899 1899  
1900 1900          if (ep->error) {
1901 1901                  if (!is_recov && !frc_use_claim_previous &&
1902 1902                      (ep->error == EINTR || ep->error == ETIMEDOUT ||
1903 1903                      NFS4_FRC_UNMT_ERR(ep->error, vp->v_vfsp))) {
1904 1904                          nfs4open_save_lost_rqst(ep->error, &lost_rqst, oop,
1905 1905                              cred_otw, vp, NULL, open_args);
1906 1906                          abort = nfs4_start_recovery(ep,
1907 1907                              VTOMI4(vp), vp, NULL, NULL,
1908 1908                              lost_rqst.lr_op == OP_OPEN ?
1909 1909                              &lost_rqst : NULL, OP_OPEN, NULL, NULL, NULL);
1910 1910                          nfs4args_copen_free(open_args);
1911 1911                          goto bailout;
1912 1912                  }
1913 1913  
1914 1914                  nfs4args_copen_free(open_args);
1915 1915  
1916 1916                  if (ep->error == EACCES && cred_otw != cr) {
1917 1917                          crfree(cred_otw);
1918 1918                          cred_otw = cr;
1919 1919                          crhold(cred_otw);
1920 1920                          nfs4_end_open_seqid_sync(oop);
1921 1921                          open_owner_rele(oop);
1922 1922                          oop = NULL;
1923 1923                          goto top;
1924 1924                  }
1925 1925                  if (ep->error == ETIMEDOUT)
1926 1926                          goto bailout;
1927 1927                  failed_msg = "Couldn't reopen: rpc error";
1928 1928                  goto kill_file;
1929 1929          }
1930 1930  
1931 1931          if (nfs4_need_to_bump_seqid(&res))
1932 1932                  nfs4_set_open_seqid(seqid, oop, args.ctag);
1933 1933  
1934 1934          switch (res.status) {
1935 1935          case NFS4_OK:
1936 1936                  if (recov.rs_flags & NFS4_RS_DELAY_MSG) {
1937 1937                          mutex_enter(&rp->r_statelock);
1938 1938                          rp->r_delay_interval = 0;
1939 1939                          mutex_exit(&rp->r_statelock);
1940 1940                  }
1941 1941                  break;
1942 1942          case NFS4ERR_BAD_SEQID:
1943 1943                  bsep = nfs4_create_bseqid_entry(oop, NULL, vp, 0,
1944 1944                      args.ctag, open_args->seqid);
1945 1945  
1946 1946                  abort = nfs4_start_recovery(ep, VTOMI4(vp), vp, NULL,
1947 1947                      NULL, lost_rqst.lr_op == OP_OPEN ? &lost_rqst :
1948 1948                      NULL, OP_OPEN, bsep, NULL, NULL);
1949 1949  
1950 1950                  nfs4args_copen_free(open_args);
1951 1951                  (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
1952 1952                  nfs4_end_open_seqid_sync(oop);
1953 1953                  open_owner_rele(oop);
1954 1954                  oop = NULL;
1955 1955                  kmem_free(bsep, sizeof (*bsep));
1956 1956  
1957 1957                  goto kill_file;
1958 1958          case NFS4ERR_NO_GRACE:
1959 1959                  nfs4args_copen_free(open_args);
1960 1960                  (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
1961 1961                  nfs4_end_open_seqid_sync(oop);
1962 1962                  open_owner_rele(oop);
1963 1963                  oop = NULL;
1964 1964                  if (claim == CLAIM_PREVIOUS) {
1965 1965                          /*
1966 1966                           * Retry as a plain open. We don't need to worry about
1967 1967                           * checking the changeinfo: it is acceptable for a
1968 1968                           * client to re-open a file and continue processing
1969 1969                           * (in the absence of locks).
1970 1970                           */
1971 1971                          NFS4_DEBUG(nfs4_client_recov_debug, (CE_NOTE,
1972 1972                              "nfs4_reopen: CLAIM_PREVIOUS: NFS4ERR_NO_GRACE; "
1973 1973                              "will retry as CLAIM_NULL"));
1974 1974                          claim = CLAIM_NULL;
1975 1975                          nfs4_mi_kstat_inc_no_grace(mi);
1976 1976                          goto top;
1977 1977                  }
1978 1978                  failed_msg =
1979 1979                      "Couldn't reopen: tried reclaim outside grace period. ";
1980 1980                  goto kill_file;
1981 1981          case NFS4ERR_GRACE:
1982 1982                  nfs4_set_grace_wait(mi);
1983 1983                  nfs4args_copen_free(open_args);
1984 1984                  (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
1985 1985                  nfs4_end_open_seqid_sync(oop);
1986 1986                  open_owner_rele(oop);
1987 1987                  oop = NULL;
1988 1988                  ep->error = nfs4_wait_for_grace(mi, &recov);
1989 1989                  if (ep->error != 0)
1990 1990                          goto bailout;
1991 1991                  goto top;
1992 1992          case NFS4ERR_DELAY:
1993 1993                  nfs4_set_delay_wait(vp);
1994 1994                  nfs4args_copen_free(open_args);
1995 1995                  (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
1996 1996                  nfs4_end_open_seqid_sync(oop);
1997 1997                  open_owner_rele(oop);
1998 1998                  oop = NULL;
1999 1999                  ep->error = nfs4_wait_for_delay(vp, &recov);
2000 2000                  nfs4_mi_kstat_inc_delay(mi);
2001 2001                  if (ep->error != 0)
2002 2002                          goto bailout;
2003 2003                  goto top;
2004 2004          case NFS4ERR_FHEXPIRED:
2005 2005                  /* recover filehandle and retry */
2006 2006                  abort = nfs4_start_recovery(ep,
2007 2007                      mi, vp, NULL, NULL, NULL, OP_OPEN, NULL, NULL, NULL);
2008 2008                  nfs4args_copen_free(open_args);
2009 2009                  (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
2010 2010                  nfs4_end_open_seqid_sync(oop);
2011 2011                  open_owner_rele(oop);
2012 2012                  oop = NULL;
2013 2013                  if (abort == FALSE)
2014 2014                          goto top;
2015 2015                  failed_msg = "Couldn't reopen: recovery aborted";
2016 2016                  goto kill_file;
2017 2017          case NFS4ERR_RESOURCE:
2018 2018          case NFS4ERR_STALE_CLIENTID:
2019 2019          case NFS4ERR_WRONGSEC:
2020 2020          case NFS4ERR_EXPIRED:
2021 2021                  /*
2022 2022                   * Do not mark the file dead and let the calling
2023 2023                   * function initiate recovery.
2024 2024                   */
2025 2025                  nfs4args_copen_free(open_args);
2026 2026                  (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
2027 2027                  nfs4_end_open_seqid_sync(oop);
2028 2028                  open_owner_rele(oop);
2029 2029                  oop = NULL;
2030 2030                  goto bailout;
2031 2031          case NFS4ERR_ACCESS:
2032 2032                  if (cred_otw != cr) {
2033 2033                          crfree(cred_otw);
2034 2034                          cred_otw = cr;
2035 2035                          crhold(cred_otw);
2036 2036                          nfs4args_copen_free(open_args);
2037 2037                          (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
2038 2038                          nfs4_end_open_seqid_sync(oop);
2039 2039                          open_owner_rele(oop);
2040 2040                          oop = NULL;
2041 2041                          goto top;
2042 2042                  }
2043 2043                  /* fall through */
2044 2044          default:
2045 2045                  NFS4_DEBUG(nfs4_client_failover_debug, (CE_NOTE,
2046 2046                      "nfs4_reopen: r_server 0x%p, mi_curr_serv 0x%p, rnode %s",
2047 2047                      (void*)VTOR4(vp)->r_server, (void*)mi->mi_curr_serv,
2048 2048                      rnode4info(VTOR4(vp))));
2049 2049                  failed_msg = "Couldn't reopen: NFSv4 error";
2050 2050                  nfs4args_copen_free(open_args);
2051 2051                  (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
2052 2052                  goto kill_file;
2053 2053          }
2054 2054  
2055 2055          resop = &res.array[1];  /* open res */
2056 2056          op_res = &resop->nfs_resop4_u.opopen;
2057 2057  
2058 2058          garp = &res.array[3].nfs_resop4_u.opgetattr.ga_res;
2059 2059  
2060 2060          /*
2061 2061           * Check if the path we reopened really is the same
2062 2062           * file. We could end up in a situation where the file
2063 2063           * was removed and a new file created with the same name.
2064 2064           */
2065 2065          resop = &res.array[2];
2066 2066          gf_res = &resop->nfs_resop4_u.opgetfh;
2067 2067          (void) nfs_rw_enter_sig(&mi->mi_fh_lock, RW_READER, 0);
2068 2068          fh_different = (nfs4cmpfh(&rp->r_fh->sfh_fh, &gf_res->object) != 0);
2069 2069          if (fh_different) {
2070 2070                  if (mi->mi_fh_expire_type == FH4_PERSISTENT ||
2071 2071                      mi->mi_fh_expire_type & FH4_NOEXPIRE_WITH_OPEN) {
2072 2072                          /* Oops, we don't have the same file */
2073 2073                          if (mi->mi_fh_expire_type == FH4_PERSISTENT)
2074 2074                                  failed_msg = "Couldn't reopen: Persistent "
2075 2075                                      "file handle changed";
2076 2076                          else
2077 2077                                  failed_msg = "Couldn't reopen: Volatile "
2078 2078                                      "(no expire on open) file handle changed";
2079 2079  
2080 2080                          nfs4args_copen_free(open_args);
2081 2081                          (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
2082 2082                          nfs_rw_exit(&mi->mi_fh_lock);
2083 2083                          goto kill_file;
2084 2084  
2085 2085                  } else {
2086 2086                          /*
2087 2087                           * We have volatile file handles that don't compare.
2088 2088                           * If the fids are the same then we assume that the
2089 2089                           * file handle expired but the rnode still refers to
2090 2090                           * the same file object.
2091 2091                           *
2092 2092                           * First check that we have fids or not.
2093 2093                           * If we don't we have a dumb server so we will
2094 2094                           * just assume every thing is ok for now.
2095 2095                           */
2096 2096                          if (!ep->error && garp->n4g_va.va_mask & AT_NODEID &&
2097 2097                              rp->r_attr.va_mask & AT_NODEID &&
2098 2098                              rp->r_attr.va_nodeid != garp->n4g_va.va_nodeid) {
2099 2099                                  /*
2100 2100                                   * We have fids, but they don't
2101 2101                                   * compare. So kill the file.
2102 2102                                   */
2103 2103                                  failed_msg =
2104 2104                                      "Couldn't reopen: file handle changed"
2105 2105                                      " due to mismatched fids";
2106 2106                                  nfs4args_copen_free(open_args);
2107 2107                                  (void) xdr_free(xdr_COMPOUND4res_clnt,
2108 2108                                      (caddr_t)&res);
2109 2109                                  nfs_rw_exit(&mi->mi_fh_lock);
2110 2110                                  goto kill_file;
2111 2111                          } else {
2112 2112                                  /*
2113 2113                                   * We have volatile file handles that refers
2114 2114                                   * to the same file (at least they have the
2115 2115                                   * same fid) or we don't have fids so we
2116 2116                                   * can't tell. :(. We'll be a kind and accepting
2117 2117                                   * client so we'll update the rnode's file
2118 2118                                   * handle with the otw handle.
2119 2119                                   *
2120 2120                                   * We need to drop mi->mi_fh_lock since
2121 2121                                   * sh4_update acquires it. Since there is
2122 2122                                   * only one recovery thread there is no
2123 2123                                   * race.
2124 2124                                   */
2125 2125                                  nfs_rw_exit(&mi->mi_fh_lock);
2126 2126                                  sfh4_update(rp->r_fh, &gf_res->object);
2127 2127                          }
2128 2128                  }
2129 2129          } else {
2130 2130                  nfs_rw_exit(&mi->mi_fh_lock);
2131 2131          }
2132 2132  
2133 2133          ASSERT(nfs4_consistent_type(vp));
2134 2134  
2135 2135          /*
2136 2136           * If the server wanted an OPEN_CONFIRM but that fails, just start
2137 2137           * over.  Presumably if there is a persistent error it will show up
2138 2138           * when we resend the OPEN.
2139 2139           */
2140 2140          if (op_res->rflags & OPEN4_RESULT_CONFIRM) {
2141 2141                  bool_t retry_open = FALSE;
2142 2142  
2143 2143                  nfs4open_confirm(vp, &seqid, &op_res->stateid,
2144 2144                      cred_otw, is_recov, &retry_open,
2145 2145                      oop, FALSE, ep, NULL);
2146 2146                  if (ep->error || ep->stat) {
2147 2147                          nfs4args_copen_free(open_args);
2148 2148                          (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
2149 2149                          nfs4_end_open_seqid_sync(oop);
2150 2150                          open_owner_rele(oop);
2151 2151                          oop = NULL;
2152 2152                          goto top;
2153 2153                  }
2154 2154          }
2155 2155  
2156 2156          mutex_enter(&osp->os_sync_lock);
2157 2157          osp->open_stateid = op_res->stateid;
2158 2158          osp->os_delegation = 0;
2159 2159          /*
2160 2160           * Need to reset this bitfield for the possible case where we were
2161 2161           * going to OTW CLOSE the file, got a non-recoverable error, and before
2162 2162           * we could retry the CLOSE, OPENed the file again.
2163 2163           */
2164 2164          ASSERT(osp->os_open_owner->oo_seqid_inuse);
2165 2165          osp->os_final_close = 0;
2166 2166          osp->os_force_close = 0;
2167 2167          if (claim == CLAIM_DELEGATE_CUR || claim == CLAIM_PREVIOUS)
2168 2168                  osp->os_dc_openacc = open_args->share_access;
2169 2169          mutex_exit(&osp->os_sync_lock);
2170 2170  
2171 2171          nfs4_end_open_seqid_sync(oop);
2172 2172  
2173 2173          /* accept delegation, if any */
2174 2174          nfs4_delegation_accept(rp, claim, op_res, garp, cred_otw);
2175 2175  
2176 2176          nfs4args_copen_free(open_args);
2177 2177  
2178 2178          nfs4_attr_cache(vp, garp, t, cr, TRUE, NULL);
2179 2179  
2180 2180          (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
2181 2181  
2182 2182          ASSERT(nfs4_consistent_type(vp));
2183 2183  
2184 2184          open_owner_rele(oop);
2185 2185          crfree(cr);
2186 2186          crfree(cred_otw);
2187 2187          return;
2188 2188  
2189 2189  kill_file:
2190 2190          nfs4_fail_recov(vp, failed_msg, ep->error, ep->stat);
2191 2191  failed_reopen:
2192 2192          NFS4_DEBUG(nfs4_open_stream_debug, (CE_NOTE,
2193 2193              "nfs4_reopen: setting os_failed_reopen for osp %p, cr %p, rp %s",
2194 2194              (void *)osp, (void *)cr, rnode4info(rp)));
2195 2195          mutex_enter(&osp->os_sync_lock);
2196 2196          osp->os_failed_reopen = 1;
2197 2197          mutex_exit(&osp->os_sync_lock);
2198 2198  bailout:
2199 2199          if (oop != NULL) {
2200 2200                  nfs4_end_open_seqid_sync(oop);
2201 2201                  open_owner_rele(oop);
2202 2202          }
2203 2203          if (cr != NULL)
2204 2204                  crfree(cr);
2205 2205          if (cred_otw != NULL)
2206 2206                  crfree(cred_otw);
2207 2207  }
2208 2208  
2209 2209  /* for . and .. OPENs */
2210 2210  /* ARGSUSED */
2211 2211  static int
2212 2212  nfs4_open_non_reg_file(vnode_t **vpp, int flag, cred_t *cr)
2213 2213  {
2214 2214          rnode4_t *rp;
2215 2215          nfs4_ga_res_t gar;
2216 2216  
2217 2217          ASSERT(nfs_zone() == VTOMI4(*vpp)->mi_zone);
2218 2218  
2219 2219          /*
2220 2220           * If close-to-open consistency checking is turned off or
2221 2221           * if there is no cached data, we can avoid
2222 2222           * the over the wire getattr.  Otherwise, force a
2223 2223           * call to the server to get fresh attributes and to
2224 2224           * check caches. This is required for close-to-open
2225 2225           * consistency.
2226 2226           */
2227 2227          rp = VTOR4(*vpp);
2228 2228          if (VTOMI4(*vpp)->mi_flags & MI4_NOCTO ||
2229 2229              (rp->r_dir == NULL && !nfs4_has_pages(*vpp)))
2230 2230                  return (0);
2231 2231  
2232 2232          gar.n4g_va.va_mask = AT_ALL;
2233 2233          return (nfs4_getattr_otw(*vpp, &gar, cr, 0));
2234 2234  }
2235 2235  
2236 2236  /*
2237 2237   * CLOSE a file
2238 2238   */
2239 2239  /* ARGSUSED */
2240 2240  static int
2241 2241  nfs4_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
2242 2242      caller_context_t *ct)
2243 2243  {
2244 2244          rnode4_t        *rp;
2245 2245          int              error = 0;
2246 2246          int              r_error = 0;
2247 2247          int              n4error = 0;
2248 2248          nfs4_error_t     e = { 0, NFS4_OK, RPC_SUCCESS };
2249 2249  
2250 2250          /*
2251 2251           * Remove client state for this (lockowner, file) pair.
2252 2252           * Issue otw v4 call to have the server do the same.
2253 2253           */
2254 2254  
2255 2255          rp = VTOR4(vp);
2256 2256  
2257 2257          /*
2258 2258           * zone_enter(2) prevents processes from changing zones with NFS files
2259 2259           * open; if we happen to get here from the wrong zone we can't do
2260 2260           * anything over the wire.
2261 2261           */
2262 2262          if (VTOMI4(vp)->mi_zone != nfs_zone()) {
2263 2263                  /*
2264 2264                   * We could attempt to clean up locks, except we're sure
2265 2265                   * that the current process didn't acquire any locks on
2266 2266                   * the file: any attempt to lock a file belong to another zone
2267 2267                   * will fail, and one can't lock an NFS file and then change
2268 2268                   * zones, as that fails too.
2269 2269                   *
2270 2270                   * Returning an error here is the sane thing to do.  A
2271 2271                   * subsequent call to VN_RELE() which translates to a
2272 2272                   * nfs4_inactive() will clean up state: if the zone of the
2273 2273                   * vnode's origin is still alive and kicking, the inactive
2274 2274                   * thread will handle the request (from the correct zone), and
2275 2275                   * everything (minus the OTW close call) should be OK.  If the
2276 2276                   * zone is going away nfs4_async_inactive() will throw away
2277 2277                   * delegations, open streams and cached pages inline.
2278 2278                   */
2279 2279                  return (EIO);
2280 2280          }
2281 2281  
2282 2282          /*
2283 2283           * If we are using local locking for this filesystem, then
2284 2284           * release all of the SYSV style record locks.  Otherwise,
2285 2285           * we are doing network locking and we need to release all
2286 2286           * of the network locks.  All of the locks held by this
2287 2287           * process on this file are released no matter what the
2288 2288           * incoming reference count is.
2289 2289           */
2290 2290          if (VTOMI4(vp)->mi_flags & MI4_LLOCK) {
2291 2291                  cleanlocks(vp, ttoproc(curthread)->p_pid, 0);
2292 2292                  cleanshares(vp, ttoproc(curthread)->p_pid);
2293 2293          } else
2294 2294                  e.error = nfs4_lockrelease(vp, flag, offset, cr);
2295 2295  
2296 2296          if (e.error) {
2297 2297                  struct lm_sysid *lmsid;
2298 2298                  lmsid = nfs4_find_sysid(VTOMI4(vp));
2299 2299                  if (lmsid == NULL) {
2300 2300                          DTRACE_PROBE2(unknown__sysid, int, e.error,
2301 2301                              vnode_t *, vp);
2302 2302                  } else {
2303 2303                          cleanlocks(vp, ttoproc(curthread)->p_pid,
2304 2304                              (lm_sysidt(lmsid) | LM_SYSID_CLIENT));
2305 2305  
2306 2306                          lm_rel_sysid(lmsid);
2307 2307                  }
2308 2308                  return (e.error);
2309 2309          }
2310 2310  
2311 2311          if (count > 1)
2312 2312                  return (0);
2313 2313  
2314 2314          /*
2315 2315           * If the file has been `unlinked', then purge the
2316 2316           * DNLC so that this vnode will get reycled quicker
2317 2317           * and the .nfs* file on the server will get removed.
2318 2318           */
2319 2319          if (rp->r_unldvp != NULL)
2320 2320                  dnlc_purge_vp(vp);
2321 2321  
2322 2322          /*
2323 2323           * If the file was open for write and there are pages,
2324 2324           * do a synchronous flush and commit of all of the
2325 2325           * dirty and uncommitted pages.
2326 2326           */
2327 2327          ASSERT(!e.error);
2328 2328          if ((flag & FWRITE) && nfs4_has_pages(vp))
2329 2329                  error = nfs4_putpage_commit(vp, 0, 0, cr);
2330 2330  
2331 2331          mutex_enter(&rp->r_statelock);
2332 2332          r_error = rp->r_error;
2333 2333          rp->r_error = 0;
2334 2334          mutex_exit(&rp->r_statelock);
2335 2335  
2336 2336          /*
2337 2337           * If this file type is one for which no explicit 'open' was
2338 2338           * done, then bail now (ie. no need for protocol 'close'). If
2339 2339           * there was an error w/the vm subsystem, return _that_ error,
2340 2340           * otherwise, return any errors that may've been reported via
2341 2341           * the rnode.
2342 2342           */
2343 2343          if (vp->v_type != VREG)
2344 2344                  return (error ? error : r_error);
2345 2345  
2346 2346          /*
2347 2347           * The sync putpage commit may have failed above, but since
2348 2348           * we're working w/a regular file, we need to do the protocol
2349 2349           * 'close' (nfs4close_one will figure out if an otw close is
2350 2350           * needed or not). Report any errors _after_ doing the protocol
2351 2351           * 'close'.
2352 2352           */
2353 2353          nfs4close_one(vp, NULL, cr, flag, NULL, &e, CLOSE_NORM, 0, 0, 0);
2354 2354          n4error = e.error ? e.error : geterrno4(e.stat);
2355 2355  
2356 2356          /*
2357 2357           * Error reporting prio (Hi -> Lo)
2358 2358           *
2359 2359           *   i) nfs4_putpage_commit (error)
2360 2360           *  ii) rnode's (r_error)
2361 2361           * iii) nfs4close_one (n4error)
2362 2362           */
2363 2363          return (error ? error : (r_error ? r_error : n4error));
2364 2364  }
2365 2365  
2366 2366  /*
2367 2367   * Initialize *lost_rqstp.
2368 2368   */
2369 2369  
2370 2370  static void
2371 2371  nfs4close_save_lost_rqst(int error, nfs4_lost_rqst_t *lost_rqstp,
2372 2372      nfs4_open_owner_t *oop, nfs4_open_stream_t *osp, cred_t *cr,
2373 2373      vnode_t *vp)
2374 2374  {
2375 2375          if (error != ETIMEDOUT && error != EINTR &&
2376 2376              !NFS4_FRC_UNMT_ERR(error, vp->v_vfsp)) {
2377 2377                  lost_rqstp->lr_op = 0;
2378 2378                  return;
2379 2379          }
2380 2380  
2381 2381          NFS4_DEBUG(nfs4_lost_rqst_debug, (CE_NOTE,
2382 2382              "nfs4close_save_lost_rqst: error %d", error));
2383 2383  
2384 2384          lost_rqstp->lr_op = OP_CLOSE;
2385 2385          /*
2386 2386           * The vp is held and rele'd via the recovery code.
2387 2387           * See nfs4_save_lost_rqst.
2388 2388           */
2389 2389          lost_rqstp->lr_vp = vp;
2390 2390          lost_rqstp->lr_dvp = NULL;
2391 2391          lost_rqstp->lr_oop = oop;
2392 2392          lost_rqstp->lr_osp = osp;
2393 2393          ASSERT(osp != NULL);
2394 2394          ASSERT(mutex_owned(&osp->os_sync_lock));
2395 2395          osp->os_pending_close = 1;
2396 2396          lost_rqstp->lr_lop = NULL;
2397 2397          lost_rqstp->lr_cr = cr;
2398 2398          lost_rqstp->lr_flk = NULL;
2399 2399          lost_rqstp->lr_putfirst = FALSE;
2400 2400  }
2401 2401  
2402 2402  /*
2403 2403   * Assumes you already have the open seqid sync grabbed as well as the
2404 2404   * 'os_sync_lock'.  Note: this will release the open seqid sync and
2405 2405   * 'os_sync_lock' if client recovery starts.  Calling functions have to
2406 2406   * be prepared to handle this.
2407 2407   *
2408 2408   * 'recov' is returned as 1 if the CLOSE operation detected client recovery
2409 2409   * was needed and was started, and that the calling function should retry
2410 2410   * this function; otherwise it is returned as 0.
2411 2411   *
2412 2412   * Errors are returned via the nfs4_error_t parameter.
2413 2413   */
2414 2414  static void
2415 2415  nfs4close_otw(rnode4_t *rp, cred_t *cred_otw, nfs4_open_owner_t *oop,
2416 2416      nfs4_open_stream_t *osp, int *recov, int *did_start_seqid_syncp,
2417 2417      nfs4_close_type_t close_type, nfs4_error_t *ep, int *have_sync_lockp)
2418 2418  {
2419 2419          COMPOUND4args_clnt args;
2420 2420          COMPOUND4res_clnt res;
2421 2421          CLOSE4args *close_args;
2422 2422          nfs_resop4 *resop;
2423 2423          nfs_argop4 argop[3];
2424 2424          int doqueue = 1;
2425 2425          mntinfo4_t *mi;
2426 2426          seqid4 seqid;
2427 2427          vnode_t *vp;
2428 2428          bool_t needrecov = FALSE;
2429 2429          nfs4_lost_rqst_t lost_rqst;
2430 2430          hrtime_t t;
2431 2431  
2432 2432          ASSERT(nfs_zone() == VTOMI4(RTOV4(rp))->mi_zone);
2433 2433  
2434 2434          ASSERT(MUTEX_HELD(&osp->os_sync_lock));
2435 2435  
2436 2436          NFS4_DEBUG(nfs4_client_state_debug, (CE_NOTE, "nfs4close_otw"));
2437 2437  
2438 2438          /* Only set this to 1 if recovery is started */
2439 2439          *recov = 0;
2440 2440  
2441 2441          /* do the OTW call to close the file */
2442 2442  
2443 2443          if (close_type == CLOSE_RESEND)
2444 2444                  args.ctag = TAG_CLOSE_LOST;
2445 2445          else if (close_type == CLOSE_AFTER_RESEND)
2446 2446                  args.ctag = TAG_CLOSE_UNDO;
2447 2447          else
2448 2448                  args.ctag = TAG_CLOSE;
2449 2449  
2450 2450          args.array_len = 3;
2451 2451          args.array = argop;
2452 2452  
2453 2453          vp = RTOV4(rp);
2454 2454  
2455 2455          mi = VTOMI4(vp);
2456 2456  
2457 2457          /* putfh target fh */
2458 2458          argop[0].argop = OP_CPUTFH;
2459 2459          argop[0].nfs_argop4_u.opcputfh.sfh = rp->r_fh;
2460 2460  
2461 2461          argop[1].argop = OP_GETATTR;
2462 2462          argop[1].nfs_argop4_u.opgetattr.attr_request = NFS4_VATTR_MASK;
2463 2463          argop[1].nfs_argop4_u.opgetattr.mi = mi;
2464 2464  
2465 2465          argop[2].argop = OP_CLOSE;
2466 2466          close_args = &argop[2].nfs_argop4_u.opclose;
2467 2467  
2468 2468          seqid = nfs4_get_open_seqid(oop) + 1;
2469 2469  
2470 2470          close_args->seqid = seqid;
2471 2471          close_args->open_stateid = osp->open_stateid;
2472 2472  
2473 2473          NFS4_DEBUG(nfs4_client_call_debug, (CE_NOTE,
2474 2474              "nfs4close_otw: %s call, rp %s", needrecov ? "recov" : "first",
2475 2475              rnode4info(rp)));
2476 2476  
2477 2477          t = gethrtime();
2478 2478  
2479 2479          rfs4call(mi, &args, &res, cred_otw, &doqueue, 0, ep);
2480 2480  
2481 2481          if (!ep->error && nfs4_need_to_bump_seqid(&res)) {
2482 2482                  nfs4_set_open_seqid(seqid, oop, args.ctag);
2483 2483          }
2484 2484  
2485 2485          needrecov = nfs4_needs_recovery(ep, TRUE, mi->mi_vfsp);
2486 2486          if (ep->error && !needrecov) {
2487 2487                  /*
2488 2488                   * if there was an error and no recovery is to be done
2489 2489                   * then then set up the file to flush its cache if
2490 2490                   * needed for the next caller.
2491 2491                   */
2492 2492                  mutex_enter(&rp->r_statelock);
2493 2493                  PURGE_ATTRCACHE4_LOCKED(rp);
2494 2494                  rp->r_flags &= ~R4WRITEMODIFIED;
2495 2495                  mutex_exit(&rp->r_statelock);
2496 2496                  return;
2497 2497          }
2498 2498  
2499 2499          if (needrecov) {
2500 2500                  bool_t abort;
2501 2501                  nfs4_bseqid_entry_t *bsep = NULL;
2502 2502  
2503 2503                  if (close_type != CLOSE_RESEND)
2504 2504                          nfs4close_save_lost_rqst(ep->error, &lost_rqst, oop,
2505 2505                              osp, cred_otw, vp);
2506 2506  
2507 2507                  if (!ep->error && res.status == NFS4ERR_BAD_SEQID)
2508 2508                          bsep = nfs4_create_bseqid_entry(oop, NULL, vp,
2509 2509                              0, args.ctag, close_args->seqid);
2510 2510  
2511 2511                  NFS4_DEBUG(nfs4_client_recov_debug, (CE_NOTE,
2512 2512                      "nfs4close_otw: initiating recovery. error %d "
2513 2513                      "res.status %d", ep->error, res.status));
2514 2514  
2515 2515                  /*
2516 2516                   * Drop the 'os_sync_lock' here so we don't hit
2517 2517                   * a potential recursive mutex_enter via an
2518 2518                   * 'open_stream_hold()'.
2519 2519                   */
2520 2520                  mutex_exit(&osp->os_sync_lock);
2521 2521                  *have_sync_lockp = 0;
2522 2522                  abort = nfs4_start_recovery(ep, VTOMI4(vp), vp, NULL, NULL,
2523 2523                      (close_type != CLOSE_RESEND &&
2524 2524                      lost_rqst.lr_op == OP_CLOSE) ? &lost_rqst : NULL,
2525 2525                      OP_CLOSE, bsep, NULL, NULL);
2526 2526  
2527 2527                  /* drop open seq sync, and let the calling function regrab it */
2528 2528                  nfs4_end_open_seqid_sync(oop);
2529 2529                  *did_start_seqid_syncp = 0;
2530 2530  
2531 2531                  if (bsep)
2532 2532                          kmem_free(bsep, sizeof (*bsep));
2533 2533                  /*
2534 2534                   * For signals, the caller wants to quit, so don't say to
2535 2535                   * retry.  For forced unmount, if it's a user thread, it
2536 2536                   * wants to quit.  If it's a recovery thread, the retry
2537 2537                   * will happen higher-up on the call stack.  Either way,
2538 2538                   * don't say to retry.
2539 2539                   */
2540 2540                  if (abort == FALSE && ep->error != EINTR &&
2541 2541                      !NFS4_FRC_UNMT_ERR(ep->error, mi->mi_vfsp) &&
2542 2542                      close_type != CLOSE_RESEND &&
2543 2543                      close_type != CLOSE_AFTER_RESEND)
2544 2544                          *recov = 1;
2545 2545                  else
2546 2546                          *recov = 0;
2547 2547  
2548 2548                  if (!ep->error)
2549 2549                          (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
2550 2550                  return;
2551 2551          }
2552 2552  
2553 2553          if (res.status) {
2554 2554                  (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
2555 2555                  return;
2556 2556          }
2557 2557  
2558 2558          mutex_enter(&rp->r_statev4_lock);
2559 2559          rp->created_v4 = 0;
2560 2560          mutex_exit(&rp->r_statev4_lock);
2561 2561  
2562 2562          resop = &res.array[2];
2563 2563          osp->open_stateid = resop->nfs_resop4_u.opclose.open_stateid;
2564 2564          osp->os_valid = 0;
2565 2565  
2566 2566          /*
2567 2567           * This removes the reference obtained at OPEN; ie, when the
2568 2568           * open stream structure was created.
2569 2569           *
2570 2570           * We don't have to worry about calling 'open_stream_rele'
2571 2571           * since we our currently holding a reference to the open
2572 2572           * stream which means the count cannot go to 0 with this
2573 2573           * decrement.
2574 2574           */
2575 2575          ASSERT(osp->os_ref_count >= 2);
2576 2576          osp->os_ref_count--;
2577 2577  
2578 2578          if (!ep->error)
2579 2579                  nfs4_attr_cache(vp,
2580 2580                      &res.array[1].nfs_resop4_u.opgetattr.ga_res,
2581 2581                      t, cred_otw, TRUE, NULL);
2582 2582  
2583 2583          NFS4_DEBUG(nfs4_client_state_debug, (CE_NOTE, "nfs4close_otw:"
2584 2584              " returning %d", ep->error));
2585 2585  
2586 2586          (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
2587 2587  }
2588 2588  
2589 2589  /* ARGSUSED */
2590 2590  static int
2591 2591  nfs4_read(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
2592 2592      caller_context_t *ct)
2593 2593  {
2594 2594          rnode4_t *rp;
2595 2595          u_offset_t off;
2596 2596          offset_t diff;
2597 2597          uint_t on;
2598 2598          uint_t n;
2599 2599          caddr_t base;
2600 2600          uint_t flags;
2601 2601          int error;
2602 2602          mntinfo4_t *mi;
2603 2603  
2604 2604          rp = VTOR4(vp);
2605 2605  
2606 2606          ASSERT(nfs_rw_lock_held(&rp->r_rwlock, RW_READER));
2607 2607  
2608 2608          if (IS_SHADOW(vp, rp))
2609 2609                  vp = RTOV4(rp);
2610 2610  
2611 2611          if (vp->v_type != VREG)
2612 2612                  return (EISDIR);
2613 2613  
2614 2614          mi = VTOMI4(vp);
2615 2615  
2616 2616          if (nfs_zone() != mi->mi_zone)
2617 2617                  return (EIO);
2618 2618  
2619 2619          if (uiop->uio_resid == 0)
2620 2620                  return (0);
2621 2621  
2622 2622          if (uiop->uio_loffset < 0 || uiop->uio_loffset + uiop->uio_resid < 0)
2623 2623                  return (EINVAL);
2624 2624  
2625 2625          mutex_enter(&rp->r_statelock);
2626 2626          if (rp->r_flags & R4RECOVERRP)
2627 2627                  error = (rp->r_error ? rp->r_error : EIO);
2628 2628          else
2629 2629                  error = 0;
2630 2630          mutex_exit(&rp->r_statelock);
2631 2631          if (error)
2632 2632                  return (error);
2633 2633  
2634 2634          /*
2635 2635           * Bypass VM if caching has been disabled (e.g., locking) or if
2636 2636           * using client-side direct I/O and the file is not mmap'd and
2637 2637           * there are no cached pages.
2638 2638           */
2639 2639          if ((vp->v_flag & VNOCACHE) ||
2640 2640              (((rp->r_flags & R4DIRECTIO) || (mi->mi_flags & MI4_DIRECTIO)) &&
2641 2641              rp->r_mapcnt == 0 && rp->r_inmap == 0 && !nfs4_has_pages(vp))) {
2642 2642                  size_t resid = 0;
2643 2643  
2644 2644                  return (nfs4read(vp, NULL, uiop->uio_loffset,
2645 2645                      uiop->uio_resid, &resid, cr, FALSE, uiop));
2646 2646          }
2647 2647  
2648 2648          error = 0;
2649 2649  
2650 2650          do {
2651 2651                  off = uiop->uio_loffset & MAXBMASK; /* mapping offset */
2652 2652                  on = uiop->uio_loffset & MAXBOFFSET; /* Relative offset */
2653 2653                  n = MIN(MAXBSIZE - on, uiop->uio_resid);
2654 2654  
2655 2655                  if (error = nfs4_validate_caches(vp, cr))
2656 2656                          break;
2657 2657  
2658 2658                  mutex_enter(&rp->r_statelock);
2659 2659                  while (rp->r_flags & R4INCACHEPURGE) {
2660 2660                          if (!cv_wait_sig(&rp->r_cv, &rp->r_statelock)) {
2661 2661                                  mutex_exit(&rp->r_statelock);
2662 2662                                  return (EINTR);
2663 2663                          }
2664 2664                  }
2665 2665                  diff = rp->r_size - uiop->uio_loffset;
2666 2666                  mutex_exit(&rp->r_statelock);
2667 2667                  if (diff <= 0)
2668 2668                          break;
2669 2669                  if (diff < n)
2670 2670                          n = (uint_t)diff;
2671 2671  
2672 2672                  if (vpm_enable) {
2673 2673                          /*
2674 2674                           * Copy data.
2675 2675                           */
2676 2676                          error = vpm_data_copy(vp, off + on, n, uiop,
2677 2677                              1, NULL, 0, S_READ);
2678 2678                  } else {
2679 2679                          base = segmap_getmapflt(segkmap, vp, off + on, n, 1,
2680 2680                              S_READ);
2681 2681  
2682 2682                          error = uiomove(base + on, n, UIO_READ, uiop);
2683 2683                  }
2684 2684  
2685 2685                  if (!error) {
2686 2686                          /*
2687 2687                           * If read a whole block or read to eof,
2688 2688                           * won't need this buffer again soon.
2689 2689                           */
2690 2690                          mutex_enter(&rp->r_statelock);
2691 2691                          if (n + on == MAXBSIZE ||
2692 2692                              uiop->uio_loffset == rp->r_size)
2693 2693                                  flags = SM_DONTNEED;
2694 2694                          else
2695 2695                                  flags = 0;
2696 2696                          mutex_exit(&rp->r_statelock);
2697 2697                          if (vpm_enable) {
2698 2698                                  error = vpm_sync_pages(vp, off, n, flags);
2699 2699                          } else {
2700 2700                                  error = segmap_release(segkmap, base, flags);
2701 2701                          }
2702 2702                  } else {
2703 2703                          if (vpm_enable) {
2704 2704                                  (void) vpm_sync_pages(vp, off, n, 0);
2705 2705                          } else {
2706 2706                                  (void) segmap_release(segkmap, base, 0);
2707 2707                          }
2708 2708                  }
2709 2709          } while (!error && uiop->uio_resid > 0);
2710 2710  
2711 2711          return (error);
2712 2712  }
2713 2713  
2714 2714  /* ARGSUSED */
2715 2715  static int
2716 2716  nfs4_write(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
2717 2717      caller_context_t *ct)
2718 2718  {
2719 2719          rlim64_t limit = uiop->uio_llimit;
2720 2720          rnode4_t *rp;
2721 2721          u_offset_t off;
2722 2722          caddr_t base;
2723 2723          uint_t flags;
2724 2724          int remainder;
2725 2725          size_t n;
2726 2726          int on;
2727 2727          int error;
2728 2728          int resid;
2729 2729          u_offset_t offset;
2730 2730          mntinfo4_t *mi;
2731 2731          uint_t bsize;
2732 2732  
2733 2733          rp = VTOR4(vp);
2734 2734  
2735 2735          if (IS_SHADOW(vp, rp))
2736 2736                  vp = RTOV4(rp);
2737 2737  
2738 2738          if (vp->v_type != VREG)
2739 2739                  return (EISDIR);
2740 2740  
2741 2741          mi = VTOMI4(vp);
2742 2742  
2743 2743          if (nfs_zone() != mi->mi_zone)
2744 2744                  return (EIO);
2745 2745  
2746 2746          if (uiop->uio_resid == 0)
2747 2747                  return (0);
2748 2748  
2749 2749          mutex_enter(&rp->r_statelock);
2750 2750          if (rp->r_flags & R4RECOVERRP)
2751 2751                  error = (rp->r_error ? rp->r_error : EIO);
2752 2752          else
2753 2753                  error = 0;
2754 2754          mutex_exit(&rp->r_statelock);
2755 2755          if (error)
2756 2756                  return (error);
2757 2757  
2758 2758          if (ioflag & FAPPEND) {
2759 2759                  struct vattr va;
2760 2760  
2761 2761                  /*
2762 2762                   * Must serialize if appending.
2763 2763                   */
2764 2764                  if (nfs_rw_lock_held(&rp->r_rwlock, RW_READER)) {
2765 2765                          nfs_rw_exit(&rp->r_rwlock);
2766 2766                          if (nfs_rw_enter_sig(&rp->r_rwlock, RW_WRITER,
2767 2767                              INTR4(vp)))
2768 2768                                  return (EINTR);
2769 2769                  }
2770 2770  
2771 2771                  va.va_mask = AT_SIZE;
2772 2772                  error = nfs4getattr(vp, &va, cr);
2773 2773                  if (error)
2774 2774                          return (error);
2775 2775                  uiop->uio_loffset = va.va_size;
2776 2776          }
2777 2777  
2778 2778          offset = uiop->uio_loffset + uiop->uio_resid;
2779 2779  
2780 2780          if (uiop->uio_loffset < (offset_t)0 || offset < 0)
2781 2781                  return (EINVAL);
2782 2782  
2783 2783          if (limit == RLIM64_INFINITY || limit > MAXOFFSET_T)
2784 2784                  limit = MAXOFFSET_T;
2785 2785  
2786 2786          /*
2787 2787           * Check to make sure that the process will not exceed
2788 2788           * its limit on file size.  It is okay to write up to
2789 2789           * the limit, but not beyond.  Thus, the write which
2790 2790           * reaches the limit will be short and the next write
2791 2791           * will return an error.
2792 2792           */
2793 2793          remainder = 0;
2794 2794          if (offset > uiop->uio_llimit) {
2795 2795                  remainder = offset - uiop->uio_llimit;
2796 2796                  uiop->uio_resid = uiop->uio_llimit - uiop->uio_loffset;
2797 2797                  if (uiop->uio_resid <= 0) {
2798 2798                          proc_t *p = ttoproc(curthread);
2799 2799  
2800 2800                          uiop->uio_resid += remainder;
2801 2801                          mutex_enter(&p->p_lock);
2802 2802                          (void) rctl_action(rctlproc_legacy[RLIMIT_FSIZE],
2803 2803                              p->p_rctls, p, RCA_UNSAFE_SIGINFO);
2804 2804                          mutex_exit(&p->p_lock);
2805 2805                          return (EFBIG);
2806 2806                  }
2807 2807          }
2808 2808  
2809 2809          /* update the change attribute, if we have a write delegation */
2810 2810  
2811 2811          mutex_enter(&rp->r_statev4_lock);
2812 2812          if (rp->r_deleg_type == OPEN_DELEGATE_WRITE)
2813 2813                  rp->r_deleg_change++;
2814 2814  
2815 2815          mutex_exit(&rp->r_statev4_lock);
2816 2816  
2817 2817          if (nfs_rw_enter_sig(&rp->r_lkserlock, RW_READER, INTR4(vp)))
2818 2818                  return (EINTR);
2819 2819  
2820 2820          /*
2821 2821           * Bypass VM if caching has been disabled (e.g., locking) or if
2822 2822           * using client-side direct I/O and the file is not mmap'd and
2823 2823           * there are no cached pages.
2824 2824           */
2825 2825          if ((vp->v_flag & VNOCACHE) ||
2826 2826              (((rp->r_flags & R4DIRECTIO) || (mi->mi_flags & MI4_DIRECTIO)) &&
2827 2827              rp->r_mapcnt == 0 && rp->r_inmap == 0 && !nfs4_has_pages(vp))) {
2828 2828                  size_t bufsize;
2829 2829                  int count;
2830 2830                  u_offset_t org_offset;
2831 2831                  stable_how4 stab_comm;
2832 2832  nfs4_fwrite:
2833 2833                  if (rp->r_flags & R4STALE) {
2834 2834                          resid = uiop->uio_resid;
2835 2835                          offset = uiop->uio_loffset;
2836 2836                          error = rp->r_error;
2837 2837                          /*
2838 2838                           * A close may have cleared r_error, if so,
2839 2839                           * propagate ESTALE error return properly
2840 2840                           */
2841 2841                          if (error == 0)
2842 2842                                  error = ESTALE;
2843 2843                          goto bottom;
2844 2844                  }
2845 2845  
2846 2846                  bufsize = MIN(uiop->uio_resid, mi->mi_stsize);
2847 2847                  base = kmem_alloc(bufsize, KM_SLEEP);
2848 2848                  do {
2849 2849                          if (ioflag & FDSYNC)
2850 2850                                  stab_comm = DATA_SYNC4;
2851 2851                          else
2852 2852                                  stab_comm = FILE_SYNC4;
2853 2853                          resid = uiop->uio_resid;
2854 2854                          offset = uiop->uio_loffset;
2855 2855                          count = MIN(uiop->uio_resid, bufsize);
2856 2856                          org_offset = uiop->uio_loffset;
2857 2857                          error = uiomove(base, count, UIO_WRITE, uiop);
2858 2858                          if (!error) {
2859 2859                                  error = nfs4write(vp, base, org_offset,
2860 2860                                      count, cr, &stab_comm);
2861 2861                                  if (!error) {
2862 2862                                          mutex_enter(&rp->r_statelock);
2863 2863                                          if (rp->r_size < uiop->uio_loffset)
2864 2864                                                  rp->r_size = uiop->uio_loffset;
2865 2865                                          mutex_exit(&rp->r_statelock);
2866 2866                                  }
2867 2867                          }
2868 2868                  } while (!error && uiop->uio_resid > 0);
2869 2869                  kmem_free(base, bufsize);
2870 2870                  goto bottom;
2871 2871          }
2872 2872  
2873 2873          bsize = vp->v_vfsp->vfs_bsize;
2874 2874  
2875 2875          do {
2876 2876                  off = uiop->uio_loffset & MAXBMASK; /* mapping offset */
2877 2877                  on = uiop->uio_loffset & MAXBOFFSET; /* Relative offset */
2878 2878                  n = MIN(MAXBSIZE - on, uiop->uio_resid);
2879 2879  
2880 2880                  resid = uiop->uio_resid;
2881 2881                  offset = uiop->uio_loffset;
2882 2882  
2883 2883                  if (rp->r_flags & R4STALE) {
2884 2884                          error = rp->r_error;
2885 2885                          /*
2886 2886                           * A close may have cleared r_error, if so,
2887 2887                           * propagate ESTALE error return properly
2888 2888                           */
2889 2889                          if (error == 0)
2890 2890                                  error = ESTALE;
2891 2891                          break;
2892 2892                  }
2893 2893  
2894 2894                  /*
2895 2895                   * Don't create dirty pages faster than they
2896 2896                   * can be cleaned so that the system doesn't
2897 2897                   * get imbalanced.  If the async queue is
2898 2898                   * maxed out, then wait for it to drain before
2899 2899                   * creating more dirty pages.  Also, wait for
2900 2900                   * any threads doing pagewalks in the vop_getattr
2901 2901                   * entry points so that they don't block for
2902 2902                   * long periods.
2903 2903                   */
2904 2904                  mutex_enter(&rp->r_statelock);
2905 2905                  while ((mi->mi_max_threads != 0 &&
2906 2906                      rp->r_awcount > 2 * mi->mi_max_threads) ||
2907 2907                      rp->r_gcount > 0) {
2908 2908                          if (INTR4(vp)) {
2909 2909                                  klwp_t *lwp = ttolwp(curthread);
2910 2910  
2911 2911                                  if (lwp != NULL)
2912 2912                                          lwp->lwp_nostop++;
2913 2913                                  if (!cv_wait_sig(&rp->r_cv, &rp->r_statelock)) {
2914 2914                                          mutex_exit(&rp->r_statelock);
2915 2915                                          if (lwp != NULL)
2916 2916                                                  lwp->lwp_nostop--;
2917 2917                                          error = EINTR;
2918 2918                                          goto bottom;
2919 2919                                  }
2920 2920                                  if (lwp != NULL)
2921 2921                                          lwp->lwp_nostop--;
2922 2922                          } else
2923 2923                                  cv_wait(&rp->r_cv, &rp->r_statelock);
2924 2924                  }
2925 2925                  mutex_exit(&rp->r_statelock);
2926 2926  
2927 2927                  /*
2928 2928                   * Touch the page and fault it in if it is not in core
2929 2929                   * before segmap_getmapflt or vpm_data_copy can lock it.
2930 2930                   * This is to avoid the deadlock if the buffer is mapped
2931 2931                   * to the same file through mmap which we want to write.
2932 2932                   */
2933 2933                  uio_prefaultpages((long)n, uiop);
2934 2934  
2935 2935                  if (vpm_enable) {
2936 2936                          /*
2937 2937                           * It will use kpm mappings, so no need to
2938 2938                           * pass an address.
2939 2939                           */
2940 2940                          error = writerp4(rp, NULL, n, uiop, 0);
2941 2941                  } else  {
2942 2942                          if (segmap_kpm) {
2943 2943                                  int pon = uiop->uio_loffset & PAGEOFFSET;
2944 2944                                  size_t pn = MIN(PAGESIZE - pon,
2945 2945                                      uiop->uio_resid);
2946 2946                                  int pagecreate;
2947 2947  
2948 2948                                  mutex_enter(&rp->r_statelock);
2949 2949                                  pagecreate = (pon == 0) && (pn == PAGESIZE ||
2950 2950                                      uiop->uio_loffset + pn >= rp->r_size);
2951 2951                                  mutex_exit(&rp->r_statelock);
2952 2952  
2953 2953                                  base = segmap_getmapflt(segkmap, vp, off + on,
2954 2954                                      pn, !pagecreate, S_WRITE);
2955 2955  
2956 2956                                  error = writerp4(rp, base + pon, n, uiop,
2957 2957                                      pagecreate);
2958 2958  
2959 2959                          } else {
2960 2960                                  base = segmap_getmapflt(segkmap, vp, off + on,
2961 2961                                      n, 0, S_READ);
2962 2962                                  error = writerp4(rp, base + on, n, uiop, 0);
2963 2963                          }
2964 2964                  }
2965 2965  
2966 2966                  if (!error) {
2967 2967                          if (mi->mi_flags & MI4_NOAC)
2968 2968                                  flags = SM_WRITE;
2969 2969                          else if ((uiop->uio_loffset % bsize) == 0 ||
2970 2970                              IS_SWAPVP(vp)) {
2971 2971                                  /*
2972 2972                                   * Have written a whole block.
2973 2973                                   * Start an asynchronous write
2974 2974                                   * and mark the buffer to
2975 2975                                   * indicate that it won't be
2976 2976                                   * needed again soon.
2977 2977                                   */
2978 2978                                  flags = SM_WRITE | SM_ASYNC | SM_DONTNEED;
2979 2979                          } else
2980 2980                                  flags = 0;
2981 2981                          if ((ioflag & (FSYNC|FDSYNC)) ||
2982 2982                              (rp->r_flags & R4OUTOFSPACE)) {
2983 2983                                  flags &= ~SM_ASYNC;
2984 2984                                  flags |= SM_WRITE;
2985 2985                          }
2986 2986                          if (vpm_enable) {
2987 2987                                  error = vpm_sync_pages(vp, off, n, flags);
2988 2988                          } else {
2989 2989                                  error = segmap_release(segkmap, base, flags);
2990 2990                          }
2991 2991                  } else {
2992 2992                          if (vpm_enable) {
2993 2993                                  (void) vpm_sync_pages(vp, off, n, 0);
2994 2994                          } else {
2995 2995                                  (void) segmap_release(segkmap, base, 0);
2996 2996                          }
2997 2997                          /*
2998 2998                           * In the event that we got an access error while
2999 2999                           * faulting in a page for a write-only file just
3000 3000                           * force a write.
3001 3001                           */
3002 3002                          if (error == EACCES)
3003 3003                                  goto nfs4_fwrite;
3004 3004                  }
3005 3005          } while (!error && uiop->uio_resid > 0);
3006 3006  
3007 3007  bottom:
3008 3008          if (error) {
3009 3009                  uiop->uio_resid = resid + remainder;
3010 3010                  uiop->uio_loffset = offset;
3011 3011          } else {
3012 3012                  uiop->uio_resid += remainder;
3013 3013  
3014 3014                  mutex_enter(&rp->r_statev4_lock);
3015 3015                  if (rp->r_deleg_type == OPEN_DELEGATE_WRITE) {
3016 3016                          gethrestime(&rp->r_attr.va_mtime);
3017 3017                          rp->r_attr.va_ctime = rp->r_attr.va_mtime;
3018 3018                  }
3019 3019                  mutex_exit(&rp->r_statev4_lock);
3020 3020          }
3021 3021  
3022 3022          nfs_rw_exit(&rp->r_lkserlock);
3023 3023  
3024 3024          return (error);
3025 3025  }
3026 3026  
3027 3027  /*
3028 3028   * Flags are composed of {B_ASYNC, B_INVAL, B_FREE, B_DONTNEED}
3029 3029   */
3030 3030  static int
3031 3031  nfs4_rdwrlbn(vnode_t *vp, page_t *pp, u_offset_t off, size_t len,
3032 3032      int flags, cred_t *cr)
3033 3033  {
3034 3034          struct buf *bp;
3035 3035          int error;
3036 3036          page_t *savepp;
3037 3037          uchar_t fsdata;
3038 3038          stable_how4 stab_comm;
3039 3039  
3040 3040          ASSERT(nfs_zone() == VTOMI4(vp)->mi_zone);
3041 3041          bp = pageio_setup(pp, len, vp, flags);
3042 3042          ASSERT(bp != NULL);
3043 3043  
3044 3044          /*
3045 3045           * pageio_setup should have set b_addr to 0.  This
3046 3046           * is correct since we want to do I/O on a page
3047 3047           * boundary.  bp_mapin will use this addr to calculate
3048 3048           * an offset, and then set b_addr to the kernel virtual
3049 3049           * address it allocated for us.
3050 3050           */
3051 3051          ASSERT(bp->b_un.b_addr == 0);
3052 3052  
3053 3053          bp->b_edev = 0;
3054 3054          bp->b_dev = 0;
3055 3055          bp->b_lblkno = lbtodb(off);
3056 3056          bp->b_file = vp;
3057 3057          bp->b_offset = (offset_t)off;
3058 3058          bp_mapin(bp);
3059 3059  
3060 3060          if ((flags & (B_WRITE|B_ASYNC)) == (B_WRITE|B_ASYNC) &&
3061 3061              freemem > desfree)
3062 3062                  stab_comm = UNSTABLE4;
3063 3063          else
3064 3064                  stab_comm = FILE_SYNC4;
3065 3065  
3066 3066          error = nfs4_bio(bp, &stab_comm, cr, FALSE);
3067 3067  
3068 3068          bp_mapout(bp);
3069 3069          pageio_done(bp);
3070 3070  
3071 3071          if (stab_comm == UNSTABLE4)
3072 3072                  fsdata = C_DELAYCOMMIT;
3073 3073          else
3074 3074                  fsdata = C_NOCOMMIT;
3075 3075  
3076 3076          savepp = pp;
3077 3077          do {
3078 3078                  pp->p_fsdata = fsdata;
3079 3079          } while ((pp = pp->p_next) != savepp);
3080 3080  
3081 3081          return (error);
3082 3082  }
3083 3083  
3084 3084  /*
3085 3085   */
3086 3086  static int
3087 3087  nfs4rdwr_check_osid(vnode_t *vp, nfs4_error_t *ep, cred_t *cr)
3088 3088  {
3089 3089          nfs4_open_owner_t       *oop;
3090 3090          nfs4_open_stream_t      *osp;
3091 3091          rnode4_t                *rp = VTOR4(vp);
3092 3092          mntinfo4_t              *mi = VTOMI4(vp);
3093 3093          int                     reopen_needed;
3094 3094  
3095 3095          ASSERT(nfs_zone() == mi->mi_zone);
3096 3096  
3097 3097  
3098 3098          oop = find_open_owner(cr, NFS4_PERM_CREATED, mi);
3099 3099          if (!oop)
3100 3100                  return (EIO);
3101 3101  
3102 3102          /* returns with 'os_sync_lock' held */
3103 3103          osp = find_open_stream(oop, rp);
3104 3104          if (!osp) {
3105 3105                  open_owner_rele(oop);
3106 3106                  return (EIO);
3107 3107          }
3108 3108  
3109 3109          if (osp->os_failed_reopen) {
3110 3110                  mutex_exit(&osp->os_sync_lock);
3111 3111                  open_stream_rele(osp, rp);
3112 3112                  open_owner_rele(oop);
3113 3113                  return (EIO);
3114 3114          }
3115 3115  
3116 3116          /*
3117 3117           * Determine whether a reopen is needed.  If this
3118 3118           * is a delegation open stream, then the os_delegation bit
3119 3119           * should be set.
3120 3120           */
3121 3121  
3122 3122          reopen_needed = osp->os_delegation;
3123 3123  
3124 3124          mutex_exit(&osp->os_sync_lock);
3125 3125          open_owner_rele(oop);
3126 3126  
3127 3127          if (reopen_needed) {
3128 3128                  nfs4_error_zinit(ep);
3129 3129                  nfs4_reopen(vp, osp, ep, CLAIM_NULL, FALSE, FALSE);
3130 3130                  mutex_enter(&osp->os_sync_lock);
3131 3131                  if (ep->error || ep->stat || osp->os_failed_reopen) {
3132 3132                          mutex_exit(&osp->os_sync_lock);
3133 3133                          open_stream_rele(osp, rp);
3134 3134                          return (EIO);
3135 3135                  }
3136 3136                  mutex_exit(&osp->os_sync_lock);
3137 3137          }
3138 3138          open_stream_rele(osp, rp);
3139 3139  
3140 3140          return (0);
3141 3141  }
3142 3142  
3143 3143  /*
3144 3144   * Write to file.  Writes to remote server in largest size
3145 3145   * chunks that the server can handle.  Write is synchronous.
3146 3146   */
3147 3147  static int
3148 3148  nfs4write(vnode_t *vp, caddr_t base, u_offset_t offset, int count, cred_t *cr,
3149 3149      stable_how4 *stab_comm)
3150 3150  {
3151 3151          mntinfo4_t *mi;
3152 3152          COMPOUND4args_clnt args;
3153 3153          COMPOUND4res_clnt res;
3154 3154          WRITE4args *wargs;
3155 3155          WRITE4res *wres;
3156 3156          nfs_argop4 argop[2];
3157 3157          nfs_resop4 *resop;
3158 3158          int tsize;
3159 3159          stable_how4 stable;
3160 3160          rnode4_t *rp;
3161 3161          int doqueue = 1;
3162 3162          bool_t needrecov;
3163 3163          nfs4_recov_state_t recov_state;
3164 3164          nfs4_stateid_types_t sid_types;
3165 3165          nfs4_error_t e = { 0, NFS4_OK, RPC_SUCCESS };
3166 3166          int recov;
3167 3167  
3168 3168          rp = VTOR4(vp);
3169 3169          mi = VTOMI4(vp);
3170 3170  
3171 3171          ASSERT(nfs_zone() == mi->mi_zone);
3172 3172  
3173 3173          stable = *stab_comm;
3174 3174          *stab_comm = FILE_SYNC4;
3175 3175  
3176 3176          needrecov = FALSE;
3177 3177          recov_state.rs_flags = 0;
3178 3178          recov_state.rs_num_retry_despite_err = 0;
3179 3179          nfs4_init_stateid_types(&sid_types);
3180 3180  
3181 3181          /* Is curthread the recovery thread? */
3182 3182          mutex_enter(&mi->mi_lock);
3183 3183          recov = (mi->mi_recovthread == curthread);
3184 3184          mutex_exit(&mi->mi_lock);
3185 3185  
3186 3186  recov_retry:
3187 3187          args.ctag = TAG_WRITE;
3188 3188          args.array_len = 2;
3189 3189          args.array = argop;
3190 3190  
3191 3191          if (!recov) {
3192 3192                  e.error = nfs4_start_fop(VTOMI4(vp), vp, NULL, OH_WRITE,
3193 3193                      &recov_state, NULL);
3194 3194                  if (e.error)
3195 3195                          return (e.error);
3196 3196          }
3197 3197  
3198 3198          /* 0. putfh target fh */
3199 3199          argop[0].argop = OP_CPUTFH;
3200 3200          argop[0].nfs_argop4_u.opcputfh.sfh = rp->r_fh;
3201 3201  
3202 3202          /* 1. write */
3203 3203          nfs4args_write(&argop[1], stable, rp, cr, &wargs, &sid_types);
3204 3204  
3205 3205          do {
3206 3206  
3207 3207                  wargs->offset = (offset4)offset;
3208 3208                  wargs->data_val = base;
3209 3209  
3210 3210                  if (mi->mi_io_kstats) {
3211 3211                          mutex_enter(&mi->mi_lock);
3212 3212                          kstat_runq_enter(KSTAT_IO_PTR(mi->mi_io_kstats));
3213 3213                          mutex_exit(&mi->mi_lock);
3214 3214                  }
3215 3215  
3216 3216                  if ((vp->v_flag & VNOCACHE) ||
3217 3217                      (rp->r_flags & R4DIRECTIO) ||
3218 3218                      (mi->mi_flags & MI4_DIRECTIO))
3219 3219                          tsize = MIN(mi->mi_stsize, count);
3220 3220                  else
3221 3221                          tsize = MIN(mi->mi_curwrite, count);
3222 3222                  wargs->data_len = (uint_t)tsize;
3223 3223                  rfs4call(mi, &args, &res, cr, &doqueue, 0, &e);
3224 3224  
3225 3225                  if (mi->mi_io_kstats) {
3226 3226                          mutex_enter(&mi->mi_lock);
3227 3227                          kstat_runq_exit(KSTAT_IO_PTR(mi->mi_io_kstats));
3228 3228                          mutex_exit(&mi->mi_lock);
3229 3229                  }
3230 3230  
3231 3231                  if (!recov) {
3232 3232                          needrecov = nfs4_needs_recovery(&e, FALSE, mi->mi_vfsp);
3233 3233                          if (e.error && !needrecov) {
3234 3234                                  nfs4_end_fop(VTOMI4(vp), vp, NULL, OH_WRITE,
3235 3235                                      &recov_state, needrecov);
3236 3236                                  return (e.error);
3237 3237                          }
3238 3238                  } else {
3239 3239                          if (e.error)
3240 3240                                  return (e.error);
3241 3241                  }
3242 3242  
3243 3243                  /*
3244 3244                   * Do handling of OLD_STATEID outside
3245 3245                   * of the normal recovery framework.
3246 3246                   *
3247 3247                   * If write receives a BAD stateid error while using a
3248 3248                   * delegation stateid, retry using the open stateid (if it
3249 3249                   * exists).  If it doesn't have an open stateid, reopen the
3250 3250                   * file first, then retry.
3251 3251                   */
3252 3252                  if (!e.error && res.status == NFS4ERR_OLD_STATEID &&
3253 3253                      sid_types.cur_sid_type != SPEC_SID) {
3254 3254                          nfs4_save_stateid(&wargs->stateid, &sid_types);
3255 3255                          if (!recov)
3256 3256                                  nfs4_end_fop(VTOMI4(vp), vp, NULL, OH_WRITE,
3257 3257                                      &recov_state, needrecov);
3258 3258                          (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
3259 3259                          goto recov_retry;
3260 3260                  } else if (e.error == 0 && res.status == NFS4ERR_BAD_STATEID &&
3261 3261                      sid_types.cur_sid_type == DEL_SID) {
3262 3262                          nfs4_save_stateid(&wargs->stateid, &sid_types);
3263 3263                          mutex_enter(&rp->r_statev4_lock);
3264 3264                          rp->r_deleg_return_pending = TRUE;
3265 3265                          mutex_exit(&rp->r_statev4_lock);
3266 3266                          if (nfs4rdwr_check_osid(vp, &e, cr)) {
3267 3267                                  if (!recov)
3268 3268                                          nfs4_end_fop(mi, vp, NULL, OH_WRITE,
3269 3269                                              &recov_state, needrecov);
3270 3270                                  (void) xdr_free(xdr_COMPOUND4res_clnt,
3271 3271                                      (caddr_t)&res);
3272 3272                                  return (EIO);
3273 3273                          }
3274 3274                          if (!recov)
3275 3275                                  nfs4_end_fop(mi, vp, NULL, OH_WRITE,
3276 3276                                      &recov_state, needrecov);
3277 3277                          /* hold needed for nfs4delegreturn_thread */
3278 3278                          VN_HOLD(vp);
3279 3279                          nfs4delegreturn_async(rp, (NFS4_DR_PUSH|NFS4_DR_REOPEN|
3280 3280                              NFS4_DR_DISCARD), FALSE);
3281 3281                          (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
3282 3282                          goto recov_retry;
3283 3283                  }
3284 3284  
3285 3285                  if (needrecov) {
3286 3286                          bool_t abort;
3287 3287  
3288 3288                          NFS4_DEBUG(nfs4_client_recov_debug, (CE_NOTE,
3289 3289                              "nfs4write: client got error %d, res.status %d"
3290 3290                              ", so start recovery", e.error, res.status));
3291 3291  
3292 3292                          abort = nfs4_start_recovery(&e,
3293 3293                              VTOMI4(vp), vp, NULL, &wargs->stateid,
3294 3294                              NULL, OP_WRITE, NULL, NULL, NULL);
3295 3295                          if (!e.error) {
3296 3296                                  e.error = geterrno4(res.status);
3297 3297                                  (void) xdr_free(xdr_COMPOUND4res_clnt,
3298 3298                                      (caddr_t)&res);
3299 3299                          }
3300 3300                          nfs4_end_fop(VTOMI4(vp), vp, NULL, OH_WRITE,
3301 3301                              &recov_state, needrecov);
3302 3302                          if (abort == FALSE)
3303 3303                                  goto recov_retry;
3304 3304                          return (e.error);
3305 3305                  }
3306 3306  
3307 3307                  if (res.status) {
3308 3308                          e.error = geterrno4(res.status);
3309 3309                          (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
3310 3310                          if (!recov)
3311 3311                                  nfs4_end_fop(VTOMI4(vp), vp, NULL, OH_WRITE,
3312 3312                                      &recov_state, needrecov);
3313 3313                          return (e.error);
3314 3314                  }
3315 3315  
3316 3316                  resop = &res.array[1];  /* write res */
3317 3317                  wres = &resop->nfs_resop4_u.opwrite;
3318 3318  
3319 3319                  if ((int)wres->count > tsize) {
3320 3320                          (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
3321 3321  
3322 3322                          zcmn_err(getzoneid(), CE_WARN,
3323 3323                              "nfs4write: server wrote %u, requested was %u",
3324 3324                              (int)wres->count, tsize);
3325 3325                          if (!recov)
3326 3326                                  nfs4_end_fop(VTOMI4(vp), vp, NULL, OH_WRITE,
3327 3327                                      &recov_state, needrecov);
3328 3328                          return (EIO);
3329 3329                  }
3330 3330                  if (wres->committed == UNSTABLE4) {
3331 3331                          *stab_comm = UNSTABLE4;
3332 3332                          if (wargs->stable == DATA_SYNC4 ||
3333 3333                              wargs->stable == FILE_SYNC4) {
3334 3334                                  (void) xdr_free(xdr_COMPOUND4res_clnt,
3335 3335                                      (caddr_t)&res);
3336 3336                                  zcmn_err(getzoneid(), CE_WARN,
3337 3337                                      "nfs4write: server %s did not commit "
3338 3338                                      "to stable storage",
3339 3339                                      rp->r_server->sv_hostname);
3340 3340                                  if (!recov)
3341 3341                                          nfs4_end_fop(VTOMI4(vp), vp, NULL,
3342 3342                                              OH_WRITE, &recov_state, needrecov);
3343 3343                                  return (EIO);
3344 3344                          }
3345 3345                  }
3346 3346  
3347 3347                  tsize = (int)wres->count;
3348 3348                  count -= tsize;
3349 3349                  base += tsize;
3350 3350                  offset += tsize;
3351 3351                  if (mi->mi_io_kstats) {
3352 3352                          mutex_enter(&mi->mi_lock);
3353 3353                          KSTAT_IO_PTR(mi->mi_io_kstats)->writes++;
3354 3354                          KSTAT_IO_PTR(mi->mi_io_kstats)->nwritten +=
3355 3355                              tsize;
3356 3356                          mutex_exit(&mi->mi_lock);
3357 3357                  }
3358 3358                  lwp_stat_update(LWP_STAT_OUBLK, 1);
3359 3359                  mutex_enter(&rp->r_statelock);
3360 3360                  if (rp->r_flags & R4HAVEVERF) {
3361 3361                          if (rp->r_writeverf != wres->writeverf) {
3362 3362                                  nfs4_set_mod(vp);
3363 3363                                  rp->r_writeverf = wres->writeverf;
3364 3364                          }
3365 3365                  } else {
3366 3366                          rp->r_writeverf = wres->writeverf;
3367 3367                          rp->r_flags |= R4HAVEVERF;
3368 3368                  }
3369 3369                  PURGE_ATTRCACHE4_LOCKED(rp);
3370 3370                  rp->r_flags |= R4WRITEMODIFIED;
3371 3371                  gethrestime(&rp->r_attr.va_mtime);
3372 3372                  rp->r_attr.va_ctime = rp->r_attr.va_mtime;
3373 3373                  mutex_exit(&rp->r_statelock);
3374 3374                  (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
3375 3375          } while (count);
3376 3376  
3377 3377          if (!recov)
3378 3378                  nfs4_end_fop(VTOMI4(vp), vp, NULL, OH_WRITE, &recov_state,
3379 3379                      needrecov);
3380 3380  
3381 3381          return (e.error);
3382 3382  }
3383 3383  
3384 3384  /*
3385 3385   * Read from a file.  Reads data in largest chunks our interface can handle.
3386 3386   */
3387 3387  static int
3388 3388  nfs4read(vnode_t *vp, caddr_t base, offset_t offset, int count,
3389 3389      size_t *residp, cred_t *cr, bool_t async, struct uio *uiop)
3390 3390  {
3391 3391          mntinfo4_t *mi;
3392 3392          COMPOUND4args_clnt args;
3393 3393          COMPOUND4res_clnt res;
3394 3394          READ4args *rargs;
3395 3395          nfs_argop4 argop[2];
3396 3396          int tsize;
3397 3397          int doqueue;
3398 3398          rnode4_t *rp;
3399 3399          int data_len;
3400 3400          bool_t is_eof;
3401 3401          bool_t needrecov = FALSE;
3402 3402          nfs4_recov_state_t recov_state;
3403 3403          nfs4_stateid_types_t sid_types;
3404 3404          nfs4_error_t e = { 0, NFS4_OK, RPC_SUCCESS };
3405 3405  
3406 3406          rp = VTOR4(vp);
3407 3407          mi = VTOMI4(vp);
3408 3408          doqueue = 1;
3409 3409  
3410 3410          ASSERT(nfs_zone() == mi->mi_zone);
3411 3411  
3412 3412          args.ctag = async ? TAG_READAHEAD : TAG_READ;
3413 3413  
3414 3414          args.array_len = 2;
3415 3415          args.array = argop;
3416 3416  
3417 3417          nfs4_init_stateid_types(&sid_types);
3418 3418  
3419 3419          recov_state.rs_flags = 0;
3420 3420          recov_state.rs_num_retry_despite_err = 0;
3421 3421  
3422 3422  recov_retry:
3423 3423          e.error = nfs4_start_fop(mi, vp, NULL, OH_READ,
3424 3424              &recov_state, NULL);
3425 3425          if (e.error)
3426 3426                  return (e.error);
3427 3427  
3428 3428          /* putfh target fh */
3429 3429          argop[0].argop = OP_CPUTFH;
3430 3430          argop[0].nfs_argop4_u.opcputfh.sfh = rp->r_fh;
3431 3431  
3432 3432          /* read */
3433 3433          argop[1].argop = OP_READ;
3434 3434          rargs = &argop[1].nfs_argop4_u.opread;
3435 3435          rargs->stateid = nfs4_get_stateid(cr, rp, curproc->p_pidp->pid_id, mi,
3436 3436              OP_READ, &sid_types, async);
3437 3437  
3438 3438          do {
3439 3439                  if (mi->mi_io_kstats) {
3440 3440                          mutex_enter(&mi->mi_lock);
3441 3441                          kstat_runq_enter(KSTAT_IO_PTR(mi->mi_io_kstats));
3442 3442                          mutex_exit(&mi->mi_lock);
3443 3443                  }
3444 3444  
3445 3445                  NFS4_DEBUG(nfs4_client_call_debug, (CE_NOTE,
3446 3446                      "nfs4read: %s call, rp %s",
3447 3447                      needrecov ? "recov" : "first",
3448 3448                      rnode4info(rp)));
3449 3449  
3450 3450                  if ((vp->v_flag & VNOCACHE) ||
3451 3451                      (rp->r_flags & R4DIRECTIO) ||
3452 3452                      (mi->mi_flags & MI4_DIRECTIO))
3453 3453                          tsize = MIN(mi->mi_tsize, count);
3454 3454                  else
3455 3455                          tsize = MIN(mi->mi_curread, count);
3456 3456  
3457 3457                  rargs->offset = (offset4)offset;
3458 3458                  rargs->count = (count4)tsize;
3459 3459                  rargs->res_data_val_alt = NULL;
3460 3460                  rargs->res_mblk = NULL;
3461 3461                  rargs->res_uiop = NULL;
3462 3462                  rargs->res_maxsize = 0;
3463 3463                  rargs->wlist = NULL;
3464 3464  
3465 3465                  if (uiop)
3466 3466                          rargs->res_uiop = uiop;
3467 3467                  else
3468 3468                          rargs->res_data_val_alt = base;
3469 3469                  rargs->res_maxsize = tsize;
3470 3470  
3471 3471                  rfs4call(mi, &args, &res, cr, &doqueue, 0, &e);
3472 3472  #ifdef  DEBUG
3473 3473                  if (nfs4read_error_inject) {
3474 3474                          res.status = nfs4read_error_inject;
3475 3475                          nfs4read_error_inject = 0;
3476 3476                  }
3477 3477  #endif
3478 3478  
3479 3479                  if (mi->mi_io_kstats) {
3480 3480                          mutex_enter(&mi->mi_lock);
3481 3481                          kstat_runq_exit(KSTAT_IO_PTR(mi->mi_io_kstats));
3482 3482                          mutex_exit(&mi->mi_lock);
3483 3483                  }
3484 3484  
3485 3485                  needrecov = nfs4_needs_recovery(&e, FALSE, mi->mi_vfsp);
3486 3486                  if (e.error != 0 && !needrecov) {
3487 3487                          nfs4_end_fop(mi, vp, NULL, OH_READ,
3488 3488                              &recov_state, needrecov);
3489 3489                          return (e.error);
3490 3490                  }
3491 3491  
3492 3492                  /*
3493 3493                   * Do proper retry for OLD and BAD stateid errors outside
3494 3494                   * of the normal recovery framework.  There are two differences
3495 3495                   * between async and sync reads.  The first is that we allow
3496 3496                   * retry on BAD_STATEID for async reads, but not sync reads.
3497 3497                   * The second is that we mark the file dead for a failed
3498 3498                   * attempt with a special stateid for sync reads, but just
3499 3499                   * return EIO for async reads.
3500 3500                   *
3501 3501                   * If a sync read receives a BAD stateid error while using a
3502 3502                   * delegation stateid, retry using the open stateid (if it
3503 3503                   * exists).  If it doesn't have an open stateid, reopen the
3504 3504                   * file first, then retry.
3505 3505                   */
3506 3506                  if (e.error == 0 && (res.status == NFS4ERR_OLD_STATEID ||
3507 3507                      res.status == NFS4ERR_BAD_STATEID) && async) {
3508 3508                          nfs4_end_fop(mi, vp, NULL, OH_READ,
3509 3509                              &recov_state, needrecov);
3510 3510                          if (sid_types.cur_sid_type == SPEC_SID) {
3511 3511                                  (void) xdr_free(xdr_COMPOUND4res_clnt,
3512 3512                                      (caddr_t)&res);
3513 3513                                  return (EIO);
3514 3514                          }
3515 3515                          nfs4_save_stateid(&rargs->stateid, &sid_types);
3516 3516                          (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
3517 3517                          goto recov_retry;
3518 3518                  } else if (e.error == 0 && res.status == NFS4ERR_OLD_STATEID &&
3519 3519                      !async && sid_types.cur_sid_type != SPEC_SID) {
3520 3520                          nfs4_save_stateid(&rargs->stateid, &sid_types);
3521 3521                          nfs4_end_fop(mi, vp, NULL, OH_READ,
3522 3522                              &recov_state, needrecov);
3523 3523                          (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
3524 3524                          goto recov_retry;
3525 3525                  } else if (e.error == 0 && res.status == NFS4ERR_BAD_STATEID &&
3526 3526                      sid_types.cur_sid_type == DEL_SID) {
3527 3527                          nfs4_save_stateid(&rargs->stateid, &sid_types);
3528 3528                          mutex_enter(&rp->r_statev4_lock);
3529 3529                          rp->r_deleg_return_pending = TRUE;
3530 3530                          mutex_exit(&rp->r_statev4_lock);
3531 3531                          if (nfs4rdwr_check_osid(vp, &e, cr)) {
3532 3532                                  nfs4_end_fop(mi, vp, NULL, OH_READ,
3533 3533                                      &recov_state, needrecov);
3534 3534                                  (void) xdr_free(xdr_COMPOUND4res_clnt,
3535 3535                                      (caddr_t)&res);
3536 3536                                  return (EIO);
3537 3537                          }
3538 3538                          nfs4_end_fop(mi, vp, NULL, OH_READ,
3539 3539                              &recov_state, needrecov);
3540 3540                          /* hold needed for nfs4delegreturn_thread */
3541 3541                          VN_HOLD(vp);
3542 3542                          nfs4delegreturn_async(rp, (NFS4_DR_PUSH|NFS4_DR_REOPEN|
3543 3543                              NFS4_DR_DISCARD), FALSE);
3544 3544                          (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
3545 3545                          goto recov_retry;
3546 3546                  }
3547 3547                  if (needrecov) {
3548 3548                          bool_t abort;
3549 3549  
3550 3550                          NFS4_DEBUG(nfs4_client_recov_debug, (CE_NOTE,
3551 3551                              "nfs4read: initiating recovery\n"));
3552 3552                          abort = nfs4_start_recovery(&e,
3553 3553                              mi, vp, NULL, &rargs->stateid,
3554 3554                              NULL, OP_READ, NULL, NULL, NULL);
3555 3555                          nfs4_end_fop(mi, vp, NULL, OH_READ,
3556 3556                              &recov_state, needrecov);
3557 3557                          /*
3558 3558                           * Do not retry if we got OLD_STATEID using a special
3559 3559                           * stateid.  This avoids looping with a broken server.
3560 3560                           */
3561 3561                          if (e.error == 0 && res.status == NFS4ERR_OLD_STATEID &&
3562 3562                              sid_types.cur_sid_type == SPEC_SID)
3563 3563                                  abort = TRUE;
3564 3564  
3565 3565                          if (abort == FALSE) {
3566 3566                                  /*
3567 3567                                   * Need to retry all possible stateids in
3568 3568                                   * case the recovery error wasn't stateid
3569 3569                                   * related or the stateids have become
3570 3570                                   * stale (server reboot).
3571 3571                                   */
3572 3572                                  nfs4_init_stateid_types(&sid_types);
3573 3573                                  (void) xdr_free(xdr_COMPOUND4res_clnt,
3574 3574                                      (caddr_t)&res);
3575 3575                                  goto recov_retry;
3576 3576                          }
3577 3577  
3578 3578                          if (!e.error) {
3579 3579                                  e.error = geterrno4(res.status);
3580 3580                                  (void) xdr_free(xdr_COMPOUND4res_clnt,
3581 3581                                      (caddr_t)&res);
3582 3582                          }
3583 3583                          return (e.error);
3584 3584                  }
3585 3585  
3586 3586                  if (res.status) {
3587 3587                          e.error = geterrno4(res.status);
3588 3588                          nfs4_end_fop(mi, vp, NULL, OH_READ,
3589 3589                              &recov_state, needrecov);
3590 3590                          (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
3591 3591                          return (e.error);
3592 3592                  }
3593 3593  
3594 3594                  data_len = res.array[1].nfs_resop4_u.opread.data_len;
3595 3595                  count -= data_len;
3596 3596                  if (base)
3597 3597                          base += data_len;
3598 3598                  offset += data_len;
3599 3599                  if (mi->mi_io_kstats) {
3600 3600                          mutex_enter(&mi->mi_lock);
3601 3601                          KSTAT_IO_PTR(mi->mi_io_kstats)->reads++;
3602 3602                          KSTAT_IO_PTR(mi->mi_io_kstats)->nread += data_len;
3603 3603                          mutex_exit(&mi->mi_lock);
3604 3604                  }
3605 3605                  lwp_stat_update(LWP_STAT_INBLK, 1);
3606 3606                  is_eof = res.array[1].nfs_resop4_u.opread.eof;
3607 3607                  (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
3608 3608  
3609 3609          } while (count && !is_eof);
3610 3610  
3611 3611          *residp = count;
3612 3612  
3613 3613          nfs4_end_fop(mi, vp, NULL, OH_READ, &recov_state, needrecov);
3614 3614  
3615 3615          return (e.error);
3616 3616  }
3617 3617  
3618 3618  /* ARGSUSED */
3619 3619  static int
3620 3620  nfs4_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp,
3621 3621      caller_context_t *ct)
3622 3622  {
3623 3623          if (nfs_zone() != VTOMI4(vp)->mi_zone)
3624 3624                  return (EIO);
3625 3625          switch (cmd) {
3626 3626                  case _FIODIRECTIO:
3627 3627                          return (nfs4_directio(vp, (int)arg, cr));
3628 3628                  default:
3629 3629                          return (ENOTTY);
3630 3630          }
3631 3631  }
3632 3632  
3633 3633  /* ARGSUSED */
3634 3634  int
3635 3635  nfs4_getattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr,
3636 3636      caller_context_t *ct)
3637 3637  {
3638 3638          int error;
3639 3639          rnode4_t *rp = VTOR4(vp);
3640 3640  
3641 3641          if (nfs_zone() != VTOMI4(vp)->mi_zone)
3642 3642                  return (EIO);
3643 3643          /*
3644 3644           * If it has been specified that the return value will
3645 3645           * just be used as a hint, and we are only being asked
3646 3646           * for size, fsid or rdevid, then return the client's
3647 3647           * notion of these values without checking to make sure
3648 3648           * that the attribute cache is up to date.
3649 3649           * The whole point is to avoid an over the wire GETATTR
3650 3650           * call.
3651 3651           */
3652 3652          if (flags & ATTR_HINT) {
3653 3653                  if (!(vap->va_mask & ~(AT_SIZE | AT_FSID | AT_RDEV))) {
3654 3654                          mutex_enter(&rp->r_statelock);
3655 3655                          if (vap->va_mask & AT_SIZE)
3656 3656                                  vap->va_size = rp->r_size;
3657 3657                          if (vap->va_mask & AT_FSID)
3658 3658                                  vap->va_fsid = rp->r_attr.va_fsid;
3659 3659                          if (vap->va_mask & AT_RDEV)
3660 3660                                  vap->va_rdev = rp->r_attr.va_rdev;
3661 3661                          mutex_exit(&rp->r_statelock);
3662 3662                          return (0);
3663 3663                  }
3664 3664          }
3665 3665  
3666 3666          /*
3667 3667           * Only need to flush pages if asking for the mtime
3668 3668           * and if there any dirty pages or any outstanding
3669 3669           * asynchronous (write) requests for this file.
3670 3670           */
3671 3671          if (vap->va_mask & AT_MTIME) {
3672 3672                  rp = VTOR4(vp);
3673 3673                  if (nfs4_has_pages(vp)) {
3674 3674                          mutex_enter(&rp->r_statev4_lock);
3675 3675                          if (rp->r_deleg_type != OPEN_DELEGATE_WRITE) {
3676 3676                                  mutex_exit(&rp->r_statev4_lock);
3677 3677                                  if (rp->r_flags & R4DIRTY ||
3678 3678                                      rp->r_awcount > 0) {
3679 3679                                          mutex_enter(&rp->r_statelock);
3680 3680                                          rp->r_gcount++;
3681 3681                                          mutex_exit(&rp->r_statelock);
3682 3682                                          error =
3683 3683                                              nfs4_putpage(vp, (u_offset_t)0,
3684 3684                                              0, 0, cr, NULL);
3685 3685                                          mutex_enter(&rp->r_statelock);
3686 3686                                          if (error && (error == ENOSPC ||
3687 3687                                              error == EDQUOT)) {
3688 3688                                                  if (!rp->r_error)
3689 3689                                                          rp->r_error = error;
3690 3690                                          }
3691 3691                                          if (--rp->r_gcount == 0)
3692 3692                                                  cv_broadcast(&rp->r_cv);
3693 3693                                          mutex_exit(&rp->r_statelock);
3694 3694                                  }
3695 3695                          } else {
3696 3696                                  mutex_exit(&rp->r_statev4_lock);
3697 3697                          }
3698 3698                  }
3699 3699          }
3700 3700          return (nfs4getattr(vp, vap, cr));
3701 3701  }
3702 3702  
3703 3703  int
3704 3704  nfs4_compare_modes(mode_t from_server, mode_t on_client)
3705 3705  {
3706 3706          /*
3707 3707           * If these are the only two bits cleared
3708 3708           * on the server then return 0 (OK) else
3709 3709           * return 1 (BAD).
3710 3710           */
3711 3711          on_client &= ~(S_ISUID|S_ISGID);
3712 3712          if (on_client == from_server)
3713 3713                  return (0);
3714 3714          else
3715 3715                  return (1);
3716 3716  }
3717 3717  
3718 3718  /*ARGSUSED4*/
3719 3719  static int
3720 3720  nfs4_setattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr,
3721 3721      caller_context_t *ct)
3722 3722  {
3723 3723          int error;
3724 3724  
3725 3725          if (vap->va_mask & AT_NOSET)
3726 3726                  return (EINVAL);
3727 3727  
3728 3728          if (nfs_zone() != VTOMI4(vp)->mi_zone)
3729 3729                  return (EIO);
3730 3730  
3731 3731          /*
3732 3732           * Don't call secpolicy_vnode_setattr, the client cannot
3733 3733           * use its cached attributes to make security decisions
3734 3734           * as the server may be faking mode bits or mapping uid/gid.
3735 3735           * Always just let the server to the checking.
3736 3736           * If we provide the ability to remove basic priviledges
3737 3737           * to setattr (e.g. basic without chmod) then we will
3738 3738           * need to add a check here before calling the server.
3739 3739           */
3740 3740          error = nfs4setattr(vp, vap, flags, cr, NULL);
3741 3741  
3742 3742          if (error == 0 && (vap->va_mask & AT_SIZE)) {
3743 3743                  if (vap->va_size == 0) {
3744 3744                          vnevent_truncate(vp, ct);
3745 3745                  } else {
3746 3746                          vnevent_resize(vp, ct);
3747 3747                  }
3748 3748          }
3749 3749  
3750 3750          return (error);
3751 3751  }
3752 3752  
3753 3753  /*
3754 3754   * To replace the "guarded" version 3 setattr, we use two types of compound
3755 3755   * setattr requests:
3756 3756   * 1. The "normal" setattr, used when the size of the file isn't being
3757 3757   *    changed - { Putfh <fh>; Setattr; Getattr }/
3758 3758   * 2. If the size is changed, precede Setattr with: Getattr; Verify
3759 3759   *    with only ctime as the argument. If the server ctime differs from
3760 3760   *    what is cached on the client, the verify will fail, but we would
3761 3761   *    already have the ctime from the preceding getattr, so just set it
3762 3762   *    and retry. Thus the compound here is - { Putfh <fh>; Getattr; Verify;
3763 3763   *      Setattr; Getattr }.
3764 3764   *
3765 3765   * The vsecattr_t * input parameter will be non-NULL if ACLs are being set in
3766 3766   * this setattr and NULL if they are not.
3767 3767   */
3768 3768  static int
3769 3769  nfs4setattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr,
3770 3770      vsecattr_t *vsap)
3771 3771  {
3772 3772          COMPOUND4args_clnt args;
3773 3773          COMPOUND4res_clnt res, *resp = NULL;
3774 3774          nfs4_ga_res_t *garp = NULL;
3775 3775          int numops = 3;                 /* { Putfh; Setattr; Getattr } */
3776 3776          nfs_argop4 argop[5];
3777 3777          int verify_argop = -1;
3778 3778          int setattr_argop = 1;
3779 3779          nfs_resop4 *resop;
3780 3780          vattr_t va;
3781 3781          rnode4_t *rp;
3782 3782          int doqueue = 1;
3783 3783          uint_t mask = vap->va_mask;
3784 3784          mode_t omode;
3785 3785          vsecattr_t *vsp;
3786 3786          timestruc_t ctime;
3787 3787          bool_t needrecov = FALSE;
3788 3788          nfs4_recov_state_t recov_state;
3789 3789          nfs4_stateid_types_t sid_types;
3790 3790          stateid4 stateid;
3791 3791          hrtime_t t;
3792 3792          nfs4_error_t e = { 0, NFS4_OK, RPC_SUCCESS };
3793 3793          servinfo4_t *svp;
3794 3794          bitmap4 supp_attrs;
3795 3795  
3796 3796          ASSERT(nfs_zone() == VTOMI4(vp)->mi_zone);
3797 3797          rp = VTOR4(vp);
3798 3798          nfs4_init_stateid_types(&sid_types);
3799 3799  
3800 3800          /*
3801 3801           * Only need to flush pages if there are any pages and
3802 3802           * if the file is marked as dirty in some fashion.  The
3803 3803           * file must be flushed so that we can accurately
3804 3804           * determine the size of the file and the cached data
3805 3805           * after the SETATTR returns.  A file is considered to
3806 3806           * be dirty if it is either marked with R4DIRTY, has
3807 3807           * outstanding i/o's active, or is mmap'd.  In this
3808 3808           * last case, we can't tell whether there are dirty
3809 3809           * pages, so we flush just to be sure.
3810 3810           */
3811 3811          if (nfs4_has_pages(vp) &&
3812 3812              ((rp->r_flags & R4DIRTY) ||
3813 3813              rp->r_count > 0 ||
3814 3814              rp->r_mapcnt > 0)) {
3815 3815                  ASSERT(vp->v_type != VCHR);
3816 3816                  e.error = nfs4_putpage(vp, (offset_t)0, 0, 0, cr, NULL);
3817 3817                  if (e.error && (e.error == ENOSPC || e.error == EDQUOT)) {
3818 3818                          mutex_enter(&rp->r_statelock);
3819 3819                          if (!rp->r_error)
3820 3820                                  rp->r_error = e.error;
3821 3821                          mutex_exit(&rp->r_statelock);
3822 3822                  }
3823 3823          }
3824 3824  
3825 3825          if (mask & AT_SIZE) {
3826 3826                  /*
3827 3827                   * Verification setattr compound for non-deleg AT_SIZE:
3828 3828                   *      { Putfh; Getattr; Verify; Setattr; Getattr }
3829 3829                   * Set ctime local here (outside the do_again label)
3830 3830                   * so that subsequent retries (after failed VERIFY)
3831 3831                   * will use ctime from GETATTR results (from failed
3832 3832                   * verify compound) as VERIFY arg.
3833 3833                   * If file has delegation, then VERIFY(time_metadata)
3834 3834                   * is of little added value, so don't bother.
3835 3835                   */
3836 3836                  mutex_enter(&rp->r_statev4_lock);
3837 3837                  if (rp->r_deleg_type == OPEN_DELEGATE_NONE ||
3838 3838                      rp->r_deleg_return_pending) {
3839 3839                          numops = 5;
3840 3840                          ctime = rp->r_attr.va_ctime;
3841 3841                  }
3842 3842                  mutex_exit(&rp->r_statev4_lock);
3843 3843          }
3844 3844  
3845 3845          recov_state.rs_flags = 0;
3846 3846          recov_state.rs_num_retry_despite_err = 0;
3847 3847  
3848 3848          args.ctag = TAG_SETATTR;
3849 3849  do_again:
3850 3850  recov_retry:
3851 3851          setattr_argop = numops - 2;
3852 3852  
3853 3853          args.array = argop;
3854 3854          args.array_len = numops;
3855 3855  
3856 3856          e.error = nfs4_start_op(VTOMI4(vp), vp, NULL, &recov_state);
3857 3857          if (e.error)
3858 3858                  return (e.error);
3859 3859  
3860 3860  
3861 3861          /* putfh target fh */
3862 3862          argop[0].argop = OP_CPUTFH;
3863 3863          argop[0].nfs_argop4_u.opcputfh.sfh = rp->r_fh;
3864 3864  
3865 3865          if (numops == 5) {
3866 3866                  /*
3867 3867                   * We only care about the ctime, but need to get mtime
3868 3868                   * and size for proper cache update.
3869 3869                   */
3870 3870                  /* getattr */
3871 3871                  argop[1].argop = OP_GETATTR;
3872 3872                  argop[1].nfs_argop4_u.opgetattr.attr_request = NFS4_VATTR_MASK;
3873 3873                  argop[1].nfs_argop4_u.opgetattr.mi = VTOMI4(vp);
3874 3874  
3875 3875                  /* verify - set later in loop */
3876 3876                  verify_argop = 2;
3877 3877          }
3878 3878  
3879 3879          /* setattr */
3880 3880          svp = rp->r_server;
3881 3881          (void) nfs_rw_enter_sig(&svp->sv_lock, RW_READER, 0);
3882 3882          supp_attrs = svp->sv_supp_attrs;
3883 3883          nfs_rw_exit(&svp->sv_lock);
3884 3884  
3885 3885          nfs4args_setattr(&argop[setattr_argop], vap, vsap, flags, rp, cr,
3886 3886              supp_attrs, &e.error, &sid_types);
3887 3887          stateid = argop[setattr_argop].nfs_argop4_u.opsetattr.stateid;
3888 3888          if (e.error) {
3889 3889                  /* req time field(s) overflow - return immediately */
3890 3890                  nfs4_end_op(VTOMI4(vp), vp, NULL, &recov_state, needrecov);
3891 3891                  nfs4_fattr4_free(&argop[setattr_argop].nfs_argop4_u.
3892 3892                      opsetattr.obj_attributes);
3893 3893                  return (e.error);
3894 3894          }
3895 3895          omode = rp->r_attr.va_mode;
3896 3896  
3897 3897          /* getattr */
3898 3898          argop[numops-1].argop = OP_GETATTR;
3899 3899          argop[numops-1].nfs_argop4_u.opgetattr.attr_request = NFS4_VATTR_MASK;
3900 3900          /*
3901 3901           * If we are setting the ACL (indicated only by vsap != NULL), request
3902 3902           * the ACL in this getattr.  The ACL returned from this getattr will be
3903 3903           * used in updating the ACL cache.
3904 3904           */
3905 3905          if (vsap != NULL)
3906 3906                  argop[numops-1].nfs_argop4_u.opgetattr.attr_request |=
3907 3907                      FATTR4_ACL_MASK;
3908 3908          argop[numops-1].nfs_argop4_u.opgetattr.mi = VTOMI4(vp);
3909 3909  
3910 3910          /*
3911 3911           * setattr iterates if the object size is set and the cached ctime
3912 3912           * does not match the file ctime. In that case, verify the ctime first.
3913 3913           */
3914 3914  
3915 3915          do {
3916 3916                  if (verify_argop != -1) {
3917 3917                          /*
3918 3918                           * Verify that the ctime match before doing setattr.
3919 3919                           */
3920 3920                          va.va_mask = AT_CTIME;
3921 3921                          va.va_ctime = ctime;
3922 3922                          svp = rp->r_server;
3923 3923                          (void) nfs_rw_enter_sig(&svp->sv_lock, RW_READER, 0);
3924 3924                          supp_attrs = svp->sv_supp_attrs;
3925 3925                          nfs_rw_exit(&svp->sv_lock);
3926 3926                          e.error = nfs4args_verify(&argop[verify_argop], &va,
3927 3927                              OP_VERIFY, supp_attrs);
3928 3928                          if (e.error) {
3929 3929                                  /* req time field(s) overflow - return */
3930 3930                                  nfs4_end_op(VTOMI4(vp), vp, NULL, &recov_state,
3931 3931                                      needrecov);
3932 3932                                  break;
3933 3933                          }
3934 3934                  }
3935 3935  
3936 3936                  doqueue = 1;
3937 3937  
3938 3938                  t = gethrtime();
3939 3939  
3940 3940                  rfs4call(VTOMI4(vp), &args, &res, cr, &doqueue, 0, &e);
3941 3941  
3942 3942                  /*
3943 3943                   * Purge the access cache and ACL cache if changing either the
3944 3944                   * owner of the file, the group owner, or the mode.  These may
3945 3945                   * change the access permissions of the file, so purge old
3946 3946                   * information and start over again.
3947 3947                   */
3948 3948                  if (mask & (AT_UID | AT_GID | AT_MODE)) {
3949 3949                          (void) nfs4_access_purge_rp(rp);
3950 3950                          if (rp->r_secattr != NULL) {
3951 3951                                  mutex_enter(&rp->r_statelock);
3952 3952                                  vsp = rp->r_secattr;
3953 3953                                  rp->r_secattr = NULL;
3954 3954                                  mutex_exit(&rp->r_statelock);
3955 3955                                  if (vsp != NULL)
3956 3956                                          nfs4_acl_free_cache(vsp);
3957 3957                          }
3958 3958                  }
3959 3959  
3960 3960                  /*
3961 3961                   * If res.array_len == numops, then everything succeeded,
3962 3962                   * except for possibly the final getattr.  If only the
3963 3963                   * last getattr failed, give up, and don't try recovery.
3964 3964                   */
3965 3965                  if (res.array_len == numops) {
3966 3966                          nfs4_end_op(VTOMI4(vp), vp, NULL, &recov_state,
3967 3967                              needrecov);
3968 3968                          if (! e.error)
3969 3969                                  resp = &res;
3970 3970                          break;
3971 3971                  }
3972 3972  
3973 3973                  /*
3974 3974                   * if either rpc call failed or completely succeeded - done
3975 3975                   */
3976 3976                  needrecov = nfs4_needs_recovery(&e, FALSE, vp->v_vfsp);
3977 3977                  if (e.error) {
3978 3978                          PURGE_ATTRCACHE4(vp);
3979 3979                          if (!needrecov) {
3980 3980                                  nfs4_end_op(VTOMI4(vp), vp, NULL, &recov_state,
3981 3981                                      needrecov);
3982 3982                                  break;
3983 3983                          }
3984 3984                  }
3985 3985  
3986 3986                  /*
3987 3987                   * Do proper retry for OLD_STATEID outside of the normal
3988 3988                   * recovery framework.
3989 3989                   */
3990 3990                  if (e.error == 0 && res.status == NFS4ERR_OLD_STATEID &&
3991 3991                      sid_types.cur_sid_type != SPEC_SID &&
3992 3992                      sid_types.cur_sid_type != NO_SID) {
3993 3993                          nfs4_end_op(VTOMI4(vp), vp, NULL, &recov_state,
3994 3994                              needrecov);
3995 3995                          nfs4_save_stateid(&stateid, &sid_types);
3996 3996                          nfs4_fattr4_free(&argop[setattr_argop].nfs_argop4_u.
3997 3997                              opsetattr.obj_attributes);
3998 3998                          if (verify_argop != -1) {
3999 3999                                  nfs4args_verify_free(&argop[verify_argop]);
4000 4000                                  verify_argop = -1;
4001 4001                          }
4002 4002                          (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
4003 4003                          goto recov_retry;
4004 4004                  }
4005 4005  
4006 4006                  if (needrecov) {
4007 4007                          bool_t abort;
4008 4008  
4009 4009                          abort = nfs4_start_recovery(&e,
4010 4010                              VTOMI4(vp), vp, NULL, NULL, NULL,
4011 4011                              OP_SETATTR, NULL, NULL, NULL);
4012 4012                          nfs4_end_op(VTOMI4(vp), vp, NULL, &recov_state,
4013 4013                              needrecov);
4014 4014                          /*
4015 4015                           * Do not retry if we failed with OLD_STATEID using
4016 4016                           * a special stateid.  This is done to avoid looping
4017 4017                           * with a broken server.
4018 4018                           */
4019 4019                          if (e.error == 0 && res.status == NFS4ERR_OLD_STATEID &&
4020 4020                              (sid_types.cur_sid_type == SPEC_SID ||
4021 4021                              sid_types.cur_sid_type == NO_SID))
4022 4022                                  abort = TRUE;
4023 4023                          if (!e.error) {
4024 4024                                  if (res.status == NFS4ERR_BADOWNER)
4025 4025                                          nfs4_log_badowner(VTOMI4(vp),
4026 4026                                              OP_SETATTR);
4027 4027  
4028 4028                                  e.error = geterrno4(res.status);
4029 4029                                  (void) xdr_free(xdr_COMPOUND4res_clnt,
4030 4030                                      (caddr_t)&res);
4031 4031                          }
4032 4032                          nfs4_fattr4_free(&argop[setattr_argop].nfs_argop4_u.
4033 4033                              opsetattr.obj_attributes);
4034 4034                          if (verify_argop != -1) {
4035 4035                                  nfs4args_verify_free(&argop[verify_argop]);
4036 4036                                  verify_argop = -1;
4037 4037                          }
4038 4038                          if (abort == FALSE) {
4039 4039                                  /*
4040 4040                                   * Need to retry all possible stateids in
4041 4041                                   * case the recovery error wasn't stateid
4042 4042                                   * related or the stateids have become
4043 4043                                   * stale (server reboot).
4044 4044                                   */
4045 4045                                  nfs4_init_stateid_types(&sid_types);
4046 4046                                  goto recov_retry;
4047 4047                          }
4048 4048                          return (e.error);
4049 4049                  }
4050 4050  
4051 4051                  /*
4052 4052                   * Need to call nfs4_end_op before nfs4getattr to
4053 4053                   * avoid potential nfs4_start_op deadlock. See RFE
4054 4054                   * 4777612.  Calls to nfs4_invalidate_pages() and
4055 4055                   * nfs4_purge_stale_fh() might also generate over the
4056 4056                   * wire calls which my cause nfs4_start_op() deadlock.
4057 4057                   */
4058 4058                  nfs4_end_op(VTOMI4(vp), vp, NULL, &recov_state, needrecov);
4059 4059  
4060 4060                  /*
4061 4061                   * Check to update lease.
4062 4062                   */
4063 4063                  resp = &res;
4064 4064                  if (res.status == NFS4_OK) {
4065 4065                          break;
4066 4066                  }
4067 4067  
4068 4068                  /*
4069 4069                   * Check if verify failed to see if try again
4070 4070                   */
4071 4071                  if ((verify_argop == -1) || (res.array_len != 3)) {
4072 4072                          /*
4073 4073                           * can't continue...
4074 4074                           */
4075 4075                          if (res.status == NFS4ERR_BADOWNER)
4076 4076                                  nfs4_log_badowner(VTOMI4(vp), OP_SETATTR);
4077 4077  
4078 4078                          e.error = geterrno4(res.status);
4079 4079                  } else {
4080 4080                          /*
4081 4081                           * When the verify request fails, the client ctime is
4082 4082                           * not in sync with the server. This is the same as
4083 4083                           * the version 3 "not synchronized" error, and we
4084 4084                           * handle it in a similar manner (XXX do we need to???).
4085 4085                           * Use the ctime returned in the first getattr for
4086 4086                           * the input to the next verify.
4087 4087                           * If we couldn't get the attributes, then we give up
4088 4088                           * because we can't complete the operation as required.
4089 4089                           */
4090 4090                          garp = &res.array[1].nfs_resop4_u.opgetattr.ga_res;
4091 4091                  }
4092 4092                  if (e.error) {
4093 4093                          PURGE_ATTRCACHE4(vp);
4094 4094                          nfs4_purge_stale_fh(e.error, vp, cr);
4095 4095                  } else {
4096 4096                          /*
4097 4097                           * retry with a new verify value
4098 4098                           */
4099 4099                          ctime = garp->n4g_va.va_ctime;
4100 4100                          (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
4101 4101                          resp = NULL;
4102 4102                  }
4103 4103                  if (!e.error) {
4104 4104                          nfs4_fattr4_free(&argop[setattr_argop].nfs_argop4_u.
4105 4105                              opsetattr.obj_attributes);
4106 4106                          if (verify_argop != -1) {
4107 4107                                  nfs4args_verify_free(&argop[verify_argop]);
4108 4108                                  verify_argop = -1;
4109 4109                          }
4110 4110                          (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
4111 4111                          goto do_again;
4112 4112                  }
4113 4113          } while (!e.error);
4114 4114  
4115 4115          if (e.error) {
4116 4116                  /*
4117 4117                   * If we are here, rfs4call has an irrecoverable error - return
4118 4118                   */
4119 4119                  nfs4_fattr4_free(&argop[setattr_argop].nfs_argop4_u.
4120 4120                      opsetattr.obj_attributes);
4121 4121                  if (verify_argop != -1) {
4122 4122                          nfs4args_verify_free(&argop[verify_argop]);
4123 4123                          verify_argop = -1;
4124 4124                  }
4125 4125                  if (resp)
4126 4126                          (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)resp);
4127 4127                  return (e.error);
4128 4128          }
4129 4129  
4130 4130  
4131 4131  
4132 4132          /*
4133 4133           * If changing the size of the file, invalidate
4134 4134           * any local cached data which is no longer part
4135 4135           * of the file.  We also possibly invalidate the
4136 4136           * last page in the file.  We could use
4137 4137           * pvn_vpzero(), but this would mark the page as
4138 4138           * modified and require it to be written back to
4139 4139           * the server for no particularly good reason.
4140 4140           * This way, if we access it, then we bring it
4141 4141           * back in.  A read should be cheaper than a
4142 4142           * write.
4143 4143           */
4144 4144          if (mask & AT_SIZE) {
4145 4145                  nfs4_invalidate_pages(vp, (vap->va_size & PAGEMASK), cr);
4146 4146          }
4147 4147  
4148 4148          /* either no error or one of the postop getattr failed */
4149 4149  
4150 4150          /*
4151 4151           * XXX Perform a simplified version of wcc checking. Instead of
4152 4152           * have another getattr to get pre-op, just purge cache if
4153 4153           * any of the ops prior to and including the getattr failed.
4154 4154           * If the getattr succeeded then update the attrcache accordingly.
4155 4155           */
4156 4156  
4157 4157          garp = NULL;
4158 4158          if (res.status == NFS4_OK) {
4159 4159                  /*
4160 4160                   * Last getattr
4161 4161                   */
4162 4162                  resop = &res.array[numops - 1];
4163 4163                  garp = &resop->nfs_resop4_u.opgetattr.ga_res;
4164 4164          }
4165 4165          /*
4166 4166           * In certain cases, nfs4_update_attrcache() will purge the attrcache,
4167 4167           * rather than filling it.  See the function itself for details.
4168 4168           */
4169 4169          e.error = nfs4_update_attrcache(res.status, garp, t, vp, cr);
4170 4170          if (garp != NULL) {
4171 4171                  if (garp->n4g_resbmap & FATTR4_ACL_MASK) {
4172 4172                          nfs4_acl_fill_cache(rp, &garp->n4g_vsa);
4173 4173                          vs_ace4_destroy(&garp->n4g_vsa);
4174 4174                  } else {
4175 4175                          if (vsap != NULL) {
4176 4176                                  /*
4177 4177                                   * The ACL was supposed to be set and to be
4178 4178                                   * returned in the last getattr of this
4179 4179                                   * compound, but for some reason the getattr
4180 4180                                   * result doesn't contain the ACL.  In this
4181 4181                                   * case, purge the ACL cache.
4182 4182                                   */
4183 4183                                  if (rp->r_secattr != NULL) {
4184 4184                                          mutex_enter(&rp->r_statelock);
4185 4185                                          vsp = rp->r_secattr;
4186 4186                                          rp->r_secattr = NULL;
4187 4187                                          mutex_exit(&rp->r_statelock);
4188 4188                                          if (vsp != NULL)
4189 4189                                                  nfs4_acl_free_cache(vsp);
4190 4190                                  }
4191 4191                          }
4192 4192                  }
4193 4193          }
4194 4194  
4195 4195          if (res.status == NFS4_OK && (mask & AT_SIZE)) {
4196 4196                  /*
4197 4197                   * Set the size, rather than relying on getting it updated
4198 4198                   * via a GETATTR.  With delegations the client tries to
4199 4199                   * suppress GETATTR calls.
4200 4200                   */
4201 4201                  mutex_enter(&rp->r_statelock);
4202 4202                  rp->r_size = vap->va_size;
4203 4203                  mutex_exit(&rp->r_statelock);
4204 4204          }
4205 4205  
4206 4206          /*
4207 4207           * Can free up request args and res
4208 4208           */
4209 4209          nfs4_fattr4_free(&argop[setattr_argop].nfs_argop4_u.
4210 4210              opsetattr.obj_attributes);
4211 4211          if (verify_argop != -1) {
4212 4212                  nfs4args_verify_free(&argop[verify_argop]);
4213 4213                  verify_argop = -1;
4214 4214          }
4215 4215          (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
4216 4216  
4217 4217          /*
4218 4218           * Some servers will change the mode to clear the setuid
4219 4219           * and setgid bits when changing the uid or gid.  The
4220 4220           * client needs to compensate appropriately.
4221 4221           */
4222 4222          if (mask & (AT_UID | AT_GID)) {
4223 4223                  int terror, do_setattr;
4224 4224  
4225 4225                  do_setattr = 0;
4226 4226                  va.va_mask = AT_MODE;
4227 4227                  terror = nfs4getattr(vp, &va, cr);
4228 4228                  if (!terror &&
4229 4229                      (((mask & AT_MODE) && va.va_mode != vap->va_mode) ||
4230 4230                      (!(mask & AT_MODE) && va.va_mode != omode))) {
4231 4231                          va.va_mask = AT_MODE;
4232 4232                          if (mask & AT_MODE) {
4233 4233                                  /*
4234 4234                                   * We asked the mode to be changed and what
4235 4235                                   * we just got from the server in getattr is
4236 4236                                   * not what we wanted it to be, so set it now.
4237 4237                                   */
4238 4238                                  va.va_mode = vap->va_mode;
4239 4239                                  do_setattr = 1;
4240 4240                          } else {
4241 4241                                  /*
4242 4242                                   * We did not ask the mode to be changed,
4243 4243                                   * Check to see that the server just cleared
4244 4244                                   * I_SUID and I_GUID from it. If not then
4245 4245                                   * set mode to omode with UID/GID cleared.
4246 4246                                   */
4247 4247                                  if (nfs4_compare_modes(va.va_mode, omode)) {
4248 4248                                          omode &= ~(S_ISUID|S_ISGID);
4249 4249                                          va.va_mode = omode;
4250 4250                                          do_setattr = 1;
4251 4251                                  }
4252 4252                          }
4253 4253  
4254 4254                          if (do_setattr)
4255 4255                                  (void) nfs4setattr(vp, &va, 0, cr, NULL);
4256 4256                  }
4257 4257          }
4258 4258  
4259 4259          return (e.error);
4260 4260  }
4261 4261  
4262 4262  /* ARGSUSED */
4263 4263  static int
4264 4264  nfs4_access(vnode_t *vp, int mode, int flags, cred_t *cr, caller_context_t *ct)
4265 4265  {
4266 4266          COMPOUND4args_clnt args;
4267 4267          COMPOUND4res_clnt res;
4268 4268          int doqueue;
4269 4269          uint32_t acc, resacc, argacc;
4270 4270          rnode4_t *rp;
4271 4271          cred_t *cred, *ncr, *ncrfree = NULL;
4272 4272          nfs4_access_type_t cacc;
4273 4273          int num_ops;
4274 4274          nfs_argop4 argop[3];
4275 4275          nfs_resop4 *resop;
4276 4276          bool_t needrecov = FALSE, do_getattr;
4277 4277          nfs4_recov_state_t recov_state;
4278 4278          int rpc_error;
4279 4279          hrtime_t t;
4280 4280          nfs4_error_t e = { 0, NFS4_OK, RPC_SUCCESS };
4281 4281          mntinfo4_t *mi = VTOMI4(vp);
4282 4282  
4283 4283          if (nfs_zone() != mi->mi_zone)
4284 4284                  return (EIO);
4285 4285  
4286 4286          acc = 0;
4287 4287          if (mode & VREAD)
4288 4288                  acc |= ACCESS4_READ;
4289 4289          if (mode & VWRITE) {
4290 4290                  if ((vp->v_vfsp->vfs_flag & VFS_RDONLY) && !ISVDEV(vp->v_type))
4291 4291                          return (EROFS);
4292 4292                  if (vp->v_type == VDIR)
4293 4293                          acc |= ACCESS4_DELETE;
4294 4294                  acc |= ACCESS4_MODIFY | ACCESS4_EXTEND;
4295 4295          }
4296 4296          if (mode & VEXEC) {
4297 4297                  if (vp->v_type == VDIR)
4298 4298                          acc |= ACCESS4_LOOKUP;
4299 4299                  else
4300 4300                          acc |= ACCESS4_EXECUTE;
4301 4301          }
4302 4302  
4303 4303          if (VTOR4(vp)->r_acache != NULL) {
4304 4304                  e.error = nfs4_validate_caches(vp, cr);
4305 4305                  if (e.error)
4306 4306                          return (e.error);
4307 4307          }
4308 4308  
4309 4309          rp = VTOR4(vp);
4310 4310          if (vp->v_type == VDIR)
4311 4311                  argacc = ACCESS4_READ | ACCESS4_DELETE | ACCESS4_MODIFY |
4312 4312                      ACCESS4_EXTEND | ACCESS4_LOOKUP;
4313 4313          else
4314 4314                  argacc = ACCESS4_READ | ACCESS4_MODIFY | ACCESS4_EXTEND |
4315 4315                      ACCESS4_EXECUTE;
4316 4316          recov_state.rs_flags = 0;
4317 4317          recov_state.rs_num_retry_despite_err = 0;
4318 4318  
4319 4319          cred = cr;
4320 4320          /*
4321 4321           * ncr and ncrfree both initially
4322 4322           * point to the memory area returned
4323 4323           * by crnetadjust();
4324 4324           * ncrfree not NULL when exiting means
4325 4325           * that we need to release it
4326 4326           */
4327 4327          ncr = crnetadjust(cred);
4328 4328          ncrfree = ncr;
4329 4329  
4330 4330  tryagain:
4331 4331          cacc = nfs4_access_check(rp, acc, cred);
4332 4332          if (cacc == NFS4_ACCESS_ALLOWED) {
4333 4333                  if (ncrfree != NULL)
4334 4334                          crfree(ncrfree);
4335 4335                  return (0);
4336 4336          }
4337 4337          if (cacc == NFS4_ACCESS_DENIED) {
4338 4338                  /*
4339 4339                   * If the cred can be adjusted, try again
4340 4340                   * with the new cred.
4341 4341                   */
4342 4342                  if (ncr != NULL) {
4343 4343                          cred = ncr;
4344 4344                          ncr = NULL;
4345 4345                          goto tryagain;
4346 4346                  }
4347 4347                  if (ncrfree != NULL)
4348 4348                          crfree(ncrfree);
4349 4349                  return (EACCES);
4350 4350          }
4351 4351  
4352 4352  recov_retry:
4353 4353          /*
4354 4354           * Don't take with r_statev4_lock here. r_deleg_type could
4355 4355           * change as soon as lock is released.  Since it is an int,
4356 4356           * there is no atomicity issue.
4357 4357           */
4358 4358          do_getattr = (rp->r_deleg_type == OPEN_DELEGATE_NONE);
4359 4359          num_ops = do_getattr ? 3 : 2;
4360 4360  
4361 4361          args.ctag = TAG_ACCESS;
4362 4362  
4363 4363          args.array_len = num_ops;
4364 4364          args.array = argop;
4365 4365  
4366 4366          if (e.error = nfs4_start_fop(mi, vp, NULL, OH_ACCESS,
4367 4367              &recov_state, NULL)) {
4368 4368                  if (ncrfree != NULL)
4369 4369                          crfree(ncrfree);
4370 4370                  return (e.error);
4371 4371          }
4372 4372  
4373 4373          /* putfh target fh */
4374 4374          argop[0].argop = OP_CPUTFH;
4375 4375          argop[0].nfs_argop4_u.opcputfh.sfh = VTOR4(vp)->r_fh;
4376 4376  
4377 4377          /* access */
4378 4378          argop[1].argop = OP_ACCESS;
4379 4379          argop[1].nfs_argop4_u.opaccess.access = argacc;
4380 4380  
4381 4381          /* getattr */
4382 4382          if (do_getattr) {
4383 4383                  argop[2].argop = OP_GETATTR;
4384 4384                  argop[2].nfs_argop4_u.opgetattr.attr_request = NFS4_VATTR_MASK;
4385 4385                  argop[2].nfs_argop4_u.opgetattr.mi = mi;
4386 4386          }
4387 4387  
4388 4388          NFS4_DEBUG(nfs4_client_call_debug, (CE_NOTE,
4389 4389              "nfs4_access: %s call, rp %s", needrecov ? "recov" : "first",
4390 4390              rnode4info(VTOR4(vp))));
4391 4391  
4392 4392          doqueue = 1;
4393 4393          t = gethrtime();
4394 4394          rfs4call(VTOMI4(vp), &args, &res, cred, &doqueue, 0, &e);
4395 4395          rpc_error = e.error;
4396 4396  
4397 4397          needrecov = nfs4_needs_recovery(&e, FALSE, vp->v_vfsp);
4398 4398          if (needrecov) {
4399 4399                  NFS4_DEBUG(nfs4_client_recov_debug, (CE_NOTE,
4400 4400                      "nfs4_access: initiating recovery\n"));
4401 4401  
4402 4402                  if (nfs4_start_recovery(&e, VTOMI4(vp), vp, NULL, NULL,
4403 4403                      NULL, OP_ACCESS, NULL, NULL, NULL) == FALSE) {
4404 4404                          nfs4_end_fop(VTOMI4(vp), vp, NULL, OH_ACCESS,
4405 4405                              &recov_state, needrecov);
4406 4406                          if (!e.error)
4407 4407                                  (void) xdr_free(xdr_COMPOUND4res_clnt,
4408 4408                                      (caddr_t)&res);
4409 4409                          goto recov_retry;
4410 4410                  }
4411 4411          }
4412 4412          nfs4_end_fop(mi, vp, NULL, OH_ACCESS, &recov_state, needrecov);
4413 4413  
4414 4414          if (e.error)
4415 4415                  goto out;
4416 4416  
4417 4417          if (res.status) {
4418 4418                  e.error = geterrno4(res.status);
4419 4419                  /*
4420 4420                   * This might generate over the wire calls throught
4421 4421                   * nfs4_invalidate_pages. Hence we need to call nfs4_end_op()
4422 4422                   * here to avoid a deadlock.
4423 4423                   */
4424 4424                  nfs4_purge_stale_fh(e.error, vp, cr);
4425 4425                  goto out;
4426 4426          }
4427 4427          resop = &res.array[1];  /* access res */
4428 4428  
4429 4429          resacc = resop->nfs_resop4_u.opaccess.access;
4430 4430  
4431 4431          if (do_getattr) {
4432 4432                  resop++;        /* getattr res */
4433 4433                  nfs4_attr_cache(vp, &resop->nfs_resop4_u.opgetattr.ga_res,
4434 4434                      t, cr, FALSE, NULL);
4435 4435          }
4436 4436  
4437 4437          if (!e.error) {
4438 4438                  nfs4_access_cache(rp, argacc, resacc, cred);
4439 4439                  /*
4440 4440                   * we just cached results with cred; if cred is the
4441 4441                   * adjusted credentials from crnetadjust, we do not want
4442 4442                   * to release them before exiting: hence setting ncrfree
4443 4443                   * to NULL
4444 4444                   */
4445 4445                  if (cred != cr)
4446 4446                          ncrfree = NULL;
4447 4447                  /* XXX check the supported bits too? */
4448 4448                  if ((acc & resacc) != acc) {
4449 4449                          /*
4450 4450                           * The following code implements the semantic
4451 4451                           * that a setuid root program has *at least* the
4452 4452                           * permissions of the user that is running the
4453 4453                           * program.  See rfs3call() for more portions
4454 4454                           * of the implementation of this functionality.
4455 4455                           */
4456 4456                          /* XXX-LP */
4457 4457                          if (ncr != NULL) {
4458 4458                                  (void) xdr_free(xdr_COMPOUND4res_clnt,
4459 4459                                      (caddr_t)&res);
4460 4460                                  cred = ncr;
4461 4461                                  ncr = NULL;
4462 4462                                  goto tryagain;
4463 4463                          }
4464 4464                          e.error = EACCES;
4465 4465                  }
4466 4466          }
4467 4467  
4468 4468  out:
4469 4469          if (!rpc_error)
4470 4470                  (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
4471 4471  
4472 4472          if (ncrfree != NULL)
4473 4473                  crfree(ncrfree);
4474 4474  
4475 4475          return (e.error);
4476 4476  }
4477 4477  
4478 4478  /* ARGSUSED */
4479 4479  static int
4480 4480  nfs4_readlink(vnode_t *vp, struct uio *uiop, cred_t *cr, caller_context_t *ct)
4481 4481  {
4482 4482          COMPOUND4args_clnt args;
4483 4483          COMPOUND4res_clnt res;
4484 4484          int doqueue;
4485 4485          rnode4_t *rp;
4486 4486          nfs_argop4 argop[3];
4487 4487          nfs_resop4 *resop;
4488 4488          READLINK4res *lr_res;
4489 4489          nfs4_ga_res_t *garp;
4490 4490          uint_t len;
4491 4491          char *linkdata;
4492 4492          bool_t needrecov = FALSE;
4493 4493          nfs4_recov_state_t recov_state;
4494 4494          hrtime_t t;
4495 4495          nfs4_error_t e = { 0, NFS4_OK, RPC_SUCCESS };
4496 4496  
4497 4497          if (nfs_zone() != VTOMI4(vp)->mi_zone)
4498 4498                  return (EIO);
4499 4499          /*
4500 4500           * Can't readlink anything other than a symbolic link.
4501 4501           */
4502 4502          if (vp->v_type != VLNK)
4503 4503                  return (EINVAL);
4504 4504  
4505 4505          rp = VTOR4(vp);
4506 4506          if (nfs4_do_symlink_cache && rp->r_symlink.contents != NULL) {
4507 4507                  e.error = nfs4_validate_caches(vp, cr);
4508 4508                  if (e.error)
4509 4509                          return (e.error);
4510 4510                  mutex_enter(&rp->r_statelock);
4511 4511                  if (rp->r_symlink.contents != NULL) {
4512 4512                          e.error = uiomove(rp->r_symlink.contents,
4513 4513                              rp->r_symlink.len, UIO_READ, uiop);
4514 4514                          mutex_exit(&rp->r_statelock);
4515 4515                          return (e.error);
4516 4516                  }
4517 4517                  mutex_exit(&rp->r_statelock);
4518 4518          }
4519 4519          recov_state.rs_flags = 0;
4520 4520          recov_state.rs_num_retry_despite_err = 0;
4521 4521  
4522 4522  recov_retry:
4523 4523          args.array_len = 3;
4524 4524          args.array = argop;
4525 4525          args.ctag = TAG_READLINK;
4526 4526  
4527 4527          e.error = nfs4_start_op(VTOMI4(vp), vp, NULL, &recov_state);
4528 4528          if (e.error) {
4529 4529                  return (e.error);
4530 4530          }
4531 4531  
4532 4532          /* 0. putfh symlink fh */
4533 4533          argop[0].argop = OP_CPUTFH;
4534 4534          argop[0].nfs_argop4_u.opcputfh.sfh = VTOR4(vp)->r_fh;
4535 4535  
4536 4536          /* 1. readlink */
4537 4537          argop[1].argop = OP_READLINK;
4538 4538  
4539 4539          /* 2. getattr */
4540 4540          argop[2].argop = OP_GETATTR;
4541 4541          argop[2].nfs_argop4_u.opgetattr.attr_request = NFS4_VATTR_MASK;
4542 4542          argop[2].nfs_argop4_u.opgetattr.mi = VTOMI4(vp);
4543 4543  
4544 4544          doqueue = 1;
4545 4545  
4546 4546          NFS4_DEBUG(nfs4_client_call_debug, (CE_NOTE,
4547 4547              "nfs4_readlink: %s call, rp %s", needrecov ? "recov" : "first",
4548 4548              rnode4info(VTOR4(vp))));
4549 4549  
4550 4550          t = gethrtime();
4551 4551  
4552 4552          rfs4call(VTOMI4(vp), &args, &res, cr, &doqueue, 0, &e);
4553 4553  
4554 4554          needrecov = nfs4_needs_recovery(&e, FALSE, vp->v_vfsp);
4555 4555          if (needrecov) {
4556 4556                  NFS4_DEBUG(nfs4_client_recov_debug, (CE_NOTE,
4557 4557                      "nfs4_readlink: initiating recovery\n"));
4558 4558  
4559 4559                  if (nfs4_start_recovery(&e, VTOMI4(vp), vp, NULL, NULL,
4560 4560                      NULL, OP_READLINK, NULL, NULL, NULL) == FALSE) {
4561 4561                          if (!e.error)
4562 4562                                  (void) xdr_free(xdr_COMPOUND4res_clnt,
4563 4563                                      (caddr_t)&res);
4564 4564  
4565 4565                          nfs4_end_op(VTOMI4(vp), vp, NULL, &recov_state,
4566 4566                              needrecov);
4567 4567                          goto recov_retry;
4568 4568                  }
4569 4569          }
4570 4570  
4571 4571          nfs4_end_op(VTOMI4(vp), vp, NULL, &recov_state, needrecov);
4572 4572  
4573 4573          if (e.error)
4574 4574                  return (e.error);
4575 4575  
4576 4576          /*
4577 4577           * There is an path in the code below which calls
4578 4578           * nfs4_purge_stale_fh(), which may generate otw calls through
4579 4579           * nfs4_invalidate_pages. Hence we need to call nfs4_end_op()
4580 4580           * here to avoid nfs4_start_op() deadlock.
4581 4581           */
4582 4582  
4583 4583          if (res.status && (res.array_len < args.array_len)) {
4584 4584                  /*
4585 4585                   * either Putfh or Link failed
4586 4586                   */
4587 4587                  e.error = geterrno4(res.status);
4588 4588                  nfs4_purge_stale_fh(e.error, vp, cr);
4589 4589                  (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
4590 4590                  return (e.error);
4591 4591          }
4592 4592  
4593 4593          resop = &res.array[1];  /* readlink res */
4594 4594          lr_res = &resop->nfs_resop4_u.opreadlink;
4595 4595  
4596 4596          /*
4597 4597           * treat symlink names as data
4598 4598           */
4599 4599          linkdata = utf8_to_str((utf8string *)&lr_res->link, &len, NULL);
4600 4600          if (linkdata != NULL) {
4601 4601                  int uio_len = len - 1;
4602 4602                  /* len includes null byte, which we won't uiomove */
4603 4603                  e.error = uiomove(linkdata, uio_len, UIO_READ, uiop);
4604 4604                  if (nfs4_do_symlink_cache && rp->r_symlink.contents == NULL) {
4605 4605                          mutex_enter(&rp->r_statelock);
4606 4606                          if (rp->r_symlink.contents == NULL) {
4607 4607                                  rp->r_symlink.contents = linkdata;
4608 4608                                  rp->r_symlink.len = uio_len;
4609 4609                                  rp->r_symlink.size = len;
4610 4610                                  mutex_exit(&rp->r_statelock);
4611 4611                          } else {
4612 4612                                  mutex_exit(&rp->r_statelock);
4613 4613                                  kmem_free(linkdata, len);
4614 4614                          }
4615 4615                  } else {
4616 4616                          kmem_free(linkdata, len);
4617 4617                  }
4618 4618          }
4619 4619          if (res.status == NFS4_OK) {
4620 4620                  resop++;        /* getattr res */
4621 4621                  garp = &resop->nfs_resop4_u.opgetattr.ga_res;
4622 4622          }
4623 4623          e.error = nfs4_update_attrcache(res.status, garp, t, vp, cr);
4624 4624  
4625 4625          (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
4626 4626  
4627 4627          /*
4628 4628           * The over the wire error for attempting to readlink something
4629 4629           * other than a symbolic link is ENXIO.  However, we need to
4630 4630           * return EINVAL instead of ENXIO, so we map it here.
4631 4631           */
4632 4632          return (e.error == ENXIO ? EINVAL : e.error);
4633 4633  }
4634 4634  
4635 4635  /*
4636 4636   * Flush local dirty pages to stable storage on the server.
4637 4637   *
4638 4638   * If FNODSYNC is specified, then there is nothing to do because
4639 4639   * metadata changes are not cached on the client before being
4640 4640   * sent to the server.
4641 4641   */
4642 4642  /* ARGSUSED */
4643 4643  static int
4644 4644  nfs4_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct)
4645 4645  {
4646 4646          int error;
4647 4647  
4648 4648          if ((syncflag & FNODSYNC) || IS_SWAPVP(vp))
4649 4649                  return (0);
4650 4650          if (nfs_zone() != VTOMI4(vp)->mi_zone)
4651 4651                  return (EIO);
4652 4652          error = nfs4_putpage_commit(vp, (offset_t)0, 0, cr);
4653 4653          if (!error)
4654 4654                  error = VTOR4(vp)->r_error;
4655 4655          return (error);
4656 4656  }
4657 4657  
4658 4658  /*
4659 4659   * Weirdness: if the file was removed or the target of a rename
4660 4660   * operation while it was open, it got renamed instead.  Here we
4661 4661   * remove the renamed file.
4662 4662   */
4663 4663  /* ARGSUSED */
4664 4664  void
4665 4665  nfs4_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
4666 4666  {
4667 4667          rnode4_t *rp;
4668 4668  
4669 4669          ASSERT(vp != DNLC_NO_VNODE);
4670 4670  
4671 4671          rp = VTOR4(vp);
4672 4672  
4673 4673          if (IS_SHADOW(vp, rp)) {
4674 4674                  sv_inactive(vp);
4675 4675                  return;
4676 4676          }
4677 4677  
4678 4678          /*
4679 4679           * If this is coming from the wrong zone, we let someone in the right
4680 4680           * zone take care of it asynchronously.  We can get here due to
4681 4681           * VN_RELE() being called from pageout() or fsflush().  This call may
4682 4682           * potentially turn into an expensive no-op if, for instance, v_count
4683 4683           * gets incremented in the meantime, but it's still correct.
4684 4684           */
4685 4685          if (nfs_zone() != VTOMI4(vp)->mi_zone) {
4686 4686                  nfs4_async_inactive(vp, cr);
4687 4687                  return;
4688 4688          }
4689 4689  
4690 4690          /*
4691 4691           * Some of the cleanup steps might require over-the-wire
4692 4692           * operations.  Since VOP_INACTIVE can get called as a result of
4693 4693           * other over-the-wire operations (e.g., an attribute cache update
4694 4694           * can lead to a DNLC purge), doing those steps now would lead to a
4695 4695           * nested call to the recovery framework, which can deadlock.  So
4696 4696           * do any over-the-wire cleanups asynchronously, in a separate
4697 4697           * thread.
4698 4698           */
4699 4699  
4700 4700          mutex_enter(&rp->r_os_lock);
4701 4701          mutex_enter(&rp->r_statelock);
4702 4702          mutex_enter(&rp->r_statev4_lock);
4703 4703  
4704 4704          if (vp->v_type == VREG && list_head(&rp->r_open_streams) != NULL) {
4705 4705                  mutex_exit(&rp->r_statev4_lock);
4706 4706                  mutex_exit(&rp->r_statelock);
4707 4707                  mutex_exit(&rp->r_os_lock);
4708 4708                  nfs4_async_inactive(vp, cr);
4709 4709                  return;
4710 4710          }
4711 4711  
4712 4712          if (rp->r_deleg_type == OPEN_DELEGATE_READ ||
4713 4713              rp->r_deleg_type == OPEN_DELEGATE_WRITE) {
4714 4714                  mutex_exit(&rp->r_statev4_lock);
4715 4715                  mutex_exit(&rp->r_statelock);
4716 4716                  mutex_exit(&rp->r_os_lock);
4717 4717                  nfs4_async_inactive(vp, cr);
4718 4718                  return;
4719 4719          }
4720 4720  
4721 4721          if (rp->r_unldvp != NULL) {
4722 4722                  mutex_exit(&rp->r_statev4_lock);
4723 4723                  mutex_exit(&rp->r_statelock);
4724 4724                  mutex_exit(&rp->r_os_lock);
4725 4725                  nfs4_async_inactive(vp, cr);
4726 4726                  return;
4727 4727          }
4728 4728          mutex_exit(&rp->r_statev4_lock);
4729 4729          mutex_exit(&rp->r_statelock);
4730 4730          mutex_exit(&rp->r_os_lock);
4731 4731  
4732 4732          rp4_addfree(rp, cr);
4733 4733  }
4734 4734  
4735 4735  /*
4736 4736   * nfs4_inactive_otw - nfs4_inactive, plus over-the-wire calls to free up
4737 4737   * various bits of state.  The caller must not refer to vp after this call.
4738 4738   */
4739 4739  
4740 4740  void
4741 4741  nfs4_inactive_otw(vnode_t *vp, cred_t *cr)
4742 4742  {
4743 4743          rnode4_t *rp = VTOR4(vp);
4744 4744          nfs4_recov_state_t recov_state;
4745 4745          nfs4_error_t e = { 0, NFS4_OK, RPC_SUCCESS };
4746 4746          vnode_t *unldvp;
4747 4747          char *unlname;
4748 4748          cred_t *unlcred;
4749 4749          COMPOUND4args_clnt args;
4750 4750          COMPOUND4res_clnt res, *resp;
4751 4751          nfs_argop4 argop[2];
4752 4752          int doqueue;
4753 4753  #ifdef DEBUG
4754 4754          char *name;
4755 4755  #endif
4756 4756  
4757 4757          ASSERT(nfs_zone() == VTOMI4(vp)->mi_zone);
4758 4758          ASSERT(!IS_SHADOW(vp, rp));
4759 4759  
4760 4760  #ifdef DEBUG
4761 4761          name = fn_name(VTOSV(vp)->sv_name);
4762 4762          NFS4_DEBUG(nfs4_client_inactive_debug, (CE_NOTE, "nfs4_inactive_otw: "
4763 4763              "release vnode %s", name));
4764 4764          kmem_free(name, MAXNAMELEN);
4765 4765  #endif
4766 4766  
4767 4767          if (vp->v_type == VREG) {
4768 4768                  bool_t recov_failed = FALSE;
4769 4769  
4770 4770                  e.error = nfs4close_all(vp, cr);
4771 4771                  if (e.error) {
4772 4772                          /* Check to see if recovery failed */
4773 4773                          mutex_enter(&(VTOMI4(vp)->mi_lock));
4774 4774                          if (VTOMI4(vp)->mi_flags & MI4_RECOV_FAIL)
4775 4775                                  recov_failed = TRUE;
4776 4776                          mutex_exit(&(VTOMI4(vp)->mi_lock));
4777 4777                          if (!recov_failed) {
4778 4778                                  mutex_enter(&rp->r_statelock);
4779 4779                                  if (rp->r_flags & R4RECOVERR)
4780 4780                                          recov_failed = TRUE;
4781 4781                                  mutex_exit(&rp->r_statelock);
4782 4782                          }
4783 4783                          if (recov_failed) {
4784 4784                                  NFS4_DEBUG(nfs4_client_recov_debug,
4785 4785                                      (CE_NOTE, "nfs4_inactive_otw: "
4786 4786                                      "close failed (recovery failure)"));
4787 4787                          }
4788 4788                  }
4789 4789          }
4790 4790  
4791 4791  redo:
4792 4792          if (rp->r_unldvp == NULL) {
4793 4793                  rp4_addfree(rp, cr);
4794 4794                  return;
4795 4795          }
4796 4796  
4797 4797          /*
4798 4798           * Save the vnode pointer for the directory where the
4799 4799           * unlinked-open file got renamed, then set it to NULL
4800 4800           * to prevent another thread from getting here before
4801 4801           * we're done with the remove.  While we have the
4802 4802           * statelock, make local copies of the pertinent rnode
4803 4803           * fields.  If we weren't to do this in an atomic way, the
4804 4804           * the unl* fields could become inconsistent with respect
4805 4805           * to each other due to a race condition between this
4806 4806           * code and nfs_remove().  See bug report 1034328.
4807 4807           */
4808 4808          mutex_enter(&rp->r_statelock);
4809 4809          if (rp->r_unldvp == NULL) {
4810 4810                  mutex_exit(&rp->r_statelock);
4811 4811                  rp4_addfree(rp, cr);
4812 4812                  return;
4813 4813          }
4814 4814  
4815 4815          unldvp = rp->r_unldvp;
4816 4816          rp->r_unldvp = NULL;
4817 4817          unlname = rp->r_unlname;
4818 4818          rp->r_unlname = NULL;
4819 4819          unlcred = rp->r_unlcred;
4820 4820          rp->r_unlcred = NULL;
4821 4821          mutex_exit(&rp->r_statelock);
4822 4822  
4823 4823          /*
4824 4824           * If there are any dirty pages left, then flush
4825 4825           * them.  This is unfortunate because they just
4826 4826           * may get thrown away during the remove operation,
4827 4827           * but we have to do this for correctness.
4828 4828           */
4829 4829          if (nfs4_has_pages(vp) &&
4830 4830              ((rp->r_flags & R4DIRTY) || rp->r_count > 0)) {
4831 4831                  ASSERT(vp->v_type != VCHR);
4832 4832                  e.error = nfs4_putpage(vp, (u_offset_t)0, 0, 0, cr, NULL);
4833 4833                  if (e.error) {
4834 4834                          mutex_enter(&rp->r_statelock);
4835 4835                          if (!rp->r_error)
4836 4836                                  rp->r_error = e.error;
4837 4837                          mutex_exit(&rp->r_statelock);
4838 4838                  }
4839 4839          }
4840 4840  
4841 4841          recov_state.rs_flags = 0;
4842 4842          recov_state.rs_num_retry_despite_err = 0;
4843 4843  recov_retry_remove:
4844 4844          /*
4845 4845           * Do the remove operation on the renamed file
4846 4846           */
4847 4847          args.ctag = TAG_INACTIVE;
4848 4848  
4849 4849          /*
4850 4850           * Remove ops: putfh dir; remove
4851 4851           */
4852 4852          args.array_len = 2;
4853 4853          args.array = argop;
4854 4854  
4855 4855          e.error = nfs4_start_op(VTOMI4(unldvp), unldvp, NULL, &recov_state);
4856 4856          if (e.error) {
4857 4857                  kmem_free(unlname, MAXNAMELEN);
4858 4858                  crfree(unlcred);
4859 4859                  VN_RELE(unldvp);
4860 4860                  /*
4861 4861                   * Try again; this time around r_unldvp will be NULL, so we'll
4862 4862                   * just call rp4_addfree() and return.
4863 4863                   */
4864 4864                  goto redo;
4865 4865          }
4866 4866  
4867 4867          /* putfh directory */
4868 4868          argop[0].argop = OP_CPUTFH;
4869 4869          argop[0].nfs_argop4_u.opcputfh.sfh = VTOR4(unldvp)->r_fh;
4870 4870  
4871 4871          /* remove */
4872 4872          argop[1].argop = OP_CREMOVE;
4873 4873          argop[1].nfs_argop4_u.opcremove.ctarget = unlname;
4874 4874  
4875 4875          doqueue = 1;
4876 4876          resp = &res;
4877 4877  
4878 4878  #if 0 /* notyet */
4879 4879          /*
4880 4880           * Can't do this yet.  We may be being called from
4881 4881           * dnlc_purge_XXX while that routine is holding a
4882 4882           * mutex lock to the nc_rele list.  The calls to
4883 4883           * nfs3_cache_wcc_data may result in calls to
4884 4884           * dnlc_purge_XXX.  This will result in a deadlock.
4885 4885           */
4886 4886          rfs4call(VTOMI4(unldvp), &args, &res, unlcred, &doqueue, 0, &e);
4887 4887          if (e.error) {
4888 4888                  PURGE_ATTRCACHE4(unldvp);
4889 4889                  resp = NULL;
4890 4890          } else if (res.status) {
4891 4891                  e.error = geterrno4(res.status);
4892 4892                  PURGE_ATTRCACHE4(unldvp);
4893 4893                  /*
4894 4894                   * This code is inactive right now
4895 4895                   * but if made active there should
4896 4896                   * be a nfs4_end_op() call before
4897 4897                   * nfs4_purge_stale_fh to avoid start_op()
4898 4898                   * deadlock. See BugId: 4948726
4899 4899                   */
4900 4900                  nfs4_purge_stale_fh(error, unldvp, cr);
4901 4901          } else {
4902 4902                  nfs_resop4 *resop;
4903 4903                  REMOVE4res *rm_res;
4904 4904  
4905 4905                  resop = &res.array[1];
4906 4906                  rm_res = &resop->nfs_resop4_u.opremove;
4907 4907                  /*
4908 4908                   * Update directory cache attribute,
4909 4909                   * readdir and dnlc caches.
4910 4910                   */
4911 4911                  nfs4_update_dircaches(&rm_res->cinfo, unldvp, NULL, NULL, NULL);
4912 4912          }
4913 4913  #else
4914 4914          rfs4call(VTOMI4(unldvp), &args, &res, unlcred, &doqueue, 0, &e);
4915 4915  
4916 4916          PURGE_ATTRCACHE4(unldvp);
4917 4917  #endif
4918 4918  
4919 4919          if (nfs4_needs_recovery(&e, FALSE, unldvp->v_vfsp)) {
4920 4920                  if (nfs4_start_recovery(&e, VTOMI4(unldvp), unldvp, NULL,
4921 4921                      NULL, NULL, OP_REMOVE, NULL, NULL, NULL) == FALSE) {
4922 4922                          if (!e.error)
4923 4923                                  (void) xdr_free(xdr_COMPOUND4res_clnt,
4924 4924                                      (caddr_t)&res);
4925 4925                          nfs4_end_op(VTOMI4(unldvp), unldvp, NULL,
4926 4926                              &recov_state, TRUE);
4927 4927                          goto recov_retry_remove;
4928 4928                  }
4929 4929          }
4930 4930          nfs4_end_op(VTOMI4(unldvp), unldvp, NULL, &recov_state, FALSE);
4931 4931  
4932 4932          /*
4933 4933           * Release stuff held for the remove
4934 4934           */
4935 4935          VN_RELE(unldvp);
4936 4936          if (!e.error && resp)
4937 4937                  (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)resp);
4938 4938  
4939 4939          kmem_free(unlname, MAXNAMELEN);
4940 4940          crfree(unlcred);
4941 4941          goto redo;
4942 4942  }
4943 4943  
4944 4944  /*
4945 4945   * Remote file system operations having to do with directory manipulation.
4946 4946   */
4947 4947  /* ARGSUSED3 */
4948 4948  int
4949 4949  nfs4_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
4950 4950      int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
4951 4951      int *direntflags, pathname_t *realpnp)
4952 4952  {
4953 4953          int error;
4954 4954          vnode_t *vp, *avp = NULL;
4955 4955          rnode4_t *drp;
4956 4956  
4957 4957          *vpp = NULL;
4958 4958          if (nfs_zone() != VTOMI4(dvp)->mi_zone)
4959 4959                  return (EPERM);
4960 4960          /*
4961 4961           * if LOOKUP_XATTR, must replace dvp (object) with
4962 4962           * object's attrdir before continuing with lookup
4963 4963           */
4964 4964          if (flags & LOOKUP_XATTR) {
4965 4965                  error = nfs4lookup_xattr(dvp, nm, &avp, flags, cr);
4966 4966                  if (error)
4967 4967                          return (error);
4968 4968  
4969 4969                  dvp = avp;
4970 4970  
4971 4971                  /*
4972 4972                   * If lookup is for "", just return dvp now.  The attrdir
4973 4973                   * has already been activated (from nfs4lookup_xattr), and
4974 4974                   * the caller will RELE the original dvp -- not
4975 4975                   * the attrdir.  So, set vpp and return.
4976 4976                   * Currently, when the LOOKUP_XATTR flag is
4977 4977                   * passed to VOP_LOOKUP, the name is always empty, and
4978 4978                   * shortcircuiting here avoids 3 unneeded lock/unlock
4979 4979                   * pairs.
4980 4980                   *
4981 4981                   * If a non-empty name was provided, then it is the
4982 4982                   * attribute name, and it will be looked up below.
4983 4983                   */
4984 4984                  if (*nm == '\0') {
4985 4985                          *vpp = dvp;
4986 4986                          return (0);
4987 4987                  }
4988 4988  
4989 4989                  /*
4990 4990                   * The vfs layer never sends a name when asking for the
4991 4991                   * attrdir, so we should never get here (unless of course
4992 4992                   * name is passed at some time in future -- at which time
4993 4993                   * we'll blow up here).
4994 4994                   */
4995 4995                  ASSERT(0);
4996 4996          }
4997 4997  
4998 4998          drp = VTOR4(dvp);
4999 4999          if (nfs_rw_enter_sig(&drp->r_rwlock, RW_READER, INTR4(dvp)))
5000 5000                  return (EINTR);
5001 5001  
5002 5002          error = nfs4lookup(dvp, nm, vpp, cr, 0);
5003 5003          nfs_rw_exit(&drp->r_rwlock);
5004 5004  
5005 5005          /*
5006 5006           * If vnode is a device, create special vnode.
5007 5007           */
5008 5008          if (!error && ISVDEV((*vpp)->v_type)) {
5009 5009                  vp = *vpp;
5010 5010                  *vpp = specvp(vp, vp->v_rdev, vp->v_type, cr);
5011 5011                  VN_RELE(vp);
5012 5012          }
5013 5013  
5014 5014          return (error);
5015 5015  }
5016 5016  
5017 5017  /* ARGSUSED */
5018 5018  static int
5019 5019  nfs4lookup_xattr(vnode_t *dvp, char *nm, vnode_t **vpp, int flags, cred_t *cr)
5020 5020  {
5021 5021          int error;
5022 5022          rnode4_t *drp;
5023 5023          int cflag = ((flags & CREATE_XATTR_DIR) != 0);
5024 5024          mntinfo4_t *mi;
5025 5025  
5026 5026          mi = VTOMI4(dvp);
5027 5027          if (!(mi->mi_vfsp->vfs_flag & VFS_XATTR) &&
5028 5028              !vfs_has_feature(mi->mi_vfsp, VFSFT_SYSATTR_VIEWS))
5029 5029                  return (EINVAL);
5030 5030  
5031 5031          drp = VTOR4(dvp);
5032 5032          if (nfs_rw_enter_sig(&drp->r_rwlock, RW_READER, INTR4(dvp)))
5033 5033                  return (EINTR);
5034 5034  
5035 5035          mutex_enter(&drp->r_statelock);
5036 5036          /*
5037 5037           * If the server doesn't support xattrs just return EINVAL
5038 5038           */
5039 5039          if (drp->r_xattr_dir == NFS4_XATTR_DIR_NOTSUPP) {
5040 5040                  mutex_exit(&drp->r_statelock);
5041 5041                  nfs_rw_exit(&drp->r_rwlock);
5042 5042                  return (EINVAL);
5043 5043          }
5044 5044  
5045 5045          /*
5046 5046           * If there is a cached xattr directory entry,
5047 5047           * use it as long as the attributes are valid. If the
5048 5048           * attributes are not valid, take the simple approach and
5049 5049           * free the cached value and re-fetch a new value.
5050 5050           *
5051 5051           * We don't negative entry cache for now, if we did we
5052 5052           * would need to check if the file has changed on every
5053 5053           * lookup. But xattrs don't exist very often and failing
5054 5054           * an openattr is not much more expensive than and NVERIFY or GETATTR
5055 5055           * so do an openattr over the wire for now.
5056 5056           */
5057 5057          if (drp->r_xattr_dir != NULL) {
5058 5058                  if (ATTRCACHE4_VALID(dvp)) {
5059 5059                          VN_HOLD(drp->r_xattr_dir);
5060 5060                          *vpp = drp->r_xattr_dir;
5061 5061                          mutex_exit(&drp->r_statelock);
5062 5062                          nfs_rw_exit(&drp->r_rwlock);
5063 5063                          return (0);
5064 5064                  }
5065 5065                  VN_RELE(drp->r_xattr_dir);
5066 5066                  drp->r_xattr_dir = NULL;
5067 5067          }
5068 5068          mutex_exit(&drp->r_statelock);
5069 5069  
5070 5070          error = nfs4openattr(dvp, vpp, cflag, cr);
5071 5071  
5072 5072          nfs_rw_exit(&drp->r_rwlock);
5073 5073  
5074 5074          return (error);
5075 5075  }
5076 5076  
5077 5077  static int
5078 5078  nfs4lookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr, int skipdnlc)
5079 5079  {
5080 5080          int error;
5081 5081          rnode4_t *drp;
5082 5082  
5083 5083          ASSERT(nfs_zone() == VTOMI4(dvp)->mi_zone);
5084 5084  
5085 5085          /*
5086 5086           * If lookup is for "", just return dvp.  Don't need
5087 5087           * to send it over the wire, look it up in the dnlc,
5088 5088           * or perform any access checks.
5089 5089           */
5090 5090          if (*nm == '\0') {
5091 5091                  VN_HOLD(dvp);
5092 5092                  *vpp = dvp;
5093 5093                  return (0);
5094 5094          }
5095 5095  
5096 5096          /*
5097 5097           * Can't do lookups in non-directories.
5098 5098           */
5099 5099          if (dvp->v_type != VDIR)
5100 5100                  return (ENOTDIR);
5101 5101  
5102 5102          /*
5103 5103           * If lookup is for ".", just return dvp.  Don't need
5104 5104           * to send it over the wire or look it up in the dnlc,
5105 5105           * just need to check access.
5106 5106           */
5107 5107          if (nm[0] == '.' && nm[1] == '\0') {
5108 5108                  error = nfs4_access(dvp, VEXEC, 0, cr, NULL);
5109 5109                  if (error)
5110 5110                          return (error);
5111 5111                  VN_HOLD(dvp);
5112 5112                  *vpp = dvp;
5113 5113                  return (0);
5114 5114          }
5115 5115  
5116 5116          drp = VTOR4(dvp);
5117 5117          if (!(drp->r_flags & R4LOOKUP)) {
5118 5118                  mutex_enter(&drp->r_statelock);
5119 5119                  drp->r_flags |= R4LOOKUP;
5120 5120                  mutex_exit(&drp->r_statelock);
5121 5121          }
5122 5122  
5123 5123          *vpp = NULL;
5124 5124          /*
5125 5125           * Lookup this name in the DNLC.  If there is no entry
5126 5126           * lookup over the wire.
5127 5127           */
5128 5128          if (!skipdnlc)
5129 5129                  *vpp = dnlc_lookup(dvp, nm);
5130 5130          if (*vpp == NULL) {
5131 5131                  /*
5132 5132                   * We need to go over the wire to lookup the name.
5133 5133                   */
5134 5134                  return (nfs4lookupnew_otw(dvp, nm, vpp, cr));
5135 5135          }
5136 5136  
5137 5137          /*
5138 5138           * We hit on the dnlc
5139 5139           */
5140 5140          if (*vpp != DNLC_NO_VNODE ||
5141 5141              (dvp->v_vfsp->vfs_flag & VFS_RDONLY)) {
5142 5142                  /*
5143 5143                   * But our attrs may not be valid.
5144 5144                   */
5145 5145                  if (ATTRCACHE4_VALID(dvp)) {
5146 5146                          error = nfs4_waitfor_purge_complete(dvp);
5147 5147                          if (error) {
5148 5148                                  VN_RELE(*vpp);
5149 5149                                  *vpp = NULL;
5150 5150                                  return (error);
5151 5151                          }
5152 5152  
5153 5153                          /*
5154 5154                           * If after the purge completes, check to make sure
5155 5155                           * our attrs are still valid.
5156 5156                           */
5157 5157                          if (ATTRCACHE4_VALID(dvp)) {
5158 5158                                  /*
5159 5159                                   * If we waited for a purge we may have
5160 5160                                   * lost our vnode so look it up again.
5161 5161                                   */
5162 5162                                  VN_RELE(*vpp);
5163 5163                                  *vpp = dnlc_lookup(dvp, nm);
5164 5164                                  if (*vpp == NULL)
5165 5165                                          return (nfs4lookupnew_otw(dvp,
5166 5166                                              nm, vpp, cr));
5167 5167  
5168 5168                                  /*
5169 5169                                   * The access cache should almost always hit
5170 5170                                   */
5171 5171                                  error = nfs4_access(dvp, VEXEC, 0, cr, NULL);
5172 5172  
5173 5173                                  if (error) {
5174 5174                                          VN_RELE(*vpp);
5175 5175                                          *vpp = NULL;
5176 5176                                          return (error);
5177 5177                                  }
5178 5178                                  if (*vpp == DNLC_NO_VNODE) {
5179 5179                                          VN_RELE(*vpp);
5180 5180                                          *vpp = NULL;
5181 5181                                          return (ENOENT);
5182 5182                                  }
5183 5183                                  return (0);
5184 5184                          }
5185 5185                  }
5186 5186          }
5187 5187  
5188 5188          ASSERT(*vpp != NULL);
5189 5189  
5190 5190          /*
5191 5191           * We may have gotten here we have one of the following cases:
5192 5192           *      1) vpp != DNLC_NO_VNODE, our attrs have timed out so we
5193 5193           *              need to validate them.
5194 5194           *      2) vpp == DNLC_NO_VNODE, a negative entry that we always
5195 5195           *              must validate.
5196 5196           *
5197 5197           * Go to the server and check if the directory has changed, if
5198 5198           * it hasn't we are done and can use the dnlc entry.
5199 5199           */
5200 5200          return (nfs4lookupvalidate_otw(dvp, nm, vpp, cr));
5201 5201  }
5202 5202  
5203 5203  /*
5204 5204   * Go to the server and check if the directory has changed, if
5205 5205   * it hasn't we are done and can use the dnlc entry.  If it
5206 5206   * has changed we get a new copy of its attributes and check
5207 5207   * the access for VEXEC, then relookup the filename and
5208 5208   * get its filehandle and attributes.
5209 5209   *
5210 5210   * PUTFH dfh NVERIFY GETATTR ACCESS LOOKUP GETFH GETATTR
5211 5211   *      if the NVERIFY failed we must
5212 5212   *              purge the caches
5213 5213   *              cache new attributes (will set r_time_attr_inval)
5214 5214   *              cache new access
5215 5215   *              recheck VEXEC access
5216 5216   *              add name to dnlc, possibly negative
5217 5217   *              if LOOKUP succeeded
5218 5218   *                      cache new attributes
5219 5219   *      else
5220 5220   *              set a new r_time_attr_inval for dvp
5221 5221   *              check to make sure we have access
5222 5222   *
5223 5223   * The vpp returned is the vnode passed in if the directory is valid,
5224 5224   * a new vnode if successful lookup, or NULL on error.
5225 5225   */
5226 5226  static int
5227 5227  nfs4lookupvalidate_otw(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr)
5228 5228  {
5229 5229          COMPOUND4args_clnt args;
5230 5230          COMPOUND4res_clnt res;
5231 5231          fattr4 *ver_fattr;
5232 5232          fattr4_change dchange;
5233 5233          int32_t *ptr;
5234 5234          int argoplist_size  = 7 * sizeof (nfs_argop4);
5235 5235          nfs_argop4 *argop;
5236 5236          int doqueue;
5237 5237          mntinfo4_t *mi;
5238 5238          nfs4_recov_state_t recov_state;
5239 5239          hrtime_t t;
5240 5240          int isdotdot;
5241 5241          vnode_t *nvp;
5242 5242          nfs_fh4 *fhp;
5243 5243          nfs4_sharedfh_t *sfhp;
5244 5244          nfs4_access_type_t cacc;
5245 5245          rnode4_t *nrp;
5246 5246          rnode4_t *drp = VTOR4(dvp);
5247 5247          nfs4_ga_res_t *garp = NULL;
5248 5248          nfs4_error_t e = { 0, NFS4_OK, RPC_SUCCESS };
5249 5249  
5250 5250          ASSERT(nfs_zone() == VTOMI4(dvp)->mi_zone);
5251 5251          ASSERT(nm != NULL);
5252 5252          ASSERT(nm[0] != '\0');
5253 5253          ASSERT(dvp->v_type == VDIR);
5254 5254          ASSERT(nm[0] != '.' || nm[1] != '\0');
5255 5255          ASSERT(*vpp != NULL);
5256 5256  
5257 5257          if (nm[0] == '.' && nm[1] == '.' && nm[2] == '\0') {
5258 5258                  isdotdot = 1;
5259 5259                  args.ctag = TAG_LOOKUP_VPARENT;
5260 5260          } else {
5261 5261                  /*
5262 5262                   * If dvp were a stub, it should have triggered and caused
5263 5263                   * a mount for us to get this far.
5264 5264                   */
5265 5265                  ASSERT(!RP_ISSTUB(VTOR4(dvp)));
5266 5266  
5267 5267                  isdotdot = 0;
5268 5268                  args.ctag = TAG_LOOKUP_VALID;
5269 5269          }
5270 5270  
5271 5271          mi = VTOMI4(dvp);
5272 5272          recov_state.rs_flags = 0;
5273 5273          recov_state.rs_num_retry_despite_err = 0;
5274 5274  
5275 5275          nvp = NULL;
5276 5276  
5277 5277          /* Save the original mount point security information */
5278 5278          (void) save_mnt_secinfo(mi->mi_curr_serv);
5279 5279  
5280 5280  recov_retry:
5281 5281          e.error = nfs4_start_fop(mi, dvp, NULL, OH_LOOKUP,
5282 5282              &recov_state, NULL);
5283 5283          if (e.error) {
5284 5284                  (void) check_mnt_secinfo(mi->mi_curr_serv, nvp);
5285 5285                  VN_RELE(*vpp);
5286 5286                  *vpp = NULL;
5287 5287                  return (e.error);
5288 5288          }
5289 5289  
5290 5290          argop = kmem_alloc(argoplist_size, KM_SLEEP);
5291 5291  
5292 5292          /* PUTFH dfh NVERIFY GETATTR ACCESS LOOKUP GETFH GETATTR */
5293 5293          args.array_len = 7;
5294 5294          args.array = argop;
5295 5295  
5296 5296          /* 0. putfh file */
5297 5297          argop[0].argop = OP_CPUTFH;
5298 5298          argop[0].nfs_argop4_u.opcputfh.sfh = VTOR4(dvp)->r_fh;
5299 5299  
5300 5300          /* 1. nverify the change info */
5301 5301          argop[1].argop = OP_NVERIFY;
5302 5302          ver_fattr = &argop[1].nfs_argop4_u.opnverify.obj_attributes;
5303 5303          ver_fattr->attrmask = FATTR4_CHANGE_MASK;
5304 5304          ver_fattr->attrlist4 = (char *)&dchange;
5305 5305          ptr = (int32_t *)&dchange;
5306 5306          IXDR_PUT_HYPER(ptr, VTOR4(dvp)->r_change);
5307 5307          ver_fattr->attrlist4_len = sizeof (fattr4_change);
5308 5308  
5309 5309          /* 2. getattr directory */
5310 5310          argop[2].argop = OP_GETATTR;
5311 5311          argop[2].nfs_argop4_u.opgetattr.attr_request = NFS4_VATTR_MASK;
5312 5312          argop[2].nfs_argop4_u.opgetattr.mi = VTOMI4(dvp);
5313 5313  
5314 5314          /* 3. access directory */
5315 5315          argop[3].argop = OP_ACCESS;
5316 5316          argop[3].nfs_argop4_u.opaccess.access = ACCESS4_READ | ACCESS4_DELETE |
5317 5317              ACCESS4_MODIFY | ACCESS4_EXTEND | ACCESS4_LOOKUP;
5318 5318  
5319 5319          /* 4. lookup name */
5320 5320          if (isdotdot) {
5321 5321                  argop[4].argop = OP_LOOKUPP;
5322 5322          } else {
5323 5323                  argop[4].argop = OP_CLOOKUP;
5324 5324                  argop[4].nfs_argop4_u.opclookup.cname = nm;
5325 5325          }
5326 5326  
5327 5327          /* 5. resulting file handle */
5328 5328          argop[5].argop = OP_GETFH;
5329 5329  
5330 5330          /* 6. resulting file attributes */
5331 5331          argop[6].argop = OP_GETATTR;
5332 5332          argop[6].nfs_argop4_u.opgetattr.attr_request = NFS4_VATTR_MASK;
5333 5333          argop[6].nfs_argop4_u.opgetattr.mi = VTOMI4(dvp);
5334 5334  
5335 5335          doqueue = 1;
5336 5336          t = gethrtime();
5337 5337  
5338 5338          rfs4call(VTOMI4(dvp), &args, &res, cr, &doqueue, 0, &e);
5339 5339  
5340 5340          if (!isdotdot && res.status == NFS4ERR_MOVED) {
5341 5341                  e.error = nfs4_setup_referral(dvp, nm, vpp, cr);
5342 5342                  if (e.error != 0 && *vpp != NULL)
5343 5343                          VN_RELE(*vpp);
5344 5344                  nfs4_end_fop(mi, dvp, NULL, OH_LOOKUP,
5345 5345                      &recov_state, FALSE);
5346 5346                  (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
5347 5347                  kmem_free(argop, argoplist_size);
5348 5348                  return (e.error);
5349 5349          }
5350 5350  
5351 5351          if (nfs4_needs_recovery(&e, FALSE, dvp->v_vfsp)) {
5352 5352                  /*
5353 5353                   * For WRONGSEC of a non-dotdot case, send secinfo directly
5354 5354                   * from this thread, do not go thru the recovery thread since
5355 5355                   * we need the nm information.
5356 5356                   *
5357 5357                   * Not doing dotdot case because there is no specification
5358 5358                   * for (PUTFH, SECINFO "..") yet.
5359 5359                   */
5360 5360                  if (!isdotdot && res.status == NFS4ERR_WRONGSEC) {
5361 5361                          if ((e.error = nfs4_secinfo_vnode_otw(dvp, nm, cr)))
5362 5362                                  nfs4_end_fop(mi, dvp, NULL, OH_LOOKUP,
5363 5363                                      &recov_state, FALSE);
5364 5364                          else
5365 5365                                  nfs4_end_fop(mi, dvp, NULL, OH_LOOKUP,
5366 5366                                      &recov_state, TRUE);
5367 5367                          (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
5368 5368                          kmem_free(argop, argoplist_size);
5369 5369                          if (!e.error)
5370 5370                                  goto recov_retry;
5371 5371                          (void) check_mnt_secinfo(mi->mi_curr_serv, nvp);
5372 5372                          VN_RELE(*vpp);
5373 5373                          *vpp = NULL;
5374 5374                          return (e.error);
5375 5375                  }
5376 5376  
5377 5377                  if (nfs4_start_recovery(&e, mi, dvp, NULL, NULL, NULL,
5378 5378                      OP_LOOKUP, NULL, NULL, NULL) == FALSE) {
5379 5379                          nfs4_end_fop(mi, dvp, NULL, OH_LOOKUP,
5380 5380                              &recov_state, TRUE);
5381 5381  
5382 5382                          (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
5383 5383                          kmem_free(argop, argoplist_size);
5384 5384                          goto recov_retry;
5385 5385                  }
5386 5386          }
5387 5387  
5388 5388          nfs4_end_fop(mi, dvp, NULL, OH_LOOKUP, &recov_state, FALSE);
5389 5389  
5390 5390          if (e.error || res.array_len == 0) {
5391 5391                  /*
5392 5392                   * If e.error isn't set, then reply has no ops (or we couldn't
5393 5393                   * be here).  The only legal way to reply without an op array
5394 5394                   * is via NFS4ERR_MINOR_VERS_MISMATCH.  An ops array should
5395 5395                   * be in the reply for all other status values.
5396 5396                   *
5397 5397                   * For valid replies without an ops array, return ENOTSUP
5398 5398                   * (geterrno4 xlation of VERS_MISMATCH).  For illegal replies,
5399 5399                   * return EIO -- don't trust status.
5400 5400                   */
5401 5401                  if (e.error == 0)
5402 5402                          e.error = (res.status == NFS4ERR_MINOR_VERS_MISMATCH) ?
5403 5403                              ENOTSUP : EIO;
5404 5404                  VN_RELE(*vpp);
5405 5405                  *vpp = NULL;
5406 5406                  kmem_free(argop, argoplist_size);
5407 5407                  (void) check_mnt_secinfo(mi->mi_curr_serv, nvp);
5408 5408                  return (e.error);
5409 5409          }
5410 5410  
5411 5411          if (res.status != NFS4ERR_SAME) {
5412 5412                  e.error = geterrno4(res.status);
5413 5413  
5414 5414                  /*
5415 5415                   * The NVERIFY "failed" so the directory has changed
5416 5416                   * First make sure PUTFH succeeded and NVERIFY "failed"
5417 5417                   * cleanly.
5418 5418                   */
5419 5419                  if ((res.array[0].nfs_resop4_u.opputfh.status != NFS4_OK) ||
5420 5420                      (res.array[1].nfs_resop4_u.opnverify.status != NFS4_OK)) {
5421 5421                          nfs4_purge_stale_fh(e.error, dvp, cr);
5422 5422                          VN_RELE(*vpp);
5423 5423                          *vpp = NULL;
5424 5424                          goto exit;
5425 5425                  }
5426 5426  
5427 5427                  /*
5428 5428                   * We know the NVERIFY "failed" so we must:
5429 5429                   *      purge the caches (access and indirectly dnlc if needed)
5430 5430                   */
5431 5431                  nfs4_purge_caches(dvp, NFS4_NOPURGE_DNLC, cr, TRUE);
5432 5432  
5433 5433                  if (res.array[2].nfs_resop4_u.opgetattr.status != NFS4_OK) {
5434 5434                          nfs4_purge_stale_fh(e.error, dvp, cr);
5435 5435                          VN_RELE(*vpp);
5436 5436                          *vpp = NULL;
5437 5437                          goto exit;
5438 5438                  }
5439 5439  
5440 5440                  /*
5441 5441                   * Install new cached attributes for the directory
5442 5442                   */
5443 5443                  nfs4_attr_cache(dvp,
5444 5444                      &res.array[2].nfs_resop4_u.opgetattr.ga_res,
5445 5445                      t, cr, FALSE, NULL);
5446 5446  
5447 5447                  if (res.array[3].nfs_resop4_u.opaccess.status != NFS4_OK) {
5448 5448                          nfs4_purge_stale_fh(e.error, dvp, cr);
5449 5449                          VN_RELE(*vpp);
5450 5450                          *vpp = NULL;
5451 5451                          e.error = geterrno4(res.status);
5452 5452                          goto exit;
5453 5453                  }
5454 5454  
5455 5455                  /*
5456 5456                   * Now we know the directory is valid,
5457 5457                   * cache new directory access
5458 5458                   */
5459 5459                  nfs4_access_cache(drp,
5460 5460                      args.array[3].nfs_argop4_u.opaccess.access,
5461 5461                      res.array[3].nfs_resop4_u.opaccess.access, cr);
5462 5462  
5463 5463                  /*
5464 5464                   * recheck VEXEC access
5465 5465                   */
5466 5466                  cacc = nfs4_access_check(drp, ACCESS4_LOOKUP, cr);
5467 5467                  if (cacc != NFS4_ACCESS_ALLOWED) {
5468 5468                          /*
5469 5469                           * Directory permissions might have been revoked
5470 5470                           */
5471 5471                          if (cacc == NFS4_ACCESS_DENIED) {
5472 5472                                  e.error = EACCES;
5473 5473                                  VN_RELE(*vpp);
5474 5474                                  *vpp = NULL;
5475 5475                                  goto exit;
5476 5476                          }
5477 5477  
5478 5478                          /*
5479 5479                           * Somehow we must not have asked for enough
5480 5480                           * so try a singleton ACCESS, should never happen.
5481 5481                           */
5482 5482                          e.error = nfs4_access(dvp, VEXEC, 0, cr, NULL);
5483 5483                          if (e.error) {
5484 5484                                  VN_RELE(*vpp);
5485 5485                                  *vpp = NULL;
5486 5486                                  goto exit;
5487 5487                          }
5488 5488                  }
5489 5489  
5490 5490                  e.error = geterrno4(res.status);
5491 5491                  if (res.array[4].nfs_resop4_u.oplookup.status != NFS4_OK) {
5492 5492                          /*
5493 5493                           * The lookup failed, probably no entry
5494 5494                           */
5495 5495                          if (e.error == ENOENT && nfs4_lookup_neg_cache) {
5496 5496                                  dnlc_update(dvp, nm, DNLC_NO_VNODE);
5497 5497                          } else {
5498 5498                                  /*
5499 5499                                   * Might be some other error, so remove
5500 5500                                   * the dnlc entry to make sure we start all
5501 5501                                   * over again, next time.
5502 5502                                   */
5503 5503                                  dnlc_remove(dvp, nm);
5504 5504                          }
5505 5505                          VN_RELE(*vpp);
5506 5506                          *vpp = NULL;
5507 5507                          goto exit;
5508 5508                  }
5509 5509  
5510 5510                  if (res.array[5].nfs_resop4_u.opgetfh.status != NFS4_OK) {
5511 5511                          /*
5512 5512                           * The file exists but we can't get its fh for
5513 5513                           * some unknown reason.  Remove it from the dnlc
5514 5514                           * and error out to be safe.
5515 5515                           */
5516 5516                          dnlc_remove(dvp, nm);
5517 5517                          VN_RELE(*vpp);
5518 5518                          *vpp = NULL;
5519 5519                          goto exit;
5520 5520                  }
5521 5521                  fhp = &res.array[5].nfs_resop4_u.opgetfh.object;
5522 5522                  if (fhp->nfs_fh4_len == 0) {
5523 5523                          /*
5524 5524                           * The file exists but a bogus fh
5525 5525                           * some unknown reason.  Remove it from the dnlc
5526 5526                           * and error out to be safe.
5527 5527                           */
5528 5528                          e.error = ENOENT;
5529 5529                          dnlc_remove(dvp, nm);
5530 5530                          VN_RELE(*vpp);
5531 5531                          *vpp = NULL;
5532 5532                          goto exit;
5533 5533                  }
5534 5534                  sfhp = sfh4_get(fhp, mi);
5535 5535  
5536 5536                  if (res.array[6].nfs_resop4_u.opgetattr.status == NFS4_OK)
5537 5537                          garp = &res.array[6].nfs_resop4_u.opgetattr.ga_res;
5538 5538  
5539 5539                  /*
5540 5540                   * Make the new rnode
5541 5541                   */
5542 5542                  if (isdotdot) {
5543 5543                          e.error = nfs4_make_dotdot(sfhp, t, dvp, cr, &nvp, 1);
5544 5544                          if (e.error) {
5545 5545                                  sfh4_rele(&sfhp);
5546 5546                                  VN_RELE(*vpp);
5547 5547                                  *vpp = NULL;
5548 5548                                  goto exit;
5549 5549                          }
5550 5550                          /*
5551 5551                           * XXX if nfs4_make_dotdot uses an existing rnode
5552 5552                           * XXX it doesn't update the attributes.
5553 5553                           * XXX for now just save them again to save an OTW
5554 5554                           */
5555 5555                          nfs4_attr_cache(nvp, garp, t, cr, FALSE, NULL);
5556 5556                  } else {
5557 5557                          nvp = makenfs4node(sfhp, garp, dvp->v_vfsp, t, cr,
5558 5558                              dvp, fn_get(VTOSV(dvp)->sv_name, nm, sfhp));
5559 5559                          /*
5560 5560                           * If v_type == VNON, then garp was NULL because
5561 5561                           * the last op in the compound failed and makenfs4node
5562 5562                           * could not find the vnode for sfhp. It created
5563 5563                           * a new vnode, so we have nothing to purge here.
5564 5564                           */
5565 5565                          if (nvp->v_type == VNON) {
5566 5566                                  vattr_t vattr;
5567 5567  
5568 5568                                  vattr.va_mask = AT_TYPE;
5569 5569                                  /*
5570 5570                                   * N.B. We've already called nfs4_end_fop above.
5571 5571                                   */
5572 5572                                  e.error = nfs4getattr(nvp, &vattr, cr);
5573 5573                                  if (e.error) {
5574 5574                                          sfh4_rele(&sfhp);
5575 5575                                          VN_RELE(*vpp);
5576 5576                                          *vpp = NULL;
5577 5577                                          VN_RELE(nvp);
5578 5578                                          goto exit;
5579 5579                                  }
5580 5580                                  nvp->v_type = vattr.va_type;
5581 5581                          }
5582 5582                  }
5583 5583                  sfh4_rele(&sfhp);
5584 5584  
5585 5585                  nrp = VTOR4(nvp);
5586 5586                  mutex_enter(&nrp->r_statev4_lock);
5587 5587                  if (!nrp->created_v4) {
5588 5588                          mutex_exit(&nrp->r_statev4_lock);
5589 5589                          dnlc_update(dvp, nm, nvp);
5590 5590                  } else
5591 5591                          mutex_exit(&nrp->r_statev4_lock);
5592 5592  
5593 5593                  VN_RELE(*vpp);
5594 5594                  *vpp = nvp;
5595 5595          } else {
5596 5596                  hrtime_t now;
5597 5597                  hrtime_t delta = 0;
5598 5598  
5599 5599                  e.error = 0;
5600 5600  
5601 5601                  /*
5602 5602                   * Because the NVERIFY "succeeded" we know that the
5603 5603                   * directory attributes are still valid
5604 5604                   * so update r_time_attr_inval
5605 5605                   */
5606 5606                  now = gethrtime();
5607 5607                  mutex_enter(&drp->r_statelock);
5608 5608                  if (!(mi->mi_flags & MI4_NOAC) && !(dvp->v_flag & VNOCACHE)) {
5609 5609                          delta = now - drp->r_time_attr_saved;
5610 5610                          if (delta < mi->mi_acdirmin)
5611 5611                                  delta = mi->mi_acdirmin;
5612 5612                          else if (delta > mi->mi_acdirmax)
5613 5613                                  delta = mi->mi_acdirmax;
5614 5614                  }
5615 5615                  drp->r_time_attr_inval = now + delta;
5616 5616                  mutex_exit(&drp->r_statelock);
5617 5617                  dnlc_update(dvp, nm, *vpp);
5618 5618  
5619 5619                  /*
5620 5620                   * Even though we have a valid directory attr cache
5621 5621                   * and dnlc entry, we may not have access.
5622 5622                   * This should almost always hit the cache.
5623 5623                   */
5624 5624                  e.error = nfs4_access(dvp, VEXEC, 0, cr, NULL);
5625 5625                  if (e.error) {
5626 5626                          VN_RELE(*vpp);
5627 5627                          *vpp = NULL;
5628 5628                  }
5629 5629  
5630 5630                  if (*vpp == DNLC_NO_VNODE) {
5631 5631                          VN_RELE(*vpp);
5632 5632                          *vpp = NULL;
5633 5633                          e.error = ENOENT;
5634 5634                  }
5635 5635          }
5636 5636  
5637 5637  exit:
5638 5638          (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
5639 5639          kmem_free(argop, argoplist_size);
5640 5640          (void) check_mnt_secinfo(mi->mi_curr_serv, nvp);
5641 5641          return (e.error);
5642 5642  }
5643 5643  
5644 5644  /*
5645 5645   * We need to go over the wire to lookup the name, but
5646 5646   * while we are there verify the directory has not
5647 5647   * changed but if it has, get new attributes and check access
5648 5648   *
5649 5649   * PUTFH dfh SAVEFH LOOKUP nm GETFH GETATTR RESTOREFH
5650 5650   *                                      NVERIFY GETATTR ACCESS
5651 5651   *
5652 5652   * With the results:
5653 5653   *      if the NVERIFY failed we must purge the caches, add new attributes,
5654 5654   *              and cache new access.
5655 5655   *      set a new r_time_attr_inval
5656 5656   *      add name to dnlc, possibly negative
5657 5657   *      if LOOKUP succeeded
5658 5658   *              cache new attributes
5659 5659   */
5660 5660  static int
5661 5661  nfs4lookupnew_otw(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr)
5662 5662  {
5663 5663          COMPOUND4args_clnt args;
5664 5664          COMPOUND4res_clnt res;
5665 5665          fattr4 *ver_fattr;
5666 5666          fattr4_change dchange;
5667 5667          int32_t *ptr;
5668 5668          nfs4_ga_res_t *garp = NULL;
5669 5669          int argoplist_size  = 9 * sizeof (nfs_argop4);
5670 5670          nfs_argop4 *argop;
5671 5671          int doqueue;
5672 5672          mntinfo4_t *mi;
5673 5673          nfs4_recov_state_t recov_state;
5674 5674          hrtime_t t;
5675 5675          int isdotdot;
5676 5676          vnode_t *nvp;
5677 5677          nfs_fh4 *fhp;
5678 5678          nfs4_sharedfh_t *sfhp;
5679 5679          nfs4_access_type_t cacc;
5680 5680          rnode4_t *nrp;
5681 5681          rnode4_t *drp = VTOR4(dvp);
5682 5682          nfs4_error_t e = { 0, NFS4_OK, RPC_SUCCESS };
5683 5683  
5684 5684          ASSERT(nfs_zone() == VTOMI4(dvp)->mi_zone);
5685 5685          ASSERT(nm != NULL);
5686 5686          ASSERT(nm[0] != '\0');
5687 5687          ASSERT(dvp->v_type == VDIR);
5688 5688          ASSERT(nm[0] != '.' || nm[1] != '\0');
5689 5689          ASSERT(*vpp == NULL);
5690 5690  
5691 5691          if (nm[0] == '.' && nm[1] == '.' && nm[2] == '\0') {
5692 5692                  isdotdot = 1;
5693 5693                  args.ctag = TAG_LOOKUP_PARENT;
5694 5694          } else {
5695 5695                  /*
5696 5696                   * If dvp were a stub, it should have triggered and caused
5697 5697                   * a mount for us to get this far.
5698 5698                   */
5699 5699                  ASSERT(!RP_ISSTUB(VTOR4(dvp)));
5700 5700  
5701 5701                  isdotdot = 0;
5702 5702                  args.ctag = TAG_LOOKUP;
5703 5703          }
5704 5704  
5705 5705          mi = VTOMI4(dvp);
5706 5706          recov_state.rs_flags = 0;
5707 5707          recov_state.rs_num_retry_despite_err = 0;
5708 5708  
5709 5709          nvp = NULL;
5710 5710  
5711 5711          /* Save the original mount point security information */
5712 5712          (void) save_mnt_secinfo(mi->mi_curr_serv);
5713 5713  
5714 5714  recov_retry:
5715 5715          e.error = nfs4_start_fop(mi, dvp, NULL, OH_LOOKUP,
5716 5716              &recov_state, NULL);
5717 5717          if (e.error) {
5718 5718                  (void) check_mnt_secinfo(mi->mi_curr_serv, nvp);
5719 5719                  return (e.error);
5720 5720          }
5721 5721  
5722 5722          argop = kmem_alloc(argoplist_size, KM_SLEEP);
5723 5723  
5724 5724          /* PUTFH SAVEFH LOOKUP GETFH GETATTR RESTOREFH NVERIFY GETATTR ACCESS */
5725 5725          args.array_len = 9;
5726 5726          args.array = argop;
5727 5727  
5728 5728          /* 0. putfh file */
5729 5729          argop[0].argop = OP_CPUTFH;
5730 5730          argop[0].nfs_argop4_u.opcputfh.sfh = VTOR4(dvp)->r_fh;
5731 5731  
5732 5732          /* 1. savefh for the nverify */
5733 5733          argop[1].argop = OP_SAVEFH;
5734 5734  
5735 5735          /* 2. lookup name */
5736 5736          if (isdotdot) {
5737 5737                  argop[2].argop = OP_LOOKUPP;
5738 5738          } else {
5739 5739                  argop[2].argop = OP_CLOOKUP;
5740 5740                  argop[2].nfs_argop4_u.opclookup.cname = nm;
5741 5741          }
5742 5742  
5743 5743          /* 3. resulting file handle */
5744 5744          argop[3].argop = OP_GETFH;
5745 5745  
5746 5746          /* 4. resulting file attributes */
5747 5747          argop[4].argop = OP_GETATTR;
5748 5748          argop[4].nfs_argop4_u.opgetattr.attr_request = NFS4_VATTR_MASK;
5749 5749          argop[4].nfs_argop4_u.opgetattr.mi = VTOMI4(dvp);
5750 5750  
5751 5751          /* 5. restorefh back the directory for the nverify */
5752 5752          argop[5].argop = OP_RESTOREFH;
5753 5753  
5754 5754          /* 6. nverify the change info */
5755 5755          argop[6].argop = OP_NVERIFY;
5756 5756          ver_fattr = &argop[6].nfs_argop4_u.opnverify.obj_attributes;
5757 5757          ver_fattr->attrmask = FATTR4_CHANGE_MASK;
5758 5758          ver_fattr->attrlist4 = (char *)&dchange;
5759 5759          ptr = (int32_t *)&dchange;
5760 5760          IXDR_PUT_HYPER(ptr, VTOR4(dvp)->r_change);
5761 5761          ver_fattr->attrlist4_len = sizeof (fattr4_change);
5762 5762  
5763 5763          /* 7. getattr directory */
5764 5764          argop[7].argop = OP_GETATTR;
5765 5765          argop[7].nfs_argop4_u.opgetattr.attr_request = NFS4_VATTR_MASK;
5766 5766          argop[7].nfs_argop4_u.opgetattr.mi = VTOMI4(dvp);
5767 5767  
5768 5768          /* 8. access directory */
5769 5769          argop[8].argop = OP_ACCESS;
5770 5770          argop[8].nfs_argop4_u.opaccess.access = ACCESS4_READ | ACCESS4_DELETE |
5771 5771              ACCESS4_MODIFY | ACCESS4_EXTEND | ACCESS4_LOOKUP;
5772 5772  
5773 5773          doqueue = 1;
5774 5774          t = gethrtime();
5775 5775  
5776 5776          rfs4call(VTOMI4(dvp), &args, &res, cr, &doqueue, 0, &e);
5777 5777  
5778 5778          if (!isdotdot && res.status == NFS4ERR_MOVED) {
5779 5779                  e.error = nfs4_setup_referral(dvp, nm, vpp, cr);
5780 5780                  if (e.error != 0 && *vpp != NULL)
5781 5781                          VN_RELE(*vpp);
5782 5782                  nfs4_end_fop(mi, dvp, NULL, OH_LOOKUP,
5783 5783                      &recov_state, FALSE);
5784 5784                  (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
5785 5785                  kmem_free(argop, argoplist_size);
5786 5786                  return (e.error);
5787 5787          }
5788 5788  
5789 5789          if (nfs4_needs_recovery(&e, FALSE, dvp->v_vfsp)) {
5790 5790                  /*
5791 5791                   * For WRONGSEC of a non-dotdot case, send secinfo directly
5792 5792                   * from this thread, do not go thru the recovery thread since
5793 5793                   * we need the nm information.
5794 5794                   *
5795 5795                   * Not doing dotdot case because there is no specification
5796 5796                   * for (PUTFH, SECINFO "..") yet.
5797 5797                   */
5798 5798                  if (!isdotdot && res.status == NFS4ERR_WRONGSEC) {
5799 5799                          if ((e.error = nfs4_secinfo_vnode_otw(dvp, nm, cr)))
5800 5800                                  nfs4_end_fop(mi, dvp, NULL, OH_LOOKUP,
5801 5801                                      &recov_state, FALSE);
5802 5802                          else
5803 5803                                  nfs4_end_fop(mi, dvp, NULL, OH_LOOKUP,
5804 5804                                      &recov_state, TRUE);
5805 5805                          (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
5806 5806                          kmem_free(argop, argoplist_size);
5807 5807                          if (!e.error)
5808 5808                                  goto recov_retry;
5809 5809                          (void) check_mnt_secinfo(mi->mi_curr_serv, nvp);
5810 5810                          return (e.error);
5811 5811                  }
5812 5812  
5813 5813                  if (nfs4_start_recovery(&e, mi, dvp, NULL, NULL, NULL,
5814 5814                      OP_LOOKUP, NULL, NULL, NULL) == FALSE) {
5815 5815                          nfs4_end_fop(mi, dvp, NULL, OH_LOOKUP,
5816 5816                              &recov_state, TRUE);
5817 5817  
5818 5818                          (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
5819 5819                          kmem_free(argop, argoplist_size);
5820 5820                          goto recov_retry;
5821 5821                  }
5822 5822          }
5823 5823  
5824 5824          nfs4_end_fop(mi, dvp, NULL, OH_LOOKUP, &recov_state, FALSE);
5825 5825  
5826 5826          if (e.error || res.array_len == 0) {
5827 5827                  /*
5828 5828                   * If e.error isn't set, then reply has no ops (or we couldn't
5829 5829                   * be here).  The only legal way to reply without an op array
5830 5830                   * is via NFS4ERR_MINOR_VERS_MISMATCH.  An ops array should
5831 5831                   * be in the reply for all other status values.
5832 5832                   *
5833 5833                   * For valid replies without an ops array, return ENOTSUP
5834 5834                   * (geterrno4 xlation of VERS_MISMATCH).  For illegal replies,
5835 5835                   * return EIO -- don't trust status.
5836 5836                   */
5837 5837                  if (e.error == 0)
5838 5838                          e.error = (res.status == NFS4ERR_MINOR_VERS_MISMATCH) ?
5839 5839                              ENOTSUP : EIO;
5840 5840  
5841 5841                  kmem_free(argop, argoplist_size);
5842 5842                  (void) check_mnt_secinfo(mi->mi_curr_serv, nvp);
5843 5843                  return (e.error);
5844 5844          }
5845 5845  
5846 5846          e.error = geterrno4(res.status);
5847 5847  
5848 5848          /*
5849 5849           * The PUTFH and SAVEFH may have failed.
5850 5850           */
5851 5851          if ((res.array[0].nfs_resop4_u.opputfh.status != NFS4_OK) ||
5852 5852              (res.array[1].nfs_resop4_u.opsavefh.status != NFS4_OK)) {
5853 5853                  nfs4_purge_stale_fh(e.error, dvp, cr);
5854 5854                  goto exit;
5855 5855          }
5856 5856  
5857 5857          /*
5858 5858           * Check if the file exists, if it does delay entering
5859 5859           * into the dnlc until after we update the directory
5860 5860           * attributes so we don't cause it to get purged immediately.
5861 5861           */
5862 5862          if (res.array[2].nfs_resop4_u.oplookup.status != NFS4_OK) {
5863 5863                  /*
5864 5864                   * The lookup failed, probably no entry
5865 5865                   */
5866 5866                  if (e.error == ENOENT && nfs4_lookup_neg_cache)
5867 5867                          dnlc_update(dvp, nm, DNLC_NO_VNODE);
5868 5868                  goto exit;
5869 5869          }
5870 5870  
5871 5871          if (res.array[3].nfs_resop4_u.opgetfh.status != NFS4_OK) {
5872 5872                  /*
5873 5873                   * The file exists but we can't get its fh for
5874 5874                   * some unknown reason. Error out to be safe.
5875 5875                   */
5876 5876                  goto exit;
5877 5877          }
5878 5878  
5879 5879          fhp = &res.array[3].nfs_resop4_u.opgetfh.object;
5880 5880          if (fhp->nfs_fh4_len == 0) {
5881 5881                  /*
5882 5882                   * The file exists but a bogus fh
5883 5883                   * some unknown reason.  Error out to be safe.
5884 5884                   */
5885 5885                  e.error = EIO;
5886 5886                  goto exit;
5887 5887          }
5888 5888          sfhp = sfh4_get(fhp, mi);
5889 5889  
5890 5890          if (res.array[4].nfs_resop4_u.opgetattr.status != NFS4_OK) {
5891 5891                  sfh4_rele(&sfhp);
5892 5892                  goto exit;
5893 5893          }
5894 5894          garp = &res.array[4].nfs_resop4_u.opgetattr.ga_res;
5895 5895  
5896 5896          /*
5897 5897           * The RESTOREFH may have failed
5898 5898           */
5899 5899          if (res.array[5].nfs_resop4_u.oprestorefh.status != NFS4_OK) {
5900 5900                  sfh4_rele(&sfhp);
5901 5901                  e.error = EIO;
5902 5902                  goto exit;
5903 5903          }
5904 5904  
5905 5905          if (res.array[6].nfs_resop4_u.opnverify.status != NFS4ERR_SAME) {
5906 5906                  /*
5907 5907                   * First make sure the NVERIFY failed as we expected,
5908 5908                   * if it didn't then be conservative and error out
5909 5909                   * as we can't trust the directory.
5910 5910                   */
5911 5911                  if (res.array[6].nfs_resop4_u.opnverify.status != NFS4_OK) {
5912 5912                          sfh4_rele(&sfhp);
5913 5913                          e.error = EIO;
5914 5914                          goto exit;
5915 5915                  }
5916 5916  
5917 5917                  /*
5918 5918                   * We know the NVERIFY "failed" so the directory has changed,
5919 5919                   * so we must:
5920 5920                   *      purge the caches (access and indirectly dnlc if needed)
5921 5921                   */
5922 5922                  nfs4_purge_caches(dvp, NFS4_NOPURGE_DNLC, cr, TRUE);
5923 5923  
5924 5924                  if (res.array[7].nfs_resop4_u.opgetattr.status != NFS4_OK) {
5925 5925                          sfh4_rele(&sfhp);
5926 5926                          goto exit;
5927 5927                  }
5928 5928                  nfs4_attr_cache(dvp,
5929 5929                      &res.array[7].nfs_resop4_u.opgetattr.ga_res,
5930 5930                      t, cr, FALSE, NULL);
5931 5931  
5932 5932                  if (res.array[8].nfs_resop4_u.opaccess.status != NFS4_OK) {
5933 5933                          nfs4_purge_stale_fh(e.error, dvp, cr);
5934 5934                          sfh4_rele(&sfhp);
5935 5935                          e.error = geterrno4(res.status);
5936 5936                          goto exit;
5937 5937                  }
5938 5938  
5939 5939                  /*
5940 5940                   * Now we know the directory is valid,
5941 5941                   * cache new directory access
5942 5942                   */
5943 5943                  nfs4_access_cache(drp,
5944 5944                      args.array[8].nfs_argop4_u.opaccess.access,
5945 5945                      res.array[8].nfs_resop4_u.opaccess.access, cr);
5946 5946  
5947 5947                  /*
5948 5948                   * recheck VEXEC access
5949 5949                   */
5950 5950                  cacc = nfs4_access_check(drp, ACCESS4_LOOKUP, cr);
5951 5951                  if (cacc != NFS4_ACCESS_ALLOWED) {
5952 5952                          /*
5953 5953                           * Directory permissions might have been revoked
5954 5954                           */
5955 5955                          if (cacc == NFS4_ACCESS_DENIED) {
5956 5956                                  sfh4_rele(&sfhp);
5957 5957                                  e.error = EACCES;
5958 5958                                  goto exit;
5959 5959                          }
5960 5960  
5961 5961                          /*
5962 5962                           * Somehow we must not have asked for enough
5963 5963                           * so try a singleton ACCESS should never happen
5964 5964                           */
5965 5965                          e.error = nfs4_access(dvp, VEXEC, 0, cr, NULL);
5966 5966                          if (e.error) {
5967 5967                                  sfh4_rele(&sfhp);
5968 5968                                  goto exit;
5969 5969                          }
5970 5970                  }
5971 5971  
5972 5972                  e.error = geterrno4(res.status);
5973 5973          } else {
5974 5974                  hrtime_t now;
5975 5975                  hrtime_t delta = 0;
5976 5976  
5977 5977                  e.error = 0;
5978 5978  
5979 5979                  /*
5980 5980                   * Because the NVERIFY "succeeded" we know that the
5981 5981                   * directory attributes are still valid
5982 5982                   * so update r_time_attr_inval
5983 5983                   */
5984 5984                  now = gethrtime();
5985 5985                  mutex_enter(&drp->r_statelock);
5986 5986                  if (!(mi->mi_flags & MI4_NOAC) && !(dvp->v_flag & VNOCACHE)) {
5987 5987                          delta = now - drp->r_time_attr_saved;
5988 5988                          if (delta < mi->mi_acdirmin)
5989 5989                                  delta = mi->mi_acdirmin;
5990 5990                          else if (delta > mi->mi_acdirmax)
5991 5991                                  delta = mi->mi_acdirmax;
5992 5992                  }
5993 5993                  drp->r_time_attr_inval = now + delta;
5994 5994                  mutex_exit(&drp->r_statelock);
5995 5995  
5996 5996                  /*
5997 5997                   * Even though we have a valid directory attr cache,
5998 5998                   * we may not have access.
5999 5999                   * This should almost always hit the cache.
6000 6000                   */
6001 6001                  e.error = nfs4_access(dvp, VEXEC, 0, cr, NULL);
6002 6002                  if (e.error) {
6003 6003                          sfh4_rele(&sfhp);
6004 6004                          goto exit;
6005 6005                  }
6006 6006          }
6007 6007  
6008 6008          /*
6009 6009           * Now we have successfully completed the lookup, if the
6010 6010           * directory has changed we now have the valid attributes.
6011 6011           * We also know we have directory access.
6012 6012           * Create the new rnode and insert it in the dnlc.
6013 6013           */
6014 6014          if (isdotdot) {
6015 6015                  e.error = nfs4_make_dotdot(sfhp, t, dvp, cr, &nvp, 1);
6016 6016                  if (e.error) {
6017 6017                          sfh4_rele(&sfhp);
6018 6018                          goto exit;
6019 6019                  }
6020 6020                  /*
6021 6021                   * XXX if nfs4_make_dotdot uses an existing rnode
6022 6022                   * XXX it doesn't update the attributes.
6023 6023                   * XXX for now just save them again to save an OTW
6024 6024                   */
6025 6025                  nfs4_attr_cache(nvp, garp, t, cr, FALSE, NULL);
6026 6026          } else {
6027 6027                  nvp = makenfs4node(sfhp, garp, dvp->v_vfsp, t, cr,
6028 6028                      dvp, fn_get(VTOSV(dvp)->sv_name, nm, sfhp));
6029 6029          }
6030 6030          sfh4_rele(&sfhp);
6031 6031  
6032 6032          nrp = VTOR4(nvp);
6033 6033          mutex_enter(&nrp->r_statev4_lock);
6034 6034          if (!nrp->created_v4) {
6035 6035                  mutex_exit(&nrp->r_statev4_lock);
6036 6036                  dnlc_update(dvp, nm, nvp);
6037 6037          } else
6038 6038                  mutex_exit(&nrp->r_statev4_lock);
6039 6039  
6040 6040          *vpp = nvp;
6041 6041  
6042 6042  exit:
6043 6043          (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
6044 6044          kmem_free(argop, argoplist_size);
6045 6045          (void) check_mnt_secinfo(mi->mi_curr_serv, nvp);
6046 6046          return (e.error);
6047 6047  }
6048 6048  
6049 6049  #ifdef DEBUG
6050 6050  void
6051 6051  nfs4lookup_dump_compound(char *where, nfs_argop4 *argbase, int argcnt)
6052 6052  {
6053 6053          uint_t i, len;
6054 6054          zoneid_t zoneid = getzoneid();
6055 6055          char *s;
6056 6056  
6057 6057          zcmn_err(zoneid, CE_NOTE, "%s: dumping cmpd", where);
6058 6058          for (i = 0; i < argcnt; i++) {
6059 6059                  nfs_argop4 *op = &argbase[i];
6060 6060                  switch (op->argop) {
6061 6061                  case OP_CPUTFH:
6062 6062                  case OP_PUTFH:
6063 6063                          zcmn_err(zoneid, CE_NOTE, "\t op %d, putfh", i);
6064 6064                          break;
6065 6065                  case OP_PUTROOTFH:
6066 6066                          zcmn_err(zoneid, CE_NOTE, "\t op %d, putrootfh", i);
6067 6067                          break;
6068 6068                  case OP_CLOOKUP:
6069 6069                          s = op->nfs_argop4_u.opclookup.cname;
6070 6070                          zcmn_err(zoneid, CE_NOTE, "\t op %d, lookup %s", i, s);
6071 6071                          break;
6072 6072                  case OP_LOOKUP:
6073 6073                          s = utf8_to_str(&op->nfs_argop4_u.oplookup.objname,
6074 6074                              &len, NULL);
6075 6075                          zcmn_err(zoneid, CE_NOTE, "\t op %d, lookup %s", i, s);
6076 6076                          kmem_free(s, len);
6077 6077                          break;
6078 6078                  case OP_LOOKUPP:
6079 6079                          zcmn_err(zoneid, CE_NOTE, "\t op %d, lookupp ..", i);
6080 6080                          break;
6081 6081                  case OP_GETFH:
6082 6082                          zcmn_err(zoneid, CE_NOTE, "\t op %d, getfh", i);
6083 6083                          break;
6084 6084                  case OP_GETATTR:
6085 6085                          zcmn_err(zoneid, CE_NOTE, "\t op %d, getattr", i);
6086 6086                          break;
6087 6087                  case OP_OPENATTR:
6088 6088                          zcmn_err(zoneid, CE_NOTE, "\t op %d, openattr", i);
6089 6089                          break;
6090 6090                  default:
6091 6091                          zcmn_err(zoneid, CE_NOTE, "\t op %d, opcode %d", i,
6092 6092                              op->argop);
6093 6093                          break;
6094 6094                  }
6095 6095          }
6096 6096  }
6097 6097  #endif
6098 6098  
6099 6099  /*
6100 6100   * nfs4lookup_setup - constructs a multi-lookup compound request.
6101 6101   *
6102 6102   * Given the path "nm1/nm2/.../nmn", the following compound requests
6103 6103   * may be created:
6104 6104   *
6105 6105   * Note: Getfh is not be needed because filehandle attr is mandatory, but it
6106 6106   * is faster, for now.
6107 6107   *
6108 6108   * l4_getattrs indicates the type of compound requested.
6109 6109   *
6110 6110   * LKP4_NO_ATTRIBUTE - no attributes (used by secinfo):
6111 6111   *
6112 6112   *      compound { Put*fh; Lookup {nm1}; Lookup {nm2}; ...  Lookup {nmn} }
6113 6113   *
6114 6114   *   total number of ops is n + 1.
6115 6115   *
6116 6116   * LKP4_LAST_NAMED_ATTR - multi-component path for a named
6117 6117   *      attribute: create lookups plus one OPENATTR/GETFH/GETATTR
6118 6118   *      before the last component, and only get attributes
6119 6119   *      for the last component.  Note that the second-to-last
6120 6120   *      pathname component is XATTR_RPATH, which does NOT go
6121 6121   *      over-the-wire as a lookup.
6122 6122   *
6123 6123   *      compound { Put*fh; Lookup {nm1}; Lookup {nm2}; ... Lookup {nmn-2};
6124 6124   *              Openattr; Getfh; Getattr; Lookup {nmn}; Getfh; Getattr }
6125 6125   *
6126 6126   *   and total number of ops is n + 5.
6127 6127   *
6128 6128   * LKP4_LAST_ATTRDIR - multi-component path for the hidden named
6129 6129   *      attribute directory: create lookups plus an OPENATTR
6130 6130   *      replacing the last lookup.  Note that the last pathname
6131 6131   *      component is XATTR_RPATH, which does NOT go over-the-wire
6132 6132   *      as a lookup.
6133 6133   *
6134 6134   *      compound { Put*fh; Lookup {nm1}; Lookup {nm2}; ... Getfh; Getattr;
6135 6135   *              Openattr; Getfh; Getattr }
6136 6136   *
6137 6137   *   and total number of ops is n + 5.
6138 6138   *
6139 6139   * LKP4_ALL_ATTRIBUTES - create lookups and get attributes for intermediate
6140 6140   *      nodes too.
6141 6141   *
6142 6142   *      compound { Put*fh; Lookup {nm1}; Getfh; Getattr;
6143 6143   *              Lookup {nm2}; ...  Lookup {nmn}; Getfh; Getattr }
6144 6144   *
6145 6145   *   and total number of ops is 3*n + 1.
6146 6146   *
6147 6147   * All cases: returns the index in the arg array of the final LOOKUP op, or
6148 6148   * -1 if no LOOKUPs were used.
6149 6149   */
6150 6150  int
6151 6151  nfs4lookup_setup(char *nm, lookup4_param_t *lookupargp, int needgetfh)
6152 6152  {
6153 6153          enum lkp4_attr_setup l4_getattrs = lookupargp->l4_getattrs;
6154 6154          nfs_argop4 *argbase, *argop;
6155 6155          int arglen, argcnt;
6156 6156          int n = 1;      /* number of components */
6157 6157          int nga = 1;    /* number of Getattr's in request */
6158 6158          char c = '\0', *s, *p;
6159 6159          int lookup_idx = -1;
6160 6160          int argoplist_size;
6161 6161  
6162 6162          /* set lookuparg response result to 0 */
6163 6163          lookupargp->resp->status = NFS4_OK;
6164 6164  
6165 6165          /* skip leading "/" or "." e.g. ".//./" if there is */
6166 6166          for (; ; nm++) {
6167 6167                  if (*nm != '/' && *nm != '.')
6168 6168                          break;
6169 6169  
6170 6170                  /* ".." is counted as 1 component */
6171 6171                  if (*nm == '.' && *(nm + 1) != '/')
6172 6172                          break;
6173 6173          }
6174 6174  
6175 6175          /*
6176 6176           * Find n = number of components - nm must be null terminated
6177 6177           * Skip "." components.
6178 6178           */
6179 6179          if (*nm != '\0')
6180 6180                  for (n = 1, s = nm; *s != '\0'; s++) {
6181 6181                          if ((*s == '/') && (*(s + 1) != '/') &&
6182 6182                              (*(s + 1) != '\0') &&
6183 6183                              !(*(s + 1) == '.' && (*(s + 2) == '/' ||
6184 6184                              *(s + 2) == '\0')))
6185 6185                                  n++;
6186 6186                  }
6187 6187          else
6188 6188                  n = 0;
6189 6189  
6190 6190          /*
6191 6191           * nga is number of components that need Getfh+Getattr
6192 6192           */
6193 6193          switch (l4_getattrs) {
6194 6194          case LKP4_NO_ATTRIBUTES:
6195 6195                  nga = 0;
6196 6196                  break;
6197 6197          case LKP4_ALL_ATTRIBUTES:
6198 6198                  nga = n;
6199 6199                  /*
6200 6200                   * Always have at least 1 getfh, getattr pair
6201 6201                   */
6202 6202                  if (nga == 0)
6203 6203                          nga++;
6204 6204                  break;
6205 6205          case LKP4_LAST_ATTRDIR:
6206 6206          case LKP4_LAST_NAMED_ATTR:
6207 6207                  nga = n+1;
6208 6208                  break;
6209 6209          }
6210 6210  
6211 6211          /*
6212 6212           * If change to use the filehandle attr instead of getfh
6213 6213           * the following line can be deleted.
6214 6214           */
6215 6215          nga *= 2;
6216 6216  
6217 6217          /*
6218 6218           * calculate number of ops in request as
6219 6219           * header + trailer + lookups + getattrs
6220 6220           */
6221 6221          arglen = lookupargp->header_len + lookupargp->trailer_len + n + nga;
6222 6222  
6223 6223          argoplist_size = arglen * sizeof (nfs_argop4);
6224 6224          argop = argbase = kmem_alloc(argoplist_size, KM_SLEEP);
6225 6225          lookupargp->argsp->array = argop;
6226 6226  
6227 6227          argcnt = lookupargp->header_len;
6228 6228          argop += argcnt;
6229 6229  
6230 6230          /*
6231 6231           * loop and create a lookup op and possibly getattr/getfh for
6232 6232           * each component. Skip "." components.
6233 6233           */
6234 6234          for (s = nm; *s != '\0'; s = p) {
6235 6235                  /*
6236 6236                   * Set up a pathname struct for each component if needed
6237 6237                   */
6238 6238                  while (*s == '/')
6239 6239                          s++;
6240 6240                  if (*s == '\0')
6241 6241                          break;
6242 6242  
6243 6243                  for (p = s; (*p != '/') && (*p != '\0'); p++)
6244 6244                          ;
6245 6245                  c = *p;
6246 6246                  *p = '\0';
6247 6247  
6248 6248                  if (s[0] == '.' && s[1] == '\0') {
6249 6249                          *p = c;
6250 6250                          continue;
6251 6251                  }
6252 6252                  if (l4_getattrs == LKP4_LAST_ATTRDIR &&
6253 6253                      strcmp(s, XATTR_RPATH) == 0) {
6254 6254                          /* getfh XXX may not be needed in future */
6255 6255                          argop->argop = OP_GETFH;
6256 6256                          argop++;
6257 6257                          argcnt++;
6258 6258  
6259 6259                          /* getattr */
6260 6260                          argop->argop = OP_GETATTR;
6261 6261                          argop->nfs_argop4_u.opgetattr.attr_request =
6262 6262                              lookupargp->ga_bits;
6263 6263                          argop->nfs_argop4_u.opgetattr.mi =
6264 6264                              lookupargp->mi;
6265 6265                          argop++;
6266 6266                          argcnt++;
6267 6267  
6268 6268                          /* openattr */
6269 6269                          argop->argop = OP_OPENATTR;
6270 6270                  } else if (l4_getattrs == LKP4_LAST_NAMED_ATTR &&
6271 6271                      strcmp(s, XATTR_RPATH) == 0) {
6272 6272                          /* openattr */
6273 6273                          argop->argop = OP_OPENATTR;
6274 6274                          argop++;
6275 6275                          argcnt++;
6276 6276  
6277 6277                          /* getfh XXX may not be needed in future */
6278 6278                          argop->argop = OP_GETFH;
6279 6279                          argop++;
6280 6280                          argcnt++;
6281 6281  
6282 6282                          /* getattr */
6283 6283                          argop->argop = OP_GETATTR;
6284 6284                          argop->nfs_argop4_u.opgetattr.attr_request =
6285 6285                              lookupargp->ga_bits;
6286 6286                          argop->nfs_argop4_u.opgetattr.mi =
6287 6287                              lookupargp->mi;
6288 6288                          argop++;
6289 6289                          argcnt++;
6290 6290                          *p = c;
6291 6291                          continue;
6292 6292                  } else if (s[0] == '.' && s[1] == '.' && s[2] == '\0') {
6293 6293                          /* lookupp */
6294 6294                          argop->argop = OP_LOOKUPP;
6295 6295                  } else {
6296 6296                          /* lookup */
6297 6297                          argop->argop = OP_LOOKUP;
6298 6298                          (void) str_to_utf8(s,
6299 6299                              &argop->nfs_argop4_u.oplookup.objname);
6300 6300                  }
6301 6301                  lookup_idx = argcnt;
6302 6302                  argop++;
6303 6303                  argcnt++;
6304 6304  
6305 6305                  *p = c;
6306 6306  
6307 6307                  if (l4_getattrs == LKP4_ALL_ATTRIBUTES) {
6308 6308                          /* getfh XXX may not be needed in future */
6309 6309                          argop->argop = OP_GETFH;
6310 6310                          argop++;
6311 6311                          argcnt++;
6312 6312  
6313 6313                          /* getattr */
6314 6314                          argop->argop = OP_GETATTR;
6315 6315                          argop->nfs_argop4_u.opgetattr.attr_request =
6316 6316                              lookupargp->ga_bits;
6317 6317                          argop->nfs_argop4_u.opgetattr.mi =
6318 6318                              lookupargp->mi;
6319 6319                          argop++;
6320 6320                          argcnt++;
6321 6321                  }
6322 6322          }
6323 6323  
6324 6324          if ((l4_getattrs != LKP4_NO_ATTRIBUTES) &&
6325 6325              ((l4_getattrs != LKP4_ALL_ATTRIBUTES) || (lookup_idx < 0))) {
6326 6326                  if (needgetfh) {
6327 6327                          /* stick in a post-lookup getfh */
6328 6328                          argop->argop = OP_GETFH;
6329 6329                          argcnt++;
6330 6330                          argop++;
6331 6331                  }
6332 6332                  /* post-lookup getattr */
6333 6333                  argop->argop = OP_GETATTR;
6334 6334                  argop->nfs_argop4_u.opgetattr.attr_request =
6335 6335                      lookupargp->ga_bits;
6336 6336                  argop->nfs_argop4_u.opgetattr.mi = lookupargp->mi;
6337 6337                  argcnt++;
6338 6338          }
6339 6339          argcnt += lookupargp->trailer_len;      /* actual op count */
6340 6340          lookupargp->argsp->array_len = argcnt;
6341 6341          lookupargp->arglen = arglen;
6342 6342  
6343 6343  #ifdef DEBUG
6344 6344          if (nfs4_client_lookup_debug)
6345 6345                  nfs4lookup_dump_compound("nfs4lookup_setup", argbase, argcnt);
6346 6346  #endif
6347 6347  
6348 6348          return (lookup_idx);
6349 6349  }
6350 6350  
6351 6351  static int
6352 6352  nfs4openattr(vnode_t *dvp, vnode_t **avp, int cflag, cred_t *cr)
6353 6353  {
6354 6354          COMPOUND4args_clnt      args;
6355 6355          COMPOUND4res_clnt       res;
6356 6356          GETFH4res       *gf_res = NULL;
6357 6357          nfs_argop4      argop[4];
6358 6358          nfs_resop4      *resop = NULL;
6359 6359          nfs4_sharedfh_t *sfhp;
6360 6360          hrtime_t t;
6361 6361          nfs4_error_t    e;
6362 6362  
6363 6363          rnode4_t        *drp;
6364 6364          int             doqueue = 1;
6365 6365          vnode_t         *vp;
6366 6366          int             needrecov = 0;
6367 6367          nfs4_recov_state_t recov_state;
6368 6368  
6369 6369          ASSERT(nfs_zone() == VTOMI4(dvp)->mi_zone);
6370 6370  
6371 6371          *avp = NULL;
6372 6372          recov_state.rs_flags = 0;
6373 6373          recov_state.rs_num_retry_despite_err = 0;
6374 6374  
6375 6375  recov_retry:
6376 6376          /* COMPOUND: putfh, openattr, getfh, getattr */
6377 6377          args.array_len = 4;
6378 6378          args.array = argop;
6379 6379          args.ctag = TAG_OPENATTR;
6380 6380  
6381 6381          e.error = nfs4_start_op(VTOMI4(dvp), dvp, NULL, &recov_state);
6382 6382          if (e.error)
6383 6383                  return (e.error);
6384 6384  
6385 6385          drp = VTOR4(dvp);
6386 6386  
6387 6387          /* putfh */
6388 6388          argop[0].argop = OP_CPUTFH;
6389 6389          argop[0].nfs_argop4_u.opcputfh.sfh = drp->r_fh;
6390 6390  
6391 6391          /* openattr */
6392 6392          argop[1].argop = OP_OPENATTR;
6393 6393          argop[1].nfs_argop4_u.opopenattr.createdir = (cflag ? TRUE : FALSE);
6394 6394  
6395 6395          /* getfh */
6396 6396          argop[2].argop = OP_GETFH;
6397 6397  
6398 6398          /* getattr */
6399 6399          argop[3].argop = OP_GETATTR;
6400 6400          argop[3].nfs_argop4_u.opgetattr.attr_request = NFS4_VATTR_MASK;
6401 6401          argop[3].nfs_argop4_u.opgetattr.mi = VTOMI4(dvp);
6402 6402  
6403 6403          NFS4_DEBUG(nfs4_client_call_debug, (CE_NOTE,
6404 6404              "nfs4openattr: %s call, drp %s", needrecov ? "recov" : "first",
6405 6405              rnode4info(drp)));
6406 6406  
6407 6407          t = gethrtime();
6408 6408  
6409 6409          rfs4call(VTOMI4(dvp), &args, &res, cr, &doqueue, 0, &e);
6410 6410  
6411 6411          needrecov = nfs4_needs_recovery(&e, FALSE, dvp->v_vfsp);
6412 6412          if (needrecov) {
6413 6413                  bool_t abort;
6414 6414  
6415 6415                  NFS4_DEBUG(nfs4_client_recov_debug, (CE_NOTE,
6416 6416                      "nfs4openattr: initiating recovery\n"));
6417 6417  
6418 6418                  abort = nfs4_start_recovery(&e,
6419 6419                      VTOMI4(dvp), dvp, NULL, NULL, NULL,
6420 6420                      OP_OPENATTR, NULL, NULL, NULL);
6421 6421                  nfs4_end_op(VTOMI4(dvp), dvp, NULL, &recov_state, needrecov);
6422 6422                  if (!e.error) {
6423 6423                          e.error = geterrno4(res.status);
6424 6424                          (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
6425 6425                  }
6426 6426                  if (abort == FALSE)
6427 6427                          goto recov_retry;
6428 6428                  return (e.error);
6429 6429          }
6430 6430  
6431 6431          if (e.error) {
6432 6432                  nfs4_end_op(VTOMI4(dvp), dvp, NULL, &recov_state, needrecov);
6433 6433                  return (e.error);
6434 6434          }
6435 6435  
6436 6436          if (res.status) {
6437 6437                  /*
6438 6438                   * If OTW errro is NOTSUPP, then it should be
6439 6439                   * translated to EINVAL.  All Solaris file system
6440 6440                   * implementations return EINVAL to the syscall layer
6441 6441                   * when the attrdir cannot be created due to an
6442 6442                   * implementation restriction or noxattr mount option.
6443 6443                   */
6444 6444                  if (res.status == NFS4ERR_NOTSUPP) {
6445 6445                          mutex_enter(&drp->r_statelock);
6446 6446                          if (drp->r_xattr_dir)
6447 6447                                  VN_RELE(drp->r_xattr_dir);
6448 6448                          VN_HOLD(NFS4_XATTR_DIR_NOTSUPP);
6449 6449                          drp->r_xattr_dir = NFS4_XATTR_DIR_NOTSUPP;
6450 6450                          mutex_exit(&drp->r_statelock);
6451 6451  
6452 6452                          e.error = EINVAL;
6453 6453                  } else {
6454 6454                          e.error = geterrno4(res.status);
6455 6455                  }
6456 6456  
6457 6457                  if (e.error) {
6458 6458                          (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
6459 6459                          nfs4_end_op(VTOMI4(dvp), dvp, NULL, &recov_state,
6460 6460                              needrecov);
6461 6461                          return (e.error);
6462 6462                  }
6463 6463          }
6464 6464  
6465 6465          resop = &res.array[0];  /* putfh res */
6466 6466          ASSERT(resop->nfs_resop4_u.opgetfh.status == NFS4_OK);
6467 6467  
6468 6468          resop = &res.array[1];  /* openattr res */
6469 6469          ASSERT(resop->nfs_resop4_u.opopenattr.status == NFS4_OK);
6470 6470  
6471 6471          resop = &res.array[2];  /* getfh res */
6472 6472          gf_res = &resop->nfs_resop4_u.opgetfh;
6473 6473          if (gf_res->object.nfs_fh4_len == 0) {
6474 6474                  *avp = NULL;
6475 6475                  (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
6476 6476                  nfs4_end_op(VTOMI4(dvp), dvp, NULL, &recov_state, needrecov);
6477 6477                  return (ENOENT);
6478 6478          }
6479 6479  
6480 6480          sfhp = sfh4_get(&gf_res->object, VTOMI4(dvp));
6481 6481          vp = makenfs4node(sfhp, &res.array[3].nfs_resop4_u.opgetattr.ga_res,
6482 6482              dvp->v_vfsp, t, cr, dvp,
6483 6483              fn_get(VTOSV(dvp)->sv_name, XATTR_RPATH, sfhp));
6484 6484          sfh4_rele(&sfhp);
6485 6485  
6486 6486          if (e.error)
6487 6487                  PURGE_ATTRCACHE4(vp);
6488 6488  
6489 6489          mutex_enter(&vp->v_lock);
6490 6490          vp->v_flag |= V_XATTRDIR;
6491 6491          mutex_exit(&vp->v_lock);
6492 6492  
6493 6493          *avp = vp;
6494 6494  
6495 6495          mutex_enter(&drp->r_statelock);
6496 6496          if (drp->r_xattr_dir)
6497 6497                  VN_RELE(drp->r_xattr_dir);
6498 6498          VN_HOLD(vp);
6499 6499          drp->r_xattr_dir = vp;
6500 6500  
6501 6501          /*
6502 6502           * Invalidate pathconf4 cache because r_xattr_dir is no longer
6503 6503           * NULL.  xattrs could be created at any time, and we have no
6504 6504           * way to update pc4_xattr_exists in the base object if/when
6505 6505           * it happens.
6506 6506           */
6507 6507          drp->r_pathconf.pc4_xattr_valid = 0;
6508 6508  
6509 6509          mutex_exit(&drp->r_statelock);
6510 6510  
6511 6511          nfs4_end_op(VTOMI4(dvp), dvp, NULL, &recov_state, needrecov);
6512 6512  
6513 6513          (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
6514 6514  
6515 6515          return (0);
6516 6516  }
6517 6517  
6518 6518  /* ARGSUSED */
6519 6519  static int
6520 6520  nfs4_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive,
6521 6521      int mode, vnode_t **vpp, cred_t *cr, int flags, caller_context_t *ct,
6522 6522      vsecattr_t *vsecp)
6523 6523  {
6524 6524          int error;
6525 6525          vnode_t *vp = NULL;
6526 6526          rnode4_t *rp;
6527 6527          struct vattr vattr;
6528 6528          rnode4_t *drp;
6529 6529          vnode_t *tempvp;
6530 6530          enum createmode4 createmode;
6531 6531          bool_t must_trunc = FALSE;
6532 6532          int     truncating = 0;
6533 6533  
6534 6534          if (nfs_zone() != VTOMI4(dvp)->mi_zone)
6535 6535                  return (EPERM);
6536 6536          if (exclusive == EXCL && (dvp->v_flag & V_XATTRDIR)) {
6537 6537                  return (EINVAL);
6538 6538          }
6539 6539  
6540 6540          /* . and .. have special meaning in the protocol, reject them. */
6541 6541  
6542 6542          if (nm[0] == '.' && (nm[1] == '\0' || (nm[1] == '.' && nm[2] == '\0')))
6543 6543                  return (EISDIR);
6544 6544  
6545 6545          drp = VTOR4(dvp);
6546 6546  
6547 6547          if (nfs_rw_enter_sig(&drp->r_rwlock, RW_WRITER, INTR4(dvp)))
6548 6548                  return (EINTR);
6549 6549  
6550 6550  top:
6551 6551          /*
6552 6552           * We make a copy of the attributes because the caller does not
6553 6553           * expect us to change what va points to.
6554 6554           */
6555 6555          vattr = *va;
6556 6556  
6557 6557          /*
6558 6558           * If the pathname is "", then dvp is the root vnode of
6559 6559           * a remote file mounted over a local directory.
6560 6560           * All that needs to be done is access
6561 6561           * checking and truncation.  Note that we avoid doing
6562 6562           * open w/ create because the parent directory might
6563 6563           * be in pseudo-fs and the open would fail.
6564 6564           */
6565 6565          if (*nm == '\0') {
6566 6566                  error = 0;
6567 6567                  VN_HOLD(dvp);
6568 6568                  vp = dvp;
6569 6569                  must_trunc = TRUE;
6570 6570          } else {
6571 6571                  /*
6572 6572                   * We need to go over the wire, just to be sure whether the
6573 6573                   * file exists or not.  Using the DNLC can be dangerous in
6574 6574                   * this case when making a decision regarding existence.
6575 6575                   */
6576 6576                  error = nfs4lookup(dvp, nm, &vp, cr, 1);
6577 6577          }
6578 6578  
6579 6579          if (exclusive)
6580 6580                  createmode = EXCLUSIVE4;
6581 6581          else
6582 6582                  createmode = GUARDED4;
6583 6583  
6584 6584          /*
6585 6585           * error would be set if the file does not exist on the
6586 6586           * server, so lets go create it.
6587 6587           */
6588 6588          if (error) {
6589 6589                  goto create_otw;
6590 6590          }
6591 6591  
6592 6592          /*
6593 6593           * File does exist on the server
6594 6594           */
6595 6595          if (exclusive == EXCL)
6596 6596                  error = EEXIST;
6597 6597          else if (vp->v_type == VDIR && (mode & VWRITE))
6598 6598                  error = EISDIR;
6599 6599          else {
6600 6600                  /*
6601 6601                   * If vnode is a device, create special vnode.
6602 6602                   */
6603 6603                  if (ISVDEV(vp->v_type)) {
6604 6604                          tempvp = vp;
6605 6605                          vp = specvp(vp, vp->v_rdev, vp->v_type, cr);
6606 6606                          VN_RELE(tempvp);
6607 6607                  }
6608 6608                  if (!(error = VOP_ACCESS(vp, mode, 0, cr, ct))) {
6609 6609                          if ((vattr.va_mask & AT_SIZE) &&
6610 6610                              vp->v_type == VREG) {
6611 6611                                  rp = VTOR4(vp);
6612 6612                                  /*
6613 6613                                   * Check here for large file handled
6614 6614                                   * by LF-unaware process (as
6615 6615                                   * ufs_create() does)
6616 6616                                   */
6617 6617                                  if (!(flags & FOFFMAX)) {
6618 6618                                          mutex_enter(&rp->r_statelock);
6619 6619                                          if (rp->r_size > MAXOFF32_T)
6620 6620                                                  error = EOVERFLOW;
6621 6621                                          mutex_exit(&rp->r_statelock);
6622 6622                                  }
6623 6623  
6624 6624                                  /* if error is set then we need to return */
6625 6625                                  if (error) {
6626 6626                                          nfs_rw_exit(&drp->r_rwlock);
6627 6627                                          VN_RELE(vp);
6628 6628                                          return (error);
6629 6629                                  }
6630 6630  
6631 6631                                  if (must_trunc) {
6632 6632                                          vattr.va_mask = AT_SIZE;
6633 6633                                          error = nfs4setattr(vp, &vattr, 0, cr,
6634 6634                                              NULL);
6635 6635                                  } else {
6636 6636                                  /*
6637 6637                                   * we know we have a regular file that already
6638 6638                                   * exists and we may end up truncating the file
6639 6639                                   * as a result of the open_otw, so flush out
6640 6640                                   * any dirty pages for this file first.
6641 6641                                   */
6642 6642                                          if (nfs4_has_pages(vp) &&
6643 6643                                              ((rp->r_flags & R4DIRTY) ||
6644 6644                                              rp->r_count > 0 ||
6645 6645                                              rp->r_mapcnt > 0)) {
6646 6646                                                  error = nfs4_putpage(vp,
6647 6647                                                      (offset_t)0, 0, 0, cr, ct);
6648 6648                                                  if (error && (error == ENOSPC ||
6649 6649                                                      error == EDQUOT)) {
6650 6650                                                          mutex_enter(
6651 6651                                                              &rp->r_statelock);
6652 6652                                                          if (!rp->r_error)
6653 6653                                                                  rp->r_error =
6654 6654                                                                      error;
6655 6655                                                          mutex_exit(
6656 6656                                                              &rp->r_statelock);
6657 6657                                                  }
6658 6658                                          }
6659 6659                                          vattr.va_mask = (AT_SIZE |
6660 6660                                              AT_TYPE | AT_MODE);
6661 6661                                          vattr.va_type = VREG;
6662 6662                                          createmode = UNCHECKED4;
6663 6663                                          truncating = 1;
6664 6664                                          goto create_otw;
6665 6665                                  }
6666 6666                          }
6667 6667                  }
6668 6668          }
6669 6669          nfs_rw_exit(&drp->r_rwlock);
6670 6670          if (error) {
6671 6671                  VN_RELE(vp);
6672 6672          } else {
6673 6673                  vnode_t *tvp;
6674 6674                  rnode4_t *trp;
6675 6675                  tvp = vp;
6676 6676                  if (vp->v_type == VREG) {
6677 6677                          trp = VTOR4(vp);
6678 6678                          if (IS_SHADOW(vp, trp))
6679 6679                                  tvp = RTOV4(trp);
6680 6680                  }
6681 6681  
6682 6682                  if (must_trunc) {
6683 6683                          /*
6684 6684                           * existing file got truncated, notify.
6685 6685                           */
6686 6686                          vnevent_create(tvp, ct);
6687 6687                  }
6688 6688  
6689 6689                  *vpp = vp;
6690 6690          }
6691 6691          return (error);
6692 6692  
6693 6693  create_otw:
6694 6694          dnlc_remove(dvp, nm);
6695 6695  
6696 6696          ASSERT(vattr.va_mask & AT_TYPE);
6697 6697  
6698 6698          /*
6699 6699           * If not a regular file let nfs4mknod() handle it.
6700 6700           */
6701 6701          if (vattr.va_type != VREG) {
6702 6702                  error = nfs4mknod(dvp, nm, &vattr, exclusive, mode, vpp, cr);
6703 6703                  nfs_rw_exit(&drp->r_rwlock);
6704 6704                  return (error);
6705 6705          }
6706 6706  
6707 6707          /*
6708 6708           * It _is_ a regular file.
6709 6709           */
6710 6710          ASSERT(vattr.va_mask & AT_MODE);
6711 6711          if (MANDMODE(vattr.va_mode)) {
6712 6712                  nfs_rw_exit(&drp->r_rwlock);
6713 6713                  return (EACCES);
6714 6714          }
6715 6715  
6716 6716          /*
6717 6717           * If this happens to be a mknod of a regular file, then flags will
6718 6718           * have neither FREAD or FWRITE.  However, we must set at least one
6719 6719           * for the call to nfs4open_otw.  If it's open(O_CREAT) driving
6720 6720           * nfs4_create, then either FREAD, FWRITE, or FRDWR has already been
6721 6721           * set (based on openmode specified by app).
6722 6722           */
6723 6723          if ((flags & (FREAD|FWRITE)) == 0)
6724 6724                  flags |= (FREAD|FWRITE);
6725 6725  
6726 6726          error = nfs4open_otw(dvp, nm, &vattr, vpp, cr, 1, flags, createmode, 0);
6727 6727  
6728 6728          if (vp != NULL) {
6729 6729                  /* if create was successful, throw away the file's pages */
6730 6730                  if (!error && (vattr.va_mask & AT_SIZE))
6731 6731                          nfs4_invalidate_pages(vp, (vattr.va_size & PAGEMASK),
6732 6732                              cr);
6733 6733                  /* release the lookup hold */
6734 6734                  VN_RELE(vp);
6735 6735                  vp = NULL;
6736 6736          }
6737 6737  
6738 6738          /*
6739 6739           * validate that we opened a regular file. This handles a misbehaving
6740 6740           * server that returns an incorrect FH.
6741 6741           */
6742 6742          if ((error == 0) && *vpp && (*vpp)->v_type != VREG) {
6743 6743                  error = EISDIR;
6744 6744                  VN_RELE(*vpp);
6745 6745          }
6746 6746  
6747 6747          /*
6748 6748           * If this is not an exclusive create, then the CREATE
6749 6749           * request will be made with the GUARDED mode set.  This
6750 6750           * means that the server will return EEXIST if the file
6751 6751           * exists.  The file could exist because of a retransmitted
6752 6752           * request.  In this case, we recover by starting over and
6753 6753           * checking to see whether the file exists.  This second
6754 6754           * time through it should and a CREATE request will not be
6755 6755           * sent.
6756 6756           *
6757 6757           * This handles the problem of a dangling CREATE request
6758 6758           * which contains attributes which indicate that the file
6759 6759           * should be truncated.  This retransmitted request could
6760 6760           * possibly truncate valid data in the file if not caught
6761 6761           * by the duplicate request mechanism on the server or if
6762 6762           * not caught by other means.  The scenario is:
6763 6763           *
6764 6764           * Client transmits CREATE request with size = 0
6765 6765           * Client times out, retransmits request.
6766 6766           * Response to the first request arrives from the server
6767 6767           *  and the client proceeds on.
6768 6768           * Client writes data to the file.
6769 6769           * The server now processes retransmitted CREATE request
6770 6770           *  and truncates file.
6771 6771           *
6772 6772           * The use of the GUARDED CREATE request prevents this from
6773 6773           * happening because the retransmitted CREATE would fail
6774 6774           * with EEXIST and would not truncate the file.
6775 6775           */
6776 6776          if (error == EEXIST && exclusive == NONEXCL) {
6777 6777  #ifdef DEBUG
6778 6778                  nfs4_create_misses++;
6779 6779  #endif
6780 6780                  goto top;
6781 6781          }
6782 6782          nfs_rw_exit(&drp->r_rwlock);
6783 6783          if (truncating && !error && *vpp) {
6784 6784                  vnode_t *tvp;
6785 6785                  rnode4_t *trp;
6786 6786                  /*
6787 6787                   * existing file got truncated, notify.
6788 6788                   */
6789 6789                  tvp = *vpp;
6790 6790                  trp = VTOR4(tvp);
6791 6791                  if (IS_SHADOW(tvp, trp))
6792 6792                          tvp = RTOV4(trp);
6793 6793                  vnevent_create(tvp, ct);
6794 6794          }
6795 6795          return (error);
6796 6796  }
6797 6797  
6798 6798  /*
6799 6799   * Create compound (for mkdir, mknod, symlink):
6800 6800   * { Putfh <dfh>; Create; Getfh; Getattr }
6801 6801   * It's okay if setattr failed to set gid - this is not considered
6802 6802   * an error, but purge attrs in that case.
6803 6803   */
6804 6804  static int
6805 6805  call_nfs4_create_req(vnode_t *dvp, char *nm, void *data, struct vattr *va,
6806 6806      vnode_t **vpp, cred_t *cr, nfs_ftype4 type)
6807 6807  {
6808 6808          int need_end_op = FALSE;
6809 6809          COMPOUND4args_clnt args;
6810 6810          COMPOUND4res_clnt res, *resp = NULL;
6811 6811          nfs_argop4 *argop;
6812 6812          nfs_resop4 *resop;
6813 6813          int doqueue;
6814 6814          mntinfo4_t *mi;
6815 6815          rnode4_t *drp = VTOR4(dvp);
6816 6816          change_info4 *cinfo;
6817 6817          GETFH4res *gf_res;
6818 6818          struct vattr vattr;
6819 6819          vnode_t *vp;
6820 6820          fattr4 *crattr;
6821 6821          bool_t needrecov = FALSE;
6822 6822          nfs4_recov_state_t recov_state;
6823 6823          nfs4_sharedfh_t *sfhp = NULL;
6824 6824          hrtime_t t;
6825 6825          nfs4_error_t e = { 0, NFS4_OK, RPC_SUCCESS };
6826 6826          int numops, argoplist_size, setgid_flag, idx_create, idx_fattr;
6827 6827          dirattr_info_t dinfo, *dinfop;
6828 6828          servinfo4_t *svp;
6829 6829          bitmap4 supp_attrs;
6830 6830  
6831 6831          ASSERT(type == NF4DIR || type == NF4LNK || type == NF4BLK ||
6832 6832              type == NF4CHR || type == NF4SOCK || type == NF4FIFO);
6833 6833  
6834 6834          mi = VTOMI4(dvp);
6835 6835  
6836 6836          /*
6837 6837           * Make sure we properly deal with setting the right gid
6838 6838           * on a new directory to reflect the parent's setgid bit
6839 6839           */
6840 6840          setgid_flag = 0;
6841 6841          if (type == NF4DIR) {
6842 6842                  struct vattr dva;
6843 6843  
6844 6844                  va->va_mode &= ~VSGID;
6845 6845                  dva.va_mask = AT_MODE | AT_GID;
6846 6846                  if (VOP_GETATTR(dvp, &dva, 0, cr, NULL) == 0) {
6847 6847  
6848 6848                          /*
6849 6849                           * If the parent's directory has the setgid bit set
6850 6850                           * _and_ the client was able to get a valid mapping
6851 6851                           * for the parent dir's owner_group, we want to
6852 6852                           * append NVERIFY(owner_group == dva.va_gid) and
6853 6853                           * SETTATTR to the CREATE compound.
6854 6854                           */
6855 6855                          if (mi->mi_flags & MI4_GRPID || dva.va_mode & VSGID) {
6856 6856                                  setgid_flag = 1;
6857 6857                                  va->va_mode |= VSGID;
6858 6858                                  if (dva.va_gid != GID_NOBODY) {
6859 6859                                          va->va_mask |= AT_GID;
6860 6860                                          va->va_gid = dva.va_gid;
6861 6861                                  }
6862 6862                          }
6863 6863                  }
6864 6864          }
6865 6865  
6866 6866          /*
6867 6867           * Create ops:
6868 6868           *      0:putfh(dir) 1:savefh(dir) 2:create 3:getfh(new) 4:getattr(new)
6869 6869           *      5:restorefh(dir) 6:getattr(dir)
6870 6870           *
6871 6871           * if (setgid)
6872 6872           *      0:putfh(dir) 1:create 2:getfh(new) 3:getattr(new)
6873 6873           *      4:savefh(new) 5:putfh(dir) 6:getattr(dir) 7:restorefh(new)
6874 6874           *      8:nverify 9:setattr
6875 6875           */
6876 6876          if (setgid_flag) {
6877 6877                  numops = 10;
6878 6878                  idx_create = 1;
6879 6879                  idx_fattr = 3;
6880 6880          } else {
6881 6881                  numops = 7;
6882 6882                  idx_create = 2;
6883 6883                  idx_fattr = 4;
6884 6884          }
6885 6885  
6886 6886          ASSERT(nfs_zone() == mi->mi_zone);
6887 6887          if (nfs_rw_enter_sig(&drp->r_rwlock, RW_WRITER, INTR4(dvp))) {
6888 6888                  return (EINTR);
6889 6889          }
6890 6890          recov_state.rs_flags = 0;
6891 6891          recov_state.rs_num_retry_despite_err = 0;
6892 6892  
6893 6893          argoplist_size = numops * sizeof (nfs_argop4);
6894 6894          argop = kmem_alloc(argoplist_size, KM_SLEEP);
6895 6895  
6896 6896  recov_retry:
6897 6897          if (type == NF4LNK)
6898 6898                  args.ctag = TAG_SYMLINK;
6899 6899          else if (type == NF4DIR)
6900 6900                  args.ctag = TAG_MKDIR;
6901 6901          else
6902 6902                  args.ctag = TAG_MKNOD;
6903 6903  
6904 6904          args.array_len = numops;
6905 6905          args.array = argop;
6906 6906  
6907 6907          if (e.error = nfs4_start_op(mi, dvp, NULL, &recov_state)) {
6908 6908                  nfs_rw_exit(&drp->r_rwlock);
6909 6909                  kmem_free(argop, argoplist_size);
6910 6910                  return (e.error);
6911 6911          }
6912 6912          need_end_op = TRUE;
6913 6913  
6914 6914  
6915 6915          /* 0: putfh directory */
6916 6916          argop[0].argop = OP_CPUTFH;
6917 6917          argop[0].nfs_argop4_u.opcputfh.sfh = drp->r_fh;
6918 6918  
6919 6919          /* 1/2: Create object */
6920 6920          argop[idx_create].argop = OP_CCREATE;
6921 6921          argop[idx_create].nfs_argop4_u.opccreate.cname = nm;
6922 6922          argop[idx_create].nfs_argop4_u.opccreate.type = type;
6923 6923          if (type == NF4LNK) {
6924 6924                  /*
6925 6925                   * symlink, treat name as data
6926 6926                   */
6927 6927                  ASSERT(data != NULL);
6928 6928                  argop[idx_create].nfs_argop4_u.opccreate.ftype4_u.clinkdata =
6929 6929                      (char *)data;
6930 6930          }
6931 6931          if (type == NF4BLK || type == NF4CHR) {
6932 6932                  ASSERT(data != NULL);
6933 6933                  argop[idx_create].nfs_argop4_u.opccreate.ftype4_u.devdata =
6934 6934                      *((specdata4 *)data);
6935 6935          }
6936 6936  
6937 6937          crattr = &argop[idx_create].nfs_argop4_u.opccreate.createattrs;
6938 6938  
6939 6939          svp = drp->r_server;
6940 6940          (void) nfs_rw_enter_sig(&svp->sv_lock, RW_READER, 0);
6941 6941          supp_attrs = svp->sv_supp_attrs;
6942 6942          nfs_rw_exit(&svp->sv_lock);
6943 6943  
6944 6944          if (vattr_to_fattr4(va, NULL, crattr, 0, OP_CREATE, supp_attrs)) {
6945 6945                  nfs_rw_exit(&drp->r_rwlock);
6946 6946                  nfs4_end_op(mi, dvp, NULL, &recov_state, needrecov);
6947 6947                  e.error = EINVAL;
6948 6948                  kmem_free(argop, argoplist_size);
6949 6949                  return (e.error);
6950 6950          }
6951 6951  
6952 6952          /* 2/3: getfh fh of created object */
6953 6953          ASSERT(idx_create + 1 == idx_fattr - 1);
6954 6954          argop[idx_create + 1].argop = OP_GETFH;
6955 6955  
6956 6956          /* 3/4: getattr of new object */
6957 6957          argop[idx_fattr].argop = OP_GETATTR;
6958 6958          argop[idx_fattr].nfs_argop4_u.opgetattr.attr_request = NFS4_VATTR_MASK;
6959 6959          argop[idx_fattr].nfs_argop4_u.opgetattr.mi = mi;
6960 6960  
6961 6961          if (setgid_flag) {
6962 6962                  vattr_t _v;
6963 6963  
6964 6964                  argop[4].argop = OP_SAVEFH;
6965 6965  
6966 6966                  argop[5].argop = OP_CPUTFH;
6967 6967                  argop[5].nfs_argop4_u.opcputfh.sfh = drp->r_fh;
6968 6968  
6969 6969                  argop[6].argop = OP_GETATTR;
6970 6970                  argop[6].nfs_argop4_u.opgetattr.attr_request = NFS4_VATTR_MASK;
6971 6971                  argop[6].nfs_argop4_u.opgetattr.mi = mi;
6972 6972  
6973 6973                  argop[7].argop = OP_RESTOREFH;
6974 6974  
6975 6975                  /*
6976 6976                   * nverify
6977 6977                   *
6978 6978                   * XXX - Revisit the last argument to nfs4_end_op()
6979 6979                   *       once 5020486 is fixed.
6980 6980                   */
6981 6981                  _v.va_mask = AT_GID;
6982 6982                  _v.va_gid = va->va_gid;
6983 6983                  if (e.error = nfs4args_verify(&argop[8], &_v, OP_NVERIFY,
6984 6984                      supp_attrs)) {
6985 6985                          nfs4_end_op(mi, dvp, *vpp, &recov_state, TRUE);
6986 6986                          nfs_rw_exit(&drp->r_rwlock);
6987 6987                          nfs4_fattr4_free(crattr);
6988 6988                          kmem_free(argop, argoplist_size);
6989 6989                          return (e.error);
6990 6990                  }
6991 6991  
6992 6992                  /*
6993 6993                   * setattr
6994 6994                   *
6995 6995                   * We _know_ we're not messing with AT_SIZE or AT_XTIME,
6996 6996                   * so no need for stateid or flags. Also we specify NULL
6997 6997                   * rp since we're only interested in setting owner_group
6998 6998                   * attributes.
6999 6999                   */
7000 7000                  nfs4args_setattr(&argop[9], &_v, NULL, 0, NULL, cr, supp_attrs,
7001 7001                      &e.error, 0);
7002 7002  
7003 7003                  if (e.error) {
7004 7004                          nfs4_end_op(mi, dvp, *vpp, &recov_state, TRUE);
7005 7005                          nfs_rw_exit(&drp->r_rwlock);
7006 7006                          nfs4_fattr4_free(crattr);
7007 7007                          nfs4args_verify_free(&argop[8]);
7008 7008                          kmem_free(argop, argoplist_size);
7009 7009                          return (e.error);
7010 7010                  }
7011 7011          } else {
7012 7012                  argop[1].argop = OP_SAVEFH;
7013 7013  
7014 7014                  argop[5].argop = OP_RESTOREFH;
7015 7015  
7016 7016                  argop[6].argop = OP_GETATTR;
7017 7017                  argop[6].nfs_argop4_u.opgetattr.attr_request = NFS4_VATTR_MASK;
7018 7018                  argop[6].nfs_argop4_u.opgetattr.mi = mi;
7019 7019          }
7020 7020  
7021 7021          dnlc_remove(dvp, nm);
7022 7022  
7023 7023          doqueue = 1;
7024 7024          t = gethrtime();
7025 7025          rfs4call(mi, &args, &res, cr, &doqueue, 0, &e);
7026 7026  
7027 7027          needrecov = nfs4_needs_recovery(&e, FALSE, mi->mi_vfsp);
7028 7028          if (e.error) {
7029 7029                  PURGE_ATTRCACHE4(dvp);
7030 7030                  if (!needrecov)
7031 7031                          goto out;
7032 7032          }
7033 7033  
7034 7034          if (needrecov) {
7035 7035                  if (nfs4_start_recovery(&e, mi, dvp, NULL, NULL, NULL,
7036 7036                      OP_CREATE, NULL, NULL, NULL) == FALSE) {
7037 7037                          nfs4_end_op(mi, dvp, NULL, &recov_state,
7038 7038                              needrecov);
7039 7039                          need_end_op = FALSE;
7040 7040                          nfs4_fattr4_free(crattr);
7041 7041                          if (setgid_flag) {
7042 7042                                  nfs4args_verify_free(&argop[8]);
7043 7043                                  nfs4args_setattr_free(&argop[9]);
7044 7044                          }
7045 7045                          (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
7046 7046                          goto recov_retry;
7047 7047                  }
7048 7048          }
7049 7049  
7050 7050          resp = &res;
7051 7051  
7052 7052          if (res.status != NFS4_OK && res.array_len <= idx_fattr + 1) {
7053 7053  
7054 7054                  if (res.status == NFS4ERR_BADOWNER)
7055 7055                          nfs4_log_badowner(mi, OP_CREATE);
7056 7056  
7057 7057                  e.error = geterrno4(res.status);
7058 7058  
7059 7059                  /*
7060 7060                   * This check is left over from when create was implemented
7061 7061                   * using a setattr op (instead of createattrs).  If the
7062 7062                   * putfh/create/getfh failed, the error was returned.  If
7063 7063                   * setattr/getattr failed, we keep going.
7064 7064                   *
7065 7065                   * It might be better to get rid of the GETFH also, and just
7066 7066                   * do PUTFH/CREATE/GETATTR since the FH attr is mandatory.
7067 7067                   * Then if any of the operations failed, we could return the
7068 7068                   * error now, and remove much of the error code below.
7069 7069                   */
7070 7070                  if (res.array_len <= idx_fattr) {
7071 7071                          /*
7072 7072                           * Either Putfh, Create or Getfh failed.
7073 7073                           */
7074 7074                          PURGE_ATTRCACHE4(dvp);
7075 7075                          /*
7076 7076                           * nfs4_purge_stale_fh() may generate otw calls through
7077 7077                           * nfs4_invalidate_pages. Hence the need to call
7078 7078                           * nfs4_end_op() here to avoid nfs4_start_op() deadlock.
7079 7079                           */
7080 7080                          nfs4_end_op(mi, dvp, NULL, &recov_state,
7081 7081                              needrecov);
7082 7082                          need_end_op = FALSE;
7083 7083                          nfs4_purge_stale_fh(e.error, dvp, cr);
7084 7084                          goto out;
7085 7085                  }
7086 7086          }
7087 7087  
7088 7088          resop = &res.array[idx_create]; /* create res */
7089 7089          cinfo = &resop->nfs_resop4_u.opcreate.cinfo;
7090 7090  
7091 7091          resop = &res.array[idx_create + 1]; /* getfh res */
7092 7092          gf_res = &resop->nfs_resop4_u.opgetfh;
7093 7093  
7094 7094          sfhp = sfh4_get(&gf_res->object, mi);
7095 7095          if (e.error) {
7096 7096                  *vpp = vp = makenfs4node(sfhp, NULL, dvp->v_vfsp, t, cr, dvp,
7097 7097                      fn_get(VTOSV(dvp)->sv_name, nm, sfhp));
7098 7098                  if (vp->v_type == VNON) {
7099 7099                          vattr.va_mask = AT_TYPE;
7100 7100                          /*
7101 7101                           * Need to call nfs4_end_op before nfs4getattr to avoid
7102 7102                           * potential nfs4_start_op deadlock. See RFE 4777612.
7103 7103                           */
7104 7104                          nfs4_end_op(mi, dvp, NULL, &recov_state,
7105 7105                              needrecov);
7106 7106                          need_end_op = FALSE;
7107 7107                          e.error = nfs4getattr(vp, &vattr, cr);
7108 7108                          if (e.error) {
7109 7109                                  VN_RELE(vp);
7110 7110                                  *vpp = NULL;
7111 7111                                  goto out;
7112 7112                          }
7113 7113                          vp->v_type = vattr.va_type;
7114 7114                  }
7115 7115                  e.error = 0;
7116 7116          } else {
7117 7117                  *vpp = vp = makenfs4node(sfhp,
7118 7118                      &res.array[idx_fattr].nfs_resop4_u.opgetattr.ga_res,
7119 7119                      dvp->v_vfsp, t, cr,
7120 7120                      dvp, fn_get(VTOSV(dvp)->sv_name, nm, sfhp));
7121 7121          }
7122 7122  
7123 7123          /*
7124 7124           * If compound succeeded, then update dir attrs
7125 7125           */
7126 7126          if (res.status == NFS4_OK) {
7127 7127                  dinfo.di_garp = &res.array[6].nfs_resop4_u.opgetattr.ga_res;
7128 7128                  dinfo.di_cred = cr;
7129 7129                  dinfo.di_time_call = t;
7130 7130                  dinfop = &dinfo;
7131 7131          } else
7132 7132                  dinfop = NULL;
7133 7133  
7134 7134          /* Update directory cache attribute, readdir and dnlc caches */
7135 7135          nfs4_update_dircaches(cinfo, dvp, vp, nm, dinfop);
7136 7136  
7137 7137  out:
7138 7138          if (sfhp != NULL)
7139 7139                  sfh4_rele(&sfhp);
7140 7140          nfs_rw_exit(&drp->r_rwlock);
7141 7141          nfs4_fattr4_free(crattr);
7142 7142          if (setgid_flag) {
7143 7143                  nfs4args_verify_free(&argop[8]);
7144 7144                  nfs4args_setattr_free(&argop[9]);
7145 7145          }
7146 7146          if (resp)
7147 7147                  (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)resp);
7148 7148          if (need_end_op)
7149 7149                  nfs4_end_op(mi, dvp, NULL, &recov_state, needrecov);
7150 7150  
7151 7151          kmem_free(argop, argoplist_size);
7152 7152          return (e.error);
7153 7153  }
7154 7154  
7155 7155  /* ARGSUSED */
7156 7156  static int
7157 7157  nfs4mknod(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive,
7158 7158      int mode, vnode_t **vpp, cred_t *cr)
7159 7159  {
7160 7160          int error;
7161 7161          vnode_t *vp;
7162 7162          nfs_ftype4 type;
7163 7163          specdata4 spec, *specp = NULL;
7164 7164  
7165 7165          ASSERT(nfs_zone() == VTOMI4(dvp)->mi_zone);
7166 7166  
7167 7167          switch (va->va_type) {
7168 7168          case VCHR:
7169 7169          case VBLK:
7170 7170                  type = (va->va_type == VCHR) ? NF4CHR : NF4BLK;
7171 7171                  spec.specdata1 = getmajor(va->va_rdev);
7172 7172                  spec.specdata2 = getminor(va->va_rdev);
7173 7173                  specp = &spec;
7174 7174                  break;
7175 7175  
7176 7176          case VFIFO:
7177 7177                  type = NF4FIFO;
7178 7178                  break;
7179 7179          case VSOCK:
7180 7180                  type = NF4SOCK;
7181 7181                  break;
7182 7182  
7183 7183          default:
7184 7184                  return (EINVAL);
7185 7185          }
7186 7186  
7187 7187          error = call_nfs4_create_req(dvp, nm, specp, va, &vp, cr, type);
7188 7188          if (error) {
7189 7189                  return (error);
7190 7190          }
7191 7191  
7192 7192          /*
7193 7193           * This might not be needed any more; special case to deal
7194 7194           * with problematic v2/v3 servers.  Since create was unable
7195 7195           * to set group correctly, not sure what hope setattr has.
7196 7196           */
7197 7197          if (va->va_gid != VTOR4(vp)->r_attr.va_gid) {
7198 7198                  va->va_mask = AT_GID;
7199 7199                  (void) nfs4setattr(vp, va, 0, cr, NULL);
7200 7200          }
7201 7201  
7202 7202          /*
7203 7203           * If vnode is a device create special vnode
7204 7204           */
7205 7205          if (ISVDEV(vp->v_type)) {
7206 7206                  *vpp = specvp(vp, vp->v_rdev, vp->v_type, cr);
7207 7207                  VN_RELE(vp);
7208 7208          } else {
7209 7209                  *vpp = vp;
7210 7210          }
7211 7211          return (error);
7212 7212  }
7213 7213  
7214 7214  /*
7215 7215   * Remove requires that the current fh be the target directory.
7216 7216   * After the operation, the current fh is unchanged.
7217 7217   * The compound op structure is:
7218 7218   *      PUTFH(targetdir), REMOVE
7219 7219   *
7220 7220   * Weirdness: if the vnode to be removed is open
7221 7221   * we rename it instead of removing it and nfs_inactive
7222 7222   * will remove the new name.
7223 7223   */
7224 7224  /* ARGSUSED */
7225 7225  static int
7226 7226  nfs4_remove(vnode_t *dvp, char *nm, cred_t *cr, caller_context_t *ct, int flags)
7227 7227  {
7228 7228          COMPOUND4args_clnt args;
7229 7229          COMPOUND4res_clnt res, *resp = NULL;
7230 7230          REMOVE4res *rm_res;
7231 7231          nfs_argop4 argop[3];
7232 7232          nfs_resop4 *resop;
7233 7233          vnode_t *vp;
7234 7234          char *tmpname;
7235 7235          int doqueue;
7236 7236          mntinfo4_t *mi;
7237 7237          rnode4_t *rp;
7238 7238          rnode4_t *drp;
7239 7239          int needrecov = 0;
7240 7240          nfs4_recov_state_t recov_state;
7241 7241          int isopen;
7242 7242          nfs4_error_t e = { 0, NFS4_OK, RPC_SUCCESS };
7243 7243          dirattr_info_t dinfo;
7244 7244  
7245 7245          if (nfs_zone() != VTOMI4(dvp)->mi_zone)
7246 7246                  return (EPERM);
7247 7247          drp = VTOR4(dvp);
7248 7248          if (nfs_rw_enter_sig(&drp->r_rwlock, RW_WRITER, INTR4(dvp)))
7249 7249                  return (EINTR);
7250 7250  
7251 7251          e.error = nfs4lookup(dvp, nm, &vp, cr, 0);
7252 7252          if (e.error) {
7253 7253                  nfs_rw_exit(&drp->r_rwlock);
7254 7254                  return (e.error);
7255 7255          }
7256 7256  
7257 7257          if (vp->v_type == VDIR) {
7258 7258                  VN_RELE(vp);
7259 7259                  nfs_rw_exit(&drp->r_rwlock);
7260 7260                  return (EISDIR);
7261 7261          }
7262 7262  
7263 7263          /*
7264 7264           * First just remove the entry from the name cache, as it
7265 7265           * is most likely the only entry for this vp.
7266 7266           */
7267 7267          dnlc_remove(dvp, nm);
7268 7268  
7269 7269          rp = VTOR4(vp);
7270 7270  
7271 7271          /*
7272 7272           * For regular file types, check to see if the file is open by looking
7273 7273           * at the open streams.
7274 7274           * For all other types, check the reference count on the vnode.  Since
7275 7275           * they are not opened OTW they never have an open stream.
7276 7276           *
7277 7277           * If the file is open, rename it to .nfsXXXX.
7278 7278           */
7279 7279          if (vp->v_type != VREG) {
7280 7280                  /*
7281 7281                   * If the file has a v_count > 1 then there may be more than one
7282 7282                   * entry in the name cache due multiple links or an open file,
7283 7283                   * but we don't have the real reference count so flush all
7284 7284                   * possible entries.
7285 7285                   */
7286 7286                  if (vp->v_count > 1)
7287 7287                          dnlc_purge_vp(vp);
7288 7288  
7289 7289                  /*
7290 7290                   * Now we have the real reference count.
7291 7291                   */
7292 7292                  isopen = vp->v_count > 1;
7293 7293          } else {
7294 7294                  mutex_enter(&rp->r_os_lock);
7295 7295                  isopen = list_head(&rp->r_open_streams) != NULL;
7296 7296                  mutex_exit(&rp->r_os_lock);
7297 7297          }
7298 7298  
7299 7299          mutex_enter(&rp->r_statelock);
7300 7300          if (isopen &&
7301 7301              (rp->r_unldvp == NULL || strcmp(nm, rp->r_unlname) == 0)) {
7302 7302                  mutex_exit(&rp->r_statelock);
7303 7303                  tmpname = newname();
7304 7304                  e.error = nfs4rename(dvp, nm, dvp, tmpname, cr, ct);
7305 7305                  if (e.error)
7306 7306                          kmem_free(tmpname, MAXNAMELEN);
7307 7307                  else {
7308 7308                          mutex_enter(&rp->r_statelock);
7309 7309                          if (rp->r_unldvp == NULL) {
7310 7310                                  VN_HOLD(dvp);
7311 7311                                  rp->r_unldvp = dvp;
7312 7312                                  if (rp->r_unlcred != NULL)
7313 7313                                          crfree(rp->r_unlcred);
7314 7314                                  crhold(cr);
7315 7315                                  rp->r_unlcred = cr;
7316 7316                                  rp->r_unlname = tmpname;
7317 7317                          } else {
7318 7318                                  kmem_free(rp->r_unlname, MAXNAMELEN);
7319 7319                                  rp->r_unlname = tmpname;
7320 7320                          }
7321 7321                          mutex_exit(&rp->r_statelock);
7322 7322                  }
7323 7323                  VN_RELE(vp);
7324 7324                  nfs_rw_exit(&drp->r_rwlock);
7325 7325                  return (e.error);
7326 7326          }
7327 7327          /*
7328 7328           * Actually remove the file/dir
7329 7329           */
7330 7330          mutex_exit(&rp->r_statelock);
7331 7331  
7332 7332          /*
7333 7333           * We need to flush any dirty pages which happen to
7334 7334           * be hanging around before removing the file.
7335 7335           * This shouldn't happen very often since in NFSv4
7336 7336           * we should be close to open consistent.
7337 7337           */
7338 7338          if (nfs4_has_pages(vp) &&
7339 7339              ((rp->r_flags & R4DIRTY) || rp->r_count > 0)) {
7340 7340                  e.error = nfs4_putpage(vp, (u_offset_t)0, 0, 0, cr, ct);
7341 7341                  if (e.error && (e.error == ENOSPC || e.error == EDQUOT)) {
7342 7342                          mutex_enter(&rp->r_statelock);
7343 7343                          if (!rp->r_error)
7344 7344                                  rp->r_error = e.error;
7345 7345                          mutex_exit(&rp->r_statelock);
7346 7346                  }
7347 7347          }
7348 7348  
7349 7349          mi = VTOMI4(dvp);
7350 7350  
7351 7351          (void) nfs4delegreturn(rp, NFS4_DR_REOPEN);
7352 7352          recov_state.rs_flags = 0;
7353 7353          recov_state.rs_num_retry_despite_err = 0;
7354 7354  
7355 7355  recov_retry:
7356 7356          /*
7357 7357           * Remove ops: putfh dir; remove
7358 7358           */
7359 7359          args.ctag = TAG_REMOVE;
7360 7360          args.array_len = 3;
7361 7361          args.array = argop;
7362 7362  
7363 7363          e.error = nfs4_start_op(VTOMI4(dvp), dvp, NULL, &recov_state);
7364 7364          if (e.error) {
7365 7365                  nfs_rw_exit(&drp->r_rwlock);
7366 7366                  VN_RELE(vp);
7367 7367                  return (e.error);
7368 7368          }
7369 7369  
7370 7370          /* putfh directory */
7371 7371          argop[0].argop = OP_CPUTFH;
7372 7372          argop[0].nfs_argop4_u.opcputfh.sfh = drp->r_fh;
7373 7373  
7374 7374          /* remove */
7375 7375          argop[1].argop = OP_CREMOVE;
7376 7376          argop[1].nfs_argop4_u.opcremove.ctarget = nm;
7377 7377  
7378 7378          /* getattr dir */
7379 7379          argop[2].argop = OP_GETATTR;
7380 7380          argop[2].nfs_argop4_u.opgetattr.attr_request = NFS4_VATTR_MASK;
7381 7381          argop[2].nfs_argop4_u.opgetattr.mi = mi;
7382 7382  
7383 7383          doqueue = 1;
7384 7384          dinfo.di_time_call = gethrtime();
7385 7385          rfs4call(mi, &args, &res, cr, &doqueue, 0, &e);
7386 7386  
7387 7387          PURGE_ATTRCACHE4(vp);
7388 7388  
7389 7389          needrecov = nfs4_needs_recovery(&e, FALSE, mi->mi_vfsp);
7390 7390          if (e.error)
7391 7391                  PURGE_ATTRCACHE4(dvp);
7392 7392  
7393 7393          if (needrecov) {
7394 7394                  if (nfs4_start_recovery(&e, VTOMI4(dvp), dvp,
7395 7395                      NULL, NULL, NULL, OP_REMOVE, NULL, NULL, NULL) == FALSE) {
7396 7396                          if (!e.error)
7397 7397                                  (void) xdr_free(xdr_COMPOUND4res_clnt,
7398 7398                                      (caddr_t)&res);
7399 7399                          nfs4_end_op(VTOMI4(dvp), dvp, NULL, &recov_state,
7400 7400                              needrecov);
7401 7401                          goto recov_retry;
7402 7402                  }
7403 7403          }
7404 7404  
7405 7405          /*
7406 7406           * Matching nfs4_end_op() for start_op() above.
7407 7407           * There is a path in the code below which calls
7408 7408           * nfs4_purge_stale_fh(), which may generate otw calls through
7409 7409           * nfs4_invalidate_pages. Hence we need to call nfs4_end_op()
7410 7410           * here to avoid nfs4_start_op() deadlock.
7411 7411           */
7412 7412          nfs4_end_op(VTOMI4(dvp), dvp, NULL, &recov_state, needrecov);
7413 7413  
7414 7414          if (!e.error) {
7415 7415                  resp = &res;
7416 7416  
7417 7417                  if (res.status) {
7418 7418                          e.error = geterrno4(res.status);
7419 7419                          PURGE_ATTRCACHE4(dvp);
7420 7420                          nfs4_purge_stale_fh(e.error, dvp, cr);
7421 7421                  } else {
7422 7422                          resop = &res.array[1];  /* remove res */
7423 7423                          rm_res = &resop->nfs_resop4_u.opremove;
7424 7424  
7425 7425                          dinfo.di_garp =
7426 7426                              &res.array[2].nfs_resop4_u.opgetattr.ga_res;
7427 7427                          dinfo.di_cred = cr;
7428 7428  
7429 7429                          /* Update directory attr, readdir and dnlc caches */
7430 7430                          nfs4_update_dircaches(&rm_res->cinfo, dvp, NULL, NULL,
7431 7431                              &dinfo);
7432 7432                  }
7433 7433          }
7434 7434          nfs_rw_exit(&drp->r_rwlock);
7435 7435          if (resp)
7436 7436                  (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)resp);
7437 7437  
7438 7438          if (e.error == 0) {
7439 7439                  vnode_t *tvp;
7440 7440                  rnode4_t *trp;
7441 7441                  trp = VTOR4(vp);
7442 7442                  tvp = vp;
7443 7443                  if (IS_SHADOW(vp, trp))
7444 7444                          tvp = RTOV4(trp);
7445 7445                  vnevent_remove(tvp, dvp, nm, ct);
7446 7446          }
7447 7447          VN_RELE(vp);
7448 7448          return (e.error);
7449 7449  }
7450 7450  
7451 7451  /*
7452 7452   * Link requires that the current fh be the target directory and the
7453 7453   * saved fh be the source fh. After the operation, the current fh is unchanged.
7454 7454   * Thus the compound op structure is:
7455 7455   *      PUTFH(file), SAVEFH, PUTFH(targetdir), LINK, RESTOREFH,
7456 7456   *      GETATTR(file)
7457 7457   */
7458 7458  /* ARGSUSED */
7459 7459  static int
7460 7460  nfs4_link(vnode_t *tdvp, vnode_t *svp, char *tnm, cred_t *cr,
7461 7461      caller_context_t *ct, int flags)
7462 7462  {
7463 7463          COMPOUND4args_clnt args;
7464 7464          COMPOUND4res_clnt res, *resp = NULL;
7465 7465          LINK4res *ln_res;
7466 7466          int argoplist_size  = 7 * sizeof (nfs_argop4);
7467 7467          nfs_argop4 *argop;
7468 7468          nfs_resop4 *resop;
7469 7469          vnode_t *realvp, *nvp;
7470 7470          int doqueue;
7471 7471          mntinfo4_t *mi;
7472 7472          rnode4_t *tdrp;
7473 7473          bool_t needrecov = FALSE;
7474 7474          nfs4_recov_state_t recov_state;
7475 7475          hrtime_t t;
7476 7476          nfs4_error_t e = { 0, NFS4_OK, RPC_SUCCESS };
7477 7477          dirattr_info_t dinfo;
7478 7478  
7479 7479          ASSERT(*tnm != '\0');
7480 7480          ASSERT(tdvp->v_type == VDIR);
7481 7481          ASSERT(nfs4_consistent_type(tdvp));
7482 7482          ASSERT(nfs4_consistent_type(svp));
7483 7483  
7484 7484          if (nfs_zone() != VTOMI4(tdvp)->mi_zone)
7485 7485                  return (EPERM);
7486 7486          if (VOP_REALVP(svp, &realvp, ct) == 0) {
7487 7487                  svp = realvp;
7488 7488                  ASSERT(nfs4_consistent_type(svp));
7489 7489          }
7490 7490  
7491 7491          tdrp = VTOR4(tdvp);
7492 7492          mi = VTOMI4(svp);
7493 7493  
7494 7494          if (!(mi->mi_flags & MI4_LINK)) {
7495 7495                  return (EOPNOTSUPP);
7496 7496          }
7497 7497          recov_state.rs_flags = 0;
7498 7498          recov_state.rs_num_retry_despite_err = 0;
7499 7499  
7500 7500          if (nfs_rw_enter_sig(&tdrp->r_rwlock, RW_WRITER, INTR4(tdvp)))
7501 7501                  return (EINTR);
7502 7502  
7503 7503  recov_retry:
7504 7504          argop = kmem_alloc(argoplist_size, KM_SLEEP);
7505 7505  
7506 7506          args.ctag = TAG_LINK;
7507 7507  
7508 7508          /*
7509 7509           * Link ops: putfh fl; savefh; putfh tdir; link; getattr(dir);
7510 7510           * restorefh; getattr(fl)
7511 7511           */
7512 7512          args.array_len = 7;
7513 7513          args.array = argop;
7514 7514  
7515 7515          e.error = nfs4_start_op(VTOMI4(svp), svp, tdvp, &recov_state);
7516 7516          if (e.error) {
7517 7517                  kmem_free(argop, argoplist_size);
7518 7518                  nfs_rw_exit(&tdrp->r_rwlock);
7519 7519                  return (e.error);
7520 7520          }
7521 7521  
7522 7522          /* 0. putfh file */
7523 7523          argop[0].argop = OP_CPUTFH;
7524 7524          argop[0].nfs_argop4_u.opcputfh.sfh = VTOR4(svp)->r_fh;
7525 7525  
7526 7526          /* 1. save current fh to free up the space for the dir */
7527 7527          argop[1].argop = OP_SAVEFH;
7528 7528  
7529 7529          /* 2. putfh targetdir */
7530 7530          argop[2].argop = OP_CPUTFH;
7531 7531          argop[2].nfs_argop4_u.opcputfh.sfh = tdrp->r_fh;
7532 7532  
7533 7533          /* 3. link: current_fh is targetdir, saved_fh is source */
7534 7534          argop[3].argop = OP_CLINK;
7535 7535          argop[3].nfs_argop4_u.opclink.cnewname = tnm;
7536 7536  
7537 7537          /* 4. Get attributes of dir */
7538 7538          argop[4].argop = OP_GETATTR;
7539 7539          argop[4].nfs_argop4_u.opgetattr.attr_request = NFS4_VATTR_MASK;
7540 7540          argop[4].nfs_argop4_u.opgetattr.mi = mi;
7541 7541  
7542 7542          /* 5. If link was successful, restore current vp to file */
7543 7543          argop[5].argop = OP_RESTOREFH;
7544 7544  
7545 7545          /* 6. Get attributes of linked object */
7546 7546          argop[6].argop = OP_GETATTR;
7547 7547          argop[6].nfs_argop4_u.opgetattr.attr_request = NFS4_VATTR_MASK;
7548 7548          argop[6].nfs_argop4_u.opgetattr.mi = mi;
7549 7549  
7550 7550          dnlc_remove(tdvp, tnm);
7551 7551  
7552 7552          doqueue = 1;
7553 7553          t = gethrtime();
7554 7554  
7555 7555          rfs4call(VTOMI4(svp), &args, &res, cr, &doqueue, 0, &e);
7556 7556  
7557 7557          needrecov = nfs4_needs_recovery(&e, FALSE, svp->v_vfsp);
7558 7558          if (e.error != 0 && !needrecov) {
7559 7559                  PURGE_ATTRCACHE4(tdvp);
7560 7560                  PURGE_ATTRCACHE4(svp);
7561 7561                  nfs4_end_op(VTOMI4(svp), svp, tdvp, &recov_state, needrecov);
7562 7562                  goto out;
7563 7563          }
7564 7564  
7565 7565          if (needrecov) {
7566 7566                  bool_t abort;
7567 7567  
7568 7568                  abort = nfs4_start_recovery(&e, VTOMI4(svp), svp, tdvp,
7569 7569                      NULL, NULL, OP_LINK, NULL, NULL, NULL);
7570 7570                  if (abort == FALSE) {
7571 7571                          nfs4_end_op(VTOMI4(svp), svp, tdvp, &recov_state,
7572 7572                              needrecov);
7573 7573                          kmem_free(argop, argoplist_size);
7574 7574                          if (!e.error)
7575 7575                                  (void) xdr_free(xdr_COMPOUND4res_clnt,
7576 7576                                      (caddr_t)&res);
7577 7577                          goto recov_retry;
7578 7578                  } else {
7579 7579                          if (e.error != 0) {
7580 7580                                  PURGE_ATTRCACHE4(tdvp);
7581 7581                                  PURGE_ATTRCACHE4(svp);
7582 7582                                  nfs4_end_op(VTOMI4(svp), svp, tdvp,
7583 7583                                      &recov_state, needrecov);
7584 7584                                  goto out;
7585 7585                          }
7586 7586                          /* fall through for res.status case */
7587 7587                  }
7588 7588          }
7589 7589  
7590 7590          nfs4_end_op(VTOMI4(svp), svp, tdvp, &recov_state, needrecov);
7591 7591  
7592 7592          resp = &res;
7593 7593          if (res.status) {
7594 7594                  /* If link succeeded, then don't return error */
7595 7595                  e.error = geterrno4(res.status);
7596 7596                  if (res.array_len <= 4) {
7597 7597                          /*
7598 7598                           * Either Putfh, Savefh, Putfh dir, or Link failed
7599 7599                           */
7600 7600                          PURGE_ATTRCACHE4(svp);
7601 7601                          PURGE_ATTRCACHE4(tdvp);
7602 7602                          if (e.error == EOPNOTSUPP) {
7603 7603                                  mutex_enter(&mi->mi_lock);
7604 7604                                  mi->mi_flags &= ~MI4_LINK;
7605 7605                                  mutex_exit(&mi->mi_lock);
7606 7606                          }
7607 7607                          /* Remap EISDIR to EPERM for non-root user for SVVS */
7608 7608                          /* XXX-LP */
7609 7609                          if (e.error == EISDIR && crgetuid(cr) != 0)
7610 7610                                  e.error = EPERM;
7611 7611                          goto out;
7612 7612                  }
7613 7613          }
7614 7614  
7615 7615          /* either no error or one of the postop getattr failed */
7616 7616  
7617 7617          /*
7618 7618           * XXX - if LINK succeeded, but no attrs were returned for link
7619 7619           * file, purge its cache.
7620 7620           *
7621 7621           * XXX Perform a simplified version of wcc checking. Instead of
7622 7622           * have another getattr to get pre-op, just purge cache if
7623 7623           * any of the ops prior to and including the getattr failed.
7624 7624           * If the getattr succeeded then update the attrcache accordingly.
7625 7625           */
7626 7626  
7627 7627          /*
7628 7628           * update cache with link file postattrs.
7629 7629           * Note: at this point resop points to link res.
7630 7630           */
7631 7631          resop = &res.array[3];  /* link res */
7632 7632          ln_res = &resop->nfs_resop4_u.oplink;
7633 7633          if (res.status == NFS4_OK)
7634 7634                  e.error = nfs4_update_attrcache(res.status,
7635 7635                      &res.array[6].nfs_resop4_u.opgetattr.ga_res,
7636 7636                      t, svp, cr);
7637 7637  
7638 7638          /*
7639 7639           * Call makenfs4node to create the new shadow vp for tnm.
7640 7640           * We pass NULL attrs because we just cached attrs for
7641 7641           * the src object.  All we're trying to accomplish is to
7642 7642           * to create the new shadow vnode.
7643 7643           */
7644 7644          nvp = makenfs4node(VTOR4(svp)->r_fh, NULL, tdvp->v_vfsp, t, cr,
7645 7645              tdvp, fn_get(VTOSV(tdvp)->sv_name, tnm, VTOR4(svp)->r_fh));
7646 7646  
7647 7647          /* Update target cache attribute, readdir and dnlc caches */
7648 7648          dinfo.di_garp = &res.array[4].nfs_resop4_u.opgetattr.ga_res;
7649 7649          dinfo.di_time_call = t;
7650 7650          dinfo.di_cred = cr;
7651 7651  
7652 7652          nfs4_update_dircaches(&ln_res->cinfo, tdvp, nvp, tnm, &dinfo);
7653 7653          ASSERT(nfs4_consistent_type(tdvp));
7654 7654          ASSERT(nfs4_consistent_type(svp));
7655 7655          ASSERT(nfs4_consistent_type(nvp));
7656 7656          VN_RELE(nvp);
7657 7657  
7658 7658          if (!e.error) {
7659 7659                  vnode_t *tvp;
7660 7660                  rnode4_t *trp;
7661 7661                  /*
7662 7662                   * Notify the source file of this link operation.
7663 7663                   */
7664 7664                  trp = VTOR4(svp);
7665 7665                  tvp = svp;
7666 7666                  if (IS_SHADOW(svp, trp))
7667 7667                          tvp = RTOV4(trp);
7668 7668                  vnevent_link(tvp, ct);
7669 7669          }
7670 7670  out:
7671 7671          kmem_free(argop, argoplist_size);
7672 7672          if (resp)
7673 7673                  (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)resp);
7674 7674  
7675 7675          nfs_rw_exit(&tdrp->r_rwlock);
7676 7676  
7677 7677          return (e.error);
7678 7678  }
7679 7679  
7680 7680  /* ARGSUSED */
7681 7681  static int
7682 7682  nfs4_rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr,
7683 7683      caller_context_t *ct, int flags)
7684 7684  {
7685 7685          vnode_t *realvp;
7686 7686  
7687 7687          if (nfs_zone() != VTOMI4(odvp)->mi_zone)
7688 7688                  return (EPERM);
7689 7689          if (VOP_REALVP(ndvp, &realvp, ct) == 0)
7690 7690                  ndvp = realvp;
7691 7691  
7692 7692          return (nfs4rename(odvp, onm, ndvp, nnm, cr, ct));
7693 7693  }
7694 7694  
7695 7695  /*
7696 7696   * nfs4rename does the real work of renaming in NFS Version 4.
7697 7697   *
7698 7698   * A file handle is considered volatile for renaming purposes if either
7699 7699   * of the volatile bits are turned on. However, the compound may differ
7700 7700   * based on the likelihood of the filehandle to change during rename.
7701 7701   */
7702 7702  static int
7703 7703  nfs4rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr,
7704 7704      caller_context_t *ct)
7705 7705  {
7706 7706          int error;
7707 7707          mntinfo4_t *mi;
7708 7708          vnode_t *nvp = NULL;
7709 7709          vnode_t *ovp = NULL;
7710 7710          char *tmpname = NULL;
7711 7711          rnode4_t *rp;
7712 7712          rnode4_t *odrp;
7713 7713          rnode4_t *ndrp;
7714 7714          int did_link = 0;
7715 7715          int do_link = 1;
7716 7716          nfsstat4 stat = NFS4_OK;
7717 7717  
7718 7718          ASSERT(nfs_zone() == VTOMI4(odvp)->mi_zone);
7719 7719          ASSERT(nfs4_consistent_type(odvp));
7720 7720          ASSERT(nfs4_consistent_type(ndvp));
7721 7721  
7722 7722          if (onm[0] == '.' && (onm[1] == '\0' ||
7723 7723              (onm[1] == '.' && onm[2] == '\0')))
7724 7724                  return (EINVAL);
7725 7725  
7726 7726          if (nnm[0] == '.' && (nnm[1] == '\0' ||
7727 7727              (nnm[1] == '.' && nnm[2] == '\0')))
7728 7728                  return (EINVAL);
7729 7729  
7730 7730          odrp = VTOR4(odvp);
7731 7731          ndrp = VTOR4(ndvp);
7732 7732          if ((intptr_t)odrp < (intptr_t)ndrp) {
7733 7733                  if (nfs_rw_enter_sig(&odrp->r_rwlock, RW_WRITER, INTR4(odvp)))
7734 7734                          return (EINTR);
7735 7735                  if (nfs_rw_enter_sig(&ndrp->r_rwlock, RW_WRITER, INTR4(ndvp))) {
7736 7736                          nfs_rw_exit(&odrp->r_rwlock);
7737 7737                          return (EINTR);
7738 7738                  }
7739 7739          } else {
7740 7740                  if (nfs_rw_enter_sig(&ndrp->r_rwlock, RW_WRITER, INTR4(ndvp)))
7741 7741                          return (EINTR);
7742 7742                  if (nfs_rw_enter_sig(&odrp->r_rwlock, RW_WRITER, INTR4(odvp))) {
7743 7743                          nfs_rw_exit(&ndrp->r_rwlock);
7744 7744                          return (EINTR);
7745 7745                  }
7746 7746          }
7747 7747  
7748 7748          /*
7749 7749           * Lookup the target file.  If it exists, it needs to be
7750 7750           * checked to see whether it is a mount point and whether
7751 7751           * it is active (open).
7752 7752           */
7753 7753          error = nfs4lookup(ndvp, nnm, &nvp, cr, 0);
7754 7754          if (!error) {
7755 7755                  int     isactive;
7756 7756  
7757 7757                  ASSERT(nfs4_consistent_type(nvp));
7758 7758                  /*
7759 7759                   * If this file has been mounted on, then just
7760 7760                   * return busy because renaming to it would remove
7761 7761                   * the mounted file system from the name space.
7762 7762                   */
7763 7763                  if (vn_ismntpt(nvp)) {
7764 7764                          VN_RELE(nvp);
7765 7765                          nfs_rw_exit(&odrp->r_rwlock);
7766 7766                          nfs_rw_exit(&ndrp->r_rwlock);
7767 7767                          return (EBUSY);
7768 7768                  }
7769 7769  
7770 7770                  /*
7771 7771                   * First just remove the entry from the name cache, as it
7772 7772                   * is most likely the only entry for this vp.
7773 7773                   */
7774 7774                  dnlc_remove(ndvp, nnm);
7775 7775  
7776 7776                  rp = VTOR4(nvp);
7777 7777  
7778 7778                  if (nvp->v_type != VREG) {
7779 7779                          /*
7780 7780                           * Purge the name cache of all references to this vnode
7781 7781                           * so that we can check the reference count to infer
7782 7782                           * whether it is active or not.
7783 7783                           */
7784 7784                          if (nvp->v_count > 1)
7785 7785                                  dnlc_purge_vp(nvp);
7786 7786  
7787 7787                          isactive = nvp->v_count > 1;
7788 7788                  } else {
7789 7789                          mutex_enter(&rp->r_os_lock);
7790 7790                          isactive = list_head(&rp->r_open_streams) != NULL;
7791 7791                          mutex_exit(&rp->r_os_lock);
7792 7792                  }
7793 7793  
7794 7794                  /*
7795 7795                   * If the vnode is active and is not a directory,
7796 7796                   * arrange to rename it to a
7797 7797                   * temporary file so that it will continue to be
7798 7798                   * accessible.  This implements the "unlink-open-file"
7799 7799                   * semantics for the target of a rename operation.
7800 7800                   * Before doing this though, make sure that the
7801 7801                   * source and target files are not already the same.
7802 7802                   */
7803 7803                  if (isactive && nvp->v_type != VDIR) {
7804 7804                          /*
7805 7805                           * Lookup the source name.
7806 7806                           */
7807 7807                          error = nfs4lookup(odvp, onm, &ovp, cr, 0);
7808 7808  
7809 7809                          /*
7810 7810                           * The source name *should* already exist.
7811 7811                           */
7812 7812                          if (error) {
7813 7813                                  VN_RELE(nvp);
7814 7814                                  nfs_rw_exit(&odrp->r_rwlock);
7815 7815                                  nfs_rw_exit(&ndrp->r_rwlock);
7816 7816                                  return (error);
7817 7817                          }
7818 7818  
7819 7819                          ASSERT(nfs4_consistent_type(ovp));
7820 7820  
7821 7821                          /*
7822 7822                           * Compare the two vnodes.  If they are the same,
7823 7823                           * just release all held vnodes and return success.
7824 7824                           */
7825 7825                          if (VN_CMP(ovp, nvp)) {
7826 7826                                  VN_RELE(ovp);
7827 7827                                  VN_RELE(nvp);
7828 7828                                  nfs_rw_exit(&odrp->r_rwlock);
7829 7829                                  nfs_rw_exit(&ndrp->r_rwlock);
7830 7830                                  return (0);
7831 7831                          }
7832 7832  
7833 7833                          /*
7834 7834                           * Can't mix and match directories and non-
7835 7835                           * directories in rename operations.  We already
7836 7836                           * know that the target is not a directory.  If
7837 7837                           * the source is a directory, return an error.
7838 7838                           */
7839 7839                          if (ovp->v_type == VDIR) {
7840 7840                                  VN_RELE(ovp);
7841 7841                                  VN_RELE(nvp);
7842 7842                                  nfs_rw_exit(&odrp->r_rwlock);
7843 7843                                  nfs_rw_exit(&ndrp->r_rwlock);
7844 7844                                  return (ENOTDIR);
7845 7845                          }
7846 7846  link_call:
7847 7847                          /*
7848 7848                           * The target file exists, is not the same as
7849 7849                           * the source file, and is active.  We first
7850 7850                           * try to Link it to a temporary filename to
7851 7851                           * avoid having the server removing the file
7852 7852                           * completely (which could cause data loss to
7853 7853                           * the user's POV in the event the Rename fails
7854 7854                           * -- see bug 1165874).
7855 7855                           */
7856 7856                          /*
7857 7857                           * The do_link and did_link booleans are
7858 7858                           * introduced in the event we get NFS4ERR_FILE_OPEN
7859 7859                           * returned for the Rename.  Some servers can
7860 7860                           * not Rename over an Open file, so they return
7861 7861                           * this error.  The client needs to Remove the
7862 7862                           * newly created Link and do two Renames, just
7863 7863                           * as if the server didn't support LINK.
7864 7864                           */
7865 7865                          tmpname = newname();
7866 7866                          error = 0;
7867 7867  
7868 7868                          if (do_link) {
7869 7869                                  error = nfs4_link(ndvp, nvp, tmpname, cr,
7870 7870                                      NULL, 0);
7871 7871                          }
7872 7872                          if (error == EOPNOTSUPP || !do_link) {
7873 7873                                  error = nfs4_rename(ndvp, nnm, ndvp, tmpname,
7874 7874                                      cr, NULL, 0);
7875 7875                                  did_link = 0;
7876 7876                          } else {
7877 7877                                  did_link = 1;
7878 7878                          }
7879 7879                          if (error) {
7880 7880                                  kmem_free(tmpname, MAXNAMELEN);
7881 7881                                  VN_RELE(ovp);
7882 7882                                  VN_RELE(nvp);
7883 7883                                  nfs_rw_exit(&odrp->r_rwlock);
7884 7884                                  nfs_rw_exit(&ndrp->r_rwlock);
7885 7885                                  return (error);
7886 7886                          }
7887 7887  
7888 7888                          mutex_enter(&rp->r_statelock);
7889 7889                          if (rp->r_unldvp == NULL) {
7890 7890                                  VN_HOLD(ndvp);
7891 7891                                  rp->r_unldvp = ndvp;
7892 7892                                  if (rp->r_unlcred != NULL)
7893 7893                                          crfree(rp->r_unlcred);
7894 7894                                  crhold(cr);
7895 7895                                  rp->r_unlcred = cr;
7896 7896                                  rp->r_unlname = tmpname;
7897 7897                          } else {
7898 7898                                  if (rp->r_unlname)
7899 7899                                          kmem_free(rp->r_unlname, MAXNAMELEN);
7900 7900                                  rp->r_unlname = tmpname;
7901 7901                          }
7902 7902                          mutex_exit(&rp->r_statelock);
7903 7903                  }
7904 7904  
7905 7905                  (void) nfs4delegreturn(VTOR4(nvp), NFS4_DR_PUSH|NFS4_DR_REOPEN);
7906 7906  
7907 7907                  ASSERT(nfs4_consistent_type(nvp));
7908 7908          }
7909 7909  
7910 7910          if (ovp == NULL) {
7911 7911                  /*
7912 7912                   * When renaming directories to be a subdirectory of a
7913 7913                   * different parent, the dnlc entry for ".." will no
7914 7914                   * longer be valid, so it must be removed.
7915 7915                   *
7916 7916                   * We do a lookup here to determine whether we are renaming
7917 7917                   * a directory and we need to check if we are renaming
7918 7918                   * an unlinked file.  This might have already been done
7919 7919                   * in previous code, so we check ovp == NULL to avoid
7920 7920                   * doing it twice.
7921 7921                   */
7922 7922                  error = nfs4lookup(odvp, onm, &ovp, cr, 0);
7923 7923                  /*
7924 7924                   * The source name *should* already exist.
7925 7925                   */
7926 7926                  if (error) {
7927 7927                          nfs_rw_exit(&odrp->r_rwlock);
7928 7928                          nfs_rw_exit(&ndrp->r_rwlock);
7929 7929                          if (nvp) {
7930 7930                                  VN_RELE(nvp);
7931 7931                          }
7932 7932                          return (error);
7933 7933                  }
7934 7934                  ASSERT(ovp != NULL);
7935 7935                  ASSERT(nfs4_consistent_type(ovp));
7936 7936          }
7937 7937  
7938 7938          /*
7939 7939           * Is the object being renamed a dir, and if so, is
7940 7940           * it being renamed to a child of itself?  The underlying
7941 7941           * fs should ultimately return EINVAL for this case;
7942 7942           * however, buggy beta non-Solaris NFSv4 servers at
7943 7943           * interop testing events have allowed this behavior,
7944 7944           * and it caused our client to panic due to a recursive
7945 7945           * mutex_enter in fn_move.
7946 7946           *
7947 7947           * The tedious locking in fn_move could be changed to
7948 7948           * deal with this case, and the client could avoid the
7949 7949           * panic; however, the client would just confuse itself
7950 7950           * later and misbehave.  A better way to handle the broken
7951 7951           * server is to detect this condition and return EINVAL
7952 7952           * without ever sending the the bogus rename to the server.
7953 7953           * We know the rename is invalid -- just fail it now.
7954 7954           */
7955 7955          if (ovp->v_type == VDIR && VN_CMP(ndvp, ovp)) {
7956 7956                  VN_RELE(ovp);
7957 7957                  nfs_rw_exit(&odrp->r_rwlock);
7958 7958                  nfs_rw_exit(&ndrp->r_rwlock);
7959 7959                  if (nvp) {
7960 7960                          VN_RELE(nvp);
7961 7961                  }
7962 7962                  return (EINVAL);
7963 7963          }
7964 7964  
7965 7965          (void) nfs4delegreturn(VTOR4(ovp), NFS4_DR_PUSH|NFS4_DR_REOPEN);
7966 7966  
7967 7967          /*
7968 7968           * If FH4_VOL_RENAME or FH4_VOLATILE_ANY bits are set, it is
7969 7969           * possible for the filehandle to change due to the rename.
7970 7970           * If neither of these bits is set, but FH4_VOL_MIGRATION is set,
7971 7971           * the fh will not change because of the rename, but we still need
7972 7972           * to update its rnode entry with the new name for
7973 7973           * an eventual fh change due to migration. The FH4_NOEXPIRE_ON_OPEN
7974 7974           * has no effect on these for now, but for future improvements,
7975 7975           * we might want to use it too to simplify handling of files
7976 7976           * that are open with that flag on. (XXX)
7977 7977           */
7978 7978          mi = VTOMI4(odvp);
7979 7979          if (NFS4_VOLATILE_FH(mi))
7980 7980                  error = nfs4rename_volatile_fh(odvp, onm, ovp, ndvp, nnm, cr,
7981 7981                      &stat);
7982 7982          else
7983 7983                  error = nfs4rename_persistent_fh(odvp, onm, ovp, ndvp, nnm, cr,
7984 7984                      &stat);
7985 7985  
7986 7986          ASSERT(nfs4_consistent_type(odvp));
7987 7987          ASSERT(nfs4_consistent_type(ndvp));
7988 7988          ASSERT(nfs4_consistent_type(ovp));
7989 7989  
7990 7990          if (stat == NFS4ERR_FILE_OPEN && did_link) {
7991 7991                  do_link = 0;
7992 7992                  /*
7993 7993                   * Before the 'link_call' code, we did a nfs4_lookup
7994 7994                   * that puts a VN_HOLD on nvp.  After the nfs4_link
7995 7995                   * call we call VN_RELE to match that hold.  We need
7996 7996                   * to place an additional VN_HOLD here since we will
7997 7997                   * be hitting that VN_RELE again.
7998 7998                   */
7999 7999                  VN_HOLD(nvp);
8000 8000  
8001 8001                  (void) nfs4_remove(ndvp, tmpname, cr, NULL, 0);
8002 8002  
8003 8003                  /* Undo the unlinked file naming stuff we just did */
8004 8004                  mutex_enter(&rp->r_statelock);
8005 8005                  if (rp->r_unldvp) {
8006 8006                          VN_RELE(ndvp);
8007 8007                          rp->r_unldvp = NULL;
8008 8008                          if (rp->r_unlcred != NULL)
8009 8009                                  crfree(rp->r_unlcred);
8010 8010                          rp->r_unlcred = NULL;
8011 8011                          /* rp->r_unlanme points to tmpname */
8012 8012                          if (rp->r_unlname)
8013 8013                                  kmem_free(rp->r_unlname, MAXNAMELEN);
8014 8014                          rp->r_unlname = NULL;
8015 8015                  }
8016 8016                  mutex_exit(&rp->r_statelock);
8017 8017  
8018 8018                  if (nvp) {
8019 8019                          VN_RELE(nvp);
8020 8020                  }
8021 8021                  goto link_call;
8022 8022          }
8023 8023  
8024 8024          if (error) {
8025 8025                  VN_RELE(ovp);
8026 8026                  nfs_rw_exit(&odrp->r_rwlock);
8027 8027                  nfs_rw_exit(&ndrp->r_rwlock);
8028 8028                  if (nvp) {
8029 8029                          VN_RELE(nvp);
8030 8030                  }
8031 8031                  return (error);
8032 8032          }
8033 8033  
8034 8034          /*
8035 8035           * when renaming directories to be a subdirectory of a
8036 8036           * different parent, the dnlc entry for ".." will no
8037 8037           * longer be valid, so it must be removed
8038 8038           */
8039 8039          rp = VTOR4(ovp);
8040 8040          if (ndvp != odvp) {
8041 8041                  if (ovp->v_type == VDIR) {
8042 8042                          dnlc_remove(ovp, "..");
8043 8043                          if (rp->r_dir != NULL)
8044 8044                                  nfs4_purge_rddir_cache(ovp);
8045 8045                  }
8046 8046          }
8047 8047  
8048 8048          /*
8049 8049           * If we are renaming the unlinked file, update the
8050 8050           * r_unldvp and r_unlname as needed.
8051 8051           */
8052 8052          mutex_enter(&rp->r_statelock);
8053 8053          if (rp->r_unldvp != NULL) {
8054 8054                  if (strcmp(rp->r_unlname, onm) == 0) {
8055 8055                          (void) strncpy(rp->r_unlname, nnm, MAXNAMELEN);
8056 8056                          rp->r_unlname[MAXNAMELEN - 1] = '\0';
8057 8057                          if (ndvp != rp->r_unldvp) {
8058 8058                                  VN_RELE(rp->r_unldvp);
8059 8059                                  rp->r_unldvp = ndvp;
8060 8060                                  VN_HOLD(ndvp);
8061 8061                          }
8062 8062                  }
8063 8063          }
8064 8064          mutex_exit(&rp->r_statelock);
8065 8065  
8066 8066          /*
8067 8067           * Notify the rename vnevents to source vnode, and to the target
8068 8068           * vnode if it already existed.
8069 8069           */
8070 8070          if (error == 0) {
8071 8071                  vnode_t *tvp, *tovp;
8072 8072                  rnode4_t *trp;
8073 8073  
8074 8074                  /*
8075 8075                   * Notify the vnode. Each links is represented by
8076 8076                   * a different vnode, in nfsv4.
8077 8077                   */
8078 8078                  if (nvp) {
8079 8079                          trp = VTOR4(nvp);
8080 8080                          tvp = nvp;
8081 8081                          if (IS_SHADOW(nvp, trp))
8082 8082                                  tvp = RTOV4(trp);
8083 8083                          vnevent_rename_dest(tvp, ndvp, nnm, ct);
8084 8084                  }
8085 8085  
8086 8086                  trp = VTOR4(ovp);
8087 8087                  tovp = ovp;
8088 8088                  if (IS_SHADOW(ovp, trp))
8089 8089                          tovp = RTOV4(trp);
8090 8090  
8091 8091                  vnevent_rename_src(tovp, odvp, onm, ct);
8092 8092  
8093 8093                  trp = VTOR4(ndvp);
8094 8094                  tvp = ndvp;
8095 8095  
8096 8096                  if (IS_SHADOW(ndvp, trp))
8097 8097                          tvp = RTOV4(trp);
8098 8098  
8099 8099                  vnevent_rename_dest_dir(tvp, tovp, nnm, ct);
8100 8100          }
8101 8101  
8102 8102          if (nvp) {
8103 8103                  VN_RELE(nvp);
8104 8104          }
8105 8105          VN_RELE(ovp);
8106 8106  
8107 8107          nfs_rw_exit(&odrp->r_rwlock);
8108 8108          nfs_rw_exit(&ndrp->r_rwlock);
8109 8109  
8110 8110          return (error);
8111 8111  }
8112 8112  
8113 8113  /*
8114 8114   * When the parent directory has changed, sv_dfh must be updated
8115 8115   */
8116 8116  static void
8117 8117  update_parentdir_sfh(vnode_t *vp, vnode_t *ndvp)
8118 8118  {
8119 8119          svnode_t *sv = VTOSV(vp);
8120 8120          nfs4_sharedfh_t *old_dfh = sv->sv_dfh;
8121 8121          nfs4_sharedfh_t *new_dfh = VTOR4(ndvp)->r_fh;
8122 8122  
8123 8123          sfh4_hold(new_dfh);
8124 8124          sv->sv_dfh = new_dfh;
8125 8125          sfh4_rele(&old_dfh);
8126 8126  }
8127 8127  
8128 8128  /*
8129 8129   * nfs4rename_persistent does the otw portion of renaming in NFS Version 4,
8130 8130   * when it is known that the filehandle is persistent through rename.
8131 8131   *
8132 8132   * Rename requires that the current fh be the target directory and the
8133 8133   * saved fh be the source directory. After the operation, the current fh
8134 8134   * is unchanged.
8135 8135   * The compound op structure for persistent fh rename is:
8136 8136   *      PUTFH(sourcdir), SAVEFH, PUTFH(targetdir), RENAME
8137 8137   * Rather than bother with the directory postop args, we'll simply
8138 8138   * update that a change occurred in the cache, so no post-op getattrs.
8139 8139   */
8140 8140  static int
8141 8141  nfs4rename_persistent_fh(vnode_t *odvp, char *onm, vnode_t *renvp,
8142 8142      vnode_t *ndvp, char *nnm, cred_t *cr, nfsstat4 *statp)
8143 8143  {
8144 8144          COMPOUND4args_clnt args;
8145 8145          COMPOUND4res_clnt res, *resp = NULL;
8146 8146          nfs_argop4 *argop;
8147 8147          nfs_resop4 *resop;
8148 8148          int doqueue, argoplist_size;
8149 8149          mntinfo4_t *mi;
8150 8150          rnode4_t *odrp = VTOR4(odvp);
8151 8151          rnode4_t *ndrp = VTOR4(ndvp);
8152 8152          RENAME4res *rn_res;
8153 8153          bool_t needrecov;
8154 8154          nfs4_recov_state_t recov_state;
8155 8155          nfs4_error_t e = { 0, NFS4_OK, RPC_SUCCESS };
8156 8156          dirattr_info_t dinfo, *dinfop;
8157 8157  
8158 8158          ASSERT(nfs_zone() == VTOMI4(odvp)->mi_zone);
8159 8159  
8160 8160          recov_state.rs_flags = 0;
8161 8161          recov_state.rs_num_retry_despite_err = 0;
8162 8162  
8163 8163          /*
8164 8164           * Rename ops: putfh sdir; savefh; putfh tdir; rename; getattr tdir
8165 8165           *
8166 8166           * If source/target are different dirs, then append putfh(src); getattr
8167 8167           */
8168 8168          args.array_len = (odvp == ndvp) ? 5 : 7;
8169 8169          argoplist_size = args.array_len * sizeof (nfs_argop4);
8170 8170          args.array = argop = kmem_alloc(argoplist_size, KM_SLEEP);
8171 8171  
8172 8172  recov_retry:
8173 8173          *statp = NFS4_OK;
8174 8174  
8175 8175          /* No need to Lookup the file, persistent fh */
8176 8176          args.ctag = TAG_RENAME;
8177 8177  
8178 8178          mi = VTOMI4(odvp);
8179 8179          e.error = nfs4_start_op(mi, odvp, ndvp, &recov_state);
8180 8180          if (e.error) {
8181 8181                  kmem_free(argop, argoplist_size);
8182 8182                  return (e.error);
8183 8183          }
8184 8184  
8185 8185          /* 0: putfh source directory */
8186 8186          argop[0].argop = OP_CPUTFH;
8187 8187          argop[0].nfs_argop4_u.opcputfh.sfh = odrp->r_fh;
8188 8188  
8189 8189          /* 1: Save source fh to free up current for target */
8190 8190          argop[1].argop = OP_SAVEFH;
8191 8191  
8192 8192          /* 2: putfh targetdir */
8193 8193          argop[2].argop = OP_CPUTFH;
8194 8194          argop[2].nfs_argop4_u.opcputfh.sfh = ndrp->r_fh;
8195 8195  
8196 8196          /* 3: current_fh is targetdir, saved_fh is sourcedir */
8197 8197          argop[3].argop = OP_CRENAME;
8198 8198          argop[3].nfs_argop4_u.opcrename.coldname = onm;
8199 8199          argop[3].nfs_argop4_u.opcrename.cnewname = nnm;
8200 8200  
8201 8201          /* 4: getattr (targetdir) */
8202 8202          argop[4].argop = OP_GETATTR;
8203 8203          argop[4].nfs_argop4_u.opgetattr.attr_request = NFS4_VATTR_MASK;
8204 8204          argop[4].nfs_argop4_u.opgetattr.mi = mi;
8205 8205  
8206 8206          if (ndvp != odvp) {
8207 8207  
8208 8208                  /* 5: putfh (sourcedir) */
8209 8209                  argop[5].argop = OP_CPUTFH;
8210 8210                  argop[5].nfs_argop4_u.opcputfh.sfh = ndrp->r_fh;
8211 8211  
8212 8212                  /* 6: getattr (sourcedir) */
8213 8213                  argop[6].argop = OP_GETATTR;
8214 8214                  argop[6].nfs_argop4_u.opgetattr.attr_request = NFS4_VATTR_MASK;
8215 8215                  argop[6].nfs_argop4_u.opgetattr.mi = mi;
8216 8216          }
8217 8217  
8218 8218          dnlc_remove(odvp, onm);
8219 8219          dnlc_remove(ndvp, nnm);
8220 8220  
8221 8221          doqueue = 1;
8222 8222          dinfo.di_time_call = gethrtime();
8223 8223          rfs4call(mi, &args, &res, cr, &doqueue, 0, &e);
8224 8224  
8225 8225          needrecov = nfs4_needs_recovery(&e, FALSE, mi->mi_vfsp);
8226 8226          if (e.error) {
8227 8227                  PURGE_ATTRCACHE4(odvp);
8228 8228                  PURGE_ATTRCACHE4(ndvp);
8229 8229          } else {
8230 8230                  *statp = res.status;
8231 8231          }
8232 8232  
8233 8233          if (needrecov) {
8234 8234                  if (nfs4_start_recovery(&e, mi, odvp, ndvp, NULL, NULL,
8235 8235                      OP_RENAME, NULL, NULL, NULL) == FALSE) {
8236 8236                          nfs4_end_op(mi, odvp, ndvp, &recov_state, needrecov);
8237 8237                          if (!e.error)
8238 8238                                  (void) xdr_free(xdr_COMPOUND4res_clnt,
8239 8239                                      (caddr_t)&res);
8240 8240                          goto recov_retry;
8241 8241                  }
8242 8242          }
8243 8243  
8244 8244          if (!e.error) {
8245 8245                  resp = &res;
8246 8246                  /*
8247 8247                   * as long as OP_RENAME
8248 8248                   */
8249 8249                  if (res.status != NFS4_OK && res.array_len <= 4) {
8250 8250                          e.error = geterrno4(res.status);
8251 8251                          PURGE_ATTRCACHE4(odvp);
8252 8252                          PURGE_ATTRCACHE4(ndvp);
8253 8253                          /*
8254 8254                           * System V defines rename to return EEXIST, not
8255 8255                           * ENOTEMPTY if the target directory is not empty.
8256 8256                           * Over the wire, the error is NFSERR_ENOTEMPTY
8257 8257                           * which geterrno4 maps to ENOTEMPTY.
8258 8258                           */
8259 8259                          if (e.error == ENOTEMPTY)
8260 8260                                  e.error = EEXIST;
8261 8261                  } else {
8262 8262  
8263 8263                          resop = &res.array[3];  /* rename res */
8264 8264                          rn_res = &resop->nfs_resop4_u.oprename;
8265 8265  
8266 8266                          if (res.status == NFS4_OK) {
8267 8267                                  /*
8268 8268                                   * Update target attribute, readdir and dnlc
8269 8269                                   * caches.
8270 8270                                   */
8271 8271                                  dinfo.di_garp =
8272 8272                                      &res.array[4].nfs_resop4_u.opgetattr.ga_res;
8273 8273                                  dinfo.di_cred = cr;
8274 8274                                  dinfop = &dinfo;
8275 8275                          } else
8276 8276                                  dinfop = NULL;
8277 8277  
8278 8278                          nfs4_update_dircaches(&rn_res->target_cinfo,
8279 8279                              ndvp, NULL, NULL, dinfop);
8280 8280  
8281 8281                          /*
8282 8282                           * Update source attribute, readdir and dnlc caches
8283 8283                           *
8284 8284                           */
8285 8285                          if (ndvp != odvp) {
8286 8286                                  update_parentdir_sfh(renvp, ndvp);
8287 8287  
8288 8288                                  if (dinfop)
8289 8289                                          dinfo.di_garp =
8290 8290                                              &(res.array[6].nfs_resop4_u.
8291 8291                                              opgetattr.ga_res);
8292 8292  
8293 8293                                  nfs4_update_dircaches(&rn_res->source_cinfo,
8294 8294                                      odvp, NULL, NULL, dinfop);
8295 8295                          }
8296 8296  
8297 8297                          fn_move(VTOSV(renvp)->sv_name, VTOSV(ndvp)->sv_name,
8298 8298                              nnm);
8299 8299                  }
8300 8300          }
8301 8301  
8302 8302          if (resp)
8303 8303                  (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)resp);
8304 8304          nfs4_end_op(mi, odvp, ndvp, &recov_state, needrecov);
8305 8305          kmem_free(argop, argoplist_size);
8306 8306  
8307 8307          return (e.error);
8308 8308  }
8309 8309  
8310 8310  /*
8311 8311   * nfs4rename_volatile_fh does the otw part of renaming in NFS Version 4, when
8312 8312   * it is possible for the filehandle to change due to the rename.
8313 8313   *
8314 8314   * The compound req in this case includes a post-rename lookup and getattr
8315 8315   * to ensure that we have the correct fh and attributes for the object.
8316 8316   *
8317 8317   * Rename requires that the current fh be the target directory and the
8318 8318   * saved fh be the source directory. After the operation, the current fh
8319 8319   * is unchanged.
8320 8320   *
8321 8321   * We need the new filehandle (hence a LOOKUP and GETFH) so that we can
8322 8322   * update the filehandle for the renamed object.  We also get the old
8323 8323   * filehandle for historical reasons; this should be taken out sometime.
8324 8324   * This results in a rather cumbersome compound...
8325 8325   *
8326 8326   *    PUTFH(sourcdir), SAVEFH, LOOKUP(src), GETFH(old),
8327 8327   *    PUTFH(targetdir), RENAME, LOOKUP(trgt), GETFH(new), GETATTR
8328 8328   *
8329 8329   */
8330 8330  static int
8331 8331  nfs4rename_volatile_fh(vnode_t *odvp, char *onm, vnode_t *ovp,
8332 8332      vnode_t *ndvp, char *nnm, cred_t *cr, nfsstat4 *statp)
8333 8333  {
8334 8334          COMPOUND4args_clnt args;
8335 8335          COMPOUND4res_clnt res, *resp = NULL;
8336 8336          int argoplist_size;
8337 8337          nfs_argop4 *argop;
8338 8338          nfs_resop4 *resop;
8339 8339          int doqueue;
8340 8340          mntinfo4_t *mi;
8341 8341          rnode4_t *odrp = VTOR4(odvp);   /* old directory */
8342 8342          rnode4_t *ndrp = VTOR4(ndvp);   /* new directory */
8343 8343          rnode4_t *orp = VTOR4(ovp);     /* object being renamed */
8344 8344          RENAME4res *rn_res;
8345 8345          GETFH4res *ngf_res;
8346 8346          bool_t needrecov;
8347 8347          nfs4_recov_state_t recov_state;
8348 8348          hrtime_t t;
8349 8349          nfs4_error_t e = { 0, NFS4_OK, RPC_SUCCESS };
8350 8350          dirattr_info_t dinfo, *dinfop = &dinfo;
8351 8351  
8352 8352          ASSERT(nfs_zone() == VTOMI4(odvp)->mi_zone);
8353 8353  
8354 8354          recov_state.rs_flags = 0;
8355 8355          recov_state.rs_num_retry_despite_err = 0;
8356 8356  
8357 8357  recov_retry:
8358 8358          *statp = NFS4_OK;
8359 8359  
8360 8360          /*
8361 8361           * There is a window between the RPC and updating the path and
8362 8362           * filehandle stored in the rnode.  Lock out the FHEXPIRED recovery
8363 8363           * code, so that it doesn't try to use the old path during that
8364 8364           * window.
8365 8365           */
8366 8366          mutex_enter(&orp->r_statelock);
8367 8367          while (orp->r_flags & R4RECEXPFH) {
8368 8368                  klwp_t *lwp = ttolwp(curthread);
8369 8369  
8370 8370                  if (lwp != NULL)
8371 8371                          lwp->lwp_nostop++;
8372 8372                  if (cv_wait_sig(&orp->r_cv, &orp->r_statelock) == 0) {
8373 8373                          mutex_exit(&orp->r_statelock);
8374 8374                          if (lwp != NULL)
8375 8375                                  lwp->lwp_nostop--;
8376 8376                          return (EINTR);
8377 8377                  }
8378 8378                  if (lwp != NULL)
8379 8379                          lwp->lwp_nostop--;
8380 8380          }
8381 8381          orp->r_flags |= R4RECEXPFH;
8382 8382          mutex_exit(&orp->r_statelock);
8383 8383  
8384 8384          mi = VTOMI4(odvp);
8385 8385  
8386 8386          args.ctag = TAG_RENAME_VFH;
8387 8387          args.array_len = (odvp == ndvp) ? 10 : 12;
8388 8388          argoplist_size  = args.array_len * sizeof (nfs_argop4);
8389 8389          argop = kmem_alloc(argoplist_size, KM_SLEEP);
8390 8390  
8391 8391          /*
8392 8392           * Rename ops:
8393 8393           *    PUTFH(sourcdir), SAVEFH, LOOKUP(src), GETFH(old),
8394 8394           *    PUTFH(targetdir), RENAME, GETATTR(targetdir)
8395 8395           *    LOOKUP(trgt), GETFH(new), GETATTR,
8396 8396           *
8397 8397           *    if (odvp != ndvp)
8398 8398           *      add putfh(sourcedir), getattr(sourcedir) }
8399 8399           */
8400 8400          args.array = argop;
8401 8401  
8402 8402          e.error = nfs4_start_fop(mi, odvp, ndvp, OH_VFH_RENAME,
8403 8403              &recov_state, NULL);
8404 8404          if (e.error) {
8405 8405                  kmem_free(argop, argoplist_size);
8406 8406                  mutex_enter(&orp->r_statelock);
8407 8407                  orp->r_flags &= ~R4RECEXPFH;
8408 8408                  cv_broadcast(&orp->r_cv);
8409 8409                  mutex_exit(&orp->r_statelock);
8410 8410                  return (e.error);
8411 8411          }
8412 8412  
8413 8413          /* 0: putfh source directory */
8414 8414          argop[0].argop = OP_CPUTFH;
8415 8415          argop[0].nfs_argop4_u.opcputfh.sfh = odrp->r_fh;
8416 8416  
8417 8417          /* 1: Save source fh to free up current for target */
8418 8418          argop[1].argop = OP_SAVEFH;
8419 8419  
8420 8420          /* 2: Lookup pre-rename fh of renamed object */
8421 8421          argop[2].argop = OP_CLOOKUP;
8422 8422          argop[2].nfs_argop4_u.opclookup.cname = onm;
8423 8423  
8424 8424          /* 3: getfh fh of renamed object (before rename) */
8425 8425          argop[3].argop = OP_GETFH;
8426 8426  
8427 8427          /* 4: putfh targetdir */
8428 8428          argop[4].argop = OP_CPUTFH;
8429 8429          argop[4].nfs_argop4_u.opcputfh.sfh = ndrp->r_fh;
8430 8430  
8431 8431          /* 5: current_fh is targetdir, saved_fh is sourcedir */
8432 8432          argop[5].argop = OP_CRENAME;
8433 8433          argop[5].nfs_argop4_u.opcrename.coldname = onm;
8434 8434          argop[5].nfs_argop4_u.opcrename.cnewname = nnm;
8435 8435  
8436 8436          /* 6: getattr of target dir (post op attrs) */
8437 8437          argop[6].argop = OP_GETATTR;
8438 8438          argop[6].nfs_argop4_u.opgetattr.attr_request = NFS4_VATTR_MASK;
8439 8439          argop[6].nfs_argop4_u.opgetattr.mi = mi;
8440 8440  
8441 8441          /* 7: Lookup post-rename fh of renamed object */
8442 8442          argop[7].argop = OP_CLOOKUP;
8443 8443          argop[7].nfs_argop4_u.opclookup.cname = nnm;
8444 8444  
8445 8445          /* 8: getfh fh of renamed object (after rename) */
8446 8446          argop[8].argop = OP_GETFH;
8447 8447  
8448 8448          /* 9: getattr of renamed object */
8449 8449          argop[9].argop = OP_GETATTR;
8450 8450          argop[9].nfs_argop4_u.opgetattr.attr_request = NFS4_VATTR_MASK;
8451 8451          argop[9].nfs_argop4_u.opgetattr.mi = mi;
8452 8452  
8453 8453          /*
8454 8454           * If source/target dirs are different, then get new post-op
8455 8455           * attrs for source dir also.
8456 8456           */
8457 8457          if (ndvp != odvp) {
8458 8458                  /* 10: putfh (sourcedir) */
8459 8459                  argop[10].argop = OP_CPUTFH;
8460 8460                  argop[10].nfs_argop4_u.opcputfh.sfh = ndrp->r_fh;
8461 8461  
8462 8462                  /* 11: getattr (sourcedir) */
8463 8463                  argop[11].argop = OP_GETATTR;
8464 8464                  argop[11].nfs_argop4_u.opgetattr.attr_request = NFS4_VATTR_MASK;
8465 8465                  argop[11].nfs_argop4_u.opgetattr.mi = mi;
8466 8466          }
8467 8467  
8468 8468          dnlc_remove(odvp, onm);
8469 8469          dnlc_remove(ndvp, nnm);
8470 8470  
8471 8471          doqueue = 1;
8472 8472          t = gethrtime();
8473 8473          rfs4call(mi, &args, &res, cr, &doqueue, 0, &e);
8474 8474  
8475 8475          needrecov = nfs4_needs_recovery(&e, FALSE, mi->mi_vfsp);
8476 8476          if (e.error) {
8477 8477                  PURGE_ATTRCACHE4(odvp);
8478 8478                  PURGE_ATTRCACHE4(ndvp);
8479 8479                  if (!needrecov) {
8480 8480                          nfs4_end_fop(mi, odvp, ndvp, OH_VFH_RENAME,
8481 8481                              &recov_state, needrecov);
8482 8482                          goto out;
8483 8483                  }
8484 8484          } else {
8485 8485                  *statp = res.status;
8486 8486          }
8487 8487  
8488 8488          if (needrecov) {
8489 8489                  bool_t abort;
8490 8490  
8491 8491                  abort = nfs4_start_recovery(&e, mi, odvp, ndvp, NULL, NULL,
8492 8492                      OP_RENAME, NULL, NULL, NULL);
8493 8493                  if (abort == FALSE) {
8494 8494                          nfs4_end_fop(mi, odvp, ndvp, OH_VFH_RENAME,
8495 8495                              &recov_state, needrecov);
8496 8496                          kmem_free(argop, argoplist_size);
8497 8497                          if (!e.error)
8498 8498                                  (void) xdr_free(xdr_COMPOUND4res_clnt,
8499 8499                                      (caddr_t)&res);
8500 8500                          mutex_enter(&orp->r_statelock);
8501 8501                          orp->r_flags &= ~R4RECEXPFH;
8502 8502                          cv_broadcast(&orp->r_cv);
8503 8503                          mutex_exit(&orp->r_statelock);
8504 8504                          goto recov_retry;
8505 8505                  } else {
8506 8506                          if (e.error != 0) {
8507 8507                                  nfs4_end_fop(mi, odvp, ndvp, OH_VFH_RENAME,
8508 8508                                      &recov_state, needrecov);
8509 8509                                  goto out;
8510 8510                          }
8511 8511                          /* fall through for res.status case */
8512 8512                  }
8513 8513          }
8514 8514  
8515 8515          resp = &res;
8516 8516          /*
8517 8517           * If OP_RENAME (or any prev op) failed, then return an error.
8518 8518           * OP_RENAME is index 5, so if array len <= 6 we return an error.
8519 8519           */
8520 8520          if ((res.status != NFS4_OK) && (res.array_len <= 6)) {
8521 8521                  /*
8522 8522                   * Error in an op other than last Getattr
8523 8523                   */
8524 8524                  e.error = geterrno4(res.status);
8525 8525                  PURGE_ATTRCACHE4(odvp);
8526 8526                  PURGE_ATTRCACHE4(ndvp);
8527 8527                  /*
8528 8528                   * System V defines rename to return EEXIST, not
8529 8529                   * ENOTEMPTY if the target directory is not empty.
8530 8530                   * Over the wire, the error is NFSERR_ENOTEMPTY
8531 8531                   * which geterrno4 maps to ENOTEMPTY.
8532 8532                   */
8533 8533                  if (e.error == ENOTEMPTY)
8534 8534                          e.error = EEXIST;
8535 8535                  nfs4_end_fop(mi, odvp, ndvp, OH_VFH_RENAME, &recov_state,
8536 8536                      needrecov);
8537 8537                  goto out;
8538 8538          }
8539 8539  
8540 8540          /* rename results */
8541 8541          rn_res = &res.array[5].nfs_resop4_u.oprename;
8542 8542  
8543 8543          if (res.status == NFS4_OK) {
8544 8544                  /* Update target attribute, readdir and dnlc caches */
8545 8545                  dinfo.di_garp =
8546 8546                      &res.array[6].nfs_resop4_u.opgetattr.ga_res;
8547 8547                  dinfo.di_cred = cr;
8548 8548                  dinfo.di_time_call = t;
8549 8549          } else
8550 8550                  dinfop = NULL;
8551 8551  
8552 8552          /* Update source cache attribute, readdir and dnlc caches */
8553 8553          nfs4_update_dircaches(&rn_res->target_cinfo, ndvp, NULL, NULL, dinfop);
8554 8554  
8555 8555          /* Update source cache attribute, readdir and dnlc caches */
8556 8556          if (ndvp != odvp) {
8557 8557                  update_parentdir_sfh(ovp, ndvp);
8558 8558  
8559 8559                  /*
8560 8560                   * If dinfop is non-NULL, then compound succeded, so
8561 8561                   * set di_garp to attrs for source dir.  dinfop is only
8562 8562                   * set to NULL when compound fails.
8563 8563                   */
8564 8564                  if (dinfop)
8565 8565                          dinfo.di_garp =
8566 8566                              &res.array[11].nfs_resop4_u.opgetattr.ga_res;
8567 8567                  nfs4_update_dircaches(&rn_res->source_cinfo, odvp, NULL, NULL,
8568 8568                      dinfop);
8569 8569          }
8570 8570  
8571 8571          /*
8572 8572           * Update the rnode with the new component name and args,
8573 8573           * and if the file handle changed, also update it with the new fh.
8574 8574           * This is only necessary if the target object has an rnode
8575 8575           * entry and there is no need to create one for it.
8576 8576           */
8577 8577          resop = &res.array[8];  /* getfh new res */
8578 8578          ngf_res = &resop->nfs_resop4_u.opgetfh;
8579 8579  
8580 8580          /*
8581 8581           * Update the path and filehandle for the renamed object.
8582 8582           */
8583 8583          nfs4rename_update(ovp, ndvp, &ngf_res->object, nnm);
8584 8584  
8585 8585          nfs4_end_fop(mi, odvp, ndvp, OH_VFH_RENAME, &recov_state, needrecov);
8586 8586  
8587 8587          if (res.status == NFS4_OK) {
8588 8588                  resop++;        /* getattr res */
8589 8589                  e.error = nfs4_update_attrcache(res.status,
8590 8590                      &resop->nfs_resop4_u.opgetattr.ga_res,
8591 8591                      t, ovp, cr);
8592 8592          }
8593 8593  
8594 8594  out:
8595 8595          kmem_free(argop, argoplist_size);
8596 8596          if (resp)
8597 8597                  (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)resp);
8598 8598          mutex_enter(&orp->r_statelock);
8599 8599          orp->r_flags &= ~R4RECEXPFH;
8600 8600          cv_broadcast(&orp->r_cv);
8601 8601          mutex_exit(&orp->r_statelock);
8602 8602  
8603 8603          return (e.error);
8604 8604  }
8605 8605  
8606 8606  /* ARGSUSED */
8607 8607  static int
8608 8608  nfs4_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp, cred_t *cr,
8609 8609      caller_context_t *ct, int flags, vsecattr_t *vsecp)
8610 8610  {
8611 8611          int error;
8612 8612          vnode_t *vp;
8613 8613  
8614 8614          if (nfs_zone() != VTOMI4(dvp)->mi_zone)
8615 8615                  return (EPERM);
8616 8616          /*
8617 8617           * As ".." has special meaning and rather than send a mkdir
8618 8618           * over the wire to just let the server freak out, we just
8619 8619           * short circuit it here and return EEXIST
8620 8620           */
8621 8621          if (nm[0] == '.' && nm[1] == '.' && nm[2] == '\0')
8622 8622                  return (EEXIST);
8623 8623  
8624 8624          /*
8625 8625           * Decision to get the right gid and setgid bit of the
8626 8626           * new directory is now made in call_nfs4_create_req.
8627 8627           */
8628 8628          va->va_mask |= AT_MODE;
8629 8629          error = call_nfs4_create_req(dvp, nm, NULL, va, &vp, cr, NF4DIR);
8630 8630          if (error)
8631 8631                  return (error);
8632 8632  
8633 8633          *vpp = vp;
8634 8634          return (0);
8635 8635  }
8636 8636  
8637 8637  
8638 8638  /*
8639 8639   * rmdir is using the same remove v4 op as does remove.
8640 8640   * Remove requires that the current fh be the target directory.
8641 8641   * After the operation, the current fh is unchanged.
8642 8642   * The compound op structure is:
8643 8643   *      PUTFH(targetdir), REMOVE
8644 8644   */
8645 8645  /*ARGSUSED4*/
8646 8646  static int
8647 8647  nfs4_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr,
8648 8648      caller_context_t *ct, int flags)
8649 8649  {
8650 8650          int need_end_op = FALSE;
8651 8651          COMPOUND4args_clnt args;
8652 8652          COMPOUND4res_clnt res, *resp = NULL;
8653 8653          REMOVE4res *rm_res;
8654 8654          nfs_argop4 argop[3];
8655 8655          nfs_resop4 *resop;
8656 8656          vnode_t *vp;
8657 8657          int doqueue;
8658 8658          mntinfo4_t *mi;
8659 8659          rnode4_t *drp;
8660 8660          bool_t needrecov = FALSE;
8661 8661          nfs4_recov_state_t recov_state;
8662 8662          nfs4_error_t e = { 0, NFS4_OK, RPC_SUCCESS };
8663 8663          dirattr_info_t dinfo, *dinfop;
8664 8664  
8665 8665          if (nfs_zone() != VTOMI4(dvp)->mi_zone)
8666 8666                  return (EPERM);
8667 8667          /*
8668 8668           * As ".." has special meaning and rather than send a rmdir
8669 8669           * over the wire to just let the server freak out, we just
8670 8670           * short circuit it here and return EEXIST
8671 8671           */
8672 8672          if (nm[0] == '.' && nm[1] == '.' && nm[2] == '\0')
8673 8673                  return (EEXIST);
8674 8674  
8675 8675          drp = VTOR4(dvp);
8676 8676          if (nfs_rw_enter_sig(&drp->r_rwlock, RW_WRITER, INTR4(dvp)))
8677 8677                  return (EINTR);
8678 8678  
8679 8679          /*
8680 8680           * Attempt to prevent a rmdir(".") from succeeding.
8681 8681           */
8682 8682          e.error = nfs4lookup(dvp, nm, &vp, cr, 0);
8683 8683          if (e.error) {
8684 8684                  nfs_rw_exit(&drp->r_rwlock);
8685 8685                  return (e.error);
8686 8686          }
8687 8687          if (vp == cdir) {
8688 8688                  VN_RELE(vp);
8689 8689                  nfs_rw_exit(&drp->r_rwlock);
8690 8690                  return (EINVAL);
8691 8691          }
8692 8692  
8693 8693          /*
8694 8694           * Since nfsv4 remove op works on both files and directories,
8695 8695           * check that the removed object is indeed a directory.
8696 8696           */
8697 8697          if (vp->v_type != VDIR) {
8698 8698                  VN_RELE(vp);
8699 8699                  nfs_rw_exit(&drp->r_rwlock);
8700 8700                  return (ENOTDIR);
8701 8701          }
8702 8702  
8703 8703          /*
8704 8704           * First just remove the entry from the name cache, as it
8705 8705           * is most likely an entry for this vp.
8706 8706           */
8707 8707          dnlc_remove(dvp, nm);
8708 8708  
8709 8709          /*
8710 8710           * If there vnode reference count is greater than one, then
8711 8711           * there may be additional references in the DNLC which will
8712 8712           * need to be purged.  First, trying removing the entry for
8713 8713           * the parent directory and see if that removes the additional
8714 8714           * reference(s).  If that doesn't do it, then use dnlc_purge_vp
8715 8715           * to completely remove any references to the directory which
8716 8716           * might still exist in the DNLC.
8717 8717           */
8718 8718          if (vp->v_count > 1) {
8719 8719                  dnlc_remove(vp, "..");
8720 8720                  if (vp->v_count > 1)
8721 8721                          dnlc_purge_vp(vp);
8722 8722          }
8723 8723  
8724 8724          mi = VTOMI4(dvp);
8725 8725          recov_state.rs_flags = 0;
8726 8726          recov_state.rs_num_retry_despite_err = 0;
8727 8727  
8728 8728  recov_retry:
8729 8729          args.ctag = TAG_RMDIR;
8730 8730  
8731 8731          /*
8732 8732           * Rmdir ops: putfh dir; remove
8733 8733           */
8734 8734          args.array_len = 3;
8735 8735          args.array = argop;
8736 8736  
8737 8737          e.error = nfs4_start_op(VTOMI4(dvp), dvp, NULL, &recov_state);
8738 8738          if (e.error) {
8739 8739                  nfs_rw_exit(&drp->r_rwlock);
8740 8740                  return (e.error);
8741 8741          }
8742 8742          need_end_op = TRUE;
8743 8743  
8744 8744          /* putfh directory */
8745 8745          argop[0].argop = OP_CPUTFH;
8746 8746          argop[0].nfs_argop4_u.opcputfh.sfh = drp->r_fh;
8747 8747  
8748 8748          /* remove */
8749 8749          argop[1].argop = OP_CREMOVE;
8750 8750          argop[1].nfs_argop4_u.opcremove.ctarget = nm;
8751 8751  
8752 8752          /* getattr (postop attrs for dir that contained removed dir) */
8753 8753          argop[2].argop = OP_GETATTR;
8754 8754          argop[2].nfs_argop4_u.opgetattr.attr_request = NFS4_VATTR_MASK;
8755 8755          argop[2].nfs_argop4_u.opgetattr.mi = mi;
8756 8756  
8757 8757          dinfo.di_time_call = gethrtime();
8758 8758          doqueue = 1;
8759 8759          rfs4call(mi, &args, &res, cr, &doqueue, 0, &e);
8760 8760  
8761 8761          PURGE_ATTRCACHE4(vp);
8762 8762  
8763 8763          needrecov = nfs4_needs_recovery(&e, FALSE, mi->mi_vfsp);
8764 8764          if (e.error) {
8765 8765                  PURGE_ATTRCACHE4(dvp);
8766 8766          }
8767 8767  
8768 8768          if (needrecov) {
8769 8769                  if (nfs4_start_recovery(&e, VTOMI4(dvp), dvp, NULL, NULL,
8770 8770                      NULL, OP_REMOVE, NULL, NULL, NULL) == FALSE) {
8771 8771                          if (!e.error)
8772 8772                                  (void) xdr_free(xdr_COMPOUND4res_clnt,
8773 8773                                      (caddr_t)&res);
8774 8774  
8775 8775                          nfs4_end_op(VTOMI4(dvp), dvp, NULL, &recov_state,
8776 8776                              needrecov);
8777 8777                          need_end_op = FALSE;
8778 8778                          goto recov_retry;
8779 8779                  }
8780 8780          }
8781 8781  
8782 8782          if (!e.error) {
8783 8783                  resp = &res;
8784 8784  
8785 8785                  /*
8786 8786                   * Only return error if first 2 ops (OP_REMOVE or earlier)
8787 8787                   * failed.
8788 8788                   */
8789 8789                  if (res.status != NFS4_OK && res.array_len <= 2) {
8790 8790                          e.error = geterrno4(res.status);
8791 8791                          PURGE_ATTRCACHE4(dvp);
8792 8792                          nfs4_end_op(VTOMI4(dvp), dvp, NULL,
8793 8793                              &recov_state, needrecov);
8794 8794                          need_end_op = FALSE;
8795 8795                          nfs4_purge_stale_fh(e.error, dvp, cr);
8796 8796                          /*
8797 8797                           * System V defines rmdir to return EEXIST, not
8798 8798                           * ENOTEMPTY if the directory is not empty.  Over
8799 8799                           * the wire, the error is NFSERR_ENOTEMPTY which
8800 8800                           * geterrno4 maps to ENOTEMPTY.
8801 8801                           */
8802 8802                          if (e.error == ENOTEMPTY)
8803 8803                                  e.error = EEXIST;
8804 8804                  } else {
8805 8805                          resop = &res.array[1];  /* remove res */
8806 8806                          rm_res = &resop->nfs_resop4_u.opremove;
8807 8807  
8808 8808                          if (res.status == NFS4_OK) {
8809 8809                                  resop = &res.array[2];  /* dir attrs */
8810 8810                                  dinfo.di_garp =
8811 8811                                      &resop->nfs_resop4_u.opgetattr.ga_res;
8812 8812                                  dinfo.di_cred = cr;
8813 8813                                  dinfop = &dinfo;
8814 8814                          } else
8815 8815                                  dinfop = NULL;
8816 8816  
8817 8817                          /* Update dir attribute, readdir and dnlc caches */
8818 8818                          nfs4_update_dircaches(&rm_res->cinfo, dvp, NULL, NULL,
8819 8819                              dinfop);
8820 8820  
8821 8821                          /* destroy rddir cache for dir that was removed */
8822 8822                          if (VTOR4(vp)->r_dir != NULL)
8823 8823                                  nfs4_purge_rddir_cache(vp);
8824 8824                  }
8825 8825          }
8826 8826  
8827 8827          if (need_end_op)
8828 8828                  nfs4_end_op(VTOMI4(dvp), dvp, NULL, &recov_state, needrecov);
8829 8829  
8830 8830          nfs_rw_exit(&drp->r_rwlock);
8831 8831  
8832 8832          if (resp)
8833 8833                  (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)resp);
8834 8834  
8835 8835          if (e.error == 0) {
8836 8836                  vnode_t *tvp;
8837 8837                  rnode4_t *trp;
8838 8838                  trp = VTOR4(vp);
8839 8839                  tvp = vp;
8840 8840                  if (IS_SHADOW(vp, trp))
8841 8841                          tvp = RTOV4(trp);
8842 8842                  vnevent_rmdir(tvp, dvp, nm, ct);
8843 8843          }
8844 8844  
8845 8845          VN_RELE(vp);
8846 8846  
8847 8847          return (e.error);
8848 8848  }
8849 8849  
8850 8850  /* ARGSUSED */
8851 8851  static int
8852 8852  nfs4_symlink(vnode_t *dvp, char *lnm, struct vattr *tva, char *tnm, cred_t *cr,
8853 8853      caller_context_t *ct, int flags)
8854 8854  {
8855 8855          int error;
8856 8856          vnode_t *vp;
8857 8857          rnode4_t *rp;
8858 8858          char *contents;
8859 8859          mntinfo4_t *mi = VTOMI4(dvp);
8860 8860  
8861 8861          if (nfs_zone() != mi->mi_zone)
8862 8862                  return (EPERM);
8863 8863          if (!(mi->mi_flags & MI4_SYMLINK))
8864 8864                  return (EOPNOTSUPP);
8865 8865  
8866 8866          error = call_nfs4_create_req(dvp, lnm, tnm, tva, &vp, cr, NF4LNK);
8867 8867          if (error)
8868 8868                  return (error);
8869 8869  
8870 8870          ASSERT(nfs4_consistent_type(vp));
8871 8871          rp = VTOR4(vp);
8872 8872          if (nfs4_do_symlink_cache && rp->r_symlink.contents == NULL) {
8873 8873  
8874 8874                  contents = kmem_alloc(MAXPATHLEN, KM_SLEEP);
8875 8875  
8876 8876                  if (contents != NULL) {
8877 8877                          mutex_enter(&rp->r_statelock);
8878 8878                          if (rp->r_symlink.contents == NULL) {
8879 8879                                  rp->r_symlink.len = strlen(tnm);
8880 8880                                  bcopy(tnm, contents, rp->r_symlink.len);
8881 8881                                  rp->r_symlink.contents = contents;
8882 8882                                  rp->r_symlink.size = MAXPATHLEN;
8883 8883                                  mutex_exit(&rp->r_statelock);
8884 8884                          } else {
8885 8885                                  mutex_exit(&rp->r_statelock);
8886 8886                                  kmem_free((void *)contents, MAXPATHLEN);
8887 8887                          }
8888 8888                  }
8889 8889          }
8890 8890          VN_RELE(vp);
8891 8891  
8892 8892          return (error);
8893 8893  }
8894 8894  
8895 8895  
8896 8896  /*
8897 8897   * Read directory entries.
8898 8898   * There are some weird things to look out for here.  The uio_loffset
8899 8899   * field is either 0 or it is the offset returned from a previous
8900 8900   * readdir.  It is an opaque value used by the server to find the
8901 8901   * correct directory block to read. The count field is the number
8902 8902   * of blocks to read on the server.  This is advisory only, the server
8903 8903   * may return only one block's worth of entries.  Entries may be compressed
8904 8904   * on the server.
8905 8905   */
8906 8906  /* ARGSUSED */
8907 8907  static int
8908 8908  nfs4_readdir(vnode_t *vp, struct uio *uiop, cred_t *cr, int *eofp,
8909 8909      caller_context_t *ct, int flags)
8910 8910  {
8911 8911          int error;
8912 8912          uint_t count;
8913 8913          rnode4_t *rp;
8914 8914          rddir4_cache *rdc;
8915 8915          rddir4_cache *rrdc;
8916 8916  
8917 8917          if (nfs_zone() != VTOMI4(vp)->mi_zone)
8918 8918                  return (EIO);
8919 8919          rp = VTOR4(vp);
8920 8920  
8921 8921          ASSERT(nfs_rw_lock_held(&rp->r_rwlock, RW_READER));
8922 8922  
8923 8923          /*
8924 8924           * Make sure that the directory cache is valid.
8925 8925           */
8926 8926          if (rp->r_dir != NULL) {
8927 8927                  if (nfs_disable_rddir_cache != 0) {
8928 8928                          /*
8929 8929                           * Setting nfs_disable_rddir_cache in /etc/system
8930 8930                           * allows interoperability with servers that do not
8931 8931                           * properly update the attributes of directories.
8932 8932                           * Any cached information gets purged before an
8933 8933                           * access is made to it.
8934 8934                           */
8935 8935                          nfs4_purge_rddir_cache(vp);
8936 8936                  }
8937 8937  
8938 8938                  error = nfs4_validate_caches(vp, cr);
8939 8939                  if (error)
8940 8940                          return (error);
8941 8941          }
8942 8942  
8943 8943          count = MIN(uiop->uio_iov->iov_len, MAXBSIZE);
8944 8944  
8945 8945          /*
8946 8946           * Short circuit last readdir which always returns 0 bytes.
8947 8947           * This can be done after the directory has been read through
8948 8948           * completely at least once.  This will set r_direof which
8949 8949           * can be used to find the value of the last cookie.
8950 8950           */
8951 8951          mutex_enter(&rp->r_statelock);
8952 8952          if (rp->r_direof != NULL &&
8953 8953              uiop->uio_loffset == rp->r_direof->nfs4_ncookie) {
8954 8954                  mutex_exit(&rp->r_statelock);
8955 8955  #ifdef DEBUG
8956 8956                  nfs4_readdir_cache_shorts++;
8957 8957  #endif
8958 8958                  if (eofp)
8959 8959                          *eofp = 1;
8960 8960                  return (0);
8961 8961          }
8962 8962  
8963 8963          /*
8964 8964           * Look for a cache entry.  Cache entries are identified
8965 8965           * by the NFS cookie value and the byte count requested.
8966 8966           */
8967 8967          rdc = rddir4_cache_lookup(rp, uiop->uio_loffset, count);
8968 8968  
8969 8969          /*
8970 8970           * If rdc is NULL then the lookup resulted in an unrecoverable error.
8971 8971           */
8972 8972          if (rdc == NULL) {
8973 8973                  mutex_exit(&rp->r_statelock);
8974 8974                  return (EINTR);
8975 8975          }
8976 8976  
8977 8977          /*
8978 8978           * Check to see if we need to fill this entry in.
8979 8979           */
8980 8980          if (rdc->flags & RDDIRREQ) {
8981 8981                  rdc->flags &= ~RDDIRREQ;
8982 8982                  rdc->flags |= RDDIR;
8983 8983                  mutex_exit(&rp->r_statelock);
8984 8984  
8985 8985                  /*
8986 8986                   * Do the readdir.
8987 8987                   */
8988 8988                  nfs4readdir(vp, rdc, cr);
8989 8989  
8990 8990                  /*
8991 8991                   * Reacquire the lock, so that we can continue
8992 8992                   */
8993 8993                  mutex_enter(&rp->r_statelock);
8994 8994                  /*
8995 8995                   * The entry is now complete
8996 8996                   */
8997 8997                  rdc->flags &= ~RDDIR;
8998 8998          }
8999 8999  
9000 9000          ASSERT(!(rdc->flags & RDDIR));
9001 9001  
9002 9002          /*
9003 9003           * If an error occurred while attempting
9004 9004           * to fill the cache entry, mark the entry invalid and
9005 9005           * just return the error.
9006 9006           */
9007 9007          if (rdc->error) {
9008 9008                  error = rdc->error;
9009 9009                  rdc->flags |= RDDIRREQ;
9010 9010                  rddir4_cache_rele(rp, rdc);
9011 9011                  mutex_exit(&rp->r_statelock);
9012 9012                  return (error);
9013 9013          }
9014 9014  
9015 9015          /*
9016 9016           * The cache entry is complete and good,
9017 9017           * copyout the dirent structs to the calling
9018 9018           * thread.
9019 9019           */
9020 9020          error = uiomove(rdc->entries, rdc->actlen, UIO_READ, uiop);
9021 9021  
9022 9022          /*
9023 9023           * If no error occurred during the copyout,
9024 9024           * update the offset in the uio struct to
9025 9025           * contain the value of the next NFS 4 cookie
9026 9026           * and set the eof value appropriately.
9027 9027           */
9028 9028          if (!error) {
9029 9029                  uiop->uio_loffset = rdc->nfs4_ncookie;
9030 9030                  if (eofp)
9031 9031                          *eofp = rdc->eof;
9032 9032          }
9033 9033  
9034 9034          /*
9035 9035           * Decide whether to do readahead.  Don't if we
9036 9036           * have already read to the end of directory.
9037 9037           */
9038 9038          if (rdc->eof) {
9039 9039                  /*
9040 9040                   * Make the entry the direof only if it is cached
9041 9041                   */
9042 9042                  if (rdc->flags & RDDIRCACHED)
9043 9043                          rp->r_direof = rdc;
9044 9044                  rddir4_cache_rele(rp, rdc);
9045 9045                  mutex_exit(&rp->r_statelock);
9046 9046                  return (error);
9047 9047          }
9048 9048  
9049 9049          /* Determine if a readdir readahead should be done */
9050 9050          if (!(rp->r_flags & R4LOOKUP)) {
9051 9051                  rddir4_cache_rele(rp, rdc);
9052 9052                  mutex_exit(&rp->r_statelock);
9053 9053                  return (error);
9054 9054          }
9055 9055  
9056 9056          /*
9057 9057           * Now look for a readahead entry.
9058 9058           *
9059 9059           * Check to see whether we found an entry for the readahead.
9060 9060           * If so, we don't need to do anything further, so free the new
9061 9061           * entry if one was allocated.  Otherwise, allocate a new entry, add
9062 9062           * it to the cache, and then initiate an asynchronous readdir
9063 9063           * operation to fill it.
9064 9064           */
9065 9065          rrdc = rddir4_cache_lookup(rp, rdc->nfs4_ncookie, count);
9066 9066  
9067 9067          /*
9068 9068           * A readdir cache entry could not be obtained for the readahead.  In
9069 9069           * this case we skip the readahead and return.
9070 9070           */
9071 9071          if (rrdc == NULL) {
9072 9072                  rddir4_cache_rele(rp, rdc);
9073 9073                  mutex_exit(&rp->r_statelock);
9074 9074                  return (error);
9075 9075          }
9076 9076  
9077 9077          /*
9078 9078           * Check to see if we need to fill this entry in.
9079 9079           */
9080 9080          if (rrdc->flags & RDDIRREQ) {
9081 9081                  rrdc->flags &= ~RDDIRREQ;
9082 9082                  rrdc->flags |= RDDIR;
9083 9083                  rddir4_cache_rele(rp, rdc);
9084 9084                  mutex_exit(&rp->r_statelock);
9085 9085  #ifdef DEBUG
9086 9086                  nfs4_readdir_readahead++;
9087 9087  #endif
9088 9088                  /*
9089 9089                   * Do the readdir.
9090 9090                   */
9091 9091                  nfs4_async_readdir(vp, rrdc, cr, do_nfs4readdir);
9092 9092                  return (error);
9093 9093          }
9094 9094  
9095 9095          rddir4_cache_rele(rp, rrdc);
9096 9096          rddir4_cache_rele(rp, rdc);
9097 9097          mutex_exit(&rp->r_statelock);
9098 9098          return (error);
9099 9099  }
9100 9100  
9101 9101  static int
9102 9102  do_nfs4readdir(vnode_t *vp, rddir4_cache *rdc, cred_t *cr)
9103 9103  {
9104 9104          int error;
9105 9105          rnode4_t *rp;
9106 9106  
9107 9107          ASSERT(nfs_zone() == VTOMI4(vp)->mi_zone);
9108 9108  
9109 9109          rp = VTOR4(vp);
9110 9110  
9111 9111          /*
9112 9112           * Obtain the readdir results for the caller.
9113 9113           */
9114 9114          nfs4readdir(vp, rdc, cr);
9115 9115  
9116 9116          mutex_enter(&rp->r_statelock);
9117 9117          /*
9118 9118           * The entry is now complete
9119 9119           */
9120 9120          rdc->flags &= ~RDDIR;
9121 9121  
9122 9122          error = rdc->error;
9123 9123          if (error)
9124 9124                  rdc->flags |= RDDIRREQ;
9125 9125          rddir4_cache_rele(rp, rdc);
9126 9126          mutex_exit(&rp->r_statelock);
9127 9127  
9128 9128          return (error);
9129 9129  }
9130 9130  
9131 9131  /*
9132 9132   * Read directory entries.
9133 9133   * There are some weird things to look out for here.  The uio_loffset
9134 9134   * field is either 0 or it is the offset returned from a previous
9135 9135   * readdir.  It is an opaque value used by the server to find the
9136 9136   * correct directory block to read. The count field is the number
9137 9137   * of blocks to read on the server.  This is advisory only, the server
9138 9138   * may return only one block's worth of entries.  Entries may be compressed
9139 9139   * on the server.
9140 9140   *
9141 9141   * Generates the following compound request:
9142 9142   * 1. If readdir offset is zero and no dnlc entry for parent exists,
9143 9143   *    must include a Lookupp as well. In this case, send:
9144 9144   *    { Putfh <fh>; Readdir; Lookupp; Getfh; Getattr }
9145 9145   * 2. Otherwise just do: { Putfh <fh>; Readdir }
9146 9146   *
9147 9147   * Get complete attributes and filehandles for entries if this is the
9148 9148   * first read of the directory. Otherwise, just get fileid's.
9149 9149   */
9150 9150  static void
9151 9151  nfs4readdir(vnode_t *vp, rddir4_cache *rdc, cred_t *cr)
9152 9152  {
9153 9153          COMPOUND4args_clnt args;
9154 9154          COMPOUND4res_clnt res;
9155 9155          READDIR4args *rargs;
9156 9156          READDIR4res_clnt *rd_res;
9157 9157          bitmap4 rd_bitsval;
9158 9158          nfs_argop4 argop[5];
9159 9159          nfs_resop4 *resop;
9160 9160          rnode4_t *rp = VTOR4(vp);
9161 9161          mntinfo4_t *mi = VTOMI4(vp);
9162 9162          int doqueue;
9163 9163          u_longlong_t nodeid, pnodeid;   /* id's of dir and its parents */
9164 9164          vnode_t *dvp;
9165 9165          nfs_cookie4 cookie = (nfs_cookie4)rdc->nfs4_cookie;
9166 9166          int num_ops, res_opcnt;
9167 9167          bool_t needrecov = FALSE;
9168 9168          nfs4_recov_state_t recov_state;
9169 9169          hrtime_t t;
9170 9170          nfs4_error_t e = { 0, NFS4_OK, RPC_SUCCESS };
9171 9171  
9172 9172          ASSERT(nfs_zone() == mi->mi_zone);
9173 9173          ASSERT(rdc->flags & RDDIR);
9174 9174          ASSERT(rdc->entries == NULL);
9175 9175  
9176 9176          /*
9177 9177           * If rp were a stub, it should have triggered and caused
9178 9178           * a mount for us to get this far.
9179 9179           */
9180 9180          ASSERT(!RP_ISSTUB(rp));
9181 9181  
9182 9182          num_ops = 2;
9183 9183          if (cookie == (nfs_cookie4)0 || cookie == (nfs_cookie4)1) {
9184 9184                  /*
9185 9185                   * Since nfsv4 readdir may not return entries for "." and "..",
9186 9186                   * the client must recreate them:
9187 9187                   * To find the correct nodeid, do the following:
9188 9188                   * For current node, get nodeid from dnlc.
9189 9189                   * - if current node is rootvp, set pnodeid to nodeid.
9190 9190                   * - else if parent is in the dnlc, get its nodeid from there.
9191 9191                   * - else add LOOKUPP+GETATTR to compound.
9192 9192                   */
9193 9193                  nodeid = rp->r_attr.va_nodeid;
9194 9194                  if (vp->v_flag & VROOT) {
9195 9195                          pnodeid = nodeid;       /* root of mount point */
9196 9196                  } else {
9197 9197                          dvp = dnlc_lookup(vp, "..");
9198 9198                          if (dvp != NULL && dvp != DNLC_NO_VNODE) {
9199 9199                                  /* parent in dnlc cache - no need for otw */
9200 9200                                  pnodeid = VTOR4(dvp)->r_attr.va_nodeid;
9201 9201                          } else {
9202 9202                                  /*
9203 9203                                   * parent not in dnlc cache,
9204 9204                                   * do lookupp to get its id
9205 9205                                   */
9206 9206                                  num_ops = 5;
9207 9207                                  pnodeid = 0; /* set later by getattr parent */
9208 9208                          }
9209 9209                          if (dvp)
9210 9210                                  VN_RELE(dvp);
9211 9211                  }
9212 9212          }
9213 9213          recov_state.rs_flags = 0;
9214 9214          recov_state.rs_num_retry_despite_err = 0;
9215 9215  
9216 9216          /* Save the original mount point security flavor */
9217 9217          (void) save_mnt_secinfo(mi->mi_curr_serv);
9218 9218  
9219 9219  recov_retry:
9220 9220          args.ctag = TAG_READDIR;
9221 9221  
9222 9222          args.array = argop;
9223 9223          args.array_len = num_ops;
9224 9224  
9225 9225          if (e.error = nfs4_start_fop(VTOMI4(vp), vp, NULL, OH_READDIR,
9226 9226              &recov_state, NULL)) {
9227 9227                  /*
9228 9228                   * If readdir a node that is a stub for a crossed mount point,
9229 9229                   * keep the original secinfo flavor for the current file
9230 9230                   * system, not the crossed one.
9231 9231                   */
9232 9232                  (void) check_mnt_secinfo(mi->mi_curr_serv, vp);
9233 9233                  rdc->error = e.error;
9234 9234                  return;
9235 9235          }
9236 9236  
9237 9237          /*
9238 9238           * Determine which attrs to request for dirents.  This code
9239 9239           * must be protected by nfs4_start/end_fop because of r_server
9240 9240           * (which will change during failover recovery).
9241 9241           *
9242 9242           */
9243 9243          if (rp->r_flags & (R4LOOKUP | R4READDIRWATTR)) {
9244 9244                  /*
9245 9245                   * Get all vattr attrs plus filehandle and rdattr_error
9246 9246                   */
9247 9247                  rd_bitsval = NFS4_VATTR_MASK |
9248 9248                      FATTR4_RDATTR_ERROR_MASK |
9249 9249                      FATTR4_FILEHANDLE_MASK;
9250 9250  
9251 9251                  if (rp->r_flags & R4READDIRWATTR) {
9252 9252                          mutex_enter(&rp->r_statelock);
9253 9253                          rp->r_flags &= ~R4READDIRWATTR;
9254 9254                          mutex_exit(&rp->r_statelock);
9255 9255                  }
9256 9256          } else {
9257 9257                  servinfo4_t *svp = rp->r_server;
9258 9258  
9259 9259                  /*
9260 9260                   * Already read directory. Use readdir with
9261 9261                   * no attrs (except for mounted_on_fileid) for updates.
9262 9262                   */
9263 9263                  rd_bitsval = FATTR4_RDATTR_ERROR_MASK;
9264 9264  
9265 9265                  /*
9266 9266                   * request mounted on fileid if supported, else request
9267 9267                   * fileid.  maybe we should verify that fileid is supported
9268 9268                   * and request something else if not.
9269 9269                   */
9270 9270                  (void) nfs_rw_enter_sig(&svp->sv_lock, RW_READER, 0);
9271 9271                  if (svp->sv_supp_attrs & FATTR4_MOUNTED_ON_FILEID_MASK)
9272 9272                          rd_bitsval |= FATTR4_MOUNTED_ON_FILEID_MASK;
9273 9273                  nfs_rw_exit(&svp->sv_lock);
9274 9274          }
9275 9275  
9276 9276          /* putfh directory fh */
9277 9277          argop[0].argop = OP_CPUTFH;
9278 9278          argop[0].nfs_argop4_u.opcputfh.sfh = rp->r_fh;
9279 9279  
9280 9280          argop[1].argop = OP_READDIR;
9281 9281          rargs = &argop[1].nfs_argop4_u.opreaddir;
9282 9282          /*
9283 9283           * 1 and 2 are reserved for client "." and ".." entry offset.
9284 9284           * cookie 0 should be used over-the-wire to start reading at
9285 9285           * the beginning of the directory excluding "." and "..".
9286 9286           */
9287 9287          if (rdc->nfs4_cookie == 0 ||
9288 9288              rdc->nfs4_cookie == 1 ||
9289 9289              rdc->nfs4_cookie == 2) {
9290 9290                  rargs->cookie = (nfs_cookie4)0;
9291 9291                  rargs->cookieverf = 0;
9292 9292          } else {
9293 9293                  rargs->cookie = (nfs_cookie4)rdc->nfs4_cookie;
9294 9294                  mutex_enter(&rp->r_statelock);
9295 9295                  rargs->cookieverf = rp->r_cookieverf4;
9296 9296                  mutex_exit(&rp->r_statelock);
9297 9297          }
9298 9298          rargs->dircount = MIN(rdc->buflen, mi->mi_tsize);
9299 9299          rargs->maxcount = mi->mi_tsize;
9300 9300          rargs->attr_request = rd_bitsval;
9301 9301          rargs->rdc = rdc;
9302 9302          rargs->dvp = vp;
9303 9303          rargs->mi = mi;
9304 9304          rargs->cr = cr;
9305 9305  
9306 9306  
9307 9307          /*
9308 9308           * If count < than the minimum required, we return no entries
9309 9309           * and fail with EINVAL
9310 9310           */
9311 9311          if (rargs->dircount < (DIRENT64_RECLEN(1) + DIRENT64_RECLEN(2))) {
9312 9312                  rdc->error = EINVAL;
9313 9313                  goto out;
9314 9314          }
9315 9315  
9316 9316          if (args.array_len == 5) {
9317 9317                  /*
9318 9318                   * Add lookupp and getattr for parent nodeid.
9319 9319                   */
9320 9320                  argop[2].argop = OP_LOOKUPP;
9321 9321  
9322 9322                  argop[3].argop = OP_GETFH;
9323 9323  
9324 9324                  /* getattr parent */
9325 9325                  argop[4].argop = OP_GETATTR;
9326 9326                  argop[4].nfs_argop4_u.opgetattr.attr_request = NFS4_VATTR_MASK;
9327 9327                  argop[4].nfs_argop4_u.opgetattr.mi = mi;
9328 9328          }
9329 9329  
9330 9330          doqueue = 1;
9331 9331  
9332 9332          if (mi->mi_io_kstats) {
9333 9333                  mutex_enter(&mi->mi_lock);
9334 9334                  kstat_runq_enter(KSTAT_IO_PTR(mi->mi_io_kstats));
9335 9335                  mutex_exit(&mi->mi_lock);
9336 9336          }
9337 9337  
9338 9338          /* capture the time of this call */
9339 9339          rargs->t = t = gethrtime();
9340 9340  
9341 9341          rfs4call(mi, &args, &res, cr, &doqueue, 0, &e);
9342 9342  
9343 9343          if (mi->mi_io_kstats) {
9344 9344                  mutex_enter(&mi->mi_lock);
9345 9345                  kstat_runq_exit(KSTAT_IO_PTR(mi->mi_io_kstats));
9346 9346                  mutex_exit(&mi->mi_lock);
9347 9347          }
9348 9348  
9349 9349          needrecov = nfs4_needs_recovery(&e, FALSE, mi->mi_vfsp);
9350 9350  
9351 9351          /*
9352 9352           * If RPC error occurred and it isn't an error that
9353 9353           * triggers recovery, then go ahead and fail now.
9354 9354           */
9355 9355          if (e.error != 0 && !needrecov) {
9356 9356                  rdc->error = e.error;
9357 9357                  goto out;
9358 9358          }
9359 9359  
9360 9360          if (needrecov) {
9361 9361                  bool_t abort;
9362 9362  
9363 9363                  NFS4_DEBUG(nfs4_client_recov_debug, (CE_NOTE,
9364 9364                      "nfs4readdir: initiating recovery.\n"));
9365 9365  
9366 9366                  abort = nfs4_start_recovery(&e, VTOMI4(vp), vp, NULL, NULL,
9367 9367                      NULL, OP_READDIR, NULL, NULL, NULL);
9368 9368                  if (abort == FALSE) {
9369 9369                          nfs4_end_fop(VTOMI4(vp), vp, NULL, OH_READDIR,
9370 9370                              &recov_state, needrecov);
9371 9371                          if (!e.error)
9372 9372                                  (void) xdr_free(xdr_COMPOUND4res_clnt,
9373 9373                                      (caddr_t)&res);
9374 9374                          if (rdc->entries != NULL) {
9375 9375                                  kmem_free(rdc->entries, rdc->entlen);
9376 9376                                  rdc->entries = NULL;
9377 9377                          }
9378 9378                          goto recov_retry;
9379 9379                  }
9380 9380  
9381 9381                  if (e.error != 0) {
9382 9382                          rdc->error = e.error;
9383 9383                          goto out;
9384 9384                  }
9385 9385  
9386 9386                  /* fall through for res.status case */
9387 9387          }
9388 9388  
9389 9389          res_opcnt = res.array_len;
9390 9390  
9391 9391          /*
9392 9392           * If compound failed first 2 ops (PUTFH+READDIR), then return
9393 9393           * failure here.  Subsequent ops are for filling out dot-dot
9394 9394           * dirent, and if they fail, we still want to give the caller
9395 9395           * the dirents returned by (the successful) READDIR op, so we need
9396 9396           * to silently ignore failure for subsequent ops (LOOKUPP+GETATTR).
9397 9397           *
9398 9398           * One example where PUTFH+READDIR ops would succeed but
9399 9399           * LOOKUPP+GETATTR would fail would be a dir that has r perm
9400 9400           * but lacks x.  In this case, a POSIX server's VOP_READDIR
9401 9401           * would succeed; however, VOP_LOOKUP(..) would fail since no
9402 9402           * x perm.  We need to come up with a non-vendor-specific way
9403 9403           * for a POSIX server to return d_ino from dotdot's dirent if
9404 9404           * client only requests mounted_on_fileid, and just say the
9405 9405           * LOOKUPP succeeded and fill out the GETATTR.  However, if
9406 9406           * client requested any mandatory attrs, server would be required
9407 9407           * to fail the GETATTR op because it can't call VOP_LOOKUP+VOP_GETATTR
9408 9408           * for dotdot.
9409 9409           */
9410 9410  
9411 9411          if (res.status) {
9412 9412                  if (res_opcnt <= 2) {
9413 9413                          e.error = geterrno4(res.status);
9414 9414                          nfs4_end_fop(VTOMI4(vp), vp, NULL, OH_READDIR,
9415 9415                              &recov_state, needrecov);
9416 9416                          nfs4_purge_stale_fh(e.error, vp, cr);
9417 9417                          rdc->error = e.error;
9418 9418                          (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
9419 9419                          if (rdc->entries != NULL) {
9420 9420                                  kmem_free(rdc->entries, rdc->entlen);
9421 9421                                  rdc->entries = NULL;
9422 9422                          }
9423 9423                          /*
9424 9424                           * If readdir a node that is a stub for a
9425 9425                           * crossed mount point, keep the original
9426 9426                           * secinfo flavor for the current file system,
9427 9427                           * not the crossed one.
9428 9428                           */
9429 9429                          (void) check_mnt_secinfo(mi->mi_curr_serv, vp);
9430 9430                          return;
9431 9431                  }
9432 9432          }
9433 9433  
9434 9434          resop = &res.array[1];  /* readdir res */
9435 9435          rd_res = &resop->nfs_resop4_u.opreaddirclnt;
9436 9436  
9437 9437          mutex_enter(&rp->r_statelock);
9438 9438          rp->r_cookieverf4 = rd_res->cookieverf;
9439 9439          mutex_exit(&rp->r_statelock);
9440 9440  
9441 9441          /*
9442 9442           * For "." and ".." entries
9443 9443           * e.g.
9444 9444           *      seek(cookie=0) -> "." entry with d_off = 1
9445 9445           *      seek(cookie=1) -> ".." entry with d_off = 2
9446 9446           */
9447 9447          if (cookie == (nfs_cookie4) 0) {
9448 9448                  if (rd_res->dotp)
9449 9449                          rd_res->dotp->d_ino = nodeid;
9450 9450                  if (rd_res->dotdotp)
9451 9451                          rd_res->dotdotp->d_ino = pnodeid;
9452 9452          }
9453 9453          if (cookie == (nfs_cookie4) 1) {
9454 9454                  if (rd_res->dotdotp)
9455 9455                          rd_res->dotdotp->d_ino = pnodeid;
9456 9456          }
9457 9457  
9458 9458  
9459 9459          /* LOOKUPP+GETATTR attemped */
9460 9460          if (args.array_len == 5 && rd_res->dotdotp) {
9461 9461                  if (res.status == NFS4_OK && res_opcnt == 5) {
9462 9462                          nfs_fh4 *fhp;
9463 9463                          nfs4_sharedfh_t *sfhp;
9464 9464                          vnode_t *pvp;
9465 9465                          nfs4_ga_res_t *garp;
9466 9466  
9467 9467                          resop++;        /* lookupp */
9468 9468                          resop++;        /* getfh   */
9469 9469                          fhp = &resop->nfs_resop4_u.opgetfh.object;
9470 9470  
9471 9471                          resop++;        /* getattr of parent */
9472 9472  
9473 9473                          /*
9474 9474                           * First, take care of finishing the
9475 9475                           * readdir results.
9476 9476                           */
9477 9477                          garp = &resop->nfs_resop4_u.opgetattr.ga_res;
9478 9478                          /*
9479 9479                           * The d_ino of .. must be the inode number
9480 9480                           * of the mounted filesystem.
9481 9481                           */
9482 9482                          if (garp->n4g_va.va_mask & AT_NODEID)
9483 9483                                  rd_res->dotdotp->d_ino =
9484 9484                                      garp->n4g_va.va_nodeid;
9485 9485  
9486 9486  
9487 9487                          /*
9488 9488                           * Next, create the ".." dnlc entry
9489 9489                           */
9490 9490                          sfhp = sfh4_get(fhp, mi);
9491 9491                          if (!nfs4_make_dotdot(sfhp, t, vp, cr, &pvp, 0)) {
9492 9492                                  dnlc_update(vp, "..", pvp);
9493 9493                                  VN_RELE(pvp);
9494 9494                          }
9495 9495                          sfh4_rele(&sfhp);
9496 9496                  }
9497 9497          }
9498 9498  
9499 9499          if (mi->mi_io_kstats) {
9500 9500                  mutex_enter(&mi->mi_lock);
9501 9501                  KSTAT_IO_PTR(mi->mi_io_kstats)->reads++;
9502 9502                  KSTAT_IO_PTR(mi->mi_io_kstats)->nread += rdc->actlen;
9503 9503                  mutex_exit(&mi->mi_lock);
9504 9504          }
9505 9505  
9506 9506          (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
9507 9507  
9508 9508  out:
9509 9509          /*
9510 9510           * If readdir a node that is a stub for a crossed mount point,
9511 9511           * keep the original secinfo flavor for the current file system,
9512 9512           * not the crossed one.
9513 9513           */
9514 9514          (void) check_mnt_secinfo(mi->mi_curr_serv, vp);
9515 9515  
9516 9516          nfs4_end_fop(mi, vp, NULL, OH_READDIR, &recov_state, needrecov);
9517 9517  }
9518 9518  
9519 9519  
9520 9520  static int
9521 9521  nfs4_bio(struct buf *bp, stable_how4 *stab_comm, cred_t *cr, bool_t readahead)
9522 9522  {
9523 9523          rnode4_t *rp = VTOR4(bp->b_vp);
9524 9524          int count;
9525 9525          int error;
9526 9526          cred_t *cred_otw = NULL;
9527 9527          offset_t offset;
9528 9528          nfs4_open_stream_t *osp = NULL;
9529 9529          bool_t first_time = TRUE;       /* first time getting otw cred */
9530 9530          bool_t last_time = FALSE;       /* last time getting otw cred */
9531 9531  
9532 9532          ASSERT(nfs_zone() == VTOMI4(bp->b_vp)->mi_zone);
9533 9533  
9534 9534          DTRACE_IO1(start, struct buf *, bp);
9535 9535          offset = ldbtob(bp->b_lblkno);
9536 9536  
9537 9537          if (bp->b_flags & B_READ) {
9538 9538          read_again:
9539 9539                  /*
9540 9540                   * Releases the osp, if it is provided.
9541 9541                   * Puts a hold on the cred_otw and the new osp (if found).
9542 9542                   */
9543 9543                  cred_otw = nfs4_get_otw_cred_by_osp(rp, cr, &osp,
9544 9544                      &first_time, &last_time);
9545 9545                  error = bp->b_error = nfs4read(bp->b_vp, bp->b_un.b_addr,
9546 9546                      offset, bp->b_bcount, &bp->b_resid, cred_otw,
9547 9547                      readahead, NULL);
9548 9548                  crfree(cred_otw);
9549 9549                  if (!error) {
9550 9550                          if (bp->b_resid) {
9551 9551                                  /*
9552 9552                                   * Didn't get it all because we hit EOF,
9553 9553                                   * zero all the memory beyond the EOF.
9554 9554                                   */
9555 9555                                  /* bzero(rdaddr + */
9556 9556                                  bzero(bp->b_un.b_addr +
9557 9557                                      bp->b_bcount - bp->b_resid, bp->b_resid);
9558 9558                          }
9559 9559                          mutex_enter(&rp->r_statelock);
9560 9560                          if (bp->b_resid == bp->b_bcount &&
9561 9561                              offset >= rp->r_size) {
9562 9562                                  /*
9563 9563                                   * We didn't read anything at all as we are
9564 9564                                   * past EOF.  Return an error indicator back
9565 9565                                   * but don't destroy the pages (yet).
9566 9566                                   */
9567 9567                                  error = NFS_EOF;
9568 9568                          }
9569 9569                          mutex_exit(&rp->r_statelock);
9570 9570                  } else if (error == EACCES && last_time == FALSE) {
9571 9571                                  goto read_again;
9572 9572                  }
9573 9573          } else {
9574 9574                  if (!(rp->r_flags & R4STALE)) {
9575 9575  write_again:
9576 9576                          /*
9577 9577                           * Releases the osp, if it is provided.
9578 9578                           * Puts a hold on the cred_otw and the new
9579 9579                           * osp (if found).
9580 9580                           */
9581 9581                          cred_otw = nfs4_get_otw_cred_by_osp(rp, cr, &osp,
9582 9582                              &first_time, &last_time);
9583 9583                          mutex_enter(&rp->r_statelock);
9584 9584                          count = MIN(bp->b_bcount, rp->r_size - offset);
9585 9585                          mutex_exit(&rp->r_statelock);
9586 9586                          if (count < 0)
9587 9587                                  cmn_err(CE_PANIC, "nfs4_bio: write count < 0");
9588 9588  #ifdef DEBUG
9589 9589                          if (count == 0) {
9590 9590                                  zoneid_t zoneid = getzoneid();
9591 9591  
9592 9592                                  zcmn_err(zoneid, CE_WARN,
9593 9593                                      "nfs4_bio: zero length write at %lld",
9594 9594                                      offset);
9595 9595                                  zcmn_err(zoneid, CE_CONT, "flags=0x%x, "
9596 9596                                      "b_bcount=%ld, file size=%lld",
9597 9597                                      rp->r_flags, (long)bp->b_bcount,
9598 9598                                      rp->r_size);
9599 9599                                  sfh4_printfhandle(VTOR4(bp->b_vp)->r_fh);
9600 9600                                  if (nfs4_bio_do_stop)
9601 9601                                          debug_enter("nfs4_bio");
9602 9602                          }
9603 9603  #endif
9604 9604                          error = nfs4write(bp->b_vp, bp->b_un.b_addr, offset,
9605 9605                              count, cred_otw, stab_comm);
9606 9606                          if (error == EACCES && last_time == FALSE) {
9607 9607                                  crfree(cred_otw);
9608 9608                                  goto write_again;
9609 9609                          }
9610 9610                          bp->b_error = error;
9611 9611                          if (error && error != EINTR &&
9612 9612                              !(bp->b_vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)) {
9613 9613                                  /*
9614 9614                                   * Don't print EDQUOT errors on the console.
9615 9615                                   * Don't print asynchronous EACCES errors.
9616 9616                                   * Don't print EFBIG errors.
9617 9617                                   * Print all other write errors.
9618 9618                                   */
9619 9619                                  if (error != EDQUOT && error != EFBIG &&
9620 9620                                      (error != EACCES ||
9621 9621                                      !(bp->b_flags & B_ASYNC)))
9622 9622                                          nfs4_write_error(bp->b_vp,
9623 9623                                              error, cred_otw);
9624 9624                                  /*
9625 9625                                   * Update r_error and r_flags as appropriate.
9626 9626                                   * If the error was ESTALE, then mark the
9627 9627                                   * rnode as not being writeable and save
9628 9628                                   * the error status.  Otherwise, save any
9629 9629                                   * errors which occur from asynchronous
9630 9630                                   * page invalidations.  Any errors occurring
9631 9631                                   * from other operations should be saved
9632 9632                                   * by the caller.
9633 9633                                   */
9634 9634                                  mutex_enter(&rp->r_statelock);
9635 9635                                  if (error == ESTALE) {
9636 9636                                          rp->r_flags |= R4STALE;
9637 9637                                          if (!rp->r_error)
9638 9638                                                  rp->r_error = error;
9639 9639                                  } else if (!rp->r_error &&
9640 9640                                      (bp->b_flags &
9641 9641                                      (B_INVAL|B_FORCE|B_ASYNC)) ==
9642 9642                                      (B_INVAL|B_FORCE|B_ASYNC)) {
9643 9643                                          rp->r_error = error;
9644 9644                                  }
9645 9645                                  mutex_exit(&rp->r_statelock);
9646 9646                          }
9647 9647                          crfree(cred_otw);
9648 9648                  } else {
9649 9649                          error = rp->r_error;
9650 9650                          /*
9651 9651                           * A close may have cleared r_error, if so,
9652 9652                           * propagate ESTALE error return properly
9653 9653                           */
9654 9654                          if (error == 0)
9655 9655                                  error = ESTALE;
9656 9656                  }
9657 9657          }
9658 9658  
9659 9659          if (error != 0 && error != NFS_EOF)
9660 9660                  bp->b_flags |= B_ERROR;
9661 9661  
9662 9662          if (osp)
9663 9663                  open_stream_rele(osp, rp);
9664 9664  
9665 9665          DTRACE_IO1(done, struct buf *, bp);
9666 9666  
9667 9667          return (error);
9668 9668  }
9669 9669  
9670 9670  /* ARGSUSED */
9671 9671  int
9672 9672  nfs4_fid(vnode_t *vp, fid_t *fidp, caller_context_t *ct)
9673 9673  {
9674 9674          return (EREMOTE);
9675 9675  }
9676 9676  
9677 9677  /* ARGSUSED2 */
9678 9678  int
9679 9679  nfs4_rwlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
9680 9680  {
9681 9681          rnode4_t *rp = VTOR4(vp);
9682 9682  
9683 9683          if (!write_lock) {
9684 9684                  (void) nfs_rw_enter_sig(&rp->r_rwlock, RW_READER, FALSE);
9685 9685                  return (V_WRITELOCK_FALSE);
9686 9686          }
9687 9687  
9688 9688          if ((rp->r_flags & R4DIRECTIO) ||
9689 9689              (VTOMI4(vp)->mi_flags & MI4_DIRECTIO)) {
9690 9690                  (void) nfs_rw_enter_sig(&rp->r_rwlock, RW_READER, FALSE);
9691 9691                  if (rp->r_mapcnt == 0 && !nfs4_has_pages(vp))
9692 9692                          return (V_WRITELOCK_FALSE);
9693 9693                  nfs_rw_exit(&rp->r_rwlock);
9694 9694          }
9695 9695  
9696 9696          (void) nfs_rw_enter_sig(&rp->r_rwlock, RW_WRITER, FALSE);
9697 9697          return (V_WRITELOCK_TRUE);
9698 9698  }
9699 9699  
9700 9700  /* ARGSUSED */
9701 9701  void
9702 9702  nfs4_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
9703 9703  {
9704 9704          rnode4_t *rp = VTOR4(vp);
9705 9705  
9706 9706          nfs_rw_exit(&rp->r_rwlock);
9707 9707  }
9708 9708  
9709 9709  /* ARGSUSED */
9710 9710  static int
9711 9711  nfs4_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
9712 9712  {
9713 9713          if (nfs_zone() != VTOMI4(vp)->mi_zone)
9714 9714                  return (EIO);
9715 9715  
9716 9716          /*
9717 9717           * Because we stuff the readdir cookie into the offset field
9718 9718           * someone may attempt to do an lseek with the cookie which
9719 9719           * we want to succeed.
9720 9720           */
9721 9721          if (vp->v_type == VDIR)
9722 9722                  return (0);
9723 9723          if (*noffp < 0)
9724 9724                  return (EINVAL);
9725 9725          return (0);
9726 9726  }
9727 9727  
9728 9728  
9729 9729  /*
9730 9730   * Return all the pages from [off..off+len) in file
9731 9731   */
9732 9732  /* ARGSUSED */
9733 9733  static int
9734 9734  nfs4_getpage(vnode_t *vp, offset_t off, size_t len, uint_t *protp,
9735 9735      page_t *pl[], size_t plsz, struct seg *seg, caddr_t addr,
9736 9736      enum seg_rw rw, cred_t *cr, caller_context_t *ct)
9737 9737  {
9738 9738          rnode4_t *rp;
9739 9739          int error;
9740 9740          mntinfo4_t *mi;
9741 9741  
9742 9742          if (nfs_zone() != VTOMI4(vp)->mi_zone)
9743 9743                  return (EIO);
9744 9744          rp = VTOR4(vp);
9745 9745          if (IS_SHADOW(vp, rp))
9746 9746                  vp = RTOV4(rp);
9747 9747  
9748 9748          if (vp->v_flag & VNOMAP)
9749 9749                  return (ENOSYS);
9750 9750  
9751 9751          if (protp != NULL)
9752 9752                  *protp = PROT_ALL;
9753 9753  
9754 9754          /*
9755 9755           * Now validate that the caches are up to date.
9756 9756           */
9757 9757          if (error = nfs4_validate_caches(vp, cr))
9758 9758                  return (error);
9759 9759  
9760 9760          mi = VTOMI4(vp);
9761 9761  retry:
9762 9762          mutex_enter(&rp->r_statelock);
9763 9763  
9764 9764          /*
9765 9765           * Don't create dirty pages faster than they
9766 9766           * can be cleaned so that the system doesn't
9767 9767           * get imbalanced.  If the async queue is
9768 9768           * maxed out, then wait for it to drain before
9769 9769           * creating more dirty pages.  Also, wait for
9770 9770           * any threads doing pagewalks in the vop_getattr
9771 9771           * entry points so that they don't block for
9772 9772           * long periods.
9773 9773           */
9774 9774          if (rw == S_CREATE) {
9775 9775                  while ((mi->mi_max_threads != 0 &&
9776 9776                      rp->r_awcount > 2 * mi->mi_max_threads) ||
9777 9777                      rp->r_gcount > 0)
9778 9778                          cv_wait(&rp->r_cv, &rp->r_statelock);
9779 9779          }
9780 9780  
9781 9781          /*
9782 9782           * If we are getting called as a side effect of an nfs_write()
9783 9783           * operation the local file size might not be extended yet.
9784 9784           * In this case we want to be able to return pages of zeroes.
9785 9785           */
9786 9786          if (off + len > rp->r_size + PAGEOFFSET && seg != segkmap) {
9787 9787                  NFS4_DEBUG(nfs4_pageio_debug,
9788 9788                      (CE_NOTE, "getpage beyond EOF: off=%lld, "
9789 9789                      "len=%llu, size=%llu, attrsize =%llu", off,
9790 9790                      (u_longlong_t)len, rp->r_size, rp->r_attr.va_size));
9791 9791                  mutex_exit(&rp->r_statelock);
9792 9792                  return (EFAULT);                /* beyond EOF */
9793 9793          }
9794 9794  
9795 9795          mutex_exit(&rp->r_statelock);
9796 9796  
9797 9797          error = pvn_getpages(nfs4_getapage, vp, off, len, protp,
9798 9798              pl, plsz, seg, addr, rw, cr);
9799 9799          NFS4_DEBUG(nfs4_pageio_debug && error,
9800 9800              (CE_NOTE, "getpages error %d; off=%lld, len=%lld",
9801 9801              error, off, (u_longlong_t)len));
9802 9802  
9803 9803          switch (error) {
9804 9804          case NFS_EOF:
9805 9805                  nfs4_purge_caches(vp, NFS4_NOPURGE_DNLC, cr, FALSE);
9806 9806                  goto retry;
9807 9807          case ESTALE:
9808 9808                  nfs4_purge_stale_fh(error, vp, cr);
9809 9809          }
9810 9810  
9811 9811          return (error);
9812 9812  }
9813 9813  
9814 9814  /*
9815 9815   * Called from pvn_getpages to get a particular page.
9816 9816   */
9817 9817  /* ARGSUSED */
9818 9818  static int
9819 9819  nfs4_getapage(vnode_t *vp, u_offset_t off, size_t len, uint_t *protp,
9820 9820      page_t *pl[], size_t plsz, struct seg *seg, caddr_t addr,
9821 9821      enum seg_rw rw, cred_t *cr)
9822 9822  {
9823 9823          rnode4_t *rp;
9824 9824          uint_t bsize;
9825 9825          struct buf *bp;
9826 9826          page_t *pp;
9827 9827          u_offset_t lbn;
9828 9828          u_offset_t io_off;
9829 9829          u_offset_t blkoff;
9830 9830          u_offset_t rablkoff;
9831 9831          size_t io_len;
9832 9832          uint_t blksize;
9833 9833          int error;
9834 9834          int readahead;
9835 9835          int readahead_issued = 0;
9836 9836          int ra_window; /* readahead window */
9837 9837          page_t *pagefound;
9838 9838          page_t *savepp;
9839 9839  
9840 9840          if (nfs_zone() != VTOMI4(vp)->mi_zone)
9841 9841                  return (EIO);
9842 9842  
9843 9843          rp = VTOR4(vp);
9844 9844          ASSERT(!IS_SHADOW(vp, rp));
9845 9845          bsize = MAX(vp->v_vfsp->vfs_bsize, PAGESIZE);
9846 9846  
9847 9847  reread:
9848 9848          bp = NULL;
9849 9849          pp = NULL;
9850 9850          pagefound = NULL;
9851 9851  
9852 9852          if (pl != NULL)
9853 9853                  pl[0] = NULL;
9854 9854  
9855 9855          error = 0;
9856 9856          lbn = off / bsize;
9857 9857          blkoff = lbn * bsize;
9858 9858  
9859 9859          /*
9860 9860           * Queueing up the readahead before doing the synchronous read
9861 9861           * results in a significant increase in read throughput because
9862 9862           * of the increased parallelism between the async threads and
9863 9863           * the process context.
9864 9864           */
9865 9865          if ((off & ((vp->v_vfsp->vfs_bsize) - 1)) == 0 &&
9866 9866              rw != S_CREATE &&
9867 9867              !(vp->v_flag & VNOCACHE)) {
9868 9868                  mutex_enter(&rp->r_statelock);
9869 9869  
9870 9870                  /*
9871 9871                   * Calculate the number of readaheads to do.
9872 9872                   * a) No readaheads at offset = 0.
9873 9873                   * b) Do maximum(nfs4_nra) readaheads when the readahead
9874 9874                   *    window is closed.
9875 9875                   * c) Do readaheads between 1 to (nfs4_nra - 1) depending
9876 9876                   *    upon how far the readahead window is open or close.
9877 9877                   * d) No readaheads if rp->r_nextr is not within the scope
9878 9878                   *    of the readahead window (random i/o).
9879 9879                   */
9880 9880  
9881 9881                  if (off == 0)
9882 9882                          readahead = 0;
9883 9883                  else if (blkoff == rp->r_nextr)
9884 9884                          readahead = nfs4_nra;
9885 9885                  else if (rp->r_nextr > blkoff &&
9886 9886                      ((ra_window = (rp->r_nextr - blkoff) / bsize)
9887 9887                      <= (nfs4_nra - 1)))
9888 9888                          readahead = nfs4_nra - ra_window;
9889 9889                  else
9890 9890                          readahead = 0;
9891 9891  
9892 9892                  rablkoff = rp->r_nextr;
9893 9893                  while (readahead > 0 && rablkoff + bsize < rp->r_size) {
9894 9894                          mutex_exit(&rp->r_statelock);
9895 9895                          if (nfs4_async_readahead(vp, rablkoff + bsize,
9896 9896                              addr + (rablkoff + bsize - off),
9897 9897                              seg, cr, nfs4_readahead) < 0) {
9898 9898                                  mutex_enter(&rp->r_statelock);
9899 9899                                  break;
9900 9900                          }
9901 9901                          readahead--;
9902 9902                          rablkoff += bsize;
9903 9903                          /*
9904 9904                           * Indicate that we did a readahead so
9905 9905                           * readahead offset is not updated
9906 9906                           * by the synchronous read below.
9907 9907                           */
9908 9908                          readahead_issued = 1;
9909 9909                          mutex_enter(&rp->r_statelock);
9910 9910                          /*
9911 9911                           * set readahead offset to
9912 9912                           * offset of last async readahead
9913 9913                           * request.
9914 9914                           */
9915 9915                          rp->r_nextr = rablkoff;
9916 9916                  }
9917 9917                  mutex_exit(&rp->r_statelock);
9918 9918          }
9919 9919  
9920 9920  again:
9921 9921          if ((pagefound = page_exists(vp, off)) == NULL) {
9922 9922                  if (pl == NULL) {
9923 9923                          (void) nfs4_async_readahead(vp, blkoff, addr, seg, cr,
9924 9924                              nfs4_readahead);
9925 9925                  } else if (rw == S_CREATE) {
9926 9926                          /*
9927 9927                           * Block for this page is not allocated, or the offset
9928 9928                           * is beyond the current allocation size, or we're
9929 9929                           * allocating a swap slot and the page was not found,
9930 9930                           * so allocate it and return a zero page.
9931 9931                           */
9932 9932                          if ((pp = page_create_va(vp, off,
9933 9933                              PAGESIZE, PG_WAIT, seg, addr)) == NULL)
9934 9934                                  cmn_err(CE_PANIC, "nfs4_getapage: page_create");
9935 9935                          io_len = PAGESIZE;
9936 9936                          mutex_enter(&rp->r_statelock);
9937 9937                          rp->r_nextr = off + PAGESIZE;
9938 9938                          mutex_exit(&rp->r_statelock);
9939 9939                  } else {
9940 9940                          /*
9941 9941                           * Need to go to server to get a block
9942 9942                           */
9943 9943                          mutex_enter(&rp->r_statelock);
9944 9944                          if (blkoff < rp->r_size &&
9945 9945                              blkoff + bsize > rp->r_size) {
9946 9946                                  /*
9947 9947                                   * If less than a block left in
9948 9948                                   * file read less than a block.
9949 9949                                   */
9950 9950                                  if (rp->r_size <= off) {
9951 9951                                          /*
9952 9952                                           * Trying to access beyond EOF,
9953 9953                                           * set up to get at least one page.
9954 9954                                           */
9955 9955                                          blksize = off + PAGESIZE - blkoff;
9956 9956                                  } else
9957 9957                                          blksize = rp->r_size - blkoff;
9958 9958                          } else if ((off == 0) ||
9959 9959                              (off != rp->r_nextr && !readahead_issued)) {
9960 9960                                  blksize = PAGESIZE;
9961 9961                                  blkoff = off; /* block = page here */
9962 9962                          } else
9963 9963                                  blksize = bsize;
9964 9964                          mutex_exit(&rp->r_statelock);
9965 9965  
9966 9966                          pp = pvn_read_kluster(vp, off, seg, addr, &io_off,
9967 9967                              &io_len, blkoff, blksize, 0);
9968 9968  
9969 9969                          /*
9970 9970                           * Some other thread has entered the page,
9971 9971                           * so just use it.
9972 9972                           */
9973 9973                          if (pp == NULL)
9974 9974                                  goto again;
9975 9975  
9976 9976                          /*
9977 9977                           * Now round the request size up to page boundaries.
9978 9978                           * This ensures that the entire page will be
9979 9979                           * initialized to zeroes if EOF is encountered.
9980 9980                           */
9981 9981                          io_len = ptob(btopr(io_len));
9982 9982  
9983 9983                          bp = pageio_setup(pp, io_len, vp, B_READ);
9984 9984                          ASSERT(bp != NULL);
9985 9985  
9986 9986                          /*
9987 9987                           * pageio_setup should have set b_addr to 0.  This
9988 9988                           * is correct since we want to do I/O on a page
9989 9989                           * boundary.  bp_mapin will use this addr to calculate
9990 9990                           * an offset, and then set b_addr to the kernel virtual
9991 9991                           * address it allocated for us.
9992 9992                           */
9993 9993                          ASSERT(bp->b_un.b_addr == 0);
9994 9994  
9995 9995                          bp->b_edev = 0;
9996 9996                          bp->b_dev = 0;
9997 9997                          bp->b_lblkno = lbtodb(io_off);
9998 9998                          bp->b_file = vp;
9999 9999                          bp->b_offset = (offset_t)off;
10000 10000                          bp_mapin(bp);
10001 10001  
10002 10002                          /*
10003 10003                           * If doing a write beyond what we believe is EOF,
10004 10004                           * don't bother trying to read the pages from the
10005 10005                           * server, we'll just zero the pages here.  We
10006 10006                           * don't check that the rw flag is S_WRITE here
10007 10007                           * because some implementations may attempt a
10008 10008                           * read access to the buffer before copying data.
10009 10009                           */
10010 10010                          mutex_enter(&rp->r_statelock);
10011 10011                          if (io_off >= rp->r_size && seg == segkmap) {
10012 10012                                  mutex_exit(&rp->r_statelock);
10013 10013                                  bzero(bp->b_un.b_addr, io_len);
10014 10014                          } else {
10015 10015                                  mutex_exit(&rp->r_statelock);
10016 10016                                  error = nfs4_bio(bp, NULL, cr, FALSE);
10017 10017                          }
10018 10018  
10019 10019                          /*
10020 10020                           * Unmap the buffer before freeing it.
10021 10021                           */
10022 10022                          bp_mapout(bp);
10023 10023                          pageio_done(bp);
10024 10024  
10025 10025                          savepp = pp;
10026 10026                          do {
10027 10027                                  pp->p_fsdata = C_NOCOMMIT;
10028 10028                          } while ((pp = pp->p_next) != savepp);
10029 10029  
10030 10030                          if (error == NFS_EOF) {
10031 10031                                  /*
10032 10032                                   * If doing a write system call just return
10033 10033                                   * zeroed pages, else user tried to get pages
10034 10034                                   * beyond EOF, return error.  We don't check
10035 10035                                   * that the rw flag is S_WRITE here because
10036 10036                                   * some implementations may attempt a read
10037 10037                                   * access to the buffer before copying data.
10038 10038                                   */
10039 10039                                  if (seg == segkmap)
10040 10040                                          error = 0;
10041 10041                                  else
10042 10042                                          error = EFAULT;
10043 10043                          }
10044 10044  
10045 10045                          if (!readahead_issued && !error) {
10046 10046                                  mutex_enter(&rp->r_statelock);
10047 10047                                  rp->r_nextr = io_off + io_len;
10048 10048                                  mutex_exit(&rp->r_statelock);
10049 10049                          }
10050 10050                  }
10051 10051          }
10052 10052  
10053 10053  out:
10054 10054          if (pl == NULL)
10055 10055                  return (error);
10056 10056  
10057 10057          if (error) {
10058 10058                  if (pp != NULL)
10059 10059                          pvn_read_done(pp, B_ERROR);
10060 10060                  return (error);
10061 10061          }
10062 10062  
10063 10063          if (pagefound) {
10064 10064                  se_t se = (rw == S_CREATE ? SE_EXCL : SE_SHARED);
10065 10065  
10066 10066                  /*
10067 10067                   * Page exists in the cache, acquire the appropriate lock.
10068 10068                   * If this fails, start all over again.
10069 10069                   */
10070 10070                  if ((pp = page_lookup(vp, off, se)) == NULL) {
10071 10071  #ifdef DEBUG
10072 10072                          nfs4_lostpage++;
10073 10073  #endif
10074 10074                          goto reread;
10075 10075                  }
10076 10076                  pl[0] = pp;
10077 10077                  pl[1] = NULL;
10078 10078                  return (0);
10079 10079          }
10080 10080  
10081 10081          if (pp != NULL)
10082 10082                  pvn_plist_init(pp, pl, plsz, off, io_len, rw);
10083 10083  
10084 10084          return (error);
10085 10085  }
10086 10086  
10087 10087  static void
10088 10088  nfs4_readahead(vnode_t *vp, u_offset_t blkoff, caddr_t addr, struct seg *seg,
10089 10089      cred_t *cr)
10090 10090  {
10091 10091          int error;
10092 10092          page_t *pp;
10093 10093          u_offset_t io_off;
10094 10094          size_t io_len;
10095 10095          struct buf *bp;
10096 10096          uint_t bsize, blksize;
10097 10097          rnode4_t *rp = VTOR4(vp);
10098 10098          page_t *savepp;
10099 10099  
10100 10100          ASSERT(nfs_zone() == VTOMI4(vp)->mi_zone);
10101 10101  
10102 10102          bsize = MAX(vp->v_vfsp->vfs_bsize, PAGESIZE);
10103 10103  
10104 10104          mutex_enter(&rp->r_statelock);
10105 10105          if (blkoff < rp->r_size && blkoff + bsize > rp->r_size) {
10106 10106                  /*
10107 10107                   * If less than a block left in file read less
10108 10108                   * than a block.
10109 10109                   */
10110 10110                  blksize = rp->r_size - blkoff;
10111 10111          } else
10112 10112                  blksize = bsize;
10113 10113          mutex_exit(&rp->r_statelock);
10114 10114  
10115 10115          pp = pvn_read_kluster(vp, blkoff, segkmap, addr,
10116 10116              &io_off, &io_len, blkoff, blksize, 1);
10117 10117          /*
10118 10118           * The isra flag passed to the kluster function is 1, we may have
10119 10119           * gotten a return value of NULL for a variety of reasons (# of free
10120 10120           * pages < minfree, someone entered the page on the vnode etc). In all
10121 10121           * cases, we want to punt on the readahead.
10122 10122           */
10123 10123          if (pp == NULL)
10124 10124                  return;
10125 10125  
10126 10126          /*
10127 10127           * Now round the request size up to page boundaries.
10128 10128           * This ensures that the entire page will be
10129 10129           * initialized to zeroes if EOF is encountered.
10130 10130           */
10131 10131          io_len = ptob(btopr(io_len));
10132 10132  
10133 10133          bp = pageio_setup(pp, io_len, vp, B_READ);
10134 10134          ASSERT(bp != NULL);
10135 10135  
10136 10136          /*
10137 10137           * pageio_setup should have set b_addr to 0.  This is correct since
10138 10138           * we want to do I/O on a page boundary. bp_mapin() will use this addr
10139 10139           * to calculate an offset, and then set b_addr to the kernel virtual
10140 10140           * address it allocated for us.
10141 10141           */
10142 10142          ASSERT(bp->b_un.b_addr == 0);
10143 10143  
10144 10144          bp->b_edev = 0;
10145 10145          bp->b_dev = 0;
10146 10146          bp->b_lblkno = lbtodb(io_off);
10147 10147          bp->b_file = vp;
10148 10148          bp->b_offset = (offset_t)blkoff;
10149 10149          bp_mapin(bp);
10150 10150  
10151 10151          /*
10152 10152           * If doing a write beyond what we believe is EOF, don't bother trying
10153 10153           * to read the pages from the server, we'll just zero the pages here.
10154 10154           * We don't check that the rw flag is S_WRITE here because some
10155 10155           * implementations may attempt a read access to the buffer before
10156 10156           * copying data.
10157 10157           */
10158 10158          mutex_enter(&rp->r_statelock);
10159 10159          if (io_off >= rp->r_size && seg == segkmap) {
10160 10160                  mutex_exit(&rp->r_statelock);
10161 10161                  bzero(bp->b_un.b_addr, io_len);
10162 10162                  error = 0;
10163 10163          } else {
10164 10164                  mutex_exit(&rp->r_statelock);
10165 10165                  error = nfs4_bio(bp, NULL, cr, TRUE);
10166 10166                  if (error == NFS_EOF)
10167 10167                          error = 0;
10168 10168          }
10169 10169  
10170 10170          /*
10171 10171           * Unmap the buffer before freeing it.
10172 10172           */
10173 10173          bp_mapout(bp);
10174 10174          pageio_done(bp);
10175 10175  
10176 10176          savepp = pp;
10177 10177          do {
10178 10178                  pp->p_fsdata = C_NOCOMMIT;
10179 10179          } while ((pp = pp->p_next) != savepp);
10180 10180  
10181 10181          pvn_read_done(pp, error ? B_READ | B_ERROR : B_READ);
10182 10182  
10183 10183          /*
10184 10184           * In case of error set readahead offset
10185 10185           * to the lowest offset.
10186 10186           * pvn_read_done() calls VN_DISPOSE to destroy the pages
10187 10187           */
10188 10188          if (error && rp->r_nextr > io_off) {
10189 10189                  mutex_enter(&rp->r_statelock);
10190 10190                  if (rp->r_nextr > io_off)
10191 10191                          rp->r_nextr = io_off;
10192 10192                  mutex_exit(&rp->r_statelock);
10193 10193          }
10194 10194  }
10195 10195  
10196 10196  /*
10197 10197   * Flags are composed of {B_INVAL, B_FREE, B_DONTNEED, B_FORCE}
10198 10198   * If len == 0, do from off to EOF.
10199 10199   *
10200 10200   * The normal cases should be len == 0 && off == 0 (entire vp list) or
10201 10201   * len == MAXBSIZE (from segmap_release actions), and len == PAGESIZE
10202 10202   * (from pageout).
10203 10203   */
10204 10204  /* ARGSUSED */
10205 10205  static int
10206 10206  nfs4_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr,
10207 10207      caller_context_t *ct)
10208 10208  {
10209 10209          int error;
10210 10210          rnode4_t *rp;
10211 10211  
10212 10212          ASSERT(cr != NULL);
10213 10213  
10214 10214          if (!(flags & B_ASYNC) && nfs_zone() != VTOMI4(vp)->mi_zone)
10215 10215                  return (EIO);
10216 10216  
10217 10217          rp = VTOR4(vp);
10218 10218          if (IS_SHADOW(vp, rp))
10219 10219                  vp = RTOV4(rp);
10220 10220  
10221 10221          /*
10222 10222           * XXX - Why should this check be made here?
10223 10223           */
10224 10224          if (vp->v_flag & VNOMAP)
10225 10225                  return (ENOSYS);
10226 10226  
10227 10227          if (len == 0 && !(flags & B_INVAL) &&
10228 10228              (vp->v_vfsp->vfs_flag & VFS_RDONLY))
10229 10229                  return (0);
10230 10230  
10231 10231          mutex_enter(&rp->r_statelock);
10232 10232          rp->r_count++;
10233 10233          mutex_exit(&rp->r_statelock);
10234 10234          error = nfs4_putpages(vp, off, len, flags, cr);
10235 10235          mutex_enter(&rp->r_statelock);
10236 10236          rp->r_count--;
10237 10237          cv_broadcast(&rp->r_cv);
10238 10238          mutex_exit(&rp->r_statelock);
10239 10239  
10240 10240          return (error);
10241 10241  }
10242 10242  
10243 10243  /*
10244 10244   * Write out a single page, possibly klustering adjacent dirty pages.
10245 10245   */
10246 10246  int
10247 10247  nfs4_putapage(vnode_t *vp, page_t *pp, u_offset_t *offp, size_t *lenp,
10248 10248      int flags, cred_t *cr)
10249 10249  {
10250 10250          u_offset_t io_off;
10251 10251          u_offset_t lbn_off;
10252 10252          u_offset_t lbn;
10253 10253          size_t io_len;
10254 10254          uint_t bsize;
10255 10255          int error;
10256 10256          rnode4_t *rp;
10257 10257  
10258 10258          ASSERT(!(vp->v_vfsp->vfs_flag & VFS_RDONLY));
10259 10259          ASSERT(pp != NULL);
10260 10260          ASSERT(cr != NULL);
10261 10261          ASSERT((flags & B_ASYNC) || nfs_zone() == VTOMI4(vp)->mi_zone);
10262 10262  
10263 10263          rp = VTOR4(vp);
10264 10264          ASSERT(rp->r_count > 0);
10265 10265          ASSERT(!IS_SHADOW(vp, rp));
10266 10266  
10267 10267          bsize = MAX(vp->v_vfsp->vfs_bsize, PAGESIZE);
10268 10268          lbn = pp->p_offset / bsize;
10269 10269          lbn_off = lbn * bsize;
10270 10270  
10271 10271          /*
10272 10272           * Find a kluster that fits in one block, or in
10273 10273           * one page if pages are bigger than blocks.  If
10274 10274           * there is less file space allocated than a whole
10275 10275           * page, we'll shorten the i/o request below.
10276 10276           */
10277 10277          pp = pvn_write_kluster(vp, pp, &io_off, &io_len, lbn_off,
10278 10278              roundup(bsize, PAGESIZE), flags);
10279 10279  
10280 10280          /*
10281 10281           * pvn_write_kluster shouldn't have returned a page with offset
10282 10282           * behind the original page we were given.  Verify that.
10283 10283           */
10284 10284          ASSERT((pp->p_offset / bsize) >= lbn);
10285 10285  
10286 10286          /*
10287 10287           * Now pp will have the list of kept dirty pages marked for
10288 10288           * write back.  It will also handle invalidation and freeing
10289 10289           * of pages that are not dirty.  Check for page length rounding
10290 10290           * problems.
10291 10291           */
10292 10292          if (io_off + io_len > lbn_off + bsize) {
10293 10293                  ASSERT((io_off + io_len) - (lbn_off + bsize) < PAGESIZE);
10294 10294                  io_len = lbn_off + bsize - io_off;
10295 10295          }
10296 10296          /*
10297 10297           * The R4MODINPROGRESS flag makes sure that nfs4_bio() sees a
10298 10298           * consistent value of r_size. R4MODINPROGRESS is set in writerp4().
10299 10299           * When R4MODINPROGRESS is set it indicates that a uiomove() is in
10300 10300           * progress and the r_size has not been made consistent with the
10301 10301           * new size of the file. When the uiomove() completes the r_size is
10302 10302           * updated and the R4MODINPROGRESS flag is cleared.
10303 10303           *
10304 10304           * The R4MODINPROGRESS flag makes sure that nfs4_bio() sees a
10305 10305           * consistent value of r_size. Without this handshaking, it is
10306 10306           * possible that nfs4_bio() picks  up the old value of r_size
10307 10307           * before the uiomove() in writerp4() completes. This will result
10308 10308           * in the write through nfs4_bio() being dropped.
10309 10309           *
10310 10310           * More precisely, there is a window between the time the uiomove()
10311 10311           * completes and the time the r_size is updated. If a VOP_PUTPAGE()
10312 10312           * operation intervenes in this window, the page will be picked up,
10313 10313           * because it is dirty (it will be unlocked, unless it was
10314 10314           * pagecreate'd). When the page is picked up as dirty, the dirty
10315 10315           * bit is reset (pvn_getdirty()). In nfs4write(), r_size is
10316 10316           * checked. This will still be the old size. Therefore the page will
10317 10317           * not be written out. When segmap_release() calls VOP_PUTPAGE(),
10318 10318           * the page will be found to be clean and the write will be dropped.
10319 10319           */
10320 10320          if (rp->r_flags & R4MODINPROGRESS) {
10321 10321                  mutex_enter(&rp->r_statelock);
10322 10322                  if ((rp->r_flags & R4MODINPROGRESS) &&
10323 10323                      rp->r_modaddr + MAXBSIZE > io_off &&
10324 10324                      rp->r_modaddr < io_off + io_len) {
10325 10325                          page_t *plist;
10326 10326                          /*
10327 10327                           * A write is in progress for this region of the file.
10328 10328                           * If we did not detect R4MODINPROGRESS here then this
10329 10329                           * path through nfs_putapage() would eventually go to
10330 10330                           * nfs4_bio() and may not write out all of the data
10331 10331                           * in the pages. We end up losing data. So we decide
10332 10332                           * to set the modified bit on each page in the page
10333 10333                           * list and mark the rnode with R4DIRTY. This write
10334 10334                           * will be restarted at some later time.
10335 10335                           */
10336 10336                          plist = pp;
10337 10337                          while (plist != NULL) {
10338 10338                                  pp = plist;
10339 10339                                  page_sub(&plist, pp);
10340 10340                                  hat_setmod(pp);
10341 10341                                  page_io_unlock(pp);
10342 10342                                  page_unlock(pp);
10343 10343                          }
10344 10344                          rp->r_flags |= R4DIRTY;
10345 10345                          mutex_exit(&rp->r_statelock);
10346 10346                          if (offp)
10347 10347                                  *offp = io_off;
10348 10348                          if (lenp)
10349 10349                                  *lenp = io_len;
10350 10350                          return (0);
10351 10351                  }
10352 10352                  mutex_exit(&rp->r_statelock);
10353 10353          }
10354 10354  
10355 10355          if (flags & B_ASYNC) {
10356 10356                  error = nfs4_async_putapage(vp, pp, io_off, io_len, flags, cr,
10357 10357                      nfs4_sync_putapage);
10358 10358          } else
10359 10359                  error = nfs4_sync_putapage(vp, pp, io_off, io_len, flags, cr);
10360 10360  
10361 10361          if (offp)
10362 10362                  *offp = io_off;
10363 10363          if (lenp)
10364 10364                  *lenp = io_len;
10365 10365          return (error);
10366 10366  }
10367 10367  
10368 10368  static int
10369 10369  nfs4_sync_putapage(vnode_t *vp, page_t *pp, u_offset_t io_off, size_t io_len,
10370 10370      int flags, cred_t *cr)
10371 10371  {
10372 10372          int error;
10373 10373          rnode4_t *rp;
10374 10374  
10375 10375          ASSERT(nfs_zone() == VTOMI4(vp)->mi_zone);
10376 10376  
10377 10377          flags |= B_WRITE;
10378 10378  
10379 10379          error = nfs4_rdwrlbn(vp, pp, io_off, io_len, flags, cr);
10380 10380  
10381 10381          rp = VTOR4(vp);
10382 10382  
10383 10383          if ((error == ENOSPC || error == EDQUOT || error == EFBIG ||
10384 10384              error == EACCES) &&
10385 10385              (flags & (B_INVAL|B_FORCE)) != (B_INVAL|B_FORCE)) {
10386 10386                  if (!(rp->r_flags & R4OUTOFSPACE)) {
10387 10387                          mutex_enter(&rp->r_statelock);
10388 10388                          rp->r_flags |= R4OUTOFSPACE;
10389 10389                          mutex_exit(&rp->r_statelock);
10390 10390                  }
10391 10391                  flags |= B_ERROR;
10392 10392                  pvn_write_done(pp, flags);
10393 10393                  /*
10394 10394                   * If this was not an async thread, then try again to
10395 10395                   * write out the pages, but this time, also destroy
10396 10396                   * them whether or not the write is successful.  This
10397 10397                   * will prevent memory from filling up with these
10398 10398                   * pages and destroying them is the only alternative
10399 10399                   * if they can't be written out.
10400 10400                   *
10401 10401                   * Don't do this if this is an async thread because
10402 10402                   * when the pages are unlocked in pvn_write_done,
10403 10403                   * some other thread could have come along, locked
10404 10404                   * them, and queued for an async thread.  It would be
10405 10405                   * possible for all of the async threads to be tied
10406 10406                   * up waiting to lock the pages again and they would
10407 10407                   * all already be locked and waiting for an async
10408 10408                   * thread to handle them.  Deadlock.
10409 10409                   */
10410 10410                  if (!(flags & B_ASYNC)) {
10411 10411                          error = nfs4_putpage(vp, io_off, io_len,
10412 10412                              B_INVAL | B_FORCE, cr, NULL);
10413 10413                  }
10414 10414          } else {
10415 10415                  if (error)
10416 10416                          flags |= B_ERROR;
10417 10417                  else if (rp->r_flags & R4OUTOFSPACE) {
10418 10418                          mutex_enter(&rp->r_statelock);
10419 10419                          rp->r_flags &= ~R4OUTOFSPACE;
10420 10420                          mutex_exit(&rp->r_statelock);
10421 10421                  }
10422 10422                  pvn_write_done(pp, flags);
10423 10423                  if (freemem < desfree)
10424 10424                          (void) nfs4_commit_vp(vp, (u_offset_t)0, 0, cr,
10425 10425                              NFS4_WRITE_NOWAIT);
10426 10426          }
10427 10427  
10428 10428          return (error);
10429 10429  }
10430 10430  
10431 10431  #ifdef DEBUG
10432 10432  int nfs4_force_open_before_mmap = 0;
10433 10433  #endif
10434 10434  
10435 10435  /* ARGSUSED */
10436 10436  static int
10437 10437  nfs4_map(vnode_t *vp, offset_t off, struct as *as, caddr_t *addrp,
10438 10438      size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cr,
10439 10439      caller_context_t *ct)
10440 10440  {
10441 10441          struct segvn_crargs vn_a;
10442 10442          int error = 0;
10443 10443          rnode4_t *rp = VTOR4(vp);
10444 10444          mntinfo4_t *mi = VTOMI4(vp);
10445 10445  
10446 10446          if (nfs_zone() != VTOMI4(vp)->mi_zone)
10447 10447                  return (EIO);
10448 10448  
10449 10449          if (vp->v_flag & VNOMAP)
10450 10450                  return (ENOSYS);
10451 10451  
10452 10452          if (off < 0 || (off + len) < 0)
10453 10453                  return (ENXIO);
10454 10454  
10455 10455          if (vp->v_type != VREG)
10456 10456                  return (ENODEV);
10457 10457  
10458 10458          /*
10459 10459           * If the file is delegated to the client don't do anything.
10460 10460           * If the file is not delegated, then validate the data cache.
10461 10461           */
10462 10462          mutex_enter(&rp->r_statev4_lock);
10463 10463          if (rp->r_deleg_type == OPEN_DELEGATE_NONE) {
10464 10464                  mutex_exit(&rp->r_statev4_lock);
10465 10465                  error = nfs4_validate_caches(vp, cr);
10466 10466                  if (error)
10467 10467                          return (error);
10468 10468          } else {
10469 10469                  mutex_exit(&rp->r_statev4_lock);
10470 10470          }
10471 10471  
10472 10472          /*
10473 10473           * Check to see if the vnode is currently marked as not cachable.
10474 10474           * This means portions of the file are locked (through VOP_FRLOCK).
10475 10475           * In this case the map request must be refused.  We use
10476 10476           * rp->r_lkserlock to avoid a race with concurrent lock requests.
10477 10477           *
10478 10478           * Atomically increment r_inmap after acquiring r_rwlock. The
10479 10479           * idea here is to acquire r_rwlock to block read/write and
10480 10480           * not to protect r_inmap. r_inmap will inform nfs4_read/write()
10481 10481           * that we are in nfs4_map(). Now, r_rwlock is acquired in order
10482 10482           * and we can prevent the deadlock that would have occurred
10483 10483           * when nfs4_addmap() would have acquired it out of order.
10484 10484           *
10485 10485           * Since we are not protecting r_inmap by any lock, we do not
10486 10486           * hold any lock when we decrement it. We atomically decrement
10487 10487           * r_inmap after we release r_lkserlock.
10488 10488           */
10489 10489  
10490 10490          if (nfs_rw_enter_sig(&rp->r_rwlock, RW_WRITER, INTR4(vp)))
10491 10491                  return (EINTR);
10492 10492          atomic_inc_uint(&rp->r_inmap);
10493 10493          nfs_rw_exit(&rp->r_rwlock);
10494 10494  
10495 10495          if (nfs_rw_enter_sig(&rp->r_lkserlock, RW_READER, INTR4(vp))) {
10496 10496                  atomic_dec_uint(&rp->r_inmap);
10497 10497                  return (EINTR);
10498 10498          }
10499 10499  
10500 10500  
10501 10501          if (vp->v_flag & VNOCACHE) {
10502 10502                  error = EAGAIN;
10503 10503                  goto done;
10504 10504          }
10505 10505  
10506 10506          /*
10507 10507           * Don't allow concurrent locks and mapping if mandatory locking is
10508 10508           * enabled.
10509 10509           */
10510 10510          if (flk_has_remote_locks(vp)) {
10511 10511                  struct vattr va;
10512 10512                  va.va_mask = AT_MODE;
10513 10513                  error = nfs4getattr(vp, &va, cr);
10514 10514                  if (error != 0)
10515 10515                          goto done;
10516 10516                  if (MANDLOCK(vp, va.va_mode)) {
10517 10517                          error = EAGAIN;
10518 10518                          goto done;
10519 10519                  }
10520 10520          }
10521 10521  
10522 10522          /*
10523 10523           * It is possible that the rnode has a lost lock request that we
10524 10524           * are still trying to recover, and that the request conflicts with
10525 10525           * this map request.
10526 10526           *
10527 10527           * An alternative approach would be for nfs4_safemap() to consider
10528 10528           * queued lock requests when deciding whether to set or clear
10529 10529           * VNOCACHE.  This would require the frlock code path to call
10530 10530           * nfs4_safemap() after enqueing a lost request.
10531 10531           */
10532 10532          if (nfs4_map_lost_lock_conflict(vp)) {
10533 10533                  error = EAGAIN;
10534 10534                  goto done;
10535 10535          }
10536 10536  
10537 10537          as_rangelock(as);
10538 10538          error = choose_addr(as, addrp, len, off, ADDR_VACALIGN, flags);
10539 10539          if (error != 0) {
10540 10540                  as_rangeunlock(as);
10541 10541                  goto done;
10542 10542          }
10543 10543  
10544 10544          if (vp->v_type == VREG) {
10545 10545                  /*
10546 10546                   * We need to retrieve the open stream
10547 10547                   */
10548 10548                  nfs4_open_stream_t      *osp = NULL;
10549 10549                  nfs4_open_owner_t       *oop = NULL;
10550 10550  
10551 10551                  oop = find_open_owner(cr, NFS4_PERM_CREATED, mi);
10552 10552                  if (oop != NULL) {
10553 10553                          /* returns with 'os_sync_lock' held */
10554 10554                          osp = find_open_stream(oop, rp);
10555 10555                          open_owner_rele(oop);
10556 10556                  }
10557 10557                  if (osp == NULL) {
10558 10558  #ifdef DEBUG
10559 10559                          if (nfs4_force_open_before_mmap) {
10560 10560                                  error = EIO;
10561 10561                                  goto done;
10562 10562                          }
10563 10563  #endif
10564 10564                          /* returns with 'os_sync_lock' held */
10565 10565                          error = open_and_get_osp(vp, cr, &osp);
10566 10566                          if (osp == NULL) {
10567 10567                                  NFS4_DEBUG(nfs4_mmap_debug, (CE_NOTE,
10568 10568                                      "nfs4_map: we tried to OPEN the file "
10569 10569                                      "but again no osp, so fail with EIO"));
10570 10570                                  goto done;
10571 10571                          }
10572 10572                  }
10573 10573  
10574 10574                  if (osp->os_failed_reopen) {
10575 10575                          mutex_exit(&osp->os_sync_lock);
10576 10576                          open_stream_rele(osp, rp);
10577 10577                          NFS4_DEBUG(nfs4_open_stream_debug, (CE_NOTE,
10578 10578                              "nfs4_map: os_failed_reopen set on "
10579 10579                              "osp %p, cr %p, rp %s", (void *)osp,
10580 10580                              (void *)cr, rnode4info(rp)));
10581 10581                          error = EIO;
10582 10582                          goto done;
10583 10583                  }
10584 10584                  mutex_exit(&osp->os_sync_lock);
10585 10585                  open_stream_rele(osp, rp);
10586 10586          }
10587 10587  
10588 10588          vn_a.vp = vp;
10589 10589          vn_a.offset = off;
10590 10590          vn_a.type = (flags & MAP_TYPE);
10591 10591          vn_a.prot = (uchar_t)prot;
10592 10592          vn_a.maxprot = (uchar_t)maxprot;
10593 10593          vn_a.flags = (flags & ~MAP_TYPE);
10594 10594          vn_a.cred = cr;
10595 10595          vn_a.amp = NULL;
10596 10596          vn_a.szc = 0;
10597 10597          vn_a.lgrp_mem_policy_flags = 0;
10598 10598  
10599 10599          error = as_map(as, *addrp, len, segvn_create, &vn_a);
10600 10600          as_rangeunlock(as);
10601 10601  
10602 10602  done:
10603 10603          nfs_rw_exit(&rp->r_lkserlock);
10604 10604          atomic_dec_uint(&rp->r_inmap);
10605 10605          return (error);
10606 10606  }
10607 10607  
10608 10608  /*
10609 10609   * We're most likely dealing with a kernel module that likes to READ
10610 10610   * and mmap without OPENing the file (ie: lookup/read/mmap), so lets
10611 10611   * officially OPEN the file to create the necessary client state
10612 10612   * for bookkeeping of os_mmap_read/write counts.
10613 10613   *
10614 10614   * Since VOP_MAP only passes in a pointer to the vnode rather than
10615 10615   * a double pointer, we can't handle the case where nfs4open_otw()
10616 10616   * returns a different vnode than the one passed into VOP_MAP (since
10617 10617   * VOP_DELMAP will not see the vnode nfs4open_otw used).  In this case,
10618 10618   * we return NULL and let nfs4_map() fail.  Note: the only case where
10619 10619   * this should happen is if the file got removed and replaced with the
10620 10620   * same name on the server (in addition to the fact that we're trying
10621 10621   * to VOP_MAP withouth VOP_OPENing the file in the first place).
10622 10622   */
10623 10623  static int
10624 10624  open_and_get_osp(vnode_t *map_vp, cred_t *cr, nfs4_open_stream_t **ospp)
10625 10625  {
10626 10626          rnode4_t                *rp, *drp;
10627 10627          vnode_t                 *dvp, *open_vp;
10628 10628          char                    file_name[MAXNAMELEN];
10629 10629          int                     just_created;
10630 10630          nfs4_open_stream_t      *osp;
10631 10631          nfs4_open_owner_t       *oop;
10632 10632          int                     error;
10633 10633  
10634 10634          *ospp = NULL;
10635 10635          open_vp = map_vp;
10636 10636  
10637 10637          rp = VTOR4(open_vp);
10638 10638          if ((error = vtodv(open_vp, &dvp, cr, TRUE)) != 0)
10639 10639                  return (error);
10640 10640          drp = VTOR4(dvp);
10641 10641  
10642 10642          if (nfs_rw_enter_sig(&drp->r_rwlock, RW_READER, INTR4(dvp))) {
10643 10643                  VN_RELE(dvp);
10644 10644                  return (EINTR);
10645 10645          }
10646 10646  
10647 10647          if ((error = vtoname(open_vp, file_name, MAXNAMELEN)) != 0) {
10648 10648                  nfs_rw_exit(&drp->r_rwlock);
10649 10649                  VN_RELE(dvp);
10650 10650                  return (error);
10651 10651          }
10652 10652  
10653 10653          mutex_enter(&rp->r_statev4_lock);
10654 10654          if (rp->created_v4) {
10655 10655                  rp->created_v4 = 0;
10656 10656                  mutex_exit(&rp->r_statev4_lock);
10657 10657  
10658 10658                  dnlc_update(dvp, file_name, open_vp);
10659 10659                  /* This is needed so we don't bump the open ref count */
10660 10660                  just_created = 1;
10661 10661          } else {
10662 10662                  mutex_exit(&rp->r_statev4_lock);
10663 10663                  just_created = 0;
10664 10664          }
10665 10665  
10666 10666          VN_HOLD(map_vp);
10667 10667  
10668 10668          error = nfs4open_otw(dvp, file_name, NULL, &open_vp, cr, 0, FREAD, 0,
10669 10669              just_created);
10670 10670          if (error) {
10671 10671                  nfs_rw_exit(&drp->r_rwlock);
10672 10672                  VN_RELE(dvp);
10673 10673                  VN_RELE(map_vp);
10674 10674                  return (error);
10675 10675          }
10676 10676  
10677 10677          nfs_rw_exit(&drp->r_rwlock);
10678 10678          VN_RELE(dvp);
10679 10679  
10680 10680          /*
10681 10681           * If nfs4open_otw() returned a different vnode then "undo"
10682 10682           * the open and return failure to the caller.
10683 10683           */
10684 10684          if (!VN_CMP(open_vp, map_vp)) {
10685 10685                  nfs4_error_t e;
10686 10686  
10687 10687                  NFS4_DEBUG(nfs4_mmap_debug, (CE_NOTE, "open_and_get_osp: "
10688 10688                      "open returned a different vnode"));
10689 10689                  /*
10690 10690                   * If there's an error, ignore it,
10691 10691                   * and let VOP_INACTIVE handle it.
10692 10692                   */
10693 10693                  (void) nfs4close_one(open_vp, NULL, cr, FREAD, NULL, &e,
10694 10694                      CLOSE_NORM, 0, 0, 0);
10695 10695                  VN_RELE(map_vp);
10696 10696                  return (EIO);
10697 10697          }
10698 10698  
10699 10699          VN_RELE(map_vp);
10700 10700  
10701 10701          oop = find_open_owner(cr, NFS4_PERM_CREATED, VTOMI4(open_vp));
10702 10702          if (!oop) {
10703 10703                  nfs4_error_t e;
10704 10704  
10705 10705                  NFS4_DEBUG(nfs4_mmap_debug, (CE_NOTE, "open_and_get_osp: "
10706 10706                      "no open owner"));
10707 10707                  /*
10708 10708                   * If there's an error, ignore it,
10709 10709                   * and let VOP_INACTIVE handle it.
10710 10710                   */
10711 10711                  (void) nfs4close_one(open_vp, NULL, cr, FREAD, NULL, &e,
10712 10712                      CLOSE_NORM, 0, 0, 0);
10713 10713                  return (EIO);
10714 10714          }
10715 10715          osp = find_open_stream(oop, rp);
10716 10716          open_owner_rele(oop);
10717 10717          *ospp = osp;
10718 10718          return (0);
10719 10719  }
10720 10720  
10721 10721  /*
10722 10722   * Please be aware that when this function is called, the address space write
10723 10723   * a_lock is held.  Do not put over the wire calls in this function.
10724 10724   */
10725 10725  /* ARGSUSED */
10726 10726  static int
10727 10727  nfs4_addmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
10728 10728      size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cr,
10729 10729      caller_context_t *ct)
10730 10730  {
10731 10731          rnode4_t                *rp;
10732 10732          int                     error = 0;
10733 10733          mntinfo4_t              *mi;
10734 10734  
10735 10735          mi = VTOMI4(vp);
10736 10736          rp = VTOR4(vp);
10737 10737  
10738 10738          if (nfs_zone() != mi->mi_zone)
10739 10739                  return (EIO);
10740 10740          if (vp->v_flag & VNOMAP)
10741 10741                  return (ENOSYS);
10742 10742  
10743 10743          /*
10744 10744           * Don't need to update the open stream first, since this
10745 10745           * mmap can't add any additional share access that isn't
10746 10746           * already contained in the open stream (for the case where we
10747 10747           * open/mmap/only update rp->r_mapcnt/server reboots/reopen doesn't
10748 10748           * take into account os_mmap_read[write] counts).
10749 10749           */
10750 10750          atomic_add_long((ulong_t *)&rp->r_mapcnt, btopr(len));
10751 10751  
10752 10752          if (vp->v_type == VREG) {
10753 10753                  /*
10754 10754                   * We need to retrieve the open stream and update the counts.
10755 10755                   * If there is no open stream here, something is wrong.
10756 10756                   */
10757 10757                  nfs4_open_stream_t      *osp = NULL;
10758 10758                  nfs4_open_owner_t       *oop = NULL;
10759 10759  
10760 10760                  oop = find_open_owner(cr, NFS4_PERM_CREATED, mi);
10761 10761                  if (oop != NULL) {
10762 10762                          /* returns with 'os_sync_lock' held */
10763 10763                          osp = find_open_stream(oop, rp);
10764 10764                          open_owner_rele(oop);
10765 10765                  }
10766 10766                  if (osp == NULL) {
10767 10767                          NFS4_DEBUG(nfs4_mmap_debug, (CE_NOTE,
10768 10768                              "nfs4_addmap: we should have an osp"
10769 10769                              "but we don't, so fail with EIO"));
10770 10770                          error = EIO;
10771 10771                          goto out;
10772 10772                  }
10773 10773  
10774 10774                  NFS4_DEBUG(nfs4_mmap_debug, (CE_NOTE, "nfs4_addmap: osp %p,"
10775 10775                      " pages %ld, prot 0x%x", (void *)osp, btopr(len), prot));
10776 10776  
10777 10777                  /*
10778 10778                   * Update the map count in the open stream.
10779 10779                   * This is necessary in the case where we
10780 10780                   * open/mmap/close/, then the server reboots, and we
10781 10781                   * attempt to reopen.  If the mmap doesn't add share
10782 10782                   * access then we send an invalid reopen with
10783 10783                   * access = NONE.
10784 10784                   *
10785 10785                   * We need to specifically check each PROT_* so a mmap
10786 10786                   * call of (PROT_WRITE | PROT_EXEC) will ensure us both
10787 10787                   * read and write access.  A simple comparison of prot
10788 10788                   * to ~PROT_WRITE to determine read access is insufficient
10789 10789                   * since prot can be |= with PROT_USER, etc.
10790 10790                   */
10791 10791  
10792 10792                  /*
10793 10793                   * Unless we're MAP_SHARED, no sense in adding os_mmap_write
10794 10794                   */
10795 10795                  if ((flags & MAP_SHARED) && (maxprot & PROT_WRITE))
10796 10796                          osp->os_mmap_write += btopr(len);
10797 10797                  if (maxprot & PROT_READ)
10798 10798                          osp->os_mmap_read += btopr(len);
10799 10799                  if (maxprot & PROT_EXEC)
10800 10800                          osp->os_mmap_read += btopr(len);
10801 10801                  /*
10802 10802                   * Ensure that os_mmap_read gets incremented, even if
10803 10803                   * maxprot were to look like PROT_NONE.
10804 10804                   */
10805 10805                  if (!(maxprot & PROT_READ) && !(maxprot & PROT_WRITE) &&
10806 10806                      !(maxprot & PROT_EXEC))
10807 10807                          osp->os_mmap_read += btopr(len);
10808 10808                  osp->os_mapcnt += btopr(len);
10809 10809                  mutex_exit(&osp->os_sync_lock);
10810 10810                  open_stream_rele(osp, rp);
10811 10811          }
10812 10812  
10813 10813  out:
10814 10814          /*
10815 10815           * If we got an error, then undo our
10816 10816           * incrementing of 'r_mapcnt'.
10817 10817           */
10818 10818  
10819 10819          if (error) {
10820 10820                  atomic_add_long((ulong_t *)&rp->r_mapcnt, -btopr(len));
10821 10821                  ASSERT(rp->r_mapcnt >= 0);
10822 10822          }
10823 10823          return (error);
10824 10824  }
10825 10825  
10826 10826  /* ARGSUSED */
10827 10827  static int
10828 10828  nfs4_cmp(vnode_t *vp1, vnode_t *vp2, caller_context_t *ct)
10829 10829  {
10830 10830  
10831 10831          return (VTOR4(vp1) == VTOR4(vp2));
10832 10832  }
10833 10833  
10834 10834  /* ARGSUSED */
10835 10835  static int
10836 10836  nfs4_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
10837 10837      offset_t offset, struct flk_callback *flk_cbp, cred_t *cr,
10838 10838      caller_context_t *ct)
10839 10839  {
10840 10840          int rc;
10841 10841          u_offset_t start, end;
10842 10842          rnode4_t *rp;
10843 10843          int error = 0, intr = INTR4(vp);
10844 10844          nfs4_error_t e;
10845 10845  
10846 10846          if (nfs_zone() != VTOMI4(vp)->mi_zone)
10847 10847                  return (EIO);
10848 10848  
10849 10849          /* check for valid cmd parameter */
10850 10850          if (cmd != F_GETLK && cmd != F_SETLK && cmd != F_SETLKW)
10851 10851                  return (EINVAL);
10852 10852  
10853 10853          /* Verify l_type. */
10854 10854          switch (bfp->l_type) {
10855 10855          case F_RDLCK:
10856 10856                  if (cmd != F_GETLK && !(flag & FREAD))
10857 10857                          return (EBADF);
10858 10858                  break;
10859 10859          case F_WRLCK:
10860 10860                  if (cmd != F_GETLK && !(flag & FWRITE))
10861 10861                          return (EBADF);
10862 10862                  break;
10863 10863          case F_UNLCK:
10864 10864                  intr = 0;
10865 10865                  break;
10866 10866  
10867 10867          default:
10868 10868                  return (EINVAL);
10869 10869          }
10870 10870  
10871 10871          /* check the validity of the lock range */
10872 10872          if (rc = flk_convert_lock_data(vp, bfp, &start, &end, offset))
10873 10873                  return (rc);
10874 10874          if (rc = flk_check_lock_data(start, end, MAXEND))
10875 10875                  return (rc);
10876 10876  
10877 10877          /*
10878 10878           * If the filesystem is mounted using local locking, pass the
10879 10879           * request off to the local locking code.
10880 10880           */
10881 10881          if (VTOMI4(vp)->mi_flags & MI4_LLOCK || vp->v_type != VREG) {
10882 10882                  if (cmd == F_SETLK || cmd == F_SETLKW) {
10883 10883                          /*
10884 10884                           * For complete safety, we should be holding
10885 10885                           * r_lkserlock.  However, we can't call
10886 10886                           * nfs4_safelock and then fs_frlock while
10887 10887                           * holding r_lkserlock, so just invoke
10888 10888                           * nfs4_safelock and expect that this will
10889 10889                           * catch enough of the cases.
10890 10890                           */
10891 10891                          if (!nfs4_safelock(vp, bfp, cr))
10892 10892                                  return (EAGAIN);
10893 10893                  }
10894 10894                  return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr, ct));
10895 10895          }
10896 10896  
10897 10897          rp = VTOR4(vp);
10898 10898  
10899 10899          /*
10900 10900           * Check whether the given lock request can proceed, given the
10901 10901           * current file mappings.
10902 10902           */
10903 10903          if (nfs_rw_enter_sig(&rp->r_lkserlock, RW_WRITER, intr))
10904 10904                  return (EINTR);
10905 10905          if (cmd == F_SETLK || cmd == F_SETLKW) {
10906 10906                  if (!nfs4_safelock(vp, bfp, cr)) {
10907 10907                          rc = EAGAIN;
10908 10908                          goto done;
10909 10909                  }
10910 10910          }
10911 10911  
10912 10912          /*
10913 10913           * Flush the cache after waiting for async I/O to finish.  For new
10914 10914           * locks, this is so that the process gets the latest bits from the
10915 10915           * server.  For unlocks, this is so that other clients see the
10916 10916           * latest bits once the file has been unlocked.  If currently dirty
10917 10917           * pages can't be flushed, then don't allow a lock to be set.  But
10918 10918           * allow unlocks to succeed, to avoid having orphan locks on the
10919 10919           * server.
10920 10920           */
10921 10921          if (cmd != F_GETLK) {
10922 10922                  mutex_enter(&rp->r_statelock);
10923 10923                  while (rp->r_count > 0) {
10924 10924                          if (intr) {
10925 10925                                  klwp_t *lwp = ttolwp(curthread);
10926 10926  
10927 10927                                  if (lwp != NULL)
10928 10928                                          lwp->lwp_nostop++;
10929 10929                                  if (cv_wait_sig(&rp->r_cv,
10930 10930                                      &rp->r_statelock) == 0) {
10931 10931                                          if (lwp != NULL)
10932 10932                                                  lwp->lwp_nostop--;
10933 10933                                          rc = EINTR;
10934 10934                                          break;
10935 10935                                  }
10936 10936                                  if (lwp != NULL)
10937 10937                                          lwp->lwp_nostop--;
10938 10938                                  } else
10939 10939                                          cv_wait(&rp->r_cv, &rp->r_statelock);
10940 10940                  }
10941 10941                  mutex_exit(&rp->r_statelock);
10942 10942                  if (rc != 0)
10943 10943                          goto done;
10944 10944                  error = nfs4_putpage(vp, (offset_t)0, 0, B_INVAL, cr, ct);
10945 10945                  if (error) {
10946 10946                          if (error == ENOSPC || error == EDQUOT) {
10947 10947                                  mutex_enter(&rp->r_statelock);
10948 10948                                  if (!rp->r_error)
10949 10949                                          rp->r_error = error;
10950 10950                                  mutex_exit(&rp->r_statelock);
10951 10951                          }
10952 10952                          if (bfp->l_type != F_UNLCK) {
10953 10953                                  rc = ENOLCK;
10954 10954                                  goto done;
10955 10955                          }
10956 10956                  }
10957 10957          }
10958 10958  
10959 10959          /*
10960 10960           * Call the lock manager to do the real work of contacting
10961 10961           * the server and obtaining the lock.
10962 10962           */
10963 10963          nfs4frlock(NFS4_LCK_CTYPE_NORM, vp, cmd, bfp, flag, offset,
10964 10964              cr, &e, NULL, NULL);
10965 10965          rc = e.error;
10966 10966  
10967 10967          if (rc == 0)
10968 10968                  nfs4_lockcompletion(vp, cmd);
10969 10969  
10970 10970  done:
10971 10971          nfs_rw_exit(&rp->r_lkserlock);
10972 10972  
10973 10973          return (rc);
10974 10974  }
10975 10975  
10976 10976  /*
10977 10977   * Free storage space associated with the specified vnode.  The portion
10978 10978   * to be freed is specified by bfp->l_start and bfp->l_len (already
10979 10979   * normalized to a "whence" of 0).
10980 10980   *
10981 10981   * This is an experimental facility whose continued existence is not
10982 10982   * guaranteed.  Currently, we only support the special case
10983 10983   * of l_len == 0, meaning free to end of file.
10984 10984   */
10985 10985  /* ARGSUSED */
10986 10986  static int
10987 10987  nfs4_space(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
10988 10988      offset_t offset, cred_t *cr, caller_context_t *ct)
10989 10989  {
10990 10990          int error;
10991 10991  
10992 10992          if (nfs_zone() != VTOMI4(vp)->mi_zone)
10993 10993                  return (EIO);
10994 10994          ASSERT(vp->v_type == VREG);
10995 10995          if (cmd != F_FREESP)
10996 10996                  return (EINVAL);
10997 10997  
10998 10998          error = convoff(vp, bfp, 0, offset);
10999 10999          if (!error) {
11000 11000                  ASSERT(bfp->l_start >= 0);
11001 11001                  if (bfp->l_len == 0) {
11002 11002                          struct vattr va;
11003 11003  
11004 11004                          va.va_mask = AT_SIZE;
11005 11005                          va.va_size = bfp->l_start;
11006 11006                          error = nfs4setattr(vp, &va, 0, cr, NULL);
11007 11007  
11008 11008                          if (error == 0) {
11009 11009                                  if (bfp->l_start == 0) {
11010 11010                                          vnevent_truncate(vp, ct);
11011 11011                                  } else {
11012 11012                                          vnevent_resize(vp, ct);
11013 11013                                  }
11014 11014                          }
11015 11015                  } else
11016 11016                          error = EINVAL;
11017 11017          }
11018 11018  
11019 11019          return (error);
11020 11020  }
11021 11021  
11022 11022  /* ARGSUSED */
11023 11023  int
11024 11024  nfs4_realvp(vnode_t *vp, vnode_t **vpp, caller_context_t *ct)
11025 11025  {
11026 11026          rnode4_t *rp;
11027 11027          rp = VTOR4(vp);
11028 11028  
11029 11029          if (vp->v_type == VREG && IS_SHADOW(vp, rp)) {
11030 11030                  vp = RTOV4(rp);
11031 11031          }
11032 11032          *vpp = vp;
11033 11033          return (0);
11034 11034  }
11035 11035  
11036 11036  /*
11037 11037   * Setup and add an address space callback to do the work of the delmap call.
11038 11038   * The callback will (and must be) deleted in the actual callback function.
11039 11039   *
11040 11040   * This is done in order to take care of the problem that we have with holding
11041 11041   * the address space's a_lock for a long period of time (e.g. if the NFS server
11042 11042   * is down).  Callbacks will be executed in the address space code while the
11043 11043   * a_lock is not held.  Holding the address space's a_lock causes things such
11044 11044   * as ps and fork to hang because they are trying to acquire this lock as well.
11045 11045   */
11046 11046  /* ARGSUSED */
11047 11047  static int
11048 11048  nfs4_delmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
11049 11049      size_t len, uint_t prot, uint_t maxprot, uint_t flags, cred_t *cr,
11050 11050      caller_context_t *ct)
11051 11051  {
11052 11052          int                     caller_found;
11053 11053          int                     error;
11054 11054          rnode4_t                *rp;
11055 11055          nfs4_delmap_args_t      *dmapp;
11056 11056          nfs4_delmapcall_t       *delmap_call;
11057 11057  
11058 11058          if (vp->v_flag & VNOMAP)
11059 11059                  return (ENOSYS);
11060 11060  
11061 11061          /*
11062 11062           * A process may not change zones if it has NFS pages mmap'ed
11063 11063           * in, so we can't legitimately get here from the wrong zone.
11064 11064           */
11065 11065          ASSERT(nfs_zone() == VTOMI4(vp)->mi_zone);
11066 11066  
11067 11067          rp = VTOR4(vp);
11068 11068  
11069 11069          /*
11070 11070           * The way that the address space of this process deletes its mapping
11071 11071           * of this file is via the following call chains:
11072 11072           * - as_free()->SEGOP_UNMAP()/segvn_unmap()->VOP_DELMAP()/nfs4_delmap()
11073 11073           * - as_unmap()->SEGOP_UNMAP()/segvn_unmap()->VOP_DELMAP()/nfs4_delmap()
11074 11074           *
11075 11075           * With the use of address space callbacks we are allowed to drop the
11076 11076           * address space lock, a_lock, while executing the NFS operations that
11077 11077           * need to go over the wire.  Returning EAGAIN to the caller of this
11078 11078           * function is what drives the execution of the callback that we add
11079 11079           * below.  The callback will be executed by the address space code
11080 11080           * after dropping the a_lock.  When the callback is finished, since
11081 11081           * we dropped the a_lock, it must be re-acquired and segvn_unmap()
11082 11082           * is called again on the same segment to finish the rest of the work
11083 11083           * that needs to happen during unmapping.
11084 11084           *
11085 11085           * This action of calling back into the segment driver causes
11086 11086           * nfs4_delmap() to get called again, but since the callback was
11087 11087           * already executed at this point, it already did the work and there
11088 11088           * is nothing left for us to do.
11089 11089           *
11090 11090           * To Summarize:
11091 11091           * - The first time nfs4_delmap is called by the current thread is when
11092 11092           * we add the caller associated with this delmap to the delmap caller
11093 11093           * list, add the callback, and return EAGAIN.
11094 11094           * - The second time in this call chain when nfs4_delmap is called we
11095 11095           * will find this caller in the delmap caller list and realize there
11096 11096           * is no more work to do thus removing this caller from the list and
11097 11097           * returning the error that was set in the callback execution.
11098 11098           */
11099 11099          caller_found = nfs4_find_and_delete_delmapcall(rp, &error);
11100 11100          if (caller_found) {
11101 11101                  /*
11102 11102                   * 'error' is from the actual delmap operations.  To avoid
11103 11103                   * hangs, we need to handle the return of EAGAIN differently
11104 11104                   * since this is what drives the callback execution.
11105 11105                   * In this case, we don't want to return EAGAIN and do the
11106 11106                   * callback execution because there are none to execute.
11107 11107                   */
11108 11108                  if (error == EAGAIN)
11109 11109                          return (0);
11110 11110                  else
11111 11111                          return (error);
11112 11112          }
11113 11113  
11114 11114          /* current caller was not in the list */
11115 11115          delmap_call = nfs4_init_delmapcall();
11116 11116  
11117 11117          mutex_enter(&rp->r_statelock);
11118 11118          list_insert_tail(&rp->r_indelmap, delmap_call);
11119 11119          mutex_exit(&rp->r_statelock);
11120 11120  
11121 11121          dmapp = kmem_alloc(sizeof (nfs4_delmap_args_t), KM_SLEEP);
11122 11122  
11123 11123          dmapp->vp = vp;
11124 11124          dmapp->off = off;
11125 11125          dmapp->addr = addr;
11126 11126          dmapp->len = len;
11127 11127          dmapp->prot = prot;
11128 11128          dmapp->maxprot = maxprot;
11129 11129          dmapp->flags = flags;
11130 11130          dmapp->cr = cr;
11131 11131          dmapp->caller = delmap_call;
11132 11132  
11133 11133          error = as_add_callback(as, nfs4_delmap_callback, dmapp,
11134 11134              AS_UNMAP_EVENT, addr, len, KM_SLEEP);
11135 11135  
11136 11136          return (error ? error : EAGAIN);
11137 11137  }
11138 11138  
11139 11139  static nfs4_delmapcall_t *
11140 11140  nfs4_init_delmapcall()
11141 11141  {
11142 11142          nfs4_delmapcall_t       *delmap_call;
11143 11143  
11144 11144          delmap_call = kmem_alloc(sizeof (nfs4_delmapcall_t), KM_SLEEP);
11145 11145          delmap_call->call_id = curthread;
11146 11146          delmap_call->error = 0;
11147 11147  
11148 11148          return (delmap_call);
11149 11149  }
11150 11150  
11151 11151  static void
11152 11152  nfs4_free_delmapcall(nfs4_delmapcall_t *delmap_call)
11153 11153  {
11154 11154          kmem_free(delmap_call, sizeof (nfs4_delmapcall_t));
11155 11155  }
11156 11156  
11157 11157  /*
11158 11158   * Searches for the current delmap caller (based on curthread) in the list of
11159 11159   * callers.  If it is found, we remove it and free the delmap caller.
11160 11160   * Returns:
11161 11161   *      0 if the caller wasn't found
11162 11162   *      1 if the caller was found, removed and freed.  *errp will be set
11163 11163   *      to what the result of the delmap was.
11164 11164   */
11165 11165  static int
11166 11166  nfs4_find_and_delete_delmapcall(rnode4_t *rp, int *errp)
11167 11167  {
11168 11168          nfs4_delmapcall_t       *delmap_call;
11169 11169  
11170 11170          /*
11171 11171           * If the list doesn't exist yet, we create it and return
11172 11172           * that the caller wasn't found.  No list = no callers.
11173 11173           */
11174 11174          mutex_enter(&rp->r_statelock);
11175 11175          if (!(rp->r_flags & R4DELMAPLIST)) {
11176 11176                  /* The list does not exist */
11177 11177                  list_create(&rp->r_indelmap, sizeof (nfs4_delmapcall_t),
11178 11178                      offsetof(nfs4_delmapcall_t, call_node));
11179 11179                  rp->r_flags |= R4DELMAPLIST;
11180 11180                  mutex_exit(&rp->r_statelock);
11181 11181                  return (0);
11182 11182          } else {
11183 11183                  /* The list exists so search it */
11184 11184                  for (delmap_call = list_head(&rp->r_indelmap);
11185 11185                      delmap_call != NULL;
11186 11186                      delmap_call = list_next(&rp->r_indelmap, delmap_call)) {
11187 11187                          if (delmap_call->call_id == curthread) {
11188 11188                                  /* current caller is in the list */
11189 11189                                  *errp = delmap_call->error;
11190 11190                                  list_remove(&rp->r_indelmap, delmap_call);
11191 11191                                  mutex_exit(&rp->r_statelock);
11192 11192                                  nfs4_free_delmapcall(delmap_call);
11193 11193                                  return (1);
11194 11194                          }
11195 11195                  }
11196 11196          }
11197 11197          mutex_exit(&rp->r_statelock);
11198 11198          return (0);
11199 11199  }
11200 11200  
11201 11201  /*
11202 11202   * Remove some pages from an mmap'd vnode.  Just update the
11203 11203   * count of pages.  If doing close-to-open, then flush and
11204 11204   * commit all of the pages associated with this file.
11205 11205   * Otherwise, start an asynchronous page flush to write out
11206 11206   * any dirty pages.  This will also associate a credential
11207 11207   * with the rnode which can be used to write the pages.
11208 11208   */
11209 11209  /* ARGSUSED */
11210 11210  static void
11211 11211  nfs4_delmap_callback(struct as *as, void *arg, uint_t event)
11212 11212  {
11213 11213          nfs4_error_t            e = { 0, NFS4_OK, RPC_SUCCESS };
11214 11214          rnode4_t                *rp;
11215 11215          mntinfo4_t              *mi;
11216 11216          nfs4_delmap_args_t      *dmapp = (nfs4_delmap_args_t *)arg;
11217 11217  
11218 11218          rp = VTOR4(dmapp->vp);
11219 11219          mi = VTOMI4(dmapp->vp);
11220 11220  
11221 11221          atomic_add_long((ulong_t *)&rp->r_mapcnt, -btopr(dmapp->len));
11222 11222          ASSERT(rp->r_mapcnt >= 0);
11223 11223  
11224 11224          /*
11225 11225           * Initiate a page flush and potential commit if there are
11226 11226           * pages, the file system was not mounted readonly, the segment
11227 11227           * was mapped shared, and the pages themselves were writeable.
11228 11228           */
11229 11229          if (nfs4_has_pages(dmapp->vp) &&
11230 11230              !(dmapp->vp->v_vfsp->vfs_flag & VFS_RDONLY) &&
11231 11231              dmapp->flags == MAP_SHARED && (dmapp->maxprot & PROT_WRITE)) {
11232 11232                  mutex_enter(&rp->r_statelock);
11233 11233                  rp->r_flags |= R4DIRTY;
11234 11234                  mutex_exit(&rp->r_statelock);
11235 11235                  e.error = nfs4_putpage_commit(dmapp->vp, dmapp->off,
11236 11236                      dmapp->len, dmapp->cr);
11237 11237                  if (!e.error) {
11238 11238                          mutex_enter(&rp->r_statelock);
11239 11239                          e.error = rp->r_error;
11240 11240                          rp->r_error = 0;
11241 11241                          mutex_exit(&rp->r_statelock);
11242 11242                  }
11243 11243          } else
11244 11244                  e.error = 0;
11245 11245  
11246 11246          if ((rp->r_flags & R4DIRECTIO) || (mi->mi_flags & MI4_DIRECTIO))
11247 11247                  (void) nfs4_putpage(dmapp->vp, dmapp->off, dmapp->len,
11248 11248                      B_INVAL, dmapp->cr, NULL);
11249 11249  
11250 11250          if (e.error) {
11251 11251                  e.stat = puterrno4(e.error);
11252 11252                  nfs4_queue_fact(RF_DELMAP_CB_ERR, mi, e.stat, 0,
11253 11253                      OP_COMMIT, FALSE, NULL, 0, dmapp->vp);
11254 11254                  dmapp->caller->error = e.error;
11255 11255          }
11256 11256  
11257 11257          /* Check to see if we need to close the file */
11258 11258  
11259 11259          if (dmapp->vp->v_type == VREG) {
11260 11260                  nfs4close_one(dmapp->vp, NULL, dmapp->cr, 0, NULL, &e,
11261 11261                      CLOSE_DELMAP, dmapp->len, dmapp->maxprot, dmapp->flags);
11262 11262  
11263 11263                  if (e.error != 0 || e.stat != NFS4_OK) {
11264 11264                          /*
11265 11265                           * Since it is possible that e.error == 0 and
11266 11266                           * e.stat != NFS4_OK (and vice versa),
11267 11267                           * we do the proper checking in order to get both
11268 11268                           * e.error and e.stat reporting the correct info.
11269 11269                           */
11270 11270                          if (e.stat == NFS4_OK)
11271 11271                                  e.stat = puterrno4(e.error);
11272 11272                          if (e.error == 0)
11273 11273                                  e.error = geterrno4(e.stat);
11274 11274  
11275 11275                          nfs4_queue_fact(RF_DELMAP_CB_ERR, mi, e.stat, 0,
11276 11276                              OP_CLOSE, FALSE, NULL, 0, dmapp->vp);
11277 11277                          dmapp->caller->error = e.error;
11278 11278                  }
11279 11279          }
11280 11280  
11281 11281          (void) as_delete_callback(as, arg);
11282 11282          kmem_free(dmapp, sizeof (nfs4_delmap_args_t));
11283 11283  }
11284 11284  
11285 11285  
11286 11286  static uint_t
11287 11287  fattr4_maxfilesize_to_bits(uint64_t ll)
11288 11288  {
11289 11289          uint_t l = 1;
11290 11290  
11291 11291          if (ll == 0) {
11292 11292                  return (0);
11293 11293          }
11294 11294  
11295 11295          if (ll & 0xffffffff00000000) {
11296 11296                  l += 32; ll >>= 32;
11297 11297          }
11298 11298          if (ll & 0xffff0000) {
11299 11299                  l += 16; ll >>= 16;
11300 11300          }
11301 11301          if (ll & 0xff00) {
11302 11302                  l += 8; ll >>= 8;
11303 11303          }
11304 11304          if (ll & 0xf0) {
11305 11305                  l += 4; ll >>= 4;
11306 11306          }
11307 11307          if (ll & 0xc) {
11308 11308                  l += 2; ll >>= 2;
11309 11309          }
11310 11310          if (ll & 0x2) {
11311 11311                  l += 1;
11312 11312          }
11313 11313          return (l);
11314 11314  }
11315 11315  
11316 11316  static int
11317 11317  nfs4_have_xattrs(vnode_t *vp, ulong_t *valp, cred_t *cr)
11318 11318  {
11319 11319          vnode_t *avp = NULL;
11320 11320          int error;
11321 11321  
11322 11322          if ((error = nfs4lookup_xattr(vp, "", &avp,
11323 11323              LOOKUP_XATTR, cr)) == 0)
11324 11324                  error = do_xattr_exists_check(avp, valp, cr);
11325 11325          if (avp)
11326 11326                  VN_RELE(avp);
11327 11327  
11328 11328          return (error);
11329 11329  }
11330 11330  
11331 11331  /* ARGSUSED */
11332 11332  int
11333 11333  nfs4_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
11334 11334      caller_context_t *ct)
11335 11335  {
11336 11336          int error;
11337 11337          hrtime_t t;
11338 11338          rnode4_t *rp;
11339 11339          nfs4_ga_res_t gar;
11340 11340          nfs4_ga_ext_res_t ger;
11341 11341  
11342 11342          gar.n4g_ext_res = &ger;
11343 11343  
11344 11344          if (nfs_zone() != VTOMI4(vp)->mi_zone)
11345 11345                  return (EIO);
11346 11346          if (cmd == _PC_PATH_MAX || cmd == _PC_SYMLINK_MAX) {
11347 11347                  *valp = MAXPATHLEN;
11348 11348                  return (0);
11349 11349          }
11350 11350          if (cmd == _PC_ACL_ENABLED) {
11351 11351                  *valp = _ACL_ACE_ENABLED;
11352 11352                  return (0);
11353 11353          }
11354 11354  
11355 11355          rp = VTOR4(vp);
11356 11356          if (cmd == _PC_XATTR_EXISTS) {
11357 11357                  /*
11358 11358                   * The existence of the xattr directory is not sufficient
11359 11359                   * for determining whether generic user attributes exists.
11360 11360                   * The attribute directory could only be a transient directory
11361 11361                   * used for Solaris sysattr support.  Do a small readdir
11362 11362                   * to verify if the only entries are sysattrs or not.
11363 11363                   *
11364 11364                   * pc4_xattr_valid can be only be trusted when r_xattr_dir
11365 11365                   * is NULL.  Once the xadir vp exists, we can create xattrs,
11366 11366                   * and we don't have any way to update the "base" object's
11367 11367                   * pc4_xattr_exists from the xattr or xadir.  Maybe FEM
11368 11368                   * could help out.
11369 11369                   */
11370 11370                  if (ATTRCACHE4_VALID(vp) && rp->r_pathconf.pc4_xattr_valid &&
11371 11371                      rp->r_xattr_dir == NULL) {
11372 11372                          return (nfs4_have_xattrs(vp, valp, cr));
11373 11373                  }
11374 11374          } else {  /* OLD CODE */
11375 11375                  if (ATTRCACHE4_VALID(vp)) {
11376 11376                          mutex_enter(&rp->r_statelock);
11377 11377                          if (rp->r_pathconf.pc4_cache_valid) {
11378 11378                                  error = 0;
11379 11379                                  switch (cmd) {
11380 11380                                  case _PC_FILESIZEBITS:
11381 11381                                          *valp =
11382 11382                                              rp->r_pathconf.pc4_filesizebits;
11383 11383                                          break;
11384 11384                                  case _PC_LINK_MAX:
11385 11385                                          *valp =
11386 11386                                              rp->r_pathconf.pc4_link_max;
11387 11387                                          break;
11388 11388                                  case _PC_NAME_MAX:
11389 11389                                          *valp =
11390 11390                                              rp->r_pathconf.pc4_name_max;
11391 11391                                          break;
11392 11392                                  case _PC_CHOWN_RESTRICTED:
11393 11393                                          *valp =
11394 11394                                              rp->r_pathconf.pc4_chown_restricted;
11395 11395                                          break;
11396 11396                                  case _PC_NO_TRUNC:
11397 11397                                          *valp =
11398 11398                                              rp->r_pathconf.pc4_no_trunc;
11399 11399                                          break;
11400 11400                                  default:
11401 11401                                          error = EINVAL;
11402 11402                                          break;
11403 11403                                  }
11404 11404                                  mutex_exit(&rp->r_statelock);
11405 11405  #ifdef DEBUG
11406 11406                                  nfs4_pathconf_cache_hits++;
11407 11407  #endif
11408 11408                                  return (error);
11409 11409                          }
11410 11410                          mutex_exit(&rp->r_statelock);
11411 11411                  }
11412 11412          }
11413 11413  #ifdef DEBUG
11414 11414          nfs4_pathconf_cache_misses++;
11415 11415  #endif
11416 11416  
11417 11417          t = gethrtime();
11418 11418  
11419 11419          error = nfs4_attr_otw(vp, TAG_PATHCONF, &gar, NFS4_PATHCONF_MASK, cr);
11420 11420  
11421 11421          if (error) {
11422 11422                  mutex_enter(&rp->r_statelock);
11423 11423                  rp->r_pathconf.pc4_cache_valid = FALSE;
11424 11424                  rp->r_pathconf.pc4_xattr_valid = FALSE;
11425 11425                  mutex_exit(&rp->r_statelock);
11426 11426                  return (error);
11427 11427          }
11428 11428  
11429 11429          /* interpret the max filesize */
11430 11430          gar.n4g_ext_res->n4g_pc4.pc4_filesizebits =
11431 11431              fattr4_maxfilesize_to_bits(gar.n4g_ext_res->n4g_maxfilesize);
11432 11432  
11433 11433          /* Store the attributes we just received */
11434 11434          nfs4_attr_cache(vp, &gar, t, cr, TRUE, NULL);
11435 11435  
11436 11436          switch (cmd) {
11437 11437          case _PC_FILESIZEBITS:
11438 11438                  *valp = gar.n4g_ext_res->n4g_pc4.pc4_filesizebits;
11439 11439                  break;
11440 11440          case _PC_LINK_MAX:
11441 11441                  *valp = gar.n4g_ext_res->n4g_pc4.pc4_link_max;
11442 11442                  break;
11443 11443          case _PC_NAME_MAX:
11444 11444                  *valp = gar.n4g_ext_res->n4g_pc4.pc4_name_max;
11445 11445                  break;
11446 11446          case _PC_CHOWN_RESTRICTED:
11447 11447                  *valp = gar.n4g_ext_res->n4g_pc4.pc4_chown_restricted;
11448 11448                  break;
11449 11449          case _PC_NO_TRUNC:
11450 11450                  *valp = gar.n4g_ext_res->n4g_pc4.pc4_no_trunc;
11451 11451                  break;
11452 11452          case _PC_XATTR_EXISTS:
11453 11453                  if (gar.n4g_ext_res->n4g_pc4.pc4_xattr_exists) {
11454 11454                          if (error = nfs4_have_xattrs(vp, valp, cr))
11455 11455                                  return (error);
11456 11456                  }
11457 11457                  break;
11458 11458          default:
11459 11459                  return (EINVAL);
11460 11460          }
11461 11461  
11462 11462          return (0);
11463 11463  }
11464 11464  
11465 11465  /*
11466 11466   * Called by async thread to do synchronous pageio. Do the i/o, wait
11467 11467   * for it to complete, and cleanup the page list when done.
11468 11468   */
11469 11469  static int
11470 11470  nfs4_sync_pageio(vnode_t *vp, page_t *pp, u_offset_t io_off, size_t io_len,
11471 11471      int flags, cred_t *cr)
11472 11472  {
11473 11473          int error;
11474 11474  
11475 11475          ASSERT(nfs_zone() == VTOMI4(vp)->mi_zone);
11476 11476  
11477 11477          error = nfs4_rdwrlbn(vp, pp, io_off, io_len, flags, cr);
11478 11478          if (flags & B_READ)
11479 11479                  pvn_read_done(pp, (error ? B_ERROR : 0) | flags);
11480 11480          else
11481 11481                  pvn_write_done(pp, (error ? B_ERROR : 0) | flags);
11482 11482          return (error);
11483 11483  }
11484 11484  
11485 11485  /* ARGSUSED */
11486 11486  static int
11487 11487  nfs4_pageio(vnode_t *vp, page_t *pp, u_offset_t io_off, size_t io_len,
11488 11488      int flags, cred_t *cr, caller_context_t *ct)
11489 11489  {
11490 11490          int error;
11491 11491          rnode4_t *rp;
11492 11492  
11493 11493          if (!(flags & B_ASYNC) && nfs_zone() != VTOMI4(vp)->mi_zone)
11494 11494                  return (EIO);
11495 11495  
11496 11496          if (pp == NULL)
11497 11497                  return (EINVAL);
11498 11498  
11499 11499          rp = VTOR4(vp);
11500 11500          mutex_enter(&rp->r_statelock);
11501 11501          rp->r_count++;
11502 11502          mutex_exit(&rp->r_statelock);
11503 11503  
11504 11504          if (flags & B_ASYNC) {
11505 11505                  error = nfs4_async_pageio(vp, pp, io_off, io_len, flags, cr,
11506 11506                      nfs4_sync_pageio);
11507 11507          } else
11508 11508                  error = nfs4_rdwrlbn(vp, pp, io_off, io_len, flags, cr);
11509 11509          mutex_enter(&rp->r_statelock);
11510 11510          rp->r_count--;
11511 11511          cv_broadcast(&rp->r_cv);
11512 11512          mutex_exit(&rp->r_statelock);
11513 11513          return (error);
11514 11514  }
11515 11515  
11516 11516  /* ARGSUSED */
11517 11517  static void
11518 11518  nfs4_dispose(vnode_t *vp, page_t *pp, int fl, int dn, cred_t *cr,
11519 11519      caller_context_t *ct)
11520 11520  {
11521 11521          int error;
11522 11522          rnode4_t *rp;
11523 11523          page_t *plist;
11524 11524          page_t *pptr;
11525 11525          offset3 offset;
11526 11526          count3 len;
11527 11527          k_sigset_t smask;
11528 11528  
11529 11529          /*
11530 11530           * We should get called with fl equal to either B_FREE or
11531 11531           * B_INVAL.  Any other value is illegal.
11532 11532           *
11533 11533           * The page that we are either supposed to free or destroy
11534 11534           * should be exclusive locked and its io lock should not
11535 11535           * be held.
11536 11536           */
11537 11537          ASSERT(fl == B_FREE || fl == B_INVAL);
11538 11538          ASSERT((PAGE_EXCL(pp) && !page_iolock_assert(pp)) || panicstr);
11539 11539  
11540 11540          rp = VTOR4(vp);
11541 11541  
11542 11542          /*
11543 11543           * If the page doesn't need to be committed or we shouldn't
11544 11544           * even bother attempting to commit it, then just make sure
11545 11545           * that the p_fsdata byte is clear and then either free or
11546 11546           * destroy the page as appropriate.
11547 11547           */
11548 11548          if (pp->p_fsdata == C_NOCOMMIT || (rp->r_flags & R4STALE)) {
11549 11549                  pp->p_fsdata = C_NOCOMMIT;
11550 11550                  if (fl == B_FREE)
11551 11551                          page_free(pp, dn);
11552 11552                  else
11553 11553                          page_destroy(pp, dn);
11554 11554                  return;
11555 11555          }
11556 11556  
11557 11557          /*
11558 11558           * If there is a page invalidation operation going on, then
11559 11559           * if this is one of the pages being destroyed, then just
11560 11560           * clear the p_fsdata byte and then either free or destroy
11561 11561           * the page as appropriate.
11562 11562           */
11563 11563          mutex_enter(&rp->r_statelock);
11564 11564          if ((rp->r_flags & R4TRUNCATE) && pp->p_offset >= rp->r_truncaddr) {
11565 11565                  mutex_exit(&rp->r_statelock);
11566 11566                  pp->p_fsdata = C_NOCOMMIT;
11567 11567                  if (fl == B_FREE)
11568 11568                          page_free(pp, dn);
11569 11569                  else
11570 11570                          page_destroy(pp, dn);
11571 11571                  return;
11572 11572          }
11573 11573  
11574 11574          /*
11575 11575           * If we are freeing this page and someone else is already
11576 11576           * waiting to do a commit, then just unlock the page and
11577 11577           * return.  That other thread will take care of commiting
11578 11578           * this page.  The page can be freed sometime after the
11579 11579           * commit has finished.  Otherwise, if the page is marked
11580 11580           * as delay commit, then we may be getting called from
11581 11581           * pvn_write_done, one page at a time.   This could result
11582 11582           * in one commit per page, so we end up doing lots of small
11583 11583           * commits instead of fewer larger commits.  This is bad,
11584 11584           * we want do as few commits as possible.
11585 11585           */
11586 11586          if (fl == B_FREE) {
11587 11587                  if (rp->r_flags & R4COMMITWAIT) {
11588 11588                          page_unlock(pp);
11589 11589                          mutex_exit(&rp->r_statelock);
11590 11590                          return;
11591 11591                  }
11592 11592                  if (pp->p_fsdata == C_DELAYCOMMIT) {
11593 11593                          pp->p_fsdata = C_COMMIT;
11594 11594                          page_unlock(pp);
11595 11595                          mutex_exit(&rp->r_statelock);
11596 11596                          return;
11597 11597                  }
11598 11598          }
11599 11599  
11600 11600          /*
11601 11601           * Check to see if there is a signal which would prevent an
11602 11602           * attempt to commit the pages from being successful.  If so,
11603 11603           * then don't bother with all of the work to gather pages and
11604 11604           * generate the unsuccessful RPC.  Just return from here and
11605 11605           * let the page be committed at some later time.
11606 11606           */
11607 11607          sigintr(&smask, VTOMI4(vp)->mi_flags & MI4_INT);
11608 11608          if (ttolwp(curthread) != NULL && ISSIG(curthread, JUSTLOOKING)) {
11609 11609                  sigunintr(&smask);
11610 11610                  page_unlock(pp);
11611 11611                  mutex_exit(&rp->r_statelock);
11612 11612                  return;
11613 11613          }
11614 11614          sigunintr(&smask);
11615 11615  
11616 11616          /*
11617 11617           * We are starting to need to commit pages, so let's try
11618 11618           * to commit as many as possible at once to reduce the
11619 11619           * overhead.
11620 11620           *
11621 11621           * Set the `commit inprogress' state bit.  We must
11622 11622           * first wait until any current one finishes.  Then
11623 11623           * we initialize the c_pages list with this page.
11624 11624           */
11625 11625          while (rp->r_flags & R4COMMIT) {
11626 11626                  rp->r_flags |= R4COMMITWAIT;
11627 11627                  cv_wait(&rp->r_commit.c_cv, &rp->r_statelock);
11628 11628                  rp->r_flags &= ~R4COMMITWAIT;
11629 11629          }
11630 11630          rp->r_flags |= R4COMMIT;
11631 11631          mutex_exit(&rp->r_statelock);
11632 11632          ASSERT(rp->r_commit.c_pages == NULL);
11633 11633          rp->r_commit.c_pages = pp;
11634 11634          rp->r_commit.c_commbase = (offset3)pp->p_offset;
11635 11635          rp->r_commit.c_commlen = PAGESIZE;
11636 11636  
11637 11637          /*
11638 11638           * Gather together all other pages which can be committed.
11639 11639           * They will all be chained off r_commit.c_pages.
11640 11640           */
11641 11641          nfs4_get_commit(vp);
11642 11642  
11643 11643          /*
11644 11644           * Clear the `commit inprogress' status and disconnect
11645 11645           * the list of pages to be committed from the rnode.
11646 11646           * At this same time, we also save the starting offset
11647 11647           * and length of data to be committed on the server.
11648 11648           */
11649 11649          plist = rp->r_commit.c_pages;
11650 11650          rp->r_commit.c_pages = NULL;
11651 11651          offset = rp->r_commit.c_commbase;
11652 11652          len = rp->r_commit.c_commlen;
11653 11653          mutex_enter(&rp->r_statelock);
11654 11654          rp->r_flags &= ~R4COMMIT;
11655 11655          cv_broadcast(&rp->r_commit.c_cv);
11656 11656          mutex_exit(&rp->r_statelock);
11657 11657  
11658 11658          if (curproc == proc_pageout || curproc == proc_fsflush ||
11659 11659              nfs_zone() != VTOMI4(vp)->mi_zone) {
11660 11660                  nfs4_async_commit(vp, plist, offset, len,
11661 11661                      cr, do_nfs4_async_commit);
11662 11662                  return;
11663 11663          }
11664 11664  
11665 11665          /*
11666 11666           * Actually generate the COMMIT op over the wire operation.
11667 11667           */
11668 11668          error = nfs4_commit(vp, (offset4)offset, (count4)len, cr);
11669 11669  
11670 11670          /*
11671 11671           * If we got an error during the commit, just unlock all
11672 11672           * of the pages.  The pages will get retransmitted to the
11673 11673           * server during a putpage operation.
11674 11674           */
11675 11675          if (error) {
11676 11676                  while (plist != NULL) {
11677 11677                          pptr = plist;
11678 11678                          page_sub(&plist, pptr);
11679 11679                          page_unlock(pptr);
11680 11680                  }
11681 11681                  return;
11682 11682          }
11683 11683  
11684 11684          /*
11685 11685           * We've tried as hard as we can to commit the data to stable
11686 11686           * storage on the server.  We just unlock the rest of the pages
11687 11687           * and clear the commit required state.  They will be put
11688 11688           * onto the tail of the cachelist if they are nolonger
11689 11689           * mapped.
11690 11690           */
11691 11691          while (plist != pp) {
11692 11692                  pptr = plist;
11693 11693                  page_sub(&plist, pptr);
11694 11694                  pptr->p_fsdata = C_NOCOMMIT;
11695 11695                  page_unlock(pptr);
11696 11696          }
11697 11697  
11698 11698          /*
11699 11699           * It is possible that nfs4_commit didn't return error but
11700 11700           * some other thread has modified the page we are going
11701 11701           * to free/destroy.
11702 11702           *    In this case we need to rewrite the page. Do an explicit check
11703 11703           * before attempting to free/destroy the page. If modified, needs to
11704 11704           * be rewritten so unlock the page and return.
11705 11705           */
11706 11706          if (hat_ismod(pp)) {
11707 11707                  pp->p_fsdata = C_NOCOMMIT;
11708 11708                  page_unlock(pp);
11709 11709                  return;
11710 11710          }
11711 11711  
11712 11712          /*
11713 11713           * Now, as appropriate, either free or destroy the page
11714 11714           * that we were called with.
11715 11715           */
11716 11716          pp->p_fsdata = C_NOCOMMIT;
11717 11717          if (fl == B_FREE)
11718 11718                  page_free(pp, dn);
11719 11719          else
11720 11720                  page_destroy(pp, dn);
11721 11721  }
11722 11722  
11723 11723  /*
11724 11724   * Commit requires that the current fh be the file written to.
11725 11725   * The compound op structure is:
11726 11726   *      PUTFH(file), COMMIT
11727 11727   */
11728 11728  static int
11729 11729  nfs4_commit(vnode_t *vp, offset4 offset, count4 count, cred_t *cr)
11730 11730  {
11731 11731          COMPOUND4args_clnt args;
11732 11732          COMPOUND4res_clnt res;
11733 11733          COMMIT4res *cm_res;
11734 11734          nfs_argop4 argop[2];
11735 11735          nfs_resop4 *resop;
11736 11736          int doqueue;
11737 11737          mntinfo4_t *mi;
11738 11738          rnode4_t *rp;
11739 11739          cred_t *cred_otw = NULL;
11740 11740          bool_t needrecov = FALSE;
11741 11741          nfs4_recov_state_t recov_state;
11742 11742          nfs4_open_stream_t *osp = NULL;
11743 11743          bool_t first_time = TRUE;       /* first time getting OTW cred */
11744 11744          bool_t last_time = FALSE;       /* last time getting OTW cred */
11745 11745          nfs4_error_t e = { 0, NFS4_OK, RPC_SUCCESS };
11746 11746  
11747 11747          ASSERT(nfs_zone() == VTOMI4(vp)->mi_zone);
11748 11748  
11749 11749          rp = VTOR4(vp);
11750 11750  
11751 11751          mi = VTOMI4(vp);
11752 11752          recov_state.rs_flags = 0;
11753 11753          recov_state.rs_num_retry_despite_err = 0;
11754 11754  get_commit_cred:
11755 11755          /*
11756 11756           * Releases the osp, if a valid open stream is provided.
11757 11757           * Puts a hold on the cred_otw and the new osp (if found).
11758 11758           */
11759 11759          cred_otw = nfs4_get_otw_cred_by_osp(rp, cr, &osp,
11760 11760              &first_time, &last_time);
11761 11761          args.ctag = TAG_COMMIT;
11762 11762  recov_retry:
11763 11763          /*
11764 11764           * Commit ops: putfh file; commit
11765 11765           */
11766 11766          args.array_len = 2;
11767 11767          args.array = argop;
11768 11768  
11769 11769          e.error = nfs4_start_fop(VTOMI4(vp), vp, NULL, OH_COMMIT,
11770 11770              &recov_state, NULL);
11771 11771          if (e.error) {
11772 11772                  crfree(cred_otw);
11773 11773                  if (osp != NULL)
11774 11774                          open_stream_rele(osp, rp);
11775 11775                  return (e.error);
11776 11776          }
11777 11777  
11778 11778          /* putfh directory */
11779 11779          argop[0].argop = OP_CPUTFH;
11780 11780          argop[0].nfs_argop4_u.opcputfh.sfh = rp->r_fh;
11781 11781  
11782 11782          /* commit */
11783 11783          argop[1].argop = OP_COMMIT;
11784 11784          argop[1].nfs_argop4_u.opcommit.offset = offset;
11785 11785          argop[1].nfs_argop4_u.opcommit.count = count;
11786 11786  
11787 11787          doqueue = 1;
11788 11788          rfs4call(mi, &args, &res, cred_otw, &doqueue, 0, &e);
11789 11789  
11790 11790          needrecov = nfs4_needs_recovery(&e, FALSE, mi->mi_vfsp);
11791 11791          if (!needrecov && e.error) {
11792 11792                  nfs4_end_fop(VTOMI4(vp), vp, NULL, OH_COMMIT, &recov_state,
11793 11793                      needrecov);
11794 11794                  crfree(cred_otw);
11795 11795                  if (e.error == EACCES && last_time == FALSE)
11796 11796                          goto get_commit_cred;
11797 11797                  if (osp != NULL)
11798 11798                          open_stream_rele(osp, rp);
11799 11799                  return (e.error);
11800 11800          }
11801 11801  
11802 11802          if (needrecov) {
11803 11803                  if (nfs4_start_recovery(&e, VTOMI4(vp), vp, NULL, NULL,
11804 11804                      NULL, OP_COMMIT, NULL, NULL, NULL) == FALSE) {
11805 11805                          nfs4_end_fop(VTOMI4(vp), vp, NULL, OH_COMMIT,
11806 11806                              &recov_state, needrecov);
11807 11807                          if (!e.error)
11808 11808                                  (void) xdr_free(xdr_COMPOUND4res_clnt,
11809 11809                                      (caddr_t)&res);
11810 11810                          goto recov_retry;
11811 11811                  }
11812 11812                  if (e.error) {
11813 11813                          nfs4_end_fop(VTOMI4(vp), vp, NULL, OH_COMMIT,
11814 11814                              &recov_state, needrecov);
11815 11815                          crfree(cred_otw);
11816 11816                          if (osp != NULL)
11817 11817                                  open_stream_rele(osp, rp);
11818 11818                          return (e.error);
11819 11819                  }
11820 11820                  /* fall through for res.status case */
11821 11821          }
11822 11822  
11823 11823          if (res.status) {
11824 11824                  e.error = geterrno4(res.status);
11825 11825                  if (e.error == EACCES && last_time == FALSE) {
11826 11826                          crfree(cred_otw);
11827 11827                          nfs4_end_fop(VTOMI4(vp), vp, NULL, OH_COMMIT,
11828 11828                              &recov_state, needrecov);
11829 11829                          (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
11830 11830                          goto get_commit_cred;
11831 11831                  }
11832 11832                  /*
11833 11833                   * Can't do a nfs4_purge_stale_fh here because this
11834 11834                   * can cause a deadlock.  nfs4_commit can
11835 11835                   * be called from nfs4_dispose which can be called
11836 11836                   * indirectly via pvn_vplist_dirty.  nfs4_purge_stale_fh
11837 11837                   * can call back to pvn_vplist_dirty.
11838 11838                   */
11839 11839                  if (e.error == ESTALE) {
11840 11840                          mutex_enter(&rp->r_statelock);
11841 11841                          rp->r_flags |= R4STALE;
11842 11842                          if (!rp->r_error)
11843 11843                                  rp->r_error = e.error;
11844 11844                          mutex_exit(&rp->r_statelock);
11845 11845                          PURGE_ATTRCACHE4(vp);
11846 11846                  } else {
11847 11847                          mutex_enter(&rp->r_statelock);
11848 11848                          if (!rp->r_error)
11849 11849                                  rp->r_error = e.error;
11850 11850                          mutex_exit(&rp->r_statelock);
11851 11851                  }
11852 11852          } else {
11853 11853                  ASSERT(rp->r_flags & R4HAVEVERF);
11854 11854                  resop = &res.array[1];  /* commit res */
11855 11855                  cm_res = &resop->nfs_resop4_u.opcommit;
11856 11856                  mutex_enter(&rp->r_statelock);
11857 11857                  if (cm_res->writeverf == rp->r_writeverf) {
11858 11858                          mutex_exit(&rp->r_statelock);
11859 11859                          (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
11860 11860                          nfs4_end_fop(VTOMI4(vp), vp, NULL, OH_COMMIT,
11861 11861                              &recov_state, needrecov);
11862 11862                          crfree(cred_otw);
11863 11863                          if (osp != NULL)
11864 11864                                  open_stream_rele(osp, rp);
11865 11865                          return (0);
11866 11866                  }
11867 11867                  nfs4_set_mod(vp);
11868 11868                  rp->r_writeverf = cm_res->writeverf;
11869 11869                  mutex_exit(&rp->r_statelock);
11870 11870                  e.error = NFS_VERF_MISMATCH;
11871 11871          }
11872 11872  
11873 11873          (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
11874 11874          nfs4_end_fop(VTOMI4(vp), vp, NULL, OH_COMMIT, &recov_state, needrecov);
11875 11875          crfree(cred_otw);
11876 11876          if (osp != NULL)
11877 11877                  open_stream_rele(osp, rp);
11878 11878  
11879 11879          return (e.error);
11880 11880  }
11881 11881  
11882 11882  static void
11883 11883  nfs4_set_mod(vnode_t *vp)
11884 11884  {
11885 11885          ASSERT(nfs_zone() == VTOMI4(vp)->mi_zone);
11886 11886  
11887 11887          /* make sure we're looking at the master vnode, not a shadow */
11888 11888          pvn_vplist_setdirty(RTOV4(VTOR4(vp)), nfs_setmod_check);
11889 11889  }
11890 11890  
11891 11891  /*
11892 11892   * This function is used to gather a page list of the pages which
11893 11893   * can be committed on the server.
11894 11894   *
11895 11895   * The calling thread must have set R4COMMIT.  This bit is used to
11896 11896   * serialize access to the commit structure in the rnode.  As long
11897 11897   * as the thread has set R4COMMIT, then it can manipulate the commit
11898 11898   * structure without requiring any other locks.
11899 11899   *
11900 11900   * When this function is called from nfs4_dispose() the page passed
11901 11901   * into nfs4_dispose() will be SE_EXCL locked, and so this function
11902 11902   * will skip it. This is not a problem since we initially add the
11903 11903   * page to the r_commit page list.
11904 11904   *
11905 11905   */
11906 11906  static void
11907 11907  nfs4_get_commit(vnode_t *vp)
11908 11908  {
11909 11909          rnode4_t *rp;
11910 11910          page_t *pp;
11911 11911          kmutex_t *vphm;
11912 11912  
11913 11913          rp = VTOR4(vp);
11914 11914  
11915 11915          ASSERT(rp->r_flags & R4COMMIT);
11916 11916  
11917 11917          /* make sure we're looking at the master vnode, not a shadow */
11918 11918  
11919 11919          if (IS_SHADOW(vp, rp))
11920 11920                  vp = RTOV4(rp);
11921 11921  
11922 11922          vphm = page_vnode_mutex(vp);
11923 11923          mutex_enter(vphm);
11924 11924  
11925 11925          /*
11926 11926           * If there are no pages associated with this vnode, then
11927 11927           * just return.
11928 11928           */
11929 11929          if ((pp = vp->v_pages) == NULL) {
11930 11930                  mutex_exit(vphm);
11931 11931                  return;
11932 11932          }
11933 11933  
11934 11934          /*
11935 11935           * Step through all of the pages associated with this vnode
11936 11936           * looking for pages which need to be committed.
11937 11937           */
11938 11938          do {
11939 11939                  /* Skip marker pages. */
11940 11940                  if (pp->p_hash == PVN_VPLIST_HASH_TAG)
11941 11941                          continue;
11942 11942  
11943 11943                  /*
11944 11944                   * First short-cut everything (without the page_lock)
11945 11945                   * and see if this page does not need to be committed
11946 11946                   * or is modified if so then we'll just skip it.
11947 11947                   */
11948 11948                  if (pp->p_fsdata == C_NOCOMMIT || hat_ismod(pp))
11949 11949                          continue;
11950 11950  
11951 11951                  /*
11952 11952                   * Attempt to lock the page.  If we can't, then
11953 11953                   * someone else is messing with it or we have been
11954 11954                   * called from nfs4_dispose and this is the page that
11955 11955                   * nfs4_dispose was called with.. anyway just skip it.
11956 11956                   */
11957 11957                  if (!page_trylock(pp, SE_EXCL))
11958 11958                          continue;
11959 11959  
11960 11960                  /*
11961 11961                   * Lets check again now that we have the page lock.
11962 11962                   */
11963 11963                  if (pp->p_fsdata == C_NOCOMMIT || hat_ismod(pp)) {
11964 11964                          page_unlock(pp);
11965 11965                          continue;
11966 11966                  }
11967 11967  
11968 11968                  /* this had better not be a free page */
11969 11969                  ASSERT(PP_ISFREE(pp) == 0);
11970 11970  
11971 11971                  /*
11972 11972                   * The page needs to be committed and we locked it.
11973 11973                   * Update the base and length parameters and add it
11974 11974                   * to r_pages.
11975 11975                   */
11976 11976                  if (rp->r_commit.c_pages == NULL) {
11977 11977                          rp->r_commit.c_commbase = (offset3)pp->p_offset;
11978 11978                          rp->r_commit.c_commlen = PAGESIZE;
11979 11979                  } else if (pp->p_offset < rp->r_commit.c_commbase) {
11980 11980                          rp->r_commit.c_commlen = rp->r_commit.c_commbase -
11981 11981                              (offset3)pp->p_offset + rp->r_commit.c_commlen;
11982 11982                          rp->r_commit.c_commbase = (offset3)pp->p_offset;
11983 11983                  } else if ((rp->r_commit.c_commbase + rp->r_commit.c_commlen)
11984 11984                      <= pp->p_offset) {
11985 11985                          rp->r_commit.c_commlen = (offset3)pp->p_offset -
11986 11986                              rp->r_commit.c_commbase + PAGESIZE;
11987 11987                  }
11988 11988                  page_add(&rp->r_commit.c_pages, pp);
11989 11989          } while ((pp = pp->p_vpnext) != vp->v_pages);
11990 11990  
11991 11991          mutex_exit(vphm);
11992 11992  }
11993 11993  
11994 11994  /*
11995 11995   * This routine is used to gather together a page list of the pages
11996 11996   * which are to be committed on the server.  This routine must not
11997 11997   * be called if the calling thread holds any locked pages.
11998 11998   *
11999 11999   * The calling thread must have set R4COMMIT.  This bit is used to
12000 12000   * serialize access to the commit structure in the rnode.  As long
12001 12001   * as the thread has set R4COMMIT, then it can manipulate the commit
12002 12002   * structure without requiring any other locks.
12003 12003   */
12004 12004  static void
12005 12005  nfs4_get_commit_range(vnode_t *vp, u_offset_t soff, size_t len)
12006 12006  {
12007 12007  
12008 12008          rnode4_t *rp;
12009 12009          page_t *pp;
12010 12010          u_offset_t end;
12011 12011          u_offset_t off;
12012 12012          ASSERT(len != 0);
12013 12013          rp = VTOR4(vp);
12014 12014          ASSERT(rp->r_flags & R4COMMIT);
12015 12015  
12016 12016          ASSERT(nfs_zone() == VTOMI4(vp)->mi_zone);
12017 12017  
12018 12018          /* make sure we're looking at the master vnode, not a shadow */
12019 12019  
12020 12020          if (IS_SHADOW(vp, rp))
12021 12021                  vp = RTOV4(rp);
12022 12022  
12023 12023          /*
12024 12024           * If there are no pages associated with this vnode, then
12025 12025           * just return.
12026 12026           */
12027 12027          if ((pp = vp->v_pages) == NULL)
12028 12028                  return;
12029 12029          /*
12030 12030           * Calculate the ending offset.
12031 12031           */
12032 12032          end = soff + len;
12033 12033          for (off = soff; off < end; off += PAGESIZE) {
12034 12034                  /*
12035 12035                   * Lookup each page by vp, offset.
12036 12036                   */
12037 12037                  if ((pp = page_lookup_nowait(vp, off, SE_EXCL)) == NULL)
12038 12038                          continue;
12039 12039                  /*
12040 12040                   * If this page does not need to be committed or is
12041 12041                   * modified, then just skip it.
12042 12042                   */
12043 12043                  if (pp->p_fsdata == C_NOCOMMIT || hat_ismod(pp)) {
12044 12044                          page_unlock(pp);
12045 12045                          continue;
12046 12046                  }
12047 12047  
12048 12048                  ASSERT(PP_ISFREE(pp) == 0);
12049 12049                  /*
12050 12050                   * The page needs to be committed and we locked it.
12051 12051                   * Update the base and length parameters and add it
12052 12052                   * to r_pages.
12053 12053                   */
12054 12054                  if (rp->r_commit.c_pages == NULL) {
12055 12055                          rp->r_commit.c_commbase = (offset3)pp->p_offset;
12056 12056                          rp->r_commit.c_commlen = PAGESIZE;
12057 12057                  } else {
12058 12058                          rp->r_commit.c_commlen = (offset3)pp->p_offset -
12059 12059                              rp->r_commit.c_commbase + PAGESIZE;
12060 12060                  }
12061 12061                  page_add(&rp->r_commit.c_pages, pp);
12062 12062          }
12063 12063  }
12064 12064  
12065 12065  /*
12066 12066   * Called from nfs4_close(), nfs4_fsync() and nfs4_delmap().
12067 12067   * Flushes and commits data to the server.
12068 12068   */
12069 12069  static int
12070 12070  nfs4_putpage_commit(vnode_t *vp, offset_t poff, size_t plen, cred_t *cr)
12071 12071  {
12072 12072          int error;
12073 12073          verifier4 write_verf;
12074 12074          rnode4_t *rp = VTOR4(vp);
12075 12075  
12076 12076          ASSERT(nfs_zone() == VTOMI4(vp)->mi_zone);
12077 12077  
12078 12078          /*
12079 12079           * Flush the data portion of the file and then commit any
12080 12080           * portions which need to be committed.  This may need to
12081 12081           * be done twice if the server has changed state since
12082 12082           * data was last written.  The data will need to be
12083 12083           * rewritten to the server and then a new commit done.
12084 12084           *
12085 12085           * In fact, this may need to be done several times if the
12086 12086           * server is having problems and crashing while we are
12087 12087           * attempting to do this.
12088 12088           */
12089 12089  
12090 12090  top:
12091 12091          /*
12092 12092           * Do a flush based on the poff and plen arguments.  This
12093 12093           * will synchronously write out any modified pages in the
12094 12094           * range specified by (poff, plen). This starts all of the
12095 12095           * i/o operations which will be waited for in the next
12096 12096           * call to nfs4_putpage
12097 12097           */
12098 12098  
12099 12099          mutex_enter(&rp->r_statelock);
12100 12100          write_verf = rp->r_writeverf;
12101 12101          mutex_exit(&rp->r_statelock);
12102 12102  
12103 12103          error = nfs4_putpage(vp, poff, plen, B_ASYNC, cr, NULL);
12104 12104          if (error == EAGAIN)
12105 12105                  error = 0;
12106 12106  
12107 12107          /*
12108 12108           * Do a flush based on the poff and plen arguments.  This
12109 12109           * will synchronously write out any modified pages in the
12110 12110           * range specified by (poff, plen) and wait until all of
12111 12111           * the asynchronous i/o's in that range are done as well.
12112 12112           */
12113 12113          if (!error)
12114 12114                  error = nfs4_putpage(vp, poff, plen, 0, cr, NULL);
12115 12115  
12116 12116          if (error)
12117 12117                  return (error);
12118 12118  
12119 12119          mutex_enter(&rp->r_statelock);
12120 12120          if (rp->r_writeverf != write_verf) {
12121 12121                  mutex_exit(&rp->r_statelock);
12122 12122                  goto top;
12123 12123          }
12124 12124          mutex_exit(&rp->r_statelock);
12125 12125  
12126 12126          /*
12127 12127           * Now commit any pages which might need to be committed.
12128 12128           * If the error, NFS_VERF_MISMATCH, is returned, then
12129 12129           * start over with the flush operation.
12130 12130           */
12131 12131          error = nfs4_commit_vp(vp, poff, plen, cr, NFS4_WRITE_WAIT);
12132 12132  
12133 12133          if (error == NFS_VERF_MISMATCH)
12134 12134                  goto top;
12135 12135  
12136 12136          return (error);
12137 12137  }
12138 12138  
12139 12139  /*
12140 12140   * nfs4_commit_vp()  will wait for other pending commits and
12141 12141   * will either commit the whole file or a range, plen dictates
12142 12142   * if we commit whole file. a value of zero indicates the whole
12143 12143   * file. Called from nfs4_putpage_commit() or nfs4_sync_putapage()
12144 12144   */
12145 12145  static int
12146 12146  nfs4_commit_vp(vnode_t *vp, u_offset_t poff, size_t plen,
12147 12147      cred_t *cr, int wait_on_writes)
12148 12148  {
12149 12149          rnode4_t *rp;
12150 12150          page_t *plist;
12151 12151          offset3 offset;
12152 12152          count3 len;
12153 12153  
12154 12154          ASSERT(nfs_zone() == VTOMI4(vp)->mi_zone);
12155 12155  
12156 12156          rp = VTOR4(vp);
12157 12157  
12158 12158          /*
12159 12159           *  before we gather commitable pages make
12160 12160           *  sure there are no outstanding async writes
12161 12161           */
12162 12162          if (rp->r_count && wait_on_writes == NFS4_WRITE_WAIT) {
12163 12163                  mutex_enter(&rp->r_statelock);
12164 12164                  while (rp->r_count > 0) {
12165 12165                          cv_wait(&rp->r_cv, &rp->r_statelock);
12166 12166                  }
12167 12167                  mutex_exit(&rp->r_statelock);
12168 12168          }
12169 12169  
12170 12170          /*
12171 12171           * Set the `commit inprogress' state bit.  We must
12172 12172           * first wait until any current one finishes.
12173 12173           */
12174 12174          mutex_enter(&rp->r_statelock);
12175 12175          while (rp->r_flags & R4COMMIT) {
12176 12176                  rp->r_flags |= R4COMMITWAIT;
12177 12177                  cv_wait(&rp->r_commit.c_cv, &rp->r_statelock);
12178 12178                  rp->r_flags &= ~R4COMMITWAIT;
12179 12179          }
12180 12180          rp->r_flags |= R4COMMIT;
12181 12181          mutex_exit(&rp->r_statelock);
12182 12182  
12183 12183          /*
12184 12184           * Gather all of the pages which need to be
12185 12185           * committed.
12186 12186           */
12187 12187          if (plen == 0)
12188 12188                  nfs4_get_commit(vp);
12189 12189          else
12190 12190                  nfs4_get_commit_range(vp, poff, plen);
12191 12191  
12192 12192          /*
12193 12193           * Clear the `commit inprogress' bit and disconnect the
12194 12194           * page list which was gathered by nfs4_get_commit.
12195 12195           */
12196 12196          plist = rp->r_commit.c_pages;
12197 12197          rp->r_commit.c_pages = NULL;
12198 12198          offset = rp->r_commit.c_commbase;
12199 12199          len = rp->r_commit.c_commlen;
12200 12200          mutex_enter(&rp->r_statelock);
12201 12201          rp->r_flags &= ~R4COMMIT;
12202 12202          cv_broadcast(&rp->r_commit.c_cv);
12203 12203          mutex_exit(&rp->r_statelock);
12204 12204  
12205 12205          /*
12206 12206           * If any pages need to be committed, commit them and
12207 12207           * then unlock them so that they can be freed some
12208 12208           * time later.
12209 12209           */
12210 12210          if (plist == NULL)
12211 12211                  return (0);
12212 12212  
12213 12213          /*
12214 12214           * No error occurred during the flush portion
12215 12215           * of this operation, so now attempt to commit
12216 12216           * the data to stable storage on the server.
12217 12217           *
12218 12218           * This will unlock all of the pages on the list.
12219 12219           */
12220 12220          return (nfs4_sync_commit(vp, plist, offset, len, cr));
12221 12221  }
12222 12222  
12223 12223  static int
12224 12224  nfs4_sync_commit(vnode_t *vp, page_t *plist, offset3 offset, count3 count,
12225 12225      cred_t *cr)
12226 12226  {
12227 12227          int error;
12228 12228          page_t *pp;
12229 12229  
12230 12230          ASSERT(nfs_zone() == VTOMI4(vp)->mi_zone);
12231 12231  
12232 12232          error = nfs4_commit(vp, (offset4)offset, (count3)count, cr);
12233 12233  
12234 12234          /*
12235 12235           * If we got an error, then just unlock all of the pages
12236 12236           * on the list.
12237 12237           */
12238 12238          if (error) {
12239 12239                  while (plist != NULL) {
12240 12240                          pp = plist;
12241 12241                          page_sub(&plist, pp);
12242 12242                          page_unlock(pp);
12243 12243                  }
12244 12244                  return (error);
12245 12245          }
12246 12246          /*
12247 12247           * We've tried as hard as we can to commit the data to stable
12248 12248           * storage on the server.  We just unlock the pages and clear
12249 12249           * the commit required state.  They will get freed later.
12250 12250           */
12251 12251          while (plist != NULL) {
12252 12252                  pp = plist;
12253 12253                  page_sub(&plist, pp);
12254 12254                  pp->p_fsdata = C_NOCOMMIT;
12255 12255                  page_unlock(pp);
12256 12256          }
12257 12257  
12258 12258          return (error);
12259 12259  }
12260 12260  
12261 12261  static void
12262 12262  do_nfs4_async_commit(vnode_t *vp, page_t *plist, offset3 offset, count3 count,
12263 12263      cred_t *cr)
12264 12264  {
12265 12265  
12266 12266          (void) nfs4_sync_commit(vp, plist, offset, count, cr);
12267 12267  }
12268 12268  
12269 12269  /*ARGSUSED*/
12270 12270  static int
12271 12271  nfs4_setsecattr(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr,
12272 12272      caller_context_t *ct)
12273 12273  {
12274 12274          int             error = 0;
12275 12275          mntinfo4_t      *mi;
12276 12276          vattr_t         va;
12277 12277          vsecattr_t      nfsace4_vsap;
12278 12278  
12279 12279          mi = VTOMI4(vp);
12280 12280          if (nfs_zone() != mi->mi_zone)
12281 12281                  return (EIO);
12282 12282          if (mi->mi_flags & MI4_ACL) {
12283 12283                  /* if we have a delegation, return it */
12284 12284                  if (VTOR4(vp)->r_deleg_type != OPEN_DELEGATE_NONE)
12285 12285                          (void) nfs4delegreturn(VTOR4(vp),
12286 12286                              NFS4_DR_REOPEN|NFS4_DR_PUSH);
12287 12287  
12288 12288                  error = nfs4_is_acl_mask_valid(vsecattr->vsa_mask,
12289 12289                      NFS4_ACL_SET);
12290 12290                  if (error) /* EINVAL */
12291 12291                          return (error);
12292 12292  
12293 12293                  if (vsecattr->vsa_mask & (VSA_ACL | VSA_DFACL)) {
12294 12294                          /*
12295 12295                           * These are aclent_t type entries.
12296 12296                           */
12297 12297                          error = vs_aent_to_ace4(vsecattr, &nfsace4_vsap,
12298 12298                              vp->v_type == VDIR, FALSE);
12299 12299                          if (error)
12300 12300                                  return (error);
12301 12301                  } else {
12302 12302                          /*
12303 12303                           * These are ace_t type entries.
12304 12304                           */
12305 12305                          error = vs_acet_to_ace4(vsecattr, &nfsace4_vsap,
12306 12306                              FALSE);
12307 12307                          if (error)
12308 12308                                  return (error);
12309 12309                  }
12310 12310                  bzero(&va, sizeof (va));
12311 12311                  error = nfs4setattr(vp, &va, flag, cr, &nfsace4_vsap);
12312 12312                  vs_ace4_destroy(&nfsace4_vsap);
12313 12313                  return (error);
12314 12314          }
12315 12315          return (ENOSYS);
12316 12316  }
12317 12317  
12318 12318  /* ARGSUSED */
12319 12319  int
12320 12320  nfs4_getsecattr(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr,
12321 12321      caller_context_t *ct)
12322 12322  {
12323 12323          int             error;
12324 12324          mntinfo4_t      *mi;
12325 12325          nfs4_ga_res_t   gar;
12326 12326          rnode4_t        *rp = VTOR4(vp);
12327 12327  
12328 12328          mi = VTOMI4(vp);
12329 12329          if (nfs_zone() != mi->mi_zone)
12330 12330                  return (EIO);
12331 12331  
12332 12332          bzero(&gar, sizeof (gar));
12333 12333          gar.n4g_vsa.vsa_mask = vsecattr->vsa_mask;
12334 12334  
12335 12335          /*
12336 12336           * vsecattr->vsa_mask holds the original acl request mask.
12337 12337           * This is needed when determining what to return.
12338 12338           * (See: nfs4_create_getsecattr_return())
12339 12339           */
12340 12340          error = nfs4_is_acl_mask_valid(vsecattr->vsa_mask, NFS4_ACL_GET);
12341 12341          if (error) /* EINVAL */
12342 12342                  return (error);
12343 12343  
12344 12344          /*
12345 12345           * If this is a referral stub, don't try to go OTW for an ACL
12346 12346           */
12347 12347          if (RP_ISSTUB_REFERRAL(VTOR4(vp)))
12348 12348                  return (fs_fab_acl(vp, vsecattr, flag, cr, ct));
12349 12349  
12350 12350          if (mi->mi_flags & MI4_ACL) {
12351 12351                  /*
12352 12352                   * Check if the data is cached and the cache is valid.  If it
12353 12353                   * is we don't go over the wire.
12354 12354                   */
12355 12355                  if (rp->r_secattr != NULL && ATTRCACHE4_VALID(vp)) {
12356 12356                          mutex_enter(&rp->r_statelock);
12357 12357                          if (rp->r_secattr != NULL) {
12358 12358                                  error = nfs4_create_getsecattr_return(
12359 12359                                      rp->r_secattr, vsecattr, rp->r_attr.va_uid,
12360 12360                                      rp->r_attr.va_gid,
12361 12361                                      vp->v_type == VDIR);
12362 12362                                  if (!error) { /* error == 0 - Success! */
12363 12363                                          mutex_exit(&rp->r_statelock);
12364 12364                                          return (error);
12365 12365                                  }
12366 12366                          }
12367 12367                          mutex_exit(&rp->r_statelock);
12368 12368                  }
12369 12369  
12370 12370                  /*
12371 12371                   * The getattr otw call will always get both the acl, in
12372 12372                   * the form of a list of nfsace4's, and the number of acl
12373 12373                   * entries; independent of the value of gar.n4g_vsa.vsa_mask.
12374 12374                   */
12375 12375                  gar.n4g_va.va_mask = AT_ALL;
12376 12376                  error =  nfs4_getattr_otw(vp, &gar, cr, 1);
12377 12377                  if (error) {
12378 12378                          vs_ace4_destroy(&gar.n4g_vsa);
12379 12379                          if (error == ENOTSUP || error == EOPNOTSUPP)
12380 12380                                  error = fs_fab_acl(vp, vsecattr, flag, cr, ct);
12381 12381                          return (error);
12382 12382                  }
12383 12383  
12384 12384                  if (!(gar.n4g_resbmap & FATTR4_ACL_MASK)) {
12385 12385                          /*
12386 12386                           * No error was returned, but according to the response
12387 12387                           * bitmap, neither was an acl.
12388 12388                           */
12389 12389                          vs_ace4_destroy(&gar.n4g_vsa);
12390 12390                          error = fs_fab_acl(vp, vsecattr, flag, cr, ct);
12391 12391                          return (error);
12392 12392                  }
12393 12393  
12394 12394                  /*
12395 12395                   * Update the cache with the ACL.
12396 12396                   */
12397 12397                  nfs4_acl_fill_cache(rp, &gar.n4g_vsa);
12398 12398  
12399 12399                  error = nfs4_create_getsecattr_return(&gar.n4g_vsa,
12400 12400                      vsecattr, gar.n4g_va.va_uid, gar.n4g_va.va_gid,
12401 12401                      vp->v_type == VDIR);
12402 12402                  vs_ace4_destroy(&gar.n4g_vsa);
12403 12403                  if ((error) && (vsecattr->vsa_mask &
12404 12404                      (VSA_ACL | VSA_ACLCNT | VSA_DFACL | VSA_DFACLCNT)) &&
12405 12405                      (error != EACCES)) {
12406 12406                          error = fs_fab_acl(vp, vsecattr, flag, cr, ct);
12407 12407                  }
12408 12408                  return (error);
12409 12409          }
12410 12410          error = fs_fab_acl(vp, vsecattr, flag, cr, ct);
12411 12411          return (error);
12412 12412  }
12413 12413  
12414 12414  /*
12415 12415   * The function returns:
12416 12416   *      - 0 (zero) if the passed in "acl_mask" is a valid request.
12417 12417   *      - EINVAL if the passed in "acl_mask" is an invalid request.
12418 12418   *
12419 12419   * In the case of getting an acl (op == NFS4_ACL_GET) the mask is invalid if:
12420 12420   * - We have a mixture of ACE and ACL requests (e.g. VSA_ACL | VSA_ACE)
12421 12421   *
12422 12422   * In the case of setting an acl (op == NFS4_ACL_SET) the mask is invalid if:
12423 12423   * - We have a mixture of ACE and ACL requests (e.g. VSA_ACL | VSA_ACE)
12424 12424   * - We have a count field set without the corresponding acl field set. (e.g. -
12425 12425   * VSA_ACECNT is set, but VSA_ACE is not)
12426 12426   */
12427 12427  static int
12428 12428  nfs4_is_acl_mask_valid(uint_t acl_mask, nfs4_acl_op_t op)
12429 12429  {
12430 12430          /* Shortcut the masks that are always valid. */
12431 12431          if (acl_mask == (VSA_ACE | VSA_ACECNT))
12432 12432                  return (0);
12433 12433          if (acl_mask == (VSA_ACL | VSA_ACLCNT | VSA_DFACL | VSA_DFACLCNT))
12434 12434                  return (0);
12435 12435  
12436 12436          if (acl_mask & (VSA_ACE | VSA_ACECNT)) {
12437 12437                  /*
12438 12438                   * We can't have any VSA_ACL type stuff in the mask now.
12439 12439                   */
12440 12440                  if (acl_mask & (VSA_ACL | VSA_ACLCNT | VSA_DFACL |
12441 12441                      VSA_DFACLCNT))
12442 12442                          return (EINVAL);
12443 12443  
12444 12444                  if (op == NFS4_ACL_SET) {
12445 12445                          if ((acl_mask & VSA_ACECNT) && !(acl_mask & VSA_ACE))
12446 12446                                  return (EINVAL);
12447 12447                  }
12448 12448          }
12449 12449  
12450 12450          if (acl_mask & (VSA_ACL | VSA_ACLCNT | VSA_DFACL | VSA_DFACLCNT)) {
12451 12451                  /*
12452 12452                   * We can't have any VSA_ACE type stuff in the mask now.
12453 12453                   */
12454 12454                  if (acl_mask & (VSA_ACE | VSA_ACECNT))
12455 12455                          return (EINVAL);
12456 12456  
12457 12457                  if (op == NFS4_ACL_SET) {
12458 12458                          if ((acl_mask & VSA_ACLCNT) && !(acl_mask & VSA_ACL))
12459 12459                                  return (EINVAL);
12460 12460  
12461 12461                          if ((acl_mask & VSA_DFACLCNT) &&
12462 12462                              !(acl_mask & VSA_DFACL))
12463 12463                                  return (EINVAL);
12464 12464                  }
12465 12465          }
12466 12466          return (0);
12467 12467  }
12468 12468  
12469 12469  /*
12470 12470   * The theory behind creating the correct getsecattr return is simply this:
12471 12471   * "Don't return anything that the caller is not expecting to have to free."
12472 12472   */
12473 12473  static int
12474 12474  nfs4_create_getsecattr_return(vsecattr_t *filled_vsap, vsecattr_t *vsap,
12475 12475      uid_t uid, gid_t gid, int isdir)
12476 12476  {
12477 12477          int error = 0;
12478 12478          /* Save the mask since the translators modify it. */
12479 12479          uint_t  orig_mask = vsap->vsa_mask;
12480 12480  
12481 12481          if (orig_mask & (VSA_ACE | VSA_ACECNT)) {
12482 12482                  error = vs_ace4_to_acet(filled_vsap, vsap, uid, gid, FALSE);
12483 12483  
12484 12484                  if (error)
12485 12485                          return (error);
12486 12486  
12487 12487                  /*
12488 12488                   * If the caller only asked for the ace count (VSA_ACECNT)
12489 12489                   * don't give them the full acl (VSA_ACE), free it.
12490 12490                   */
12491 12491                  if (!orig_mask & VSA_ACE) {
12492 12492                          if (vsap->vsa_aclentp != NULL) {
12493 12493                                  kmem_free(vsap->vsa_aclentp,
12494 12494                                      vsap->vsa_aclcnt * sizeof (ace_t));
12495 12495                                  vsap->vsa_aclentp = NULL;
12496 12496                          }
12497 12497                  }
12498 12498                  vsap->vsa_mask = orig_mask;
12499 12499  
12500 12500          } else if (orig_mask & (VSA_ACL | VSA_ACLCNT | VSA_DFACL |
12501 12501              VSA_DFACLCNT)) {
12502 12502                  error = vs_ace4_to_aent(filled_vsap, vsap, uid, gid,
12503 12503                      isdir, FALSE);
12504 12504  
12505 12505                  if (error)
12506 12506                          return (error);
12507 12507  
12508 12508                  /*
12509 12509                   * If the caller only asked for the acl count (VSA_ACLCNT)
12510 12510                   * and/or the default acl count (VSA_DFACLCNT) don't give them
12511 12511                   * the acl (VSA_ACL) or default acl (VSA_DFACL), free it.
12512 12512                   */
12513 12513                  if (!orig_mask & VSA_ACL) {
12514 12514                          if (vsap->vsa_aclentp != NULL) {
12515 12515                                  kmem_free(vsap->vsa_aclentp,
12516 12516                                      vsap->vsa_aclcnt * sizeof (aclent_t));
12517 12517                                  vsap->vsa_aclentp = NULL;
12518 12518                          }
12519 12519                  }
12520 12520  
12521 12521                  if (!orig_mask & VSA_DFACL) {
12522 12522                          if (vsap->vsa_dfaclentp != NULL) {
12523 12523                                  kmem_free(vsap->vsa_dfaclentp,
12524 12524                                      vsap->vsa_dfaclcnt * sizeof (aclent_t));
12525 12525                                  vsap->vsa_dfaclentp = NULL;
12526 12526                          }
12527 12527                  }
12528 12528                  vsap->vsa_mask = orig_mask;
12529 12529          }
12530 12530          return (0);
12531 12531  }
12532 12532  
12533 12533  /* ARGSUSED */
12534 12534  int
12535 12535  nfs4_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr,
12536 12536      caller_context_t *ct)
12537 12537  {
12538 12538          int error;
12539 12539  
12540 12540          if (nfs_zone() != VTOMI4(vp)->mi_zone)
12541 12541                  return (EIO);
12542 12542          /*
12543 12543           * check for valid cmd parameter
12544 12544           */
12545 12545          if (cmd != F_SHARE && cmd != F_UNSHARE && cmd != F_HASREMOTELOCKS)
12546 12546                  return (EINVAL);
12547 12547  
12548 12548          /*
12549 12549           * Check access permissions
12550 12550           */
12551 12551          if ((cmd & F_SHARE) &&
12552 12552              (((shr->s_access & F_RDACC) && (flag & FREAD) == 0) ||
12553 12553              (shr->s_access == F_WRACC && (flag & FWRITE) == 0)))
12554 12554                  return (EBADF);
12555 12555  
12556 12556          /*
12557 12557           * If the filesystem is mounted using local locking, pass the
12558 12558           * request off to the local share code.
12559 12559           */
12560 12560          if (VTOMI4(vp)->mi_flags & MI4_LLOCK)
12561 12561                  return (fs_shrlock(vp, cmd, shr, flag, cr, ct));
12562 12562  
12563 12563          switch (cmd) {
12564 12564          case F_SHARE:
12565 12565          case F_UNSHARE:
12566 12566                  /*
12567 12567                   * This will be properly implemented later,
12568 12568                   * see RFE: 4823948 .
12569 12569                   */
12570 12570                  error = EAGAIN;
12571 12571                  break;
12572 12572  
12573 12573          case F_HASREMOTELOCKS:
12574 12574                  /*
12575 12575                   * NFS client can't store remote locks itself
12576 12576                   */
12577 12577                  shr->s_access = 0;
12578 12578                  error = 0;
12579 12579                  break;
12580 12580  
12581 12581          default:
12582 12582                  error = EINVAL;
12583 12583                  break;
12584 12584          }
12585 12585  
12586 12586          return (error);
12587 12587  }
12588 12588  
12589 12589  /*
12590 12590   * Common code called by directory ops to update the attrcache
12591 12591   */
12592 12592  static int
12593 12593  nfs4_update_attrcache(nfsstat4 status, nfs4_ga_res_t *garp,
12594 12594      hrtime_t t, vnode_t *vp, cred_t *cr)
12595 12595  {
12596 12596          int error = 0;
12597 12597  
12598 12598          ASSERT(nfs_zone() == VTOMI4(vp)->mi_zone);
12599 12599  
12600 12600          if (status != NFS4_OK) {
12601 12601                  /* getattr not done or failed */
12602 12602                  PURGE_ATTRCACHE4(vp);
12603 12603                  return (error);
12604 12604          }
12605 12605  
12606 12606          if (garp) {
12607 12607                  nfs4_attr_cache(vp, garp, t, cr, FALSE, NULL);
12608 12608          } else {
12609 12609                  PURGE_ATTRCACHE4(vp);
12610 12610          }
12611 12611          return (error);
12612 12612  }
12613 12613  
12614 12614  /*
12615 12615   * Update directory caches for directory modification ops (link, rename, etc.)
12616 12616   * When dinfo is NULL, manage dircaches in the old way.
12617 12617   */
12618 12618  static void
12619 12619  nfs4_update_dircaches(change_info4 *cinfo, vnode_t *dvp, vnode_t *vp, char *nm,
12620 12620      dirattr_info_t *dinfo)
12621 12621  {
12622 12622          rnode4_t        *drp = VTOR4(dvp);
12623 12623  
12624 12624          ASSERT(nfs_zone() == VTOMI4(dvp)->mi_zone);
12625 12625  
12626 12626          /* Purge rddir cache for dir since it changed */
12627 12627          if (drp->r_dir != NULL)
12628 12628                  nfs4_purge_rddir_cache(dvp);
12629 12629  
12630 12630          /*
12631 12631           * If caller provided dinfo, then use it to manage dir caches.
12632 12632           */
12633 12633          if (dinfo != NULL) {
12634 12634                  if (vp != NULL) {
12635 12635                          mutex_enter(&VTOR4(vp)->r_statev4_lock);
12636 12636                          if (!VTOR4(vp)->created_v4) {
12637 12637                                  mutex_exit(&VTOR4(vp)->r_statev4_lock);
12638 12638                                  dnlc_update(dvp, nm, vp);
12639 12639                          } else {
12640 12640                                  /*
12641 12641                                   * XXX don't update if the created_v4 flag is
12642 12642                                   * set
12643 12643                                   */
12644 12644                                  mutex_exit(&VTOR4(vp)->r_statev4_lock);
12645 12645                                  NFS4_DEBUG(nfs4_client_state_debug,
12646 12646                                      (CE_NOTE, "nfs4_update_dircaches: "
12647 12647                                      "don't update dnlc: created_v4 flag"));
12648 12648                          }
12649 12649                  }
12650 12650  
12651 12651                  nfs4_attr_cache(dvp, dinfo->di_garp, dinfo->di_time_call,
12652 12652                      dinfo->di_cred, FALSE, cinfo);
12653 12653  
12654 12654                  return;
12655 12655          }
12656 12656  
12657 12657          /*
12658 12658           * Caller didn't provide dinfo, then check change_info4 to update DNLC.
12659 12659           * Since caller modified dir but didn't receive post-dirmod-op dir
12660 12660           * attrs, the dir's attrs must be purged.
12661 12661           *
12662 12662           * XXX this check and dnlc update/purge should really be atomic,
12663 12663           * XXX but can't use rnode statelock because it'll deadlock in
12664 12664           * XXX dnlc_purge_vp, however, the risk is minimal even if a race
12665 12665           * XXX does occur.
12666 12666           *
12667 12667           * XXX We also may want to check that atomic is true in the
12668 12668           * XXX change_info struct. If it is not, the change_info may
12669 12669           * XXX reflect changes by more than one clients which means that
12670 12670           * XXX our cache may not be valid.
12671 12671           */
12672 12672          PURGE_ATTRCACHE4(dvp);
12673 12673          if (drp->r_change == cinfo->before) {
12674 12674                  /* no changes took place in the directory prior to our link */
12675 12675                  if (vp != NULL) {
12676 12676                          mutex_enter(&VTOR4(vp)->r_statev4_lock);
12677 12677                          if (!VTOR4(vp)->created_v4) {
12678 12678                                  mutex_exit(&VTOR4(vp)->r_statev4_lock);
12679 12679                                  dnlc_update(dvp, nm, vp);
12680 12680                          } else {
12681 12681                                  /*
12682 12682                                   * XXX dont' update if the created_v4 flag
12683 12683                                   * is set
12684 12684                                   */
12685 12685                                  mutex_exit(&VTOR4(vp)->r_statev4_lock);
12686 12686                                  NFS4_DEBUG(nfs4_client_state_debug, (CE_NOTE,
12687 12687                                      "nfs4_update_dircaches: don't"
12688 12688                                      " update dnlc: created_v4 flag"));
12689 12689                          }
12690 12690                  }
12691 12691          } else {
12692 12692                  /* Another client modified directory - purge its dnlc cache */
12693 12693                  dnlc_purge_vp(dvp);
12694 12694          }
12695 12695  }
12696 12696  
12697 12697  /*
12698 12698   * The OPEN_CONFIRM operation confirms the sequence number used in OPENing a
12699 12699   * file.
12700 12700   *
12701 12701   * The 'reopening_file' boolean should be set to TRUE if we are reopening this
12702 12702   * file (ie: client recovery) and otherwise set to FALSE.
12703 12703   *
12704 12704   * 'nfs4_start/end_op' should have been called by the proper (ie: not recovery
12705 12705   * initiated) calling functions.
12706 12706   *
12707 12707   * 'resend' is set to TRUE if this is a OPEN_CONFIRM issued as a result
12708 12708   * of resending a 'lost' open request.
12709 12709   *
12710 12710   * 'num_bseqid_retryp' makes sure we don't loop forever on a broken
12711 12711   * server that hands out BAD_SEQID on open confirm.
12712 12712   *
12713 12713   * Errors are returned via the nfs4_error_t parameter.
12714 12714   */
12715 12715  void
12716 12716  nfs4open_confirm(vnode_t *vp, seqid4 *seqid, stateid4 *stateid, cred_t *cr,
12717 12717      bool_t reopening_file, bool_t *retry_open, nfs4_open_owner_t *oop,
12718 12718      bool_t resend, nfs4_error_t *ep, int *num_bseqid_retryp)
12719 12719  {
12720 12720          COMPOUND4args_clnt args;
12721 12721          COMPOUND4res_clnt res;
12722 12722          nfs_argop4 argop[2];
12723 12723          nfs_resop4 *resop;
12724 12724          int doqueue = 1;
12725 12725          mntinfo4_t *mi;
12726 12726          OPEN_CONFIRM4args *open_confirm_args;
12727 12727          int needrecov;
12728 12728  
12729 12729          ASSERT(nfs_zone() == VTOMI4(vp)->mi_zone);
12730 12730  #if DEBUG
12731 12731          mutex_enter(&oop->oo_lock);
12732 12732          ASSERT(oop->oo_seqid_inuse);
12733 12733          mutex_exit(&oop->oo_lock);
12734 12734  #endif
12735 12735  
12736 12736  recov_retry_confirm:
12737 12737          nfs4_error_zinit(ep);
12738 12738          *retry_open = FALSE;
12739 12739  
12740 12740          if (resend)
12741 12741                  args.ctag = TAG_OPEN_CONFIRM_LOST;
12742 12742          else
12743 12743                  args.ctag = TAG_OPEN_CONFIRM;
12744 12744  
12745 12745          args.array_len = 2;
12746 12746          args.array = argop;
12747 12747  
12748 12748          /* putfh target fh */
12749 12749          argop[0].argop = OP_CPUTFH;
12750 12750          argop[0].nfs_argop4_u.opcputfh.sfh = VTOR4(vp)->r_fh;
12751 12751  
12752 12752          argop[1].argop = OP_OPEN_CONFIRM;
12753 12753          open_confirm_args = &argop[1].nfs_argop4_u.opopen_confirm;
12754 12754  
12755 12755          (*seqid) += 1;
12756 12756          open_confirm_args->seqid = *seqid;
12757 12757          open_confirm_args->open_stateid = *stateid;
12758 12758  
12759 12759          mi = VTOMI4(vp);
12760 12760  
12761 12761          rfs4call(mi, &args, &res, cr, &doqueue, 0, ep);
12762 12762  
12763 12763          if (!ep->error && nfs4_need_to_bump_seqid(&res)) {
12764 12764                  nfs4_set_open_seqid((*seqid), oop, args.ctag);
12765 12765          }
12766 12766  
12767 12767          needrecov = nfs4_needs_recovery(ep, FALSE, mi->mi_vfsp);
12768 12768          if (!needrecov && ep->error)
12769 12769                  return;
12770 12770  
12771 12771          if (needrecov) {
12772 12772                  bool_t abort = FALSE;
12773 12773  
12774 12774                  if (reopening_file == FALSE) {
12775 12775                          nfs4_bseqid_entry_t *bsep = NULL;
12776 12776  
12777 12777                          if (!ep->error && res.status == NFS4ERR_BAD_SEQID)
12778 12778                                  bsep = nfs4_create_bseqid_entry(oop, NULL,
12779 12779                                      vp, 0, args.ctag,
12780 12780                                      open_confirm_args->seqid);
12781 12781  
12782 12782                          abort = nfs4_start_recovery(ep, VTOMI4(vp), vp, NULL,
12783 12783                              NULL, NULL, OP_OPEN_CONFIRM, bsep, NULL, NULL);
12784 12784                          if (bsep) {
12785 12785                                  kmem_free(bsep, sizeof (*bsep));
12786 12786                                  if (num_bseqid_retryp &&
12787 12787                                      --(*num_bseqid_retryp) == 0)
12788 12788                                          abort = TRUE;
12789 12789                          }
12790 12790                  }
12791 12791                  if ((ep->error == ETIMEDOUT ||
12792 12792                      res.status == NFS4ERR_RESOURCE) &&
12793 12793                      abort == FALSE && resend == FALSE) {
12794 12794                          if (!ep->error)
12795 12795                                  (void) xdr_free(xdr_COMPOUND4res_clnt,
12796 12796                                      (caddr_t)&res);
12797 12797  
12798 12798                          delay(SEC_TO_TICK(confirm_retry_sec));
12799 12799                          goto recov_retry_confirm;
12800 12800                  }
12801 12801                  /* State may have changed so retry the entire OPEN op */
12802 12802                  if (abort == FALSE)
12803 12803                          *retry_open = TRUE;
12804 12804                  else
12805 12805                          *retry_open = FALSE;
12806 12806                  if (!ep->error)
12807 12807                          (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
12808 12808                  return;
12809 12809          }
12810 12810  
12811 12811          if (res.status) {
12812 12812                  (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
12813 12813                  return;
12814 12814          }
12815 12815  
12816 12816          resop = &res.array[1];  /* open confirm res */
12817 12817          bcopy(&resop->nfs_resop4_u.opopen_confirm.open_stateid,
12818 12818              stateid, sizeof (*stateid));
12819 12819  
12820 12820          (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
12821 12821  }
12822 12822  
12823 12823  /*
12824 12824   * Return the credentials associated with a client state object.  The
12825 12825   * caller is responsible for freeing the credentials.
12826 12826   */
12827 12827  
12828 12828  static cred_t *
12829 12829  state_to_cred(nfs4_open_stream_t *osp)
12830 12830  {
12831 12831          cred_t *cr;
12832 12832  
12833 12833          /*
12834 12834           * It's ok to not lock the open stream and open owner to get
12835 12835           * the oo_cred since this is only written once (upon creation)
12836 12836           * and will not change.
12837 12837           */
12838 12838          cr = osp->os_open_owner->oo_cred;
12839 12839          crhold(cr);
12840 12840  
12841 12841          return (cr);
12842 12842  }
12843 12843  
12844 12844  /*
12845 12845   * nfs4_find_sysid
12846 12846   *
12847 12847   * Find the sysid for the knetconfig associated with the given mi.
12848 12848   */
12849 12849  static struct lm_sysid *
12850 12850  nfs4_find_sysid(mntinfo4_t *mi)
12851 12851  {
12852 12852          ASSERT(nfs_zone() == mi->mi_zone);
12853 12853  
12854 12854          /*
12855 12855           * Switch from RDMA knconf to original mount knconf
12856 12856           */
12857 12857          return (lm_get_sysid(ORIG_KNCONF(mi), &mi->mi_curr_serv->sv_addr,
12858 12858              mi->mi_curr_serv->sv_hostname, NULL));
12859 12859  }
12860 12860  
12861 12861  #ifdef DEBUG
12862 12862  /*
12863 12863   * Return a string version of the call type for easy reading.
12864 12864   */
12865 12865  static char *
12866 12866  nfs4frlock_get_call_type(nfs4_lock_call_type_t ctype)
12867 12867  {
12868 12868          switch (ctype) {
12869 12869          case NFS4_LCK_CTYPE_NORM:
12870 12870                  return ("NORMAL");
12871 12871          case NFS4_LCK_CTYPE_RECLAIM:
12872 12872                  return ("RECLAIM");
12873 12873          case NFS4_LCK_CTYPE_RESEND:
12874 12874                  return ("RESEND");
12875 12875          case NFS4_LCK_CTYPE_REINSTATE:
12876 12876                  return ("REINSTATE");
12877 12877          default:
12878 12878                  cmn_err(CE_PANIC, "nfs4frlock_get_call_type: got illegal "
12879 12879                      "type %d", ctype);
12880 12880                  return ("");
12881 12881          }
12882 12882  }
12883 12883  #endif
12884 12884  
12885 12885  /*
12886 12886   * Map the frlock cmd and lock type to the NFSv4 over-the-wire lock type
12887 12887   * Unlock requests don't have an over-the-wire locktype, so we just return
12888 12888   * something non-threatening.
12889 12889   */
12890 12890  
12891 12891  static nfs_lock_type4
12892 12892  flk_to_locktype(int cmd, int l_type)
12893 12893  {
12894 12894          ASSERT(l_type == F_RDLCK || l_type == F_WRLCK || l_type == F_UNLCK);
12895 12895  
12896 12896          switch (l_type) {
12897 12897          case F_UNLCK:
12898 12898                  return (READ_LT);
12899 12899          case F_RDLCK:
12900 12900                  if (cmd == F_SETLK)
12901 12901                          return (READ_LT);
12902 12902                  else
12903 12903                          return (READW_LT);
12904 12904          case F_WRLCK:
12905 12905                  if (cmd == F_SETLK)
12906 12906                          return (WRITE_LT);
12907 12907                  else
12908 12908                          return (WRITEW_LT);
12909 12909          }
12910 12910          panic("flk_to_locktype");
12911 12911          /*NOTREACHED*/
12912 12912  }
12913 12913  
12914 12914  /*
12915 12915   * Do some preliminary checks for nfs4frlock.
12916 12916   */
12917 12917  static int
12918 12918  nfs4frlock_validate_args(int cmd, flock64_t *flk, int flag, vnode_t *vp,
12919 12919      u_offset_t offset)
12920 12920  {
12921 12921          int error = 0;
12922 12922  
12923 12923          /*
12924 12924           * If we are setting a lock, check that the file is opened
12925 12925           * with the correct mode.
12926 12926           */
12927 12927          if (cmd == F_SETLK || cmd == F_SETLKW) {
12928 12928                  if ((flk->l_type == F_RDLCK && (flag & FREAD) == 0) ||
12929 12929                      (flk->l_type == F_WRLCK && (flag & FWRITE) == 0)) {
12930 12930                          NFS4_DEBUG(nfs4_client_lock_debug, (CE_NOTE,
12931 12931                              "nfs4frlock_validate_args: file was opened with "
12932 12932                              "incorrect mode"));
12933 12933                          return (EBADF);
12934 12934                  }
12935 12935          }
12936 12936  
12937 12937          /* Convert the offset. It may need to be restored before returning. */
12938 12938          if (error = convoff(vp, flk, 0, offset)) {
12939 12939                  NFS4_DEBUG(nfs4_client_lock_debug, (CE_NOTE,
12940 12940                      "nfs4frlock_validate_args: convoff  =>  error= %d\n",
12941 12941                      error));
12942 12942                  return (error);
12943 12943          }
12944 12944  
12945 12945          return (error);
12946 12946  }
12947 12947  
12948 12948  /*
12949 12949   * Set the flock64's lm_sysid for nfs4frlock.
12950 12950   */
12951 12951  static int
12952 12952  nfs4frlock_get_sysid(struct lm_sysid **lspp, vnode_t *vp, flock64_t *flk)
12953 12953  {
12954 12954          ASSERT(nfs_zone() == VTOMI4(vp)->mi_zone);
12955 12955  
12956 12956          /* Find the lm_sysid */
12957 12957          *lspp = nfs4_find_sysid(VTOMI4(vp));
12958 12958  
12959 12959          if (*lspp == NULL) {
12960 12960                  NFS4_DEBUG(nfs4_client_lock_debug, (CE_NOTE,
12961 12961                      "nfs4frlock_get_sysid: no sysid, return ENOLCK"));
12962 12962                  return (ENOLCK);
12963 12963          }
12964 12964  
12965 12965          flk->l_sysid = lm_sysidt(*lspp);
12966 12966  
12967 12967          return (0);
12968 12968  }
12969 12969  
12970 12970  /*
12971 12971   * Do the remaining preliminary setup for nfs4frlock.
12972 12972   */
12973 12973  static void
12974 12974  nfs4frlock_pre_setup(clock_t *tick_delayp, nfs4_recov_state_t *recov_statep,
12975 12975      flock64_t *flk, short *whencep, vnode_t *vp, cred_t *search_cr,
12976 12976      cred_t **cred_otw)
12977 12977  {
12978 12978          /*
12979 12979           * set tick_delay to the base delay time.
12980 12980           * (NFS4_BASE_WAIT_TIME is in secs)
12981 12981           */
12982 12982  
12983 12983          *tick_delayp = drv_usectohz(NFS4_BASE_WAIT_TIME * 1000 * 1000);
12984 12984  
12985 12985          /*
12986 12986           * If lock is relative to EOF, we need the newest length of the
12987 12987           * file. Therefore invalidate the ATTR_CACHE.
12988 12988           */
12989 12989  
12990 12990          *whencep = flk->l_whence;
12991 12991  
12992 12992          if (*whencep == 2)              /* SEEK_END */
12993 12993                  PURGE_ATTRCACHE4(vp);
12994 12994  
12995 12995          recov_statep->rs_flags = 0;
12996 12996          recov_statep->rs_num_retry_despite_err = 0;
12997 12997          *cred_otw = nfs4_get_otw_cred(search_cr, VTOMI4(vp), NULL);
12998 12998  }
12999 12999  
13000 13000  /*
13001 13001   * Initialize and allocate the data structures necessary for
13002 13002   * the nfs4frlock call.
13003 13003   * Allocates argsp's op array, frees up the saved_rqstpp if there is one.
13004 13004   */
13005 13005  static void
13006 13006  nfs4frlock_call_init(COMPOUND4args_clnt *argsp, COMPOUND4args_clnt **argspp,
13007 13007      nfs_argop4 **argopp, nfs4_op_hint_t *op_hintp, flock64_t *flk, int cmd,
13008 13008      bool_t *retry, bool_t *did_start_fop, COMPOUND4res_clnt **respp,
13009 13009      bool_t *skip_get_err, nfs4_lost_rqst_t *lost_rqstp)
13010 13010  {
13011 13011          int             argoplist_size;
13012 13012          int             num_ops = 2;
13013 13013  
13014 13014          *retry = FALSE;
13015 13015          *did_start_fop = FALSE;
13016 13016          *skip_get_err = FALSE;
13017 13017          lost_rqstp->lr_op = 0;
13018 13018          argoplist_size  = num_ops * sizeof (nfs_argop4);
13019 13019          /* fill array with zero */
13020 13020          *argopp = kmem_zalloc(argoplist_size, KM_SLEEP);
13021 13021  
13022 13022          *argspp = argsp;
13023 13023          *respp = NULL;
13024 13024  
13025 13025          argsp->array_len = num_ops;
13026 13026          argsp->array = *argopp;
13027 13027  
13028 13028          /* initialize in case of error; will get real value down below */
13029 13029          argsp->ctag = TAG_NONE;
13030 13030  
13031 13031          if ((cmd == F_SETLK || cmd == F_SETLKW) && flk->l_type == F_UNLCK)
13032 13032                  *op_hintp = OH_LOCKU;
13033 13033          else
13034 13034                  *op_hintp = OH_OTHER;
13035 13035  }
13036 13036  
13037 13037  /*
13038 13038   * Call the nfs4_start_fop() for nfs4frlock, if necessary.  Assign
13039 13039   * the proper nfs4_server_t for this instance of nfs4frlock.
13040 13040   * Returns 0 (success) or an errno value.
13041 13041   */
13042 13042  static int
13043 13043  nfs4frlock_start_call(nfs4_lock_call_type_t ctype, vnode_t *vp,
13044 13044      nfs4_op_hint_t op_hint, nfs4_recov_state_t *recov_statep,
13045 13045      bool_t *did_start_fop, bool_t *startrecovp)
13046 13046  {
13047 13047          int error = 0;
13048 13048          rnode4_t *rp;
13049 13049  
13050 13050          ASSERT(nfs_zone() == VTOMI4(vp)->mi_zone);
13051 13051  
13052 13052          if (ctype == NFS4_LCK_CTYPE_NORM) {
13053 13053                  error = nfs4_start_fop(VTOMI4(vp), vp, NULL, op_hint,
13054 13054                      recov_statep, startrecovp);
13055 13055                  if (error)
13056 13056                          return (error);
13057 13057                  *did_start_fop = TRUE;
13058 13058          } else {
13059 13059                  *did_start_fop = FALSE;
13060 13060                  *startrecovp = FALSE;
13061 13061          }
13062 13062  
13063 13063          if (!error) {
13064 13064                  rp = VTOR4(vp);
13065 13065  
13066 13066                  /* If the file failed recovery, just quit. */
13067 13067                  mutex_enter(&rp->r_statelock);
13068 13068                  if (rp->r_flags & R4RECOVERR) {
13069 13069                          error = EIO;
13070 13070                  }
13071 13071                  mutex_exit(&rp->r_statelock);
13072 13072          }
13073 13073  
13074 13074          return (error);
13075 13075  }
13076 13076  
13077 13077  /*
13078 13078   * Setup the LOCK4/LOCKU4 arguments for resending a lost lock request.  A
13079 13079   * resend nfs4frlock call is initiated by the recovery framework.
13080 13080   * Acquires the lop and oop seqid synchronization.
13081 13081   */
13082 13082  static void
13083 13083  nfs4frlock_setup_resend_lock_args(nfs4_lost_rqst_t *resend_rqstp,
13084 13084      COMPOUND4args_clnt *argsp, nfs_argop4 *argop, nfs4_lock_owner_t **lopp,
13085 13085      nfs4_open_owner_t **oopp, nfs4_open_stream_t **ospp,
13086 13086      LOCK4args **lock_argsp, LOCKU4args **locku_argsp)
13087 13087  {
13088 13088          mntinfo4_t *mi = VTOMI4(resend_rqstp->lr_vp);
13089 13089          int error;
13090 13090  
13091 13091          NFS4_DEBUG((nfs4_lost_rqst_debug || nfs4_client_lock_debug),
13092 13092              (CE_NOTE,
13093 13093              "nfs4frlock_setup_resend_lock_args: have lost lock to resend"));
13094 13094          ASSERT(resend_rqstp != NULL);
13095 13095          ASSERT(resend_rqstp->lr_op == OP_LOCK ||
13096 13096              resend_rqstp->lr_op == OP_LOCKU);
13097 13097  
13098 13098          *oopp = resend_rqstp->lr_oop;
13099 13099          if (resend_rqstp->lr_oop) {
13100 13100                  open_owner_hold(resend_rqstp->lr_oop);
13101 13101                  error = nfs4_start_open_seqid_sync(resend_rqstp->lr_oop, mi);
13102 13102                  ASSERT(error == 0);     /* recov thread always succeeds */
13103 13103          }
13104 13104  
13105 13105          /* Must resend this lost lock/locku request. */
13106 13106          ASSERT(resend_rqstp->lr_lop != NULL);
13107 13107          *lopp = resend_rqstp->lr_lop;
13108 13108          lock_owner_hold(resend_rqstp->lr_lop);
13109 13109          error = nfs4_start_lock_seqid_sync(resend_rqstp->lr_lop, mi);
13110 13110          ASSERT(error == 0);     /* recov thread always succeeds */
13111 13111  
13112 13112          *ospp = resend_rqstp->lr_osp;
13113 13113          if (*ospp)
13114 13114                  open_stream_hold(resend_rqstp->lr_osp);
13115 13115  
13116 13116          if (resend_rqstp->lr_op == OP_LOCK) {
13117 13117                  LOCK4args *lock_args;
13118 13118  
13119 13119                  argop->argop = OP_LOCK;
13120 13120                  *lock_argsp = lock_args = &argop->nfs_argop4_u.oplock;
13121 13121                  lock_args->locktype = resend_rqstp->lr_locktype;
13122 13122                  lock_args->reclaim =
13123 13123                      (resend_rqstp->lr_ctype == NFS4_LCK_CTYPE_RECLAIM);
13124 13124                  lock_args->offset = resend_rqstp->lr_flk->l_start;
13125 13125                  lock_args->length = resend_rqstp->lr_flk->l_len;
13126 13126                  if (lock_args->length == 0)
13127 13127                          lock_args->length = ~lock_args->length;
13128 13128                  nfs4_setup_lock_args(*lopp, *oopp, *ospp,
13129 13129                      mi2clientid(mi), &lock_args->locker);
13130 13130  
13131 13131                  switch (resend_rqstp->lr_ctype) {
13132 13132                  case NFS4_LCK_CTYPE_RESEND:
13133 13133                          argsp->ctag = TAG_LOCK_RESEND;
13134 13134                          break;
13135 13135                  case NFS4_LCK_CTYPE_REINSTATE:
13136 13136                          argsp->ctag = TAG_LOCK_REINSTATE;
13137 13137                          break;
13138 13138                  case NFS4_LCK_CTYPE_RECLAIM:
13139 13139                          argsp->ctag = TAG_LOCK_RECLAIM;
13140 13140                          break;
13141 13141                  default:
13142 13142                          argsp->ctag = TAG_LOCK_UNKNOWN;
13143 13143                          break;
13144 13144                  }
13145 13145          } else {
13146 13146                  LOCKU4args *locku_args;
13147 13147                  nfs4_lock_owner_t *lop = resend_rqstp->lr_lop;
13148 13148  
13149 13149                  argop->argop = OP_LOCKU;
13150 13150                  *locku_argsp = locku_args = &argop->nfs_argop4_u.oplocku;
13151 13151                  locku_args->locktype = READ_LT;
13152 13152                  locku_args->seqid = lop->lock_seqid + 1;
13153 13153                  mutex_enter(&lop->lo_lock);
13154 13154                  locku_args->lock_stateid = lop->lock_stateid;
13155 13155                  mutex_exit(&lop->lo_lock);
13156 13156                  locku_args->offset = resend_rqstp->lr_flk->l_start;
13157 13157                  locku_args->length = resend_rqstp->lr_flk->l_len;
13158 13158                  if (locku_args->length == 0)
13159 13159                          locku_args->length = ~locku_args->length;
13160 13160  
13161 13161                  switch (resend_rqstp->lr_ctype) {
13162 13162                  case NFS4_LCK_CTYPE_RESEND:
13163 13163                          argsp->ctag = TAG_LOCKU_RESEND;
13164 13164                          break;
13165 13165                  case NFS4_LCK_CTYPE_REINSTATE:
13166 13166                          argsp->ctag = TAG_LOCKU_REINSTATE;
13167 13167                          break;
13168 13168                  default:
13169 13169                          argsp->ctag = TAG_LOCK_UNKNOWN;
13170 13170                          break;
13171 13171                  }
13172 13172          }
13173 13173  }
13174 13174  
13175 13175  /*
13176 13176   * Setup the LOCKT4 arguments.
13177 13177   */
13178 13178  static void
13179 13179  nfs4frlock_setup_lockt_args(nfs4_lock_call_type_t ctype, nfs_argop4 *argop,
13180 13180      LOCKT4args **lockt_argsp, COMPOUND4args_clnt *argsp, flock64_t *flk,
13181 13181      rnode4_t *rp)
13182 13182  {
13183 13183          LOCKT4args *lockt_args;
13184 13184  
13185 13185          ASSERT(nfs_zone() == VTOMI4(RTOV4(rp))->mi_zone);
13186 13186          ASSERT(ctype == NFS4_LCK_CTYPE_NORM);
13187 13187          argop->argop = OP_LOCKT;
13188 13188          argsp->ctag = TAG_LOCKT;
13189 13189          lockt_args = &argop->nfs_argop4_u.oplockt;
13190 13190  
13191 13191          /*
13192 13192           * The locktype will be READ_LT unless it's
13193 13193           * a write lock. We do this because the Solaris
13194 13194           * system call allows the combination of
13195 13195           * F_UNLCK and F_GETLK* and so in that case the
13196 13196           * unlock is mapped to a read.
13197 13197           */
13198 13198          if (flk->l_type == F_WRLCK)
13199 13199                  lockt_args->locktype = WRITE_LT;
13200 13200          else
13201 13201                  lockt_args->locktype = READ_LT;
13202 13202  
13203 13203          lockt_args->owner.clientid = mi2clientid(VTOMI4(RTOV4(rp)));
13204 13204          /* set the lock owner4 args */
13205 13205          nfs4_setlockowner_args(&lockt_args->owner, rp,
13206 13206              ctype == NFS4_LCK_CTYPE_NORM ? curproc->p_pidp->pid_id :
13207 13207              flk->l_pid);
13208 13208          lockt_args->offset = flk->l_start;
13209 13209          lockt_args->length = flk->l_len;
13210 13210          if (flk->l_len == 0)
13211 13211                  lockt_args->length = ~lockt_args->length;
13212 13212  
13213 13213          *lockt_argsp = lockt_args;
13214 13214  }
13215 13215  
13216 13216  /*
13217 13217   * If the client is holding a delegation, and the open stream to be used
13218 13218   * with this lock request is a delegation open stream, then re-open the stream.
13219 13219   * Sets the nfs4_error_t to all zeros unless the open stream has already
13220 13220   * failed a reopen or we couldn't find the open stream.  NFS4ERR_DELAY
13221 13221   * means the caller should retry (like a recovery retry).
13222 13222   */
13223 13223  static void
13224 13224  nfs4frlock_check_deleg(vnode_t *vp, nfs4_error_t *ep, cred_t *cr, int lt)
13225 13225  {
13226 13226          open_delegation_type4   dt;
13227 13227          bool_t                  reopen_needed, force;
13228 13228          nfs4_open_stream_t      *osp;
13229 13229          open_claim_type4        oclaim;
13230 13230          rnode4_t                *rp = VTOR4(vp);
13231 13231          mntinfo4_t              *mi = VTOMI4(vp);
13232 13232  
13233 13233          ASSERT(nfs_zone() == mi->mi_zone);
13234 13234  
13235 13235          nfs4_error_zinit(ep);
13236 13236  
13237 13237          mutex_enter(&rp->r_statev4_lock);
13238 13238          dt = rp->r_deleg_type;
13239 13239          mutex_exit(&rp->r_statev4_lock);
13240 13240  
13241 13241          if (dt != OPEN_DELEGATE_NONE) {
13242 13242                  nfs4_open_owner_t       *oop;
13243 13243  
13244 13244                  oop = find_open_owner(cr, NFS4_PERM_CREATED, mi);
13245 13245                  if (!oop) {
13246 13246                          ep->stat = NFS4ERR_IO;
13247 13247                          return;
13248 13248                  }
13249 13249                  /* returns with 'os_sync_lock' held */
13250 13250                  osp = find_open_stream(oop, rp);
13251 13251                  if (!osp) {
13252 13252                          open_owner_rele(oop);
13253 13253                          ep->stat = NFS4ERR_IO;
13254 13254                          return;
13255 13255                  }
13256 13256  
13257 13257                  if (osp->os_failed_reopen) {
13258 13258                          NFS4_DEBUG((nfs4_open_stream_debug ||
13259 13259                              nfs4_client_lock_debug), (CE_NOTE,
13260 13260                              "nfs4frlock_check_deleg: os_failed_reopen set "
13261 13261                              "for osp %p, cr %p, rp %s", (void *)osp,
13262 13262                              (void *)cr, rnode4info(rp)));
13263 13263                          mutex_exit(&osp->os_sync_lock);
13264 13264                          open_stream_rele(osp, rp);
13265 13265                          open_owner_rele(oop);
13266 13266                          ep->stat = NFS4ERR_IO;
13267 13267                          return;
13268 13268                  }
13269 13269  
13270 13270                  /*
13271 13271                   * Determine whether a reopen is needed.  If this
13272 13272                   * is a delegation open stream, then send the open
13273 13273                   * to the server to give visibility to the open owner.
13274 13274                   * Even if it isn't a delegation open stream, we need
13275 13275                   * to check if the previous open CLAIM_DELEGATE_CUR
13276 13276                   * was sufficient.
13277 13277                   */
13278 13278  
13279 13279                  reopen_needed = osp->os_delegation ||
13280 13280                      ((lt == F_RDLCK &&
13281 13281                      !(osp->os_dc_openacc & OPEN4_SHARE_ACCESS_READ)) ||
13282 13282                      (lt == F_WRLCK &&
13283 13283                      !(osp->os_dc_openacc & OPEN4_SHARE_ACCESS_WRITE)));
13284 13284  
13285 13285                  mutex_exit(&osp->os_sync_lock);
13286 13286                  open_owner_rele(oop);
13287 13287  
13288 13288                  if (reopen_needed) {
13289 13289                          /*
13290 13290                           * Always use CLAIM_PREVIOUS after server reboot.
13291 13291                           * The server will reject CLAIM_DELEGATE_CUR if
13292 13292                           * it is used during the grace period.
13293 13293                           */
13294 13294                          mutex_enter(&mi->mi_lock);
13295 13295                          if (mi->mi_recovflags & MI4R_SRV_REBOOT) {
13296 13296                                  oclaim = CLAIM_PREVIOUS;
13297 13297                                  force = TRUE;
13298 13298                          } else {
13299 13299                                  oclaim = CLAIM_DELEGATE_CUR;
13300 13300                                  force = FALSE;
13301 13301                          }
13302 13302                          mutex_exit(&mi->mi_lock);
13303 13303  
13304 13304                          nfs4_reopen(vp, osp, ep, oclaim, force, FALSE);
13305 13305                          if (ep->error == EAGAIN) {
13306 13306                                  nfs4_error_zinit(ep);
13307 13307                                  ep->stat = NFS4ERR_DELAY;
13308 13308                          }
13309 13309                  }
13310 13310                  open_stream_rele(osp, rp);
13311 13311                  osp = NULL;
13312 13312          }
13313 13313  }
13314 13314  
13315 13315  /*
13316 13316   * Setup the LOCKU4 arguments.
13317 13317   * Returns errors via the nfs4_error_t.
13318 13318   * NFS4_OK              no problems.  *go_otwp is TRUE if call should go
13319 13319   *                      over-the-wire.  The caller must release the
13320 13320   *                      reference on *lopp.
13321 13321   * NFS4ERR_DELAY        caller should retry (like recovery retry)
13322 13322   * (other)              unrecoverable error.
13323 13323   */
13324 13324  static void
13325 13325  nfs4frlock_setup_locku_args(nfs4_lock_call_type_t ctype, nfs_argop4 *argop,
13326 13326      LOCKU4args **locku_argsp, flock64_t *flk,
13327 13327      nfs4_lock_owner_t **lopp, nfs4_error_t *ep, COMPOUND4args_clnt *argsp,
13328 13328      vnode_t *vp, int flag, u_offset_t offset, cred_t *cr,
13329 13329      bool_t *skip_get_err, bool_t *go_otwp)
13330 13330  {
13331 13331          nfs4_lock_owner_t       *lop = NULL;
13332 13332          LOCKU4args              *locku_args;
13333 13333          pid_t                   pid;
13334 13334          bool_t                  is_spec = FALSE;
13335 13335          rnode4_t                *rp = VTOR4(vp);
13336 13336  
13337 13337          ASSERT(nfs_zone() == VTOMI4(vp)->mi_zone);
13338 13338          ASSERT(ctype == NFS4_LCK_CTYPE_NORM);
13339 13339  
13340 13340          nfs4frlock_check_deleg(vp, ep, cr, F_UNLCK);
13341 13341          if (ep->error || ep->stat)
13342 13342                  return;
13343 13343  
13344 13344          argop->argop = OP_LOCKU;
13345 13345          if (ctype == NFS4_LCK_CTYPE_REINSTATE)
13346 13346                  argsp->ctag = TAG_LOCKU_REINSTATE;
13347 13347          else
13348 13348                  argsp->ctag = TAG_LOCKU;
13349 13349          locku_args = &argop->nfs_argop4_u.oplocku;
13350 13350          *locku_argsp = locku_args;
13351 13351  
13352 13352          /*
13353 13353           * XXX what should locku_args->locktype be?
13354 13354           * setting to ALWAYS be READ_LT so at least
13355 13355           * it is a valid locktype.
13356 13356           */
13357 13357  
13358 13358          locku_args->locktype = READ_LT;
13359 13359  
13360 13360          pid = ctype == NFS4_LCK_CTYPE_NORM ? curproc->p_pidp->pid_id :
13361 13361              flk->l_pid;
13362 13362  
13363 13363          /*
13364 13364           * Get the lock owner stateid.  If no lock owner
13365 13365           * exists, return success.
13366 13366           */
13367 13367          lop = find_lock_owner(rp, pid, LOWN_ANY);
13368 13368          *lopp = lop;
13369 13369          if (lop && CLNT_ISSPECIAL(&lop->lock_stateid))
13370 13370                  is_spec = TRUE;
13371 13371          if (!lop || is_spec) {
13372 13372                  /*
13373 13373                   * No lock owner so no locks to unlock.
13374 13374                   * Return success.  If there was a failed
13375 13375                   * reclaim earlier, the lock might still be
13376 13376                   * registered with the local locking code,
13377 13377                   * so notify it of the unlock.
13378 13378                   *
13379 13379                   * If the lockowner is using a special stateid,
13380 13380                   * then the original lock request (that created
13381 13381                   * this lockowner) was never successful, so we
13382 13382                   * have no lock to undo OTW.
13383 13383                   */
13384 13384                  NFS4_DEBUG(nfs4_client_lock_debug, (CE_NOTE,
13385 13385                      "nfs4frlock_setup_locku_args: LOCKU: no lock owner "
13386 13386                      "(%ld) so return success", (long)pid));
13387 13387  
13388 13388                  if (ctype == NFS4_LCK_CTYPE_NORM)
13389 13389                          flk->l_pid = curproc->p_pid;
13390 13390                  nfs4_register_lock_locally(vp, flk, flag, offset);
13391 13391                  /*
13392 13392                   * Release our hold and NULL out so final_cleanup
13393 13393                   * doesn't try to end a lock seqid sync we
13394 13394                   * never started.
13395 13395                   */
13396 13396                  if (is_spec) {
13397 13397                          lock_owner_rele(lop);
13398 13398                          *lopp = NULL;
13399 13399                  }
13400 13400                  *skip_get_err = TRUE;
13401 13401                  *go_otwp = FALSE;
13402 13402                  return;
13403 13403          }
13404 13404  
13405 13405          ep->error = nfs4_start_lock_seqid_sync(lop, VTOMI4(vp));
13406 13406          if (ep->error == EAGAIN) {
13407 13407                  lock_owner_rele(lop);
13408 13408                  *lopp = NULL;
13409 13409                  return;
13410 13410          }
13411 13411  
13412 13412          mutex_enter(&lop->lo_lock);
13413 13413          locku_args->lock_stateid = lop->lock_stateid;
13414 13414          mutex_exit(&lop->lo_lock);
13415 13415          locku_args->seqid = lop->lock_seqid + 1;
13416 13416  
13417 13417          /* leave the ref count on lop, rele after RPC call */
13418 13418  
13419 13419          locku_args->offset = flk->l_start;
13420 13420          locku_args->length = flk->l_len;
13421 13421          if (flk->l_len == 0)
13422 13422                  locku_args->length = ~locku_args->length;
13423 13423  
13424 13424          *go_otwp = TRUE;
13425 13425  }
13426 13426  
13427 13427  /*
13428 13428   * Setup the LOCK4 arguments.
13429 13429   *
13430 13430   * Returns errors via the nfs4_error_t.
13431 13431   * NFS4_OK              no problems
13432 13432   * NFS4ERR_DELAY        caller should retry (like recovery retry)
13433 13433   * (other)              unrecoverable error
13434 13434   */
13435 13435  static void
13436 13436  nfs4frlock_setup_lock_args(nfs4_lock_call_type_t ctype, LOCK4args **lock_argsp,
13437 13437      nfs4_open_owner_t **oopp, nfs4_open_stream_t **ospp,
13438 13438      nfs4_lock_owner_t **lopp, nfs_argop4 *argop, COMPOUND4args_clnt *argsp,
13439 13439      flock64_t *flk, int cmd, vnode_t *vp, cred_t *cr, nfs4_error_t *ep)
13440 13440  {
13441 13441          LOCK4args               *lock_args;
13442 13442          nfs4_open_owner_t       *oop = NULL;
13443 13443          nfs4_open_stream_t      *osp = NULL;
13444 13444          nfs4_lock_owner_t       *lop = NULL;
13445 13445          pid_t                   pid;
13446 13446          rnode4_t                *rp = VTOR4(vp);
13447 13447  
13448 13448          ASSERT(nfs_zone() == VTOMI4(vp)->mi_zone);
13449 13449  
13450 13450          nfs4frlock_check_deleg(vp, ep, cr, flk->l_type);
13451 13451          if (ep->error || ep->stat != NFS4_OK)
13452 13452                  return;
13453 13453  
13454 13454          argop->argop = OP_LOCK;
13455 13455          if (ctype == NFS4_LCK_CTYPE_NORM)
13456 13456                  argsp->ctag = TAG_LOCK;
13457 13457          else if (ctype == NFS4_LCK_CTYPE_RECLAIM)
13458 13458                  argsp->ctag = TAG_RELOCK;
13459 13459          else
13460 13460                  argsp->ctag = TAG_LOCK_REINSTATE;
13461 13461          lock_args = &argop->nfs_argop4_u.oplock;
13462 13462          lock_args->locktype = flk_to_locktype(cmd, flk->l_type);
13463 13463          lock_args->reclaim = ctype == NFS4_LCK_CTYPE_RECLAIM ? 1 : 0;
13464 13464          /*
13465 13465           * Get the lock owner.  If no lock owner exists,
13466 13466           * create a 'temporary' one and grab the open seqid
13467 13467           * synchronization (which puts a hold on the open
13468 13468           * owner and open stream).
13469 13469           * This also grabs the lock seqid synchronization.
13470 13470           */
13471 13471          pid = ctype == NFS4_LCK_CTYPE_NORM ? curproc->p_pid : flk->l_pid;
13472 13472          ep->stat =
13473 13473              nfs4_find_or_create_lock_owner(pid, rp, cr, &oop, &osp, &lop);
13474 13474  
13475 13475          if (ep->stat != NFS4_OK)
13476 13476                  goto out;
13477 13477  
13478 13478          nfs4_setup_lock_args(lop, oop, osp, mi2clientid(VTOMI4(vp)),
13479 13479              &lock_args->locker);
13480 13480  
13481 13481          lock_args->offset = flk->l_start;
13482 13482          lock_args->length = flk->l_len;
13483 13483          if (flk->l_len == 0)
13484 13484                  lock_args->length = ~lock_args->length;
13485 13485          *lock_argsp = lock_args;
13486 13486  out:
13487 13487          *oopp = oop;
13488 13488          *ospp = osp;
13489 13489          *lopp = lop;
13490 13490  }
13491 13491  
13492 13492  /*
13493 13493   * After we get the reply from the server, record the proper information
13494 13494   * for possible resend lock requests.
13495 13495   *
13496 13496   * Allocates memory for the saved_rqstp if we have a lost lock to save.
13497 13497   */
13498 13498  static void
13499 13499  nfs4frlock_save_lost_rqst(nfs4_lock_call_type_t ctype, int error,
13500 13500      nfs_lock_type4 locktype, nfs4_open_owner_t *oop,
13501 13501      nfs4_open_stream_t *osp, nfs4_lock_owner_t *lop, flock64_t *flk,
13502 13502      nfs4_lost_rqst_t *lost_rqstp, cred_t *cr, vnode_t *vp)
13503 13503  {
13504 13504          bool_t unlock = (flk->l_type == F_UNLCK);
13505 13505  
13506 13506          ASSERT(nfs_zone() == VTOMI4(vp)->mi_zone);
13507 13507          ASSERT(ctype == NFS4_LCK_CTYPE_NORM ||
13508 13508              ctype == NFS4_LCK_CTYPE_REINSTATE);
13509 13509  
13510 13510          if (error != 0 && !unlock) {
13511 13511                  NFS4_DEBUG((nfs4_lost_rqst_debug ||
13512 13512                      nfs4_client_lock_debug), (CE_NOTE,
13513 13513                      "nfs4frlock_save_lost_rqst: set lo_pending_rqsts to 1 "
13514 13514                      " for lop %p", (void *)lop));
13515 13515                  ASSERT(lop != NULL);
13516 13516                  mutex_enter(&lop->lo_lock);
13517 13517                  lop->lo_pending_rqsts = 1;
13518 13518                  mutex_exit(&lop->lo_lock);
13519 13519          }
13520 13520  
13521 13521          lost_rqstp->lr_putfirst = FALSE;
13522 13522          lost_rqstp->lr_op = 0;
13523 13523  
13524 13524          /*
13525 13525           * For lock/locku requests, we treat EINTR as ETIMEDOUT for
13526 13526           * recovery purposes so that the lock request that was sent
13527 13527           * can be saved and re-issued later.  Ditto for EIO from a forced
13528 13528           * unmount.  This is done to have the client's local locking state
13529 13529           * match the v4 server's state; that is, the request was
13530 13530           * potentially received and accepted by the server but the client
13531 13531           * thinks it was not.
13532 13532           */
13533 13533          if (error == ETIMEDOUT || error == EINTR ||
13534 13534              NFS4_FRC_UNMT_ERR(error, vp->v_vfsp)) {
13535 13535                  NFS4_DEBUG((nfs4_lost_rqst_debug ||
13536 13536                      nfs4_client_lock_debug), (CE_NOTE,
13537 13537                      "nfs4frlock_save_lost_rqst: got a lost %s lock for "
13538 13538                      "lop %p oop %p osp %p", unlock ? "LOCKU" : "LOCK",
13539 13539                      (void *)lop, (void *)oop, (void *)osp));
13540 13540                  if (unlock)
13541 13541                          lost_rqstp->lr_op = OP_LOCKU;
13542 13542                  else {
13543 13543                          lost_rqstp->lr_op = OP_LOCK;
13544 13544                          lost_rqstp->lr_locktype = locktype;
13545 13545                  }
13546 13546                  /*
13547 13547                   * Objects are held and rele'd via the recovery code.
13548 13548                   * See nfs4_save_lost_rqst.
13549 13549                   */
13550 13550                  lost_rqstp->lr_vp = vp;
13551 13551                  lost_rqstp->lr_dvp = NULL;
13552 13552                  lost_rqstp->lr_oop = oop;
13553 13553                  lost_rqstp->lr_osp = osp;
13554 13554                  lost_rqstp->lr_lop = lop;
13555 13555                  lost_rqstp->lr_cr = cr;
13556 13556                  switch (ctype) {
13557 13557                  case NFS4_LCK_CTYPE_NORM:
13558 13558                          flk->l_pid = ttoproc(curthread)->p_pid;
13559 13559                          lost_rqstp->lr_ctype = NFS4_LCK_CTYPE_RESEND;
13560 13560                          break;
13561 13561                  case NFS4_LCK_CTYPE_REINSTATE:
13562 13562                          lost_rqstp->lr_putfirst = TRUE;
13563 13563                          lost_rqstp->lr_ctype = ctype;
13564 13564                          break;
13565 13565                  default:
13566 13566                          break;
13567 13567                  }
13568 13568                  lost_rqstp->lr_flk = flk;
13569 13569          }
13570 13570  }
13571 13571  
13572 13572  /*
13573 13573   * Update lop's seqid.  Also update the seqid stored in a resend request,
13574 13574   * if any.  (Some recovery errors increment the seqid, and we may have to
13575 13575   * send the resend request again.)
13576 13576   */
13577 13577  
13578 13578  static void
13579 13579  nfs4frlock_bump_seqid(LOCK4args *lock_args, LOCKU4args *locku_args,
13580 13580      nfs4_open_owner_t *oop, nfs4_lock_owner_t *lop, nfs4_tag_type_t tag_type)
13581 13581  {
13582 13582          if (lock_args) {
13583 13583                  if (lock_args->locker.new_lock_owner == TRUE)
13584 13584                          nfs4_get_and_set_next_open_seqid(oop, tag_type);
13585 13585                  else {
13586 13586                          ASSERT(lop->lo_flags & NFS4_LOCK_SEQID_INUSE);
13587 13587                          nfs4_set_lock_seqid(lop->lock_seqid + 1, lop);
13588 13588                  }
13589 13589          } else if (locku_args) {
13590 13590                  ASSERT(lop->lo_flags & NFS4_LOCK_SEQID_INUSE);
13591 13591                  nfs4_set_lock_seqid(lop->lock_seqid +1, lop);
13592 13592          }
13593 13593  }
13594 13594  
13595 13595  /*
13596 13596   * Calls nfs4_end_fop, drops the seqid syncs, and frees up the
13597 13597   * COMPOUND4 args/res for calls that need to retry.
13598 13598   * Switches the *cred_otwp to base_cr.
13599 13599   */
13600 13600  static void
13601 13601  nfs4frlock_check_access(vnode_t *vp, nfs4_op_hint_t op_hint,
13602 13602      nfs4_recov_state_t *recov_statep, int needrecov, bool_t *did_start_fop,
13603 13603      COMPOUND4args_clnt **argspp, COMPOUND4res_clnt **respp, int error,
13604 13604      nfs4_lock_owner_t **lopp, nfs4_open_owner_t **oopp,
13605 13605      nfs4_open_stream_t **ospp, cred_t *base_cr, cred_t **cred_otwp)
13606 13606  {
13607 13607          nfs4_open_owner_t       *oop = *oopp;
13608 13608          nfs4_open_stream_t      *osp = *ospp;
13609 13609          nfs4_lock_owner_t       *lop = *lopp;
13610 13610          nfs_argop4              *argop = (*argspp)->array;
13611 13611  
13612 13612          if (*did_start_fop) {
13613 13613                  nfs4_end_fop(VTOMI4(vp), vp, NULL, op_hint, recov_statep,
13614 13614                      needrecov);
13615 13615                  *did_start_fop = FALSE;
13616 13616          }
13617 13617          ASSERT((*argspp)->array_len == 2);
13618 13618          if (argop[1].argop == OP_LOCK)
13619 13619                  nfs4args_lock_free(&argop[1]);
13620 13620          else if (argop[1].argop == OP_LOCKT)
13621 13621                  nfs4args_lockt_free(&argop[1]);
13622 13622          kmem_free(argop, 2 * sizeof (nfs_argop4));
13623 13623          if (!error)
13624 13624                  (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)*respp);
13625 13625          *argspp = NULL;
13626 13626          *respp = NULL;
13627 13627  
13628 13628          if (lop) {
13629 13629                  nfs4_end_lock_seqid_sync(lop);
13630 13630                  lock_owner_rele(lop);
13631 13631                  *lopp = NULL;
13632 13632          }
13633 13633  
13634 13634          /* need to free up the reference on osp for lock args */
13635 13635          if (osp != NULL) {
13636 13636                  open_stream_rele(osp, VTOR4(vp));
13637 13637                  *ospp = NULL;
13638 13638          }
13639 13639  
13640 13640          /* need to free up the reference on oop for lock args */
13641 13641          if (oop != NULL) {
13642 13642                  nfs4_end_open_seqid_sync(oop);
13643 13643                  open_owner_rele(oop);
13644 13644                  *oopp = NULL;
13645 13645          }
13646 13646  
13647 13647          crfree(*cred_otwp);
13648 13648          *cred_otwp = base_cr;
13649 13649          crhold(*cred_otwp);
13650 13650  }
13651 13651  
13652 13652  /*
13653 13653   * Function to process the client's recovery for nfs4frlock.
13654 13654   * Returns TRUE if we should retry the lock request; FALSE otherwise.
13655 13655   *
13656 13656   * Calls nfs4_end_fop, drops the seqid syncs, and frees up the
13657 13657   * COMPOUND4 args/res for calls that need to retry.
13658 13658   *
13659 13659   * Note: the rp's r_lkserlock is *not* dropped during this path.
13660 13660   */
13661 13661  static bool_t
13662 13662  nfs4frlock_recovery(int needrecov, nfs4_error_t *ep,
13663 13663      COMPOUND4args_clnt **argspp, COMPOUND4res_clnt **respp,
13664 13664      LOCK4args *lock_args, LOCKU4args *locku_args,
13665 13665      nfs4_open_owner_t **oopp, nfs4_open_stream_t **ospp,
13666 13666      nfs4_lock_owner_t **lopp, rnode4_t *rp, vnode_t *vp,
13667 13667      nfs4_recov_state_t *recov_statep, nfs4_op_hint_t op_hint,
13668 13668      bool_t *did_start_fop, nfs4_lost_rqst_t *lost_rqstp, flock64_t *flk)
13669 13669  {
13670 13670          nfs4_open_owner_t       *oop = *oopp;
13671 13671          nfs4_open_stream_t      *osp = *ospp;
13672 13672          nfs4_lock_owner_t       *lop = *lopp;
13673 13673  
13674 13674          bool_t abort, retry;
13675 13675  
13676 13676          ASSERT(nfs_zone() == VTOMI4(vp)->mi_zone);
13677 13677          ASSERT((*argspp) != NULL);
13678 13678          ASSERT((*respp) != NULL);
13679 13679          if (lock_args || locku_args)
13680 13680                  ASSERT(lop != NULL);
13681 13681  
13682 13682          NFS4_DEBUG((nfs4_client_lock_debug || nfs4_client_recov_debug),
13683 13683              (CE_NOTE, "nfs4frlock_recovery: initiating recovery\n"));
13684 13684  
13685 13685          retry = TRUE;
13686 13686          abort = FALSE;
13687 13687          if (needrecov) {
13688 13688                  nfs4_bseqid_entry_t *bsep = NULL;
13689 13689                  nfs_opnum4 op;
13690 13690  
13691 13691                  op = lock_args ? OP_LOCK : locku_args ? OP_LOCKU : OP_LOCKT;
13692 13692  
13693 13693                  if (!ep->error && ep->stat == NFS4ERR_BAD_SEQID) {
13694 13694                          seqid4 seqid;
13695 13695  
13696 13696                          if (lock_args) {
13697 13697                                  if (lock_args->locker.new_lock_owner == TRUE)
13698 13698                                          seqid = lock_args->locker.locker4_u.
13699 13699                                              open_owner.open_seqid;
13700 13700                                  else
13701 13701                                          seqid = lock_args->locker.locker4_u.
13702 13702                                              lock_owner.lock_seqid;
13703 13703                          } else if (locku_args) {
13704 13704                                  seqid = locku_args->seqid;
13705 13705                          } else {
13706 13706                                  seqid = 0;
13707 13707                          }
13708 13708  
13709 13709                          bsep = nfs4_create_bseqid_entry(oop, lop, vp,
13710 13710                              flk->l_pid, (*argspp)->ctag, seqid);
13711 13711                  }
13712 13712  
13713 13713                  abort = nfs4_start_recovery(ep, VTOMI4(vp), vp, NULL, NULL,
13714 13714                      (lost_rqstp && (lost_rqstp->lr_op == OP_LOCK ||
13715 13715                      lost_rqstp->lr_op == OP_LOCKU)) ? lost_rqstp :
13716 13716                      NULL, op, bsep, NULL, NULL);
13717 13717  
13718 13718                  if (bsep)
13719 13719                          kmem_free(bsep, sizeof (*bsep));
13720 13720          }
13721 13721  
13722 13722          /*
13723 13723           * Return that we do not want to retry the request for 3 cases:
13724 13724           * 1. If we received EINTR or are bailing out because of a forced
13725 13725           *    unmount, we came into this code path just for the sake of
13726 13726           *    initiating recovery, we now need to return the error.
13727 13727           * 2. If we have aborted recovery.
13728 13728           * 3. We received NFS4ERR_BAD_SEQID.
13729 13729           */
13730 13730          if (ep->error == EINTR || NFS4_FRC_UNMT_ERR(ep->error, vp->v_vfsp) ||
13731 13731              abort == TRUE || (ep->error == 0 && ep->stat == NFS4ERR_BAD_SEQID))
13732 13732                  retry = FALSE;
13733 13733  
13734 13734          if (*did_start_fop == TRUE) {
13735 13735                  nfs4_end_fop(VTOMI4(vp), vp, NULL, op_hint, recov_statep,
13736 13736                      needrecov);
13737 13737                  *did_start_fop = FALSE;
13738 13738          }
13739 13739  
13740 13740          if (retry == TRUE) {
13741 13741                  nfs_argop4      *argop;
13742 13742  
13743 13743                  argop = (*argspp)->array;
13744 13744                  ASSERT((*argspp)->array_len == 2);
13745 13745  
13746 13746                  if (argop[1].argop == OP_LOCK)
13747 13747                          nfs4args_lock_free(&argop[1]);
13748 13748                  else if (argop[1].argop == OP_LOCKT)
13749 13749                          nfs4args_lockt_free(&argop[1]);
13750 13750                  kmem_free(argop, 2 * sizeof (nfs_argop4));
13751 13751                  if (!ep->error)
13752 13752                          (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)*respp);
13753 13753                  *respp = NULL;
13754 13754                  *argspp = NULL;
13755 13755          }
13756 13756  
13757 13757          if (lop != NULL) {
13758 13758                  nfs4_end_lock_seqid_sync(lop);
13759 13759                  lock_owner_rele(lop);
13760 13760          }
13761 13761  
13762 13762          *lopp = NULL;
13763 13763  
13764 13764          /* need to free up the reference on osp for lock args */
13765 13765          if (osp != NULL) {
13766 13766                  open_stream_rele(osp, rp);
13767 13767                  *ospp = NULL;
13768 13768          }
13769 13769  
13770 13770          /* need to free up the reference on oop for lock args */
13771 13771          if (oop != NULL) {
13772 13772                  nfs4_end_open_seqid_sync(oop);
13773 13773                  open_owner_rele(oop);
13774 13774                  *oopp = NULL;
13775 13775          }
13776 13776  
13777 13777          return (retry);
13778 13778  }
13779 13779  
13780 13780  /*
13781 13781   * Handles the successful reply from the server for nfs4frlock.
13782 13782   */
13783 13783  static void
13784 13784  nfs4frlock_results_ok(nfs4_lock_call_type_t ctype, int cmd, flock64_t *flk,
13785 13785      vnode_t *vp, int flag, u_offset_t offset,
13786 13786      nfs4_lost_rqst_t *resend_rqstp)
13787 13787  {
13788 13788          ASSERT(nfs_zone() == VTOMI4(vp)->mi_zone);
13789 13789          if ((cmd == F_SETLK || cmd == F_SETLKW) &&
13790 13790              (flk->l_type == F_RDLCK || flk->l_type == F_WRLCK)) {
13791 13791                  if (ctype == NFS4_LCK_CTYPE_NORM) {
13792 13792                          flk->l_pid = ttoproc(curthread)->p_pid;
13793 13793                          /*
13794 13794                           * We do not register lost locks locally in
13795 13795                           * the 'resend' case since the user/application
13796 13796                           * doesn't think we have the lock.
13797 13797                           */
13798 13798                          ASSERT(!resend_rqstp);
13799 13799                          nfs4_register_lock_locally(vp, flk, flag, offset);
13800 13800                  }
13801 13801          }
13802 13802  }
13803 13803  
13804 13804  /*
13805 13805   * Handle the DENIED reply from the server for nfs4frlock.
13806 13806   * Returns TRUE if we should retry the request; FALSE otherwise.
13807 13807   *
13808 13808   * Calls nfs4_end_fop, drops the seqid syncs, and frees up the
13809 13809   * COMPOUND4 args/res for calls that need to retry.  Can also
13810 13810   * drop and regrab the r_lkserlock.
13811 13811   */
13812 13812  static bool_t
13813 13813  nfs4frlock_results_denied(nfs4_lock_call_type_t ctype, LOCK4args *lock_args,
13814 13814      LOCKT4args *lockt_args, nfs4_open_owner_t **oopp,
13815 13815      nfs4_open_stream_t **ospp, nfs4_lock_owner_t **lopp, int cmd,
13816 13816      vnode_t *vp, flock64_t *flk, nfs4_op_hint_t op_hint,
13817 13817      nfs4_recov_state_t *recov_statep, int needrecov,
13818 13818      COMPOUND4args_clnt **argspp, COMPOUND4res_clnt **respp,
13819 13819      clock_t *tick_delayp, short *whencep, int *errorp,
13820 13820      nfs_resop4 *resop, cred_t *cr, bool_t *did_start_fop,
13821 13821      bool_t *skip_get_err)
13822 13822  {
13823 13823          ASSERT(nfs_zone() == VTOMI4(vp)->mi_zone);
13824 13824  
13825 13825          if (lock_args) {
13826 13826                  nfs4_open_owner_t       *oop = *oopp;
13827 13827                  nfs4_open_stream_t      *osp = *ospp;
13828 13828                  nfs4_lock_owner_t       *lop = *lopp;
13829 13829                  int                     intr;
13830 13830  
13831 13831                  /*
13832 13832                   * Blocking lock needs to sleep and retry from the request.
13833 13833                   *
13834 13834                   * Do not block and wait for 'resend' or 'reinstate'
13835 13835                   * lock requests, just return the error.
13836 13836                   *
13837 13837                   * Note: reclaim requests have cmd == F_SETLK, not F_SETLKW.
13838 13838                   */
13839 13839                  if (cmd == F_SETLKW) {
13840 13840                          rnode4_t *rp = VTOR4(vp);
13841 13841                          nfs_argop4 *argop = (*argspp)->array;
13842 13842  
13843 13843                          ASSERT(ctype == NFS4_LCK_CTYPE_NORM);
13844 13844  
13845 13845                          nfs4_end_fop(VTOMI4(vp), vp, NULL, op_hint,
13846 13846                              recov_statep, needrecov);
13847 13847                          *did_start_fop = FALSE;
13848 13848                          ASSERT((*argspp)->array_len == 2);
13849 13849                          if (argop[1].argop == OP_LOCK)
13850 13850                                  nfs4args_lock_free(&argop[1]);
13851 13851                          else if (argop[1].argop == OP_LOCKT)
13852 13852                                  nfs4args_lockt_free(&argop[1]);
13853 13853                          kmem_free(argop, 2 * sizeof (nfs_argop4));
13854 13854                          if (*respp)
13855 13855                                  (void) xdr_free(xdr_COMPOUND4res_clnt,
13856 13856                                      (caddr_t)*respp);
13857 13857                          *argspp = NULL;
13858 13858                          *respp = NULL;
13859 13859                          nfs4_end_lock_seqid_sync(lop);
13860 13860                          lock_owner_rele(lop);
13861 13861                          *lopp = NULL;
13862 13862                          if (osp != NULL) {
13863 13863                                  open_stream_rele(osp, rp);
13864 13864                                  *ospp = NULL;
13865 13865                          }
13866 13866                          if (oop != NULL) {
13867 13867                                  nfs4_end_open_seqid_sync(oop);
13868 13868                                  open_owner_rele(oop);
13869 13869                                  *oopp = NULL;
13870 13870                          }
13871 13871  
13872 13872                          nfs_rw_exit(&rp->r_lkserlock);
13873 13873  
13874 13874                          intr = nfs4_block_and_wait(tick_delayp, rp);
13875 13875  
13876 13876                          if (intr) {
13877 13877                                  (void) nfs_rw_enter_sig(&rp->r_lkserlock,
13878 13878                                      RW_WRITER, FALSE);
13879 13879                                  *errorp = EINTR;
13880 13880                                  return (FALSE);
13881 13881                          }
13882 13882  
13883 13883                          (void) nfs_rw_enter_sig(&rp->r_lkserlock,
13884 13884                              RW_WRITER, FALSE);
13885 13885  
13886 13886                          /*
13887 13887                           * Make sure we are still safe to lock with
13888 13888                           * regards to mmapping.
13889 13889                           */
13890 13890                          if (!nfs4_safelock(vp, flk, cr)) {
13891 13891                                  *errorp = EAGAIN;
13892 13892                                  return (FALSE);
13893 13893                          }
13894 13894  
13895 13895                          return (TRUE);
13896 13896                  }
13897 13897                  if (ctype == NFS4_LCK_CTYPE_NORM)
13898 13898                          *errorp = EAGAIN;
13899 13899                  *skip_get_err = TRUE;
13900 13900                  flk->l_whence = 0;
13901 13901                  *whencep = 0;
13902 13902                  return (FALSE);
13903 13903          } else if (lockt_args) {
13904 13904                  NFS4_DEBUG(nfs4_client_lock_debug, (CE_NOTE,
13905 13905                      "nfs4frlock_results_denied: OP_LOCKT DENIED"));
13906 13906  
13907 13907                  denied_to_flk(&resop->nfs_resop4_u.oplockt.denied,
13908 13908                      flk, lockt_args);
13909 13909  
13910 13910                  /* according to NLM code */
13911 13911                  *errorp = 0;
13912 13912                  *whencep = 0;
13913 13913                  *skip_get_err = TRUE;
13914 13914                  return (FALSE);
13915 13915          }
13916 13916          return (FALSE);
13917 13917  }
13918 13918  
13919 13919  /*
13920 13920   * Handles all NFS4 errors besides NFS4_OK and NFS4ERR_DENIED for nfs4frlock.
13921 13921   */
13922 13922  static void
13923 13923  nfs4frlock_results_default(COMPOUND4res_clnt *resp, int *errorp)
13924 13924  {
13925 13925          switch (resp->status) {
13926 13926          case NFS4ERR_ACCESS:
13927 13927          case NFS4ERR_ADMIN_REVOKED:
13928 13928          case NFS4ERR_BADHANDLE:
13929 13929          case NFS4ERR_BAD_RANGE:
13930 13930          case NFS4ERR_BAD_SEQID:
13931 13931          case NFS4ERR_BAD_STATEID:
13932 13932          case NFS4ERR_BADXDR:
13933 13933          case NFS4ERR_DEADLOCK:
13934 13934          case NFS4ERR_DELAY:
13935 13935          case NFS4ERR_EXPIRED:
13936 13936          case NFS4ERR_FHEXPIRED:
13937 13937          case NFS4ERR_GRACE:
13938 13938          case NFS4ERR_INVAL:
13939 13939          case NFS4ERR_ISDIR:
13940 13940          case NFS4ERR_LEASE_MOVED:
13941 13941          case NFS4ERR_LOCK_NOTSUPP:
13942 13942          case NFS4ERR_LOCK_RANGE:
13943 13943          case NFS4ERR_MOVED:
13944 13944          case NFS4ERR_NOFILEHANDLE:
13945 13945          case NFS4ERR_NO_GRACE:
13946 13946          case NFS4ERR_OLD_STATEID:
13947 13947          case NFS4ERR_OPENMODE:
13948 13948          case NFS4ERR_RECLAIM_BAD:
13949 13949          case NFS4ERR_RECLAIM_CONFLICT:
13950 13950          case NFS4ERR_RESOURCE:
13951 13951          case NFS4ERR_SERVERFAULT:
13952 13952          case NFS4ERR_STALE:
13953 13953          case NFS4ERR_STALE_CLIENTID:
13954 13954          case NFS4ERR_STALE_STATEID:
13955 13955                  return;
13956 13956          default:
13957 13957                  NFS4_DEBUG(nfs4_client_lock_debug, (CE_NOTE,
13958 13958                      "nfs4frlock_results_default: got unrecognizable "
13959 13959                      "res.status %d", resp->status));
13960 13960                  *errorp = NFS4ERR_INVAL;
13961 13961          }
13962 13962  }
13963 13963  
13964 13964  /*
13965 13965   * The lock request was successful, so update the client's state.
13966 13966   */
13967 13967  static void
13968 13968  nfs4frlock_update_state(LOCK4args *lock_args, LOCKU4args *locku_args,
13969 13969      LOCKT4args *lockt_args, nfs_resop4 *resop, nfs4_lock_owner_t *lop,
13970 13970      vnode_t *vp, flock64_t *flk, cred_t *cr,
13971 13971      nfs4_lost_rqst_t *resend_rqstp)
13972 13972  {
13973 13973          ASSERT(nfs_zone() == VTOMI4(vp)->mi_zone);
13974 13974  
13975 13975          if (lock_args) {
13976 13976                  LOCK4res *lock_res;
13977 13977  
13978 13978                  lock_res = &resop->nfs_resop4_u.oplock;
13979 13979                  /* update the stateid with server's response */
13980 13980  
13981 13981                  if (lock_args->locker.new_lock_owner == TRUE) {
13982 13982                          mutex_enter(&lop->lo_lock);
13983 13983                          lop->lo_just_created = NFS4_PERM_CREATED;
13984 13984                          mutex_exit(&lop->lo_lock);
13985 13985                  }
13986 13986  
13987 13987                  nfs4_set_lock_stateid(lop, lock_res->LOCK4res_u.lock_stateid);
13988 13988  
13989 13989                  /*
13990 13990                   * If the lock was the result of a resending a lost
13991 13991                   * request, we've synched up the stateid and seqid
13992 13992                   * with the server, but now the server might be out of sync
13993 13993                   * with what the application thinks it has for locks.
13994 13994                   * Clean that up here.  It's unclear whether we should do
13995 13995                   * this even if the filesystem has been forcibly unmounted.
13996 13996                   * For most servers, it's probably wasted effort, but
13997 13997                   * RFC3530 lets servers require that unlocks exactly match
13998 13998                   * the locks that are held.
13999 13999                   */
14000 14000                  if (resend_rqstp != NULL &&
14001 14001                      resend_rqstp->lr_ctype != NFS4_LCK_CTYPE_REINSTATE) {
14002 14002                          nfs4_reinstitute_local_lock_state(vp, flk, cr, lop);
14003 14003                  } else {
14004 14004                          flk->l_whence = 0;
14005 14005                  }
14006 14006          } else if (locku_args) {
14007 14007                  LOCKU4res *locku_res;
14008 14008  
14009 14009                  locku_res = &resop->nfs_resop4_u.oplocku;
14010 14010  
14011 14011                  /* Update the stateid with the server's response */
14012 14012                  nfs4_set_lock_stateid(lop, locku_res->lock_stateid);
14013 14013          } else if (lockt_args) {
14014 14014                  /* Switch the lock type to express success, see fcntl */
14015 14015                  flk->l_type = F_UNLCK;
14016 14016                  flk->l_whence = 0;
14017 14017          }
14018 14018  }
14019 14019  
14020 14020  /*
14021 14021   * Do final cleanup before exiting nfs4frlock.
14022 14022   * Calls nfs4_end_fop, drops the seqid syncs, and frees up the
14023 14023   * COMPOUND4 args/res for calls that haven't already.
14024 14024   */
14025 14025  static void
14026 14026  nfs4frlock_final_cleanup(nfs4_lock_call_type_t ctype, COMPOUND4args_clnt *argsp,
14027 14027      COMPOUND4res_clnt *resp, vnode_t *vp, nfs4_op_hint_t op_hint,
14028 14028      nfs4_recov_state_t *recov_statep, int needrecov, nfs4_open_owner_t *oop,
14029 14029      nfs4_open_stream_t *osp, nfs4_lock_owner_t *lop, flock64_t *flk,
14030 14030      short whence, u_offset_t offset, struct lm_sysid *ls,
14031 14031      int *errorp, LOCK4args *lock_args, LOCKU4args *locku_args,
14032 14032      bool_t did_start_fop, bool_t skip_get_err,
14033 14033      cred_t *cred_otw, cred_t *cred)
14034 14034  {
14035 14035          mntinfo4_t      *mi = VTOMI4(vp);
14036 14036          rnode4_t        *rp = VTOR4(vp);
14037 14037          int             error = *errorp;
14038 14038          nfs_argop4      *argop;
14039 14039          int     do_flush_pages = 0;
14040 14040  
14041 14041          ASSERT(nfs_zone() == mi->mi_zone);
14042 14042          /*
14043 14043           * The client recovery code wants the raw status information,
14044 14044           * so don't map the NFS status code to an errno value for
14045 14045           * non-normal call types.
14046 14046           */
14047 14047          if (ctype == NFS4_LCK_CTYPE_NORM) {
14048 14048                  if (*errorp == 0 && resp != NULL && skip_get_err == FALSE)
14049 14049                          *errorp = geterrno4(resp->status);
14050 14050                  if (did_start_fop == TRUE)
14051 14051                          nfs4_end_fop(mi, vp, NULL, op_hint, recov_statep,
14052 14052                              needrecov);
14053 14053  
14054 14054                  /*
14055 14055                   * We've established a new lock on the server, so invalidate
14056 14056                   * the pages associated with the vnode to get the most up to
14057 14057                   * date pages from the server after acquiring the lock. We
14058 14058                   * want to be sure that the read operation gets the newest data.
14059 14059                   * N.B.
14060 14060                   * We used to do this in nfs4frlock_results_ok but that doesn't
14061 14061                   * work since VOP_PUTPAGE can call nfs4_commit which calls
14062 14062                   * nfs4_start_fop. We flush the pages below after calling
14063 14063                   * nfs4_end_fop above
14064 14064                   * The flush of the page cache must be done after
14065 14065                   * nfs4_end_open_seqid_sync() to avoid a 4-way hang.
14066 14066                   */
14067 14067                  if (!error && resp && resp->status == NFS4_OK)
14068 14068                          do_flush_pages = 1;
14069 14069          }
14070 14070          if (argsp) {
14071 14071                  ASSERT(argsp->array_len == 2);
14072 14072                  argop = argsp->array;
14073 14073                  if (argop[1].argop == OP_LOCK)
14074 14074                          nfs4args_lock_free(&argop[1]);
14075 14075                  else if (argop[1].argop == OP_LOCKT)
14076 14076                          nfs4args_lockt_free(&argop[1]);
14077 14077                  kmem_free(argop, 2 * sizeof (nfs_argop4));
14078 14078                  if (resp)
14079 14079                          (void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)resp);
14080 14080          }
14081 14081  
14082 14082          /* free the reference on the lock owner */
14083 14083          if (lop != NULL) {
14084 14084                  nfs4_end_lock_seqid_sync(lop);
14085 14085                  lock_owner_rele(lop);
14086 14086          }
14087 14087  
14088 14088          /* need to free up the reference on osp for lock args */
14089 14089          if (osp != NULL)
14090 14090                  open_stream_rele(osp, rp);
14091 14091  
14092 14092          /* need to free up the reference on oop for lock args */
14093 14093          if (oop != NULL) {
14094 14094                  nfs4_end_open_seqid_sync(oop);
14095 14095                  open_owner_rele(oop);
14096 14096          }
14097 14097  
14098 14098          if (do_flush_pages)
14099 14099                  nfs4_flush_pages(vp, cred);
14100 14100  
14101 14101          (void) convoff(vp, flk, whence, offset);
14102 14102  
14103 14103          lm_rel_sysid(ls);
14104 14104  
14105 14105          /*
14106 14106           * Record debug information in the event we get EINVAL.
14107 14107           */
14108 14108          mutex_enter(&mi->mi_lock);
14109 14109          if (*errorp == EINVAL && (lock_args || locku_args) &&
14110 14110              (!(mi->mi_flags & MI4_POSIX_LOCK))) {
14111 14111                  if (!(mi->mi_flags & MI4_LOCK_DEBUG)) {
14112 14112                          zcmn_err(getzoneid(), CE_NOTE,
14113 14113                              "%s operation failed with "
14114 14114                              "EINVAL probably since the server, %s,"
14115 14115                              " doesn't support POSIX style locking",
14116 14116                              lock_args ? "LOCK" : "LOCKU",
14117 14117                              mi->mi_curr_serv->sv_hostname);
14118 14118                          mi->mi_flags |= MI4_LOCK_DEBUG;
14119 14119                  }
14120 14120          }
14121 14121          mutex_exit(&mi->mi_lock);
14122 14122  
14123 14123          if (cred_otw)
14124 14124                  crfree(cred_otw);
14125 14125  }
14126 14126  
14127 14127  /*
14128 14128   * This calls the server and the local locking code.
14129 14129   *
14130 14130   * Client locks are registerred locally by oring the sysid with
14131 14131   * LM_SYSID_CLIENT. The server registers locks locally using just the sysid.
14132 14132   * We need to distinguish between the two to avoid collision in case one
14133 14133   * machine is used as both client and server.
14134 14134   *
14135 14135   * Blocking lock requests will continually retry to acquire the lock
14136 14136   * forever.
14137 14137   *
14138 14138   * The ctype is defined as follows:
14139 14139   * NFS4_LCK_CTYPE_NORM: normal lock request.
14140 14140   *
14141 14141   * NFS4_LCK_CTYPE_RECLAIM:  bypass the usual calls for synchronizing with client
14142 14142   * recovery, get the pid from flk instead of curproc, and don't reregister
14143 14143   * the lock locally.
14144 14144   *
14145 14145   * NFS4_LCK_CTYPE_RESEND: same as NFS4_LCK_CTYPE_RECLAIM, with the addition
14146 14146   * that we will use the information passed in via resend_rqstp to setup the
14147 14147   * lock/locku request.  This resend is the exact same request as the 'lost
14148 14148   * lock', and is initiated by the recovery framework. A successful resend
14149 14149   * request can initiate one or more reinstate requests.
14150 14150   *
14151 14151   * NFS4_LCK_CTYPE_REINSTATE: same as NFS4_LCK_CTYPE_RESEND, except that it
14152 14152   * does not trigger additional reinstate requests.  This lock call type is
14153 14153   * set for setting the v4 server's locking state back to match what the
14154 14154   * client's local locking state is in the event of a received 'lost lock'.
14155 14155   *
14156 14156   * Errors are returned via the nfs4_error_t parameter.
14157 14157   */
14158 14158  void
14159 14159  nfs4frlock(nfs4_lock_call_type_t ctype, vnode_t *vp, int cmd, flock64_t *flk,
14160 14160      int flag, u_offset_t offset, cred_t *cr, nfs4_error_t *ep,
14161 14161      nfs4_lost_rqst_t *resend_rqstp, int *did_reclaimp)
14162 14162  {
14163 14163          COMPOUND4args_clnt      args, *argsp = NULL;
14164 14164          COMPOUND4res_clnt       res, *resp = NULL;
14165 14165          nfs_argop4      *argop;
14166 14166          nfs_resop4      *resop;
14167 14167          rnode4_t        *rp;
14168 14168          int             doqueue = 1;
14169 14169          clock_t         tick_delay;  /* delay in clock ticks */
14170 14170          struct lm_sysid *ls;
14171 14171          LOCK4args       *lock_args = NULL;
14172 14172          LOCKU4args      *locku_args = NULL;
14173 14173          LOCKT4args      *lockt_args = NULL;
14174 14174          nfs4_open_owner_t *oop = NULL;
14175 14175          nfs4_open_stream_t *osp = NULL;
14176 14176          nfs4_lock_owner_t *lop = NULL;
14177 14177          bool_t          needrecov = FALSE;
14178 14178          nfs4_recov_state_t recov_state;
14179 14179          short           whence;
14180 14180          nfs4_op_hint_t  op_hint;
14181 14181          nfs4_lost_rqst_t lost_rqst;
14182 14182          bool_t          retry = FALSE;
14183 14183          bool_t          did_start_fop = FALSE;
14184 14184          bool_t          skip_get_err = FALSE;
14185 14185          cred_t          *cred_otw = NULL;
14186 14186          bool_t          recovonly;      /* just queue request */
14187 14187          int             frc_no_reclaim = 0;
14188 14188  #ifdef DEBUG
14189 14189          char *name;
14190 14190  #endif
14191 14191  
14192 14192          ASSERT(nfs_zone() == VTOMI4(vp)->mi_zone);
14193 14193  
14194 14194  #ifdef DEBUG
14195 14195          name = fn_name(VTOSV(vp)->sv_name);
14196 14196          NFS4_DEBUG(nfs4_client_lock_debug, (CE_NOTE, "nfs4frlock: "
14197 14197              "%s: cmd %d, type %d, offset %llu, start %"PRIx64", "
14198 14198              "length %"PRIu64", pid %d, sysid %d, call type %s, "
14199 14199              "resend request %s", name, cmd, flk->l_type, offset, flk->l_start,
14200 14200              flk->l_len, ctype == NFS4_LCK_CTYPE_NORM ? curproc->p_pid :
14201 14201              flk->l_pid, flk->l_sysid, nfs4frlock_get_call_type(ctype),
14202 14202              resend_rqstp ? "TRUE" : "FALSE"));
14203 14203          kmem_free(name, MAXNAMELEN);
14204 14204  #endif
14205 14205  
14206 14206          nfs4_error_zinit(ep);
14207 14207          ep->error = nfs4frlock_validate_args(cmd, flk, flag, vp, offset);
14208 14208          if (ep->error)
14209 14209                  return;
14210 14210          ep->error = nfs4frlock_get_sysid(&ls, vp, flk);
14211 14211          if (ep->error)
14212 14212                  return;
14213 14213          nfs4frlock_pre_setup(&tick_delay, &recov_state, flk, &whence,
14214 14214              vp, cr, &cred_otw);
14215 14215  
14216 14216  recov_retry:
14217 14217          nfs4frlock_call_init(&args, &argsp, &argop, &op_hint, flk, cmd,
14218 14218              &retry, &did_start_fop, &resp, &skip_get_err, &lost_rqst);
14219 14219          rp = VTOR4(vp);
14220 14220  
14221 14221          ep->error = nfs4frlock_start_call(ctype, vp, op_hint, &recov_state,
14222 14222              &did_start_fop, &recovonly);
14223 14223  
14224 14224          if (ep->error)
14225 14225                  goto out;
14226 14226  
14227 14227          if (recovonly) {
14228 14228                  /*
14229 14229                   * Leave the request for the recovery system to deal with.
14230 14230                   */
14231 14231                  ASSERT(ctype == NFS4_LCK_CTYPE_NORM);
14232 14232                  ASSERT(cmd != F_GETLK);
14233 14233                  ASSERT(flk->l_type == F_UNLCK);
14234 14234  
14235 14235                  nfs4_error_init(ep, EINTR);
14236 14236                  needrecov = TRUE;
14237 14237                  lop = find_lock_owner(rp, curproc->p_pid, LOWN_ANY);
14238 14238                  if (lop != NULL) {
14239 14239                          nfs4frlock_save_lost_rqst(ctype, ep->error, READ_LT,
14240 14240                              NULL, NULL, lop, flk, &lost_rqst, cr, vp);
14241 14241                          (void) nfs4_start_recovery(ep,
14242 14242                              VTOMI4(vp), vp, NULL, NULL,
14243 14243                              (lost_rqst.lr_op == OP_LOCK ||
14244 14244                              lost_rqst.lr_op == OP_LOCKU) ?
14245 14245                              &lost_rqst : NULL, OP_LOCKU, NULL, NULL, NULL);
14246 14246                          lock_owner_rele(lop);
14247 14247                          lop = NULL;
14248 14248                  }
14249 14249                  flk->l_pid = curproc->p_pid;
14250 14250                  nfs4_register_lock_locally(vp, flk, flag, offset);
14251 14251                  goto out;
14252 14252          }
14253 14253  
14254 14254          /* putfh directory fh */
14255 14255          argop[0].argop = OP_CPUTFH;
14256 14256          argop[0].nfs_argop4_u.opcputfh.sfh = rp->r_fh;
14257 14257  
14258 14258          /*
14259 14259           * Set up the over-the-wire arguments and get references to the
14260 14260           * open owner, etc.
14261 14261           */
14262 14262  
14263 14263          if (ctype == NFS4_LCK_CTYPE_RESEND ||
14264 14264              ctype == NFS4_LCK_CTYPE_REINSTATE) {
14265 14265                  nfs4frlock_setup_resend_lock_args(resend_rqstp, argsp,
14266 14266                      &argop[1], &lop, &oop, &osp, &lock_args, &locku_args);
14267 14267          } else {
14268 14268                  bool_t go_otw = TRUE;
14269 14269  
14270 14270                  ASSERT(resend_rqstp == NULL);
14271 14271  
14272 14272                  switch (cmd) {
14273 14273                  case F_GETLK:
14274 14274                  case F_O_GETLK:
14275 14275                          nfs4frlock_setup_lockt_args(ctype, &argop[1],
14276 14276                              &lockt_args, argsp, flk, rp);
14277 14277                          break;
14278 14278                  case F_SETLKW:
14279 14279                  case F_SETLK:
14280 14280                          if (flk->l_type == F_UNLCK)
14281 14281                                  nfs4frlock_setup_locku_args(ctype,
14282 14282                                      &argop[1], &locku_args, flk,
14283 14283                                      &lop, ep, argsp,
14284 14284                                      vp, flag, offset, cr,
14285 14285                                      &skip_get_err, &go_otw);
14286 14286                          else
14287 14287                                  nfs4frlock_setup_lock_args(ctype,
14288 14288                                      &lock_args, &oop, &osp, &lop, &argop[1],
14289 14289                                      argsp, flk, cmd, vp, cr, ep);
14290 14290  
14291 14291                          if (ep->error)
14292 14292                                  goto out;
14293 14293  
14294 14294                          switch (ep->stat) {
14295 14295                          case NFS4_OK:
14296 14296                                  break;
14297 14297                          case NFS4ERR_DELAY:
14298 14298                                  /* recov thread never gets this error */
14299 14299                                  ASSERT(resend_rqstp == NULL);
14300 14300                                  ASSERT(did_start_fop);
14301 14301  
14302 14302                                  nfs4_end_fop(VTOMI4(vp), vp, NULL, op_hint,
14303 14303                                      &recov_state, TRUE);
14304 14304                                  did_start_fop = FALSE;
14305 14305                                  if (argop[1].argop == OP_LOCK)
14306 14306                                          nfs4args_lock_free(&argop[1]);
14307 14307                                  else if (argop[1].argop == OP_LOCKT)
14308 14308                                          nfs4args_lockt_free(&argop[1]);
14309 14309                                  kmem_free(argop, 2 * sizeof (nfs_argop4));
14310 14310                                  argsp = NULL;
14311 14311                                  goto recov_retry;
14312 14312                          default:
14313 14313                                  ep->error = EIO;
14314 14314                                  goto out;
14315 14315                          }
14316 14316                          break;
14317 14317                  default:
14318 14318                          NFS4_DEBUG(nfs4_client_lock_debug, (CE_NOTE,
14319 14319                              "nfs4_frlock: invalid cmd %d", cmd));
14320 14320                          ep->error = EINVAL;
14321 14321                          goto out;
14322 14322                  }
14323 14323  
14324 14324                  if (!go_otw)
14325 14325                          goto out;
14326 14326          }
14327 14327  
14328 14328          /* XXX should we use the local reclock as a cache ? */
14329 14329          /*
14330 14330           * Unregister the lock with the local locking code before
14331 14331           * contacting the server.  This avoids a potential race where
14332 14332           * another process gets notified that it has been granted a lock
14333 14333           * before we can unregister ourselves locally.
14334 14334           */
14335 14335          if ((cmd == F_SETLK || cmd == F_SETLKW) && flk->l_type == F_UNLCK) {
14336 14336                  if (ctype == NFS4_LCK_CTYPE_NORM)
14337 14337                          flk->l_pid = ttoproc(curthread)->p_pid;
14338 14338                  nfs4_register_lock_locally(vp, flk, flag, offset);
14339 14339          }
14340 14340  
14341 14341          /*
14342 14342           * Send the server the lock request.  Continually loop with a delay
14343 14343           * if get error NFS4ERR_DENIED (for blocking locks) or NFS4ERR_GRACE.
14344 14344           */
14345 14345          resp = &res;
14346 14346  
14347 14347          NFS4_DEBUG((nfs4_client_call_debug || nfs4_client_lock_debug),
14348 14348              (CE_NOTE,
14349 14349              "nfs4frlock: %s call, rp %s", needrecov ? "recov" : "first",
14350 14350              rnode4info(rp)));
14351 14351  
14352 14352          if (lock_args && frc_no_reclaim) {
14353 14353                  ASSERT(ctype == NFS4_LCK_CTYPE_RECLAIM);
14354 14354                  NFS4_DEBUG(nfs4_client_lock_debug, (CE_NOTE,
14355 14355                      "nfs4frlock: frc_no_reclaim: clearing reclaim"));
14356 14356                  lock_args->reclaim = FALSE;
14357 14357                  if (did_reclaimp)
14358 14358                          *did_reclaimp = 0;
14359 14359          }
14360 14360  
14361 14361          /*
14362 14362           * Do the OTW call.
14363 14363           */
14364 14364          rfs4call(VTOMI4(vp), argsp, resp, cred_otw, &doqueue, 0, ep);
14365 14365  
14366 14366          NFS4_DEBUG(nfs4_client_lock_debug, (CE_NOTE,
14367 14367              "nfs4frlock: error %d, status %d", ep->error, resp->status));
14368 14368  
14369 14369          needrecov = nfs4_needs_recovery(ep, TRUE, vp->v_vfsp);
14370 14370          NFS4_DEBUG(nfs4_client_lock_debug, (CE_NOTE,
14371 14371              "nfs4frlock: needrecov %d", needrecov));
14372 14372  
14373 14373          if (ep->error == 0 && nfs4_need_to_bump_seqid(resp))
14374 14374                  nfs4frlock_bump_seqid(lock_args, locku_args, oop, lop,
14375 14375                      args.ctag);
14376 14376  
14377 14377          /*
14378 14378           * Check if one of these mutually exclusive error cases has
14379 14379           * happened:
14380 14380           *   need to swap credentials due to access error
14381 14381           *   recovery is needed
14382 14382           *   different error (only known case is missing Kerberos ticket)
14383 14383           */
14384 14384  
14385 14385          if ((ep->error == EACCES ||
14386 14386              (ep->error == 0 && resp->status == NFS4ERR_ACCESS)) &&
14387 14387              cred_otw != cr) {
14388 14388                  nfs4frlock_check_access(vp, op_hint, &recov_state, needrecov,
14389 14389                      &did_start_fop, &argsp, &resp, ep->error, &lop, &oop, &osp,
14390 14390                      cr, &cred_otw);
14391 14391                  goto recov_retry;
14392 14392          }
14393 14393  
14394 14394          if (needrecov) {
14395 14395                  /*
14396 14396                   * LOCKT requests don't need to recover from lost
14397 14397                   * requests since they don't create/modify state.
14398 14398                   */
14399 14399                  if ((ep->error == EINTR ||
14400 14400                      NFS4_FRC_UNMT_ERR(ep->error, vp->v_vfsp)) &&
14401 14401                      lockt_args)
14402 14402                          goto out;
14403 14403                  /*
14404 14404                   * Do not attempt recovery for requests initiated by
14405 14405                   * the recovery framework.  Let the framework redrive them.
14406 14406                   */
14407 14407                  if (ctype != NFS4_LCK_CTYPE_NORM)
14408 14408                          goto out;
14409 14409                  else {
14410 14410                          ASSERT(resend_rqstp == NULL);
14411 14411                  }
14412 14412  
14413 14413                  nfs4frlock_save_lost_rqst(ctype, ep->error,
14414 14414                      flk_to_locktype(cmd, flk->l_type),
14415 14415                      oop, osp, lop, flk, &lost_rqst, cred_otw, vp);
14416 14416  
14417 14417                  retry = nfs4frlock_recovery(needrecov, ep, &argsp,
14418 14418                      &resp, lock_args, locku_args, &oop, &osp, &lop,
14419 14419                      rp, vp, &recov_state, op_hint, &did_start_fop,
14420 14420                      cmd != F_GETLK ? &lost_rqst : NULL, flk);
14421 14421  
14422 14422                  if (retry) {
14423 14423                          ASSERT(oop == NULL);
14424 14424                          ASSERT(osp == NULL);
14425 14425                          ASSERT(lop == NULL);
14426 14426                          goto recov_retry;
14427 14427                  }
14428 14428                  goto out;
14429 14429          }
14430 14430  
14431 14431          /*
14432 14432           * Bail out if have reached this point with ep->error set. Can
14433 14433           * happen if (ep->error == EACCES && !needrecov && cred_otw == cr).
14434 14434           * This happens if Kerberos ticket has expired or has been
14435 14435           * destroyed.
14436 14436           */
14437 14437          if (ep->error != 0)
14438 14438                  goto out;
14439 14439  
14440 14440          /*
14441 14441           * Process the reply.
14442 14442           */
14443 14443          switch (resp->status) {
14444 14444          case NFS4_OK:
14445 14445                  resop = &resp->array[1];
14446 14446                  nfs4frlock_results_ok(ctype, cmd, flk, vp, flag, offset,
14447 14447                      resend_rqstp);
14448 14448                  /*
14449 14449                   * Have a successful lock operation, now update state.
14450 14450                   */
14451 14451                  nfs4frlock_update_state(lock_args, locku_args, lockt_args,
14452 14452                      resop, lop, vp, flk, cr, resend_rqstp);
14453 14453                  break;
14454 14454  
14455 14455          case NFS4ERR_DENIED:
14456 14456                  resop = &resp->array[1];
14457 14457                  retry = nfs4frlock_results_denied(ctype, lock_args, lockt_args,
14458 14458                      &oop, &osp, &lop, cmd, vp, flk, op_hint,
14459 14459                      &recov_state, needrecov, &argsp, &resp,
14460 14460                      &tick_delay, &whence, &ep->error, resop, cr,
14461 14461                      &did_start_fop, &skip_get_err);
14462 14462  
14463 14463                  if (retry) {
14464 14464                          ASSERT(oop == NULL);
14465 14465                          ASSERT(osp == NULL);
14466 14466                          ASSERT(lop == NULL);
14467 14467                          goto recov_retry;
14468 14468                  }
14469 14469                  break;
14470 14470          /*
14471 14471           * If the server won't let us reclaim, fall-back to trying to lock
14472 14472           * the file from scratch. Code elsewhere will check the changeinfo
14473 14473           * to ensure the file hasn't been changed.
14474 14474           */
14475 14475          case NFS4ERR_NO_GRACE:
14476 14476                  if (lock_args && lock_args->reclaim == TRUE) {
14477 14477                          ASSERT(ctype == NFS4_LCK_CTYPE_RECLAIM);
14478 14478                          NFS4_DEBUG(nfs4_client_lock_debug, (CE_NOTE,
14479 14479                              "nfs4frlock: reclaim: NFS4ERR_NO_GRACE"));
14480 14480                          frc_no_reclaim = 1;
14481 14481                          /* clean up before retrying */
14482 14482                          needrecov = 0;
14483 14483                          (void) nfs4frlock_recovery(needrecov, ep, &argsp, &resp,
14484 14484                              lock_args, locku_args, &oop, &osp, &lop, rp, vp,
14485 14485                              &recov_state, op_hint, &did_start_fop, NULL, flk);
14486 14486                          goto recov_retry;
14487 14487                  }
14488 14488                  /* FALLTHROUGH */
14489 14489  
14490 14490          default:
14491 14491                  nfs4frlock_results_default(resp, &ep->error);
14492 14492                  break;
14493 14493          }
14494 14494  out:
14495 14495          /*
14496 14496           * Process and cleanup from error.  Make interrupted unlock
14497 14497           * requests look successful, since they will be handled by the
14498 14498           * client recovery code.
14499 14499           */
14500 14500          nfs4frlock_final_cleanup(ctype, argsp, resp, vp, op_hint, &recov_state,
14501 14501              needrecov, oop, osp, lop, flk, whence, offset, ls, &ep->error,
14502 14502              lock_args, locku_args, did_start_fop,
14503 14503              skip_get_err, cred_otw, cr);
14504 14504  
14505 14505          if (ep->error == EINTR && flk->l_type == F_UNLCK &&
14506 14506              (cmd == F_SETLK || cmd == F_SETLKW))
14507 14507                  ep->error = 0;
14508 14508  }
14509 14509  
14510 14510  /*
14511 14511   * nfs4_safelock:
14512 14512   *
14513 14513   * Return non-zero if the given lock request can be handled without
14514 14514   * violating the constraints on concurrent mapping and locking.
14515 14515   */
14516 14516  
14517 14517  static int
14518 14518  nfs4_safelock(vnode_t *vp, const struct flock64 *bfp, cred_t *cr)
14519 14519  {
14520 14520          rnode4_t *rp = VTOR4(vp);
14521 14521          struct vattr va;
14522 14522          int error;
14523 14523  
14524 14524          ASSERT(nfs_zone() == VTOMI4(vp)->mi_zone);
14525 14525          ASSERT(rp->r_mapcnt >= 0);
14526 14526          NFS4_DEBUG(nfs4_client_lock_debug, (CE_NOTE, "nfs4_safelock %s: "
14527 14527              "(%"PRIx64", %"PRIx64"); mapcnt = %ld", bfp->l_type == F_WRLCK ?
14528 14528              "write" : bfp->l_type == F_RDLCK ? "read" : "unlock",
14529 14529              bfp->l_start, bfp->l_len, rp->r_mapcnt));
14530 14530  
14531 14531          if (rp->r_mapcnt == 0)
14532 14532                  return (1);             /* always safe if not mapped */
14533 14533  
14534 14534          /*
14535 14535           * If the file is already mapped and there are locks, then they
14536 14536           * should be all safe locks.  So adding or removing a lock is safe
14537 14537           * as long as the new request is safe (i.e., whole-file, meaning
14538 14538           * length and starting offset are both zero).
14539 14539           */
14540 14540  
14541 14541          if (bfp->l_start != 0 || bfp->l_len != 0) {
14542 14542                  NFS4_DEBUG(nfs4_client_lock_debug, (CE_NOTE, "nfs4_safelock: "
14543 14543                      "cannot lock a memory mapped file unless locking the "
14544 14544                      "entire file: start %"PRIx64", len %"PRIx64,
14545 14545                      bfp->l_start, bfp->l_len));
14546 14546                  return (0);
14547 14547          }
14548 14548  
14549 14549          /* mandatory locking and mapping don't mix */
14550 14550          va.va_mask = AT_MODE;
14551 14551          error = VOP_GETATTR(vp, &va, 0, cr, NULL);
14552 14552          if (error != 0) {
14553 14553                  NFS4_DEBUG(nfs4_client_lock_debug, (CE_NOTE, "nfs4_safelock: "
14554 14554                      "getattr error %d", error));
14555 14555                  return (0);             /* treat errors conservatively */
14556 14556          }
14557 14557          if (MANDLOCK(vp, va.va_mode)) {
14558 14558                  NFS4_DEBUG(nfs4_client_lock_debug, (CE_NOTE, "nfs4_safelock: "
14559 14559                      "cannot mandatory lock and mmap a file"));
14560 14560                  return (0);
14561 14561          }
14562 14562  
14563 14563          return (1);
14564 14564  }
14565 14565  
14566 14566  
14567 14567  /*
14568 14568   * Register the lock locally within Solaris.
14569 14569   * As the client, we "or" the sysid with LM_SYSID_CLIENT when
14570 14570   * recording locks locally.
14571 14571   *
14572 14572   * This should handle conflicts/cooperation with NFS v2/v3 since all locks
14573 14573   * are registered locally.
14574 14574   */
14575 14575  void
14576 14576  nfs4_register_lock_locally(vnode_t *vp, struct flock64 *flk, int flag,
14577 14577      u_offset_t offset)
14578 14578  {
14579 14579          int oldsysid;
14580 14580          int error;
14581 14581  #ifdef DEBUG
14582 14582          char *name;
14583 14583  #endif
14584 14584  
14585 14585          ASSERT(nfs_zone() == VTOMI4(vp)->mi_zone);
14586 14586  
14587 14587  #ifdef DEBUG
14588 14588          name = fn_name(VTOSV(vp)->sv_name);
14589 14589          NFS4_DEBUG(nfs4_client_lock_debug,
14590 14590              (CE_NOTE, "nfs4_register_lock_locally: %s: type %d, "
14591 14591              "start %"PRIx64", length %"PRIx64", pid %ld, sysid %d",
14592 14592              name, flk->l_type, flk->l_start, flk->l_len, (long)flk->l_pid,
14593 14593              flk->l_sysid));
14594 14594          kmem_free(name, MAXNAMELEN);
14595 14595  #endif
14596 14596  
14597 14597          /* register the lock with local locking */
14598 14598          oldsysid = flk->l_sysid;
14599 14599          flk->l_sysid |= LM_SYSID_CLIENT;
14600 14600          error = reclock(vp, flk, SETFLCK, flag, offset, NULL);
14601 14601  #ifdef DEBUG
14602 14602          if (error != 0) {
14603 14603                  NFS4_DEBUG(nfs4_client_lock_debug, (CE_NOTE,
14604 14604                      "nfs4_register_lock_locally: could not register with"
14605 14605                      " local locking"));
14606 14606                  NFS4_DEBUG(nfs4_client_lock_debug, (CE_CONT,
14607 14607                      "error %d, vp 0x%p, pid %d, sysid 0x%x",
14608 14608                      error, (void *)vp, flk->l_pid, flk->l_sysid));
14609 14609                  NFS4_DEBUG(nfs4_client_lock_debug, (CE_CONT,
14610 14610                      "type %d off 0x%" PRIx64 " len 0x%" PRIx64,
14611 14611                      flk->l_type, flk->l_start, flk->l_len));
14612 14612                  (void) reclock(vp, flk, 0, flag, offset, NULL);
14613 14613                  NFS4_DEBUG(nfs4_client_lock_debug, (CE_CONT,
14614 14614                      "blocked by pid %d sysid 0x%x type %d "
14615 14615                      "off 0x%" PRIx64 " len 0x%" PRIx64,
14616 14616                      flk->l_pid, flk->l_sysid, flk->l_type, flk->l_start,
14617 14617                      flk->l_len));
14618 14618          }
14619 14619  #endif
14620 14620          flk->l_sysid = oldsysid;
14621 14621  }
14622 14622  
14623 14623  /*
14624 14624   * nfs4_lockrelease:
14625 14625   *
14626 14626   * Release any locks on the given vnode that are held by the current
14627 14627   * process.  Also removes the lock owner (if one exists) from the rnode's
14628 14628   * list.
14629 14629   */
14630 14630  static int
14631 14631  nfs4_lockrelease(vnode_t *vp, int flag, offset_t offset, cred_t *cr)
14632 14632  {
14633 14633          flock64_t ld;
14634 14634          int ret, error;
14635 14635          rnode4_t *rp;
14636 14636          nfs4_lock_owner_t *lop;
14637 14637          nfs4_recov_state_t recov_state;
14638 14638          mntinfo4_t *mi;
14639 14639          bool_t possible_orphan = FALSE;
14640 14640          bool_t recovonly;
14641 14641  
14642 14642          ASSERT((uintptr_t)vp > KERNELBASE);
14643 14643          ASSERT(nfs_zone() == VTOMI4(vp)->mi_zone);
14644 14644  
14645 14645          rp = VTOR4(vp);
14646 14646          mi = VTOMI4(vp);
14647 14647  
14648 14648          /*
14649 14649           * If we have not locked anything then we can
14650 14650           * just return since we have no work to do.
14651 14651           */
14652 14652          if (rp->r_lo_head.lo_next_rnode == &rp->r_lo_head) {
14653 14653                  return (0);
14654 14654          }
14655 14655  
14656 14656          /*
14657 14657           * We need to comprehend that another thread may
14658 14658           * kick off recovery and the lock_owner we have stashed
14659 14659           * in lop might be invalid so we should NOT cache it
14660 14660           * locally!
14661 14661           */
14662 14662          recov_state.rs_flags = 0;
14663 14663          recov_state.rs_num_retry_despite_err = 0;
14664 14664          error = nfs4_start_fop(mi, vp, NULL, OH_LOCKU, &recov_state,
14665 14665              &recovonly);
14666 14666          if (error) {
14667 14667                  mutex_enter(&rp->r_statelock);
14668 14668                  rp->r_flags |= R4LODANGLERS;
14669 14669                  mutex_exit(&rp->r_statelock);
14670 14670                  return (error);
14671 14671          }
14672 14672  
14673 14673          lop = find_lock_owner(rp, curproc->p_pid, LOWN_ANY);
14674 14674  
14675 14675          /*
14676 14676           * Check if the lock owner might have a lock (request was sent but
14677 14677           * no response was received).  Also check if there are any remote
14678 14678           * locks on the file.  (In theory we shouldn't have to make this
14679 14679           * second check if there's no lock owner, but for now we'll be
14680 14680           * conservative and do it anyway.)  If either condition is true,
14681 14681           * send an unlock for the entire file to the server.
14682 14682           *
14683 14683           * Note that no explicit synchronization is needed here.  At worst,
14684 14684           * flk_has_remote_locks() will return a false positive, in which case
14685 14685           * the unlock call wastes time but doesn't harm correctness.
14686 14686           */
14687 14687  
14688 14688          if (lop) {
14689 14689                  mutex_enter(&lop->lo_lock);
14690 14690                  possible_orphan = lop->lo_pending_rqsts;
14691 14691                  mutex_exit(&lop->lo_lock);
14692 14692                  lock_owner_rele(lop);
14693 14693          }
14694 14694  
14695 14695          nfs4_end_fop(mi, vp, NULL, OH_LOCKU, &recov_state, 0);
14696 14696  
14697 14697          NFS4_DEBUG(nfs4_client_lock_debug, (CE_NOTE,
14698 14698              "nfs4_lockrelease: possible orphan %d, remote locks %d, for "
14699 14699              "lop %p.", possible_orphan, flk_has_remote_locks(vp),
14700 14700              (void *)lop));
14701 14701  
14702 14702          if (possible_orphan || flk_has_remote_locks(vp)) {
14703 14703                  ld.l_type = F_UNLCK;    /* set to unlock entire file */
14704 14704                  ld.l_whence = 0;        /* unlock from start of file */
14705 14705                  ld.l_start = 0;
14706 14706                  ld.l_len = 0;           /* do entire file */
14707 14707  
14708 14708                  ret = VOP_FRLOCK(vp, F_SETLK, &ld, flag, offset, NULL,
14709 14709                      cr, NULL);
14710 14710  
14711 14711                  if (ret != 0) {
14712 14712                          /*
14713 14713                           * If VOP_FRLOCK fails, make sure we unregister
14714 14714                           * local locks before we continue.
14715 14715                           */
14716 14716                          ld.l_pid = ttoproc(curthread)->p_pid;
14717 14717                          nfs4_register_lock_locally(vp, &ld, flag, offset);
14718 14718                          NFS4_DEBUG(nfs4_client_lock_debug, (CE_NOTE,
14719 14719                              "nfs4_lockrelease: lock release error on vp"
14720 14720                              " %p: error %d.\n", (void *)vp, ret));
14721 14721                  }
14722 14722          }
14723 14723  
14724 14724          recov_state.rs_flags = 0;
14725 14725          recov_state.rs_num_retry_despite_err = 0;
14726 14726          error = nfs4_start_fop(mi, vp, NULL, OH_LOCKU, &recov_state,
14727 14727              &recovonly);
14728 14728          if (error) {
14729 14729                  mutex_enter(&rp->r_statelock);
14730 14730                  rp->r_flags |= R4LODANGLERS;
14731 14731                  mutex_exit(&rp->r_statelock);
14732 14732                  return (error);
14733 14733          }
14734 14734  
14735 14735          /*
14736 14736           * So, here we're going to need to retrieve the lock-owner
14737 14737           * again (in case recovery has done a switch-a-roo) and
14738 14738           * remove it because we can.
14739 14739           */
14740 14740          lop = find_lock_owner(rp, curproc->p_pid, LOWN_ANY);
14741 14741  
14742 14742          if (lop) {
14743 14743                  nfs4_rnode_remove_lock_owner(rp, lop);
14744 14744                  lock_owner_rele(lop);
14745 14745          }
14746 14746  
14747 14747          nfs4_end_fop(mi, vp, NULL, OH_LOCKU, &recov_state, 0);
14748 14748          return (0);
14749 14749  }
14750 14750  
14751 14751  /*
14752 14752   * Wait for 'tick_delay' clock ticks.
14753 14753   * Implement exponential backoff until hit the lease_time of this nfs4_server.
14754 14754   * NOTE: lock_lease_time is in seconds.
14755 14755   *
14756 14756   * XXX For future improvements, should implement a waiting queue scheme.
14757 14757   */
14758 14758  static int
14759 14759  nfs4_block_and_wait(clock_t *tick_delay, rnode4_t *rp)
14760 14760  {
14761 14761          long milliseconds_delay;
14762 14762          time_t lock_lease_time;
14763 14763  
14764 14764          /* wait tick_delay clock ticks or siginteruptus */
14765 14765          if (delay_sig(*tick_delay)) {
14766 14766                  return (EINTR);
14767 14767          }
14768 14768          NFS4_DEBUG(nfs4_client_lock_debug, (CE_NOTE, "nfs4_block_and_wait: "
14769 14769              "reissue the lock request: blocked for %ld clock ticks: %ld "
14770 14770              "milliseconds", *tick_delay, drv_hztousec(*tick_delay) / 1000));
14771 14771  
14772 14772          /* get the lease time */
14773 14773          lock_lease_time = r2lease_time(rp);
14774 14774  
14775 14775          /* drv_hztousec converts ticks to microseconds */
14776 14776          milliseconds_delay = drv_hztousec(*tick_delay) / 1000;
14777 14777          if (milliseconds_delay < lock_lease_time * 1000) {
14778 14778                  *tick_delay = 2 * *tick_delay;
14779 14779                  if (drv_hztousec(*tick_delay) > lock_lease_time * 1000 * 1000)
14780 14780                          *tick_delay = drv_usectohz(lock_lease_time*1000*1000);
14781 14781          }
14782 14782          return (0);
14783 14783  }
14784 14784  
14785 14785  
14786 14786  void
14787 14787  nfs4_vnops_init(void)
14788 14788  {
14789 14789  }
14790 14790  
14791 14791  void
14792 14792  nfs4_vnops_fini(void)
14793 14793  {
14794 14794  }
14795 14795  
14796 14796  /*
14797 14797   * Return a reference to the directory (parent) vnode for a given vnode,
14798 14798   * using the saved pathname information and the directory file handle.  The
14799 14799   * caller is responsible for disposing of the reference.
14800 14800   * Returns zero or an errno value.
14801 14801   *
14802 14802   * Caller should set need_start_op to FALSE if it is the recovery
14803 14803   * thread, or if a start_fop has already been done.  Otherwise, TRUE.
14804 14804   */
14805 14805  int
14806 14806  vtodv(vnode_t *vp, vnode_t **dvpp, cred_t *cr, bool_t need_start_op)
14807 14807  {
14808 14808          svnode_t *svnp;
14809 14809          vnode_t *dvp = NULL;
14810 14810          servinfo4_t *svp;
14811 14811          nfs4_fname_t *mfname;
14812 14812          int error;
14813 14813  
14814 14814          ASSERT(nfs_zone() == VTOMI4(vp)->mi_zone);
14815 14815  
14816 14816          if (vp->v_flag & VROOT) {
14817 14817                  nfs4_sharedfh_t *sfh;
14818 14818                  nfs_fh4 fh;
14819 14819                  mntinfo4_t *mi;
14820 14820  
14821 14821                  ASSERT(vp->v_type == VREG);
14822 14822  
14823 14823                  mi = VTOMI4(vp);
14824 14824                  svp = mi->mi_curr_serv;
14825 14825                  (void) nfs_rw_enter_sig(&svp->sv_lock, RW_READER, 0);
14826 14826                  fh.nfs_fh4_len = svp->sv_pfhandle.fh_len;
14827 14827                  fh.nfs_fh4_val = svp->sv_pfhandle.fh_buf;
14828 14828                  sfh = sfh4_get(&fh, VTOMI4(vp));
14829 14829                  nfs_rw_exit(&svp->sv_lock);
14830 14830                  mfname = mi->mi_fname;
14831 14831                  fn_hold(mfname);
14832 14832                  dvp = makenfs4node_by_fh(sfh, NULL, &mfname, NULL, mi, cr, 0);
14833 14833                  sfh4_rele(&sfh);
14834 14834  
14835 14835                  if (dvp->v_type == VNON)
14836 14836                          dvp->v_type = VDIR;
14837 14837                  *dvpp = dvp;
14838 14838                  return (0);
14839 14839          }
14840 14840  
14841 14841          svnp = VTOSV(vp);
14842 14842  
14843 14843          if (svnp == NULL) {
14844 14844                  NFS4_DEBUG(nfs4_client_shadow_debug, (CE_NOTE, "vtodv: "
14845 14845                      "shadow node is NULL"));
14846 14846                  return (EINVAL);
14847 14847          }
14848 14848  
14849 14849          if (svnp->sv_name == NULL || svnp->sv_dfh == NULL) {
14850 14850                  NFS4_DEBUG(nfs4_client_shadow_debug, (CE_NOTE, "vtodv: "
14851 14851                      "shadow node name or dfh val == NULL"));
14852 14852                  return (EINVAL);
14853 14853          }
14854 14854  
14855 14855          error = nfs4_make_dotdot(svnp->sv_dfh, 0, vp, cr, &dvp,
14856 14856              (int)need_start_op);
14857 14857          if (error != 0) {
14858 14858                  NFS4_DEBUG(nfs4_client_shadow_debug, (CE_NOTE, "vtodv: "
14859 14859                      "nfs4_make_dotdot returned %d", error));
14860 14860                  return (error);
14861 14861          }
14862 14862          if (!dvp) {
14863 14863                  NFS4_DEBUG(nfs4_client_shadow_debug, (CE_NOTE, "vtodv: "
14864 14864                      "nfs4_make_dotdot returned a NULL dvp"));
14865 14865                  return (EIO);
14866 14866          }
14867 14867          if (dvp->v_type == VNON)
14868 14868                  dvp->v_type = VDIR;
14869 14869          ASSERT(dvp->v_type == VDIR);
14870 14870          if (VTOR4(vp)->r_flags & R4ISXATTR) {
14871 14871                  mutex_enter(&dvp->v_lock);
14872 14872                  dvp->v_flag |= V_XATTRDIR;
14873 14873                  mutex_exit(&dvp->v_lock);
14874 14874          }
14875 14875          *dvpp = dvp;
14876 14876          return (0);
14877 14877  }
14878 14878  
14879 14879  /*
14880 14880   * Copy the (final) component name of vp to fnamep.  maxlen is the maximum
14881 14881   * length that fnamep can accept, including the trailing null.
14882 14882   * Returns 0 if okay, returns an errno value if there was a problem.
14883 14883   */
14884 14884  
14885 14885  int
14886 14886  vtoname(vnode_t *vp, char *fnamep, ssize_t maxlen)
14887 14887  {
14888 14888          char *fn;
14889 14889          int err = 0;
14890 14890          servinfo4_t *svp;
14891 14891          svnode_t *shvp;
14892 14892  
14893 14893          /*
14894 14894           * If the file being opened has VROOT set, then this is
14895 14895           * a "file" mount.  sv_name will not be interesting, so
14896 14896           * go back to the servinfo4 to get the original mount
14897 14897           * path and strip off all but the final edge.  Otherwise
14898 14898           * just return the name from the shadow vnode.
14899 14899           */
14900 14900  
14901 14901          if (vp->v_flag & VROOT) {
14902 14902  
14903 14903                  svp = VTOMI4(vp)->mi_curr_serv;
14904 14904                  (void) nfs_rw_enter_sig(&svp->sv_lock, RW_READER, 0);
14905 14905  
14906 14906                  fn = strrchr(svp->sv_path, '/');
14907 14907                  if (fn == NULL)
14908 14908                          err = EINVAL;
14909 14909                  else
14910 14910                          fn++;
14911 14911          } else {
14912 14912                  shvp = VTOSV(vp);
14913 14913                  fn = fn_name(shvp->sv_name);
14914 14914          }
14915 14915  
14916 14916          if (err == 0)
14917 14917                  if (strlen(fn) < maxlen)
14918 14918                          (void) strcpy(fnamep, fn);
14919 14919                  else
14920 14920                          err = ENAMETOOLONG;
14921 14921  
14922 14922          if (vp->v_flag & VROOT)
14923 14923                  nfs_rw_exit(&svp->sv_lock);
14924 14924          else
14925 14925                  kmem_free(fn, MAXNAMELEN);
14926 14926  
14927 14927          return (err);
14928 14928  }
14929 14929  
14930 14930  /*
14931 14931   * Bookkeeping for a close that doesn't need to go over the wire.
14932 14932   * *have_lockp is set to 0 if 'os_sync_lock' is released; otherwise
14933 14933   * it is left at 1.
14934 14934   */
14935 14935  void
14936 14936  nfs4close_notw(vnode_t *vp, nfs4_open_stream_t *osp, int *have_lockp)
14937 14937  {
14938 14938          rnode4_t                *rp;
14939 14939          mntinfo4_t              *mi;
14940 14940  
14941 14941          mi = VTOMI4(vp);
14942 14942          rp = VTOR4(vp);
14943 14943  
14944 14944          NFS4_DEBUG(nfs4close_notw_debug, (CE_NOTE, "nfs4close_notw: "
14945 14945              "rp=%p osp=%p", (void *)rp, (void *)osp));
14946 14946          ASSERT(nfs_zone() == mi->mi_zone);
14947 14947          ASSERT(mutex_owned(&osp->os_sync_lock));
14948 14948          ASSERT(*have_lockp);
14949 14949  
14950 14950          if (!osp->os_valid ||
14951 14951              osp->os_open_ref_count > 0 || osp->os_mapcnt > 0) {
14952 14952                  return;
14953 14953          }
14954 14954  
14955 14955          /*
14956 14956           * This removes the reference obtained at OPEN; ie,
14957 14957           * when the open stream structure was created.
14958 14958           *
14959 14959           * We don't have to worry about calling 'open_stream_rele'
14960 14960           * since we our currently holding a reference to this
14961 14961           * open stream which means the count can not go to 0 with
14962 14962           * this decrement.
14963 14963           */
14964 14964          ASSERT(osp->os_ref_count >= 2);
14965 14965          osp->os_ref_count--;
14966 14966          osp->os_valid = 0;
14967 14967          mutex_exit(&osp->os_sync_lock);
14968 14968          *have_lockp = 0;
14969 14969  
14970 14970          nfs4_dec_state_ref_count(mi);
14971 14971  }
14972 14972  
14973 14973  /*
14974 14974   * Close all remaining open streams on the rnode.  These open streams
14975 14975   * could be here because:
14976 14976   * - The close attempted at either close or delmap failed
14977 14977   * - Some kernel entity did VOP_OPEN but never did VOP_CLOSE
14978 14978   * - Someone did mknod on a regular file but never opened it
14979 14979   */
14980 14980  int
14981 14981  nfs4close_all(vnode_t *vp, cred_t *cr)
14982 14982  {
14983 14983          nfs4_open_stream_t *osp;
14984 14984          int error;
14985 14985          nfs4_error_t e = { 0, NFS4_OK, RPC_SUCCESS };
14986 14986          rnode4_t *rp;
14987 14987  
14988 14988          ASSERT(nfs_zone() == VTOMI4(vp)->mi_zone);
14989 14989  
14990 14990          error = 0;
14991 14991          rp = VTOR4(vp);
14992 14992  
14993 14993          /*
14994 14994           * At this point, all we know is that the last time
14995 14995           * someone called vn_rele, the count was 1.  Since then,
14996 14996           * the vnode could have been re-activated.  We want to
14997 14997           * loop through the open streams and close each one, but
14998 14998           * we have to be careful since once we release the rnode
14999 14999           * hash bucket lock, someone else is free to come in and
15000 15000           * re-activate the rnode and add new open streams.  The
15001 15001           * strategy is take the rnode hash bucket lock, verify that
15002 15002           * the count is still 1, grab the open stream off the
15003 15003           * head of the list and mark it invalid, then release the
15004 15004           * rnode hash bucket lock and proceed with that open stream.
15005 15005           * This is ok because nfs4close_one() will acquire the proper
15006 15006           * open/create to close/destroy synchronization for open
15007 15007           * streams, and will ensure that if someone has reopened
15008 15008           * the open stream after we've dropped the hash bucket lock
15009 15009           * then we'll just simply return without destroying the
15010 15010           * open stream.
15011 15011           * Repeat until the list is empty.
15012 15012           */
15013 15013  
15014 15014          for (;;) {
15015 15015  
15016 15016                  /* make sure vnode hasn't been reactivated */
15017 15017                  rw_enter(&rp->r_hashq->r_lock, RW_READER);
15018 15018                  mutex_enter(&vp->v_lock);
15019 15019                  if (vp->v_count > 1) {
15020 15020                          mutex_exit(&vp->v_lock);
15021 15021                          rw_exit(&rp->r_hashq->r_lock);
15022 15022                          break;
15023 15023                  }
15024 15024                  /*
15025 15025                   * Grabbing r_os_lock before releasing v_lock prevents
15026 15026                   * a window where the rnode/open stream could get
15027 15027                   * reactivated (and os_force_close set to 0) before we
15028 15028                   * had a chance to set os_force_close to 1.
15029 15029                   */
15030 15030                  mutex_enter(&rp->r_os_lock);
15031 15031                  mutex_exit(&vp->v_lock);
15032 15032  
15033 15033                  osp = list_head(&rp->r_open_streams);
15034 15034                  if (!osp) {
15035 15035                          /* nothing left to CLOSE OTW, so return */
15036 15036                          mutex_exit(&rp->r_os_lock);
15037 15037                          rw_exit(&rp->r_hashq->r_lock);
15038 15038                          break;
15039 15039                  }
15040 15040  
15041 15041                  mutex_enter(&rp->r_statev4_lock);
15042 15042                  /* the file can't still be mem mapped */
15043 15043                  ASSERT(rp->r_mapcnt == 0);
15044 15044                  if (rp->created_v4)
15045 15045                          rp->created_v4 = 0;
15046 15046                  mutex_exit(&rp->r_statev4_lock);
15047 15047  
15048 15048                  /*
15049 15049                   * Grab a ref on this open stream; nfs4close_one
15050 15050                   * will mark it as invalid
15051 15051                   */
15052 15052                  mutex_enter(&osp->os_sync_lock);
15053 15053                  osp->os_ref_count++;
15054 15054                  osp->os_force_close = 1;
15055 15055                  mutex_exit(&osp->os_sync_lock);
15056 15056                  mutex_exit(&rp->r_os_lock);
15057 15057                  rw_exit(&rp->r_hashq->r_lock);
15058 15058  
15059 15059                  nfs4close_one(vp, osp, cr, 0, NULL, &e, CLOSE_FORCE, 0, 0, 0);
15060 15060  
15061 15061                  /* Update error if it isn't already non-zero */
15062 15062                  if (error == 0) {
15063 15063                          if (e.error)
15064 15064                                  error = e.error;
15065 15065                          else if (e.stat)
15066 15066                                  error = geterrno4(e.stat);
15067 15067                  }
15068 15068  
15069 15069  #ifdef  DEBUG
15070 15070                  nfs4close_all_cnt++;
15071 15071  #endif
15072 15072                  /* Release the ref on osp acquired above. */
15073 15073                  open_stream_rele(osp, rp);
15074 15074  
15075 15075                  /* Proceed to the next open stream, if any */
15076 15076          }
15077 15077          return (error);
15078 15078  }
15079 15079  
15080 15080  /*
15081 15081   * nfs4close_one - close one open stream for a file if needed.
15082 15082   *
15083 15083   * "close_type" indicates which close path this is:
15084 15084   * CLOSE_NORM: close initiated via VOP_CLOSE.
15085 15085   * CLOSE_DELMAP: close initiated via VOP_DELMAP.
15086 15086   * CLOSE_FORCE: close initiated via VOP_INACTIVE.  This path forces
15087 15087   *      the close and release of client state for this open stream
15088 15088   *      (unless someone else has the open stream open).
15089 15089   * CLOSE_RESEND: indicates the request is a replay of an earlier request
15090 15090   *      (e.g., due to abort because of a signal).
15091 15091   * CLOSE_AFTER_RESEND: close initiated to "undo" a successful resent OPEN.
15092 15092   *
15093 15093   * CLOSE_RESEND and CLOSE_AFTER_RESEND will not attempt to retry after client
15094 15094   * recovery.  Instead, the caller is expected to deal with retries.
15095 15095   *
15096 15096   * The caller can either pass in the osp ('provided_osp') or not.
15097 15097   *
15098 15098   * 'access_bits' represents the access we are closing/downgrading.
15099 15099   *
15100 15100   * 'len', 'prot', and 'mmap_flags' are used for CLOSE_DELMAP.  'len' is the
15101 15101   * number of bytes we are unmapping, 'maxprot' is the mmap protection, and
15102 15102   * 'mmap_flags' tells us the type of sharing (MAP_PRIVATE or MAP_SHARED).
15103 15103   *
15104 15104   * Errors are returned via the nfs4_error_t.
15105 15105   */
15106 15106  void
15107 15107  nfs4close_one(vnode_t *vp, nfs4_open_stream_t *provided_osp, cred_t *cr,
15108 15108      int access_bits, nfs4_lost_rqst_t *lrp, nfs4_error_t *ep,
15109 15109      nfs4_close_type_t close_type, size_t len, uint_t maxprot,
15110 15110      uint_t mmap_flags)
15111 15111  {
15112 15112          nfs4_open_owner_t *oop;
15113 15113          nfs4_open_stream_t *osp = NULL;
15114 15114          int retry = 0;
15115 15115          int num_retries = NFS4_NUM_RECOV_RETRIES;
15116 15116          rnode4_t *rp;
15117 15117          mntinfo4_t *mi;
15118 15118          nfs4_recov_state_t recov_state;
15119 15119          cred_t *cred_otw = NULL;
15120 15120          bool_t recovonly = FALSE;
15121 15121          int isrecov;
15122 15122          int force_close;
15123 15123          int close_failed = 0;
15124 15124          int did_dec_count = 0;
15125 15125          int did_start_op = 0;
15126 15126          int did_force_recovlock = 0;
15127 15127          int did_start_seqid_sync = 0;
15128 15128          int have_sync_lock = 0;
15129 15129  
15130 15130          ASSERT(nfs_zone() == VTOMI4(vp)->mi_zone);
15131 15131  
15132 15132          NFS4_DEBUG(nfs4close_one_debug, (CE_NOTE, "closing vp %p osp %p, "
15133 15133              "lrp %p, close type %d len %ld prot %x mmap flags %x bits %x",
15134 15134              (void *)vp, (void *)provided_osp, (void *)lrp, close_type,
15135 15135              len, maxprot, mmap_flags, access_bits));
15136 15136  
15137 15137          nfs4_error_zinit(ep);
15138 15138          rp = VTOR4(vp);
15139 15139          mi = VTOMI4(vp);
15140 15140          isrecov = (close_type == CLOSE_RESEND ||
15141 15141              close_type == CLOSE_AFTER_RESEND);
15142 15142  
15143 15143          /*
15144 15144           * First get the open owner.
15145 15145           */
15146 15146          if (!provided_osp) {
15147 15147                  oop = find_open_owner(cr, NFS4_PERM_CREATED, mi);
15148 15148          } else {
15149 15149                  oop = provided_osp->os_open_owner;
15150 15150                  ASSERT(oop != NULL);
15151 15151                  open_owner_hold(oop);
15152 15152          }
15153 15153  
15154 15154          if (!oop) {
15155 15155                  NFS4_DEBUG(nfs4_client_recov_debug, (CE_NOTE,
15156 15156                      "nfs4close_one: no oop, rp %p, mi %p, cr %p, osp %p, "
15157 15157                      "close type %d", (void *)rp, (void *)mi, (void *)cr,
15158 15158                      (void *)provided_osp, close_type));
15159 15159                  ep->error = EIO;
15160 15160                  goto out;
15161 15161          }
15162 15162  
15163 15163          cred_otw = nfs4_get_otw_cred(cr, mi, oop);
15164 15164  recov_retry:
15165 15165          osp = NULL;
15166 15166          close_failed = 0;
15167 15167          force_close = (close_type == CLOSE_FORCE);
15168 15168          retry = 0;
15169 15169          did_start_op = 0;
15170 15170          did_force_recovlock = 0;
15171 15171          did_start_seqid_sync = 0;
15172 15172          have_sync_lock = 0;
15173 15173          recovonly = FALSE;
15174 15174          recov_state.rs_flags = 0;
15175 15175          recov_state.rs_num_retry_despite_err = 0;
15176 15176  
15177 15177          /*
15178 15178           * Second synchronize with recovery.
15179 15179           */
15180 15180          if (!isrecov) {
15181 15181                  ep->error = nfs4_start_fop(mi, vp, NULL, OH_CLOSE,
15182 15182                      &recov_state, &recovonly);
15183 15183                  if (!ep->error) {
15184 15184                          did_start_op = 1;
15185 15185                  } else {
15186 15186                          close_failed = 1;
15187 15187                          /*
15188 15188                           * If we couldn't get start_fop, but have to
15189 15189                           * cleanup state, then at least acquire the
15190 15190                           * mi_recovlock so we can synchronize with
15191 15191                           * recovery.
15192 15192                           */
15193 15193                          if (close_type == CLOSE_FORCE) {
15194 15194                                  (void) nfs_rw_enter_sig(&mi->mi_recovlock,
15195 15195                                      RW_READER, FALSE);
15196 15196                                  did_force_recovlock = 1;
15197 15197                          } else
15198 15198                                  goto out;
15199 15199                  }
15200 15200          }
15201 15201  
15202 15202          /*
15203 15203           * We cannot attempt to get the open seqid sync if nfs4_start_fop
15204 15204           * set 'recovonly' to TRUE since most likely this is due to
15205 15205           * reovery being active (MI4_RECOV_ACTIV).  If recovery is active,
15206 15206           * nfs4_start_open_seqid_sync() will fail with EAGAIN asking us
15207 15207           * to retry, causing us to loop until recovery finishes.  Plus we
15208 15208           * don't need protection over the open seqid since we're not going
15209 15209           * OTW, hence don't need to use the seqid.
15210 15210           */
15211 15211          if (recovonly == FALSE) {
15212 15212                  /* need to grab the open owner sync before 'os_sync_lock' */
15213 15213                  ep->error = nfs4_start_open_seqid_sync(oop, mi);
15214 15214                  if (ep->error == EAGAIN) {
15215 15215                          ASSERT(!isrecov);
15216 15216                          if (did_start_op)
15217 15217                                  nfs4_end_fop(mi, vp, NULL, OH_CLOSE,
15218 15218                                      &recov_state, TRUE);
15219 15219                          if (did_force_recovlock)
15220 15220                                  nfs_rw_exit(&mi->mi_recovlock);
15221 15221                          goto recov_retry;
15222 15222                  }
15223 15223                  did_start_seqid_sync = 1;
15224 15224          }
15225 15225  
15226 15226          /*
15227 15227           * Third get an open stream and acquire 'os_sync_lock' to
15228 15228           * sychronize the opening/creating of an open stream with the
15229 15229           * closing/destroying of an open stream.
15230 15230           */
15231 15231          if (!provided_osp) {
15232 15232                  /* returns with 'os_sync_lock' held */
15233 15233                  osp = find_open_stream(oop, rp);
15234 15234                  if (!osp) {
15235 15235                          ep->error = EIO;
15236 15236                          goto out;
15237 15237                  }
15238 15238          } else {
15239 15239                  osp = provided_osp;
15240 15240                  open_stream_hold(osp);
15241 15241                  mutex_enter(&osp->os_sync_lock);
15242 15242          }
15243 15243          have_sync_lock = 1;
15244 15244  
15245 15245          ASSERT(oop == osp->os_open_owner);
15246 15246  
15247 15247          /*
15248 15248           * Fourth, do any special pre-OTW CLOSE processing
15249 15249           * based on the specific close type.
15250 15250           */
15251 15251          if ((close_type == CLOSE_NORM || close_type == CLOSE_AFTER_RESEND) &&
15252 15252              !did_dec_count) {
15253 15253                  ASSERT(osp->os_open_ref_count > 0);
15254 15254                  osp->os_open_ref_count--;
15255 15255                  did_dec_count = 1;
15256 15256                  if (osp->os_open_ref_count == 0)
15257 15257                          osp->os_final_close = 1;
15258 15258          }
15259 15259  
15260 15260          if (close_type == CLOSE_FORCE) {
15261 15261                  /* see if somebody reopened the open stream. */
15262 15262                  if (!osp->os_force_close) {
15263 15263                          NFS4_DEBUG(nfs4close_one_debug, (CE_NOTE,
15264 15264                              "nfs4close_one: skip CLOSE_FORCE as osp %p "
15265 15265                              "was reopened, vp %p", (void *)osp, (void *)vp));
15266 15266                          ep->error = 0;
15267 15267                          ep->stat = NFS4_OK;
15268 15268                          goto out;
15269 15269                  }
15270 15270  
15271 15271                  if (!osp->os_final_close && !did_dec_count) {
15272 15272                          osp->os_open_ref_count--;
15273 15273                          did_dec_count = 1;
15274 15274                  }
15275 15275  
15276 15276                  /*
15277 15277                   * We can't depend on os_open_ref_count being 0 due to the
15278 15278                   * way executables are opened (VN_RELE to match a VOP_OPEN).
15279 15279                   */
15280 15280  #ifdef  NOTYET
15281 15281                  ASSERT(osp->os_open_ref_count == 0);
15282 15282  #endif
15283 15283                  if (osp->os_open_ref_count != 0) {
15284 15284                          NFS4_DEBUG(nfs4close_one_debug, (CE_NOTE,
15285 15285                              "nfs4close_one: should panic here on an "
15286 15286                              "ASSERT(osp->os_open_ref_count == 0). Ignoring "
15287 15287                              "since this is probably the exec problem."));
15288 15288  
15289 15289                          osp->os_open_ref_count = 0;
15290 15290                  }
15291 15291  
15292 15292                  /*
15293 15293                   * There is the possibility that nfs4close_one()
15294 15294                   * for close_type == CLOSE_DELMAP couldn't find the
15295 15295                   * open stream, thus couldn't decrement its os_mapcnt;
15296 15296                   * therefore we can't use this ASSERT yet.
15297 15297                   */
15298 15298  #ifdef  NOTYET
15299 15299                  ASSERT(osp->os_mapcnt == 0);
15300 15300  #endif
15301 15301                  osp->os_mapcnt = 0;
15302 15302          }
15303 15303  
15304 15304          if (close_type == CLOSE_DELMAP && !did_dec_count) {
15305 15305                  ASSERT(osp->os_mapcnt >= btopr(len));
15306 15306  
15307 15307                  if ((mmap_flags & MAP_SHARED) && (maxprot & PROT_WRITE))
15308 15308                          osp->os_mmap_write -= btopr(len);
15309 15309                  if (maxprot & PROT_READ)
15310 15310                          osp->os_mmap_read -= btopr(len);
15311 15311                  if (maxprot & PROT_EXEC)
15312 15312                          osp->os_mmap_read -= btopr(len);
15313 15313                  /* mirror the PROT_NONE check in nfs4_addmap() */
15314 15314                  if (!(maxprot & PROT_READ) && !(maxprot & PROT_WRITE) &&
15315 15315                      !(maxprot & PROT_EXEC))
15316 15316                          osp->os_mmap_read -= btopr(len);
15317 15317                  osp->os_mapcnt -= btopr(len);
15318 15318                  did_dec_count = 1;
15319 15319          }
15320 15320  
15321 15321          if (recovonly) {
15322 15322                  nfs4_lost_rqst_t lost_rqst;
15323 15323  
15324 15324                  /* request should not already be in recovery queue */
15325 15325                  ASSERT(lrp == NULL);
15326 15326                  nfs4_error_init(ep, EINTR);
15327 15327                  nfs4close_save_lost_rqst(ep->error, &lost_rqst, oop,
15328 15328                      osp, cred_otw, vp);
15329 15329                  mutex_exit(&osp->os_sync_lock);
15330 15330                  have_sync_lock = 0;
15331 15331                  (void) nfs4_start_recovery(ep, mi, vp, NULL, NULL,
15332 15332                      lost_rqst.lr_op == OP_CLOSE ?
15333 15333                      &lost_rqst : NULL, OP_CLOSE, NULL, NULL, NULL);
15334 15334                  close_failed = 1;
15335 15335                  force_close = 0;
15336 15336                  goto close_cleanup;
15337 15337          }
15338 15338  
15339 15339          /*
15340 15340           * If a previous OTW call got NFS4ERR_BAD_SEQID, then
15341 15341           * we stopped operating on the open owner's <old oo_name, old seqid>
15342 15342           * space, which means we stopped operating on the open stream
15343 15343           * too.  So don't go OTW (as the seqid is likely bad, and the
15344 15344           * stateid could be stale, potentially triggering a false
15345 15345           * setclientid), and just clean up the client's internal state.
15346 15346           */
15347 15347          if (osp->os_orig_oo_name != oop->oo_name) {
15348 15348                  NFS4_DEBUG(nfs4close_one_debug || nfs4_client_recov_debug,
15349 15349                      (CE_NOTE, "nfs4close_one: skip OTW close for osp %p "
15350 15350                      "oop %p due to bad seqid (orig oo_name %" PRIx64 " current "
15351 15351                      "oo_name %" PRIx64")",
15352 15352                      (void *)osp, (void *)oop, osp->os_orig_oo_name,
15353 15353                      oop->oo_name));
15354 15354                  close_failed = 1;
15355 15355          }
15356 15356  
15357 15357          /* If the file failed recovery, just quit. */
15358 15358          mutex_enter(&rp->r_statelock);
15359 15359          if (rp->r_flags & R4RECOVERR) {
15360 15360                  close_failed = 1;
15361 15361          }
15362 15362          mutex_exit(&rp->r_statelock);
15363 15363  
15364 15364          /*
15365 15365           * If the force close path failed to obtain start_fop
15366 15366           * then skip the OTW close and just remove the state.
15367 15367           */
15368 15368          if (close_failed)
15369 15369                  goto close_cleanup;
15370 15370  
15371 15371          /*
15372 15372           * Fifth, check to see if there are still mapped pages or other
15373 15373           * opens using this open stream.  If there are then we can't
15374 15374           * close yet but we can see if an OPEN_DOWNGRADE is necessary.
15375 15375           */
15376 15376          if (osp->os_open_ref_count > 0 || osp->os_mapcnt > 0) {
15377 15377                  nfs4_lost_rqst_t        new_lost_rqst;
15378 15378                  bool_t                  needrecov = FALSE;
15379 15379                  cred_t                  *odg_cred_otw = NULL;
15380 15380                  seqid4                  open_dg_seqid = 0;
15381 15381  
15382 15382                  if (osp->os_delegation) {
15383 15383                          /*
15384 15384                           * If this open stream was never OPENed OTW then we
15385 15385                           * surely can't DOWNGRADE it (especially since the
15386 15386                           * osp->open_stateid is really a delegation stateid
15387 15387                           * when os_delegation is 1).
15388 15388                           */
15389 15389                          if (access_bits & FREAD)
15390 15390                                  osp->os_share_acc_read--;
15391 15391                          if (access_bits & FWRITE)
15392 15392                                  osp->os_share_acc_write--;
15393 15393                          osp->os_share_deny_none--;
15394 15394                          nfs4_error_zinit(ep);
15395 15395                          goto out;
15396 15396                  }
15397 15397                  nfs4_open_downgrade(access_bits, 0, oop, osp, vp, cr,
15398 15398                      lrp, ep, &odg_cred_otw, &open_dg_seqid);
15399 15399                  needrecov = nfs4_needs_recovery(ep, TRUE, mi->mi_vfsp);
15400 15400                  if (needrecov && !isrecov) {
15401 15401                          bool_t abort;
15402 15402                          nfs4_bseqid_entry_t *bsep = NULL;
15403 15403  
15404 15404                          if (!ep->error && ep->stat == NFS4ERR_BAD_SEQID)
15405 15405                                  bsep = nfs4_create_bseqid_entry(oop, NULL,
15406 15406                                      vp, 0,
15407 15407                                      lrp ? TAG_OPEN_DG_LOST : TAG_OPEN_DG,
15408 15408                                      open_dg_seqid);
15409 15409  
15410 15410                          nfs4open_dg_save_lost_rqst(ep->error, &new_lost_rqst,
15411 15411                              oop, osp, odg_cred_otw, vp, access_bits, 0);
15412 15412                          mutex_exit(&osp->os_sync_lock);
15413 15413                          have_sync_lock = 0;
15414 15414                          abort = nfs4_start_recovery(ep, mi, vp, NULL, NULL,
15415 15415                              new_lost_rqst.lr_op == OP_OPEN_DOWNGRADE ?
15416 15416                              &new_lost_rqst : NULL, OP_OPEN_DOWNGRADE,
15417 15417                              bsep, NULL, NULL);
15418 15418                          if (odg_cred_otw)
15419 15419                                  crfree(odg_cred_otw);
15420 15420                          if (bsep)
15421 15421                                  kmem_free(bsep, sizeof (*bsep));
15422 15422  
15423 15423                          if (abort == TRUE)
15424 15424                                  goto out;
15425 15425  
15426 15426                          if (did_start_seqid_sync) {
15427 15427                                  nfs4_end_open_seqid_sync(oop);
15428 15428                                  did_start_seqid_sync = 0;
15429 15429                          }
15430 15430                          open_stream_rele(osp, rp);
15431 15431  
15432 15432                          if (did_start_op)
15433 15433                                  nfs4_end_fop(mi, vp, NULL, OH_CLOSE,
15434 15434                                      &recov_state, FALSE);
15435 15435                          if (did_force_recovlock)
15436 15436                                  nfs_rw_exit(&mi->mi_recovlock);
15437 15437  
15438 15438                          goto recov_retry;
15439 15439                  } else {
15440 15440                          if (odg_cred_otw)
15441 15441                                  crfree(odg_cred_otw);
15442 15442                  }
15443 15443                  goto out;
15444 15444          }
15445 15445  
15446 15446          /*
15447 15447           * If this open stream was created as the results of an open
15448 15448           * while holding a delegation, then just release it; no need
15449 15449           * to do an OTW close.  Otherwise do a "normal" OTW close.
15450 15450           */
15451 15451          if (osp->os_delegation) {
15452 15452                  nfs4close_notw(vp, osp, &have_sync_lock);
15453 15453                  nfs4_error_zinit(ep);
15454 15454                  goto out;
15455 15455          }
15456 15456  
15457 15457          /*
15458 15458           * If this stream is not valid, we're done.
15459 15459           */
15460 15460          if (!osp->os_valid) {
15461 15461                  nfs4_error_zinit(ep);
15462 15462                  goto out;
15463 15463          }
15464 15464  
15465 15465          /*
15466 15466           * Last open or mmap ref has vanished, need to do an OTW close.
15467 15467           * First check to see if a close is still necessary.
15468 15468           */
15469 15469          if (osp->os_failed_reopen) {
15470 15470                  NFS4_DEBUG(nfs4_client_recov_debug, (CE_NOTE,
15471 15471                      "don't close OTW osp %p since reopen failed.",
15472 15472                      (void *)osp));
15473 15473                  /*
15474 15474                   * Reopen of the open stream failed, hence the
15475 15475                   * stateid of the open stream is invalid/stale, and
15476 15476                   * sending this OTW would incorrectly cause another
15477 15477                   * round of recovery.  In this case, we need to set
15478 15478                   * the 'os_valid' bit to 0 so another thread doesn't
15479 15479                   * come in and re-open this open stream before
15480 15480                   * this "closing" thread cleans up state (decrementing
15481 15481                   * the nfs4_server_t's state_ref_count and decrementing
15482 15482                   * the os_ref_count).
15483 15483                   */
15484 15484                  osp->os_valid = 0;
15485 15485                  /*
15486 15486                   * This removes the reference obtained at OPEN; ie,
15487 15487                   * when the open stream structure was created.
15488 15488                   *
15489 15489                   * We don't have to worry about calling 'open_stream_rele'
15490 15490                   * since we our currently holding a reference to this
15491 15491                   * open stream which means the count can not go to 0 with
15492 15492                   * this decrement.
15493 15493                   */
15494 15494                  ASSERT(osp->os_ref_count >= 2);
15495 15495                  osp->os_ref_count--;
15496 15496                  nfs4_error_zinit(ep);
15497 15497                  close_failed = 0;
15498 15498                  goto close_cleanup;
15499 15499          }
15500 15500  
15501 15501          ASSERT(osp->os_ref_count > 1);
15502 15502  
15503 15503          /*
15504 15504           * Sixth, try the CLOSE OTW.
15505 15505           */
15506 15506          nfs4close_otw(rp, cred_otw, oop, osp, &retry, &did_start_seqid_sync,
15507 15507              close_type, ep, &have_sync_lock);
15508 15508  
15509 15509          if (ep->error == EINTR || NFS4_FRC_UNMT_ERR(ep->error, vp->v_vfsp)) {
15510 15510                  /*
15511 15511                   * Let the recovery thread be responsible for
15512 15512                   * removing the state for CLOSE.
15513 15513                   */
15514 15514                  close_failed = 1;
15515 15515                  force_close = 0;
15516 15516                  retry = 0;
15517 15517          }
15518 15518  
15519 15519          /* See if we need to retry with a different cred */
15520 15520          if ((ep->error == EACCES ||
15521 15521              (ep->error == 0 && ep->stat == NFS4ERR_ACCESS)) &&
15522 15522              cred_otw != cr) {
15523 15523                  crfree(cred_otw);
15524 15524                  cred_otw = cr;
15525 15525                  crhold(cred_otw);
15526 15526                  retry = 1;
15527 15527          }
15528 15528  
15529 15529          if (ep->error || ep->stat)
15530 15530                  close_failed = 1;
15531 15531  
15532 15532          if (retry && !isrecov && num_retries-- > 0) {
15533 15533                  if (have_sync_lock) {
15534 15534                          mutex_exit(&osp->os_sync_lock);
15535 15535                          have_sync_lock = 0;
15536 15536                  }
15537 15537                  if (did_start_seqid_sync) {
15538 15538                          nfs4_end_open_seqid_sync(oop);
15539 15539                          did_start_seqid_sync = 0;
15540 15540                  }
15541 15541                  open_stream_rele(osp, rp);
15542 15542  
15543 15543                  if (did_start_op)
15544 15544                          nfs4_end_fop(mi, vp, NULL, OH_CLOSE,
15545 15545                              &recov_state, FALSE);
15546 15546                  if (did_force_recovlock)
15547 15547                          nfs_rw_exit(&mi->mi_recovlock);
15548 15548                  NFS4_DEBUG(nfs4_client_recov_debug, (CE_NOTE,
15549 15549                      "nfs4close_one: need to retry the close "
15550 15550                      "operation"));
15551 15551                  goto recov_retry;
15552 15552          }
15553 15553  close_cleanup:
15554 15554          /*
15555 15555           * Seventh and lastly, process our results.
15556 15556           */
15557 15557          if (close_failed && force_close) {
15558 15558                  /*
15559 15559                   * It's ok to drop and regrab the 'os_sync_lock' since
15560 15560                   * nfs4close_notw() will recheck to make sure the
15561 15561                   * "close"/removal of state should happen.
15562 15562                   */
15563 15563                  if (!have_sync_lock) {
15564 15564                          mutex_enter(&osp->os_sync_lock);
15565 15565                          have_sync_lock = 1;
15566 15566                  }
15567 15567                  /*
15568 15568                   * This is last call, remove the ref on the open
15569 15569                   * stream created by open and clean everything up.
15570 15570                   */
15571 15571                  osp->os_pending_close = 0;
15572 15572                  nfs4close_notw(vp, osp, &have_sync_lock);
15573 15573                  nfs4_error_zinit(ep);
15574 15574          }
15575 15575  
15576 15576          if (!close_failed) {
15577 15577                  if (have_sync_lock) {
15578 15578                          osp->os_pending_close = 0;
15579 15579                          mutex_exit(&osp->os_sync_lock);
15580 15580                          have_sync_lock = 0;
15581 15581                  } else {
15582 15582                          mutex_enter(&osp->os_sync_lock);
15583 15583                          osp->os_pending_close = 0;
15584 15584                          mutex_exit(&osp->os_sync_lock);
15585 15585                  }
15586 15586                  if (did_start_op && recov_state.rs_sp != NULL) {
15587 15587                          mutex_enter(&recov_state.rs_sp->s_lock);
15588 15588                          nfs4_dec_state_ref_count_nolock(recov_state.rs_sp, mi);
15589 15589                          mutex_exit(&recov_state.rs_sp->s_lock);
15590 15590                  } else {
15591 15591                          nfs4_dec_state_ref_count(mi);
15592 15592                  }
15593 15593                  nfs4_error_zinit(ep);
15594 15594          }
15595 15595  
15596 15596  out:
15597 15597          if (have_sync_lock)
15598 15598                  mutex_exit(&osp->os_sync_lock);
15599 15599          if (did_start_op)
15600 15600                  nfs4_end_fop(mi, vp, NULL, OH_CLOSE, &recov_state,
15601 15601                      recovonly ? TRUE : FALSE);
15602 15602          if (did_force_recovlock)
15603 15603                  nfs_rw_exit(&mi->mi_recovlock);
15604 15604          if (cred_otw)
15605 15605                  crfree(cred_otw);
15606 15606          if (osp)
15607 15607                  open_stream_rele(osp, rp);
15608 15608          if (oop) {
15609 15609                  if (did_start_seqid_sync)
15610 15610                          nfs4_end_open_seqid_sync(oop);
15611 15611                  open_owner_rele(oop);
15612 15612          }
15613 15613  }
15614 15614  
15615 15615  /*
15616 15616   * Convert information returned by the server in the LOCK4denied
15617 15617   * structure to the form required by fcntl.
15618 15618   */
15619 15619  static void
15620 15620  denied_to_flk(LOCK4denied *lockt_denied, flock64_t *flk, LOCKT4args *lockt_args)
15621 15621  {
15622 15622          nfs4_lo_name_t *lo;
15623 15623  
15624 15624  #ifdef  DEBUG
15625 15625          if (denied_to_flk_debug) {
15626 15626                  lockt_denied_debug = lockt_denied;
15627 15627                  debug_enter("lockt_denied");
15628 15628          }
15629 15629  #endif
15630 15630  
15631 15631          flk->l_type = lockt_denied->locktype == READ_LT ? F_RDLCK : F_WRLCK;
15632 15632          flk->l_whence = 0;      /* aka SEEK_SET */
15633 15633          flk->l_start = lockt_denied->offset;
15634 15634          flk->l_len = lockt_denied->length;
15635 15635  
15636 15636          /*
15637 15637           * If the blocking clientid matches our client id, then we can
15638 15638           * interpret the lockowner (since we built it).  If not, then
15639 15639           * fabricate a sysid and pid.  Note that the l_sysid field
15640 15640           * in *flk already has the local sysid.
15641 15641           */
15642 15642  
15643 15643          if (lockt_denied->owner.clientid == lockt_args->owner.clientid) {
15644 15644  
15645 15645                  if (lockt_denied->owner.owner_len == sizeof (*lo)) {
15646 15646                          lo = (nfs4_lo_name_t *)
15647 15647                              lockt_denied->owner.owner_val;
15648 15648  
15649 15649                          flk->l_pid = lo->ln_pid;
15650 15650                  } else {
15651 15651                          NFS4_DEBUG(nfs4_client_lock_debug, (CE_NOTE,
15652 15652                              "denied_to_flk: bad lock owner length\n"));
15653 15653  
15654 15654                          flk->l_pid = lo_to_pid(&lockt_denied->owner);
15655 15655                  }
15656 15656          } else {
15657 15657                  NFS4_DEBUG(nfs4_client_lock_debug, (CE_NOTE,
15658 15658                  "denied_to_flk: foreign clientid\n"));
15659 15659  
15660 15660                  /*
15661 15661                   * Construct a new sysid which should be different from
15662 15662                   * sysids of other systems.
15663 15663                   */
15664 15664  
15665 15665                  flk->l_sysid++;
15666 15666                  flk->l_pid = lo_to_pid(&lockt_denied->owner);
15667 15667          }
15668 15668  }
15669 15669  
15670 15670  static pid_t
15671 15671  lo_to_pid(lock_owner4 *lop)
15672 15672  {
15673 15673          pid_t pid = 0;
15674 15674          uchar_t *cp;
15675 15675          int i;
15676 15676  
15677 15677          cp = (uchar_t *)&lop->clientid;
15678 15678  
15679 15679          for (i = 0; i < sizeof (lop->clientid); i++)
15680 15680                  pid += (pid_t)*cp++;
15681 15681  
15682 15682          cp = (uchar_t *)lop->owner_val;
15683 15683  
15684 15684          for (i = 0; i < lop->owner_len; i++)
15685 15685                  pid += (pid_t)*cp++;
15686 15686  
15687 15687          return (pid);
15688 15688  }
15689 15689  
15690 15690  /*
15691 15691   * Given a lock pointer, returns the length of that lock.
15692 15692   * "end" is the last locked offset the "l_len" covers from
15693 15693   * the start of the lock.
15694 15694   */
15695 15695  static off64_t
15696 15696  lock_to_end(flock64_t *lock)
15697 15697  {
15698 15698          off64_t lock_end;
15699 15699  
15700 15700          if (lock->l_len == 0)
15701 15701                  lock_end = (off64_t)MAXEND;
15702 15702          else
15703 15703                  lock_end = lock->l_start + lock->l_len - 1;
15704 15704  
15705 15705          return (lock_end);
15706 15706  }
15707 15707  
15708 15708  /*
15709 15709   * Given the end of a lock, it will return you the length "l_len" for that lock.
15710 15710   */
15711 15711  static off64_t
15712 15712  end_to_len(off64_t start, off64_t end)
15713 15713  {
15714 15714          off64_t lock_len;
15715 15715  
15716 15716          ASSERT(end >= start);
15717 15717          if (end == MAXEND)
15718 15718                  lock_len = 0;
15719 15719          else
15720 15720                  lock_len = end - start + 1;
15721 15721  
15722 15722          return (lock_len);
15723 15723  }
15724 15724  
15725 15725  /*
15726 15726   * On given end for a lock it determines if it is the last locked offset
15727 15727   * or not, if so keeps it as is, else adds one to return the length for
15728 15728   * valid start.
15729 15729   */
15730 15730  static off64_t
15731 15731  start_check(off64_t x)
15732 15732  {
15733 15733          if (x == MAXEND)
15734 15734                  return (x);
15735 15735          else
15736 15736                  return (x + 1);
15737 15737  }
15738 15738  
15739 15739  /*
15740 15740   * See if these two locks overlap, and if so return 1;
15741 15741   * otherwise, return 0.
15742 15742   */
15743 15743  static int
15744 15744  locks_intersect(flock64_t *llfp, flock64_t *curfp)
15745 15745  {
15746 15746          off64_t llfp_end, curfp_end;
15747 15747  
15748 15748          llfp_end = lock_to_end(llfp);
15749 15749          curfp_end = lock_to_end(curfp);
15750 15750  
15751 15751          if (((llfp_end >= curfp->l_start) &&
15752 15752              (llfp->l_start <= curfp->l_start)) ||
15753 15753              ((curfp->l_start <= llfp->l_start) && (curfp_end >= llfp->l_start)))
15754 15754                  return (1);
15755 15755          return (0);
15756 15756  }
15757 15757  
15758 15758  /*
15759 15759   * Determine what the intersecting lock region is, and add that to the
15760 15760   * 'nl_llpp' locklist in increasing order (by l_start).
15761 15761   */
15762 15762  static void
15763 15763  nfs4_add_lock_range(flock64_t *lost_flp, flock64_t *local_flp,
15764 15764      locklist_t **nl_llpp, vnode_t *vp)
15765 15765  {
15766 15766          locklist_t *intersect_llp, *tmp_fllp, *cur_fllp;
15767 15767          off64_t lost_flp_end, local_flp_end, len, start;
15768 15768  
15769 15769          NFS4_DEBUG(nfs4_lost_rqst_debug, (CE_NOTE, "nfs4_add_lock_range:"));
15770 15770  
15771 15771          if (!locks_intersect(lost_flp, local_flp))
15772 15772                  return;
15773 15773  
15774 15774          NFS4_DEBUG(nfs4_lost_rqst_debug, (CE_NOTE, "nfs4_add_lock_range: "
15775 15775              "locks intersect"));
15776 15776  
15777 15777          lost_flp_end = lock_to_end(lost_flp);
15778 15778          local_flp_end = lock_to_end(local_flp);
15779 15779  
15780 15780          /* Find the starting point of the intersecting region */
15781 15781          if (local_flp->l_start > lost_flp->l_start)
15782 15782                  start = local_flp->l_start;
15783 15783          else
15784 15784                  start = lost_flp->l_start;
15785 15785  
15786 15786          /* Find the lenght of the intersecting region */
15787 15787          if (lost_flp_end < local_flp_end)
15788 15788                  len = end_to_len(start, lost_flp_end);
15789 15789          else
15790 15790                  len = end_to_len(start, local_flp_end);
15791 15791  
15792 15792          /*
15793 15793           * Prepare the flock structure for the intersection found and insert
15794 15794           * it into the new list in increasing l_start order. This list contains
15795 15795           * intersections of locks registered by the client with the local host
15796 15796           * and the lost lock.
15797 15797           * The lock type of this lock is the same as that of the local_flp.
15798 15798           */
15799 15799          intersect_llp = (locklist_t *)kmem_alloc(sizeof (locklist_t), KM_SLEEP);
15800 15800          intersect_llp->ll_flock.l_start = start;
15801 15801          intersect_llp->ll_flock.l_len = len;
15802 15802          intersect_llp->ll_flock.l_type = local_flp->l_type;
15803 15803          intersect_llp->ll_flock.l_pid = local_flp->l_pid;
15804 15804          intersect_llp->ll_flock.l_sysid = local_flp->l_sysid;
15805 15805          intersect_llp->ll_flock.l_whence = 0;   /* aka SEEK_SET */
15806 15806          intersect_llp->ll_vp = vp;
15807 15807  
15808 15808          tmp_fllp = *nl_llpp;
15809 15809          cur_fllp = NULL;
15810 15810          while (tmp_fllp != NULL && tmp_fllp->ll_flock.l_start <
15811 15811              intersect_llp->ll_flock.l_start) {
15812 15812                          cur_fllp = tmp_fllp;
15813 15813                          tmp_fllp = tmp_fllp->ll_next;
15814 15814          }
15815 15815          if (cur_fllp == NULL) {
15816 15816                  /* first on the list */
15817 15817                  intersect_llp->ll_next = *nl_llpp;
15818 15818                  *nl_llpp = intersect_llp;
15819 15819          } else {
15820 15820                  intersect_llp->ll_next = cur_fllp->ll_next;
15821 15821                  cur_fllp->ll_next = intersect_llp;
15822 15822          }
15823 15823  
15824 15824          NFS4_DEBUG(nfs4_lost_rqst_debug, (CE_NOTE, "nfs4_add_lock_range: "
15825 15825              "created lock region: start %"PRIx64" end %"PRIx64" : %s\n",
15826 15826              intersect_llp->ll_flock.l_start,
15827 15827              intersect_llp->ll_flock.l_start + intersect_llp->ll_flock.l_len,
15828 15828              intersect_llp->ll_flock.l_type == F_RDLCK ? "READ" : "WRITE"));
15829 15829  }
15830 15830  
15831 15831  /*
15832 15832   * Our local locking current state is potentially different than
15833 15833   * what the NFSv4 server thinks we have due to a lost lock that was
15834 15834   * resent and then received.  We need to reset our "NFSv4" locking
15835 15835   * state to match the current local locking state for this pid since
15836 15836   * that is what the user/application sees as what the world is.
15837 15837   *
15838 15838   * We cannot afford to drop the open/lock seqid sync since then we can
15839 15839   * get confused about what the current local locking state "is" versus
15840 15840   * "was".
15841 15841   *
15842 15842   * If we are unable to fix up the locks, we send SIGLOST to the affected
15843 15843   * process.  This is not done if the filesystem has been forcibly
15844 15844   * unmounted, in case the process has already exited and a new process
15845 15845   * exists with the same pid.
15846 15846   */
15847 15847  static void
15848 15848  nfs4_reinstitute_local_lock_state(vnode_t *vp, flock64_t *lost_flp, cred_t *cr,
15849 15849      nfs4_lock_owner_t *lop)
15850 15850  {
15851 15851          locklist_t *locks, *llp, *ri_llp, *tmp_llp;
15852 15852          mntinfo4_t *mi = VTOMI4(vp);
15853 15853          const int cmd = F_SETLK;
15854 15854          off64_t cur_start, llp_ll_flock_end, lost_flp_end;
15855 15855          flock64_t ul_fl;
15856 15856  
15857 15857          NFS4_DEBUG(nfs4_lost_rqst_debug, (CE_NOTE,
15858 15858              "nfs4_reinstitute_local_lock_state"));
15859 15859  
15860 15860          /*
15861 15861           * Find active locks for this vp from the local locking code.
15862 15862           * Scan through this list and find out the locks that intersect with
15863 15863           * the lost lock. Once we find the lock that intersects, add the
15864 15864           * intersection area as a new lock to a new list "ri_llp". The lock
15865 15865           * type of the intersection region lock added to ri_llp is the same
15866 15866           * as that found in the active lock list, "list". The intersecting
15867 15867           * region locks are added to ri_llp in increasing l_start order.
15868 15868           */
15869 15869          ASSERT(nfs_zone() == mi->mi_zone);
15870 15870  
15871 15871          locks = flk_active_locks_for_vp(vp);
15872 15872          ri_llp = NULL;
15873 15873  
15874 15874          for (llp = locks; llp != NULL; llp = llp->ll_next) {
15875 15875                  ASSERT(llp->ll_vp == vp);
15876 15876                  /*
15877 15877                   * Pick locks that belong to this pid/lockowner
15878 15878                   */
15879 15879                  if (llp->ll_flock.l_pid != lost_flp->l_pid)
15880 15880                          continue;
15881 15881  
15882 15882                  nfs4_add_lock_range(lost_flp, &llp->ll_flock, &ri_llp, vp);
15883 15883          }
15884 15884  
15885 15885          /*
15886 15886           * Now we have the list of intersections with the lost lock. These are
15887 15887           * the locks that were/are active before the server replied to the
15888 15888           * last/lost lock. Issue these locks to the server here. Playing these
15889 15889           * locks to the server will re-establish aur current local locking state
15890 15890           * with the v4 server.
15891 15891           * If we get an error, send SIGLOST to the application for that lock.
15892 15892           */
15893 15893  
15894 15894          for (llp = ri_llp; llp != NULL; llp = llp->ll_next) {
15895 15895                  NFS4_DEBUG(nfs4_lost_rqst_debug, (CE_NOTE,
15896 15896                      "nfs4_reinstitute_local_lock_state: need to issue "
15897 15897                      "flock: [%"PRIx64" - %"PRIx64"] : %s",
15898 15898                      llp->ll_flock.l_start,
15899 15899                      llp->ll_flock.l_start + llp->ll_flock.l_len,
15900 15900                      llp->ll_flock.l_type == F_RDLCK ? "READ" :
15901 15901                      llp->ll_flock.l_type == F_WRLCK ? "WRITE" : "INVALID"));
15902 15902                  /*
15903 15903                   * No need to relock what we already have
15904 15904                   */
15905 15905                  if (llp->ll_flock.l_type == lost_flp->l_type)
15906 15906                          continue;
15907 15907  
15908 15908                  push_reinstate(vp, cmd, &llp->ll_flock, cr, lop);
15909 15909          }
15910 15910  
15911 15911          /*
15912 15912           * Now keeping the start of the lost lock as our reference parse the
15913 15913           * newly created ri_llp locklist to find the ranges that we have locked
15914 15914           * with the v4 server but not in the current local locking. We need
15915 15915           * to unlock these ranges.
15916 15916           * These ranges can also be reffered to as those ranges, where the lost
15917 15917           * lock does not overlap with the locks in the ri_llp but are locked
15918 15918           * since the server replied to the lost lock.
15919 15919           */
15920 15920          cur_start = lost_flp->l_start;
15921 15921          lost_flp_end = lock_to_end(lost_flp);
15922 15922  
15923 15923          ul_fl.l_type = F_UNLCK;
15924 15924          ul_fl.l_whence = 0;     /* aka SEEK_SET */
15925 15925          ul_fl.l_sysid = lost_flp->l_sysid;
15926 15926          ul_fl.l_pid = lost_flp->l_pid;
15927 15927  
15928 15928          for (llp = ri_llp; llp != NULL; llp = llp->ll_next) {
15929 15929                  llp_ll_flock_end = lock_to_end(&llp->ll_flock);
15930 15930  
15931 15931                  if (llp->ll_flock.l_start <= cur_start) {
15932 15932                          cur_start = start_check(llp_ll_flock_end);
15933 15933                          continue;
15934 15934                  }
15935 15935                  NFS4_DEBUG(nfs4_lost_rqst_debug, (CE_NOTE,
15936 15936                      "nfs4_reinstitute_local_lock_state: "
15937 15937                      "UNLOCK [%"PRIx64" - %"PRIx64"]",
15938 15938                      cur_start, llp->ll_flock.l_start));
15939 15939  
15940 15940                  ul_fl.l_start = cur_start;
15941 15941                  ul_fl.l_len = end_to_len(cur_start,
15942 15942                      (llp->ll_flock.l_start - 1));
15943 15943  
15944 15944                  push_reinstate(vp, cmd, &ul_fl, cr, lop);
15945 15945                  cur_start = start_check(llp_ll_flock_end);
15946 15946          }
15947 15947  
15948 15948          /*
15949 15949           * In the case where the lost lock ends after all intersecting locks,
15950 15950           * unlock the last part of the lost lock range.
15951 15951           */
15952 15952          if (cur_start != start_check(lost_flp_end)) {
15953 15953                  NFS4_DEBUG(nfs4_lost_rqst_debug, (CE_NOTE,
15954 15954                      "nfs4_reinstitute_local_lock_state: UNLOCK end of the "
15955 15955                      "lost lock region [%"PRIx64" - %"PRIx64"]",
15956 15956                      cur_start, lost_flp->l_start + lost_flp->l_len));
15957 15957  
15958 15958                  ul_fl.l_start = cur_start;
15959 15959                  /*
15960 15960                   * Is it an to-EOF lock? if so unlock till the end
15961 15961                   */
15962 15962                  if (lost_flp->l_len == 0)
15963 15963                          ul_fl.l_len = 0;
15964 15964                  else
15965 15965                          ul_fl.l_len = start_check(lost_flp_end) - cur_start;
15966 15966  
15967 15967                  push_reinstate(vp, cmd, &ul_fl, cr, lop);
15968 15968          }
15969 15969  
15970 15970          if (locks != NULL)
15971 15971                  flk_free_locklist(locks);
15972 15972  
15973 15973          /* Free up our newly created locklist */
15974 15974          for (llp = ri_llp; llp != NULL; ) {
15975 15975                  tmp_llp = llp->ll_next;
15976 15976                  kmem_free(llp, sizeof (locklist_t));
15977 15977                  llp = tmp_llp;
15978 15978          }
15979 15979  
15980 15980          /*
15981 15981           * Now return back to the original calling nfs4frlock()
15982 15982           * and let us naturally drop our seqid syncs.
15983 15983           */
15984 15984  }
15985 15985  
15986 15986  /*
15987 15987   * Create a lost state record for the given lock reinstantiation request
15988 15988   * and push it onto the lost state queue.
15989 15989   */
15990 15990  static void
15991 15991  push_reinstate(vnode_t *vp, int cmd, flock64_t *flk, cred_t *cr,
15992 15992      nfs4_lock_owner_t *lop)
15993 15993  {
15994 15994          nfs4_lost_rqst_t req;
15995 15995          nfs_lock_type4 locktype;
15996 15996          nfs4_error_t e = { EINTR, NFS4_OK, RPC_SUCCESS };
15997 15997  
15998 15998          ASSERT(nfs_zone() == VTOMI4(vp)->mi_zone);
15999 15999  
16000 16000          locktype = flk_to_locktype(cmd, flk->l_type);
16001 16001          nfs4frlock_save_lost_rqst(NFS4_LCK_CTYPE_REINSTATE, EINTR, locktype,
16002 16002              NULL, NULL, lop, flk, &req, cr, vp);
16003 16003          (void) nfs4_start_recovery(&e, VTOMI4(vp), vp, NULL, NULL,
16004 16004              (req.lr_op == OP_LOCK || req.lr_op == OP_LOCKU) ?
16005 16005              &req : NULL, flk->l_type == F_UNLCK ? OP_LOCKU : OP_LOCK,
16006 16006              NULL, NULL, NULL);
16007 16007  }
  
    | 
      ↓ open down ↓ | 
    16007 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX