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
@@ -19,11 +19,11 @@
* CDDL HEADER END
*/
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
*/
/*
* File Change Notification (FCN)
* SMB1 specific part.
@@ -56,19 +56,10 @@
*/
#include <smbsrv/smb_kproto.h>
/*
- * We add this flag to the CompletionFilter (see above) when the
- * client sets WatchTree. Must not overlap FILE_NOTIFY_VALID_MASK.
- */
-#define NODE_FLAGS_WATCH_TREE 0x10000000
-#if (NODE_FLAGS_WATCH_TREE & FILE_NOTIFY_VALID_MASK)
-#error "NODE_FLAGS_WATCH_TREE"
-#endif
-
-/*
* smb_nt_transact_notify_change
*
* Handle and SMB NT transact NOTIFY CHANGE request.
* Basically, wait until "something has changed", and either
* return information about what changed, or return a special
@@ -80,40 +71,177 @@
* then send the reply to the client.
*/
smb_sdrc_t
smb_nt_transact_notify_change(smb_request_t *sr, struct smb_xa *xa)
{
+ mbuf_chain_t tmp_mbc;
+ uint32_t oBufSize;
uint32_t CompletionFilter;
unsigned char WatchTree;
uint32_t status;
- hrtime_t t1, t2;
if (smb_mbc_decodef(&xa->req_setup_mb, "lwb",
&CompletionFilter, &sr->smb_fid, &WatchTree) != 0) {
smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 0, 0);
return (SDRC_ERROR);
}
- CompletionFilter &= FILE_NOTIFY_VALID_MASK;
- if (WatchTree)
- CompletionFilter |= NODE_FLAGS_WATCH_TREE;
smbsr_lookup_file(sr);
+ if (sr->fid_ofile == NULL) {
+ smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 0, 0);
+ return (SDRC_ERROR);
+ }
- t1 = gethrtime();
- status = smb_notify_common(sr, &xa->rep_data_mb, CompletionFilter);
- t2 = gethrtime();
+ oBufSize = xa->rep_param_mb.max_bytes;
+ CompletionFilter &= FILE_NOTIFY_VALID_MASK;
+ if (WatchTree)
+ CompletionFilter |= FILE_NOTIFY_CHANGE_EV_SUBDIR;
/*
- * We don't want to include the (indefinite) wait time of the
- * smb_notify_common() call in the SMB1 transact latency.
- * The easiest way to do that, without adding special case
- * logic to the common SMB1 dispatch handler is to adjust the
- * start time of this request to effectively subtract out the
- * time we were blocked in smb_notify_common().
+ * Check for events and consume, non-blocking.
+ * Special return STATUS_PENDING means:
+ * No events; caller must call "act2" next.
*/
- sr->sr_time_start += (t2 - t1);
+ status = smb_notify_act1(sr, oBufSize, CompletionFilter);
+ if (status == NT_STATUS_PENDING) {
+ status = smb_notify_act2(sr);
+ if (status == NT_STATUS_PENDING) {
+ /* See: smb_nt_transact_notify_finish */
+ return (SDRC_SR_KEPT);
+ }
+ /* else: some other error, or even success */
+ }
- if (status != 0)
- smbsr_error(sr, status, 0, 0);
+ /*
+ * SMB1 expects an empty trans response after the
+ * FID we're watching is closed.
+ */
+ if (status == NT_STATUS_NOTIFY_CLEANUP) {
+ status = 0;
+ MBC_FLUSH(&sr->raw_data);
+ }
+ if (status != 0) {
+ smbsr_status(sr, status, 0, 0);
+ if (NT_SC_SEVERITY(status) == NT_STATUS_SEVERITY_ERROR)
+ return (SDRC_ERROR);
+ /* Else continue with NT_STATUS_NOTIFY_ENUM_DIR etc. */
+ }
+
+ /*
+ * The nt_trans call expects the output in rep_param_mb,
+ * but our common code puts it in raw_data. Move it
+ * where the caller expects it via swaping the two,
+ * which lets the normal cleanup take care of both.
+ */
+ tmp_mbc = xa->rep_param_mb;
+ xa->rep_param_mb = sr->raw_data;
+ sr->raw_data = tmp_mbc;
+
return (SDRC_SUCCESS);
+}
+
+/*
+ * This is called via taskq_dispatch in smb_notify.c
+ * to finish up an NT transact notify change request.
+ */
+void
+smb_nt_transact_notify_finish(void *arg)
+{
+ smb_request_t *sr = arg;
+ struct smb_xa *xa;
+ smb_disp_stats_t *sds;
+ int total_bytes, n_setup, n_param, n_data;
+ int param_off, param_pad, data_off, data_pad;
+ uint32_t status;
+
+ SMB_REQ_VALID(sr);
+
+ /*
+ * Common part of notify, puts data in sr->raw_data
+ */
+ status = smb_notify_act3(sr);
+
+ /*
+ * SMB1 expects an empty trans response after the
+ * FID we're watching is closed.
+ */
+ if (status == NT_STATUS_NOTIFY_CLEANUP) {
+ status = 0;
+ MBC_FLUSH(&sr->raw_data);
+ }
+
+ if (status != 0) {
+ smbsr_status(sr, status, 0, 0);
+ if (NT_SC_SEVERITY(status) == NT_STATUS_SEVERITY_ERROR) {
+ (void) smb_mbc_encodef(&sr->reply, "bwbw",
+ (short)0, 0L, (short)0, 0L);
+ goto sendit;
+ }
+ /* Else continue with NT_STATUS_NOTIFY_ENUM_DIR etc. */
+ }
+
+ /*
+ * setup the NT transact reply
+ *
+ * Note that this is a copy/paste of code from
+ * smb_nt_trans_dispatch(), with minor changes.
+ * Intentionally keeping this similar to the
+ * original rather than hand-optimizing.
+ *
+ * The "setup" and "data" parts of this trans reply
+ * (n_setup, n_data, rep_setup_mb, rep_data_mb) are
+ * always empty. sr->raw_data replaces rep_param_mb.
+ */
+ xa = sr->r_xa;
+ n_setup = MBC_LENGTH(&xa->rep_setup_mb);
+ n_param = MBC_LENGTH(&sr->raw_data);
+ n_data = MBC_LENGTH(&xa->rep_data_mb);
+
+ n_setup = (n_setup + 1) / 2; /* Convert to setup words */
+ param_pad = 1; /* must be one */
+ param_off = param_pad + 32 + 37 + (n_setup << 1) + 2;
+ /* Pad to 4 bytes */
+ data_pad = (4 - ((param_off + n_param) & 3)) % 4;
+ /* Param off from hdr */
+ data_off = param_off + n_param + data_pad;
+ total_bytes = param_pad + n_param + data_pad + n_data;
+
+ (void) smbsr_encode_result(sr, 18+n_setup, total_bytes,
+ "b3.llllllllbCw#.C#.C",
+ 18 + n_setup, /* wct */
+ n_param, /* Total Parameter Bytes */
+ n_data, /* Total Data Bytes */
+ n_param, /* Total Parameter Bytes this buffer */
+ param_off, /* Param offset from header start */
+ 0, /* Param displacement */
+ n_data, /* Total Data Bytes this buffer */
+ data_off, /* Data offset from header start */
+ 0, /* Data displacement */
+ n_setup, /* suwcnt */
+ &xa->rep_setup_mb, /* setup[] */
+ total_bytes, /* Total data bytes */
+ param_pad,
+ &sr->raw_data, /* output mbc */
+ data_pad,
+ &xa->rep_data_mb);
+
+sendit:
+ /*
+ * When smb_nt_transact_notify_change returned SDRC_SR_KEPT
+ * the dispatcher skipped the "done" probe, so do it now.
+ * Note: Don't use this probe in response time statistics.
+ */
+ DTRACE_SMB_DONE(op__NtTransact, smb_request_t *, sr);
+
+ sds = &sr->sr_server->sv_disp_stats1[sr->smb_com];
+ atomic_add_64(&sds->sdt_txb, (int64_t)sr->reply.chain_offset);
+
+ smbsr_send_reply(sr); /* also puts the SMB header. */
+ smbsr_cleanup(sr);
+
+ mutex_enter(&sr->sr_mutex);
+ sr->sr_state = SMB_REQ_STATE_COMPLETED;
+ mutex_exit(&sr->sr_mutex);
+
+ smb_request_free(sr);
}