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)
NEX-16818 Add fksmbcl development tool
NEX-17264 SMB client test tp_smbutil_013 fails after NEX-14666
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
and: (fix ref leaks)
5404 smbfs needs mmap support
Portions contributed by: Gordon Ross <gordon.w.ross@gmail.com>
Reviewed by: C Fraire <cfraire@me.com>
Reviewed by: Toomas Soome <tsoome@me.com>
Reviewed by: Jason King <jason.brian.king@gmail.com>
Reviewed by: Andrew Stormont <andyjstormont@gmail.com>
Approved by: Richard Lowe <richlowe@richlowe.net>

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_client.c
          +++ new/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_client.c
↓ open down ↓ 14 lines elided ↑ open up ↑
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  
  22   22  /*
  23   23   * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  24   24   *
  25      - *      Copyright (c) 1983,1984,1985,1986,1987,1988,1989  AT&T.
       25 + *      Copyright (c) 1983,1984,1985,1986,1987,1988,1989  AT&T.
  26   26   *      All rights reserved.
       27 + *
       28 + * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  27   29   */
  28   30  
  29   31  #include <sys/param.h>
  30   32  #include <sys/systm.h>
  31   33  #include <sys/thread.h>
  32   34  #include <sys/t_lock.h>
  33   35  #include <sys/time.h>
  34   36  #include <sys/vnode.h>
  35   37  #include <sys/vfs.h>
  36   38  #include <sys/errno.h>
↓ open down ↓ 16 lines elided ↑ open up ↑
  53   55  #include <sys/zone.h>
  54   56  
  55   57  #include <netsmb/smb.h>
  56   58  #include <netsmb/smb_conn.h>
  57   59  #include <netsmb/smb_subr.h>
  58   60  
  59   61  #include <smbfs/smbfs.h>
  60   62  #include <smbfs/smbfs_node.h>
  61   63  #include <smbfs/smbfs_subr.h>
  62   64  
       65 +#ifdef  _KERNEL
  63   66  #include <vm/hat.h>
  64   67  #include <vm/as.h>
  65   68  #include <vm/page.h>
  66   69  #include <vm/pvn.h>
  67   70  #include <vm/seg.h>
  68   71  #include <vm/seg_map.h>
  69   72  #include <vm/seg_vn.h>
       73 +#endif  // _KERNEL
  70   74  
       75 +#define ATTRCACHE_VALID(vp)     (gethrtime() < VTOSMB(vp)->r_attrtime)
       76 +
  71   77  static int smbfs_getattr_cache(vnode_t *, smbfattr_t *);
  72   78  static void smbfattr_to_vattr(vnode_t *, smbfattr_t *, vattr_t *);
  73   79  static void smbfattr_to_xvattr(smbfattr_t *, vattr_t *);
       80 +static int smbfs_getattr_otw(vnode_t *, struct smbfattr *, cred_t *);
  74   81  
       82 +
  75   83  /*
  76   84   * The following code provide zone support in order to perform an action
  77   85   * for each smbfs mount in a zone.  This is also where we would add
  78   86   * per-zone globals and kernel threads for the smbfs module (since
  79   87   * they must be terminated by the shutdown callback).
  80   88   */
  81   89  
  82   90  struct smi_globals {
  83   91          kmutex_t        smg_lock;  /* lock protecting smg_list */
  84   92          list_t          smg_list;  /* list of SMBFS mounts in zone */
↓ open down ↓ 10 lines elided ↑ open up ↑
  95  103   * There is a time associated with the cached attributes (r_attrtime)
  96  104   * which tells whether the attributes are valid. The time is initialized
  97  105   * to the difference between current time and the modify time of the vnode
  98  106   * when new attributes are cached. This allows the attributes for
  99  107   * files that have changed recently to be timed out sooner than for files
 100  108   * that have not changed for a long time. There are minimum and maximum
 101  109   * timeout values that can be set per mount point.
 102  110   */
 103  111  
 104  112  /*
 105      - * Validate caches by checking cached attributes. If they have timed out
 106      - * get the attributes from the server and compare mtimes. If mtimes are
 107      - * different purge all caches for this vnode.
      113 + * Helper for _validate_caches
 108  114   */
 109  115  int
      116 +smbfs_waitfor_purge_complete(vnode_t *vp)
      117 +{
      118 +        smbnode_t *np;
      119 +        k_sigset_t smask;
      120 +
      121 +        np = VTOSMB(vp);
      122 +        if (np->r_serial != NULL && np->r_serial != curthread) {
      123 +                mutex_enter(&np->r_statelock);
      124 +                sigintr(&smask, VTOSMI(vp)->smi_flags & SMI_INT);
      125 +                while (np->r_serial != NULL) {
      126 +                        if (!cv_wait_sig(&np->r_cv, &np->r_statelock)) {
      127 +                                sigunintr(&smask);
      128 +                                mutex_exit(&np->r_statelock);
      129 +                                return (EINTR);
      130 +                        }
      131 +                }
      132 +                sigunintr(&smask);
      133 +                mutex_exit(&np->r_statelock);
      134 +        }
      135 +        return (0);
      136 +}
      137 +
      138 +/*
      139 + * Validate caches by checking cached attributes. If the cached
      140 + * attributes have timed out, then get new attributes from the server.
      141 + * As a side affect, this will do cache invalidation if the attributes
      142 + * have changed.
      143 + *
      144 + * If the attributes have not timed out and if there is a cache
      145 + * invalidation being done by some other thread, then wait until that
      146 + * thread has completed the cache invalidation.
      147 + */
      148 +int
 110  149  smbfs_validate_caches(
 111  150          struct vnode *vp,
 112  151          cred_t *cr)
 113  152  {
 114      -        struct vattr va;
      153 +        struct smbfattr fa;
      154 +        int error;
 115  155  
 116      -        va.va_mask = AT_SIZE;
 117      -        return (smbfsgetattr(vp, &va, cr));
      156 +        if (ATTRCACHE_VALID(vp)) {
      157 +                error = smbfs_waitfor_purge_complete(vp);
      158 +                if (error)
      159 +                        return (error);
      160 +                return (0);
      161 +        }
      162 +
      163 +        return (smbfs_getattr_otw(vp, &fa, cr));
 118  164  }
 119  165  
 120  166  /*
 121  167   * Purge all of the various data caches.
      168 + *
      169 + * Here NFS also had a flags arg to control what gets flushed.
      170 + * We only have the page cache, so no flags arg.
 122  171   */
 123      -/*ARGSUSED*/
      172 +/* ARGSUSED */
 124  173  void
 125      -smbfs_purge_caches(struct vnode *vp)
      174 +smbfs_purge_caches(struct vnode *vp, cred_t *cr)
 126  175  {
 127      -#if 0   /* not yet: mmap support */
      176 +
 128  177          /*
 129      -         * NFS: Purge the DNLC for this vp,
      178 +         * Here NFS has: Purge the DNLC for this vp,
 130  179           * Clear any readdir state bits,
 131  180           * the readlink response cache, ...
 132  181           */
 133      -        smbnode_t *np = VTOSMB(vp);
 134  182  
 135  183          /*
 136  184           * Flush the page cache.
 137  185           */
 138  186          if (vn_has_cached_data(vp)) {
 139  187                  (void) VOP_PUTPAGE(vp, (u_offset_t)0, 0, B_INVAL, cr, NULL);
 140  188          }
 141      -#endif  /* not yet */
      189 +
      190 +        /*
      191 +         * Here NFS has: Flush the readdir response cache.
      192 +         * No readdir cache in smbfs.
      193 +         */
 142  194  }
 143  195  
 144  196  /*
      197 + * Here NFS has:
      198 + * nfs_purge_rddir_cache()
      199 + * nfs3_cache_post_op_attr()
      200 + * nfs3_cache_post_op_vattr()
      201 + * nfs3_cache_wcc_data()
      202 + */
      203 +
      204 +/*
 145  205   * Check the attribute cache to see if the new attributes match
 146  206   * those cached.  If they do, the various `data' caches are
 147  207   * considered to be good.  Otherwise, purge the cached data.
 148  208   */
 149      -void
      209 +static void
 150  210  smbfs_cache_check(
 151  211          struct vnode *vp,
 152      -        struct smbfattr *fap)
      212 +        struct smbfattr *fap,
      213 +        cred_t *cr)
 153  214  {
 154  215          smbnode_t *np;
 155  216          int purge_data = 0;
 156  217          int purge_acl = 0;
 157  218  
 158  219          np = VTOSMB(vp);
 159  220          mutex_enter(&np->r_statelock);
 160  221  
 161  222          /*
 162  223           * Compare with NFS macro: CACHE_VALID
↓ open down ↓ 4 lines elided ↑ open up ↑
 167  228              np->r_attr.fa_mtime.tv_nsec != fap->fa_mtime.tv_nsec)
 168  229                  purge_data = 1;
 169  230          if (np->r_attr.fa_size != fap->fa_size)
 170  231                  purge_data = 1;
 171  232  
 172  233          if (np->r_attr.fa_ctime.tv_sec != fap->fa_ctime.tv_sec ||
 173  234              np->r_attr.fa_ctime.tv_nsec != fap->fa_ctime.tv_nsec)
 174  235                  purge_acl = 1;
 175  236  
 176  237          if (purge_acl) {
 177      -                /* just invalidate r_secattr (XXX: OK?) */
 178  238                  np->r_sectime = gethrtime();
 179  239          }
 180  240  
 181  241          mutex_exit(&np->r_statelock);
 182  242  
 183  243          if (purge_data)
 184      -                smbfs_purge_caches(vp);
      244 +                smbfs_purge_caches(vp, cr);
 185  245  }
 186  246  
 187  247  /*
 188      - * Set attributes cache for given vnode using vnode attributes.
 189      - * From NFS: nfs_attrcache_va
 190      - */
 191      -#if 0   /* not yet (not sure if we need this) */
 192      -void
 193      -smbfs_attrcache_va(vnode_t *vp, struct vattr *vap)
 194      -{
 195      -        smbfattr_t fa;
 196      -        smbnode_t *np;
 197      -
 198      -        vattr_to_fattr(vp, vap, &fa);
 199      -        smbfs_attrcache_fa(vp, &fa);
 200      -}
 201      -#endif  /* not yet */
 202      -
 203      -/*
 204  248   * Set attributes cache for given vnode using SMB fattr
 205  249   * and update the attribute cache timeout.
 206  250   *
 207      - * From NFS: nfs_attrcache, nfs_attrcache_va
      251 + * Based on NFS: nfs_attrcache, nfs_attrcache_va
 208  252   */
 209  253  void
 210  254  smbfs_attrcache_fa(vnode_t *vp, struct smbfattr *fap)
 211  255  {
 212  256          smbnode_t *np;
 213  257          smbmntinfo_t *smi;
 214  258          hrtime_t delta, now;
 215  259          u_offset_t newsize;
 216  260          vtype_t  vtype, oldvt;
 217  261          mode_t mode;
↓ open down ↓ 68 lines elided ↑ open up ↑
 286  330           *
 287  331           * Also deal with the fact that SMB presents
 288  332           * directories as having size=0.  Doing that
 289  333           * here and leaving fa_size as returned OtW
 290  334           * avoids fixing the size lots of places.
 291  335           */
 292  336          newsize = fap->fa_size;
 293  337          if (vtype == VDIR && newsize < DEV_BSIZE)
 294  338                  newsize = DEV_BSIZE;
 295  339  
 296      -        if (np->r_size != newsize) {
 297      -#if 0   /* not yet: mmap support */
 298      -                if (!vn_has_cached_data(vp) || ...)
 299      -                        /* XXX: See NFS page cache code. */
 300      -#endif  /* not yet */
      340 +        if (np->r_size != newsize &&
      341 +            (!vn_has_cached_data(vp) ||
      342 +            (!(np->r_flags & RDIRTY) && np->r_count == 0))) {
 301  343                  /* OK to set the size. */
 302  344                  np->r_size = newsize;
 303  345          }
 304  346  
 305      -        /* NFS: np->r_flags &= ~RWRITEATTR; */
 306      -        np->n_flag &= ~NATTRCHANGED;
      347 +        /*
      348 +         * Here NFS has:
      349 +         * nfs_setswaplike(vp, va);
      350 +         * np->r_flags &= ~RWRITEATTR;
      351 +         * (not needed here)
      352 +         */
 307  353  
      354 +        np->n_flag &= ~NATTRCHANGED;
 308  355          mutex_exit(&np->r_statelock);
 309  356  
 310  357          if (oldvt != vtype) {
 311  358                  SMBVDEBUG("vtype change %d to %d\n", oldvt, vtype);
 312  359          }
 313  360  }
 314  361  
 315  362  /*
 316  363   * Fill in attribute from the cache.
 317  364   *
↓ open down ↓ 23 lines elided ↑ open up ↑
 341  388  
 342  389          return (error);
 343  390  }
 344  391  
 345  392  /*
 346  393   * Get attributes over-the-wire and update attributes cache
 347  394   * if no error occurred in the over-the-wire operation.
 348  395   * Return 0 if successful, otherwise error.
 349  396   * From NFS: nfs_getattr_otw
 350  397   */
 351      -int
      398 +static int
 352  399  smbfs_getattr_otw(vnode_t *vp, struct smbfattr *fap, cred_t *cr)
 353  400  {
 354      -        struct smbnode *np;
 355  401          struct smb_cred scred;
      402 +        smbnode_t       *np = VTOSMB(vp);
      403 +        smb_share_t     *ssp = np->n_mount->smi_share;
      404 +        smb_fh_t        *fhp = NULL;
 356  405          int error;
 357  406  
 358      -        np = VTOSMB(vp);
      407 +        bzero(fap, sizeof (*fap));
 359  408  
 360  409          /*
 361      -         * NFS uses the ACL rpc here (if smi_flags & SMI_ACL)
      410 +         * Special case the XATTR directory here (all fake).
      411 +         * OK to leave a,c,m times zero (expected).
      412 +         */
      413 +        if (vp->v_flag & V_XATTRDIR) {
      414 +                fap->fa_attr = SMB_FA_DIR;
      415 +                fap->fa_size = DEV_BSIZE;
      416 +                return (0);
      417 +        }
      418 +
      419 +        /*
      420 +         * Here NFS uses the ACL RPC (if smi_flags & SMI_ACL)
 362  421           * With SMB, getting the ACL is a significantly more
 363  422           * expensive operation, so we do that only when asked
 364  423           * for the uid/gid.  See smbfsgetattr().
 365  424           */
 366  425  
 367  426          /* Shared lock for (possible) n_fid use. */
 368  427          if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
 369  428                  return (EINTR);
 370  429          smb_credinit(&scred, cr);
 371  430  
 372      -        bzero(fap, sizeof (*fap));
 373      -        error = smbfs_smb_getfattr(np, fap, &scred);
      431 +// Does the attr. open code path work for streams?
      432 +// Trying that, and if it doesn't work enable this.
      433 +#if 0   // XXX
      434 +        /*
      435 +         * Extended attribute files
      436 +         */
      437 +        if (np->n_flag & N_XATTR) {
      438 +                error = smbfs_xa_getfattr(np, fap, scrp);
      439 +                goto out;
      440 +        }
      441 +#endif  // XXX
 374  442  
      443 +        if (np->n_fidrefs > 0 &&
      444 +            (fhp = np->n_fid) != NULL &&
      445 +            (fhp->fh_vcgenid == ssp->ss_vcgenid)) {
      446 +                /* Use the FID we have. */
      447 +                error = smbfs_smb_getfattr(np, fhp, fap, &scred);
      448 +
      449 +        } else {
      450 +                /* This will do an attr open */
      451 +                error = smbfs_smb_getpattr(np, fap, &scred);
      452 +        }
      453 +
 375  454          smb_credrele(&scred);
 376  455          smbfs_rw_exit(&np->r_lkserlock);
 377  456  
 378  457          if (error) {
 379      -                /* NFS had: PURGE_STALE_FH(error, vp, cr) */
      458 +                /* Here NFS has: PURGE_STALE_FH(error, vp, cr) */
 380  459                  smbfs_attrcache_remove(np);
 381  460                  if (error == ENOENT || error == ENOTDIR) {
 382  461                          /*
 383  462                           * Getattr failed because the object was
 384  463                           * removed or renamed by another client.
 385  464                           * Remove any cached attributes under it.
 386  465                           */
 387  466                          smbfs_attrcache_prune(np);
 388  467                  }
 389  468                  return (error);
 390  469          }
 391  470  
 392  471          /*
 393      -         * NFS: smbfs_cache_fattr(vap, fa, vap, t, cr);
      472 +         * Here NFS has: nfs_cache_fattr(vap, fa, vap, t, cr);
 394  473           * which did: fattr_to_vattr, nfs_attr_cache.
 395  474           * We cache the fattr form, so just do the
 396  475           * cache check and store the attributes.
 397  476           */
 398      -        smbfs_cache_check(vp, fap);
      477 +        smbfs_cache_check(vp, fap, cr);
 399  478          smbfs_attrcache_fa(vp, fap);
 400  479  
 401  480          return (0);
 402  481  }
 403  482  
 404  483  /*
 405      - * Return either cached or remote attributes. If get remote attr
      484 + * Return either cached or remote attributes. If we get remote attrs,
 406  485   * use them to check and invalidate caches, then cache the new attributes.
 407  486   *
 408  487   * From NFS: nfsgetattr()
 409  488   */
 410  489  int
 411  490  smbfsgetattr(vnode_t *vp, struct vattr *vap, cred_t *cr)
 412  491  {
 413  492          struct smbfattr fa;
 414  493          smbmntinfo_t *smi;
 415  494          uint_t mask;
↓ open down ↓ 128 lines elided ↑ open up ↑
 544  623          }
 545  624  
 546  625          if (XVA_ISSET_REQ(xvap, XAT_HIDDEN)) {
 547  626                  xoap->xoa_hidden =
 548  627                      ((fa->fa_attr & SMB_FA_HIDDEN) != 0);
 549  628                  XVA_SET_RTN(xvap, XAT_HIDDEN);
 550  629          }
 551  630  }
 552  631  
 553  632  /*
      633 + * Here NFS has:
      634 + *      nfs_async_... stuff
      635 + * which we're not using (no async I/O), and:
      636 + *      writerp(),
      637 + *      nfs_putpages()
      638 + *      nfs_invalidate_pages()
      639 + * which we have in smbfs_vnops.c, and
      640 + *      nfs_printfhandle()
      641 + *      nfs_write_error()
      642 + * not needed here.
      643 + */
      644 +
      645 +/*
      646 + * Helper function for smbfs_sync
      647 + *
      648 + * Walk the per-zone list of smbfs mounts, calling smbfs_rflush
      649 + * on each one.  This is a little tricky because we need to exit
      650 + * the list mutex before each _rflush call and then try to resume
      651 + * where we were in the list after re-entering the mutex.
      652 + */
      653 +void
      654 +smbfs_flushall(cred_t *cr)
      655 +{
      656 +        smi_globals_t *smg;
      657 +        smbmntinfo_t *tmp_smi, *cur_smi, *next_smi;
      658 +
      659 +        smg = zone_getspecific(smi_list_key, crgetzone(cr));
      660 +        ASSERT(smg != NULL);
      661 +
      662 +        mutex_enter(&smg->smg_lock);
      663 +        cur_smi = list_head(&smg->smg_list);
      664 +        if (cur_smi == NULL) {
      665 +                mutex_exit(&smg->smg_lock);
      666 +                return;
      667 +        }
      668 +        VFS_HOLD(cur_smi->smi_vfsp);
      669 +        mutex_exit(&smg->smg_lock);
      670 +
      671 +flush:
      672 +        smbfs_rflush(cur_smi->smi_vfsp, cr);
      673 +
      674 +        mutex_enter(&smg->smg_lock);
      675 +        /*
      676 +         * Resume after cur_smi if that's still on the list,
      677 +         * otherwise restart at the head.
      678 +         */
      679 +        for (tmp_smi = list_head(&smg->smg_list);
      680 +            tmp_smi != NULL;
      681 +            tmp_smi = list_next(&smg->smg_list, tmp_smi))
      682 +                if (tmp_smi == cur_smi)
      683 +                        break;
      684 +        if (tmp_smi != NULL)
      685 +                next_smi = list_next(&smg->smg_list, tmp_smi);
      686 +        else
      687 +                next_smi = list_head(&smg->smg_list);
      688 +
      689 +        if (next_smi != NULL)
      690 +                VFS_HOLD(next_smi->smi_vfsp);
      691 +        VFS_RELE(cur_smi->smi_vfsp);
      692 +
      693 +        mutex_exit(&smg->smg_lock);
      694 +
      695 +        if (next_smi != NULL) {
      696 +                cur_smi = next_smi;
      697 +                goto flush;
      698 +        }
      699 +}
      700 +
      701 +/*
 554  702   * SMB Client initialization and cleanup.
 555  703   * Much of it is per-zone now.
 556  704   */
 557  705  
 558  706  
 559  707  /* ARGSUSED */
 560  708  static void *
 561  709  smbfs_zone_init(zoneid_t zoneid)
 562  710  {
 563  711          smi_globals_t *smg;
↓ open down ↓ 133 lines elided ↑ open up ↑
 697  845  }
 698  846  
 699  847  /*ARGSUSED*/
 700  848  static void smbfs_cb_nop(smb_share_t *ss)
 701  849  {
 702  850          /* no-op */
 703  851  }
 704  852  
 705  853  smb_fscb_t smbfs_cb = {
 706  854          .fscb_disconn   = smbfs_dead,
 707      -        .fscb_connect   = smbfs_cb_nop,
 708      -        .fscb_down      = smbfs_cb_nop,
 709      -        .fscb_up        = smbfs_cb_nop };
      855 +        .fscb_connect   = smbfs_cb_nop
      856 +};
 710  857  
 711  858  #endif /* NEED_SMBFS_CALLBACKS */
 712  859  
 713  860  /*
 714  861   * SMBFS Client initialization routine.  This routine should only be called
 715  862   * once.  It performs the following tasks:
 716  863   *      - Initalize all global locks
 717  864   *      - Call sub-initialization routines (localize access to variables)
 718  865   */
 719  866  int
↓ open down ↓ 23 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX