Print this page
NEX-15279 support NFS server in zone
NEX-15520 online NFS shares cause zoneadm halt to hang in nfs_export_zone_fini
Portions contributed by: Dan Kruchinin dan.kruchinin@nexenta.com
Portions contributed by: Stepan Zastupov stepan.zastupov@gmail.com
Reviewed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
4487 snoop can only work with 2GB files
Reviewed by: Jason King <jason.brian.king@gmail.com>
Reviewed by: Marcel Telka <marcel.telka@nexenta.com>
Reviewed by: Sebastien Roy <sebastien.roy@delphix.com>
Approved by: Garrett D'Amore <garrett@damore.org>
3105 Kernel inet_pton() implementation returns result in host byte order
Reviewed by: Garrett D'Amore <garrett@damore.org>
Reviewed by: Robert Mustacchi <rm@joyent.com>
        
@@ -20,13 +20,16 @@
  */
 
 /*
  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
- * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
  */
 
+/*
+ * 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,14 +49,11 @@
 #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
 
@@ -136,30 +136,37 @@
 /*
  * Update the delegation policy with the
  * value of "new_policy"
  */
 void
-rfs4_set_deleg_policy(srv_deleg_policy_t new_policy)
+rfs4_set_deleg_policy(nfs4_srv_t *nsrv4, 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);
+        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(void)
+rfs4_hold_deleg_policy(nfs4_srv_t *nsrv4)
 {
-        rw_enter(&rfs4_deleg_policy_lock, RW_READER);
+        rw_enter(&nsrv4->deleg_policy_lock, RW_READER);
 }
 
 void
-rfs4_rele_deleg_policy(void)
+rfs4_rele_deleg_policy(nfs4_srv_t *nsrv4)
 {
-        rw_exit(&rfs4_deleg_policy_lock);
+        rw_exit(&nsrv4->deleg_policy_lock);
 }
 
+srv_deleg_policy_t
+nfs4_get_deleg_policy()
+{
+        nfs4_srv_t *nsrv4 = zone_getspecific(rfs4_zone_key, curzone);
+        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,11 +215,11 @@
         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;
+                zthread_exit();
         }
 
         /* Mark the cbinfo as having a thread in the NULL callback */
         cbp->cb_nullcaller = TRUE;
 
@@ -276,11 +283,11 @@
         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;
+                zthread_exit();
         }
 
         /* mark rfs4_client_t as CALLBACK NULL in progress */
         cbp->cb_state = CB_INPROG;
         mutex_exit(cbp->cb_lock);
@@ -318,12 +325,12 @@
                 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,11 +692,11 @@
 
         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,
+        (void) zthread_create(NULL, 0, rfs4_do_cb_null, cp, 0,
             minclsyspri);
 }
 
 static void
 rfs4args_cb_recall_free(nfs_cb_argop4 *argop)
@@ -946,12 +953,12 @@
         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,11 +982,11 @@
         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;
+                zthread_exit();
         }
 
         mutex_exit(fp->rf_dinfo.rd_recall_lock);
 
         mutex_init(&cpr_lock, NULL, MUTEX_DEFAULT, NULL);
@@ -1008,11 +1015,11 @@
                 arg->trunc = map->trunc;
                 arg->dsp = dsp;
 
                 recall_count++;
 
-                (void) thread_create(NULL, 0, do_recall, arg, 0, &p0, TS_RUN,
+                (void) zthread_create(NULL, 0, do_recall, arg, 0,
                     minclsyspri);
         }
 
         rfs4_dbe_unlock(fp->rf_dbe);
 
@@ -1033,10 +1040,11 @@
         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,11 +1076,11 @@
         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,
+        (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,16 +1212,16 @@
 /*
  * 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_delegation_policy(nfs4_srv_t *nsrv4, open_delegation_type4 dtype,
     rfs4_dinfo_t *dinfo, clientid4 cid)
 {
         time_t elapsed;
 
-        if (rfs4_deleg_policy != SRV_NORMAL_DELEGATE)
+        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,25 +1260,28 @@
  * 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 = zone_getspecific(rfs4_zone_key, curzone);
+
         /* Is the server even providing delegations? */
-        if (rfs4_deleg_policy == SRV_NEVER_DELEGATE || dreq == DELEG_NONE)
+        if (nsrv4->nfs4_deleg_policy == SRV_NEVER_DELEGATE || dreq == DELEG_NONE)
                 return (NULL);
 
         /* Check to see if delegations have been temporarily disabled */
-        mutex_enter(&rfs4_deleg_lock);
+        mutex_enter(&nsrv4->deleg_lock);
         no_delegation = rfs4_deleg_disabled;
-        mutex_exit(&rfs4_deleg_lock);
+        mutex_exit(&nsrv4->deleg_lock);
 
         if (no_delegation)
                 return (NULL);
 
         /* Don't grant a delegation if a deletion is impending. */
@@ -1347,11 +1358,11 @@
 
                 /*
                  * Based on policy and the history of the file get the
                  * actual delegation.
                  */
-                dtype = rfs4_delegation_policy(dtype, &fp->rf_dinfo,
+                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,12 +1447,14 @@
 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 = zone_getspecific(rfs4_zone_key, curzone);
+
         /* Is delegation enabled? */
-        if (rfs4_deleg_policy == SRV_NEVER_DELEGATE)
+        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,28 +1515,30 @@
  * 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;
 
-        rfs4_hold_deleg_policy();
+        nsrv4 = zone_getspecific(rfs4_zone_key, curzone);
+        rfs4_hold_deleg_policy(nsrv4);
 
         /* Is delegation enabled? */
-        if (rfs4_deleg_policy != SRV_NEVER_DELEGATE) {
+        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();
+        rfs4_rele_deleg_policy(nsrv4);
         return (rc);
 }
 
 /*
  * Release a hold on the hold_grant counter which
@@ -1531,11 +1546,13 @@
  * or a rename is in progress.
  */
 void
 rfs4_clear_dont_grant(rfs4_file_t *fp)
 {
-        if (rfs4_deleg_policy == SRV_NEVER_DELEGATE)
+        nfs4_srv_t *nsrv4 = zone_getspecific(rfs4_zone_key, curzone);
+
+        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,22 +1884,28 @@
 }
 
 void
 rfs4_disable_delegation(void)
 {
-        mutex_enter(&rfs4_deleg_lock);
+        nfs4_srv_t *nsrv4;
+
+        nsrv4 = zone_getspecific(rfs4_zone_key, curzone);
+        mutex_enter(&nsrv4->deleg_lock);
         rfs4_deleg_disabled++;
-        mutex_exit(&rfs4_deleg_lock);
+        mutex_exit(&nsrv4->deleg_lock);
 }
 
 void
 rfs4_enable_delegation(void)
 {
-        mutex_enter(&rfs4_deleg_lock);
+        nfs4_srv_t *nsrv4;
+
+        nsrv4 = zone_getspecific(rfs4_zone_key, curzone);
+        mutex_enter(&nsrv4->deleg_lock);
         ASSERT(rfs4_deleg_disabled > 0);
         rfs4_deleg_disabled--;
-        mutex_exit(&rfs4_deleg_lock);
+        mutex_exit(&nsrv4->deleg_lock);
 }
 
 void
 rfs4_mon_hold(void *arg)
 {