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
        
@@ -21,10 +21,11 @@
 
 /*
  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright 2016 Nexenta Systems, Inc.  All rights reserved.
  * Copyright 2016 Jason King.
+ * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  */
 
 /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
 /*        All Rights Reserved   */
 
@@ -35,11 +36,16 @@
 #include <nfs/auth.h>
 #include <sys/vnode.h>
 #include <nfs/nfs4.h>
 #include <sys/kiconv.h>
 #include <sys/avl.h>
+#include <sys/zone.h>
 
+#ifdef _KERNEL
+#include <sys/pkp_hash.h> /* for PKP_HASH_SIZE */
+#endif /* _KERNEL */
+
 #ifdef  __cplusplus
 extern "C" {
 #endif
 
 /*
@@ -465,23 +471,29 @@
         struct exportinfo  *tree_exi;
         struct exp_visible *tree_vis;
 } treenode_t;
 
 /*
- * TREE_ROOT checks if the node corresponds to a filesystem root
+ * Now that we have links to chase, we can get the zone rootvp just from
+ * an export.  No current-zone-context needed.
+ */
+#define EXI_TO_ZONEROOTVP(exi) ((exi)->exi_ne->exi_root->exi_vp)
+
+/*
+ * TREE_ROOT checks if the node corresponds to a filesystem root or
+ * the zone's root directory.
  * TREE_EXPORTED checks if the node is explicitly shared
  */
 
 #define TREE_ROOT(t) \
-        ((t)->tree_exi && (t)->tree_exi->exi_vp->v_flag & VROOT)
+        ((t)->tree_exi != NULL && \
+        (((t)->tree_exi->exi_vp->v_flag & VROOT) || \
+        VN_CMP(EXI_TO_ZONEROOTVP((t)->tree_exi), (t)->tree_exi->exi_vp)))
 
 #define TREE_EXPORTED(t) \
         ((t)->tree_exi && !PSEUDO((t)->tree_exi))
 
-/* Root of nfs pseudo namespace */
-extern treenode_t *ns_root;
-
 #define EXPTABLESIZE   256
 
 struct exp_hash {
         struct exportinfo       *prev;  /* ptr to the previous exportinfo */
         struct exportinfo       *next;  /* ptr to the next exportinfo */
@@ -515,23 +527,33 @@
         struct treenode         *exi_tree;
         fhandle_t               exi_fh;
         krwlock_t               exi_cache_lock;
         kmutex_t                exi_lock;
         uint_t                  exi_count;
+        zoneid_t                exi_zoneid;
         vnode_t                 *exi_vp;
         vnode_t                 *exi_dvp;
         avl_tree_t              *exi_cache[AUTH_TABLESIZE];
         struct log_buffer       *exi_logbuffer;
         struct exp_visible      *exi_visible;
         struct charset_cache    *exi_charset;
         unsigned                exi_volatile_dev:1;
         unsigned                exi_moved:1;
+        int                     exi_id;
+        avl_node_t              exi_id_link;
+        /*
+         * Soft-reference/backpointer to zone's nfs_export_t.
+         * This allows us access to the zone's rootvp (stored in
+         * exi_ne->exi_root->exi_vp) even if the current thread isn't in
+         * same-zone context.
+         */
+        struct nfs_export       *exi_ne;
 #ifdef VOLATILE_FH_TEST
         uint32_t                exi_volatile_id;
         struct ex_vol_rename    *exi_vol_rename;
         kmutex_t                exi_vol_rename_lock;
-#endif /* VOLATILE_FH_TEST */
+#endif /* VOLATILE_FH_TEST -- keep last! */
 };
 
 typedef struct exportinfo exportinfo_t;
 typedef struct exportdata exportdata_t;
 typedef struct secinfo secinfo_t;
@@ -606,12 +628,16 @@
     struct svc_req *, cred_t *, uid_t *, gid_t *, uint_t *, gid_t **);
 extern int      nfsauth4_secinfo_access(struct exportinfo *,
     struct svc_req *, int, int, cred_t *);
 extern int      nfsauth_cache_clnt_compar(const void *, const void *);
 extern int      nfs_fhbcmp(char *, char *, int);
-extern int      nfs_exportinit(void);
+extern void     nfs_exportinit(void);
 extern void     nfs_exportfini(void);
+extern void     nfs_export_zone_init(nfs_globals_t *);
+extern void     nfs_export_zone_fini(nfs_globals_t *);
+extern void     nfs_export_zone_shutdown(nfs_globals_t *);
+extern int      nfs_export_get_rootfh(nfs_globals_t *);
 extern int      chk_clnt_sec(struct exportinfo *, struct svc_req *);
 extern int      makefh(fhandle_t *, struct vnode *, struct exportinfo *);
 extern int      makefh_ol(fhandle_t *, struct exportinfo *, uint_t);
 extern int      makefh3(nfs_fh3 *, struct vnode *, struct exportinfo *);
 extern int      makefh3_ol(nfs_fh3 *, struct exportinfo *, uint_t);
@@ -623,50 +649,82 @@
 extern void     exi_rele(struct exportinfo *);
 extern struct exportinfo *nfs_vptoexi(vnode_t *, vnode_t *, cred_t *, int *,
     int *, bool_t);
 extern int      nfs_check_vpexi(vnode_t *, vnode_t *, cred_t *,
                         struct exportinfo **);
-extern void     export_link(struct exportinfo *);
-extern void     export_unlink(struct exportinfo *);
-extern vnode_t *untraverse(vnode_t *);
+extern vnode_t *untraverse(vnode_t *, vnode_t *);
 extern int      vn_is_nfs_reparse(vnode_t *, cred_t *);
 extern int      client_is_downrev(struct svc_req *);
 extern char    *build_symlink(vnode_t *, cred_t *, size_t *);
 
+extern fhandle_t nullfh2;       /* for comparing V2 filehandles */
+
+typedef struct nfs_export {
+        /* Root of nfs pseudo namespace */
+        treenode_t *ns_root;
+
+        nfs_globals_t           *ne_globals;    /* "up" pointer */
+
+        struct exportinfo *exptable_path_hash[PKP_HASH_SIZE];
+        struct exportinfo *exptable[EXPTABLESIZE];
+
+        /*
+         * Read/Write lock that protects the exportinfo list.  This lock
+         * must be held when searching or modifiying the exportinfo list.
+         */
+        krwlock_t exported_lock;
+
+        /* "public" and default (root) location for public filehandle */
+        struct exportinfo *exi_public;
+        struct exportinfo *exi_root;
+        /* For checking default public file handle */
+        fid_t exi_rootfid;
+        /* For comparing V2 filehandles */
+        fhandle_t nullfh2;
+
+        /* The change attribute value of the root of nfs pseudo namespace */
+        timespec_t ns_root_change;
+} nfs_export_t;
+
 /*
  * Functions that handle the NFSv4 server namespace
  */
 extern exportinfo_t *vis2exi(treenode_t *);
 extern int      treeclimb_export(struct exportinfo *);
-extern void     treeclimb_unexport(struct exportinfo *);
+extern void     treeclimb_unexport(nfs_export_t *, struct exportinfo *);
 extern int      nfs_visible(struct exportinfo *, vnode_t *, int *);
 extern int      nfs_visible_inode(struct exportinfo *, ino64_t,
     struct exp_visible **);
 extern int      has_visible(struct exportinfo *, vnode_t *);
 extern void     free_visible(struct exp_visible *);
 extern int      nfs_exported(struct exportinfo *, vnode_t *);
-extern struct exportinfo *pseudo_exportfs(vnode_t *, fid_t *,
+extern struct exportinfo *pseudo_exportfs(nfs_export_t *, vnode_t *, fid_t *,
     struct exp_visible *, struct exportdata *);
 extern int      vop_fid_pseudo(vnode_t *, fid_t *);
 extern int      nfs4_vget_pseudo(struct exportinfo *, vnode_t **, fid_t *);
 extern bool_t   nfs_visible_change(struct exportinfo *, vnode_t *,
     timespec_t *);
-extern void     tree_update_change(treenode_t *, timespec_t *);
+extern void     tree_update_change(nfs_export_t *, treenode_t *, timespec_t *);
+extern void     rfs4_clean_state_exi(nfs_export_t *, struct exportinfo *);
+
 /*
  * Functions that handle the NFSv4 server namespace security flavors
  * information.
  */
 extern void     srv_secinfo_exp2pseu(struct exportdata *, struct exportdata *);
 extern void     srv_secinfo_list_free(struct secinfo *, int);
 
+extern nfs_export_t *nfs_get_export();
+extern void     export_link(nfs_export_t *, struct exportinfo *);
+extern void     export_unlink(nfs_export_t *, struct exportinfo *);
+
 /*
- * "public" and default (root) location for public filehandle
+ * exi_id support
  */
-extern struct exportinfo *exi_public, *exi_root;
-extern fhandle_t nullfh2;       /* for comparing V2 filehandles */
-extern krwlock_t exported_lock;
-extern struct exportinfo *exptable[];
+extern kmutex_t  nfs_exi_id_lock;
+extern avl_tree_t exi_id_tree;
+extern int exi_id_get_next(void);
 
 /*
  * Two macros for identifying public filehandles.
  * A v2 public filehandle is 32 zero bytes.
  * A v3 public filehandle is zero length.