xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_oplock.c (revision b8052df9f609edb713f6828c9eecc3d7be19dfb3)
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  */
25 
26 /*
27  * smb1 oplock support
28  */
29 
30 #include <smbsrv/smb_kproto.h>
31 
32 #define	BATCH_OR_EXCL	(OPLOCK_LEVEL_BATCH | OPLOCK_LEVEL_ONE)
33 
34 /*
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.
38  */
39 void
40 smb1_oplock_acquire(smb_request_t *sr, boolean_t level2ok)
41 {
42 	smb_arg_open_t *op = &sr->arg.open;
43 	smb_ofile_t *ofile = sr->fid_ofile;
44 	uint32_t status;
45 
46 	/* Only disk trees get oplocks. */
47 	if ((sr->tid_tree->t_res_type & STYPE_MASK) != STYPE_DISKTREE) {
48 		op->op_oplock_level = SMB_OPLOCK_NONE;
49 		return;
50 	}
51 
52 	if (!smb_tree_has_feature(sr->tid_tree, SMB_TREE_OPLOCKS)) {
53 		op->op_oplock_level = SMB_OPLOCK_NONE;
54 		return;
55 	}
56 
57 	if (!smb_session_levelII_oplocks(sr->session))
58 		level2ok = B_FALSE;
59 
60 	/* Common code checks file type. */
61 
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;
68 		break;
69 	case SMB_OPLOCK_EXCLUSIVE:
70 		op->op_oplock_state = OPLOCK_LEVEL_ONE;
71 		break;
72 	case SMB_OPLOCK_LEVEL_II:
73 		op->op_oplock_state = OPLOCK_LEVEL_TWO;
74 		break;
75 	case SMB_OPLOCK_NONE:
76 	default:
77 		op->op_oplock_level = SMB_OPLOCK_NONE;
78 		return;
79 	}
80 
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;
86 	}
87 
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);
94 	} else {
95 		status = NT_STATUS_OPLOCK_NOT_GRANTED;
96 	}
97 
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);
106 	}
107 
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(sr, ofile->f_node, 0);
114 		status = 0;
115 	}
116 
117 	/*
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.
125 	 */
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;
135 		return;
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;
142 		return;
143 	}
144 
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;
157 	}
158 }
159