Print this page
NEX-15555 SMB2 async redesign
NEX-15061 smtorture smb2.lock.cancel.cancel is failed
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Also follow-up change to:
 NEX-1643 dtrace provider for smbsrv (remove "done2" probes,
 which don't make sense with the new async design)
NEX-15555 SMB2 async redesign
NEX-15061 smtorture smb2.lock.cancel.cancel is failed
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Also follow-up change to:
 NEX-1643 dtrace provider for smbsrv (remove "done2" probes,
 which don't make sense with the new async design)
NEX-1643 dtrace provider for smbsrv
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
NEX-6402 SMB2 change notify response wrong when STATUS_NOTIFY_ENUM_DIR
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
NEX-3906 Prefer that SMB change notify not tie up a worker thread
NEX-5278 SMB notify should buffer per file handle
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Matt Barden <Matt.Barden@nexenta.com>
NEX-3310 smbstat misreports change notify
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
Reviewed by: Dan Fields <dan.fields@nexenta.com>
SMB-11 SMB2 message parse & dispatch
SMB-12 SMB2 Negotiate Protocol
SMB-13 SMB2 Session Setup
SMB-14 SMB2 Logoff
SMB-15 SMB2 Tree Connect
SMB-16 SMB2 Tree Disconnect
SMB-17 SMB2 Create
SMB-18 SMB2 Close
SMB-19 SMB2 Flush
SMB-20 SMB2 Read
SMB-21 SMB2 Write
SMB-22 SMB2 Lock/Unlock
SMB-23 SMB2 Ioctl
SMB-24 SMB2 Cancel
SMB-25 SMB2 Echo
SMB-26 SMB2 Query Dir
SMB-27 SMB2 Change Notify
SMB-28 SMB2 Query Info
SMB-29 SMB2 Set Info
SMB-30 SMB2 Oplocks
SMB-53 SMB2 Create Context options
(SMB2 code review cleanup 1, 2, 3)
re #13470 rb4432 Sync some SMB differences from illumos
re #11215 rb3676 sesctl to SGI JBOD hangs in biowait() with a command stuck in mptsas driver
re #10734 NT Trans. Notify returning too quickly

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/fs/smbsrv/smb_nt_transact_notify_change.c
          +++ new/usr/src/uts/common/fs/smbsrv/smb_nt_transact_notify_change.c
↓ open down ↓ 13 lines elided ↑ open up ↑
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  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) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  24      - * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
       24 + * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
  25   25   */
  26   26  
  27   27  /*
  28   28   * File Change Notification (FCN)
  29   29   * SMB1 specific part.
  30   30   */
  31   31  
  32   32  /*
  33   33   * SMB: nt_transact_notify_change
  34   34   *
↓ open down ↓ 16 lines elided ↑ open up ↑
  51   51   *  ParameterCount                     # of bytes of change data
  52   52   *  Parameters[ ParameterCount ]       FILE_NOTIFY_INFORMATION
  53   53   *                                      structures
  54   54   *
  55   55   * See smb_notify.c for details of FILE_NOTIFY_INFORMATION
  56   56   */
  57   57  
  58   58  #include <smbsrv/smb_kproto.h>
  59   59  
  60   60  /*
  61      - * We add this flag to the CompletionFilter (see above) when the
  62      - * client sets WatchTree.  Must not overlap FILE_NOTIFY_VALID_MASK.
  63      - */
  64      -#define NODE_FLAGS_WATCH_TREE           0x10000000
  65      -#if (NODE_FLAGS_WATCH_TREE & FILE_NOTIFY_VALID_MASK)
  66      -#error "NODE_FLAGS_WATCH_TREE"
  67      -#endif
  68      -
  69      -/*
  70   61   * smb_nt_transact_notify_change
  71   62   *
  72   63   * Handle and SMB NT transact NOTIFY CHANGE request.
  73   64   * Basically, wait until "something has changed", and either
  74   65   * return information about what changed, or return a special
  75   66   * error telling the client "many things changed".
  76   67   *
  77   68   * The implementation uses a per-node list of waiting notify
  78   69   * requests like this one, each with a blocked worker thead.
  79   70   * Later, FEM and/or smbsrv events wake these threads, which
  80   71   * then send the reply to the client.
  81   72   */
  82   73  smb_sdrc_t
  83   74  smb_nt_transact_notify_change(smb_request_t *sr, struct smb_xa *xa)
  84   75  {
       76 +        mbuf_chain_t            tmp_mbc;
       77 +        uint32_t                oBufSize;
  85   78          uint32_t                CompletionFilter;
  86   79          unsigned char           WatchTree;
  87   80          uint32_t                status;
  88      -        hrtime_t                t1, t2;
  89   81  
  90   82          if (smb_mbc_decodef(&xa->req_setup_mb, "lwb",
  91   83              &CompletionFilter, &sr->smb_fid, &WatchTree) != 0) {
  92   84                  smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 0, 0);
  93   85                  return (SDRC_ERROR);
  94   86          }
  95      -        CompletionFilter &= FILE_NOTIFY_VALID_MASK;
  96      -        if (WatchTree)
  97      -                CompletionFilter |= NODE_FLAGS_WATCH_TREE;
  98   87  
  99   88          smbsr_lookup_file(sr);
       89 +        if (sr->fid_ofile == NULL) {
       90 +                smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 0, 0);
       91 +                return (SDRC_ERROR);
       92 +        }
 100   93  
 101      -        t1 = gethrtime();
 102      -        status = smb_notify_common(sr, &xa->rep_data_mb, CompletionFilter);
 103      -        t2 = gethrtime();
       94 +        oBufSize = xa->rep_param_mb.max_bytes;
       95 +        CompletionFilter &= FILE_NOTIFY_VALID_MASK;
       96 +        if (WatchTree)
       97 +                CompletionFilter |= FILE_NOTIFY_CHANGE_EV_SUBDIR;
 104   98  
 105   99          /*
 106      -         * We don't want to include the (indefinite) wait time of the
 107      -         * smb_notify_common() call in the SMB1 transact latency.
 108      -         * The easiest way to do that, without adding special case
 109      -         * logic to the common SMB1 dispatch handler is to adjust the
 110      -         * start time of this request to effectively subtract out the
 111      -         * time we were blocked in smb_notify_common().
      100 +         * Check for events and consume, non-blocking.
      101 +         * Special return STATUS_PENDING means:
      102 +         *   No events; caller must call "act2" next.
 112  103           */
 113      -        sr->sr_time_start += (t2 - t1);
      104 +        status = smb_notify_act1(sr, oBufSize, CompletionFilter);
      105 +        if (status == NT_STATUS_PENDING) {
      106 +                status = smb_notify_act2(sr);
      107 +                if (status == NT_STATUS_PENDING) {
      108 +                        /* See: smb_nt_transact_notify_finish */
      109 +                        return (SDRC_SR_KEPT);
      110 +                }
      111 +                /* else: some other error, or even success */
      112 +        }
 114  113  
 115      -        if (status != 0)
 116      -                smbsr_error(sr, status, 0, 0);
      114 +        /*
      115 +         * SMB1 expects an empty trans response after the
      116 +         * FID we're watching is closed.
      117 +         */
      118 +        if (status == NT_STATUS_NOTIFY_CLEANUP) {
      119 +                status = 0;
      120 +                MBC_FLUSH(&sr->raw_data);
      121 +        }
 117  122  
      123 +        if (status != 0) {
      124 +                smbsr_status(sr, status, 0, 0);
      125 +                if (NT_SC_SEVERITY(status) == NT_STATUS_SEVERITY_ERROR)
      126 +                        return (SDRC_ERROR);
      127 +                /* Else continue with NT_STATUS_NOTIFY_ENUM_DIR etc. */
      128 +        }
      129 +
      130 +        /*
      131 +         * The nt_trans call expects the output in rep_param_mb,
      132 +         * but our common code puts it in raw_data.  Move it
      133 +         * where the caller expects it via swaping the two,
      134 +         * which lets the normal cleanup take care of both.
      135 +         */
      136 +        tmp_mbc = xa->rep_param_mb;
      137 +        xa->rep_param_mb = sr->raw_data;
      138 +        sr->raw_data = tmp_mbc;
      139 +
 118  140          return (SDRC_SUCCESS);
      141 +}
      142 +
      143 +/*
      144 + * This is called via taskq_dispatch in smb_notify.c
      145 + * to finish up an NT transact notify change request.
      146 + */
      147 +void
      148 +smb_nt_transact_notify_finish(void *arg)
      149 +{
      150 +        smb_request_t   *sr = arg;
      151 +        struct smb_xa   *xa;
      152 +        smb_disp_stats_t *sds;
      153 +        int             total_bytes, n_setup, n_param, n_data;
      154 +        int             param_off, param_pad, data_off, data_pad;
      155 +        uint32_t        status;
      156 +
      157 +        SMB_REQ_VALID(sr);
      158 +
      159 +        /*
      160 +         * Common part of notify, puts data in sr->raw_data
      161 +         */
      162 +        status = smb_notify_act3(sr);
      163 +
      164 +        /*
      165 +         * SMB1 expects an empty trans response after the
      166 +         * FID we're watching is closed.
      167 +         */
      168 +        if (status == NT_STATUS_NOTIFY_CLEANUP) {
      169 +                status = 0;
      170 +                MBC_FLUSH(&sr->raw_data);
      171 +        }
      172 +
      173 +        if (status != 0) {
      174 +                smbsr_status(sr, status, 0, 0);
      175 +                if (NT_SC_SEVERITY(status) == NT_STATUS_SEVERITY_ERROR) {
      176 +                        (void) smb_mbc_encodef(&sr->reply, "bwbw",
      177 +                            (short)0, 0L, (short)0, 0L);
      178 +                        goto sendit;
      179 +                }
      180 +                /* Else continue with NT_STATUS_NOTIFY_ENUM_DIR etc. */
      181 +        }
      182 +
      183 +        /*
      184 +         * setup the NT transact reply
      185 +         *
      186 +         * Note that this is a copy/paste of code from
      187 +         * smb_nt_trans_dispatch(), with minor changes.
      188 +         * Intentionally keeping this similar to the
      189 +         * original rather than hand-optimizing.
      190 +         *
      191 +         * The "setup" and "data" parts of this trans reply
      192 +         * (n_setup, n_data, rep_setup_mb, rep_data_mb) are
      193 +         * always empty.  sr->raw_data replaces rep_param_mb.
      194 +         */
      195 +        xa = sr->r_xa;
      196 +        n_setup = MBC_LENGTH(&xa->rep_setup_mb);
      197 +        n_param = MBC_LENGTH(&sr->raw_data);
      198 +        n_data  = MBC_LENGTH(&xa->rep_data_mb);
      199 +
      200 +        n_setup = (n_setup + 1) / 2;    /* Convert to setup words */
      201 +        param_pad = 1;                  /* must be one */
      202 +        param_off = param_pad + 32 + 37 + (n_setup << 1) + 2;
      203 +        /* Pad to 4 bytes */
      204 +        data_pad = (4 - ((param_off + n_param) & 3)) % 4;
      205 +        /* Param off from hdr */
      206 +        data_off = param_off + n_param + data_pad;
      207 +        total_bytes = param_pad + n_param + data_pad + n_data;
      208 +
      209 +        (void) smbsr_encode_result(sr, 18+n_setup, total_bytes,
      210 +            "b3.llllllllbCw#.C#.C",
      211 +            18 + n_setup,       /* wct */
      212 +            n_param,            /* Total Parameter Bytes */
      213 +            n_data,             /* Total Data Bytes */
      214 +            n_param,            /* Total Parameter Bytes this buffer */
      215 +            param_off,          /* Param offset from header start */
      216 +            0,                  /* Param displacement */
      217 +            n_data,             /* Total Data Bytes this buffer */
      218 +            data_off,           /* Data offset from header start */
      219 +            0,                  /* Data displacement */
      220 +            n_setup,            /* suwcnt */
      221 +            &xa->rep_setup_mb,  /* setup[] */
      222 +            total_bytes,        /* Total data bytes */
      223 +            param_pad,
      224 +            &sr->raw_data,      /* output mbc */
      225 +            data_pad,
      226 +            &xa->rep_data_mb);
      227 +
      228 +sendit:
      229 +        /*
      230 +         * When smb_nt_transact_notify_change returned SDRC_SR_KEPT
      231 +         * the dispatcher skipped the "done" probe, so do it now.
      232 +         * Note: Don't use this probe in response time statistics.
      233 +         */
      234 +        DTRACE_SMB_DONE(op__NtTransact, smb_request_t *, sr);
      235 +
      236 +        sds = &sr->sr_server->sv_disp_stats1[sr->smb_com];
      237 +        atomic_add_64(&sds->sdt_txb, (int64_t)sr->reply.chain_offset);
      238 +
      239 +        smbsr_send_reply(sr);   /* also puts the SMB header. */
      240 +        smbsr_cleanup(sr);
      241 +
      242 +        mutex_enter(&sr->sr_mutex);
      243 +        sr->sr_state = SMB_REQ_STATE_COMPLETED;
      244 +        mutex_exit(&sr->sr_mutex);
      245 +
      246 +        smb_request_free(sr);
 119  247  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX