Print this page
NEX-17589 Get "too high" smbd error when copy big file to cifs share (redo)
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-16943 network outages with thread stuck in smb2_scoreboard_cancel
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-1643 dtrace provider for smbsrv
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
NEX-9864 Some SMB cancel races remain after NEX-5845
Revert (part of) "NEX-5845 rework SMB immediate cancel"
reverts (part of) commit 7a5da69f6d42b17ebcc95ca3d02925d07a01343e.
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-5845 rework SMB immediate cancel
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
NEX-2975 SMB2 Cancel may fail (nits)
NEX-2975 SMB2 Cancel may fail
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Tony Nguyen <tony.nguyen@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)
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/uts/common/fs/smbsrv/smb2_cancel.c
+++ new/usr/src/uts/common/fs/smbsrv/smb2_cancel.c
1 1 /*
2 2 * This file and its contents are supplied under the terms of the
|
↓ open down ↓ |
2 lines elided |
↑ open up ↑ |
3 3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 4 * You may only use this file in accordance with the terms of version
5 5 * 1.0 of the CDDL.
6 6 *
7 7 * A full copy of the text of the CDDL should have accompanied this
8 8 * source. A copy of the CDDL is also available via the Internet at
9 9 * http://www.illumos.org/license/CDDL.
10 10 */
11 11
12 12 /*
13 - * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
13 + * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
14 14 */
15 15
16 16 /*
17 17 * Dispatch function for SMB2_CANCEL
18 18 */
19 19
20 20 #include <smbsrv/smb2_kproto.h>
21 21
22 -static void smb2sr_cancel_async(smb_request_t *);
23 -static void smb2sr_cancel_sync(smb_request_t *);
22 +static void smb2_cancel_async(smb_request_t *);
23 +static void smb2_cancel_sync(smb_request_t *);
24 24
25 25 /*
26 26 * This handles an SMB2_CANCEL request when seen in the reader.
27 27 * (See smb2sr_newrq) Handle this immediately, rather than
28 28 * going through the normal taskq dispatch mechanism.
29 29 * Note that Cancel does NOT get a response.
30 + *
31 + * Any non-zero return causes disconnect.
32 + * SMB2 header is already decoded.
30 33 */
31 34 int
32 -smb2sr_newrq_cancel(smb_request_t *sr)
35 +smb2_newrq_cancel(smb_request_t *sr)
33 36 {
34 - int rc;
35 37
36 38 /*
37 - * Decode the header
39 + * If we get SMB2 cancel as part of a compound,
40 + * that's a protocol violation. Drop 'em!
38 41 */
39 - if ((rc = smb2_decode_header(sr)) != 0)
40 - return (rc);
42 + if (sr->smb2_next_command != 0)
43 + return (EINVAL);
41 44
45 + DTRACE_SMB2_START(op__Cancel, smb_request_t *, sr);
46 +
42 47 if (sr->smb2_hdr_flags & SMB2_FLAGS_ASYNC_COMMAND)
43 - smb2sr_cancel_async(sr);
48 + smb2_cancel_async(sr);
44 49 else
45 - smb2sr_cancel_sync(sr);
50 + smb2_cancel_sync(sr);
46 51
52 + DTRACE_SMB2_DONE(op__Cancel, smb_request_t *, sr);
53 +
47 54 return (0);
48 55 }
49 56
57 +/*
58 + * Dispatch handler for SMB2_CANCEL.
59 + * Note that Cancel does NOT get a response.
60 + */
61 +smb_sdrc_t
62 +smb2_cancel(smb_request_t *sr)
63 +{
64 +
65 + /*
66 + * If we get SMB2 cancel as part of a compound,
67 + * that's a protocol violation. Drop 'em!
68 + */
69 + if (sr->smb2_cmd_hdr != 0 || sr->smb2_next_command != 0)
70 + return (SDRC_DROP_VC);
71 +
72 + DTRACE_SMB2_START(op__Cancel, smb_request_t *, sr);
73 +
74 + if (sr->smb2_hdr_flags & SMB2_FLAGS_ASYNC_COMMAND) {
75 + smb2_cancel_async(sr);
76 + } else {
77 + smb2_cancel_sync(sr);
78 + }
79 +
80 + DTRACE_SMB2_DONE(op__Cancel, smb_request_t *, sr);
81 +
82 + return (SDRC_NO_REPLY);
83 +}
84 +
85 +/*
86 + * SMB2 Cancel (sync) has an inherent race with the request being
87 + * cancelled. The request may have been received but not yet
88 + * executed by a worker thread, in which case we'll mark the
89 + * request state as cancelled, and when a worker thread starts
90 + * on this request we'll cancel everything in the compound.
91 + */
50 92 static void
51 -smb2sr_cancel_sync(smb_request_t *sr)
93 +smb2_cancel_sync(smb_request_t *sr)
52 94 {
53 95 struct smb_request *req;
54 96 struct smb_session *session = sr->session;
55 97 int cnt = 0;
56 98
99 + if (sr->smb2_messageid == 0)
100 + goto failure;
101 +
57 102 smb_slist_enter(&session->s_req_list);
58 - req = smb_slist_head(&session->s_req_list);
59 - while (req) {
60 - ASSERT(req->sr_magic == SMB_REQ_MAGIC);
61 - if ((req != sr) &&
62 - (req->smb2_messageid == sr->smb2_messageid)) {
103 + for (req = smb_slist_head(&session->s_req_list); req != NULL;
104 + req = smb_slist_next(&session->s_req_list, req)) {
105 +
106 + /* never cancel self */
107 + if (req == sr)
108 + continue;
109 +
110 + if (sr->smb2_messageid >= req->smb2_first_msgid &&
111 + sr->smb2_messageid < (req->smb2_first_msgid +
112 + req->smb2_total_credits)) {
63 113 smb_request_cancel(req);
64 114 cnt++;
65 115 }
66 - req = smb_slist_next(&session->s_req_list, req);
67 116 }
117 + smb_slist_exit(&session->s_req_list);
118 +
68 119 if (cnt != 1) {
120 + failure:
69 121 DTRACE_PROBE2(smb2__cancel__error,
70 122 uint64_t, sr->smb2_messageid, int, cnt);
123 +#ifdef DEBUG
124 + /*
125 + * It's somewhat common that we may see a cancel for a
126 + * request that has already completed, so report that
127 + * only in debug builds.
128 + */
129 + cmn_err(CE_WARN, "SMB2 cancel failed, "
130 + "client=%s, MID=0x%llx",
131 + sr->session->ip_addr_str,
132 + (u_longlong_t)sr->smb2_messageid);
133 +#endif
71 134 }
72 - smb_slist_exit(&session->s_req_list);
73 135 }
74 136
137 +/*
138 + * Note that cancelling an async request doesn't have a race
139 + * because the client doesn't learn about the async ID until we
140 + * send it to them in an interim reply, and by that point the
141 + * request has progressed to the point where smb_cancel can find
142 + * the request and cancel it.
143 + */
75 144 static void
76 -smb2sr_cancel_async(smb_request_t *sr)
145 +smb2_cancel_async(smb_request_t *sr)
77 146 {
78 147 struct smb_request *req;
79 148 struct smb_session *session = sr->session;
80 149 int cnt = 0;
81 150
82 151 smb_slist_enter(&session->s_req_list);
83 152 req = smb_slist_head(&session->s_req_list);
84 153 while (req) {
85 154 ASSERT(req->sr_magic == SMB_REQ_MAGIC);
86 155 if ((req != sr) &&
87 156 (req->smb2_async_id == sr->smb2_async_id)) {
88 157 smb_request_cancel(req);
89 158 cnt++;
90 159 }
91 160 req = smb_slist_next(&session->s_req_list, req);
92 161 }
93 162 if (cnt != 1) {
94 163 DTRACE_PROBE2(smb2__cancel__error,
95 164 uint64_t, sr->smb2_async_id, int, cnt);
165 + /*
166 + * Not logging here, as this is normal, i.e.
167 + * when both a cancel and a handle close
168 + * terminates an SMB2_notify request.
169 + */
96 170 }
97 171 smb_slist_exit(&session->s_req_list);
98 172 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX