Print this page
NEX-15578 SMB2 durable handle redesign
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-5665 SMB2 oplock leases
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-15578 SMB2 durable handle redesign
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-5665 SMB2 oplock leases
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@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-5586 SMB2 ofiles need real Persistent IDs
NEX-5313 SMB2 oplock break notification should use TID=0
Reviewed by: Gordon Ross <gwr@nexenta.com>
NEX-5560 smb2 should use 64-bit server-global uids
Reviewed by: Gordon Ross <gwr@nexenta.com>
NEX-1892 30 sec. delay responding to smb2_create
NEX-1734 SMB2 oplock break request missing a flag
SMB-122 smbd core dumps in smbd_dc_update / smb_log
SMB-117 Win7 fails to open security properties
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_oplock.c
+++ new/usr/src/uts/common/fs/smbsrv/smb2_oplock.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 2017 Nexenta Systems, Inc. All rights reserved.
14 14 */
15 15
16 16 /*
17 17 * Dispatch function for SMB2_OPLOCK_BREAK
18 18 */
19 19
20 20 #include <smbsrv/smb2_kproto.h>
21 21
22 +#define BATCH_OR_EXCL (OPLOCK_LEVEL_BATCH | OPLOCK_LEVEL_ONE)
23 +
24 +/* StructSize for the two "break" message formats. */
25 +#define SSZ_OPLOCK 24
26 +#define SSZ_LEASE 36
27 +
22 28 /*
23 29 * SMB2 Oplock Break Acknowledgement
24 - * [MS-SMB2 2.2.24]
30 + * [MS-SMB2] 3.3.5.22.1 Processing an Oplock Acknowledgment
31 + * Called via smb2_disp_table[]
25 32 */
26 33 smb_sdrc_t
27 34 smb2_oplock_break_ack(smb_request_t *sr)
28 35 {
29 - smb_node_t *node;
36 + smb_ofile_t *ofile;
30 37 smb2fid_t smb2fid;
31 38 uint32_t status;
32 - uint16_t StructSize;
33 - uint8_t OplockLevel;
34 - uint8_t brk;
39 + uint32_t NewLevel;
40 + uint8_t smbOplockLevel;
35 41 int rc = 0;
42 + uint16_t StructSize;
36 43
37 44 /*
38 - * Decode the SMB2 Oplock Break Ack.
45 + * Decode the SMB2 Oplock Break Ack (24 bytes) or
46 + * Lease Break Ack (36 bytes), starting with just
47 + * the StructSize, which tells us what this is.
39 48 */
49 + rc = smb_mbc_decodef(&sr->smb_data, "w", &StructSize);
50 + if (rc != 0)
51 + return (SDRC_ERROR);
52 +
53 + if (StructSize == SSZ_LEASE) {
54 + /* See smb2_lease.c */
55 + return (smb2_lease_break_ack(sr));
56 + }
57 + if (StructSize != SSZ_OPLOCK)
58 + return (SDRC_ERROR);
59 +
60 + /*
61 + * Decode an SMB2 Oplock Break Ack.
62 + * [MS-SMB2] 2.2.24.1
63 + * Note: Struct size decoded above.
64 + */
40 65 rc = smb_mbc_decodef(
41 - &sr->smb_data, "wb5.qq",
42 - &StructSize, /* w */
43 - &OplockLevel, /* b */
66 + &sr->smb_data, "b5.qq",
67 + &smbOplockLevel, /* b */
44 68 /* reserved 5. */
45 69 &smb2fid.persistent, /* q */
46 70 &smb2fid.temporal); /* q */
47 - if (rc || StructSize != 24)
71 + if (rc != 0)
48 72 return (SDRC_ERROR);
49 73
74 + /* Find the ofile */
50 75 status = smb2sr_lookup_fid(sr, &smb2fid);
51 - if (status)
76 + /* Success or NT_STATUS_FILE_CLOSED */
77 +
78 + DTRACE_SMB2_START(op__OplockBreak, smb_request_t *, sr);
79 + if (status != 0)
52 80 goto errout;
53 - if ((node = sr->fid_ofile->f_node) == NULL) {
54 - /* Not a regular file */
55 - status = NT_STATUS_INVALID_PARAMETER;
56 - goto errout;
57 - }
58 81
59 82 /*
60 - * Process the oplock break ack. We only expect levels
61 - * at or below the hightest break levels we send, which is
62 - * currently SMB2_OPLOCK_LEVEL_II.
83 + * Process an (old-style) oplock break ack.
63 84 */
64 - switch (OplockLevel) {
85 + switch (smbOplockLevel) {
65 86 case SMB2_OPLOCK_LEVEL_NONE: /* 0x00 */
66 - brk = SMB_OPLOCK_BREAK_TO_NONE;
87 + NewLevel = OPLOCK_LEVEL_NONE;
67 88 break;
68 -
69 89 case SMB2_OPLOCK_LEVEL_II: /* 0x01 */
70 - brk = SMB_OPLOCK_BREAK_TO_LEVEL_II;
90 + NewLevel = OPLOCK_LEVEL_TWO;
71 91 break;
72 -
73 - /* We don't break to these levels (yet). */
74 92 case SMB2_OPLOCK_LEVEL_EXCLUSIVE: /* 0x08 */
93 + NewLevel = OPLOCK_LEVEL_ONE;
94 + break;
75 95 case SMB2_OPLOCK_LEVEL_BATCH: /* 0x09 */
96 + NewLevel = OPLOCK_LEVEL_BATCH;
97 + break;
76 98 case SMB2_OPLOCK_LEVEL_LEASE: /* 0xFF */
77 - default: /* gcc -Wuninitialized */
78 - status = NT_STATUS_INVALID_PARAMETER;
99 + default:
100 + NewLevel = OPLOCK_LEVEL_NONE;
101 + break;
102 + }
103 +
104 + ofile = sr->fid_ofile;
105 + ofile->f_oplock.og_breaking = 0;
106 + status = smb_oplock_ack_break(sr, ofile, &NewLevel);
107 + if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
108 + status = smb2sr_go_async(sr);
109 + if (status != 0)
110 + goto errout;
111 + (void) smb_oplock_wait_break(ofile->f_node, 0);
112 + status = 0;
113 + }
114 + if (status != 0) {
115 + NewLevel = OPLOCK_LEVEL_NONE;
79 116 goto errout;
80 117 }
81 118
82 - smb_oplock_ack(node, sr->fid_ofile, brk);
119 + ofile->f_oplock.og_state = NewLevel;
120 + switch (NewLevel & OPLOCK_LEVEL_TYPE_MASK) {
121 + case OPLOCK_LEVEL_NONE:
122 + smbOplockLevel = SMB2_OPLOCK_LEVEL_NONE;
123 + break;
124 + case OPLOCK_LEVEL_TWO:
125 + smbOplockLevel = SMB2_OPLOCK_LEVEL_II;
126 + break;
127 + case OPLOCK_LEVEL_ONE:
128 + smbOplockLevel = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
129 + break;
130 + case OPLOCK_LEVEL_BATCH:
131 + smbOplockLevel = SMB2_OPLOCK_LEVEL_BATCH;
132 + break;
133 + case OPLOCK_LEVEL_GRANULAR:
134 + default:
135 + smbOplockLevel = SMB2_OPLOCK_LEVEL_NONE;
136 + break;
137 + }
83 138
139 +errout:
140 + sr->smb2_status = status;
141 + DTRACE_SMB2_DONE(op__OplockBreak, smb_request_t *, sr);
142 + if (status) {
143 + smb2sr_put_error(sr, status);
144 + return (SDRC_SUCCESS);
145 + }
146 +
84 147 /*
85 - * Generate SMB2 Oplock Break response
86 - * [MS-SMB2] 2.2.25
148 + * Encode an SMB2 Oplock Break Ack response
149 + * [MS-SMB2] 2.2.25.1
87 150 */
88 - StructSize = 24;
89 151 (void) smb_mbc_encodef(
90 152 &sr->reply, "wb5.qq",
91 - StructSize, /* w */
92 - OplockLevel, /* b */
153 + SSZ_OPLOCK, /* w */
154 + smbOplockLevel, /* b */
93 155 /* reserved 5. */
94 156 smb2fid.persistent, /* q */
95 157 smb2fid.temporal); /* q */
96 - return (SDRC_SUCCESS);
97 158
98 -errout:
99 - smb2sr_put_error(sr, status);
100 159 return (SDRC_SUCCESS);
101 160 }
102 161
103 162 /*
104 163 * Compose an SMB2 Oplock Break Notification packet, including
105 164 * the SMB2 header and everything, in sr->reply.
106 165 * The caller will send it and free the request.
107 166 */
108 167 void
109 -smb2_oplock_break_notification(smb_request_t *sr, uint8_t brk)
168 +smb2_oplock_break_notification(smb_request_t *sr, uint32_t NewLevel)
110 169 {
111 170 smb_ofile_t *ofile = sr->fid_ofile;
112 171 smb2fid_t smb2fid;
113 172 uint16_t StructSize;
114 173 uint8_t OplockLevel;
115 174
116 - switch (brk) {
175 + /*
176 + * Convert internal level to SMB2
177 + */
178 + switch (NewLevel) {
117 179 default:
118 180 ASSERT(0);
119 181 /* FALLTHROUGH */
120 - case SMB_OPLOCK_BREAK_TO_NONE:
182 + case OPLOCK_LEVEL_NONE:
121 183 OplockLevel = SMB2_OPLOCK_LEVEL_NONE;
122 184 break;
123 - case SMB_OPLOCK_BREAK_TO_LEVEL_II:
185 + case OPLOCK_LEVEL_TWO:
124 186 OplockLevel = SMB2_OPLOCK_LEVEL_II;
125 187 break;
126 188 }
127 189
128 190 /*
129 191 * SMB2 Header
130 192 */
131 193 sr->smb2_cmd_code = SMB2_OPLOCK_BREAK;
132 194 sr->smb2_hdr_flags = SMB2_FLAGS_SERVER_TO_REDIR;
133 - sr->smb_tid = ofile->f_tree->t_tid;
195 + sr->smb_tid = 0;
134 196 sr->smb_pid = 0;
135 - sr->smb_uid = 0;
197 + sr->smb2_ssnid = 0;
136 198 sr->smb2_messageid = UINT64_MAX;
137 199 (void) smb2_encode_header(sr, B_FALSE);
138 200
139 201 /*
140 202 * SMB2 Oplock Break, variable part
141 203 */
142 204 StructSize = 24;
143 - smb2fid.persistent = 0;
205 + smb2fid.persistent = ofile->f_persistid;
144 206 smb2fid.temporal = ofile->f_fid;
145 207 (void) smb_mbc_encodef(
146 208 &sr->reply, "wb5.qq",
147 209 StructSize, /* w */
148 210 OplockLevel, /* b */
149 211 /* reserved 5. */
150 212 smb2fid.persistent, /* q */
151 213 smb2fid.temporal); /* q */
214 +}
215 +
216 +/*
217 + * Client has an open handle and requests an oplock.
218 + * Convert SMB2 oplock request info in to internal form,
219 + * call common oplock code, convert result to SMB2.
220 + *
221 + * If necessary, "go async" here.
222 + */
223 +void
224 +smb2_oplock_acquire(smb_request_t *sr)
225 +{
226 + smb_arg_open_t *op = &sr->arg.open;
227 + smb_ofile_t *ofile = sr->fid_ofile;
228 + uint32_t status;
229 +
230 + /* Only disk trees get oplocks. */
231 + ASSERT((sr->tid_tree->t_res_type & STYPE_MASK) == STYPE_DISKTREE);
232 +
233 + /* Only plain files... */
234 + if (!smb_node_is_file(ofile->f_node)) {
235 + op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
236 + return;
237 + }
238 +
239 + if (!smb_tree_has_feature(sr->tid_tree, SMB_TREE_OPLOCKS)) {
240 + op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
241 + return;
242 + }
243 +
244 + /*
245 + * SMB2: Convert to internal form.
246 + */
247 + switch (op->op_oplock_level) {
248 + case SMB2_OPLOCK_LEVEL_BATCH:
249 + op->op_oplock_state = OPLOCK_LEVEL_BATCH;
250 + break;
251 + case SMB2_OPLOCK_LEVEL_EXCLUSIVE:
252 + op->op_oplock_state = OPLOCK_LEVEL_ONE;
253 + break;
254 + case SMB2_OPLOCK_LEVEL_II:
255 + op->op_oplock_state = OPLOCK_LEVEL_TWO;
256 + break;
257 + case SMB2_OPLOCK_LEVEL_LEASE:
258 + ASSERT(0); /* Handled elsewhere */
259 + /* FALLTHROUGH */
260 + case SMB2_OPLOCK_LEVEL_NONE:
261 + default:
262 + op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
263 + return;
264 + }
265 +
266 + /*
267 + * Tree options may force shared oplocks,
268 + * in which case we reduce the request.
269 + */
270 + if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_FORCE_L2_OPLOCK)) {
271 + op->op_oplock_state = OPLOCK_LEVEL_TWO;
272 + }
273 +
274 + /*
275 + * Try exclusive first, if requested
276 + */
277 + if ((op->op_oplock_state & BATCH_OR_EXCL) != 0) {
278 + status = smb_oplock_request(sr, ofile,
279 + &op->op_oplock_state);
280 + } else {
281 + status = NT_STATUS_OPLOCK_NOT_GRANTED;
282 + }
283 +
284 + /*
285 + * If exclusive failed (or the tree forced shared oplocks)
286 + * try for a shared oplock (Level II)
287 + */
288 + if (status == NT_STATUS_OPLOCK_NOT_GRANTED) {
289 + op->op_oplock_state = OPLOCK_LEVEL_TWO;
290 + status = smb_oplock_request(sr, ofile,
291 + &op->op_oplock_state);
292 + }
293 +
294 + /*
295 + * Either of the above may have returned the
296 + * status code that says we should wait.
297 + */
298 + if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
299 + (void) smb2sr_go_async(sr);
300 + (void) smb_oplock_wait_break(ofile->f_node, 0);
301 + status = 0;
302 + }
303 +
304 + /*
305 + * Keep track of what we got (in ofile->f_oplock.og_state)
306 + * so we'll know what we had when sending a break later.
307 + * The og_dialect here is the oplock dialect, not the
308 + * SMB dialect. No lease here, so SMB 2.0.
309 + */
310 + ofile->f_oplock.og_dialect = SMB_VERS_2_002;
311 + switch (status) {
312 + case NT_STATUS_SUCCESS:
313 + ofile->f_oplock.og_state = op->op_oplock_state;
314 + break;
315 + case NT_STATUS_OPLOCK_NOT_GRANTED:
316 + ofile->f_oplock.og_state = 0;
317 + op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
318 + return;
319 + default:
320 + /* Caller did not check args sufficiently? */
321 + cmn_err(CE_NOTE, "clnt %s oplock req. err 0x%x",
322 + sr->session->ip_addr_str, status);
323 + ofile->f_oplock.og_state = 0;
324 + op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
325 + return;
326 + }
327 +
328 + /*
329 + * Have STATUS_SUCCESS
330 + * Convert internal oplock state to SMB2
331 + */
332 + if (op->op_oplock_state & OPLOCK_LEVEL_GRANULAR) {
333 + ASSERT(0);
334 + op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
335 + } else if (op->op_oplock_state & OPLOCK_LEVEL_BATCH) {
336 + op->op_oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
337 + } else if (op->op_oplock_state & OPLOCK_LEVEL_ONE) {
338 + op->op_oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
339 + } else if (op->op_oplock_state & OPLOCK_LEVEL_TWO) {
340 + op->op_oplock_level = SMB2_OPLOCK_LEVEL_II;
341 + } else {
342 + op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
343 + }
152 344 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX