2011-02-24 21:07:19 +03:00
/*
* SMB2 version specific operations
*
* Copyright ( c ) 2012 , Jeff Layton < jlayton @ redhat . com >
*
* This library is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License v2 as published
* by the Free Software Foundation .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See
* the GNU Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
2012-09-19 03:20:28 +04:00
# include <linux/pagemap.h>
2012-09-19 03:20:34 +04:00
# include <linux/vfs.h>
2011-02-24 21:07:19 +03:00
# include "cifsglob.h"
2011-12-26 22:53:34 +04:00
# include "smb2pdu.h"
# include "smb2proto.h"
2012-05-23 16:18:00 +04:00
# include "cifsproto.h"
# include "cifs_debug.h"
2013-08-14 19:25:21 +04:00
# include "cifs_unicode.h"
2012-09-19 03:20:33 +04:00
# include "smb2status.h"
2012-09-19 03:20:34 +04:00
# include "smb2glob.h"
2012-05-23 16:18:00 +04:00
static int
change_conf ( struct TCP_Server_Info * server )
{
server - > credits + = server - > echo_credits + server - > oplock_credits ;
server - > oplock_credits = server - > echo_credits = 0 ;
switch ( server - > credits ) {
case 0 :
return - 1 ;
case 1 :
server - > echoes = false ;
server - > oplocks = false ;
2013-05-05 07:12:25 +04:00
cifs_dbg ( VFS , " disabling echoes and oplocks \n " ) ;
2012-05-23 16:18:00 +04:00
break ;
case 2 :
server - > echoes = true ;
server - > oplocks = false ;
server - > echo_credits = 1 ;
2013-05-05 07:12:25 +04:00
cifs_dbg ( FYI , " disabling oplocks \n " ) ;
2012-05-23 16:18:00 +04:00
break ;
default :
server - > echoes = true ;
server - > oplocks = true ;
server - > echo_credits = 1 ;
server - > oplock_credits = 1 ;
}
server - > credits - = server - > echo_credits + server - > oplock_credits ;
return 0 ;
}
static void
smb2_add_credits ( struct TCP_Server_Info * server , const unsigned int add ,
const int optype )
{
int * val , rc = 0 ;
spin_lock ( & server - > req_lock ) ;
val = server - > ops - > get_credits_field ( server , optype ) ;
* val + = add ;
server - > in_flight - - ;
2011-12-27 16:12:43 +04:00
if ( server - > in_flight = = 0 & & ( optype & CIFS_OP_MASK ) ! = CIFS_NEG_OP )
2012-05-23 16:18:00 +04:00
rc = change_conf ( server ) ;
2012-09-19 03:20:33 +04:00
/*
* Sometimes server returns 0 credits on oplock break ack - we need to
* rebalance credits in this case .
*/
else if ( server - > in_flight > 0 & & server - > oplock_credits = = 0 & &
server - > oplocks ) {
if ( server - > credits > 1 ) {
server - > credits - - ;
server - > oplock_credits + + ;
}
}
2012-05-23 16:18:00 +04:00
spin_unlock ( & server - > req_lock ) ;
wake_up ( & server - > request_q ) ;
if ( rc )
cifs_reconnect ( server ) ;
}
static void
smb2_set_credits ( struct TCP_Server_Info * server , const int val )
{
spin_lock ( & server - > req_lock ) ;
server - > credits = val ;
spin_unlock ( & server - > req_lock ) ;
}
static int *
smb2_get_credits_field ( struct TCP_Server_Info * server , const int optype )
{
switch ( optype ) {
case CIFS_ECHO_OP :
return & server - > echo_credits ;
case CIFS_OBREAK_OP :
return & server - > oplock_credits ;
default :
return & server - > credits ;
}
}
static unsigned int
smb2_get_credits ( struct mid_q_entry * mid )
{
return le16_to_cpu ( ( ( struct smb2_hdr * ) mid - > resp_buf ) - > CreditRequest ) ;
}
2011-12-26 22:53:34 +04:00
static __u64
smb2_get_next_mid ( struct TCP_Server_Info * server )
{
__u64 mid ;
/* for SMB2 we need the current value */
spin_lock ( & GlobalMid_Lock ) ;
mid = server - > CurrentMid + + ;
spin_unlock ( & GlobalMid_Lock ) ;
return mid ;
}
2011-02-24 21:07:19 +03:00
2011-06-08 15:51:07 +04:00
static struct mid_q_entry *
smb2_find_mid ( struct TCP_Server_Info * server , char * buf )
{
struct mid_q_entry * mid ;
struct smb2_hdr * hdr = ( struct smb2_hdr * ) buf ;
spin_lock ( & GlobalMid_Lock ) ;
list_for_each_entry ( mid , & server - > pending_mid_q , qhead ) {
if ( ( mid - > mid = = hdr - > MessageId ) & &
( mid - > mid_state = = MID_REQUEST_SUBMITTED ) & &
( mid - > command = = hdr - > Command ) ) {
spin_unlock ( & GlobalMid_Lock ) ;
return mid ;
}
}
spin_unlock ( & GlobalMid_Lock ) ;
return NULL ;
}
static void
smb2_dump_detail ( void * buf )
{
# ifdef CONFIG_CIFS_DEBUG2
struct smb2_hdr * smb = ( struct smb2_hdr * ) buf ;
2013-05-05 07:12:25 +04:00
cifs_dbg ( VFS , " Cmd: %d Err: 0x%x Flags: 0x%x Mid: %llu Pid: %d \n " ,
smb - > Command , smb - > Status , smb - > Flags , smb - > MessageId ,
smb - > ProcessId ) ;
cifs_dbg ( VFS , " smb buf %p len %u \n " , smb , smb2_calc_size ( smb ) ) ;
2011-06-08 15:51:07 +04:00
# endif
}
2011-12-27 16:12:43 +04:00
static bool
smb2_need_neg ( struct TCP_Server_Info * server )
{
return server - > max_read = = 0 ;
}
static int
smb2_negotiate ( const unsigned int xid , struct cifs_ses * ses )
{
int rc ;
ses - > server - > CurrentMid = 0 ;
rc = SMB2_negotiate ( xid , ses ) ;
/* BB we probably don't need to retry with modern servers */
if ( rc = = - EAGAIN )
rc = - EHOSTDOWN ;
return rc ;
}
2012-09-19 03:20:28 +04:00
static unsigned int
smb2_negotiate_wsize ( struct cifs_tcon * tcon , struct smb_vol * volume_info )
{
struct TCP_Server_Info * server = tcon - > ses - > server ;
unsigned int wsize ;
/* start with specified wsize, or default */
wsize = volume_info - > wsize ? volume_info - > wsize : CIFS_DEFAULT_IOSIZE ;
wsize = min_t ( unsigned int , wsize , server - > max_write ) ;
/*
* limit write size to 2 * * 16 , because we don ' t support multicredit
* requests now .
*/
wsize = min_t ( unsigned int , wsize , 2 < < 15 ) ;
return wsize ;
}
static unsigned int
smb2_negotiate_rsize ( struct cifs_tcon * tcon , struct smb_vol * volume_info )
{
struct TCP_Server_Info * server = tcon - > ses - > server ;
unsigned int rsize ;
/* start with specified rsize, or default */
rsize = volume_info - > rsize ? volume_info - > rsize : CIFS_DEFAULT_IOSIZE ;
rsize = min_t ( unsigned int , rsize , server - > max_read ) ;
/*
* limit write size to 2 * * 16 , because we don ' t support multicredit
* requests now .
*/
rsize = min_t ( unsigned int , rsize , 2 < < 15 ) ;
return rsize ;
}
2013-10-14 10:21:53 +04:00
# ifdef CONFIG_CIFS_STATS2
static int
SMB3_request_interfaces ( const unsigned int xid , struct cifs_tcon * tcon )
{
int rc ;
unsigned int ret_data_len = 0 ;
struct network_interface_info_ioctl_rsp * out_buf ;
rc = SMB2_ioctl ( xid , tcon , NO_FILE_ID , NO_FILE_ID ,
FSCTL_QUERY_NETWORK_INTERFACE_INFO , true /* is_fsctl */ ,
NULL /* no data input */ , 0 /* no data input */ ,
( char * * ) & out_buf , & ret_data_len ) ;
if ( ( rc = = 0 ) & & ( ret_data_len > 0 ) ) {
/* Dump info on first interface */
cifs_dbg ( FYI , " Adapter Capability 0x%x \t " ,
le32_to_cpu ( out_buf - > Capability ) ) ;
cifs_dbg ( FYI , " Link Speed %lld \n " ,
le64_to_cpu ( out_buf - > LinkSpeed ) ) ;
} else
cifs_dbg ( VFS , " error %d on ioctl to get interface list \n " , rc ) ;
return rc ;
}
# endif /* STATS2 */
2013-10-10 05:55:53 +04:00
static void
smb3_qfs_tcon ( const unsigned int xid , struct cifs_tcon * tcon )
{
int rc ;
__le16 srch_path = 0 ; /* Null - open root of share */
u8 oplock = SMB2_OPLOCK_LEVEL_NONE ;
struct cifs_open_parms oparms ;
struct cifs_fid fid ;
oparms . tcon = tcon ;
oparms . desired_access = FILE_READ_ATTRIBUTES ;
oparms . disposition = FILE_OPEN ;
oparms . create_options = 0 ;
oparms . fid = & fid ;
oparms . reconnect = false ;
rc = SMB2_open ( xid , & oparms , & srch_path , & oplock , NULL , NULL ) ;
if ( rc )
return ;
2013-10-14 10:21:53 +04:00
# ifdef CONFIG_CIFS_STATS2
SMB3_request_interfaces ( xid , tcon ) ;
# endif /* STATS2 */
2013-10-10 05:55:53 +04:00
SMB2_QFS_attr ( xid , tcon , fid . persistent_fid , fid . volatile_fid ,
FS_ATTRIBUTE_INFORMATION ) ;
SMB2_QFS_attr ( xid , tcon , fid . persistent_fid , fid . volatile_fid ,
FS_DEVICE_INFORMATION ) ;
SMB2_QFS_attr ( xid , tcon , fid . persistent_fid , fid . volatile_fid ,
FS_SECTOR_SIZE_INFORMATION ) ; /* SMB3 specific */
SMB2_close ( xid , tcon , fid . persistent_fid , fid . volatile_fid ) ;
return ;
}
2013-10-09 11:07:00 +04:00
static void
smb2_qfs_tcon ( const unsigned int xid , struct cifs_tcon * tcon )
{
int rc ;
__le16 srch_path = 0 ; /* Null - open root of share */
u8 oplock = SMB2_OPLOCK_LEVEL_NONE ;
struct cifs_open_parms oparms ;
struct cifs_fid fid ;
oparms . tcon = tcon ;
oparms . desired_access = FILE_READ_ATTRIBUTES ;
oparms . disposition = FILE_OPEN ;
oparms . create_options = 0 ;
oparms . fid = & fid ;
oparms . reconnect = false ;
rc = SMB2_open ( xid , & oparms , & srch_path , & oplock , NULL , NULL ) ;
if ( rc )
return ;
2013-10-09 22:36:35 +04:00
SMB2_QFS_attr ( xid , tcon , fid . persistent_fid , fid . volatile_fid ,
FS_ATTRIBUTE_INFORMATION ) ;
SMB2_QFS_attr ( xid , tcon , fid . persistent_fid , fid . volatile_fid ,
FS_DEVICE_INFORMATION ) ;
2013-10-09 11:07:00 +04:00
SMB2_close ( xid , tcon , fid . persistent_fid , fid . volatile_fid ) ;
return ;
}
2011-12-26 22:58:46 +04:00
static int
smb2_is_path_accessible ( const unsigned int xid , struct cifs_tcon * tcon ,
struct cifs_sb_info * cifs_sb , const char * full_path )
{
int rc ;
__le16 * utf16_path ;
2012-09-19 03:20:33 +04:00
__u8 oplock = SMB2_OPLOCK_LEVEL_NONE ;
2013-07-09 18:20:30 +04:00
struct cifs_open_parms oparms ;
struct cifs_fid fid ;
2011-12-26 22:58:46 +04:00
utf16_path = cifs_convert_path_to_utf16 ( full_path , cifs_sb ) ;
if ( ! utf16_path )
return - ENOMEM ;
2013-07-09 18:20:30 +04:00
oparms . tcon = tcon ;
oparms . desired_access = FILE_READ_ATTRIBUTES ;
oparms . disposition = FILE_OPEN ;
oparms . create_options = 0 ;
oparms . fid = & fid ;
2013-07-09 18:40:58 +04:00
oparms . reconnect = false ;
2013-07-09 18:20:30 +04:00
2013-08-14 19:25:21 +04:00
rc = SMB2_open ( xid , & oparms , utf16_path , & oplock , NULL , NULL ) ;
2011-12-26 22:58:46 +04:00
if ( rc ) {
kfree ( utf16_path ) ;
return rc ;
}
2013-07-09 18:20:30 +04:00
rc = SMB2_close ( xid , tcon , fid . persistent_fid , fid . volatile_fid ) ;
2011-12-26 22:58:46 +04:00
kfree ( utf16_path ) ;
return rc ;
}
2011-12-29 17:06:33 +04:00
static int
smb2_get_srv_inum ( const unsigned int xid , struct cifs_tcon * tcon ,
struct cifs_sb_info * cifs_sb , const char * full_path ,
u64 * uniqueid , FILE_ALL_INFO * data )
{
* uniqueid = le64_to_cpu ( data - > IndexNumber ) ;
return 0 ;
}
2012-09-19 03:20:27 +04:00
static int
smb2_query_file_info ( const unsigned int xid , struct cifs_tcon * tcon ,
struct cifs_fid * fid , FILE_ALL_INFO * data )
{
int rc ;
struct smb2_file_all_info * smb2_data ;
smb2_data = kzalloc ( sizeof ( struct smb2_file_all_info ) + MAX_NAME * 2 ,
GFP_KERNEL ) ;
if ( smb2_data = = NULL )
return - ENOMEM ;
rc = SMB2_query_info ( xid , tcon , fid - > persistent_fid , fid - > volatile_fid ,
smb2_data ) ;
if ( ! rc )
move_smb2_info_to_cifs ( data , smb2_data ) ;
kfree ( smb2_data ) ;
return rc ;
}
2012-07-12 18:30:44 +04:00
static bool
smb2_can_echo ( struct TCP_Server_Info * server )
{
return server - > echoes ;
}
2012-05-28 15:19:39 +04:00
static void
smb2_clear_stats ( struct cifs_tcon * tcon )
{
# ifdef CONFIG_CIFS_STATS
int i ;
for ( i = 0 ; i < NUMBER_OF_SMB2_COMMANDS ; i + + ) {
atomic_set ( & tcon - > stats . smb2_stats . smb2_com_sent [ i ] , 0 ) ;
atomic_set ( & tcon - > stats . smb2_stats . smb2_com_failed [ i ] , 0 ) ;
}
# endif
}
2013-06-19 23:15:30 +04:00
static void
smb2_dump_share_caps ( struct seq_file * m , struct cifs_tcon * tcon )
{
seq_puts ( m , " \n \t Share Capabilities: " ) ;
if ( tcon - > capabilities & SMB2_SHARE_CAP_DFS )
seq_puts ( m , " DFS, " ) ;
if ( tcon - > capabilities & SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY )
seq_puts ( m , " CONTINUOUS AVAILABILITY, " ) ;
if ( tcon - > capabilities & SMB2_SHARE_CAP_SCALEOUT )
seq_puts ( m , " SCALEOUT, " ) ;
if ( tcon - > capabilities & SMB2_SHARE_CAP_CLUSTER )
seq_puts ( m , " CLUSTER, " ) ;
if ( tcon - > capabilities & SMB2_SHARE_CAP_ASYMMETRIC )
seq_puts ( m , " ASYMMETRIC, " ) ;
if ( tcon - > capabilities = = 0 )
seq_puts ( m , " None " ) ;
2013-10-10 05:55:53 +04:00
if ( tcon - > ss_flags & SSINFO_FLAGS_ALIGNED_DEVICE )
seq_puts ( m , " Aligned, " ) ;
if ( tcon - > ss_flags & SSINFO_FLAGS_PARTITION_ALIGNED_ON_DEVICE )
seq_puts ( m , " Partition Aligned, " ) ;
if ( tcon - > ss_flags & SSINFO_FLAGS_NO_SEEK_PENALTY )
seq_puts ( m , " SSD, " ) ;
if ( tcon - > ss_flags & SSINFO_FLAGS_TRIM_ENABLED )
seq_puts ( m , " TRIM-support, " ) ;
2013-06-19 23:15:30 +04:00
seq_printf ( m , " \t Share Flags: 0x%x " , tcon - > share_flags ) ;
2013-10-10 05:55:53 +04:00
if ( tcon - > perf_sector_size )
seq_printf ( m , " \t Optimal sector size: 0x%x " ,
tcon - > perf_sector_size ) ;
2013-06-19 23:15:30 +04:00
}
2012-05-28 15:19:39 +04:00
static void
smb2_print_stats ( struct seq_file * m , struct cifs_tcon * tcon )
{
# ifdef CONFIG_CIFS_STATS
atomic_t * sent = tcon - > stats . smb2_stats . smb2_com_sent ;
atomic_t * failed = tcon - > stats . smb2_stats . smb2_com_failed ;
seq_printf ( m , " \n Negotiates: %d sent %d failed " ,
atomic_read ( & sent [ SMB2_NEGOTIATE_HE ] ) ,
atomic_read ( & failed [ SMB2_NEGOTIATE_HE ] ) ) ;
seq_printf ( m , " \n SessionSetups: %d sent %d failed " ,
atomic_read ( & sent [ SMB2_SESSION_SETUP_HE ] ) ,
atomic_read ( & failed [ SMB2_SESSION_SETUP_HE ] ) ) ;
seq_printf ( m , " \n Logoffs: %d sent %d failed " ,
atomic_read ( & sent [ SMB2_LOGOFF_HE ] ) ,
atomic_read ( & failed [ SMB2_LOGOFF_HE ] ) ) ;
seq_printf ( m , " \n TreeConnects: %d sent %d failed " ,
atomic_read ( & sent [ SMB2_TREE_CONNECT_HE ] ) ,
atomic_read ( & failed [ SMB2_TREE_CONNECT_HE ] ) ) ;
seq_printf ( m , " \n TreeDisconnects: %d sent %d failed " ,
atomic_read ( & sent [ SMB2_TREE_DISCONNECT_HE ] ) ,
atomic_read ( & failed [ SMB2_TREE_DISCONNECT_HE ] ) ) ;
seq_printf ( m , " \n Creates: %d sent %d failed " ,
atomic_read ( & sent [ SMB2_CREATE_HE ] ) ,
atomic_read ( & failed [ SMB2_CREATE_HE ] ) ) ;
seq_printf ( m , " \n Closes: %d sent %d failed " ,
atomic_read ( & sent [ SMB2_CLOSE_HE ] ) ,
atomic_read ( & failed [ SMB2_CLOSE_HE ] ) ) ;
seq_printf ( m , " \n Flushes: %d sent %d failed " ,
atomic_read ( & sent [ SMB2_FLUSH_HE ] ) ,
atomic_read ( & failed [ SMB2_FLUSH_HE ] ) ) ;
seq_printf ( m , " \n Reads: %d sent %d failed " ,
atomic_read ( & sent [ SMB2_READ_HE ] ) ,
atomic_read ( & failed [ SMB2_READ_HE ] ) ) ;
seq_printf ( m , " \n Writes: %d sent %d failed " ,
atomic_read ( & sent [ SMB2_WRITE_HE ] ) ,
atomic_read ( & failed [ SMB2_WRITE_HE ] ) ) ;
seq_printf ( m , " \n Locks: %d sent %d failed " ,
atomic_read ( & sent [ SMB2_LOCK_HE ] ) ,
atomic_read ( & failed [ SMB2_LOCK_HE ] ) ) ;
seq_printf ( m , " \n IOCTLs: %d sent %d failed " ,
atomic_read ( & sent [ SMB2_IOCTL_HE ] ) ,
atomic_read ( & failed [ SMB2_IOCTL_HE ] ) ) ;
seq_printf ( m , " \n Cancels: %d sent %d failed " ,
atomic_read ( & sent [ SMB2_CANCEL_HE ] ) ,
atomic_read ( & failed [ SMB2_CANCEL_HE ] ) ) ;
seq_printf ( m , " \n Echos: %d sent %d failed " ,
atomic_read ( & sent [ SMB2_ECHO_HE ] ) ,
atomic_read ( & failed [ SMB2_ECHO_HE ] ) ) ;
seq_printf ( m , " \n QueryDirectories: %d sent %d failed " ,
atomic_read ( & sent [ SMB2_QUERY_DIRECTORY_HE ] ) ,
atomic_read ( & failed [ SMB2_QUERY_DIRECTORY_HE ] ) ) ;
seq_printf ( m , " \n ChangeNotifies: %d sent %d failed " ,
atomic_read ( & sent [ SMB2_CHANGE_NOTIFY_HE ] ) ,
atomic_read ( & failed [ SMB2_CHANGE_NOTIFY_HE ] ) ) ;
seq_printf ( m , " \n QueryInfos: %d sent %d failed " ,
atomic_read ( & sent [ SMB2_QUERY_INFO_HE ] ) ,
atomic_read ( & failed [ SMB2_QUERY_INFO_HE ] ) ) ;
seq_printf ( m , " \n SetInfos: %d sent %d failed " ,
atomic_read ( & sent [ SMB2_SET_INFO_HE ] ) ,
atomic_read ( & failed [ SMB2_SET_INFO_HE ] ) ) ;
seq_printf ( m , " \n OplockBreaks: %d sent %d failed " ,
atomic_read ( & sent [ SMB2_OPLOCK_BREAK_HE ] ) ,
atomic_read ( & failed [ SMB2_OPLOCK_BREAK_HE ] ) ) ;
# endif
}
2012-09-19 03:20:26 +04:00
static void
smb2_set_fid ( struct cifsFileInfo * cfile , struct cifs_fid * fid , __u32 oplock )
{
2012-09-19 03:20:33 +04:00
struct cifsInodeInfo * cinode = CIFS_I ( cfile - > dentry - > d_inode ) ;
2013-09-05 16:11:28 +04:00
struct TCP_Server_Info * server = tlink_tcon ( cfile - > tlink ) - > ses - > server ;
2012-09-19 03:20:26 +04:00
cfile - > fid . persistent_fid = fid - > persistent_fid ;
cfile - > fid . volatile_fid = fid - > volatile_fid ;
2013-09-05 21:30:16 +04:00
server - > ops - > set_oplock_level ( cinode , oplock , fid - > epoch ,
& fid - > purge_cache ) ;
2013-09-05 13:01:06 +04:00
cinode - > can_cache_brlcks = CIFS_CACHE_WRITE ( cinode ) ;
2012-09-19 03:20:26 +04:00
}
2012-09-25 11:00:07 +04:00
static void
2012-09-19 03:20:26 +04:00
smb2_close_file ( const unsigned int xid , struct cifs_tcon * tcon ,
struct cifs_fid * fid )
{
2012-09-25 11:00:07 +04:00
SMB2_close ( xid , tcon , fid - > persistent_fid , fid - > volatile_fid ) ;
2012-09-19 03:20:26 +04:00
}
2013-11-14 10:05:36 +04:00
static int
SMB2_request_res_key ( const unsigned int xid , struct cifs_tcon * tcon ,
u64 persistent_fid , u64 volatile_fid ,
struct copychunk_ioctl * pcchunk )
{
int rc ;
unsigned int ret_data_len ;
struct resume_key_req * res_key ;
rc = SMB2_ioctl ( xid , tcon , persistent_fid , volatile_fid ,
FSCTL_SRV_REQUEST_RESUME_KEY , true /* is_fsctl */ ,
NULL , 0 /* no input */ ,
( char * * ) & res_key , & ret_data_len ) ;
if ( rc ) {
cifs_dbg ( VFS , " refcpy ioctl error %d getting resume key \n " , rc ) ;
goto req_res_key_exit ;
}
if ( ret_data_len < sizeof ( struct resume_key_req ) ) {
cifs_dbg ( VFS , " Invalid refcopy resume key length \n " ) ;
rc = - EINVAL ;
goto req_res_key_exit ;
}
memcpy ( pcchunk - > SourceKey , res_key - > ResumeKey , COPY_CHUNK_RES_KEY_SIZE ) ;
req_res_key_exit :
kfree ( res_key ) ;
return rc ;
}
static int
smb2_clone_range ( const unsigned int xid ,
struct cifsFileInfo * srcfile ,
struct cifsFileInfo * trgtfile , u64 src_off ,
u64 len , u64 dest_off )
{
int rc ;
unsigned int ret_data_len ;
struct copychunk_ioctl * pcchunk ;
char * retbuf = NULL ;
pcchunk = kmalloc ( sizeof ( struct copychunk_ioctl ) , GFP_KERNEL ) ;
if ( pcchunk = = NULL )
return - ENOMEM ;
cifs_dbg ( FYI , " in smb2_clone_range - about to call request res key \n " ) ;
/* Request a key from the server to identify the source of the copy */
rc = SMB2_request_res_key ( xid , tlink_tcon ( srcfile - > tlink ) ,
srcfile - > fid . persistent_fid ,
srcfile - > fid . volatile_fid , pcchunk ) ;
/* Note: request_res_key sets res_key null only if rc !=0 */
if ( rc )
return rc ;
/* For now array only one chunk long, will make more flexible later */
pcchunk - > ChunkCount = __constant_cpu_to_le32 ( 1 ) ;
pcchunk - > Reserved = 0 ;
pcchunk - > SourceOffset = cpu_to_le64 ( src_off ) ;
pcchunk - > TargetOffset = cpu_to_le64 ( dest_off ) ;
pcchunk - > Length = cpu_to_le32 ( len ) ;
pcchunk - > Reserved2 = 0 ;
/* Request that server copy to target from src file identified by key */
rc = SMB2_ioctl ( xid , tlink_tcon ( trgtfile - > tlink ) ,
trgtfile - > fid . persistent_fid ,
trgtfile - > fid . volatile_fid , FSCTL_SRV_COPYCHUNK_WRITE ,
true /* is_fsctl */ , ( char * ) pcchunk ,
sizeof ( struct copychunk_ioctl ) , & retbuf , & ret_data_len ) ;
/* BB need to special case rc = EINVAL to alter chunk size */
cifs_dbg ( FYI , " rc %d data length out %d \n " , rc , ret_data_len ) ;
kfree ( pcchunk ) ;
return rc ;
}
2012-09-19 03:20:28 +04:00
static int
smb2_flush_file ( const unsigned int xid , struct cifs_tcon * tcon ,
struct cifs_fid * fid )
{
return SMB2_flush ( xid , tcon , fid - > persistent_fid , fid - > volatile_fid ) ;
}
2012-09-19 03:20:29 +04:00
static unsigned int
smb2_read_data_offset ( char * buf )
{
struct smb2_read_rsp * rsp = ( struct smb2_read_rsp * ) buf ;
return rsp - > DataOffset ;
}
static unsigned int
smb2_read_data_length ( char * buf )
{
struct smb2_read_rsp * rsp = ( struct smb2_read_rsp * ) buf ;
return le32_to_cpu ( rsp - > DataLength ) ;
}
2012-09-19 03:20:30 +04:00
static int
smb2_sync_read ( const unsigned int xid , struct cifsFileInfo * cfile ,
struct cifs_io_parms * parms , unsigned int * bytes_read ,
char * * buf , int * buf_type )
{
parms - > persistent_fid = cfile - > fid . persistent_fid ;
parms - > volatile_fid = cfile - > fid . volatile_fid ;
return SMB2_read ( xid , parms , bytes_read , buf , buf_type ) ;
}
2012-09-19 03:20:30 +04:00
static int
smb2_sync_write ( const unsigned int xid , struct cifsFileInfo * cfile ,
struct cifs_io_parms * parms , unsigned int * written ,
struct kvec * iov , unsigned long nr_segs )
{
parms - > persistent_fid = cfile - > fid . persistent_fid ;
parms - > volatile_fid = cfile - > fid . volatile_fid ;
return SMB2_write ( xid , parms , written , iov , nr_segs ) ;
}
2012-09-19 03:20:32 +04:00
static int
smb2_set_file_size ( const unsigned int xid , struct cifs_tcon * tcon ,
struct cifsFileInfo * cfile , __u64 size , bool set_alloc )
{
__le64 eof = cpu_to_le64 ( size ) ;
return SMB2_set_eof ( xid , tcon , cfile - > fid . persistent_fid ,
cfile - > fid . volatile_fid , cfile - > pid , & eof ) ;
}
2013-10-15 00:31:32 +04:00
static int
smb2_set_compression ( const unsigned int xid , struct cifs_tcon * tcon ,
struct cifsFileInfo * cfile )
{
return SMB2_set_compression ( xid , tcon , cfile - > fid . persistent_fid ,
cfile - > fid . volatile_fid ) ;
}
2012-09-19 03:20:33 +04:00
static int
smb2_query_dir_first ( const unsigned int xid , struct cifs_tcon * tcon ,
const char * path , struct cifs_sb_info * cifs_sb ,
struct cifs_fid * fid , __u16 search_flags ,
struct cifs_search_info * srch_inf )
{
__le16 * utf16_path ;
int rc ;
2012-09-19 03:20:33 +04:00
__u8 oplock = SMB2_OPLOCK_LEVEL_NONE ;
2013-07-09 18:20:30 +04:00
struct cifs_open_parms oparms ;
2012-09-19 03:20:33 +04:00
utf16_path = cifs_convert_path_to_utf16 ( path , cifs_sb ) ;
if ( ! utf16_path )
return - ENOMEM ;
2013-07-09 18:20:30 +04:00
oparms . tcon = tcon ;
oparms . desired_access = FILE_READ_ATTRIBUTES | FILE_READ_DATA ;
oparms . disposition = FILE_OPEN ;
oparms . create_options = 0 ;
oparms . fid = fid ;
2013-07-09 18:40:58 +04:00
oparms . reconnect = false ;
2013-07-09 18:20:30 +04:00
2013-08-14 19:25:21 +04:00
rc = SMB2_open ( xid , & oparms , utf16_path , & oplock , NULL , NULL ) ;
2012-09-19 03:20:33 +04:00
kfree ( utf16_path ) ;
if ( rc ) {
2013-05-05 07:12:25 +04:00
cifs_dbg ( VFS , " open dir failed \n " ) ;
2012-09-19 03:20:33 +04:00
return rc ;
}
srch_inf - > entries_in_buffer = 0 ;
srch_inf - > index_of_last_entry = 0 ;
2013-07-09 18:20:30 +04:00
rc = SMB2_query_directory ( xid , tcon , fid - > persistent_fid ,
fid - > volatile_fid , 0 , srch_inf ) ;
2012-09-19 03:20:33 +04:00
if ( rc ) {
2013-05-05 07:12:25 +04:00
cifs_dbg ( VFS , " query directory failed \n " ) ;
2013-07-09 18:20:30 +04:00
SMB2_close ( xid , tcon , fid - > persistent_fid , fid - > volatile_fid ) ;
2012-09-19 03:20:33 +04:00
}
return rc ;
}
static int
smb2_query_dir_next ( const unsigned int xid , struct cifs_tcon * tcon ,
struct cifs_fid * fid , __u16 search_flags ,
struct cifs_search_info * srch_inf )
{
return SMB2_query_directory ( xid , tcon , fid - > persistent_fid ,
fid - > volatile_fid , 0 , srch_inf ) ;
}
static int
smb2_close_dir ( const unsigned int xid , struct cifs_tcon * tcon ,
struct cifs_fid * fid )
{
return SMB2_close ( xid , tcon , fid - > persistent_fid , fid - > volatile_fid ) ;
}
2012-09-19 03:20:33 +04:00
/*
* If we negotiate SMB2 protocol and get STATUS_PENDING - update
* the number of credits and return true . Otherwise - return false .
*/
static bool
smb2_is_status_pending ( char * buf , struct TCP_Server_Info * server , int length )
{
struct smb2_hdr * hdr = ( struct smb2_hdr * ) buf ;
2012-09-19 20:19:39 +04:00
if ( hdr - > Status ! = STATUS_PENDING )
2012-09-19 03:20:33 +04:00
return false ;
if ( ! length ) {
spin_lock ( & server - > req_lock ) ;
server - > credits + = le16_to_cpu ( hdr - > CreditRequest ) ;
spin_unlock ( & server - > req_lock ) ;
wake_up ( & server - > request_q ) ;
}
return true ;
}
2012-09-19 03:20:33 +04:00
static int
smb2_oplock_response ( struct cifs_tcon * tcon , struct cifs_fid * fid ,
struct cifsInodeInfo * cinode )
{
2012-09-19 17:22:45 +04:00
if ( tcon - > ses - > server - > capabilities & SMB2_GLOBAL_CAP_LEASING )
return SMB2_lease_break ( 0 , tcon , cinode - > lease_key ,
smb2_get_lease_state ( cinode ) ) ;
2012-09-19 03:20:33 +04:00
return SMB2_oplock_break ( 0 , tcon , fid - > persistent_fid ,
fid - > volatile_fid ,
2013-09-05 13:01:06 +04:00
CIFS_CACHE_READ ( cinode ) ? 1 : 0 ) ;
2012-09-19 03:20:33 +04:00
}
2012-09-19 03:20:34 +04:00
static int
smb2_queryfs ( const unsigned int xid , struct cifs_tcon * tcon ,
struct kstatfs * buf )
{
int rc ;
__le16 srch_path = 0 ; /* Null - open root of share */
u8 oplock = SMB2_OPLOCK_LEVEL_NONE ;
2013-07-09 18:20:30 +04:00
struct cifs_open_parms oparms ;
struct cifs_fid fid ;
oparms . tcon = tcon ;
oparms . desired_access = FILE_READ_ATTRIBUTES ;
oparms . disposition = FILE_OPEN ;
oparms . create_options = 0 ;
oparms . fid = & fid ;
2013-07-09 18:40:58 +04:00
oparms . reconnect = false ;
2012-09-19 03:20:34 +04:00
2013-08-14 19:25:21 +04:00
rc = SMB2_open ( xid , & oparms , & srch_path , & oplock , NULL , NULL ) ;
2012-09-19 03:20:34 +04:00
if ( rc )
return rc ;
buf - > f_type = SMB2_MAGIC_NUMBER ;
2013-07-09 18:20:30 +04:00
rc = SMB2_QFS_info ( xid , tcon , fid . persistent_fid , fid . volatile_fid ,
buf ) ;
SMB2_close ( xid , tcon , fid . persistent_fid , fid . volatile_fid ) ;
2012-09-19 03:20:34 +04:00
return rc ;
}
2012-09-19 17:22:43 +04:00
static bool
smb2_compare_fids ( struct cifsFileInfo * ob1 , struct cifsFileInfo * ob2 )
{
return ob1 - > fid . persistent_fid = = ob2 - > fid . persistent_fid & &
ob1 - > fid . volatile_fid = = ob2 - > fid . volatile_fid ;
}
2012-09-19 17:22:43 +04:00
static int
smb2_mand_lock ( const unsigned int xid , struct cifsFileInfo * cfile , __u64 offset ,
__u64 length , __u32 type , int lock , int unlock , bool wait )
{
if ( unlock & & ! lock )
type = SMB2_LOCKFLAG_UNLOCK ;
return SMB2_lock ( xid , tlink_tcon ( cfile - > tlink ) ,
cfile - > fid . persistent_fid , cfile - > fid . volatile_fid ,
current - > tgid , length , offset , type , wait ) ;
}
2012-09-19 17:22:44 +04:00
static void
smb2_get_lease_key ( struct inode * inode , struct cifs_fid * fid )
{
memcpy ( fid - > lease_key , CIFS_I ( inode ) - > lease_key , SMB2_LEASE_KEY_SIZE ) ;
}
static void
smb2_set_lease_key ( struct inode * inode , struct cifs_fid * fid )
{
memcpy ( CIFS_I ( inode ) - > lease_key , fid - > lease_key , SMB2_LEASE_KEY_SIZE ) ;
}
static void
smb2_new_lease_key ( struct cifs_fid * fid )
{
get_random_bytes ( fid - > lease_key , SMB2_LEASE_KEY_SIZE ) ;
}
2013-08-14 19:25:21 +04:00
static int
smb2_query_symlink ( const unsigned int xid , struct cifs_tcon * tcon ,
const char * full_path , char * * target_path ,
struct cifs_sb_info * cifs_sb )
{
int rc ;
__le16 * utf16_path ;
__u8 oplock = SMB2_OPLOCK_LEVEL_NONE ;
struct cifs_open_parms oparms ;
struct cifs_fid fid ;
struct smb2_err_rsp * err_buf = NULL ;
struct smb2_symlink_err_rsp * symlink ;
unsigned int sub_len , sub_offset ;
cifs_dbg ( FYI , " %s: path: %s \n " , __func__ , full_path ) ;
utf16_path = cifs_convert_path_to_utf16 ( full_path , cifs_sb ) ;
if ( ! utf16_path )
return - ENOMEM ;
oparms . tcon = tcon ;
oparms . desired_access = FILE_READ_ATTRIBUTES ;
oparms . disposition = FILE_OPEN ;
oparms . create_options = 0 ;
oparms . fid = & fid ;
oparms . reconnect = false ;
rc = SMB2_open ( xid , & oparms , utf16_path , & oplock , NULL , & err_buf ) ;
if ( ! rc | | ! err_buf ) {
kfree ( utf16_path ) ;
return - ENOENT ;
}
/* open must fail on symlink - reset rc */
rc = 0 ;
symlink = ( struct smb2_symlink_err_rsp * ) err_buf - > ErrorData ;
sub_len = le16_to_cpu ( symlink - > SubstituteNameLength ) ;
sub_offset = le16_to_cpu ( symlink - > SubstituteNameOffset ) ;
* target_path = cifs_strndup_from_utf16 (
( char * ) symlink - > PathBuffer + sub_offset ,
sub_len , true , cifs_sb - > local_nls ) ;
if ( ! ( * target_path ) ) {
kfree ( utf16_path ) ;
return - ENOMEM ;
}
convert_delimiter ( * target_path , ' / ' ) ;
cifs_dbg ( FYI , " %s: target path: %s \n " , __func__ , * target_path ) ;
kfree ( utf16_path ) ;
return rc ;
}
2013-09-05 16:11:28 +04:00
static void
2013-09-05 21:30:16 +04:00
smb2_set_oplock_level ( struct cifsInodeInfo * cinode , __u32 oplock ,
unsigned int epoch , bool * purge_cache )
2013-09-05 16:11:28 +04:00
{
oplock & = 0xFF ;
if ( oplock = = SMB2_OPLOCK_LEVEL_NOCHANGE )
return ;
if ( oplock = = SMB2_OPLOCK_LEVEL_BATCH ) {
2013-09-05 21:30:16 +04:00
cinode - > oplock = CIFS_CACHE_RHW_FLG ;
2013-09-05 16:11:28 +04:00
cifs_dbg ( FYI , " Batch Oplock granted on inode %p \n " ,
& cinode - > vfs_inode ) ;
} else if ( oplock = = SMB2_OPLOCK_LEVEL_EXCLUSIVE ) {
2013-09-05 21:30:16 +04:00
cinode - > oplock = CIFS_CACHE_RW_FLG ;
2013-09-05 16:11:28 +04:00
cifs_dbg ( FYI , " Exclusive Oplock granted on inode %p \n " ,
& cinode - > vfs_inode ) ;
} else if ( oplock = = SMB2_OPLOCK_LEVEL_II ) {
cinode - > oplock = CIFS_CACHE_READ_FLG ;
cifs_dbg ( FYI , " Level II Oplock granted on inode %p \n " ,
& cinode - > vfs_inode ) ;
} else
cinode - > oplock = 0 ;
}
static void
2013-09-05 21:30:16 +04:00
smb21_set_oplock_level ( struct cifsInodeInfo * cinode , __u32 oplock ,
unsigned int epoch , bool * purge_cache )
2013-09-05 16:11:28 +04:00
{
char message [ 5 ] = { 0 } ;
oplock & = 0xFF ;
if ( oplock = = SMB2_OPLOCK_LEVEL_NOCHANGE )
return ;
cinode - > oplock = 0 ;
if ( oplock & SMB2_LEASE_READ_CACHING_HE ) {
cinode - > oplock | = CIFS_CACHE_READ_FLG ;
strcat ( message , " R " ) ;
}
if ( oplock & SMB2_LEASE_HANDLE_CACHING_HE ) {
cinode - > oplock | = CIFS_CACHE_HANDLE_FLG ;
strcat ( message , " H " ) ;
}
if ( oplock & SMB2_LEASE_WRITE_CACHING_HE ) {
cinode - > oplock | = CIFS_CACHE_WRITE_FLG ;
strcat ( message , " W " ) ;
}
if ( ! cinode - > oplock )
strcat ( message , " None " ) ;
cifs_dbg ( FYI , " %s Lease granted on inode %p \n " , message ,
& cinode - > vfs_inode ) ;
}
2013-09-05 21:30:16 +04:00
static void
smb3_set_oplock_level ( struct cifsInodeInfo * cinode , __u32 oplock ,
unsigned int epoch , bool * purge_cache )
{
unsigned int old_oplock = cinode - > oplock ;
smb21_set_oplock_level ( cinode , oplock , epoch , purge_cache ) ;
if ( purge_cache ) {
* purge_cache = false ;
if ( old_oplock = = CIFS_CACHE_READ_FLG ) {
if ( cinode - > oplock = = CIFS_CACHE_READ_FLG & &
( epoch - cinode - > epoch > 0 ) )
* purge_cache = true ;
else if ( cinode - > oplock = = CIFS_CACHE_RH_FLG & &
( epoch - cinode - > epoch > 1 ) )
* purge_cache = true ;
else if ( cinode - > oplock = = CIFS_CACHE_RHW_FLG & &
( epoch - cinode - > epoch > 1 ) )
* purge_cache = true ;
else if ( cinode - > oplock = = 0 & &
( epoch - cinode - > epoch > 0 ) )
* purge_cache = true ;
} else if ( old_oplock = = CIFS_CACHE_RH_FLG ) {
if ( cinode - > oplock = = CIFS_CACHE_RH_FLG & &
( epoch - cinode - > epoch > 0 ) )
* purge_cache = true ;
else if ( cinode - > oplock = = CIFS_CACHE_RHW_FLG & &
( epoch - cinode - > epoch > 1 ) )
* purge_cache = true ;
}
cinode - > epoch = epoch ;
}
}
2013-09-05 16:11:28 +04:00
static bool
smb2_is_read_op ( __u32 oplock )
{
return oplock = = SMB2_OPLOCK_LEVEL_II ;
}
static bool
smb21_is_read_op ( __u32 oplock )
{
return ( oplock & SMB2_LEASE_READ_CACHING_HE ) & &
! ( oplock & SMB2_LEASE_WRITE_CACHING_HE ) ;
}
2013-09-04 13:44:05 +04:00
static __le32
map_oplock_to_lease ( u8 oplock )
{
if ( oplock = = SMB2_OPLOCK_LEVEL_EXCLUSIVE )
return SMB2_LEASE_WRITE_CACHING | SMB2_LEASE_READ_CACHING ;
else if ( oplock = = SMB2_OPLOCK_LEVEL_II )
return SMB2_LEASE_READ_CACHING ;
else if ( oplock = = SMB2_OPLOCK_LEVEL_BATCH )
return SMB2_LEASE_HANDLE_CACHING | SMB2_LEASE_READ_CACHING |
SMB2_LEASE_WRITE_CACHING ;
return 0 ;
}
2013-09-04 13:07:41 +04:00
static char *
smb2_create_lease_buf ( u8 * lease_key , u8 oplock )
{
struct create_lease * buf ;
buf = kzalloc ( sizeof ( struct create_lease ) , GFP_KERNEL ) ;
if ( ! buf )
return NULL ;
buf - > lcontext . LeaseKeyLow = cpu_to_le64 ( * ( ( u64 * ) lease_key ) ) ;
buf - > lcontext . LeaseKeyHigh = cpu_to_le64 ( * ( ( u64 * ) ( lease_key + 8 ) ) ) ;
2013-09-04 13:44:05 +04:00
buf - > lcontext . LeaseState = map_oplock_to_lease ( oplock ) ;
2013-09-04 13:07:41 +04:00
buf - > ccontext . DataOffset = cpu_to_le16 ( offsetof
( struct create_lease , lcontext ) ) ;
buf - > ccontext . DataLength = cpu_to_le32 ( sizeof ( struct lease_context ) ) ;
buf - > ccontext . NameOffset = cpu_to_le16 ( offsetof
( struct create_lease , Name ) ) ;
buf - > ccontext . NameLength = cpu_to_le16 ( 4 ) ;
buf - > Name [ 0 ] = ' R ' ;
buf - > Name [ 1 ] = ' q ' ;
buf - > Name [ 2 ] = ' L ' ;
buf - > Name [ 3 ] = ' s ' ;
return ( char * ) buf ;
}
2013-09-04 13:44:05 +04:00
static char *
smb3_create_lease_buf ( u8 * lease_key , u8 oplock )
{
struct create_lease_v2 * buf ;
buf = kzalloc ( sizeof ( struct create_lease_v2 ) , GFP_KERNEL ) ;
if ( ! buf )
return NULL ;
buf - > lcontext . LeaseKeyLow = cpu_to_le64 ( * ( ( u64 * ) lease_key ) ) ;
buf - > lcontext . LeaseKeyHigh = cpu_to_le64 ( * ( ( u64 * ) ( lease_key + 8 ) ) ) ;
buf - > lcontext . LeaseState = map_oplock_to_lease ( oplock ) ;
buf - > ccontext . DataOffset = cpu_to_le16 ( offsetof
( struct create_lease_v2 , lcontext ) ) ;
buf - > ccontext . DataLength = cpu_to_le32 ( sizeof ( struct lease_context_v2 ) ) ;
buf - > ccontext . NameOffset = cpu_to_le16 ( offsetof
( struct create_lease_v2 , Name ) ) ;
buf - > ccontext . NameLength = cpu_to_le16 ( 4 ) ;
buf - > Name [ 0 ] = ' R ' ;
buf - > Name [ 1 ] = ' q ' ;
buf - > Name [ 2 ] = ' L ' ;
buf - > Name [ 3 ] = ' s ' ;
return ( char * ) buf ;
}
2013-09-05 20:16:45 +04:00
static __u8
2013-09-05 21:30:16 +04:00
smb2_parse_lease_buf ( void * buf , unsigned int * epoch )
2013-09-05 20:16:45 +04:00
{
struct create_lease * lc = ( struct create_lease * ) buf ;
2013-09-05 21:30:16 +04:00
* epoch = 0 ; /* not used */
2013-09-05 20:16:45 +04:00
if ( lc - > lcontext . LeaseFlags & SMB2_LEASE_FLAG_BREAK_IN_PROGRESS )
return SMB2_OPLOCK_LEVEL_NOCHANGE ;
return le32_to_cpu ( lc - > lcontext . LeaseState ) ;
}
2013-09-04 13:44:05 +04:00
static __u8
2013-09-05 21:30:16 +04:00
smb3_parse_lease_buf ( void * buf , unsigned int * epoch )
2013-09-04 13:44:05 +04:00
{
struct create_lease_v2 * lc = ( struct create_lease_v2 * ) buf ;
2013-09-05 21:30:16 +04:00
* epoch = le16_to_cpu ( lc - > lcontext . Epoch ) ;
2013-09-04 13:44:05 +04:00
if ( lc - > lcontext . LeaseFlags & SMB2_LEASE_FLAG_BREAK_IN_PROGRESS )
return SMB2_OPLOCK_LEVEL_NOCHANGE ;
return le32_to_cpu ( lc - > lcontext . LeaseState ) ;
}
2013-09-05 16:11:28 +04:00
struct smb_version_operations smb20_operations = {
2012-09-19 17:22:43 +04:00
. compare_fids = smb2_compare_fids ,
2011-12-26 22:53:34 +04:00
. setup_request = smb2_setup_request ,
2012-07-11 14:45:28 +04:00
. setup_async_request = smb2_setup_async_request ,
2011-12-26 22:53:34 +04:00
. check_receive = smb2_check_receive ,
2012-05-23 16:18:00 +04:00
. add_credits = smb2_add_credits ,
. set_credits = smb2_set_credits ,
. get_credits_field = smb2_get_credits_field ,
. get_credits = smb2_get_credits ,
2011-12-26 22:53:34 +04:00
. get_next_mid = smb2_get_next_mid ,
2012-09-19 03:20:29 +04:00
. read_data_offset = smb2_read_data_offset ,
. read_data_length = smb2_read_data_length ,
. map_error = map_smb2_to_linux_error ,
2011-06-08 15:51:07 +04:00
. find_mid = smb2_find_mid ,
. check_message = smb2_check_message ,
. dump_detail = smb2_dump_detail ,
2012-05-28 15:19:39 +04:00
. clear_stats = smb2_clear_stats ,
. print_stats = smb2_print_stats ,
2012-09-19 03:20:33 +04:00
. is_oplock_break = smb2_is_valid_oplock_break ,
2011-12-27 16:12:43 +04:00
. need_neg = smb2_need_neg ,
. negotiate = smb2_negotiate ,
2012-09-19 03:20:28 +04:00
. negotiate_wsize = smb2_negotiate_wsize ,
. negotiate_rsize = smb2_negotiate_rsize ,
2011-12-27 16:22:00 +04:00
. sess_setup = SMB2_sess_setup ,
. logoff = SMB2_logoff ,
2011-12-27 16:04:00 +04:00
. tree_connect = SMB2_tcon ,
. tree_disconnect = SMB2_tdis ,
2013-10-09 11:07:00 +04:00
. qfs_tcon = smb2_qfs_tcon ,
2011-12-26 22:58:46 +04:00
. is_path_accessible = smb2_is_path_accessible ,
2012-07-12 18:30:44 +04:00
. can_echo = smb2_can_echo ,
. echo = SMB2_echo ,
2011-12-29 17:06:33 +04:00
. query_path_info = smb2_query_path_info ,
. get_srv_inum = smb2_get_srv_inum ,
2012-09-19 03:20:27 +04:00
. query_file_info = smb2_query_file_info ,
2012-09-19 03:20:32 +04:00
. set_path_size = smb2_set_path_size ,
. set_file_size = smb2_set_file_size ,
2012-09-19 03:20:32 +04:00
. set_file_info = smb2_set_file_info ,
2013-10-15 00:31:32 +04:00
. set_compression = smb2_set_compression ,
2011-07-19 12:56:37 +04:00
. mkdir = smb2_mkdir ,
. mkdir_setinfo = smb2_mkdir_setinfo ,
2012-07-10 16:14:38 +04:00
. rmdir = smb2_rmdir ,
2012-09-19 03:20:25 +04:00
. unlink = smb2_unlink ,
2012-09-19 03:20:31 +04:00
. rename = smb2_rename_path ,
2012-09-19 03:20:31 +04:00
. create_hardlink = smb2_create_hardlink ,
2013-08-14 19:25:21 +04:00
. query_symlink = smb2_query_symlink ,
2012-09-19 03:20:26 +04:00
. open = smb2_open_file ,
. set_fid = smb2_set_fid ,
. close = smb2_close_file ,
2012-09-19 03:20:28 +04:00
. flush = smb2_flush_file ,
2012-09-19 03:20:29 +04:00
. async_readv = smb2_async_readv ,
2012-09-19 03:20:29 +04:00
. async_writev = smb2_async_writev ,
2012-09-19 03:20:30 +04:00
. sync_read = smb2_sync_read ,
2012-09-19 03:20:30 +04:00
. sync_write = smb2_sync_write ,
2012-09-19 03:20:33 +04:00
. query_dir_first = smb2_query_dir_first ,
. query_dir_next = smb2_query_dir_next ,
. close_dir = smb2_close_dir ,
. calc_smb_size = smb2_calc_size ,
2012-09-19 03:20:33 +04:00
. is_status_pending = smb2_is_status_pending ,
2012-09-19 03:20:33 +04:00
. oplock_response = smb2_oplock_response ,
2012-09-19 03:20:34 +04:00
. queryfs = smb2_queryfs ,
2012-09-19 17:22:43 +04:00
. mand_lock = smb2_mand_lock ,
. mand_unlock_range = smb2_unlock_range ,
2012-09-19 17:22:44 +04:00
. push_mand_locks = smb2_push_mandatory_locks ,
2012-09-19 17:22:44 +04:00
. get_lease_key = smb2_get_lease_key ,
. set_lease_key = smb2_set_lease_key ,
. new_lease_key = smb2_new_lease_key ,
2012-12-09 08:08:06 +04:00
. calc_signature = smb2_calc_signature ,
2013-09-05 16:11:28 +04:00
. is_read_op = smb2_is_read_op ,
. set_oplock_level = smb2_set_oplock_level ,
2013-09-04 13:07:41 +04:00
. create_lease_buf = smb2_create_lease_buf ,
2013-09-05 20:16:45 +04:00
. parse_lease_buf = smb2_parse_lease_buf ,
2013-11-14 10:05:36 +04:00
. clone_range = smb2_clone_range ,
2012-12-09 08:08:06 +04:00
} ;
2013-09-05 16:11:28 +04:00
struct smb_version_operations smb21_operations = {
. compare_fids = smb2_compare_fids ,
. setup_request = smb2_setup_request ,
. setup_async_request = smb2_setup_async_request ,
. check_receive = smb2_check_receive ,
. add_credits = smb2_add_credits ,
. set_credits = smb2_set_credits ,
. get_credits_field = smb2_get_credits_field ,
. get_credits = smb2_get_credits ,
. get_next_mid = smb2_get_next_mid ,
. read_data_offset = smb2_read_data_offset ,
. read_data_length = smb2_read_data_length ,
. map_error = map_smb2_to_linux_error ,
. find_mid = smb2_find_mid ,
. check_message = smb2_check_message ,
. dump_detail = smb2_dump_detail ,
. clear_stats = smb2_clear_stats ,
. print_stats = smb2_print_stats ,
. is_oplock_break = smb2_is_valid_oplock_break ,
. need_neg = smb2_need_neg ,
. negotiate = smb2_negotiate ,
. negotiate_wsize = smb2_negotiate_wsize ,
. negotiate_rsize = smb2_negotiate_rsize ,
. sess_setup = SMB2_sess_setup ,
. logoff = SMB2_logoff ,
. tree_connect = SMB2_tcon ,
. tree_disconnect = SMB2_tdis ,
2013-10-09 11:07:00 +04:00
. qfs_tcon = smb2_qfs_tcon ,
2013-09-05 16:11:28 +04:00
. is_path_accessible = smb2_is_path_accessible ,
. can_echo = smb2_can_echo ,
. echo = SMB2_echo ,
. query_path_info = smb2_query_path_info ,
. get_srv_inum = smb2_get_srv_inum ,
. query_file_info = smb2_query_file_info ,
. set_path_size = smb2_set_path_size ,
. set_file_size = smb2_set_file_size ,
. set_file_info = smb2_set_file_info ,
2013-10-15 00:31:32 +04:00
. set_compression = smb2_set_compression ,
2013-09-05 16:11:28 +04:00
. mkdir = smb2_mkdir ,
. mkdir_setinfo = smb2_mkdir_setinfo ,
. rmdir = smb2_rmdir ,
. unlink = smb2_unlink ,
. rename = smb2_rename_path ,
. create_hardlink = smb2_create_hardlink ,
. query_symlink = smb2_query_symlink ,
. open = smb2_open_file ,
. set_fid = smb2_set_fid ,
. close = smb2_close_file ,
. flush = smb2_flush_file ,
. async_readv = smb2_async_readv ,
. async_writev = smb2_async_writev ,
. sync_read = smb2_sync_read ,
. sync_write = smb2_sync_write ,
. query_dir_first = smb2_query_dir_first ,
. query_dir_next = smb2_query_dir_next ,
. close_dir = smb2_close_dir ,
. calc_smb_size = smb2_calc_size ,
. is_status_pending = smb2_is_status_pending ,
. oplock_response = smb2_oplock_response ,
. queryfs = smb2_queryfs ,
. mand_lock = smb2_mand_lock ,
. mand_unlock_range = smb2_unlock_range ,
. push_mand_locks = smb2_push_mandatory_locks ,
. get_lease_key = smb2_get_lease_key ,
. set_lease_key = smb2_set_lease_key ,
. new_lease_key = smb2_new_lease_key ,
. calc_signature = smb2_calc_signature ,
. is_read_op = smb21_is_read_op ,
. set_oplock_level = smb21_set_oplock_level ,
2013-09-04 13:07:41 +04:00
. create_lease_buf = smb2_create_lease_buf ,
2013-09-05 20:16:45 +04:00
. parse_lease_buf = smb2_parse_lease_buf ,
2013-11-14 10:05:36 +04:00
. clone_range = smb2_clone_range ,
2013-09-05 16:11:28 +04:00
} ;
2012-12-09 08:08:06 +04:00
struct smb_version_operations smb30_operations = {
. compare_fids = smb2_compare_fids ,
. setup_request = smb2_setup_request ,
. setup_async_request = smb2_setup_async_request ,
. check_receive = smb2_check_receive ,
. add_credits = smb2_add_credits ,
. set_credits = smb2_set_credits ,
. get_credits_field = smb2_get_credits_field ,
. get_credits = smb2_get_credits ,
. get_next_mid = smb2_get_next_mid ,
. read_data_offset = smb2_read_data_offset ,
. read_data_length = smb2_read_data_length ,
. map_error = map_smb2_to_linux_error ,
. find_mid = smb2_find_mid ,
. check_message = smb2_check_message ,
. dump_detail = smb2_dump_detail ,
. clear_stats = smb2_clear_stats ,
. print_stats = smb2_print_stats ,
2013-06-19 23:15:30 +04:00
. dump_share_caps = smb2_dump_share_caps ,
2012-12-09 08:08:06 +04:00
. is_oplock_break = smb2_is_valid_oplock_break ,
. need_neg = smb2_need_neg ,
. negotiate = smb2_negotiate ,
. negotiate_wsize = smb2_negotiate_wsize ,
. negotiate_rsize = smb2_negotiate_rsize ,
. sess_setup = SMB2_sess_setup ,
. logoff = SMB2_logoff ,
. tree_connect = SMB2_tcon ,
. tree_disconnect = SMB2_tdis ,
2013-10-10 05:55:53 +04:00
. qfs_tcon = smb3_qfs_tcon ,
2012-12-09 08:08:06 +04:00
. is_path_accessible = smb2_is_path_accessible ,
. can_echo = smb2_can_echo ,
. echo = SMB2_echo ,
. query_path_info = smb2_query_path_info ,
. get_srv_inum = smb2_get_srv_inum ,
. query_file_info = smb2_query_file_info ,
. set_path_size = smb2_set_path_size ,
. set_file_size = smb2_set_file_size ,
. set_file_info = smb2_set_file_info ,
2013-10-15 00:31:32 +04:00
. set_compression = smb2_set_compression ,
2012-12-09 08:08:06 +04:00
. mkdir = smb2_mkdir ,
. mkdir_setinfo = smb2_mkdir_setinfo ,
. rmdir = smb2_rmdir ,
. unlink = smb2_unlink ,
. rename = smb2_rename_path ,
. create_hardlink = smb2_create_hardlink ,
2013-08-14 19:25:21 +04:00
. query_symlink = smb2_query_symlink ,
2012-12-09 08:08:06 +04:00
. open = smb2_open_file ,
. set_fid = smb2_set_fid ,
. close = smb2_close_file ,
. flush = smb2_flush_file ,
. async_readv = smb2_async_readv ,
. async_writev = smb2_async_writev ,
. sync_read = smb2_sync_read ,
. sync_write = smb2_sync_write ,
. query_dir_first = smb2_query_dir_first ,
. query_dir_next = smb2_query_dir_next ,
. close_dir = smb2_close_dir ,
. calc_smb_size = smb2_calc_size ,
. is_status_pending = smb2_is_status_pending ,
. oplock_response = smb2_oplock_response ,
. queryfs = smb2_queryfs ,
. mand_lock = smb2_mand_lock ,
. mand_unlock_range = smb2_unlock_range ,
. push_mand_locks = smb2_push_mandatory_locks ,
. get_lease_key = smb2_get_lease_key ,
. set_lease_key = smb2_set_lease_key ,
. new_lease_key = smb2_new_lease_key ,
2013-06-27 10:06:50 +04:00
. generate_signingkey = generate_smb3signingkey ,
2012-12-09 08:08:06 +04:00
. calc_signature = smb3_calc_signature ,
2013-09-05 16:11:28 +04:00
. is_read_op = smb21_is_read_op ,
2013-09-05 21:30:16 +04:00
. set_oplock_level = smb3_set_oplock_level ,
2013-09-04 13:44:05 +04:00
. create_lease_buf = smb3_create_lease_buf ,
. parse_lease_buf = smb3_parse_lease_buf ,
2013-11-14 10:05:36 +04:00
. clone_range = smb2_clone_range ,
2011-02-24 21:07:19 +03:00
} ;
2012-11-29 09:21:06 +04:00
struct smb_version_values smb20_values = {
. version_string = SMB20_VERSION_STRING ,
. protocol_id = SMB20_PROT_ID ,
. req_capabilities = 0 , /* MBZ */
. large_lock_type = 0 ,
. exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK ,
. shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK ,
. unlock_lock_type = SMB2_LOCKFLAG_UNLOCK ,
. header_size = sizeof ( struct smb2_hdr ) ,
. max_header_size = MAX_SMB2_HDR_SIZE ,
. read_rsp_size = sizeof ( struct smb2_read_rsp ) - 1 ,
. lock_cmd = SMB2_LOCK ,
. cap_unix = 0 ,
. cap_nt_find = SMB2_NT_FIND ,
. cap_large_files = SMB2_LARGE_FILES ,
2013-06-27 20:45:00 +04:00
. signing_enabled = SMB2_NEGOTIATE_SIGNING_ENABLED | SMB2_NEGOTIATE_SIGNING_REQUIRED ,
. signing_required = SMB2_NEGOTIATE_SIGNING_REQUIRED ,
2013-09-04 13:07:41 +04:00
. create_lease_size = sizeof ( struct create_lease ) ,
2012-11-29 09:21:06 +04:00
} ;
2011-02-24 21:07:19 +03:00
struct smb_version_values smb21_values = {
. version_string = SMB21_VERSION_STRING ,
2012-10-01 21:26:22 +04:00
. protocol_id = SMB21_PROT_ID ,
. req_capabilities = 0 , /* MBZ on negotiate req until SMB3 dialect */
. large_lock_type = 0 ,
. exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK ,
. shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK ,
. unlock_lock_type = SMB2_LOCKFLAG_UNLOCK ,
. header_size = sizeof ( struct smb2_hdr ) ,
. max_header_size = MAX_SMB2_HDR_SIZE ,
. read_rsp_size = sizeof ( struct smb2_read_rsp ) - 1 ,
. lock_cmd = SMB2_LOCK ,
. cap_unix = 0 ,
. cap_nt_find = SMB2_NT_FIND ,
. cap_large_files = SMB2_LARGE_FILES ,
2013-06-27 20:45:00 +04:00
. signing_enabled = SMB2_NEGOTIATE_SIGNING_ENABLED | SMB2_NEGOTIATE_SIGNING_REQUIRED ,
. signing_required = SMB2_NEGOTIATE_SIGNING_REQUIRED ,
2013-09-04 13:07:41 +04:00
. create_lease_size = sizeof ( struct create_lease ) ,
2012-10-01 21:26:22 +04:00
} ;
struct smb_version_values smb30_values = {
. version_string = SMB30_VERSION_STRING ,
. protocol_id = SMB30_PROT_ID ,
. req_capabilities = SMB2_GLOBAL_CAP_DFS | SMB2_GLOBAL_CAP_LEASING | SMB2_GLOBAL_CAP_LARGE_MTU ,
2012-09-19 17:22:43 +04:00
. large_lock_type = 0 ,
. exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK ,
. shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK ,
. unlock_lock_type = SMB2_LOCKFLAG_UNLOCK ,
2011-06-08 15:51:07 +04:00
. header_size = sizeof ( struct smb2_hdr ) ,
. max_header_size = MAX_SMB2_HDR_SIZE ,
2012-09-19 03:20:29 +04:00
. read_rsp_size = sizeof ( struct smb2_read_rsp ) - 1 ,
2011-12-26 22:53:34 +04:00
. lock_cmd = SMB2_LOCK ,
2012-07-13 13:58:14 +04:00
. cap_unix = 0 ,
. cap_nt_find = SMB2_NT_FIND ,
. cap_large_files = SMB2_LARGE_FILES ,
2013-06-27 20:45:00 +04:00
. signing_enabled = SMB2_NEGOTIATE_SIGNING_ENABLED | SMB2_NEGOTIATE_SIGNING_REQUIRED ,
. signing_required = SMB2_NEGOTIATE_SIGNING_REQUIRED ,
2013-09-04 13:44:05 +04:00
. create_lease_size = sizeof ( struct create_lease_v2 ) ,
2011-02-24 21:07:19 +03:00
} ;
2013-06-13 07:48:41 +04:00
struct smb_version_values smb302_values = {
. version_string = SMB302_VERSION_STRING ,
. protocol_id = SMB302_PROT_ID ,
. req_capabilities = SMB2_GLOBAL_CAP_DFS | SMB2_GLOBAL_CAP_LEASING | SMB2_GLOBAL_CAP_LARGE_MTU ,
. large_lock_type = 0 ,
. exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK ,
. shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK ,
. unlock_lock_type = SMB2_LOCKFLAG_UNLOCK ,
. header_size = sizeof ( struct smb2_hdr ) ,
. max_header_size = MAX_SMB2_HDR_SIZE ,
. read_rsp_size = sizeof ( struct smb2_read_rsp ) - 1 ,
. lock_cmd = SMB2_LOCK ,
. cap_unix = 0 ,
. cap_nt_find = SMB2_NT_FIND ,
. cap_large_files = SMB2_LARGE_FILES ,
2013-06-27 20:45:00 +04:00
. signing_enabled = SMB2_NEGOTIATE_SIGNING_ENABLED | SMB2_NEGOTIATE_SIGNING_REQUIRED ,
. signing_required = SMB2_NEGOTIATE_SIGNING_REQUIRED ,
2013-09-04 13:44:05 +04:00
. create_lease_size = sizeof ( struct create_lease_v2 ) ,
2013-06-13 07:48:41 +04:00
} ;