xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_oplock.c (revision 3b24312d6398cc8e8e513562a52571c416322378)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23  * Copyright 2020 Tintri by DDN, Inc.  All rights reserved.
24  * Copyright 2022 RackTop Systems, Inc.
25  */
26 
27 /*
28  * smb1 oplock support
29  */
30 
31 #include <smbsrv/smb_kproto.h>
32 
33 #define	BATCH_OR_EXCL	(OPLOCK_LEVEL_BATCH | OPLOCK_LEVEL_ONE)
34 
35 /*
36  * This is called by the SMB1 "Locking_andX" handler,
37  * for SMB1 oplock break acknowledgement.
38  * This is an "Ack" from the client.
39  */
40 void
smb1_oplock_ack_break(smb_request_t * sr,uchar_t oplock_level)41 smb1_oplock_ack_break(smb_request_t *sr, uchar_t oplock_level)
42 {
43 	smb_ofile_t	*ofile;
44 	smb_node_t	*node;
45 	uint32_t	NewLevel;
46 
47 	ofile = sr->fid_ofile;
48 	node = ofile->f_node;
49 
50 	if (oplock_level == 0)
51 		NewLevel = OPLOCK_LEVEL_NONE;
52 	else
53 		NewLevel = OPLOCK_LEVEL_TWO;
54 
55 	smb_llist_enter(&node->n_ofile_list, RW_READER);
56 	mutex_enter(&node->n_oplock.ol_mutex);
57 
58 	ofile->f_oplock.og_breaking = B_FALSE;
59 	cv_broadcast(&ofile->f_oplock.og_ack_cv);
60 
61 	(void) smb_oplock_ack_break(sr, ofile, &NewLevel);
62 
63 	ofile->f_oplock.og_state = NewLevel;
64 
65 	mutex_exit(&node->n_oplock.ol_mutex);
66 	smb_llist_exit(&node->n_ofile_list);
67 }
68 
69 /*
70  * Compose an SMB1 Oplock Break Notification packet, including
71  * the SMB1 header and everything, in sr->reply.
72  * The caller will send it and free the request.
73  */
74 static void
smb1_oplock_break_notification(smb_request_t * sr,uint32_t NewLevel)75 smb1_oplock_break_notification(smb_request_t *sr, uint32_t NewLevel)
76 {
77 	smb_ofile_t *ofile = sr->fid_ofile;
78 	uint16_t fid;
79 	uint8_t lock_type;
80 	uint8_t oplock_level;
81 
82 	/*
83 	 * Convert internal level to SMB1
84 	 */
85 	switch (NewLevel) {
86 	default:
87 		ASSERT(0);
88 		/* FALLTHROUGH */
89 	case OPLOCK_LEVEL_NONE:
90 		oplock_level = 0;
91 		break;
92 
93 	case OPLOCK_LEVEL_TWO:
94 		oplock_level = 1;
95 		break;
96 	}
97 
98 	sr->smb_com = SMB_COM_LOCKING_ANDX;
99 	sr->smb_tid = ofile->f_tree->t_tid;
100 	sr->smb_pid = 0xFFFF;
101 	sr->smb_uid = 0;
102 	sr->smb_mid = 0xFFFF;
103 	fid = ofile->f_fid;
104 	lock_type = LOCKING_ANDX_OPLOCK_RELEASE;
105 
106 	(void) smb_mbc_encodef(
107 	    &sr->reply, "Mb19.wwwwbb3.wbb10.",
108 	    /*  "\xffSMB"		   M */
109 	    sr->smb_com,		/* b */
110 	    /* status, flags, signature	 19. */
111 	    sr->smb_tid,		/* w */
112 	    sr->smb_pid,		/* w */
113 	    sr->smb_uid,		/* w */
114 	    sr->smb_mid,		/* w */
115 	    8,		/* word count	   b */
116 	    0xFF,	/* AndX cmd	   b */
117 	    /*  AndX reserved, offset	  3. */
118 	    fid,
119 	    lock_type,
120 	    oplock_level);
121 }
122 
123 /*
124  * Send an oplock break over the wire, or if we can't,
125  * then process the oplock break locally.
126  *
127  * [MS-CIFS] 3.3.4.2 Object Store Indicates an OpLock Break
128  *
129  * This is mostly similar to smb2_oplock_send_break()
130  * See top comment there about the design.
131  * Called from smb_oplock_async_break.
132  *
133  * This handles only SMB1, which has no durable handles,
134  * and never has GRANULAR oplocks.
135  */
136 void
smb1_oplock_send_break(smb_request_t * sr)137 smb1_oplock_send_break(smb_request_t *sr)
138 {
139 	smb_ofile_t	*ofile = sr->fid_ofile;
140 	smb_node_t	*node = ofile->f_node;
141 	uint32_t	NewLevel = sr->arg.olbrk.NewLevel;
142 	boolean_t	AckReq = sr->arg.olbrk.AckRequired;
143 	uint32_t	status;
144 	int		rc;
145 
146 	/*
147 	 * SMB1 clients should only get Level II oplocks if they
148 	 * set the capability indicating they know about them.
149 	 */
150 	if (NewLevel == OPLOCK_LEVEL_TWO &&
151 	    ofile->f_oplock.og_dialect < NT_LM_0_12)
152 		NewLevel = OPLOCK_LEVEL_NONE;
153 
154 	/*
155 	 * Build the break message in sr->reply.
156 	 * It's free'd in smb_request_free().
157 	 * Always SMB1 here.
158 	 */
159 	sr->reply.max_bytes = MLEN;
160 	smb1_oplock_break_notification(sr, NewLevel);
161 
162 	/*
163 	 * Try to send the break message to the client.
164 	 * If connected, this IF body will be true.
165 	 */
166 	if (sr->session == ofile->f_session)
167 		rc = smb_session_send(sr->session, 0, &sr->reply);
168 	else
169 		rc = ENOTCONN;
170 
171 	if (rc != 0) {
172 		/*
173 		 * We were unable to send the oplock break request,
174 		 * presumably because the connection is gone.
175 		 * Just close the handle.
176 		 */
177 		smb_ofile_close(ofile, 0);
178 		return;
179 	}
180 
181 	/*
182 	 * OK, we were able to send the break message.
183 	 * If no ack. required, we're done.
184 	 */
185 	if (!AckReq)
186 		return;
187 
188 	/*
189 	 * We're expecting an ACK.  Wait in this thread
190 	 * so we can log clients that don't respond.
191 	 * Note: this can also fail for other reasons
192 	 * such as client disconnect or server shutdown.
193 	 */
194 	status = smb_oplock_wait_ack(sr, NewLevel);
195 	if (status == 0)
196 		return;
197 
198 	DTRACE_PROBE2(wait__ack__failed, smb_request_t *, sr,
199 	    uint32_t, status);
200 
201 	/*
202 	 * Did not get an ACK, so do the ACK locally.
203 	 * Note: always break to none here, regardless
204 	 * of what the passed in cache level was.
205 	 */
206 	NewLevel = OPLOCK_LEVEL_NONE;
207 
208 	smb_llist_enter(&node->n_ofile_list, RW_READER);
209 	mutex_enter(&node->n_oplock.ol_mutex);
210 
211 	ofile->f_oplock.og_breaking = B_FALSE;
212 	cv_broadcast(&ofile->f_oplock.og_ack_cv);
213 
214 	status = smb_oplock_ack_break(sr, ofile, &NewLevel);
215 
216 	ofile->f_oplock.og_state = NewLevel;
217 
218 	mutex_exit(&node->n_oplock.ol_mutex);
219 	smb_llist_exit(&node->n_ofile_list);
220 
221 #ifdef	DEBUG
222 	if (status != 0) {
223 		cmn_err(CE_NOTE, "clnt %s local oplock ack, status=0x%x",
224 		    sr->session->ip_addr_str, status);
225 	}
226 #endif
227 }
228 
229 /*
230  * Client has an open handle and requests an oplock.
231  * Convert SMB1 oplock request info in to internal form,
232  * call common oplock code, convert result to SMB1.
233  */
234 void
smb1_oplock_acquire(smb_request_t * sr,boolean_t level2ok)235 smb1_oplock_acquire(smb_request_t *sr, boolean_t level2ok)
236 {
237 	smb_arg_open_t *op = &sr->arg.open;
238 	smb_ofile_t *ofile = sr->fid_ofile;
239 	uint32_t status;
240 
241 	/* Only disk trees get oplocks. */
242 	if ((sr->tid_tree->t_res_type & STYPE_MASK) != STYPE_DISKTREE) {
243 		op->op_oplock_level = SMB_OPLOCK_NONE;
244 		return;
245 	}
246 
247 	if (!smb_tree_has_feature(sr->tid_tree, SMB_TREE_OPLOCKS)) {
248 		op->op_oplock_level = SMB_OPLOCK_NONE;
249 		return;
250 	}
251 
252 	if (!smb_session_levelII_oplocks(sr->session))
253 		level2ok = B_FALSE;
254 
255 	/* Common code checks file type. */
256 
257 	/*
258 	 * SMB1: Convert to internal form.
259 	 */
260 	switch (op->op_oplock_level) {
261 	case SMB_OPLOCK_BATCH:
262 		op->op_oplock_state = OPLOCK_LEVEL_BATCH;
263 		break;
264 	case SMB_OPLOCK_EXCLUSIVE:
265 		op->op_oplock_state = OPLOCK_LEVEL_ONE;
266 		break;
267 	case SMB_OPLOCK_LEVEL_II:
268 		op->op_oplock_state = OPLOCK_LEVEL_TWO;
269 		break;
270 	case SMB_OPLOCK_NONE:
271 	default:
272 		op->op_oplock_level = SMB_OPLOCK_NONE;
273 		return;
274 	}
275 
276 	/*
277 	 * Tree options may force shared oplocks
278 	 */
279 	if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_FORCE_L2_OPLOCK)) {
280 		op->op_oplock_state = OPLOCK_LEVEL_TWO;
281 	}
282 
283 	/*
284 	 * Try exclusive first, if requested
285 	 */
286 	if ((op->op_oplock_state & BATCH_OR_EXCL) != 0) {
287 		status = smb_oplock_request(sr, ofile,
288 		    &op->op_oplock_state);
289 	} else {
290 		status = NT_STATUS_OPLOCK_NOT_GRANTED;
291 	}
292 
293 	/*
294 	 * If exclusive failed (or the tree forced shared oplocks)
295 	 * and if the caller supports Level II, try shared.
296 	 */
297 	if (status == NT_STATUS_OPLOCK_NOT_GRANTED && level2ok) {
298 		op->op_oplock_state = OPLOCK_LEVEL_TWO;
299 		status = smb_oplock_request(sr, ofile,
300 		    &op->op_oplock_state);
301 	}
302 
303 	/*
304 	 * Keep track of what we got (ofile->f_oplock.og_state etc)
305 	 * so we'll know what we had when sending a break later.
306 	 * The og_dialect here is the oplock dialect, which may be
307 	 * different than SMB dialect.  Pre-NT clients did not
308 	 * support "Level II" oplocks.  If we're talking to a
309 	 * client that didn't set the CAP_LEVEL_II_OPLOCKS in
310 	 * its capabilities, let og_dialect = LANMAN2_1.
311 	 */
312 	switch (status) {
313 	case NT_STATUS_SUCCESS:
314 	case NT_STATUS_OPLOCK_BREAK_IN_PROGRESS:
315 		ofile->f_oplock.og_dialect = (level2ok) ?
316 		    NT_LM_0_12 : LANMAN2_1;
317 		ofile->f_oplock.og_state   = op->op_oplock_state;
318 		ofile->f_oplock.og_breakto = op->op_oplock_state;
319 		ofile->f_oplock.og_breaking = B_FALSE;
320 		break;
321 	case NT_STATUS_OPLOCK_NOT_GRANTED:
322 		op->op_oplock_level = SMB_OPLOCK_NONE;
323 		return;
324 	default:
325 		/* Caller did not check args sufficiently? */
326 		cmn_err(CE_NOTE, "clnt %s oplock req. err 0x%x",
327 		    sr->session->ip_addr_str, status);
328 		op->op_oplock_level = SMB_OPLOCK_NONE;
329 		return;
330 	}
331 
332 	/*
333 	 * Only succes cases get here.
334 	 * Convert internal oplock state to SMB1
335 	 */
336 	if (op->op_oplock_state & OPLOCK_LEVEL_BATCH) {
337 		op->op_oplock_level = SMB_OPLOCK_BATCH;
338 	} else if (op->op_oplock_state & OPLOCK_LEVEL_ONE) {
339 		op->op_oplock_level = SMB_OPLOCK_EXCLUSIVE;
340 	} else if (op->op_oplock_state & OPLOCK_LEVEL_TWO) {
341 		op->op_oplock_level = SMB_OPLOCK_LEVEL_II;
342 	} else {
343 		op->op_oplock_level = SMB_OPLOCK_NONE;
344 	}
345 
346 	/*
347 	 * An smb_oplock_reqest call may have returned the
348 	 * status code that says we should wait.
349 	 */
350 	if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
351 		(void) smb_oplock_wait_break(sr, ofile->f_node, 0);
352 	}
353 }
354