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
20 #include <linux/pagemap.h>
23 #include "smb2proto.h"
24 #include "cifsproto.h"
25 #include "cifs_debug.h"
28 change_conf(struct TCP_Server_Info
*server
)
30 server
->credits
+= server
->echo_credits
+ server
->oplock_credits
;
31 server
->oplock_credits
= server
->echo_credits
= 0;
32 switch (server
->credits
) {
36 server
->echoes
= false;
37 server
->oplocks
= false;
38 cERROR(1, "disabling echoes and oplocks");
41 server
->echoes
= true;
42 server
->oplocks
= false;
43 server
->echo_credits
= 1;
44 cFYI(1, "disabling oplocks");
47 server
->echoes
= true;
48 server
->oplocks
= true;
49 server
->echo_credits
= 1;
50 server
->oplock_credits
= 1;
52 server
->credits
-= server
->echo_credits
+ server
->oplock_credits
;
57 smb2_add_credits(struct TCP_Server_Info
*server
, const unsigned int add
,
61 spin_lock(&server
->req_lock
);
62 val
= server
->ops
->get_credits_field(server
, optype
);
65 if (server
->in_flight
== 0 && (optype
& CIFS_OP_MASK
) != CIFS_NEG_OP
)
66 rc
= change_conf(server
);
67 spin_unlock(&server
->req_lock
);
68 wake_up(&server
->request_q
);
70 cifs_reconnect(server
);
74 smb2_set_credits(struct TCP_Server_Info
*server
, const int val
)
76 spin_lock(&server
->req_lock
);
77 server
->credits
= val
;
78 spin_unlock(&server
->req_lock
);
82 smb2_get_credits_field(struct TCP_Server_Info
*server
, const int optype
)
86 return &server
->echo_credits
;
88 return &server
->oplock_credits
;
90 return &server
->credits
;
95 smb2_get_credits(struct mid_q_entry
*mid
)
97 return le16_to_cpu(((struct smb2_hdr
*)mid
->resp_buf
)->CreditRequest
);
101 smb2_get_next_mid(struct TCP_Server_Info
*server
)
104 /* for SMB2 we need the current value */
105 spin_lock(&GlobalMid_Lock
);
106 mid
= server
->CurrentMid
++;
107 spin_unlock(&GlobalMid_Lock
);
111 static struct mid_q_entry
*
112 smb2_find_mid(struct TCP_Server_Info
*server
, char *buf
)
114 struct mid_q_entry
*mid
;
115 struct smb2_hdr
*hdr
= (struct smb2_hdr
*)buf
;
117 spin_lock(&GlobalMid_Lock
);
118 list_for_each_entry(mid
, &server
->pending_mid_q
, qhead
) {
119 if ((mid
->mid
== hdr
->MessageId
) &&
120 (mid
->mid_state
== MID_REQUEST_SUBMITTED
) &&
121 (mid
->command
== hdr
->Command
)) {
122 spin_unlock(&GlobalMid_Lock
);
126 spin_unlock(&GlobalMid_Lock
);
131 smb2_dump_detail(void *buf
)
133 #ifdef CONFIG_CIFS_DEBUG2
134 struct smb2_hdr
*smb
= (struct smb2_hdr
*)buf
;
136 cERROR(1, "Cmd: %d Err: 0x%x Flags: 0x%x Mid: %llu Pid: %d",
137 smb
->Command
, smb
->Status
, smb
->Flags
, smb
->MessageId
,
139 cERROR(1, "smb buf %p len %u", smb
, smb2_calc_size(smb
));
144 smb2_need_neg(struct TCP_Server_Info
*server
)
146 return server
->max_read
== 0;
150 smb2_negotiate(const unsigned int xid
, struct cifs_ses
*ses
)
153 ses
->server
->CurrentMid
= 0;
154 rc
= SMB2_negotiate(xid
, ses
);
155 /* BB we probably don't need to retry with modern servers */
162 smb2_negotiate_wsize(struct cifs_tcon
*tcon
, struct smb_vol
*volume_info
)
164 struct TCP_Server_Info
*server
= tcon
->ses
->server
;
167 /* start with specified wsize, or default */
168 wsize
= volume_info
->wsize
? volume_info
->wsize
: CIFS_DEFAULT_IOSIZE
;
169 wsize
= min_t(unsigned int, wsize
, server
->max_write
);
171 * limit write size to 2 ** 16, because we don't support multicredit
174 wsize
= min_t(unsigned int, wsize
, 2 << 15);
176 /* limit to the amount that we can kmap at once */
177 wsize
= min_t(unsigned int, wsize
, CIFS_KMAP_SIZE_LIMIT
);
183 smb2_negotiate_rsize(struct cifs_tcon
*tcon
, struct smb_vol
*volume_info
)
185 struct TCP_Server_Info
*server
= tcon
->ses
->server
;
188 /* start with specified rsize, or default */
189 rsize
= volume_info
->rsize
? volume_info
->rsize
: CIFS_DEFAULT_IOSIZE
;
190 rsize
= min_t(unsigned int, rsize
, server
->max_read
);
192 * limit write size to 2 ** 16, because we don't support multicredit
195 rsize
= min_t(unsigned int, rsize
, 2 << 15);
197 /* limit to the amount that we can kmap at once */
198 rsize
= min_t(unsigned int, rsize
, CIFS_KMAP_SIZE_LIMIT
);
204 smb2_is_path_accessible(const unsigned int xid
, struct cifs_tcon
*tcon
,
205 struct cifs_sb_info
*cifs_sb
, const char *full_path
)
208 __u64 persistent_fid
, volatile_fid
;
211 utf16_path
= cifs_convert_path_to_utf16(full_path
, cifs_sb
);
215 rc
= SMB2_open(xid
, tcon
, utf16_path
, &persistent_fid
, &volatile_fid
,
216 FILE_READ_ATTRIBUTES
, FILE_OPEN
, 0, 0, NULL
);
222 rc
= SMB2_close(xid
, tcon
, persistent_fid
, volatile_fid
);
228 smb2_get_srv_inum(const unsigned int xid
, struct cifs_tcon
*tcon
,
229 struct cifs_sb_info
*cifs_sb
, const char *full_path
,
230 u64
*uniqueid
, FILE_ALL_INFO
*data
)
232 *uniqueid
= le64_to_cpu(data
->IndexNumber
);
237 smb2_query_file_info(const unsigned int xid
, struct cifs_tcon
*tcon
,
238 struct cifs_fid
*fid
, FILE_ALL_INFO
*data
)
241 struct smb2_file_all_info
*smb2_data
;
243 smb2_data
= kzalloc(sizeof(struct smb2_file_all_info
) + MAX_NAME
* 2,
245 if (smb2_data
== NULL
)
248 rc
= SMB2_query_info(xid
, tcon
, fid
->persistent_fid
, fid
->volatile_fid
,
251 move_smb2_info_to_cifs(data
, smb2_data
);
257 smb2_build_path_to_root(struct smb_vol
*vol
, struct cifs_sb_info
*cifs_sb
,
258 struct cifs_tcon
*tcon
)
260 int pplen
= vol
->prepath
? strlen(vol
->prepath
) : 0;
261 char *full_path
= NULL
;
263 /* if no prefix path, simply set path to the root of share to "" */
265 full_path
= kzalloc(2, GFP_KERNEL
);
269 cERROR(1, "prefixpath is not supported for SMB2 now");
274 smb2_can_echo(struct TCP_Server_Info
*server
)
276 return server
->echoes
;
280 smb2_clear_stats(struct cifs_tcon
*tcon
)
282 #ifdef CONFIG_CIFS_STATS
284 for (i
= 0; i
< NUMBER_OF_SMB2_COMMANDS
; i
++) {
285 atomic_set(&tcon
->stats
.smb2_stats
.smb2_com_sent
[i
], 0);
286 atomic_set(&tcon
->stats
.smb2_stats
.smb2_com_failed
[i
], 0);
292 smb2_print_stats(struct seq_file
*m
, struct cifs_tcon
*tcon
)
294 #ifdef CONFIG_CIFS_STATS
295 atomic_t
*sent
= tcon
->stats
.smb2_stats
.smb2_com_sent
;
296 atomic_t
*failed
= tcon
->stats
.smb2_stats
.smb2_com_failed
;
297 seq_printf(m
, "\nNegotiates: %d sent %d failed",
298 atomic_read(&sent
[SMB2_NEGOTIATE_HE
]),
299 atomic_read(&failed
[SMB2_NEGOTIATE_HE
]));
300 seq_printf(m
, "\nSessionSetups: %d sent %d failed",
301 atomic_read(&sent
[SMB2_SESSION_SETUP_HE
]),
302 atomic_read(&failed
[SMB2_SESSION_SETUP_HE
]));
303 #define SMB2LOGOFF 0x0002 /* trivial request/resp */
304 seq_printf(m
, "\nLogoffs: %d sent %d failed",
305 atomic_read(&sent
[SMB2_LOGOFF_HE
]),
306 atomic_read(&failed
[SMB2_LOGOFF_HE
]));
307 seq_printf(m
, "\nTreeConnects: %d sent %d failed",
308 atomic_read(&sent
[SMB2_TREE_CONNECT_HE
]),
309 atomic_read(&failed
[SMB2_TREE_CONNECT_HE
]));
310 seq_printf(m
, "\nTreeDisconnects: %d sent %d failed",
311 atomic_read(&sent
[SMB2_TREE_DISCONNECT_HE
]),
312 atomic_read(&failed
[SMB2_TREE_DISCONNECT_HE
]));
313 seq_printf(m
, "\nCreates: %d sent %d failed",
314 atomic_read(&sent
[SMB2_CREATE_HE
]),
315 atomic_read(&failed
[SMB2_CREATE_HE
]));
316 seq_printf(m
, "\nCloses: %d sent %d failed",
317 atomic_read(&sent
[SMB2_CLOSE_HE
]),
318 atomic_read(&failed
[SMB2_CLOSE_HE
]));
319 seq_printf(m
, "\nFlushes: %d sent %d failed",
320 atomic_read(&sent
[SMB2_FLUSH_HE
]),
321 atomic_read(&failed
[SMB2_FLUSH_HE
]));
322 seq_printf(m
, "\nReads: %d sent %d failed",
323 atomic_read(&sent
[SMB2_READ_HE
]),
324 atomic_read(&failed
[SMB2_READ_HE
]));
325 seq_printf(m
, "\nWrites: %d sent %d failed",
326 atomic_read(&sent
[SMB2_WRITE_HE
]),
327 atomic_read(&failed
[SMB2_WRITE_HE
]));
328 seq_printf(m
, "\nLocks: %d sent %d failed",
329 atomic_read(&sent
[SMB2_LOCK_HE
]),
330 atomic_read(&failed
[SMB2_LOCK_HE
]));
331 seq_printf(m
, "\nIOCTLs: %d sent %d failed",
332 atomic_read(&sent
[SMB2_IOCTL_HE
]),
333 atomic_read(&failed
[SMB2_IOCTL_HE
]));
334 seq_printf(m
, "\nCancels: %d sent %d failed",
335 atomic_read(&sent
[SMB2_CANCEL_HE
]),
336 atomic_read(&failed
[SMB2_CANCEL_HE
]));
337 seq_printf(m
, "\nEchos: %d sent %d failed",
338 atomic_read(&sent
[SMB2_ECHO_HE
]),
339 atomic_read(&failed
[SMB2_ECHO_HE
]));
340 seq_printf(m
, "\nQueryDirectories: %d sent %d failed",
341 atomic_read(&sent
[SMB2_QUERY_DIRECTORY_HE
]),
342 atomic_read(&failed
[SMB2_QUERY_DIRECTORY_HE
]));
343 seq_printf(m
, "\nChangeNotifies: %d sent %d failed",
344 atomic_read(&sent
[SMB2_CHANGE_NOTIFY_HE
]),
345 atomic_read(&failed
[SMB2_CHANGE_NOTIFY_HE
]));
346 seq_printf(m
, "\nQueryInfos: %d sent %d failed",
347 atomic_read(&sent
[SMB2_QUERY_INFO_HE
]),
348 atomic_read(&failed
[SMB2_QUERY_INFO_HE
]));
349 seq_printf(m
, "\nSetInfos: %d sent %d failed",
350 atomic_read(&sent
[SMB2_SET_INFO_HE
]),
351 atomic_read(&failed
[SMB2_SET_INFO_HE
]));
352 seq_printf(m
, "\nOplockBreaks: %d sent %d failed",
353 atomic_read(&sent
[SMB2_OPLOCK_BREAK_HE
]),
354 atomic_read(&failed
[SMB2_OPLOCK_BREAK_HE
]));
359 smb2_set_fid(struct cifsFileInfo
*cfile
, struct cifs_fid
*fid
, __u32 oplock
)
361 /* struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); */
362 cfile
->fid
.persistent_fid
= fid
->persistent_fid
;
363 cfile
->fid
.volatile_fid
= fid
->volatile_fid
;
364 /* cifs_set_oplock_level(cinode, oplock); */
365 /* cinode->can_cache_brlcks = cinode->clientCanCacheAll; */
369 smb2_close_file(const unsigned int xid
, struct cifs_tcon
*tcon
,
370 struct cifs_fid
*fid
)
372 return SMB2_close(xid
, tcon
, fid
->persistent_fid
, fid
->volatile_fid
);
376 smb2_flush_file(const unsigned int xid
, struct cifs_tcon
*tcon
,
377 struct cifs_fid
*fid
)
379 return SMB2_flush(xid
, tcon
, fid
->persistent_fid
, fid
->volatile_fid
);
382 struct smb_version_operations smb21_operations
= {
383 .setup_request
= smb2_setup_request
,
384 .setup_async_request
= smb2_setup_async_request
,
385 .check_receive
= smb2_check_receive
,
386 .add_credits
= smb2_add_credits
,
387 .set_credits
= smb2_set_credits
,
388 .get_credits_field
= smb2_get_credits_field
,
389 .get_credits
= smb2_get_credits
,
390 .get_next_mid
= smb2_get_next_mid
,
391 .find_mid
= smb2_find_mid
,
392 .check_message
= smb2_check_message
,
393 .dump_detail
= smb2_dump_detail
,
394 .clear_stats
= smb2_clear_stats
,
395 .print_stats
= smb2_print_stats
,
396 .need_neg
= smb2_need_neg
,
397 .negotiate
= smb2_negotiate
,
398 .negotiate_wsize
= smb2_negotiate_wsize
,
399 .negotiate_rsize
= smb2_negotiate_rsize
,
400 .sess_setup
= SMB2_sess_setup
,
401 .logoff
= SMB2_logoff
,
402 .tree_connect
= SMB2_tcon
,
403 .tree_disconnect
= SMB2_tdis
,
404 .is_path_accessible
= smb2_is_path_accessible
,
405 .can_echo
= smb2_can_echo
,
407 .query_path_info
= smb2_query_path_info
,
408 .get_srv_inum
= smb2_get_srv_inum
,
409 .query_file_info
= smb2_query_file_info
,
410 .build_path_to_root
= smb2_build_path_to_root
,
412 .mkdir_setinfo
= smb2_mkdir_setinfo
,
414 .unlink
= smb2_unlink
,
415 .open
= smb2_open_file
,
416 .set_fid
= smb2_set_fid
,
417 .close
= smb2_close_file
,
418 .flush
= smb2_flush_file
,
421 struct smb_version_values smb21_values
= {
422 .version_string
= SMB21_VERSION_STRING
,
423 .header_size
= sizeof(struct smb2_hdr
),
424 .max_header_size
= MAX_SMB2_HDR_SIZE
,
425 .lock_cmd
= SMB2_LOCK
,
427 .cap_nt_find
= SMB2_NT_FIND
,
428 .cap_large_files
= SMB2_LARGE_FILES
,