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,41 ****
--- 32,43 ----
   * $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,68 ****
--- 61,71 ----
  #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,87 ****
--- 81,93 ----
  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,113 ****
  
  void
  smb_sm_done(void)
  {
          /*
!          * XXX Q4BP 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);
  }
--- 109,119 ----
  
  void
  smb_sm_done(void)
  {
          /*
!          * 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,188 ****
--- 185,204 ----
  {
          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,376 ****
                  iconv_close(vcp->vc_toserver);
  #endif
  
          if (vcp->vc_mackey != NULL)
                  kmem_free(vcp->vc_mackey, vcp->vc_mackeylen);
  
          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));
  }
  
--- 379,394 ----
                  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);
          cv_destroy(&vcp->vc_statechg);
          smb_co_done(VCTOCP(vcp));
          kmem_free(vcp, sizeof (*vcp));
  }
  
*** 390,407 ****
          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);
  
          /* Expanded TAILQ_HEAD_INITIALIZER */
          vcp->iod_rqlist.tqh_last = &vcp->iod_rqlist.tqh_first;
  
!         vcp->vc_state = SMBIOD_ST_IDLE;
  
          /*
           * These identify the connection.
           */
          vcp->vc_zoneid = getzoneid();
--- 408,426 ----
          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);
          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;
  
!         /* A brand new VC should connect. */
!         vcp->vc_state = SMBIOD_ST_RECONNECT;
  
          /*
           * These identify the connection.
           */
          vcp->vc_zoneid = getzoneid();
*** 610,622 ****
--- 629,645 ----
  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,662 ****
--- 676,686 ----
          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,777 ****
--- 792,802 ----
   * 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,820 ****
--- 836,848 ----
           * 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,836 ****
--- 855,972 ----
  
          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)