Print this page
NEX-14666 Need to provide SMB 2.1 Client
NEX-17187 panic in smbfs_acl_store
NEX-17231 smbfs create xattr files finds wrong file
NEX-17224 smbfs lookup EINVAL should be ENOENT
NEX-17260 SMB1 client fails to list directory after NEX-14666
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
Reviewed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
and: (cleanup)
NEX-16824 SMB client connection setup rework
NEX-17232 SMB client reconnect failures
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
and: (improve debug)

@@ -32,10 +32,12 @@
  * $Id: smb_conn.c,v 1.27.166.1 2005/05/27 02:35:29 lindak Exp $
  */
 /*
  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  */
 
 /*
  * Connection engine.
  */

@@ -59,10 +61,11 @@
 #include <sys/u8_textprep.h>
 
 #include <netsmb/smb_osdep.h>
 
 #include <netsmb/smb.h>
+#include <netsmb/smb2.h>
 #include <netsmb/smb_conn.h>
 #include <netsmb/smb_subr.h>
 #include <netsmb/smb_tran.h>
 #include <netsmb/smb_pass.h>
 

@@ -78,10 +81,13 @@
 static void smb_vc_gone(struct smb_connobj *cp);
 
 static void smb_share_free(struct smb_connobj *cp);
 static void smb_share_gone(struct smb_connobj *cp);
 
+static void smb_fh_free(struct smb_connobj *cp);
+static void smb_fh_gone(struct smb_connobj *cp);
+
 int
 smb_sm_init(void)
 {
         smb_co_init(&smb_vclist, SMBL_SM, "smbsm");
         return (0);

@@ -103,11 +109,11 @@
 
 void
 smb_sm_done(void)
 {
         /*
-         * XXX Q4BP why are we not iterating on smb_vclist here?
+         * Why are we not iterating on smb_vclist here?
          * Because the caller has just called smb_sm_idle() to
          * make sure we have no VCs before calling this.
          */
         smb_co_done(&smb_vclist);
 }

@@ -179,10 +185,20 @@
 {
         struct smb_connobj *parent;
         int old_flags;
 
         SMB_CO_LOCK(co);
+
+        /*
+         * When VC usecount goes from 2 to 1, signal the iod_idle CV.
+         * It's unfortunate to have object type-specific logic here,
+         * but it's hard to do this anywhere else.
+         */
+        if (co->co_level == SMBL_VC && co->co_usecount == 2) {
+                smb_vc_t *vcp = CPTOVC(co);
+                cv_signal(&vcp->iod_idle);
+        }
         if (co->co_usecount > 1) {
                 co->co_usecount--;
                 SMB_CO_UNLOCK(co);
                 return;
         }

@@ -363,14 +379,16 @@
                 iconv_close(vcp->vc_toserver);
 #endif
 
         if (vcp->vc_mackey != NULL)
                 kmem_free(vcp->vc_mackey, vcp->vc_mackeylen);
+        if (vcp->vc_ssnkey != NULL)
+                kmem_free(vcp->vc_ssnkey, vcp->vc_ssnkeylen);
 
+        cv_destroy(&vcp->iod_muxwait);
         cv_destroy(&vcp->iod_idle);
         rw_destroy(&vcp->iod_rqlock);
-        sema_destroy(&vcp->vc_sendlock);
         cv_destroy(&vcp->vc_statechg);
         smb_co_done(VCTOCP(vcp));
         kmem_free(vcp, sizeof (*vcp));
 }
 

@@ -390,18 +408,19 @@
         smb_co_init(VCTOCP(vcp), SMBL_VC, objtype);
         vcp->vc_co.co_free = smb_vc_free;
         vcp->vc_co.co_gone = smb_vc_gone;
 
         cv_init(&vcp->vc_statechg, objtype, CV_DRIVER, NULL);
-        sema_init(&vcp->vc_sendlock, 1, objtype, SEMA_DRIVER, NULL);
         rw_init(&vcp->iod_rqlock, objtype, RW_DRIVER, NULL);
         cv_init(&vcp->iod_idle, objtype, CV_DRIVER, NULL);
+        cv_init(&vcp->iod_muxwait, objtype, CV_DRIVER, NULL);
 
         /* Expanded TAILQ_HEAD_INITIALIZER */
         vcp->iod_rqlist.tqh_last = &vcp->iod_rqlist.tqh_first;
 
-        vcp->vc_state = SMBIOD_ST_IDLE;
+        /* A brand new VC should connect. */
+        vcp->vc_state = SMBIOD_ST_RECONNECT;
 
         /*
          * These identify the connection.
          */
         vcp->vc_zoneid = getzoneid();

@@ -610,13 +629,17 @@
 static void
 smb_share_gone(struct smb_connobj *cp)
 {
         struct smb_cred scred;
         struct smb_share *ssp = CPTOSS(cp);
+        smb_vc_t *vcp = SSTOVC(ssp);
 
         smb_credinit(&scred, NULL);
         smb_iod_shutdown_share(ssp);
+        if (vcp->vc_flags & SMBV_SMB2)
+                (void) smb2_smb_treedisconnect(ssp, &scred);
+        else
         (void) smb_smb_treedisconnect(ssp, &scred);
         smb_credrele(&scred);
 }
 
 /*

@@ -653,10 +676,11 @@
         ssp->ss_co.co_free = smb_share_free;
         ssp->ss_co.co_gone = smb_share_gone;
 
         cv_init(&ssp->ss_conn_done, objtype, CV_DRIVER, NULL);
         ssp->ss_tid = SMB_TID_UNKNOWN;
+        ssp->ss2_tree_id = SMB2_TID_UNKNOWN;
 
         bcopy(&tcon->tc_sh, &ssp->ss_ioc,
             sizeof (smbioc_oshare_t));
 
         smb_co_addchild(VCTOCP(vcp), SSTOCP(ssp));

@@ -768,10 +792,11 @@
  * and called by smb_rq_enqueue() for reconnect.
  */
 int
 smb_share_tcon(smb_share_t *ssp, smb_cred_t *scred)
 {
+        smb_vc_t *vcp = SSTOVC(ssp);
         clock_t tmo;
         int error;
 
         SMB_SS_LOCK(ssp);
 

@@ -811,10 +836,13 @@
          * Drop the lock while doing the TCON.
          * On success, sets ss_tid, ss_vcgenid,
          * and ss_flags |= SMBS_CONNECTED;
          */
         SMB_SS_UNLOCK(ssp);
+        if (vcp->vc_flags & SMBV_SMB2)
+                error = smb2_smb_treeconnect(ssp, scred);
+        else
         error = smb_smb_treeconnect(ssp, scred);
         SMB_SS_LOCK(ssp);
 
         ssp->ss_flags &= ~SMBS_RECONNECTING;
 

@@ -827,10 +855,118 @@
 
         return (error);
 }
 
 /*
+ * File handle level functions
+ */
+
+void
+smb_fh_hold(struct smb_fh *fhp)
+{
+        smb_co_hold(FHTOCP(fhp));
+}
+
+void
+smb_fh_rele(struct smb_fh *fhp)
+{
+        smb_co_rele(FHTOCP(fhp));
+}
+
+void
+smb_fh_close(struct smb_fh *fhp)
+{
+        smb_co_kill(FHTOCP(fhp));
+}
+
+/*
+ * Normally called via smb_fh_rele()
+ * after co_usecount drops to zero.
+ * Also called via: smb_fh_kill()
+ */
+static void
+smb_fh_gone(struct smb_connobj *cp)
+{
+        struct smb_cred scred;
+        struct smb_fh *fhp = CPTOFH(cp);
+        smb_share_t *ssp = FHTOSS(fhp);
+        int err;
+
+        if ((fhp->fh_flags & SMBFH_VALID) == 0)
+                return;
+
+        /*
+         * We have no durable handles (yet) so if there has been a
+         * reconnect, don't bother to close this handle.
+         */
+        if (fhp->fh_vcgenid != ssp->ss_vcgenid)
+                return;
+
+        smb_credinit(&scred, NULL);
+        err = smb_smb_close(ssp, fhp, &scred);
+        smb_credrele(&scred);
+        if (err) {
+                SMBSDEBUG("close err=%d\n", err);
+        }
+}
+
+/*
+ * Normally called via smb_fh_rele()
+ * after co_usecount drops to zero.
+ */
+static void
+smb_fh_free(struct smb_connobj *cp)
+{
+        struct smb_fh *fhp = CPTOFH(cp);
+
+        smb_co_done(FHTOCP(fhp));
+        kmem_free(fhp, sizeof (*fhp));
+}
+
+/*
+ * Allocate fh structure and attach it to the given share.
+ * Share expected to be locked on entry.
+ */
+/*ARGSUSED*/
+int
+smb_fh_create(smb_share_t *ssp, struct smb_fh **fhpp)
+{
+        static char objtype[] = "smb_fh";
+        struct smb_fh *fhp;
+
+        fhp = kmem_zalloc(sizeof (struct smb_fh), KM_SLEEP);
+        smb_co_init(FHTOCP(fhp), SMBL_FH, objtype);
+        fhp->fh_co.co_free = smb_fh_free;
+        fhp->fh_co.co_gone = smb_fh_gone;
+
+        SMB_SS_LOCK(ssp);
+        if ((ssp->ss_flags & SMBS_GONE) != 0) {
+                SMB_SS_UNLOCK(ssp);
+                smb_fh_free(FHTOCP(fhp));
+                return (ENOTCONN);
+        }
+
+        smb_co_addchild(SSTOCP(ssp), FHTOCP(fhp));
+        *fhpp = fhp;
+        SMB_SS_UNLOCK(ssp);
+
+        return (0);
+}
+
+void
+smb_fh_opened(struct smb_fh *fhp)
+{
+        smb_share_t *ssp = FHTOSS(fhp);
+
+        SMB_FH_LOCK(fhp);
+        fhp->fh_vcgenid = ssp->ss_vcgenid;
+        fhp->fh_flags |= SMBFH_VALID;
+        SMB_FH_UNLOCK(fhp);
+}
+
+
+/*
  * Solaris zones support
  */
 /*ARGSUSED*/
 void
 lingering_vc(struct smb_vc *vc)