2 * SMB2 version specific operations
4 * Copyright (c) 2012, Jeff Layton <jlayton@redhat.com>
6 * This library is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License v2 as published
8 * by the Free Software Foundation.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
13 * the GNU Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "smb2proto.h"
23 #include "cifsproto.h"
24 #include "cifs_debug.h"
27 change_conf(struct TCP_Server_Info
*server
)
29 server
->credits
+= server
->echo_credits
+ server
->oplock_credits
;
30 server
->oplock_credits
= server
->echo_credits
= 0;
31 switch (server
->credits
) {
35 server
->echoes
= false;
36 server
->oplocks
= false;
37 cERROR(1, "disabling echoes and oplocks");
40 server
->echoes
= true;
41 server
->oplocks
= false;
42 server
->echo_credits
= 1;
43 cFYI(1, "disabling oplocks");
46 server
->echoes
= true;
47 server
->oplocks
= true;
48 server
->echo_credits
= 1;
49 server
->oplock_credits
= 1;
51 server
->credits
-= server
->echo_credits
+ server
->oplock_credits
;
56 smb2_add_credits(struct TCP_Server_Info
*server
, const unsigned int add
,
60 spin_lock(&server
->req_lock
);
61 val
= server
->ops
->get_credits_field(server
, optype
);
64 if (server
->in_flight
== 0 && (optype
& CIFS_OP_MASK
) != CIFS_NEG_OP
)
65 rc
= change_conf(server
);
66 spin_unlock(&server
->req_lock
);
67 wake_up(&server
->request_q
);
69 cifs_reconnect(server
);
73 smb2_set_credits(struct TCP_Server_Info
*server
, const int val
)
75 spin_lock(&server
->req_lock
);
76 server
->credits
= val
;
77 spin_unlock(&server
->req_lock
);
81 smb2_get_credits_field(struct TCP_Server_Info
*server
, const int optype
)
85 return &server
->echo_credits
;
87 return &server
->oplock_credits
;
89 return &server
->credits
;
94 smb2_get_credits(struct mid_q_entry
*mid
)
96 return le16_to_cpu(((struct smb2_hdr
*)mid
->resp_buf
)->CreditRequest
);
100 smb2_get_next_mid(struct TCP_Server_Info
*server
)
103 /* for SMB2 we need the current value */
104 spin_lock(&GlobalMid_Lock
);
105 mid
= server
->CurrentMid
++;
106 spin_unlock(&GlobalMid_Lock
);
110 static struct mid_q_entry
*
111 smb2_find_mid(struct TCP_Server_Info
*server
, char *buf
)
113 struct mid_q_entry
*mid
;
114 struct smb2_hdr
*hdr
= (struct smb2_hdr
*)buf
;
116 spin_lock(&GlobalMid_Lock
);
117 list_for_each_entry(mid
, &server
->pending_mid_q
, qhead
) {
118 if ((mid
->mid
== hdr
->MessageId
) &&
119 (mid
->mid_state
== MID_REQUEST_SUBMITTED
) &&
120 (mid
->command
== hdr
->Command
)) {
121 spin_unlock(&GlobalMid_Lock
);
125 spin_unlock(&GlobalMid_Lock
);
130 smb2_dump_detail(void *buf
)
132 #ifdef CONFIG_CIFS_DEBUG2
133 struct smb2_hdr
*smb
= (struct smb2_hdr
*)buf
;
135 cERROR(1, "Cmd: %d Err: 0x%x Flags: 0x%x Mid: %llu Pid: %d",
136 smb
->Command
, smb
->Status
, smb
->Flags
, smb
->MessageId
,
138 cERROR(1, "smb buf %p len %u", smb
, smb2_calc_size(smb
));
143 smb2_need_neg(struct TCP_Server_Info
*server
)
145 return server
->max_read
== 0;
149 smb2_negotiate(const unsigned int xid
, struct cifs_ses
*ses
)
152 ses
->server
->CurrentMid
= 0;
153 rc
= SMB2_negotiate(xid
, ses
);
154 /* BB we probably don't need to retry with modern servers */
161 smb2_is_path_accessible(const unsigned int xid
, struct cifs_tcon
*tcon
,
162 struct cifs_sb_info
*cifs_sb
, const char *full_path
)
165 __u64 persistent_fid
, volatile_fid
;
168 utf16_path
= cifs_convert_path_to_utf16(full_path
, cifs_sb
);
172 rc
= SMB2_open(xid
, tcon
, utf16_path
, &persistent_fid
, &volatile_fid
,
173 FILE_READ_ATTRIBUTES
, FILE_OPEN
, 0, 0);
179 rc
= SMB2_close(xid
, tcon
, persistent_fid
, volatile_fid
);
185 smb2_get_srv_inum(const unsigned int xid
, struct cifs_tcon
*tcon
,
186 struct cifs_sb_info
*cifs_sb
, const char *full_path
,
187 u64
*uniqueid
, FILE_ALL_INFO
*data
)
189 *uniqueid
= le64_to_cpu(data
->IndexNumber
);
194 smb2_build_path_to_root(struct smb_vol
*vol
, struct cifs_sb_info
*cifs_sb
,
195 struct cifs_tcon
*tcon
)
197 int pplen
= vol
->prepath
? strlen(vol
->prepath
) : 0;
198 char *full_path
= NULL
;
200 /* if no prefix path, simply set path to the root of share to "" */
202 full_path
= kzalloc(2, GFP_KERNEL
);
206 cERROR(1, "prefixpath is not supported for SMB2 now");
211 smb2_can_echo(struct TCP_Server_Info
*server
)
213 return server
->echoes
;
217 smb2_clear_stats(struct cifs_tcon
*tcon
)
219 #ifdef CONFIG_CIFS_STATS
221 for (i
= 0; i
< NUMBER_OF_SMB2_COMMANDS
; i
++) {
222 atomic_set(&tcon
->stats
.smb2_stats
.smb2_com_sent
[i
], 0);
223 atomic_set(&tcon
->stats
.smb2_stats
.smb2_com_failed
[i
], 0);
229 smb2_print_stats(struct seq_file
*m
, struct cifs_tcon
*tcon
)
231 #ifdef CONFIG_CIFS_STATS
232 atomic_t
*sent
= tcon
->stats
.smb2_stats
.smb2_com_sent
;
233 atomic_t
*failed
= tcon
->stats
.smb2_stats
.smb2_com_failed
;
234 seq_printf(m
, "\nNegotiates: %d sent %d failed",
235 atomic_read(&sent
[SMB2_NEGOTIATE_HE
]),
236 atomic_read(&failed
[SMB2_NEGOTIATE_HE
]));
237 seq_printf(m
, "\nSessionSetups: %d sent %d failed",
238 atomic_read(&sent
[SMB2_SESSION_SETUP_HE
]),
239 atomic_read(&failed
[SMB2_SESSION_SETUP_HE
]));
240 #define SMB2LOGOFF 0x0002 /* trivial request/resp */
241 seq_printf(m
, "\nLogoffs: %d sent %d failed",
242 atomic_read(&sent
[SMB2_LOGOFF_HE
]),
243 atomic_read(&failed
[SMB2_LOGOFF_HE
]));
244 seq_printf(m
, "\nTreeConnects: %d sent %d failed",
245 atomic_read(&sent
[SMB2_TREE_CONNECT_HE
]),
246 atomic_read(&failed
[SMB2_TREE_CONNECT_HE
]));
247 seq_printf(m
, "\nTreeDisconnects: %d sent %d failed",
248 atomic_read(&sent
[SMB2_TREE_DISCONNECT_HE
]),
249 atomic_read(&failed
[SMB2_TREE_DISCONNECT_HE
]));
250 seq_printf(m
, "\nCreates: %d sent %d failed",
251 atomic_read(&sent
[SMB2_CREATE_HE
]),
252 atomic_read(&failed
[SMB2_CREATE_HE
]));
253 seq_printf(m
, "\nCloses: %d sent %d failed",
254 atomic_read(&sent
[SMB2_CLOSE_HE
]),
255 atomic_read(&failed
[SMB2_CLOSE_HE
]));
256 seq_printf(m
, "\nFlushes: %d sent %d failed",
257 atomic_read(&sent
[SMB2_FLUSH_HE
]),
258 atomic_read(&failed
[SMB2_FLUSH_HE
]));
259 seq_printf(m
, "\nReads: %d sent %d failed",
260 atomic_read(&sent
[SMB2_READ_HE
]),
261 atomic_read(&failed
[SMB2_READ_HE
]));
262 seq_printf(m
, "\nWrites: %d sent %d failed",
263 atomic_read(&sent
[SMB2_WRITE_HE
]),
264 atomic_read(&failed
[SMB2_WRITE_HE
]));
265 seq_printf(m
, "\nLocks: %d sent %d failed",
266 atomic_read(&sent
[SMB2_LOCK_HE
]),
267 atomic_read(&failed
[SMB2_LOCK_HE
]));
268 seq_printf(m
, "\nIOCTLs: %d sent %d failed",
269 atomic_read(&sent
[SMB2_IOCTL_HE
]),
270 atomic_read(&failed
[SMB2_IOCTL_HE
]));
271 seq_printf(m
, "\nCancels: %d sent %d failed",
272 atomic_read(&sent
[SMB2_CANCEL_HE
]),
273 atomic_read(&failed
[SMB2_CANCEL_HE
]));
274 seq_printf(m
, "\nEchos: %d sent %d failed",
275 atomic_read(&sent
[SMB2_ECHO_HE
]),
276 atomic_read(&failed
[SMB2_ECHO_HE
]));
277 seq_printf(m
, "\nQueryDirectories: %d sent %d failed",
278 atomic_read(&sent
[SMB2_QUERY_DIRECTORY_HE
]),
279 atomic_read(&failed
[SMB2_QUERY_DIRECTORY_HE
]));
280 seq_printf(m
, "\nChangeNotifies: %d sent %d failed",
281 atomic_read(&sent
[SMB2_CHANGE_NOTIFY_HE
]),
282 atomic_read(&failed
[SMB2_CHANGE_NOTIFY_HE
]));
283 seq_printf(m
, "\nQueryInfos: %d sent %d failed",
284 atomic_read(&sent
[SMB2_QUERY_INFO_HE
]),
285 atomic_read(&failed
[SMB2_QUERY_INFO_HE
]));
286 seq_printf(m
, "\nSetInfos: %d sent %d failed",
287 atomic_read(&sent
[SMB2_SET_INFO_HE
]),
288 atomic_read(&failed
[SMB2_SET_INFO_HE
]));
289 seq_printf(m
, "\nOplockBreaks: %d sent %d failed",
290 atomic_read(&sent
[SMB2_OPLOCK_BREAK_HE
]),
291 atomic_read(&failed
[SMB2_OPLOCK_BREAK_HE
]));
295 struct smb_version_operations smb21_operations
= {
296 .setup_request
= smb2_setup_request
,
297 .setup_async_request
= smb2_setup_async_request
,
298 .check_receive
= smb2_check_receive
,
299 .add_credits
= smb2_add_credits
,
300 .set_credits
= smb2_set_credits
,
301 .get_credits_field
= smb2_get_credits_field
,
302 .get_credits
= smb2_get_credits
,
303 .get_next_mid
= smb2_get_next_mid
,
304 .find_mid
= smb2_find_mid
,
305 .check_message
= smb2_check_message
,
306 .dump_detail
= smb2_dump_detail
,
307 .clear_stats
= smb2_clear_stats
,
308 .print_stats
= smb2_print_stats
,
309 .need_neg
= smb2_need_neg
,
310 .negotiate
= smb2_negotiate
,
311 .sess_setup
= SMB2_sess_setup
,
312 .logoff
= SMB2_logoff
,
313 .tree_connect
= SMB2_tcon
,
314 .tree_disconnect
= SMB2_tdis
,
315 .is_path_accessible
= smb2_is_path_accessible
,
316 .can_echo
= smb2_can_echo
,
318 .query_path_info
= smb2_query_path_info
,
319 .get_srv_inum
= smb2_get_srv_inum
,
320 .build_path_to_root
= smb2_build_path_to_root
,
322 .mkdir_setinfo
= smb2_mkdir_setinfo
,
326 struct smb_version_values smb21_values
= {
327 .version_string
= SMB21_VERSION_STRING
,
328 .header_size
= sizeof(struct smb2_hdr
),
329 .max_header_size
= MAX_SMB2_HDR_SIZE
,
330 .lock_cmd
= SMB2_LOCK
,
332 .cap_nt_find
= SMB2_NT_FIND
,
333 .cap_large_files
= SMB2_LARGE_FILES
,