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-6041 Should pass the smbtorture lock tests
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
NEX-3553 SMB2/3 durable handles
Reviewed by: Gordon Ross <gwr@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
NEX-5555 smb locks don't need l_uid or l_session_kid
Reviewed by: Gordon Ross <gwr@nexenta.com>
NEX-5537 Want reference counts for users, trees...
Reviewed by: Gordon Ross <gwr@nexenta.com>
NEX-5314 SMB server may wait for oplock break ack on disconnected session
Reviewed by: Matt Barden <matt.barden@nexenta.com>
NEX-4083 Upstream changes from illumos 5917 and 5995
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-2516 Need a way to disable exclusive oplocks
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)
SMB-74 Process oplock breaks as session requests (part two)
SMB-74 Process oplock breaks as session requests
SMB-65 SMB server in non-global zones (kmem_caches)
common kmem_cache instances across zones
separate GZ-only init from NGZ init
SMB-64 smbsrv workers run at excessively high priority
SUP-599 smb_oplock_acquire thread deadlock
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/uts/common/fs/smbsrv/smb_oplock.c
+++ new/usr/src/uts/common/fs/smbsrv/smb_oplock.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
|
↓ open down ↓ |
12 lines elided |
↑ open up ↑ |
13 13 * When distributing Covered Code, include this CDDL HEADER in each
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 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 - * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
23 + * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
24 24 */
25 25
26 26 /*
27 - * smb_oplock_wait / smb_oplock_broadcast
28 - * When an oplock is being acquired, we must ensure that the acquisition
29 - * response is submitted to the network stack before any other operation
30 - * is permitted on the oplock.
31 - * In smb_oplock_acquire, oplock.ol_xthread is set to point to the worker
32 - * thread processing the command that is granting the oplock.
33 - * Other threads accessing the oplock will be suspended in smb_oplock_wait().
34 - * They will be awakened when the worker thread referenced in 'ol_xthread'
35 - * calls smb_oplock_broadcast().
36 - *
37 - * The purpose of this mechanism is to prevent another thread from
38 - * triggering an oplock break before the response conveying the grant
39 - * has been sent.
27 + * smb1 oplock support
40 28 */
41 29
42 30 #include <smbsrv/smb_kproto.h>
43 -#include <sys/nbmlock.h>
44 31
45 -#define SMB_OPLOCK_IS_EXCLUSIVE(level) \
46 - (((level) == SMB_OPLOCK_EXCLUSIVE) || \
47 - ((level) == SMB_OPLOCK_BATCH))
32 +#define BATCH_OR_EXCL (OPLOCK_LEVEL_BATCH | OPLOCK_LEVEL_ONE)
48 33
49 -static int smb_oplock_install_fem(smb_node_t *);
50 -static void smb_oplock_uninstall_fem(smb_node_t *);
51 -
52 -static void smb_oplock_wait(smb_node_t *);
53 -static void smb_oplock_wait_ack(smb_node_t *, uint32_t);
54 -static void smb_oplock_timedout(smb_node_t *);
55 -
56 -static smb_oplock_grant_t *smb_oplock_set_grant(smb_ofile_t *, uint8_t);
57 -void smb_oplock_clear_grant(smb_oplock_grant_t *);
58 -static int smb_oplock_insert_grant(smb_node_t *, smb_oplock_grant_t *);
59 -static void smb_oplock_remove_grant(smb_node_t *, smb_oplock_grant_t *);
60 -static smb_oplock_grant_t *smb_oplock_exclusive_grant(list_t *);
61 -static smb_oplock_grant_t *smb_oplock_get_grant(smb_oplock_t *, smb_ofile_t *);
62 -
63 -static void smb_oplock_sched_async_break(smb_oplock_grant_t *, uint8_t);
64 -static void smb_oplock_exec_async_break(void *);
65 -static void smb_oplock_break_levelII_locked(smb_node_t *);
66 -
67 34 /*
68 - * smb_oplock_install_fem
69 - * Install fem monitor for cross protocol oplock breaking.
35 + * Client has an open handle and requests an oplock.
36 + * Convert SMB1 oplock request info in to internal form,
37 + * call common oplock code, convert result to SMB1.
70 38 */
71 -static int
72 -smb_oplock_install_fem(smb_node_t *node)
73 -{
74 - ASSERT(MUTEX_HELD(&node->n_oplock.ol_mutex));
75 -
76 - if (node->n_oplock.ol_fem == B_FALSE) {
77 - if (smb_fem_oplock_install(node) != 0) {
78 - cmn_err(CE_NOTE, "No oplock granted: "
79 - "failed to install fem monitor %s",
80 - node->vp->v_path);
81 - return (-1);
82 - }
83 - node->n_oplock.ol_fem = B_TRUE;
84 - }
85 - return (0);
86 -}
87 -
88 -/*
89 - * smb_oplock_uninstall_fem
90 - * Uninstall fem monitor for cross protocol oplock breaking.
91 - */
92 -static void
93 -smb_oplock_uninstall_fem(smb_node_t *node)
94 -{
95 - ASSERT(MUTEX_HELD(&node->n_oplock.ol_mutex));
96 -
97 - if (node->n_oplock.ol_fem) {
98 - smb_fem_oplock_uninstall(node);
99 - node->n_oplock.ol_fem = B_FALSE;
100 - }
101 -}
102 -
103 -/*
104 - * This provides a way to fully disable oplocks, i.e. for testing.
105 - * You _really_ do _not_ want to turn this off, because if you do,
106 - * the clients send you very small read requests, and a _lot_ more
107 - * of them. The skc_oplock_enable parameter can be used to enable
108 - * or disable exclusive oplocks. Disabling that can be helpful
109 - * when there are clients not responding to oplock breaks.
110 - */
111 -int smb_oplocks_enabled = 1;
112 -
113 -/*
114 - * smb_oplock_acquire
115 - *
116 - * Attempt to acquire an oplock. Clients will request EXCLUSIVE or BATCH,
117 - * but might only be granted LEVEL_II or NONE.
118 - *
119 - * If oplocks are not supported on the tree, or node, grant NONE.
120 - * If nobody else has the file open, grant the requested level.
121 - * If any of the following are true, grant NONE:
122 - * - there is an exclusive oplock on the node
123 - * - op->op_oplock_levelII is B_FALSE (LEVEL_II not supported by open cmd.
124 - * - LEVEL_II oplocks are not supported for the session
125 - * - a BATCH oplock is requested on a named stream
126 - * - there are any range locks on the node (SMB writers)
127 - * Otherwise, grant LEVEL_II.
128 - *
129 - * ol->ol_xthread is set to the current thread to lock the oplock against
130 - * other operations until the acquire response is on the wire. When the
131 - * acquire response is on the wire, smb_oplock_broadcast() is called to
132 - * reset ol->ol_xthread and wake any waiting threads.
133 - */
134 39 void
135 -smb_oplock_acquire(smb_request_t *sr, smb_node_t *node, smb_ofile_t *ofile)
40 +smb1_oplock_acquire(smb_request_t *sr, boolean_t level2ok)
136 41 {
137 - smb_oplock_t *ol;
138 - smb_oplock_grant_t *og;
139 - list_t *grants;
140 - smb_arg_open_t *op;
141 - smb_tree_t *tree;
142 - smb_session_t *session;
42 + smb_arg_open_t *op = &sr->arg.open;
43 + smb_ofile_t *ofile = sr->fid_ofile;
44 + uint32_t status;
143 45
144 - SMB_NODE_VALID(node);
145 - SMB_OFILE_VALID(ofile);
146 -
147 - ASSERT(node == SMB_OFILE_GET_NODE(ofile));
148 - ASSERT(RW_LOCK_HELD(&node->n_lock));
149 -
150 - op = &sr->sr_open;
151 - tree = SMB_OFILE_GET_TREE(ofile);
152 - session = SMB_OFILE_GET_SESSION(ofile);
153 -
154 - if (smb_oplocks_enabled == 0 ||
155 - (op->op_oplock_level == SMB_OPLOCK_NONE) ||
156 - ((op->op_oplock_level == SMB_OPLOCK_BATCH) &&
157 - SMB_IS_STREAM(node))) {
46 + /* Only disk trees get oplocks. */
47 + if ((sr->tid_tree->t_res_type & STYPE_MASK) != STYPE_DISKTREE) {
158 48 op->op_oplock_level = SMB_OPLOCK_NONE;
159 49 return;
160 50 }
161 51
162 - ol = &node->n_oplock;
163 - grants = &ol->ol_grants;
164 -
165 - mutex_enter(&ol->ol_mutex);
166 - smb_oplock_wait(node);
167 -
168 - /*
169 - * Even if there are no other opens, we might want to
170 - * grant only a Level II (shared) oplock so we avoid
171 - * ever granting exclusive oplocks.
172 - *
173 - * Borrowing the SMB_TREE_OPLOCKS flag to enable/disable
174 - * exclusive oplocks (for now). See skc_oplock_enable,
175 - * which can now be taken as "exclusive oplock enable".
176 - * Should rename this parameter, and/or implement a new
177 - * multi-valued parameter for oplock enables.
178 - */
179 - if ((node->n_open_count > 1) ||
180 - (node->n_opening_count > 1) ||
181 - !smb_tree_has_feature(tree, SMB_TREE_OPLOCKS) ||
182 - smb_vop_other_opens(node->vp, ofile->f_mode)) {
183 - /*
184 - * There are other opens.
185 - */
186 - if ((!op->op_oplock_levelII) ||
187 - (!smb_session_levelII_oplocks(session)) ||
188 - (smb_oplock_exclusive_grant(grants) != NULL) ||
189 - (smb_lock_range_access(sr, node, 0, 0, B_FALSE))) {
190 - /*
191 - * LevelII (shared) oplock not allowed,
192 - * so reply with "none".
193 - */
194 - op->op_oplock_level = SMB_OPLOCK_NONE;
195 - mutex_exit(&ol->ol_mutex);
196 - return;
197 - }
198 -
199 - op->op_oplock_level = SMB_OPLOCK_LEVEL_II;
200 - }
201 -
202 - og = smb_oplock_set_grant(ofile, op->op_oplock_level);
203 - if (smb_oplock_insert_grant(node, og) != 0) {
204 - smb_oplock_clear_grant(og);
52 + if (!smb_tree_has_feature(sr->tid_tree, SMB_TREE_OPLOCKS)) {
205 53 op->op_oplock_level = SMB_OPLOCK_NONE;
206 - mutex_exit(&ol->ol_mutex);
207 54 return;
208 55 }
209 56
210 - ol->ol_xthread = curthread;
211 - mutex_exit(&ol->ol_mutex);
212 -}
57 + if (!smb_session_levelII_oplocks(sr->session))
58 + level2ok = B_FALSE;
213 59
214 -/*
215 - * smb_oplock_break
216 - *
217 - * Break granted oplocks according to the following rules:
218 - *
219 - * If there's an exclusive oplock granted on the node
220 - * - if the BREAK_BATCH flags is specified and the oplock is not
221 - * a batch oplock, no break is required.
222 - * - if the session doesn't support LEVEL II oplocks, and 'brk' is
223 - * BREAK_TO_LEVEL_II, do a BREAK_TO_NONE.
224 - * - if the oplock is already breaking update the break level (if
225 - * the requested break is to a lesser level), otherwise send an
226 - * oplock break.
227 - * Wait for acknowledgement of the break (unless NOWAIT flag is set)
228 - *
229 - * Otherwise:
230 - * If there are level II oplocks granted on the node, and the flags
231 - * indicate that they should be broken (BREAK_TO_NONE specified,
232 - * BREAK_EXCLUSIVE, BREAK_BATCH not specified) queue the levelII
233 - * break request for asynchronous processing.
234 - *
235 - * Returns:
236 - * 0 - oplock broken (or no break required)
237 - * EAGAIN - oplock break request sent and would block
238 - * awaiting the reponse but NOWAIT was specified
239 - *
240 - * NB: sr == NULL when called by FEM framework.
241 - */
242 -int
243 -smb_oplock_break(smb_request_t *sr, smb_node_t *node, uint32_t flags)
244 -{
245 - smb_oplock_t *ol;
246 - smb_oplock_grant_t *og;
247 - list_t *grants;
248 - uint32_t timeout;
249 - uint8_t brk;
60 + /* Common code checks file type. */
250 61
251 - SMB_NODE_VALID(node);
252 - ol = &node->n_oplock;
253 - grants = &ol->ol_grants;
254 -
255 - mutex_enter(&ol->ol_mutex);
256 - smb_oplock_wait(node);
257 -
258 - og = list_head(grants);
259 - if (og == NULL) {
260 - mutex_exit(&ol->ol_mutex);
261 - return (0);
262 - }
263 -
264 - SMB_OPLOCK_GRANT_VALID(og);
265 -
266 - /* break levelII oplocks */
267 - if (og->og_level == SMB_OPLOCK_LEVEL_II) {
268 - mutex_exit(&ol->ol_mutex);
269 -
270 - if ((flags & SMB_OPLOCK_BREAK_TO_NONE) &&
271 - !(flags & SMB_OPLOCK_BREAK_EXCLUSIVE) &&
272 - !(flags & SMB_OPLOCK_BREAK_BATCH)) {
273 - smb_oplock_break_levelII(node);
274 - }
275 - return (0);
276 - }
277 -
278 - /* break exclusive oplock */
279 - if ((flags & SMB_OPLOCK_BREAK_BATCH) &&
280 - (og->og_level != SMB_OPLOCK_BATCH)) {
281 - mutex_exit(&ol->ol_mutex);
282 - return (0);
283 - }
284 -
285 - if ((flags & SMB_OPLOCK_BREAK_TO_LEVEL_II) &&
286 - smb_session_levelII_oplocks(og->og_session)) {
287 - brk = SMB_OPLOCK_BREAK_TO_LEVEL_II;
288 - } else {
289 - brk = SMB_OPLOCK_BREAK_TO_NONE;
290 - }
291 -
292 - switch (ol->ol_break) {
293 - case SMB_OPLOCK_NO_BREAK:
294 - ol->ol_break = brk;
295 - smb_oplock_sched_async_break(og, brk);
62 + /*
63 + * SMB1: Convert to internal form.
64 + */
65 + switch (op->op_oplock_level) {
66 + case SMB_OPLOCK_BATCH:
67 + op->op_oplock_state = OPLOCK_LEVEL_BATCH;
296 68 break;
297 - case SMB_OPLOCK_BREAK_TO_LEVEL_II:
298 - if (brk == SMB_OPLOCK_BREAK_TO_NONE)
299 - ol->ol_break = SMB_OPLOCK_BREAK_TO_NONE;
69 + case SMB_OPLOCK_EXCLUSIVE:
70 + op->op_oplock_state = OPLOCK_LEVEL_ONE;
300 71 break;
301 - case SMB_OPLOCK_BREAK_TO_NONE:
302 - default:
72 + case SMB_OPLOCK_LEVEL_II:
73 + op->op_oplock_state = OPLOCK_LEVEL_TWO;
303 74 break;
75 + case SMB_OPLOCK_NONE:
76 + default:
77 + op->op_oplock_level = SMB_OPLOCK_NONE;
78 + return;
304 79 }
305 80
306 - if (flags & SMB_OPLOCK_BREAK_NOWAIT) {
307 - mutex_exit(&ol->ol_mutex);
308 - return (EAGAIN);
81 + /*
82 + * Tree options may force shared oplocks
83 + */
84 + if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_FORCE_L2_OPLOCK)) {
85 + op->op_oplock_state = OPLOCK_LEVEL_TWO;
309 86 }
310 87
311 - if (sr && (sr->session == og->og_session) &&
312 - (sr->smb_uid == og->og_uid)) {
313 - timeout = smb_oplock_min_timeout;
88 + /*
89 + * Try exclusive first, if requested
90 + */
91 + if ((op->op_oplock_state & BATCH_OR_EXCL) != 0) {
92 + status = smb_oplock_request(sr, ofile,
93 + &op->op_oplock_state);
314 94 } else {
315 - timeout = smb_oplock_timeout;
95 + status = NT_STATUS_OPLOCK_NOT_GRANTED;
316 96 }
317 97
318 - mutex_exit(&ol->ol_mutex);
319 - smb_oplock_wait_ack(node, timeout);
320 - return (0);
321 -}
322 -
323 -/*
324 - * smb_oplock_break_levelII
325 - *
326 - * This is called after a file is modified in some way. If there are
327 - * LevelII (shared) oplocks, break those to none. If there is an
328 - * exclusive oplock, there can be no LevelII oplocks, so do nothing.
329 - *
330 - * LevelII (shared) oplock breaks are processed asynchronously.
331 - * Unlike exclusive oplock breaks, the thread initiating the break
332 - * is NOT blocked while the request is processed.
333 - *
334 - * There may be a thread with exclusive rights to oplock state for
335 - * this node (via ol_xthread in smb_oplock_wait) and if so, we must
336 - * avoid breaking oplocks until that's out of the way. However, we
337 - * really don't want to block here, so when ol_xthread is set, we'll
338 - * just mark that a "break level II to none" is pending, and let the
339 - * exclusive thread do this work when it's done being exclusive.
340 - */
341 -void
342 -smb_oplock_break_levelII(smb_node_t *node)
343 -{
344 - smb_oplock_t *ol;
345 -
346 - ol = &node->n_oplock;
347 - mutex_enter(&ol->ol_mutex);
348 -
349 - /* Instead of: smb_oplock_wait() ... */
350 - if (ol->ol_xthread != NULL) {
351 - /* Defer the call to smb_oplock_broadcast(). */
352 - ol->ol_brk_pending = SMB_OPLOCK_BREAK_TO_NONE;
353 - } else {
354 - /* Equivalent of smb_oplock_wait() done. */
355 - smb_oplock_break_levelII_locked(node);
98 + /*
99 + * If exclusive failed (or tree forced shared oplocks)
100 + * and if the caller supports Level II, try shared.
101 + */
102 + if (status == NT_STATUS_OPLOCK_NOT_GRANTED && level2ok) {
103 + op->op_oplock_state = OPLOCK_LEVEL_TWO;
104 + status = smb_oplock_request(sr, ofile,
105 + &op->op_oplock_state);
356 106 }
357 107
358 - mutex_exit(&ol->ol_mutex);
359 -}
360 -
361 -/*
362 - * smb_oplock_break_levelII_locked
363 - * Internal helper for smb_oplock_break_levelII()
364 - *
365 - * Called with the oplock mutex already held, and _after_
366 - * (the equivalent of) an smb_oplock_wait().
367 - */
368 -static void
369 -smb_oplock_break_levelII_locked(smb_node_t *node)
370 -{
371 - smb_oplock_t *ol;
372 - smb_oplock_grant_t *og;
373 - list_t *grants;
374 -
375 - ol = &node->n_oplock;
376 - grants = &ol->ol_grants;
377 -
378 - ASSERT(MUTEX_HELD(&ol->ol_mutex));
379 - ASSERT(ol->ol_xthread == NULL);
380 -
381 - while ((og = list_head(grants)) != NULL) {
382 - SMB_OPLOCK_GRANT_VALID(og);
383 -
384 - /*
385 - * If there's an exclusive oplock, there are
386 - * no LevelII oplocks, so do nothing.
387 - */
388 - if (SMB_OPLOCK_IS_EXCLUSIVE(og->og_level))
389 - break;
390 -
391 - smb_oplock_sched_async_break(og, SMB_OPLOCK_BREAK_TO_NONE);
392 - smb_oplock_remove_grant(node, og);
393 - smb_oplock_clear_grant(og);
108 + /*
109 + * Either of the above may have returned the
110 + * status code that says we should wait.
111 + */
112 + if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
113 + (void) smb_oplock_wait_break(ofile->f_node, 0);
114 + status = 0;
394 115 }
395 -}
396 116
397 -/*
398 - * Schedule a call to smb_session_oplock_break
399 - * using an smb_request on the owning session.
400 - */
401 -static void
402 -smb_oplock_sched_async_break(smb_oplock_grant_t *og, uint8_t brk)
403 -{
404 - smb_request_t *sr;
405 - smb_ofile_t *ofile;
406 -
407 117 /*
408 - * Make sure we can get a hold on the ofile. If we can't,
409 - * the file is closing, and there's no point scheduling an
410 - * oplock break on it. (Also hold the tree and user.)
411 - * These holds account for the pointers we copy into the
412 - * smb_request fields: fid_ofile, tid_tree, uid_user.
413 - * These holds are released via smb_request_free after
414 - * the oplock break has been sent.
118 + * Keep track of what we got (in ofile->f_oplock.og_state)
119 + * so we'll know what we had when sending a break later.
120 + * The og_dialect here is the oplock dialect, which may be
121 + * different than SMB dialect. Pre-NT clients did not
122 + * support "Level II" oplocks. If we're talking to a
123 + * client that didn't set the CAP_LEVEL_II_OPLOCKS in
124 + * its capabilities, let og_dialect = LANMAN2_1.
415 125 */
416 - ofile = og->og_ofile;
417 - if (!smb_ofile_hold(ofile))
126 + ofile->f_oplock.og_dialect = (level2ok) ?
127 + NT_LM_0_12 : LANMAN2_1;
128 + switch (status) {
129 + case NT_STATUS_SUCCESS:
130 + ofile->f_oplock.og_state = op->op_oplock_state;
131 + break;
132 + case NT_STATUS_OPLOCK_NOT_GRANTED:
133 + ofile->f_oplock.og_state = 0;
134 + op->op_oplock_level = SMB_OPLOCK_NONE;
418 135 return;
419 - smb_tree_hold_internal(ofile->f_tree);
420 - smb_user_hold_internal(ofile->f_user);
421 -
422 - sr = smb_request_alloc(og->og_session, 0);
423 - sr->sr_state = SMB_REQ_STATE_SUBMITTED;
424 - sr->user_cr = zone_kcred();
425 - sr->fid_ofile = ofile;
426 - sr->tid_tree = ofile->f_tree;
427 - sr->uid_user = ofile->f_user;
428 -
429 - sr->arg.olbrk = *og; /* struct copy */
430 - sr->arg.olbrk.og_breaking = brk;
431 -
432 - (void) taskq_dispatch(
433 - sr->sr_server->sv_worker_pool,
434 - smb_oplock_exec_async_break, sr, TQ_SLEEP);
435 -}
436 -
437 -/*
438 - * smb_oplock_exec_async_break
439 - *
440 - * Called via the taskq to handle an asynchronous oplock break.
441 - * We have a hold on the ofile, which keeps the FID here valid.
442 - */
443 -static void
444 -smb_oplock_exec_async_break(void *arg)
445 -{
446 - smb_request_t *sr = arg;
447 - smb_oplock_grant_t *og = &sr->arg.olbrk;
448 -
449 - SMB_REQ_VALID(sr);
450 - SMB_OPLOCK_GRANT_VALID(og);
451 -
452 - mutex_enter(&sr->sr_mutex);
453 - sr->sr_worker = curthread;
454 - sr->sr_time_active = gethrtime();
455 -
456 - switch (sr->sr_state) {
457 - case SMB_REQ_STATE_SUBMITTED:
458 - sr->sr_state = SMB_REQ_STATE_ACTIVE;
459 - mutex_exit(&sr->sr_mutex);
460 -
461 - /*
462 - * This is where we actually do the deferred work
463 - * requested by smb_oplock_sched_async_break().
464 - */
465 - smb_session_oplock_break(sr, og->og_breaking);
466 -
467 - mutex_enter(&sr->sr_mutex);
468 - /* FALLTHROUGH */
469 -
470 - default: /* typically cancelled */
471 - sr->sr_state = SMB_REQ_STATE_COMPLETED;
472 - mutex_exit(&sr->sr_mutex);
473 - }
474 -
475 - smb_request_free(sr);
476 -}
477 -
478 -/*
479 - * smb_oplock_wait_ack
480 - *
481 - * Timed wait for an oplock break acknowledgement (or oplock release).
482 - */
483 -static void
484 -smb_oplock_wait_ack(smb_node_t *node, uint32_t timeout)
485 -{
486 - smb_oplock_t *ol;
487 - clock_t time;
488 -
489 - ol = &node->n_oplock;
490 - mutex_enter(&ol->ol_mutex);
491 - time = MSEC_TO_TICK(timeout) + ddi_get_lbolt();
492 -
493 - while (ol->ol_break != SMB_OPLOCK_NO_BREAK) {
494 - if (cv_timedwait(&ol->ol_cv, &ol->ol_mutex, time) < 0) {
495 - smb_oplock_timedout(node);
496 - cv_broadcast(&ol->ol_cv);
497 - break;
498 - }
499 - }
500 - mutex_exit(&ol->ol_mutex);
501 -}
502 -
503 -/*
504 - * smb_oplock_timedout
505 - *
506 - * An oplock break has not been acknowledged within timeout
507 - * 'smb_oplock_timeout'.
508 - * Set oplock grant to the desired break level.
509 - */
510 -static void
511 -smb_oplock_timedout(smb_node_t *node)
512 -{
513 - smb_oplock_t *ol;
514 - smb_oplock_grant_t *og;
515 - list_t *grants;
516 -
517 - ol = &node->n_oplock;
518 - grants = &ol->ol_grants;
519 -
520 - ASSERT(MUTEX_HELD(&ol->ol_mutex));
521 -
522 - og = smb_oplock_exclusive_grant(grants);
523 - if (og) {
524 - switch (ol->ol_break) {
525 - case SMB_OPLOCK_BREAK_TO_NONE:
526 - og->og_level = SMB_OPLOCK_NONE;
527 - smb_oplock_remove_grant(node, og);
528 - smb_oplock_clear_grant(og);
529 - break;
530 - case SMB_OPLOCK_BREAK_TO_LEVEL_II:
531 - og->og_level = SMB_OPLOCK_LEVEL_II;
532 - break;
533 - default:
534 - SMB_PANIC();
535 - }
536 - }
537 - ol->ol_break = SMB_OPLOCK_NO_BREAK;
538 -}
539 -
540 -/*
541 - * smb_oplock_release
542 - *
543 - * Release the oplock granted on ofile 'of'.
544 - * Wake any threads waiting for an oplock break acknowledgement for
545 - * this oplock.
546 - * This is called when the ofile is being closed.
547 - */
548 -void
549 -smb_oplock_release(smb_node_t *node, smb_ofile_t *of)
550 -{
551 - smb_oplock_t *ol;
552 - smb_oplock_grant_t *og;
553 -
554 - ol = &node->n_oplock;
555 - mutex_enter(&ol->ol_mutex);
556 - smb_oplock_wait(node);
557 -
558 - og = smb_oplock_get_grant(ol, of);
559 - if (og) {
560 - smb_oplock_remove_grant(node, og);
561 - smb_oplock_clear_grant(og);
562 -
563 - if (ol->ol_break != SMB_OPLOCK_NO_BREAK) {
564 - ol->ol_break = SMB_OPLOCK_NO_BREAK;
565 - cv_broadcast(&ol->ol_cv);
566 - }
567 - }
568 -
569 - mutex_exit(&ol->ol_mutex);
570 -}
571 -
572 -/*
573 - * smb_oplock_ack
574 - *
575 - * Process oplock acknowledgement received for ofile 'of'.
576 - * - oplock.ol_break is the break level that was requested.
577 - * - brk is the break level being acknowledged by the client.
578 - *
579 - * Update the oplock grant level to the lesser of ol_break and brk.
580 - * If the grant is now SMB_OPLOCK_NONE, remove the grant from the
581 - * oplock's grant list and delete it.
582 - * If the requested break level (ol_break) was NONE and the brk is
583 - * LEVEL_II, send another oplock break (NONE). Do not wait for an
584 - * acknowledgement.
585 - * Wake any threads waiting for the oplock break acknowledgement.
586 - */
587 -void
588 -smb_oplock_ack(smb_node_t *node, smb_ofile_t *of, uint8_t brk)
589 -{
590 - smb_oplock_t *ol;
591 - smb_oplock_grant_t *og;
592 -
593 - ol = &node->n_oplock;
594 - mutex_enter(&ol->ol_mutex);
595 - smb_oplock_wait(node);
596 -
597 - if ((ol->ol_break == SMB_OPLOCK_NO_BREAK) ||
598 - ((og = smb_oplock_get_grant(ol, of)) == NULL)) {
599 - mutex_exit(&ol->ol_mutex);
136 + default:
137 + /* Caller did not check args sufficiently? */
138 + cmn_err(CE_NOTE, "clnt %s oplock req. err 0x%x",
139 + sr->session->ip_addr_str, status);
140 + ofile->f_oplock.og_state = 0;
141 + op->op_oplock_level = SMB_OPLOCK_NONE;
600 142 return;
601 143 }
602 144
603 - switch (brk) {
604 - case SMB_OPLOCK_BREAK_TO_NONE:
605 - og->og_level = SMB_OPLOCK_NONE;
606 - break;
607 - case SMB_OPLOCK_BREAK_TO_LEVEL_II:
608 - if (ol->ol_break == SMB_OPLOCK_BREAK_TO_LEVEL_II) {
609 - og->og_level = SMB_OPLOCK_LEVEL_II;
610 - } else {
611 - /* SMB_OPLOCK_BREAK_TO_NONE */
612 - og->og_level = SMB_OPLOCK_NONE;
613 - smb_oplock_sched_async_break(og,
614 - SMB_OPLOCK_BREAK_TO_NONE);
615 - }
616 - break;
617 - default:
618 - SMB_PANIC();
145 + /*
146 + * Have STATUS_SUCCESS
147 + * Convert internal oplock state to SMB1
148 + */
149 + if (op->op_oplock_state & OPLOCK_LEVEL_BATCH) {
150 + op->op_oplock_level = SMB_OPLOCK_BATCH;
151 + } else if (op->op_oplock_state & OPLOCK_LEVEL_ONE) {
152 + op->op_oplock_level = SMB_OPLOCK_EXCLUSIVE;
153 + } else if (op->op_oplock_state & OPLOCK_LEVEL_TWO) {
154 + op->op_oplock_level = SMB_OPLOCK_LEVEL_II;
155 + } else {
156 + op->op_oplock_level = SMB_OPLOCK_NONE;
619 157 }
620 -
621 - if (og->og_level == SMB_OPLOCK_NONE) {
622 - smb_oplock_remove_grant(node, og);
623 - smb_oplock_clear_grant(og);
624 - }
625 -
626 - ol->ol_break = SMB_OPLOCK_NO_BREAK;
627 - cv_broadcast(&ol->ol_cv);
628 -
629 - mutex_exit(&ol->ol_mutex);
630 -}
631 -
632 -/*
633 - * smb_oplock_broadcast
634 - *
635 - * Called when an open with oplock request completes.
636 - *
637 - * ol->ol_xthread identifies the thread that was performing an oplock
638 - * acquire. Other threads may be blocked awaiting completion of the
639 - * acquire.
640 - * If the calling thread is ol_xthread, wake any waiting threads.
641 - */
642 -void
643 -smb_oplock_broadcast(smb_node_t *node)
644 -{
645 - smb_oplock_t *ol;
646 -
647 - SMB_NODE_VALID(node);
648 - ol = &node->n_oplock;
649 -
650 - mutex_enter(&ol->ol_mutex);
651 - if ((ol->ol_xthread != NULL) && (ol->ol_xthread == curthread)) {
652 - ol->ol_xthread = NULL;
653 - if (ol->ol_brk_pending) {
654 - ol->ol_brk_pending = 0;
655 - smb_oplock_break_levelII_locked(node);
656 - }
657 - cv_broadcast(&ol->ol_cv);
658 - }
659 - mutex_exit(&ol->ol_mutex);
660 -}
661 -
662 -/*
663 - * smb_oplock_wait
664 - *
665 - * Wait for the completion of an oplock acquire.
666 - * If ol_xthread is not NULL and doesn't contain the pointer to the
667 - * context of the calling thread, the caller will sleep until the
668 - * ol_xthread is reset to NULL (via smb_oplock_broadcast()).
669 - */
670 -static void
671 -smb_oplock_wait(smb_node_t *node)
672 -{
673 - smb_oplock_t *ol;
674 -
675 - ol = &node->n_oplock;
676 - ASSERT(MUTEX_HELD(&ol->ol_mutex));
677 -
678 - if ((ol->ol_xthread != NULL) && (ol->ol_xthread != curthread)) {
679 - while (ol->ol_xthread != NULL)
680 - cv_wait(&ol->ol_cv, &ol->ol_mutex);
681 - }
682 -}
683 -
684 -/*
685 - * smb_oplock_set_grant
686 - */
687 -static smb_oplock_grant_t *
688 -smb_oplock_set_grant(smb_ofile_t *of, uint8_t level)
689 -{
690 - smb_oplock_grant_t *og;
691 -
692 - og = &of->f_oplock_grant;
693 -
694 - og->og_magic = SMB_OPLOCK_GRANT_MAGIC;
695 - og->og_breaking = 0;
696 - og->og_level = level;
697 - og->og_ofile = of;
698 - og->og_fid = of->f_fid;
699 - og->og_tid = of->f_tree->t_tid;
700 - og->og_uid = of->f_user->u_uid;
701 - og->og_session = of->f_session;
702 - return (og);
703 -}
704 -
705 -/*
706 - * smb_oplock_clear_grant
707 - */
708 -void
709 -smb_oplock_clear_grant(smb_oplock_grant_t *og)
710 -{
711 - bzero(og, sizeof (smb_oplock_grant_t));
712 -}
713 -
714 -/*
715 - * smb_oplock_insert_grant
716 - *
717 - * If there are no grants in the oplock's list install the fem
718 - * monitor.
719 - * Insert the grant into the list and increment the grant count.
720 - */
721 -static int
722 -smb_oplock_insert_grant(smb_node_t *node, smb_oplock_grant_t *og)
723 -{
724 - smb_oplock_t *ol = &node->n_oplock;
725 -
726 - ASSERT(MUTEX_HELD(&ol->ol_mutex));
727 -
728 - if (ol->ol_count == 0) {
729 - if (smb_oplock_install_fem(node) != 0)
730 - return (-1);
731 - }
732 -
733 - list_insert_tail(&ol->ol_grants, og);
734 - ++ol->ol_count;
735 - return (0);
736 -}
737 -
738 -/*
739 - * smb_oplock_remove_grant
740 - *
741 - * Remove the oplock grant from the list, decrement the grant count
742 - * and, if there are no other grants in the list, uninstall the fem
743 - * monitor.
744 - */
745 -static void
746 -smb_oplock_remove_grant(smb_node_t *node, smb_oplock_grant_t *og)
747 -{
748 - smb_oplock_t *ol = &node->n_oplock;
749 -
750 - ASSERT(MUTEX_HELD(&ol->ol_mutex));
751 - ASSERT(ol->ol_count > 0);
752 -
753 - list_remove(&ol->ol_grants, og);
754 - if (--ol->ol_count == 0)
755 - smb_oplock_uninstall_fem(node);
756 -}
757 -
758 -/*
759 - * smb_oplock_exclusive_grant
760 - *
761 - * If an exclusive (EXCLUSIVE or BATCH) oplock grant exists,
762 - * return it. Otherwise return NULL.
763 - */
764 -static smb_oplock_grant_t *
765 -smb_oplock_exclusive_grant(list_t *grants)
766 -{
767 - smb_oplock_grant_t *og;
768 -
769 - og = list_head(grants);
770 - if (og) {
771 - SMB_OPLOCK_GRANT_VALID(og);
772 - if (SMB_OPLOCK_IS_EXCLUSIVE(og->og_level))
773 - return (og);
774 - }
775 - return (NULL);
776 -}
777 -
778 -/*
779 - * smb_oplock_get_grant
780 - *
781 - * Find oplock grant corresponding to the specified ofile.
782 - */
783 -static smb_oplock_grant_t *
784 -smb_oplock_get_grant(smb_oplock_t *ol, smb_ofile_t *ofile)
785 -{
786 - ASSERT(MUTEX_HELD(&ol->ol_mutex));
787 -
788 - if (SMB_OFILE_OPLOCK_GRANTED(ofile))
789 - return (&ofile->f_oplock_grant);
790 - else
791 - return (NULL);
792 158 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX