xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_oplock.c (revision 20a7641f9918de8574b8b3b47dbe35c4bfc78df1)
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
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
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
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 	 */
192 	status = smb_oplock_wait_ack(sr, NewLevel);
193 	if (status == 0)
194 		return;
195 
196 	cmn_err(CE_NOTE, "clnt %s oplock break timeout",
197 	    sr->session->ip_addr_str);
198 	DTRACE_PROBE1(ack_timeout, smb_request_t *, sr);
199 
200 	/*
201 	 * Did not get an ACK, so do the ACK locally.
202 	 * Note: always break to none here, regardless
203 	 * of what the passed in cache level was.
204 	 */
205 	NewLevel = OPLOCK_LEVEL_NONE;
206 
207 	smb_llist_enter(&node->n_ofile_list, RW_READER);
208 	mutex_enter(&node->n_oplock.ol_mutex);
209 
210 	ofile->f_oplock.og_breaking = B_FALSE;
211 	cv_broadcast(&ofile->f_oplock.og_ack_cv);
212 
213 	status = smb_oplock_ack_break(sr, ofile, &NewLevel);
214 
215 	ofile->f_oplock.og_state = NewLevel;
216 
217 	mutex_exit(&node->n_oplock.ol_mutex);
218 	smb_llist_exit(&node->n_ofile_list);
219 
220 #ifdef	DEBUG
221 	if (status != 0) {
222 		cmn_err(CE_NOTE, "clnt %s local oplock ack, status=0x%x",
223 		    sr->session->ip_addr_str, status);
224 	}
225 #endif
226 }
227 
228 /*
229  * Client has an open handle and requests an oplock.
230  * Convert SMB1 oplock request info in to internal form,
231  * call common oplock code, convert result to SMB1.
232  */
233 void
234 smb1_oplock_acquire(smb_request_t *sr, boolean_t level2ok)
235 {
236 	smb_arg_open_t *op = &sr->arg.open;
237 	smb_ofile_t *ofile = sr->fid_ofile;
238 	uint32_t status;
239 
240 	/* Only disk trees get oplocks. */
241 	if ((sr->tid_tree->t_res_type & STYPE_MASK) != STYPE_DISKTREE) {
242 		op->op_oplock_level = SMB_OPLOCK_NONE;
243 		return;
244 	}
245 
246 	if (!smb_tree_has_feature(sr->tid_tree, SMB_TREE_OPLOCKS)) {
247 		op->op_oplock_level = SMB_OPLOCK_NONE;
248 		return;
249 	}
250 
251 	if (!smb_session_levelII_oplocks(sr->session))
252 		level2ok = B_FALSE;
253 
254 	/* Common code checks file type. */
255 
256 	/*
257 	 * SMB1: Convert to internal form.
258 	 */
259 	switch (op->op_oplock_level) {
260 	case SMB_OPLOCK_BATCH:
261 		op->op_oplock_state = OPLOCK_LEVEL_BATCH;
262 		break;
263 	case SMB_OPLOCK_EXCLUSIVE:
264 		op->op_oplock_state = OPLOCK_LEVEL_ONE;
265 		break;
266 	case SMB_OPLOCK_LEVEL_II:
267 		op->op_oplock_state = OPLOCK_LEVEL_TWO;
268 		break;
269 	case SMB_OPLOCK_NONE:
270 	default:
271 		op->op_oplock_level = SMB_OPLOCK_NONE;
272 		return;
273 	}
274 
275 	/*
276 	 * Tree options may force shared oplocks
277 	 */
278 	if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_FORCE_L2_OPLOCK)) {
279 		op->op_oplock_state = OPLOCK_LEVEL_TWO;
280 	}
281 
282 	/*
283 	 * Try exclusive first, if requested
284 	 */
285 	if ((op->op_oplock_state & BATCH_OR_EXCL) != 0) {
286 		status = smb_oplock_request(sr, ofile,
287 		    &op->op_oplock_state);
288 	} else {
289 		status = NT_STATUS_OPLOCK_NOT_GRANTED;
290 	}
291 
292 	/*
293 	 * If exclusive failed (or the tree forced shared oplocks)
294 	 * and if the caller supports Level II, try shared.
295 	 */
296 	if (status == NT_STATUS_OPLOCK_NOT_GRANTED && level2ok) {
297 		op->op_oplock_state = OPLOCK_LEVEL_TWO;
298 		status = smb_oplock_request(sr, ofile,
299 		    &op->op_oplock_state);
300 	}
301 
302 	/*
303 	 * Keep track of what we got (ofile->f_oplock.og_state etc)
304 	 * so we'll know what we had when sending a break later.
305 	 * The og_dialect here is the oplock dialect, which may be
306 	 * different than SMB dialect.  Pre-NT clients did not
307 	 * support "Level II" oplocks.  If we're talking to a
308 	 * client that didn't set the CAP_LEVEL_II_OPLOCKS in
309 	 * its capabilities, let og_dialect = LANMAN2_1.
310 	 */
311 	switch (status) {
312 	case NT_STATUS_SUCCESS:
313 	case NT_STATUS_OPLOCK_BREAK_IN_PROGRESS:
314 		ofile->f_oplock.og_dialect = (level2ok) ?
315 		    NT_LM_0_12 : LANMAN2_1;
316 		ofile->f_oplock.og_state   = op->op_oplock_state;
317 		ofile->f_oplock.og_breakto = op->op_oplock_state;
318 		ofile->f_oplock.og_breaking = B_FALSE;
319 		break;
320 	case NT_STATUS_OPLOCK_NOT_GRANTED:
321 		op->op_oplock_level = SMB_OPLOCK_NONE;
322 		return;
323 	default:
324 		/* Caller did not check args sufficiently? */
325 		cmn_err(CE_NOTE, "clnt %s oplock req. err 0x%x",
326 		    sr->session->ip_addr_str, status);
327 		op->op_oplock_level = SMB_OPLOCK_NONE;
328 		return;
329 	}
330 
331 	/*
332 	 * Only succes cases get here.
333 	 * Convert internal oplock state to SMB1
334 	 */
335 	if (op->op_oplock_state & OPLOCK_LEVEL_BATCH) {
336 		op->op_oplock_level = SMB_OPLOCK_BATCH;
337 	} else if (op->op_oplock_state & OPLOCK_LEVEL_ONE) {
338 		op->op_oplock_level = SMB_OPLOCK_EXCLUSIVE;
339 	} else if (op->op_oplock_state & OPLOCK_LEVEL_TWO) {
340 		op->op_oplock_level = SMB_OPLOCK_LEVEL_II;
341 	} else {
342 		op->op_oplock_level = SMB_OPLOCK_NONE;
343 	}
344 
345 	/*
346 	 * An smb_oplock_reqest call may have returned the
347 	 * status code that says we should wait.
348 	 */
349 	if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
350 		(void) smb_oplock_wait_break(sr, ofile->f_node, 0);
351 	}
352 }
353