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,29 **** * CDDL HEADER END */ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. ! * Copyright 2015 Nexenta Systems, Inc. All rights reserved. */ /* * File Change Notification (FCN) * SMB1 specific part. --- 19,29 ---- * CDDL HEADER END */ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. ! * Copyright 2017 Nexenta Systems, Inc. All rights reserved. */ /* * File Change Notification (FCN) * SMB1 specific part.
*** 56,74 **** */ #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 --- 56,65 ----
*** 80,119 **** * then send the reply to the client. */ smb_sdrc_t smb_nt_transact_notify_change(smb_request_t *sr, struct smb_xa *xa) { 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); ! t1 = gethrtime(); ! status = smb_notify_common(sr, &xa->rep_data_mb, CompletionFilter); ! t2 = gethrtime(); /* ! * 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(). */ ! sr->sr_time_start += (t2 - t1); ! if (status != 0) ! smbsr_error(sr, status, 0, 0); return (SDRC_SUCCESS); } --- 71,247 ---- * 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; 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); } smbsr_lookup_file(sr); + if (sr->fid_ofile == NULL) { + smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 0, 0); + return (SDRC_ERROR); + } ! oBufSize = xa->rep_param_mb.max_bytes; ! CompletionFilter &= FILE_NOTIFY_VALID_MASK; ! if (WatchTree) ! CompletionFilter |= FILE_NOTIFY_CHANGE_EV_SUBDIR; /* ! * Check for events and consume, non-blocking. ! * Special return STATUS_PENDING means: ! * No events; caller must call "act2" next. */ ! 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 */ ! } ! /* ! * 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); }