Print this page
11083 support NFS server in zone
Portions contributed by: Dan Kruchinin <dan.kruchinin@nexenta.com>
Portions contributed by: Stepan Zastupov <stepan.zastupov@gmail.com>
Portions contributed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
Portions contributed by: Mike Zeller <mike@mikezeller.net>
Portions contributed by: Dan McDonald <danmcd@joyent.com>
Portions contributed by: Gordon Ross <gordon.w.ross@gmail.com>
Portions contributed by: Vitaliy Gusev <gusev.vitaliy@gmail.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Jason King <jbk@joyent.com>
Reviewed by: C Fraire <cfraire@me.com>
Change-Id: I22f289d357503f9b48a0bc2482cc4328a6d43d16
        
*** 20,32 ****
   */
  
  /*
   * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
   * Use is subject to license terms.
-  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
   */
  
  #include <sys/systm.h>
  #include <rpc/auth.h>
  #include <rpc/clnt.h>
  #include <nfs/nfs4_kprot.h>
  #include <nfs/nfs4.h>
--- 20,35 ----
   */
  
  /*
   * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
   * Use is subject to license terms.
   */
  
+ /*
+  * Copyright 2018 Nexenta Systems, Inc.
+  */
+ 
  #include <sys/systm.h>
  #include <rpc/auth.h>
  #include <rpc/clnt.h>
  #include <nfs/nfs4_kprot.h>
  #include <nfs/nfs4.h>
*** 46,59 ****
  #include <inet/ip.h>
  #include <inet/ip6.h>
  
  #define MAX_READ_DELEGATIONS 5
  
- krwlock_t rfs4_deleg_policy_lock;
- srv_deleg_policy_t rfs4_deleg_policy = SRV_NEVER_DELEGATE;
  static int rfs4_deleg_wlp = 5;
- kmutex_t rfs4_deleg_lock;
  static int rfs4_deleg_disabled;
  static int rfs4_max_setup_cb_tries = 5;
  
  #ifdef DEBUG
  
--- 49,59 ----
*** 136,165 ****
  /*
   * Update the delegation policy with the
   * value of "new_policy"
   */
  void
! rfs4_set_deleg_policy(srv_deleg_policy_t new_policy)
  {
!         rw_enter(&rfs4_deleg_policy_lock, RW_WRITER);
!         rfs4_deleg_policy = new_policy;
!         rw_exit(&rfs4_deleg_policy_lock);
  }
  
  void
! rfs4_hold_deleg_policy(void)
  {
!         rw_enter(&rfs4_deleg_policy_lock, RW_READER);
  }
  
  void
! rfs4_rele_deleg_policy(void)
  {
!         rw_exit(&rfs4_deleg_policy_lock);
  }
  
  
  /*
   * This free function is to be used when the client struct is being
   * released and nothing at all is needed of the callback info any
   * longer.
   */
--- 136,172 ----
  /*
   * Update the delegation policy with the
   * value of "new_policy"
   */
  void
! rfs4_set_deleg_policy(nfs4_srv_t *nsrv4, srv_deleg_policy_t new_policy)
  {
!         rw_enter(&nsrv4->deleg_policy_lock, RW_WRITER);
!         nsrv4->nfs4_deleg_policy = new_policy;
!         rw_exit(&nsrv4->deleg_policy_lock);
  }
  
  void
! rfs4_hold_deleg_policy(nfs4_srv_t *nsrv4)
  {
!         rw_enter(&nsrv4->deleg_policy_lock, RW_READER);
  }
  
  void
! rfs4_rele_deleg_policy(nfs4_srv_t *nsrv4)
  {
!         rw_exit(&nsrv4->deleg_policy_lock);
  }
  
+ srv_deleg_policy_t
+ nfs4_get_deleg_policy()
+ {
+         nfs4_srv_t *nsrv4 = nfs4_get_srv();
+         return (nsrv4->nfs4_deleg_policy);
+ }
  
+ 
  /*
   * This free function is to be used when the client struct is being
   * released and nothing at all is needed of the callback info any
   * longer.
   */
*** 208,218 ****
          mutex_enter(cbp->cb_lock);
          /* If another thread is doing CB_NULL RPC then return */
          if (cbp->cb_nullcaller == TRUE) {
                  mutex_exit(cbp->cb_lock);
                  rfs4_client_rele(cp);
!                 return;
          }
  
          /* Mark the cbinfo as having a thread in the NULL callback */
          cbp->cb_nullcaller = TRUE;
  
--- 215,225 ----
          mutex_enter(cbp->cb_lock);
          /* If another thread is doing CB_NULL RPC then return */
          if (cbp->cb_nullcaller == TRUE) {
                  mutex_exit(cbp->cb_lock);
                  rfs4_client_rele(cp);
!                 zthread_exit();
          }
  
          /* Mark the cbinfo as having a thread in the NULL callback */
          cbp->cb_nullcaller = TRUE;
  
*** 276,286 ****
          if (cbp->cb_state != CB_NONE) {
                  cv_broadcast(cbp->cb_cv);       /* let the others know */
                  cbp->cb_nullcaller = FALSE;
                  mutex_exit(cbp->cb_lock);
                  rfs4_client_rele(cp);
!                 return;
          }
  
          /* mark rfs4_client_t as CALLBACK NULL in progress */
          cbp->cb_state = CB_INPROG;
          mutex_exit(cbp->cb_lock);
--- 283,293 ----
          if (cbp->cb_state != CB_NONE) {
                  cv_broadcast(cbp->cb_cv);       /* let the others know */
                  cbp->cb_nullcaller = FALSE;
                  mutex_exit(cbp->cb_lock);
                  rfs4_client_rele(cp);
!                 zthread_exit();
          }
  
          /* mark rfs4_client_t as CALLBACK NULL in progress */
          cbp->cb_state = CB_INPROG;
          mutex_exit(cbp->cb_lock);
*** 318,329 ****
                  cbp->cb_timefailed = gethrestime_sec(); /* observability */
  
          cv_broadcast(cbp->cb_cv);       /* start up the other threads */
          cbp->cb_nullcaller = FALSE;
          mutex_exit(cbp->cb_lock);
- 
          rfs4_client_rele(cp);
  }
  
  /*
   * Given a client struct, inspect the callback info to see if the
   * callback path is up and available.
--- 325,336 ----
                  cbp->cb_timefailed = gethrestime_sec(); /* observability */
  
          cv_broadcast(cbp->cb_cv);       /* start up the other threads */
          cbp->cb_nullcaller = FALSE;
          mutex_exit(cbp->cb_lock);
          rfs4_client_rele(cp);
+         zthread_exit();
  }
  
  /*
   * Given a client struct, inspect the callback info to see if the
   * callback path is up and available.
*** 685,695 ****
  
          cp->rc_cbinfo.cb_newer.cb_confirmed = TRUE;
  
          rfs4_dbe_hold(cp->rc_dbe); /* hold the client struct for thread */
  
!         (void) thread_create(NULL, 0, rfs4_do_cb_null, cp, 0, &p0, TS_RUN,
              minclsyspri);
  }
  
  static void
  rfs4args_cb_recall_free(nfs_cb_argop4 *argop)
--- 692,702 ----
  
          cp->rc_cbinfo.cb_newer.cb_confirmed = TRUE;
  
          rfs4_dbe_hold(cp->rc_dbe); /* hold the client struct for thread */
  
!         (void) zthread_create(NULL, 0, rfs4_do_cb_null, cp, 0,
              minclsyspri);
  }
  
  static void
  rfs4args_cb_recall_free(nfs_cb_argop4 *argop)
*** 946,957 ****
          mutex_enter(&cpr_lock);
          CALLB_CPR_EXIT(&cpr_info);
          mutex_destroy(&cpr_lock);
  
          rfs4_deleg_state_rele(dsp); /* release the hold for this thread */
- 
          kmem_free(arg, sizeof (struct recall_arg));
  }
  
  struct master_recall_args {
      rfs4_file_t *fp;
      void (*recall)(rfs4_deleg_state_t *, bool_t);
--- 953,964 ----
          mutex_enter(&cpr_lock);
          CALLB_CPR_EXIT(&cpr_info);
          mutex_destroy(&cpr_lock);
  
          rfs4_deleg_state_rele(dsp); /* release the hold for this thread */
          kmem_free(arg, sizeof (struct recall_arg));
+         zthread_exit();
  }
  
  struct master_recall_args {
      rfs4_file_t *fp;
      void (*recall)(rfs4_deleg_state_t *, bool_t);
*** 975,985 ****
          if (fp->rf_dinfo.rd_recall_count != 0) {
                  mutex_exit(fp->rf_dinfo.rd_recall_lock);
                  rfs4_dbe_rele_nolock(fp->rf_dbe);
                  rfs4_dbe_unlock(fp->rf_dbe);
                  kmem_free(map, sizeof (struct master_recall_args));
!                 return;
          }
  
          mutex_exit(fp->rf_dinfo.rd_recall_lock);
  
          mutex_init(&cpr_lock, NULL, MUTEX_DEFAULT, NULL);
--- 982,992 ----
          if (fp->rf_dinfo.rd_recall_count != 0) {
                  mutex_exit(fp->rf_dinfo.rd_recall_lock);
                  rfs4_dbe_rele_nolock(fp->rf_dbe);
                  rfs4_dbe_unlock(fp->rf_dbe);
                  kmem_free(map, sizeof (struct master_recall_args));
!                 zthread_exit();
          }
  
          mutex_exit(fp->rf_dinfo.rd_recall_lock);
  
          mutex_init(&cpr_lock, NULL, MUTEX_DEFAULT, NULL);
*** 1008,1018 ****
                  arg->trunc = map->trunc;
                  arg->dsp = dsp;
  
                  recall_count++;
  
!                 (void) thread_create(NULL, 0, do_recall, arg, 0, &p0, TS_RUN,
                      minclsyspri);
          }
  
          rfs4_dbe_unlock(fp->rf_dbe);
  
--- 1015,1025 ----
                  arg->trunc = map->trunc;
                  arg->dsp = dsp;
  
                  recall_count++;
  
!                 (void) zthread_create(NULL, 0, do_recall, arg, 0,
                      minclsyspri);
          }
  
          rfs4_dbe_unlock(fp->rf_dbe);
  
*** 1033,1042 ****
--- 1040,1050 ----
          rfs4_file_rele(fp);
          kmem_free(map, sizeof (struct master_recall_args));
          mutex_enter(&cpr_lock);
          CALLB_CPR_EXIT(&cpr_info);
          mutex_destroy(&cpr_lock);
+         zthread_exit();
  }
  
  static void
  rfs4_recall_file(rfs4_file_t *fp,
      void (*recall)(rfs4_deleg_state_t *, bool_t trunc),
*** 1068,1078 ****
          args = kmem_alloc(sizeof (struct master_recall_args), KM_SLEEP);
          args->fp = fp;
          args->recall = recall;
          args->trunc = trunc;
  
!         (void) thread_create(NULL, 0, do_recall_file, args, 0, &p0, TS_RUN,
              minclsyspri);
  }
  
  void
  rfs4_recall_deleg(rfs4_file_t *fp, bool_t trunc, rfs4_client_t *cp)
--- 1076,1086 ----
          args = kmem_alloc(sizeof (struct master_recall_args), KM_SLEEP);
          args->fp = fp;
          args->recall = recall;
          args->trunc = trunc;
  
!         (void) zthread_create(NULL, 0, do_recall_file, args, 0,
              minclsyspri);
  }
  
  void
  rfs4_recall_deleg(rfs4_file_t *fp, bool_t trunc, rfs4_client_t *cp)
*** 1204,1219 ****
  /*
   * Given the desired delegation type and the "history" of the file
   * determine the actual delegation type to return.
   */
  static open_delegation_type4
! rfs4_delegation_policy(open_delegation_type4 dtype,
      rfs4_dinfo_t *dinfo, clientid4 cid)
  {
          time_t elapsed;
  
!         if (rfs4_deleg_policy != SRV_NORMAL_DELEGATE)
                  return (OPEN_DELEGATE_NONE);
  
          /*
           * Has this file/delegation ever been recalled?  If not then
           * no further checks for a delegation race need to be done.
--- 1212,1227 ----
  /*
   * Given the desired delegation type and the "history" of the file
   * determine the actual delegation type to return.
   */
  static open_delegation_type4
! rfs4_delegation_policy(nfs4_srv_t *nsrv4, open_delegation_type4 dtype,
      rfs4_dinfo_t *dinfo, clientid4 cid)
  {
          time_t elapsed;
  
!         if (nsrv4->nfs4_deleg_policy != SRV_NORMAL_DELEGATE)
                  return (OPEN_DELEGATE_NONE);
  
          /*
           * Has this file/delegation ever been recalled?  If not then
           * no further checks for a delegation race need to be done.
*** 1252,1276 ****
   * The state and associate file entry must be locked
   */
  rfs4_deleg_state_t *
  rfs4_grant_delegation(delegreq_t dreq, rfs4_state_t *sp, int *recall)
  {
          rfs4_file_t *fp = sp->rs_finfo;
          open_delegation_type4 dtype;
          int no_delegation;
  
          ASSERT(rfs4_dbe_islocked(sp->rs_dbe));
          ASSERT(rfs4_dbe_islocked(fp->rf_dbe));
  
          /* Is the server even providing delegations? */
!         if (rfs4_deleg_policy == SRV_NEVER_DELEGATE || dreq == DELEG_NONE)
                  return (NULL);
  
          /* Check to see if delegations have been temporarily disabled */
!         mutex_enter(&rfs4_deleg_lock);
          no_delegation = rfs4_deleg_disabled;
!         mutex_exit(&rfs4_deleg_lock);
  
          if (no_delegation)
                  return (NULL);
  
          /* Don't grant a delegation if a deletion is impending. */
--- 1260,1289 ----
   * The state and associate file entry must be locked
   */
  rfs4_deleg_state_t *
  rfs4_grant_delegation(delegreq_t dreq, rfs4_state_t *sp, int *recall)
  {
+         nfs4_srv_t *nsrv4;
          rfs4_file_t *fp = sp->rs_finfo;
          open_delegation_type4 dtype;
          int no_delegation;
  
          ASSERT(rfs4_dbe_islocked(sp->rs_dbe));
          ASSERT(rfs4_dbe_islocked(fp->rf_dbe));
  
+         nsrv4 = nfs4_get_srv();
+ 
          /* Is the server even providing delegations? */
!         if (nsrv4->nfs4_deleg_policy == SRV_NEVER_DELEGATE ||
!             dreq == DELEG_NONE) {
                  return (NULL);
+         }
  
          /* Check to see if delegations have been temporarily disabled */
!         mutex_enter(&nsrv4->deleg_lock);
          no_delegation = rfs4_deleg_disabled;
!         mutex_exit(&nsrv4->deleg_lock);
  
          if (no_delegation)
                  return (NULL);
  
          /* Don't grant a delegation if a deletion is impending. */
*** 1347,1357 ****
  
                  /*
                   * Based on policy and the history of the file get the
                   * actual delegation.
                   */
!                 dtype = rfs4_delegation_policy(dtype, &fp->rf_dinfo,
                      sp->rs_owner->ro_client->rc_clientid);
  
                  if (dtype == OPEN_DELEGATE_NONE)
                          return (NULL);
                  break;
--- 1360,1370 ----
  
                  /*
                   * Based on policy and the history of the file get the
                   * actual delegation.
                   */
!                 dtype = rfs4_delegation_policy(nsrv4, dtype, &fp->rf_dinfo,
                      sp->rs_owner->ro_client->rc_clientid);
  
                  if (dtype == OPEN_DELEGATE_NONE)
                          return (NULL);
                  break;
*** 1436,1447 ****
  rfs4_check_delegated_byfp(int mode, rfs4_file_t *fp,
      bool_t trunc, bool_t do_delay, bool_t is_rm, clientid4 *cp)
  {
          rfs4_deleg_state_t *dsp;
  
          /* Is delegation enabled? */
!         if (rfs4_deleg_policy == SRV_NEVER_DELEGATE)
                  return (FALSE);
  
          /* do we have a delegation on this file? */
          rfs4_dbe_lock(fp->rf_dbe);
          if (fp->rf_dinfo.rd_dtype == OPEN_DELEGATE_NONE) {
--- 1449,1462 ----
  rfs4_check_delegated_byfp(int mode, rfs4_file_t *fp,
      bool_t trunc, bool_t do_delay, bool_t is_rm, clientid4 *cp)
  {
          rfs4_deleg_state_t *dsp;
  
+         nfs4_srv_t *nsrv4 = nfs4_get_srv();
+ 
          /* Is delegation enabled? */
!         if (nsrv4->nfs4_deleg_policy == SRV_NEVER_DELEGATE)
                  return (FALSE);
  
          /* do we have a delegation on this file? */
          rfs4_dbe_lock(fp->rf_dbe);
          if (fp->rf_dinfo.rd_dtype == OPEN_DELEGATE_NONE) {
*** 1502,1529 ****
   * drop the request and in the case of v3 JUKEBOX should be returned.
   */
  bool_t
  rfs4_check_delegated(int mode, vnode_t *vp, bool_t trunc)
  {
          rfs4_file_t *fp;
          bool_t create = FALSE;
          bool_t rc = FALSE;
  
!         rfs4_hold_deleg_policy();
  
          /* Is delegation enabled? */
!         if (rfs4_deleg_policy != SRV_NEVER_DELEGATE) {
                  fp = rfs4_findfile(vp, NULL, &create);
                  if (fp != NULL) {
                          if (rfs4_check_delegated_byfp(mode, fp, trunc,
                              TRUE, FALSE, NULL)) {
                                  rc = TRUE;
                          }
                          rfs4_file_rele(fp);
                  }
          }
!         rfs4_rele_deleg_policy();
          return (rc);
  }
  
  /*
   * Release a hold on the hold_grant counter which
--- 1517,1546 ----
   * drop the request and in the case of v3 JUKEBOX should be returned.
   */
  bool_t
  rfs4_check_delegated(int mode, vnode_t *vp, bool_t trunc)
  {
+         nfs4_srv_t *nsrv4;
          rfs4_file_t *fp;
          bool_t create = FALSE;
          bool_t rc = FALSE;
  
!         nsrv4 = nfs4_get_srv();
!         rfs4_hold_deleg_policy(nsrv4);
  
          /* Is delegation enabled? */
!         if (nsrv4->nfs4_deleg_policy != SRV_NEVER_DELEGATE) {
                  fp = rfs4_findfile(vp, NULL, &create);
                  if (fp != NULL) {
                          if (rfs4_check_delegated_byfp(mode, fp, trunc,
                              TRUE, FALSE, NULL)) {
                                  rc = TRUE;
                          }
                          rfs4_file_rele(fp);
                  }
          }
!         rfs4_rele_deleg_policy(nsrv4);
          return (rc);
  }
  
  /*
   * Release a hold on the hold_grant counter which
*** 1531,1541 ****
   * or a rename is in progress.
   */
  void
  rfs4_clear_dont_grant(rfs4_file_t *fp)
  {
!         if (rfs4_deleg_policy == SRV_NEVER_DELEGATE)
                  return;
          rfs4_dbe_lock(fp->rf_dbe);
          ASSERT(fp->rf_dinfo.rd_hold_grant > 0);
          fp->rf_dinfo.rd_hold_grant--;
          fp->rf_dinfo.rd_time_rm_delayed = 0;
--- 1548,1560 ----
   * or a rename is in progress.
   */
  void
  rfs4_clear_dont_grant(rfs4_file_t *fp)
  {
!         nfs4_srv_t *nsrv4 = nfs4_get_srv();
! 
!         if (nsrv4->nfs4_deleg_policy == SRV_NEVER_DELEGATE)
                  return;
          rfs4_dbe_lock(fp->rf_dbe);
          ASSERT(fp->rf_dinfo.rd_hold_grant > 0);
          fp->rf_dinfo.rd_hold_grant--;
          fp->rf_dinfo.rd_time_rm_delayed = 0;
*** 1867,1888 ****
  }
  
  void
  rfs4_disable_delegation(void)
  {
!         mutex_enter(&rfs4_deleg_lock);
          rfs4_deleg_disabled++;
!         mutex_exit(&rfs4_deleg_lock);
  }
  
  void
  rfs4_enable_delegation(void)
  {
!         mutex_enter(&rfs4_deleg_lock);
          ASSERT(rfs4_deleg_disabled > 0);
          rfs4_deleg_disabled--;
!         mutex_exit(&rfs4_deleg_lock);
  }
  
  void
  rfs4_mon_hold(void *arg)
  {
--- 1886,1913 ----
  }
  
  void
  rfs4_disable_delegation(void)
  {
!         nfs4_srv_t *nsrv4;
! 
!         nsrv4 = nfs4_get_srv();
!         mutex_enter(&nsrv4->deleg_lock);
          rfs4_deleg_disabled++;
!         mutex_exit(&nsrv4->deleg_lock);
  }
  
  void
  rfs4_enable_delegation(void)
  {
!         nfs4_srv_t *nsrv4;
! 
!         nsrv4 = nfs4_get_srv();
!         mutex_enter(&nsrv4->deleg_lock);
          ASSERT(rfs4_deleg_disabled > 0);
          rfs4_deleg_disabled--;
!         mutex_exit(&nsrv4->deleg_lock);
  }
  
  void
  rfs4_mon_hold(void *arg)
  {