Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
etercifs
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
etersoft
etercifs
Commits
4a267003
Commit
4a267003
authored
Dec 09, 2008
by
Konstantin Baev
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
update sources/2.6.27
- source: cifs-2.6.git - refspec: v2.6.27-etercifs - commit: 1827b7d4082cc5aef979a6d86c7cb96f9dee2c09 merge with new kernel minor version (v2.6.27.8)
parent
d99211de
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
617 additions
and
580 deletions
+617
-580
cifs_debug.c
sources/2.6.27/cifs_debug.c
+93
-72
cifs_spnego.c
sources/2.6.27/cifs_spnego.c
+2
-1
cifsfs.c
sources/2.6.27/cifsfs.c
+15
-16
cifsglob.h
sources/2.6.27/cifsglob.h
+24
-19
cifsproto.h
sources/2.6.27/cifsproto.h
+1
-1
cifssmb.c
sources/2.6.27/cifssmb.c
+34
-57
connect.c
sources/2.6.27/connect.c
+373
-358
file.c
sources/2.6.27/file.c
+5
-2
misc.c
sources/2.6.27/misc.c
+34
-42
transport.c
sources/2.6.27/transport.c
+36
-12
No files found.
sources/2.6.27/cifs_debug.c
View file @
4a267003
...
...
@@ -107,12 +107,13 @@ void cifs_dump_mids(struct TCP_Server_Info *server)
#ifdef CONFIG_PROC_FS
static
int
cifs_debug_data_proc_show
(
struct
seq_file
*
m
,
void
*
v
)
{
struct
list_head
*
tmp
;
struct
list_head
*
tmp1
;
struct
list_head
*
tmp1
,
*
tmp2
,
*
tmp3
;
struct
mid_q_entry
*
mid_entry
;
struct
TCP_Server_Info
*
server
;
struct
cifsSesInfo
*
ses
;
struct
cifsTconInfo
*
tcon
;
int
i
;
int
i
,
j
;
__u32
dev_type
;
seq_puts
(
m
,
"Display Internal CIFS Data Structures for Debugging
\n
"
...
...
@@ -122,77 +123,55 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
seq_printf
(
m
,
"Servers:"
);
i
=
0
;
read_lock
(
&
GlobalSMBSeslock
);
list_for_each
(
tmp
,
&
GlobalSMBSessionList
)
{
read_lock
(
&
cifs_tcp_ses_lock
);
list_for_each
(
tmp1
,
&
cifs_tcp_ses_list
)
{
server
=
list_entry
(
tmp1
,
struct
TCP_Server_Info
,
tcp_ses_list
);
i
++
;
ses
=
list_entry
(
tmp
,
struct
cifsSesInfo
,
cifsSessionList
);
if
((
ses
->
serverDomain
==
NULL
)
||
(
ses
->
serverOS
==
NULL
)
||
list_for_each
(
tmp2
,
&
server
->
smb_ses_list
)
{
ses
=
list_entry
(
tmp2
,
struct
cifsSesInfo
,
smb_ses_list
);
if
((
ses
->
serverDomain
==
NULL
)
||
(
ses
->
serverOS
==
NULL
)
||
(
ses
->
serverNOS
==
NULL
))
{
seq_printf
(
m
,
"
\n
entry for %s not fully "
"displayed
\n\t
"
,
ses
->
serverName
);
seq_printf
(
m
,
"
\n
%d)
entry for %s not fully "
"displayed
\n\t
"
,
i
,
ses
->
serverName
);
}
else
{
seq_printf
(
m
,
"
\n
%d) Name: %s Domain: %s
Mount
s: %d OS:"
" %s
\n\t
NOS: %s
\t
Capability: 0x%x
\n\t
SMB"
"
\n
%d) Name: %s Domain: %s
Use
s: %d OS:"
" %s
\n\t
NOS: %s
\t
Capability: 0x%x
\n\t
SMB"
" session status: %d
\t
"
,
i
,
ses
->
serverName
,
ses
->
serverDomain
,
atomic_read
(
&
ses
->
inUse
),
ses
->
serverOS
,
ses
->
serverNOS
,
ses
->
ses_count
,
ses
->
serverOS
,
ses
->
serverNOS
,
ses
->
capabilities
,
ses
->
status
);
}
if
(
ses
->
server
)
{
seq_printf
(
m
,
"TCP status: %d
\n\t
Local Users To "
"Server: %d SecMode: 0x%x Req On Wire: %d"
,
ses
->
server
->
tcpStatus
,
atomic_read
(
&
ses
->
server
->
socketUseCount
),
ses
->
server
->
secMode
,
atomic_read
(
&
ses
->
server
->
inFlight
));
server
->
tcpStatus
,
server
->
srv_count
,
server
->
secMode
,
atomic_read
(
&
server
->
inFlight
));
#ifdef CONFIG_CIFS_STATS2
seq_printf
(
m
,
" In Send: %d In MaxReq Wait: %d"
,
atomic_read
(
&
se
s
->
se
rver
->
inSend
),
atomic_read
(
&
se
s
->
se
rver
->
num_waiters
));
atomic_read
(
&
server
->
inSend
),
atomic_read
(
&
server
->
num_waiters
));
#endif
seq_puts
(
m
,
"
\n
MIDs:
\n
"
);
spin_lock
(
&
GlobalMid_Lock
);
list_for_each
(
tmp1
,
&
ses
->
server
->
pending_mid_q
)
{
mid_entry
=
list_entry
(
tmp1
,
struct
mid_q_entry
,
qhead
);
seq_printf
(
m
,
"State: %d com: %d pid:"
" %d tsk: %p mid %d
\n
"
,
mid_entry
->
midState
,
(
int
)
mid_entry
->
command
,
mid_entry
->
pid
,
mid_entry
->
tsk
,
mid_entry
->
mid
);
}
spin_unlock
(
&
GlobalMid_Lock
);
}
}
read_unlock
(
&
GlobalSMBSeslock
);
seq_putc
(
m
,
'\n'
);
seq_puts
(
m
,
"Shares:"
);
i
=
0
;
read_lock
(
&
GlobalSMBSeslock
);
list_for_each
(
tmp
,
&
GlobalTreeConnectionList
)
{
__u32
dev_type
;
i
++
;
tcon
=
list_entry
(
tmp
,
struct
cifsTconInfo
,
cifsConnectionList
);
seq_puts
(
m
,
"
\n\t
Shares:"
);
j
=
0
;
list_for_each
(
tmp3
,
&
ses
->
tcon_list
)
{
tcon
=
list_entry
(
tmp3
,
struct
cifsTconInfo
,
tcon_list
);
++
j
;
dev_type
=
le32_to_cpu
(
tcon
->
fsDevInfo
.
DeviceType
);
seq_printf
(
m
,
"
\n
%d) %s Uses: %d "
,
i
,
tcon
->
treeName
,
atomic_read
(
&
tcon
->
useCount
)
);
seq_printf
(
m
,
"
\n\t
%d) %s Mounts: %d "
,
j
,
tcon
->
treeName
,
tcon
->
tc_count
);
if
(
tcon
->
nativeFileSystem
)
{
seq_printf
(
m
,
"Type: %s "
,
tcon
->
nativeFileSystem
);
}
seq_printf
(
m
,
"DevInfo: 0x%x Attributes: 0x%x"
"
\n
PathComponentMax: %d Status:
%d"
,
"
\n
PathComponentMax: %d Status: 0x
%d"
,
le32_to_cpu
(
tcon
->
fsDevInfo
.
DeviceCharacteristics
),
le32_to_cpu
(
tcon
->
fsAttrInfo
.
Attributes
),
le32_to_cpu
(
tcon
->
fsAttrInfo
.
MaxPathNameComponentLength
),
...
...
@@ -204,11 +183,29 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
else
seq_printf
(
m
,
" type: %d "
,
dev_type
);
if
(
tcon
->
tidStatus
==
CifsNeedR
econnect
)
if
(
tcon
->
need_r
econnect
)
seq_puts
(
m
,
"
\t
DISCONNECTED "
);
seq_putc
(
m
,
'\n'
);
}
read_unlock
(
&
GlobalSMBSeslock
);
seq_puts
(
m
,
"
\n\t
MIDs:
\n
"
);
spin_lock
(
&
GlobalMid_Lock
);
list_for_each
(
tmp3
,
&
server
->
pending_mid_q
)
{
mid_entry
=
list_entry
(
tmp3
,
struct
mid_q_entry
,
qhead
);
seq_printf
(
m
,
"
\t
State: %d com: %d pid:"
" %d tsk: %p mid %d
\n
"
,
mid_entry
->
midState
,
(
int
)
mid_entry
->
command
,
mid_entry
->
pid
,
mid_entry
->
tsk
,
mid_entry
->
mid
);
}
spin_unlock
(
&
GlobalMid_Lock
);
}
}
read_unlock
(
&
cifs_tcp_ses_lock
);
seq_putc
(
m
,
'\n'
);
/* BB add code to dump additional info such as TCP session info now */
...
...
@@ -234,7 +231,9 @@ static ssize_t cifs_stats_proc_write(struct file *file,
{
char
c
;
int
rc
;
struct
list_head
*
tmp
;
struct
list_head
*
tmp1
,
*
tmp2
,
*
tmp3
;
struct
TCP_Server_Info
*
server
;
struct
cifsSesInfo
*
ses
;
struct
cifsTconInfo
*
tcon
;
rc
=
get_user
(
c
,
buffer
);
...
...
@@ -242,14 +241,21 @@ static ssize_t cifs_stats_proc_write(struct file *file,
return
rc
;
if
(
c
==
'1'
||
c
==
'y'
||
c
==
'Y'
||
c
==
'0'
)
{
read_lock
(
&
GlobalSMBSeslock
);
#ifdef CONFIG_CIFS_STATS2
atomic_set
(
&
totBufAllocCount
,
0
);
atomic_set
(
&
totSmBufAllocCount
,
0
);
#endif
/* CONFIG_CIFS_STATS2 */
list_for_each
(
tmp
,
&
GlobalTreeConnectionList
)
{
tcon
=
list_entry
(
tmp
,
struct
cifsTconInfo
,
cifsConnectionList
);
read_lock
(
&
cifs_tcp_ses_lock
);
list_for_each
(
tmp1
,
&
cifs_tcp_ses_list
)
{
server
=
list_entry
(
tmp1
,
struct
TCP_Server_Info
,
tcp_ses_list
);
list_for_each
(
tmp2
,
&
server
->
smb_ses_list
)
{
ses
=
list_entry
(
tmp2
,
struct
cifsSesInfo
,
smb_ses_list
);
list_for_each
(
tmp3
,
&
ses
->
tcon_list
)
{
tcon
=
list_entry
(
tmp3
,
struct
cifsTconInfo
,
tcon_list
);
atomic_set
(
&
tcon
->
num_smbs_sent
,
0
);
atomic_set
(
&
tcon
->
num_writes
,
0
);
atomic_set
(
&
tcon
->
num_reads
,
0
);
...
...
@@ -268,7 +274,9 @@ static ssize_t cifs_stats_proc_write(struct file *file,
atomic_set
(
&
tcon
->
num_symlinks
,
0
);
atomic_set
(
&
tcon
->
num_locks
,
0
);
}
read_unlock
(
&
GlobalSMBSeslock
);
}
}
read_unlock
(
&
cifs_tcp_ses_lock
);
}
return
count
;
...
...
@@ -277,7 +285,9 @@ static ssize_t cifs_stats_proc_write(struct file *file,
static
int
cifs_stats_proc_show
(
struct
seq_file
*
m
,
void
*
v
)
{
int
i
;
struct
list_head
*
tmp
;
struct
list_head
*
tmp1
,
*
tmp2
,
*
tmp3
;
struct
TCP_Server_Info
*
server
;
struct
cifsSesInfo
*
ses
;
struct
cifsTconInfo
*
tcon
;
seq_printf
(
m
,
...
...
@@ -306,12 +316,20 @@ static int cifs_stats_proc_show(struct seq_file *m, void *v)
GlobalCurrentXid
,
GlobalMaxActiveXid
);
i
=
0
;
read_lock
(
&
GlobalSMBSeslock
);
list_for_each
(
tmp
,
&
GlobalTreeConnectionList
)
{
read_lock
(
&
cifs_tcp_ses_lock
);
list_for_each
(
tmp1
,
&
cifs_tcp_ses_list
)
{
server
=
list_entry
(
tmp1
,
struct
TCP_Server_Info
,
tcp_ses_list
);
list_for_each
(
tmp2
,
&
server
->
smb_ses_list
)
{
ses
=
list_entry
(
tmp2
,
struct
cifsSesInfo
,
smb_ses_list
);
list_for_each
(
tmp3
,
&
ses
->
tcon_list
)
{
tcon
=
list_entry
(
tmp3
,
struct
cifsTconInfo
,
tcon_list
);
i
++
;
tcon
=
list_entry
(
tmp
,
struct
cifsTconInfo
,
cifsConnectionList
);
seq_printf
(
m
,
"
\n
%d) %s"
,
i
,
tcon
->
treeName
);
if
(
tcon
->
tidStatus
==
CifsNeedR
econnect
)
if
(
tcon
->
need_r
econnect
)
seq_puts
(
m
,
"
\t
DISCONNECTED "
);
seq_printf
(
m
,
"
\n
SMBs: %d Oplock Breaks: %d"
,
atomic_read
(
&
tcon
->
num_smbs_sent
),
...
...
@@ -322,13 +340,13 @@ static int cifs_stats_proc_show(struct seq_file *m, void *v)
seq_printf
(
m
,
"
\n
Writes: %d Bytes: %lld"
,
atomic_read
(
&
tcon
->
num_writes
),
(
long
long
)(
tcon
->
bytes_written
));
seq_printf
(
m
,
"
\n
Locks: %d HardLinks: %d
Symlinks: %d"
,
seq_printf
(
m
,
"
\n
Locks: %d HardLinks: %d "
"
Symlinks: %d"
,
atomic_read
(
&
tcon
->
num_locks
),
atomic_read
(
&
tcon
->
num_hardlinks
),
atomic_read
(
&
tcon
->
num_symlinks
));
seq_printf
(
m
,
"
\n
Opens: %d Closes: %d
Deletes: %d"
,
seq_printf
(
m
,
"
\n
Opens: %d Closes: %d"
"
Deletes: %d"
,
atomic_read
(
&
tcon
->
num_opens
),
atomic_read
(
&
tcon
->
num_closes
),
atomic_read
(
&
tcon
->
num_deletes
));
...
...
@@ -338,12 +356,15 @@ static int cifs_stats_proc_show(struct seq_file *m, void *v)
seq_printf
(
m
,
"
\n
Renames: %d T2 Renames %d"
,
atomic_read
(
&
tcon
->
num_renames
),
atomic_read
(
&
tcon
->
num_t2renames
));
seq_printf
(
m
,
"
\n
FindFirst: %d FNext %d FClose %d"
,
seq_printf
(
m
,
"
\n
FindFirst: %d FNext %d "
"FClose %d"
,
atomic_read
(
&
tcon
->
num_ffirst
),
atomic_read
(
&
tcon
->
num_fnext
),
atomic_read
(
&
tcon
->
num_fclose
));
}
read_unlock
(
&
GlobalSMBSeslock
);
}
}
read_unlock
(
&
cifs_tcp_ses_lock
);
seq_putc
(
m
,
'\n'
);
return
0
;
...
...
sources/2.6.27/cifs_spnego.c
View file @
4a267003
...
...
@@ -70,7 +70,8 @@ struct key_type cifs_spnego_key_type = {
strlen("ver=0xFF") */
#define MAX_MECH_STR_LEN 13
/* length of longest security mechanism name, eg
in future could have strlen(";sec=ntlmsspi") */
#define MAX_IPV6_ADDR_LEN 42
/* eg FEDC:BA98:7654:3210:FEDC:BA98:7654:3210/60 */
/* max possible addr len eg FEDC:BA98:7654:3210:FEDC:BA98:7654:3210/128 */
#define MAX_IPV6_ADDR_LEN 43
/* get a key struct with a SPNEGO security blob, suitable for session setup */
struct
key
*
cifs_get_spnego_key
(
struct
cifsSesInfo
*
sesInfo
)
...
...
sources/2.6.27/cifsfs.c
View file @
4a267003
...
...
@@ -510,10 +510,11 @@ static void cifs_umount_begin(struct super_block *sb)
tcon
=
cifs_sb
->
tcon
;
if
(
tcon
==
NULL
)
return
;
down
(
&
tcon
->
tconSem
);
if
(
atomic_read
(
&
tcon
->
useCount
)
==
1
)
read_lock
(
&
cifs_tcp_ses_lock
);
if
(
tcon
->
tc_count
==
1
)
tcon
->
tidStatus
=
CifsExiting
;
up
(
&
tcon
->
tconSem
);
read_unlock
(
&
cifs_tcp_ses_lock
);
/* cancel_brl_requests(tcon); */
/* BB mark all brl mids as exiting */
/* cancel_notify_requests(tcon); */
...
...
@@ -980,11 +981,10 @@ static int cifs_oplock_thread(void *dummyarg)
not bother sending an oplock release if session
to server still is disconnected since oplock
already released by the server in that case */
if
(
pTcon
->
tidStatus
!=
CifsNeedR
econnect
)
{
if
(
!
pTcon
->
need_r
econnect
)
{
/* PV: disable caching if oplock missed */
CIFS_I
(
inode
)
->
clientCanCacheRead
=
false
;
CIFS_I
(
inode
)
->
clientCanCacheAll
=
false
;
rc
=
CIFSSMBLock
(
0
,
pTcon
,
netfid
,
0
/* len */
,
0
/* offset */
,
0
,
0
,
LOCKING_ANDX_OPLOCK_RELEASE
,
...
...
@@ -1002,24 +1002,24 @@ static int cifs_oplock_thread(void *dummyarg)
static
int
cifs_dnotify_thread
(
void
*
dummyarg
)
{
struct
list_head
*
tmp
;
struct
cifsSesInfo
*
ses
;
struct
TCP_Server_Info
*
server
;
do
{
if
(
try_to_freeze
())
continue
;
set_current_state
(
TASK_INTERRUPTIBLE
);
schedule_timeout
(
15
*
HZ
);
read_lock
(
&
GlobalSMBSeslock
);
/* check if any stuck requests that need
to be woken up and wakeq so the
thread can wake up and error out */
list_for_each
(
tmp
,
&
GlobalSMBSessionList
)
{
ses
=
list_entry
(
tmp
,
struct
cifsSesInfo
,
cifsSessionList
);
if
(
ses
->
server
&&
atomic_read
(
&
ses
->
server
->
inFlight
))
wake_up_all
(
&
ses
->
server
->
response_q
);
read_lock
(
&
cifs_tcp_ses_lock
);
list_for_each
(
tmp
,
&
cifs_tcp_ses_list
)
{
server
=
list_entry
(
tmp
,
struct
TCP_Server_Info
,
tcp_ses_list
);
if
(
atomic_read
(
&
server
->
inFlight
))
wake_up_all
(
&
server
->
response_q
);
}
read_unlock
(
&
GlobalSMBSes
lock
);
read_unlock
(
&
cifs_tcp_ses_
lock
);
}
while
(
!
kthread_should_stop
());
return
0
;
...
...
@@ -1030,9 +1030,7 @@ init_cifs(void)
{
int
rc
=
0
;
cifs_proc_init
();
/* INIT_LIST_HEAD(&GlobalServerList);*/
/* BB not implemented yet */
INIT_LIST_HEAD
(
&
GlobalSMBSessionList
);
INIT_LIST_HEAD
(
&
GlobalTreeConnectionList
);
INIT_LIST_HEAD
(
&
cifs_tcp_ses_list
);
INIT_LIST_HEAD
(
&
GlobalOplock_Q
);
#ifdef CONFIG_CIFS_EXPERIMENTAL
INIT_LIST_HEAD
(
&
GlobalDnotifyReqList
);
...
...
@@ -1060,6 +1058,7 @@ init_cifs(void)
GlobalMaxActiveXid
=
0
;
memset
(
Local_System_Name
,
0
,
15
);
rwlock_init
(
&
GlobalSMBSeslock
);
rwlock_init
(
&
cifs_tcp_ses_lock
);
spin_lock_init
(
&
GlobalMid_Lock
);
if
(
cifs_max_pending
<
2
)
{
...
...
sources/2.6.27/cifsglob.h
View file @
4a267003
...
...
@@ -85,8 +85,7 @@ enum securityEnum {
};
enum
protocolEnum
{
IPV4
=
0
,
IPV6
,
TCP
=
0
,
SCTP
/* Netbios frames protocol not supported at this time */
};
...
...
@@ -122,6 +121,9 @@ struct cifs_cred {
*/
struct
TCP_Server_Info
{
struct
list_head
tcp_ses_list
;
struct
list_head
smb_ses_list
;
int
srv_count
;
/* reference counter */
/* 15 character server name + 0x20 16th byte indicating type = srv */
char
server_RFC1001_name
[
SERVER_NAME_LEN_WITH_NULL
];
char
unicode_server_Name
[
SERVER_NAME_LEN_WITH_NULL
*
2
];
...
...
@@ -141,7 +143,8 @@ struct TCP_Server_Info {
char
versionMajor
;
char
versionMinor
;
bool
svlocal
:
1
;
/* local server or remote */
atomic_t
socketUseCount
;
/* number of open cifs sessions on socket */
bool
noblocksnd
;
/* use blocking sendmsg */
bool
noautotune
;
/* do not autotune send buf sizes */
atomic_t
inFlight
;
/* number of requests on the wire to server */
#ifdef CONFIG_CIFS_STATS2
atomic_t
inSend
;
/* requests trying to send */
...
...
@@ -192,13 +195,14 @@ struct cifsUidInfo {
* Session structure. One of these for each uid session with a particular host
*/
struct
cifsSesInfo
{
struct
list_head
cifsSessionList
;
struct
list_head
smb_ses_list
;
struct
list_head
tcon_list
;
struct
semaphore
sesSem
;
#if 0
struct cifsUidInfo *uidInfo; /* pointer to user info */
#endif
struct
TCP_Server_Info
*
server
;
/* pointer to server info */
atomic_t
inUse
;
/* # of mounts (tree connections) on this ses
*/
int
ses_count
;
/* reference counter
*/
enum
statusEnum
status
;
unsigned
overrideSecFlg
;
/* if non-zero override global sec flags */
__u16
ipc_tid
;
/* special tid for connection to IPC share */
...
...
@@ -214,6 +218,7 @@ struct cifsSesInfo {
char
userName
[
MAX_USERNAME_SIZE
+
1
];
char
*
domainName
;
char
*
password
;
bool
need_reconnect
:
1
;
/* connection reset, uid now invalid */
};
/* no more than one of the following three session flags may be set */
#define CIFS_SES_NT4 1
...
...
@@ -228,16 +233,15 @@ struct cifsSesInfo {
* session
*/
struct
cifsTconInfo
{
struct
list_head
cifsConnectionList
;
struct
list_head
tcon_list
;
int
tc_count
;
struct
list_head
openFileList
;
struct
semaphore
tconSem
;
struct
cifsSesInfo
*
ses
;
/* pointer to session associated with */
char
treeName
[
MAX_TREE_SIZE
+
1
];
/* UNC name of resource in ASCII */
char
*
nativeFileSystem
;
__u16
tid
;
/* The 2 byte tree id */
__u16
Flags
;
/* optional support bits */
enum
statusEnum
tidStatus
;
atomic_t
useCount
;
/* how many explicit/implicit mounts to share */
#ifdef CONFIG_CIFS_STATS
atomic_t
num_smbs_sent
;
atomic_t
num_writes
;
...
...
@@ -285,6 +289,7 @@ struct cifsTconInfo {
bool
seal
:
1
;
/* transport encryption for this mounted share */
bool
unix_ext
:
1
;
/* if false disable Linux extensions to CIFS protocol
for this mount even if server would support */
bool
need_reconnect
:
1
;
/* connection reset, tid now invalid */
/* BB add field for back pointer to sb struct(s)? */
};
...
...
@@ -585,21 +590,21 @@ require use of the stronger protocol */
#endif
/*
* The list of servers that did not respond with NT LM 0.12.
* This list helps improve performance and eliminate the messages indicating
* that we had a communications error talking to the server in this list.
* the list of TCP_Server_Info structures, ie each of the sockets
* connecting our client to a distinct server (ip address), is
* chained together by cifs_tcp_ses_list. The list of all our SMB
* sessions (and from that the tree connections) can be found
* by iterating over cifs_tcp_ses_list
*/
/* Feature not supported */
/* GLOBAL_EXTERN struct servers_not_supported *NotSuppList; */
GLOBAL_EXTERN
struct
list_head
cifs_tcp_ses_list
;
/*
* The following is a hash table of all the users we know about.
* This lock protects the cifs_tcp_ses_list, the list of smb sessions per
* tcp session, and the list of tcon's per smb session. It also protects
* the reference counters for the server, smb session, and tcon. Finally,
* changes to the tcon->tidStatus should be done while holding this lock.
*/
GLOBAL_EXTERN
struct
smbUidInfo
*
GlobalUidList
[
UID_HASH
];
/* GLOBAL_EXTERN struct list_head GlobalServerList; BB not implemented yet */
GLOBAL_EXTERN
struct
list_head
GlobalSMBSessionList
;
GLOBAL_EXTERN
struct
list_head
GlobalTreeConnectionList
;
GLOBAL_EXTERN
rwlock_t
cifs_tcp_ses_lock
;
GLOBAL_EXTERN
rwlock_t
GlobalSMBSeslock
;
/* protects list inserts on 3 above */
GLOBAL_EXTERN
struct
list_head
GlobalOplock_Q
;
...
...
sources/2.6.27/cifsproto.h
View file @
4a267003
...
...
@@ -36,7 +36,7 @@ extern void cifs_buf_release(void *);
extern
struct
smb_hdr
*
cifs_small_buf_get
(
void
);
extern
void
cifs_small_buf_release
(
void
*
);
extern
int
smb_send
(
struct
socket
*
,
struct
smb_hdr
*
,
unsigned
int
/* length */
,
struct
sockaddr
*
);
unsigned
int
/* length */
,
struct
sockaddr
*
,
bool
);
extern
unsigned
int
_GetXid
(
void
);
extern
void
_FreeXid
(
unsigned
int
);
#define GetXid() (int)_GetXid(); cFYI(1,("CIFS VFS: in %s as Xid: %d with uid: %d",__func__, xid,current->fsuid));
...
...
sources/2.6.27/cifssmb.c
View file @
4a267003
...
...
@@ -190,10 +190,10 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
/* need to prevent multiple threads trying to
simultaneously reconnect the same SMB session */
down
(
&
tcon
->
ses
->
sesSem
);
if
(
tcon
->
ses
->
status
==
CifsNeedR
econnect
)
if
(
tcon
->
ses
->
need_r
econnect
)
rc
=
cifs_setup_session
(
0
,
tcon
->
ses
,
nls_codepage
);
if
(
!
rc
&&
(
tcon
->
tidStatus
==
CifsNeedR
econnect
))
{
if
(
!
rc
&&
(
tcon
->
need_r
econnect
))
{
mark_open_files_invalid
(
tcon
);
rc
=
CIFSTCon
(
0
,
tcon
->
ses
,
tcon
->
treeName
,
tcon
,
nls_codepage
);
...
...
@@ -337,10 +337,10 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
/* need to prevent multiple threads trying to
simultaneously reconnect the same SMB session */
down
(
&
tcon
->
ses
->
sesSem
);
if
(
tcon
->
ses
->
status
==
CifsNeedR
econnect
)
if
(
tcon
->
ses
->
need_r
econnect
)
rc
=
cifs_setup_session
(
0
,
tcon
->
ses
,
nls_codepage
);
if
(
!
rc
&&
(
tcon
->
tidStatus
==
CifsNeedR
econnect
))
{
if
(
!
rc
&&
(
tcon
->
need_r
econnect
))
{
mark_open_files_invalid
(
tcon
);
rc
=
CIFSTCon
(
0
,
tcon
->
ses
,
tcon
->
treeName
,
tcon
,
nls_codepage
);
...
...
@@ -664,8 +664,9 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
rc
=
-
EIO
;
goto
neg_err_exit
;
}
if
(
server
->
socketUseCount
.
counter
>
1
)
{
read_lock
(
&
cifs_tcp_ses_lock
);
if
(
server
->
srv_count
>
1
)
{
read_unlock
(
&
cifs_tcp_ses_lock
);
if
(
memcmp
(
server
->
server_GUID
,
pSMBr
->
u
.
extended_response
.
GUID
,
16
)
!=
0
)
{
...
...
@@ -674,9 +675,11 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
pSMBr
->
u
.
extended_response
.
GUID
,
16
);
}
}
else
}
else
{
read_unlock
(
&
cifs_tcp_ses_lock
);
memcpy
(
server
->
server_GUID
,
pSMBr
->
u
.
extended_response
.
GUID
,
16
);
}
if
(
count
==
16
)
{
server
->
secType
=
RawNTLMSSP
;
...
...
@@ -739,48 +742,29 @@ CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
int
rc
=
0
;
cFYI
(
1
,
(
"In tree disconnect"
));
/*
* If last user of the connection and
* connection alive - disconnect it
* If this is the last connection on the server session disconnect it
* (and inside session disconnect we should check if tcp socket needs
* to be freed and kernel thread woken up).
*/
if
(
tcon
)
down
(
&
tcon
->
tconSem
);
else
return
-
EIO
;
atomic_dec
(
&
tcon
->
useCount
);
if
(
atomic_read
(
&
tcon
->
useCount
)
>
0
)
{
up
(
&
tcon
->
tconSem
);
return
-
EBUSY
;
}
/* BB: do we need to check this? These should never be NULL. */
if
((
tcon
->
ses
==
NULL
)
||
(
tcon
->
ses
->
server
==
NULL
))
return
-
EIO
;
/* No need to return error on this operation if tid invalidated and
closed on server already e.g. due to tcp session crashing */
if
(
tcon
->
tidStatus
==
CifsNeedReconnect
)
{
up
(
&
tcon
->
tconSem
);
/*
* No need to return error on this operation if tid invalidated and
* closed on server already e.g. due to tcp session crashing. Also,
* the tcon is no longer on the list, so no need to take lock before
* checking this.
*/
if
(
tcon
->
need_reconnect
)
return
0
;
}
if
((
tcon
->
ses
==
NULL
)
||
(
tcon
->
ses
->
server
==
NULL
))
{
up
(
&
tcon
->
tconSem
);
return
-
EIO
;
}
rc
=
small_smb_init
(
SMB_COM_TREE_DISCONNECT
,
0
,
tcon
,
(
void
**
)
&
smb_buffer
);
if
(
rc
)
{
up
(
&
tcon
->
tconSem
);
if
(
rc
)
return
rc
;
}
rc
=
SendReceiveNoRsp
(
xid
,
tcon
->
ses
,
smb_buffer
,
0
);
if
(
rc
)
cFYI
(
1
,
(
"Tree disconnect failed %d"
,
rc
));
up
(
&
tcon
->
tconSem
);
/* No need to return error on this operation if tid invalidated and
closed on server already e.g. due to tcp session crashing */
if
(
rc
==
-
EAGAIN
)
...
...
@@ -796,43 +780,36 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
int
rc
=
0
;
cFYI
(
1
,
(
"In SMBLogoff for session disconnect"
));
if
(
ses
)
down
(
&
ses
->
sesSem
);
else
/*
* BB: do we need to check validity of ses and server? They should
* always be valid since we have an active reference. If not, that
* should probably be a BUG()
*/
if
(
!
ses
||
!
ses
->
server
)
return
-
EIO
;
atomic_dec
(
&
ses
->
inUse
);
if
(
atomic_read
(
&
ses
->
inUse
)
>
0
)
{
up
(
&
ses
->
sesSem
);
return
-
EBUSY
;
}
down
(
&
ses
->
sesSem
);
if
(
ses
->
need_reconnect
)
goto
session_already_dead
;
/* no need to send SMBlogoff if uid
already closed due to reconnect */
rc
=
small_smb_init
(
SMB_COM_LOGOFF_ANDX
,
2
,
NULL
,
(
void
**
)
&
pSMB
);
if
(
rc
)
{
up
(
&
ses
->
sesSem
);
return
rc
;
}
if
(
ses
->
server
)
{
pSMB
->
hdr
.
Mid
=
GetNextMid
(
ses
->
server
);
if
(
ses
->
server
->
secMode
&
(
SECMODE_SIGN_REQUIRED
|
SECMODE_SIGN_ENABLED
))
pSMB
->
hdr
.
Flags2
|=
SMBFLG2_SECURITY_SIGNATURE
;
}
pSMB
->
hdr
.
Uid
=
ses
->
Suid
;
pSMB
->
AndXCommand
=
0xFF
;
rc
=
SendReceiveNoRsp
(
xid
,
ses
,
(
struct
smb_hdr
*
)
pSMB
,
0
);
if
(
ses
->
server
)
{
atomic_dec
(
&
ses
->
server
->
socketUseCount
);
if
(
atomic_read
(
&
ses
->
server
->
socketUseCount
)
==
0
)
{
spin_lock
(
&
GlobalMid_Lock
);
ses
->
server
->
tcpStatus
=
CifsExiting
;
spin_unlock
(
&
GlobalMid_Lock
);
rc
=
-
ESHUTDOWN
;
}
}
session_already_dead:
up
(
&
ses
->
sesSem
);
/* if session dead then we do not need to do ulogoff,
...
...
@@ -1539,7 +1516,7 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
__u32
bytes_sent
;
__u16
byte_count
;
/* cFYI(1,("write at %lld %d bytes",offset,count));*/
/* cFYI(1,
("write at %lld %d bytes",offset,count));*/
if
(
tcon
->
ses
==
NULL
)
return
-
ECONNABORTED
;
...
...
sources/2.6.27/connect.c
View file @
4a267003
...
...
@@ -90,6 +90,8 @@ struct smb_vol {
bool
nocase
:
1
;
/* request case insensitive filenames */
bool
nobrl
:
1
;
/* disable sending byte range locks to srv */
bool
seal
:
1
;
/* request transport encryption on share */
bool
noblocksnd
:
1
;
bool
noautotune
:
1
;
unsigned
int
rsize
;
unsigned
int
wsize
;
unsigned
int
sockopt
;
...
...
@@ -100,9 +102,11 @@ struct smb_vol {
static
int
ipv4_connect
(
struct
sockaddr_in
*
psin_server
,
struct
socket
**
csocket
,
char
*
netb_name
,
char
*
server_netb_name
);
char
*
server_netb_name
,
bool
noblocksnd
,
bool
nosndbuf
);
/* ipv6 never set sndbuf size */
static
int
ipv6_connect
(
struct
sockaddr_in6
*
psin_server
,
struct
socket
**
csocket
);
struct
socket
**
csocket
,
bool
noblocksnd
);
/*
...
...
@@ -118,7 +122,7 @@ static int
cifs_reconnect
(
struct
TCP_Server_Info
*
server
)
{
int
rc
=
0
;
struct
list_head
*
tmp
;
struct
list_head
*
tmp
,
*
tmp2
;
struct
cifsSesInfo
*
ses
;
struct
cifsTconInfo
*
tcon
;
struct
mid_q_entry
*
mid_entry
;
...
...
@@ -138,23 +142,17 @@ cifs_reconnect(struct TCP_Server_Info *server)
/* before reconnecting the tcp session, mark the smb session (uid)
and the tid bad so they are not used until reconnected */
read_lock
(
&
GlobalSMBSeslock
);
list_for_each
(
tmp
,
&
GlobalSMBSessionList
)
{
ses
=
list_entry
(
tmp
,
struct
cifsSesInfo
,
cifsSessionList
);
if
(
ses
->
server
)
{
if
(
ses
->
server
==
server
)
{
ses
->
status
=
CifsNeedReconnect
;
read_lock
(
&
cifs_tcp_ses_lock
);
list_for_each
(
tmp
,
&
server
->
smb_ses_list
)
{
ses
=
list_entry
(
tmp
,
struct
cifsSesInfo
,
smb_ses_list
);
ses
->
need_reconnect
=
true
;
ses
->
ipc_tid
=
0
;
list_for_each
(
tmp2
,
&
ses
->
tcon_list
)
{
tcon
=
list_entry
(
tmp2
,
struct
cifsTconInfo
,
tcon_list
);
tcon
->
need_reconnect
=
true
;
}
}
/* else tcp and smb sessions need reconnection */
}
list_for_each
(
tmp
,
&
GlobalTreeConnectionList
)
{
tcon
=
list_entry
(
tmp
,
struct
cifsTconInfo
,
cifsConnectionList
);
if
((
tcon
->
ses
)
&&
(
tcon
->
ses
->
server
==
server
))
tcon
->
tidStatus
=
CifsNeedReconnect
;
}
read_unlock
(
&
GlobalSMBSeslock
);
read_unlock
(
&
cifs_tcp_ses_lock
);
/* do not want to be sending data on a socket we are freeing */
down
(
&
server
->
tcpSem
);
if
(
server
->
ssocket
)
{
...
...
@@ -186,14 +184,15 @@ cifs_reconnect(struct TCP_Server_Info *server)
while
((
!
kthread_should_stop
())
&&
(
server
->
tcpStatus
!=
CifsGood
))
{
try_to_freeze
();
if
(
server
->
protocolType
==
IPV
6
)
{
if
(
server
->
addr
.
sockAddr6
.
sin6_family
==
AF_INET
6
)
{
rc
=
ipv6_connect
(
&
server
->
addr
.
sockAddr6
,
&
server
->
ssocket
);
&
server
->
ssocket
,
server
->
noautotune
);
}
else
{
rc
=
ipv4_connect
(
&
server
->
addr
.
sockAddr
,
&
server
->
ssocket
,
server
->
workstation_RFC1001_name
,
server
->
server_RFC1001_name
);
server
->
server_RFC1001_name
,
server
->
noblocksnd
,
server
->
noautotune
);
}
if
(
rc
)
{
cFYI
(
1
,
(
"reconnect error %d"
,
rc
));
...
...
@@ -409,8 +408,14 @@ incomplete_rcv:
msleep
(
1
);
/* minimum sleep to prevent looping
allowing socket to clear and app threads to set
tcpStatus CifsNeedReconnect if server hung */
if
(
pdu_length
<
4
)
if
(
pdu_length
<
4
)
{
iov
.
iov_base
=
(
4
-
pdu_length
)
+
(
char
*
)
smb_buffer
;
iov
.
iov_len
=
pdu_length
;
smb_msg
.
msg_control
=
NULL
;
smb_msg
.
msg_controllen
=
0
;
goto
incomplete_rcv
;
}
else
continue
;
}
else
if
(
length
<=
0
)
{
...
...
@@ -646,6 +651,11 @@ multi_t2_fnd:
}
}
/* end while !EXITING */
/* take it off the list, if it's not already */
write_lock
(
&
cifs_tcp_ses_lock
);
list_del_init
(
&
server
->
tcp_ses_list
);
write_unlock
(
&
cifs_tcp_ses_lock
);
spin_lock
(
&
GlobalMid_Lock
);
server
->
tcpStatus
=
CifsExiting
;
spin_unlock
(
&
GlobalMid_Lock
);
...
...
@@ -686,28 +696,28 @@ multi_t2_fnd:
if
(
smallbuf
)
/* no sense logging a debug message if NULL */
cifs_small_buf_release
(
smallbuf
);
read_lock
(
&
GlobalSMBSeslock
);
/*
* BB: we shouldn't have to do any of this. It shouldn't be
* possible to exit from the thread with active SMB sessions
*/
read_lock
(
&
cifs_tcp_ses_lock
);
if
(
list_empty
(
&
server
->
pending_mid_q
))
{
/* loop through server session structures attached to this and
mark them dead */
list_for_each
(
tmp
,
&
GlobalSMBSessionList
)
{
ses
=
list_entry
(
tmp
,
struct
cifsSesInfo
,
cifsSessionList
);
if
(
ses
->
server
==
server
)
{
list_for_each
(
tmp
,
&
server
->
smb_ses_list
)
{
ses
=
list_entry
(
tmp
,
struct
cifsSesInfo
,
smb_ses_list
);
ses
->
status
=
CifsExiting
;
ses
->
server
=
NULL
;
}
}
read_unlock
(
&
GlobalSMBSeslock
);
read_unlock
(
&
cifs_tcp_ses_lock
);
}
else
{
/* although we can not zero the server struct pointer yet,
since there are active requests which may depnd on them,
mark the corresponding SMB sessions as exiting too */
list_for_each
(
tmp
,
&
GlobalSMBSessionL
ist
)
{
list_for_each
(
tmp
,
&
server
->
smb_ses_l
ist
)
{
ses
=
list_entry
(
tmp
,
struct
cifsSesInfo
,
cifsSessionList
);
if
(
ses
->
server
==
server
)
smb_ses_list
);
ses
->
status
=
CifsExiting
;
}
...
...
@@ -723,7 +733,7 @@ multi_t2_fnd:
}
}
spin_unlock
(
&
GlobalMid_Lock
);
read_unlock
(
&
GlobalSMBSes
lock
);
read_unlock
(
&
cifs_tcp_ses_
lock
);
/* 1/8th of sec is more than enough time for them to exit */
msleep
(
125
);
}
...
...
@@ -745,14 +755,13 @@ multi_t2_fnd:
if there are any pointing to this (e.g
if a crazy root user tried to kill cifsd
kernel thread explicitly this might happen) */
write_lock
(
&
GlobalSMBSeslock
);
list_for_each
(
tmp
,
&
GlobalSMBSessionList
)
{
ses
=
list_entry
(
tmp
,
struct
cifsSesInfo
,
cifsSessionList
);
if
(
ses
->
server
==
server
)
/* BB: This shouldn't be necessary, see above */
read_lock
(
&
cifs_tcp_ses_lock
);
list_for_each
(
tmp
,
&
server
->
smb_ses_list
)
{
ses
=
list_entry
(
tmp
,
struct
cifsSesInfo
,
smb_ses_list
);
ses
->
server
=
NULL
;
}
write_unlock
(
&
GlobalSMBSes
lock
);
read_unlock
(
&
cifs_tcp_ses_
lock
);
kfree
(
server
->
hostname
);
kfree
(
server
);
...
...
@@ -1186,6 +1195,10 @@ cifs_parse_mount_options(char *options, const char *devname,
/* ignore */
}
else
if
(
strnicmp
(
data
,
"rw"
,
2
)
==
0
)
{
vol
->
rw
=
true
;
}
else
if
(
strnicmp
(
data
,
"noblocksnd"
,
11
)
==
0
)
{
vol
->
noblocksnd
=
true
;
}
else
if
(
strnicmp
(
data
,
"noautotune"
,
10
)
==
0
)
{
vol
->
noautotune
=
true
;
}
else
if
((
strnicmp
(
data
,
"suid"
,
4
)
==
0
)
||
(
strnicmp
(
data
,
"nosuid"
,
6
)
==
0
)
||
(
strnicmp
(
data
,
"exec"
,
4
)
==
0
)
||
...
...
@@ -1331,94 +1344,158 @@ cifs_parse_mount_options(char *options, const char *devname,
return
0
;
}
static
struct
cifsSesInfo
*
cifs_find_tcp_session
(
struct
in_addr
*
target_ip_addr
,
struct
in6_addr
*
target_ip6_addr
,
char
*
userName
,
struct
TCP_Server_Info
**
psrvTcp
)
static
struct
TCP_Server_Info
*
cifs_find_tcp_session
(
struct
sockaddr
*
addr
)
{
struct
list_head
*
tmp
;
struct
cifsSesInfo
*
ses
;
*
psrvTcp
=
NULL
;
read_lock
(
&
GlobalSMBSeslock
);
list_for_each
(
tmp
,
&
GlobalSMBSessionList
)
{
ses
=
list_entry
(
tmp
,
struct
cifsSesInfo
,
cifsSessionList
);
if
(
!
ses
->
server
)
struct
TCP_Server_Info
*
server
;
struct
sockaddr_in
*
addr4
=
(
struct
sockaddr_in
*
)
addr
;
struct
sockaddr_in6
*
addr6
=
(
struct
sockaddr_in6
*
)
addr
;
write_lock
(
&
cifs_tcp_ses_lock
);
list_for_each
(
tmp
,
&
cifs_tcp_ses_list
)
{
server
=
list_entry
(
tmp
,
struct
TCP_Server_Info
,
tcp_ses_list
);
/*
* the demux thread can exit on its own while still in CifsNew
* so don't accept any sockets in that state. Since the
* tcpStatus never changes back to CifsNew it's safe to check
* for this without a lock.
*/
if
(
server
->
tcpStatus
==
CifsNew
)
continue
;
if
(
target_ip_addr
&&
ses
->
server
->
addr
.
sockAddr
.
sin_addr
.
s_addr
!=
target_ip_addr
->
s_addr
)
if
(
addr
->
sa_family
==
AF_INET
&&
(
addr4
->
sin_addr
.
s_addr
!=
server
->
addr
.
sockAddr
.
sin_addr
.
s_addr
))
continue
;
else
if
(
target_ip6_addr
&&
memcmp
(
&
se
s
->
se
rver
->
addr
.
sockAddr6
.
sin6_addr
,
target_ip6_addr
,
sizeof
(
*
target_ip
6_addr
)))
else
if
(
addr
->
sa_family
==
AF_INET6
&&
memcmp
(
&
server
->
addr
.
sockAddr6
.
sin6_addr
,
&
addr6
->
sin6_addr
,
sizeof
(
addr6
->
sin
6_addr
)))
continue
;
/* BB lock server and tcp session; increment use count here?? */
/* found a match on the TCP session */
*
psrvTcp
=
ses
->
server
;
/* BB check if reconnection needed */
if
(
strncmp
(
ses
->
userName
,
userName
,
MAX_USERNAME_SIZE
)
==
0
)
{
read_unlock
(
&
GlobalSMBSeslock
);
/* Found exact match on both TCP and
SMB sessions */
return
ses
;
++
server
->
srv_count
;
write_unlock
(
&
cifs_tcp_ses_lock
);
cFYI
(
1
,
(
"Existing tcp session with server found"
));
return
server
;
}
/* else tcp and smb sessions need reconnection */
write_unlock
(
&
cifs_tcp_ses_lock
);
return
NULL
;
}
static
void
cifs_put_tcp_session
(
struct
TCP_Server_Info
*
server
)
{
struct
task_struct
*
task
;
write_lock
(
&
cifs_tcp_ses_lock
);
if
(
--
server
->
srv_count
>
0
)
{
write_unlock
(
&
cifs_tcp_ses_lock
);
return
;
}
read_unlock
(
&
GlobalSMBSeslock
);
return
NULL
;
list_del_init
(
&
server
->
tcp_ses_list
);
write_unlock
(
&
cifs_tcp_ses_lock
);
spin_lock
(
&
GlobalMid_Lock
);
server
->
tcpStatus
=
CifsExiting
;
spin_unlock
(
&
GlobalMid_Lock
);
task
=
xchg
(
&
server
->
tsk
,
NULL
);
if
(
task
)
force_sig
(
SIGKILL
,
task
);
}
static
struct
cifs
Tcon
Info
*
find_unc
(
__be32
new_target_ip_addr
,
char
*
uncName
,
char
*
userN
ame
)
static
struct
cifs
Ses
Info
*
cifs_find_smb_ses
(
struct
TCP_Server_Info
*
server
,
char
*
usern
ame
)
{
struct
list_head
*
tmp
;
struct
cifsTconInfo
*
tcon
;
__be32
old_ip
;
read_lock
(
&
GlobalSMBSeslock
);
struct
cifsSesInfo
*
ses
;
list_for_each
(
tmp
,
&
GlobalTreeConnectionList
)
{
cFYI
(
1
,
(
"Next tcon"
));
tcon
=
list_entry
(
tmp
,
struct
cifsTconInfo
,
cifsConnectionL
ist
);
if
(
!
tcon
->
ses
||
!
tcon
->
ses
->
server
)
write_lock
(
&
cifs_tcp_ses_lock
);
list_for_each
(
tmp
,
&
server
->
smb_ses_list
)
{
ses
=
list_entry
(
tmp
,
struct
cifsSesInfo
,
smb_ses_l
ist
);
if
(
strncmp
(
ses
->
userName
,
username
,
MAX_USERNAME_SIZE
)
)
continue
;
old_ip
=
tcon
->
ses
->
server
->
addr
.
sockAddr
.
sin_addr
.
s_addr
;
cFYI
(
1
,
(
"old ip addr: %x == new ip %x ?"
,
old_ip
,
new_target_ip_addr
));
++
ses
->
ses_count
;
write_unlock
(
&
cifs_tcp_ses_lock
);
return
ses
;
}
write_unlock
(
&
cifs_tcp_ses_lock
);
return
NULL
;
}
static
void
cifs_put_smb_ses
(
struct
cifsSesInfo
*
ses
)
{
int
xid
;
struct
TCP_Server_Info
*
server
=
ses
->
server
;
if
(
old_ip
!=
new_target_ip_addr
)
continue
;
write_lock
(
&
cifs_tcp_ses_lock
);
if
(
--
ses
->
ses_count
>
0
)
{
write_unlock
(
&
cifs_tcp_ses_lock
);
return
;
}
/* BB lock tcon, server, tcp session and increment use count? */
/* found a match on the TCP session */
/* BB check if reconnection needed */
cFYI
(
1
,
(
"IP match, old UNC: %s new: %s"
,
tcon
->
treeName
,
uncName
));
list_del_init
(
&
ses
->
smb_ses_list
);
write_unlock
(
&
cifs_tcp_ses_lock
);
if
(
strncmp
(
tcon
->
treeName
,
uncName
,
MAX_TREE_SIZE
))
continue
;
if
(
ses
->
status
==
CifsGood
)
{
xid
=
GetXid
();
CIFSSMBLogoff
(
xid
,
ses
);
_FreeXid
(
xid
);
}
sesInfoFree
(
ses
);
cifs_put_tcp_session
(
server
);
}
cFYI
(
1
,
(
"and old usr: %s new: %s"
,
tcon
->
treeName
,
uncName
));
static
struct
cifsTconInfo
*
cifs_find_tcon
(
struct
cifsSesInfo
*
ses
,
const
char
*
unc
)
{
struct
list_head
*
tmp
;
struct
cifsTconInfo
*
tcon
;
if
(
strncmp
(
tcon
->
ses
->
userName
,
userName
,
MAX_USERNAME_SIZE
))
write_lock
(
&
cifs_tcp_ses_lock
);
list_for_each
(
tmp
,
&
ses
->
tcon_list
)
{
tcon
=
list_entry
(
tmp
,
struct
cifsTconInfo
,
tcon_list
);
if
(
tcon
->
tidStatus
==
CifsExiting
)
continue
;
if
(
strncmp
(
tcon
->
treeName
,
unc
,
MAX_TREE_SIZE
))
continue
;
/* matched smb session (user name) */
read_unlock
(
&
GlobalSMBSes
lock
);
++
tcon
->
tc_count
;
write_unlock
(
&
cifs_tcp_ses_
lock
);
return
tcon
;
}
read_unlock
(
&
GlobalSMBSeslock
);
write_unlock
(
&
cifs_tcp_ses_lock
);
return
NULL
;
}
static
void
cifs_put_tcon
(
struct
cifsTconInfo
*
tcon
)
{
int
xid
;
struct
cifsSesInfo
*
ses
=
tcon
->
ses
;
write_lock
(
&
cifs_tcp_ses_lock
);
if
(
--
tcon
->
tc_count
>
0
)
{
write_unlock
(
&
cifs_tcp_ses_lock
);
return
;
}
list_del_init
(
&
tcon
->
tcon_list
);
write_unlock
(
&
cifs_tcp_ses_lock
);
xid
=
GetXid
();
CIFSSMBTDis
(
xid
,
tcon
);
_FreeXid
(
xid
);
DeleteTconOplockQEntries
(
tcon
);
tconInfoFree
(
tcon
);
cifs_put_smb_ses
(
ses
);
}
int
get_dfs_path
(
int
xid
,
struct
cifsSesInfo
*
pSesInfo
,
const
char
*
old_path
,
const
struct
nls_table
*
nls_codepage
,
unsigned
int
*
pnum_referrals
,
...
...
@@ -1506,7 +1583,8 @@ static void rfc1002mangle(char *target, char *source, unsigned int length)
static
int
ipv4_connect
(
struct
sockaddr_in
*
psin_server
,
struct
socket
**
csocket
,
char
*
netbios_name
,
char
*
target_name
)
char
*
netbios_name
,
char
*
target_name
,
bool
noblocksnd
,
bool
noautotune
)
{
int
rc
=
0
;
int
connected
=
0
;
...
...
@@ -1578,11 +1656,15 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
(
*
csocket
)
->
sk
->
sk_sndbuf
,
(
*
csocket
)
->
sk
->
sk_rcvbuf
,
(
*
csocket
)
->
sk
->
sk_rcvtimeo
));
(
*
csocket
)
->
sk
->
sk_rcvtimeo
=
7
*
HZ
;
if
(
!
noblocksnd
)
(
*
csocket
)
->
sk
->
sk_sndtimeo
=
3
*
HZ
;
/* make the bufsizes depend on wsize/rsize and max requests */
if
(
noautotune
)
{
if
((
*
csocket
)
->
sk
->
sk_sndbuf
<
(
200
*
1024
))
(
*
csocket
)
->
sk
->
sk_sndbuf
=
200
*
1024
;
if
((
*
csocket
)
->
sk
->
sk_rcvbuf
<
(
140
*
1024
))
(
*
csocket
)
->
sk
->
sk_rcvbuf
=
140
*
1024
;
}
/* send RFC1001 sessinit */
if
(
psin_server
->
sin_port
==
htons
(
RFC1001_PORT
))
{
...
...
@@ -1619,7 +1701,7 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
/* sizeof RFC1002_SESSION_REQUEST with no scope */
smb_buf
->
smb_buf_length
=
0x81000044
;
rc
=
smb_send
(
*
csocket
,
smb_buf
,
0x44
,
(
struct
sockaddr
*
)
psin_server
);
(
struct
sockaddr
*
)
psin_server
,
noblocksnd
);
kfree
(
ses_init_buf
);
msleep
(
1
);
/* RFC1001 layer in at least one server
requires very short break before negprot
...
...
@@ -1639,7 +1721,8 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
}
static
int
ipv6_connect
(
struct
sockaddr_in6
*
psin_server
,
struct
socket
**
csocket
)
ipv6_connect
(
struct
sockaddr_in6
*
psin_server
,
struct
socket
**
csocket
,
bool
noblocksnd
)
{
int
rc
=
0
;
int
connected
=
0
;
...
...
@@ -1708,6 +1791,8 @@ ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
the default. sock_setsockopt not used because it expects
user space buffer */
(
*
csocket
)
->
sk
->
sk_rcvtimeo
=
7
*
HZ
;
if
(
!
noblocksnd
)
(
*
csocket
)
->
sk
->
sk_sndtimeo
=
3
*
HZ
;
return
rc
;
}
...
...
@@ -1845,19 +1930,104 @@ convert_delimiter(char *path, char delim)
}
}
static
void
setup_cifs_sb
(
struct
smb_vol
*
pvolume_info
,
struct
cifs_sb_info
*
cifs_sb
)
{
if
(
pvolume_info
->
rsize
>
CIFSMaxBufSize
)
{
cERROR
(
1
,
(
"rsize %d too large, using MaxBufSize"
,
pvolume_info
->
rsize
));
cifs_sb
->
rsize
=
CIFSMaxBufSize
;
}
else
if
((
pvolume_info
->
rsize
)
&&
(
pvolume_info
->
rsize
<=
CIFSMaxBufSize
))
cifs_sb
->
rsize
=
pvolume_info
->
rsize
;
else
/* default */
cifs_sb
->
rsize
=
CIFSMaxBufSize
;
if
(
pvolume_info
->
wsize
>
PAGEVEC_SIZE
*
PAGE_CACHE_SIZE
)
{
cERROR
(
1
,
(
"wsize %d too large, using 4096 instead"
,
pvolume_info
->
wsize
));
cifs_sb
->
wsize
=
4096
;
}
else
if
(
pvolume_info
->
wsize
)
cifs_sb
->
wsize
=
pvolume_info
->
wsize
;
else
cifs_sb
->
wsize
=
min_t
(
const
int
,
PAGEVEC_SIZE
*
PAGE_CACHE_SIZE
,
127
*
1024
);
/* old default of CIFSMaxBufSize was too small now
that SMB Write2 can send multiple pages in kvec.
RFC1001 does not describe what happens when frame
bigger than 128K is sent so use that as max in
conjunction with 52K kvec constraint on arch with 4K
page size */
if
(
cifs_sb
->
rsize
<
2048
)
{
cifs_sb
->
rsize
=
2048
;
/* Windows ME may prefer this */
cFYI
(
1
,
(
"readsize set to minimum: 2048"
));
}
/* calculate prepath */
cifs_sb
->
prepath
=
pvolume_info
->
prepath
;
if
(
cifs_sb
->
prepath
)
{
cifs_sb
->
prepathlen
=
strlen
(
cifs_sb
->
prepath
);
/* we can not convert the / to \ in the path
separators in the prefixpath yet because we do not
know (until reset_cifs_unix_caps is called later)
whether POSIX PATH CAP is available. We normalize
the / to \ after reset_cifs_unix_caps is called */
pvolume_info
->
prepath
=
NULL
;
}
else
cifs_sb
->
prepathlen
=
0
;
cifs_sb
->
mnt_uid
=
pvolume_info
->
linux_uid
;
cifs_sb
->
mnt_gid
=
pvolume_info
->
linux_gid
;
cifs_sb
->
mnt_file_mode
=
pvolume_info
->
file_mode
;
cifs_sb
->
mnt_dir_mode
=
pvolume_info
->
dir_mode
;
cFYI
(
1
,
(
"file mode: 0x%x dir mode: 0x%x"
,
cifs_sb
->
mnt_file_mode
,
cifs_sb
->
mnt_dir_mode
));
if
(
pvolume_info
->
noperm
)
cifs_sb
->
mnt_cifs_flags
|=
CIFS_MOUNT_NO_PERM
;
if
(
pvolume_info
->
setuids
)
cifs_sb
->
mnt_cifs_flags
|=
CIFS_MOUNT_SET_UID
;
if
(
pvolume_info
->
server_ino
)
cifs_sb
->
mnt_cifs_flags
|=
CIFS_MOUNT_SERVER_INUM
;
if
(
pvolume_info
->
remap
)
cifs_sb
->
mnt_cifs_flags
|=
CIFS_MOUNT_MAP_SPECIAL_CHR
;
if
(
pvolume_info
->
no_xattr
)
cifs_sb
->
mnt_cifs_flags
|=
CIFS_MOUNT_NO_XATTR
;
if
(
pvolume_info
->
sfu_emul
)
cifs_sb
->
mnt_cifs_flags
|=
CIFS_MOUNT_UNX_EMUL
;
if
(
pvolume_info
->
nobrl
)
cifs_sb
->
mnt_cifs_flags
|=
CIFS_MOUNT_NO_BRL
;
if
(
pvolume_info
->
cifs_acl
)
cifs_sb
->
mnt_cifs_flags
|=
CIFS_MOUNT_CIFS_ACL
;
if
(
pvolume_info
->
override_uid
)
cifs_sb
->
mnt_cifs_flags
|=
CIFS_MOUNT_OVERR_UID
;
if
(
pvolume_info
->
override_gid
)
cifs_sb
->
mnt_cifs_flags
|=
CIFS_MOUNT_OVERR_GID
;
if
(
pvolume_info
->
dynperm
)
cifs_sb
->
mnt_cifs_flags
|=
CIFS_MOUNT_DYNPERM
;
if
(
pvolume_info
->
direct_io
)
{
cFYI
(
1
,
(
"mounting share using direct i/o"
));
cifs_sb
->
mnt_cifs_flags
|=
CIFS_MOUNT_DIRECT_IO
;
}
if
((
pvolume_info
->
cifs_acl
)
&&
(
pvolume_info
->
dynperm
))
cERROR
(
1
,
(
"mount option dynperm ignored if cifsacl "
"mount option supported"
));
}
int
cifs_mount
(
struct
super_block
*
sb
,
struct
cifs_sb_info
*
cifs_sb
,
char
*
mount_data
,
const
char
*
devname
)
{
int
rc
=
0
;
int
xid
;
int
address_type
=
AF_INET
;
struct
socket
*
csocket
=
NULL
;
struct
sockaddr_in
sin_server
;
struct
sockaddr_in6
sin_server6
;
struct
sockaddr
addr
;
struct
sockaddr_in
*
sin_server
=
(
struct
sockaddr_in
*
)
&
addr
;
struct
sockaddr_in6
*
sin_server6
=
(
struct
sockaddr_in6
*
)
&
addr
;
struct
smb_vol
volume_info
;
struct
cifsSesInfo
*
pSesInfo
=
NULL
;
struct
cifsSesInfo
*
existingCifsSes
=
NULL
;
struct
cifsTconInfo
*
tcon
=
NULL
;
struct
TCP_Server_Info
*
srvTcp
=
NULL
;
...
...
@@ -1865,6 +2035,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
memset
(
&
addr
,
0
,
sizeof
(
struct
sockaddr
));
memset
(
&
volume_info
,
0
,
sizeof
(
struct
smb_vol
));
if
(
cifs_parse_mount_options
(
mount_data
,
devname
,
&
volume_info
))
{
rc
=
-
EINVAL
;
...
...
@@ -1887,16 +2058,16 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
if
(
volume_info
.
UNCip
&&
volume_info
.
UNC
)
{
rc
=
cifs_inet_pton
(
AF_INET
,
volume_info
.
UNCip
,
&
sin_server
.
sin_addr
.
s_addr
);
&
sin_server
->
sin_addr
.
s_addr
);
if
(
rc
<=
0
)
{
/* not ipv4 address, try ipv6 */
rc
=
cifs_inet_pton
(
AF_INET6
,
volume_info
.
UNCip
,
&
sin_server6
.
sin6_addr
.
in6_u
);
&
sin_server6
->
sin6_addr
.
in6_u
);
if
(
rc
>
0
)
addr
ess_type
=
AF_INET6
;
addr
.
sa_family
=
AF_INET6
;
}
else
{
addr
ess_type
=
AF_INET
;
addr
.
sa_family
=
AF_INET
;
}
if
(
rc
<=
0
)
{
...
...
@@ -1936,38 +2107,25 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
}
}
if
(
address_type
==
AF_INET
)
existingCifsSes
=
cifs_find_tcp_session
(
&
sin_server
.
sin_addr
,
NULL
/* no ipv6 addr */
,
volume_info
.
username
,
&
srvTcp
);
else
if
(
address_type
==
AF_INET6
)
{
cFYI
(
1
,
(
"looking for ipv6 address"
));
existingCifsSes
=
cifs_find_tcp_session
(
NULL
/* no ipv4 addr */
,
&
sin_server6
.
sin6_addr
,
volume_info
.
username
,
&
srvTcp
);
}
else
{
rc
=
-
EINVAL
;
goto
out
;
}
if
(
srvTcp
)
{
cFYI
(
1
,
(
"Existing tcp session with server found"
));
}
else
{
/* create socket */
if
(
volume_info
.
port
)
sin_server
.
sin_port
=
htons
(
volume_info
.
port
);
else
sin_server
.
sin_port
=
0
;
if
(
address_type
==
AF_INET6
)
{
srvTcp
=
cifs_find_tcp_session
(
&
addr
);
if
(
!
srvTcp
)
{
/* create socket */
if
(
addr
.
sa_family
==
AF_INET6
)
{
cFYI
(
1
,
(
"attempting ipv6 connect"
));
/* BB should we allow ipv6 on port 139? */
/* other OS never observed in Wild doing 139 with v6 */
rc
=
ipv6_connect
(
&
sin_server6
,
&
csocket
);
}
else
rc
=
ipv4_connect
(
&
sin_server
,
&
csocket
,
sin_server6
->
sin6_port
=
htons
(
volume_info
.
port
);
rc
=
ipv6_connect
(
sin_server6
,
&
csocket
,
volume_info
.
noblocksnd
);
}
else
{
sin_server
->
sin_port
=
htons
(
volume_info
.
port
);
rc
=
ipv4_connect
(
sin_server
,
&
csocket
,
volume_info
.
source_rfc1001_name
,
volume_info
.
target_rfc1001_name
);
volume_info
.
target_rfc1001_name
,
volume_info
.
noblocksnd
,
volume_info
.
noautotune
);
}
if
(
rc
<
0
)
{
cERROR
(
1
,
(
"Error connecting to
IPv4
socket. "
cERROR
(
1
,
(
"Error connecting to socket. "
"Aborting operation"
));
if
(
csocket
!=
NULL
)
sock_release
(
csocket
);
...
...
@@ -1980,12 +2138,17 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
sock_release
(
csocket
);
goto
out
;
}
else
{
memcpy
(
&
srvTcp
->
addr
.
sockAddr
,
&
sin_server
,
srvTcp
->
noblocksnd
=
volume_info
.
noblocksnd
;
srvTcp
->
noautotune
=
volume_info
.
noautotune
;
if
(
addr
.
sa_family
==
AF_INET6
)
memcpy
(
&
srvTcp
->
addr
.
sockAddr6
,
sin_server6
,
sizeof
(
struct
sockaddr_in6
));
else
memcpy
(
&
srvTcp
->
addr
.
sockAddr
,
sin_server
,
sizeof
(
struct
sockaddr_in
));
atomic_set
(
&
srvTcp
->
inFlight
,
0
);
/* BB Add code for ipv6 case too */
srvTcp
->
ssocket
=
csocket
;
srvTcp
->
protocolType
=
IPV4
;
srvTcp
->
hostname
=
extract_hostname
(
volume_info
.
UNC
);
if
(
IS_ERR
(
srvTcp
->
hostname
))
{
rc
=
PTR_ERR
(
srvTcp
->
hostname
);
...
...
@@ -2015,15 +2178,28 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
memcpy
(
srvTcp
->
server_RFC1001_name
,
volume_info
.
target_rfc1001_name
,
16
);
srvTcp
->
sequence_number
=
0
;
INIT_LIST_HEAD
(
&
srvTcp
->
tcp_ses_list
);
INIT_LIST_HEAD
(
&
srvTcp
->
smb_ses_list
);
++
srvTcp
->
srv_count
;
write_lock
(
&
cifs_tcp_ses_lock
);
list_add
(
&
srvTcp
->
tcp_ses_list
,
&
cifs_tcp_ses_list
);
write_unlock
(
&
cifs_tcp_ses_lock
);
}
}
if
(
existingCifsSes
)
{
pSesInfo
=
existingCifsSes
;
pSesInfo
=
cifs_find_smb_ses
(
srvTcp
,
volume_info
.
username
);
if
(
pSesInfo
)
{
cFYI
(
1
,
(
"Existing smb sess found (status=%d)"
,
pSesInfo
->
status
));
/*
* The existing SMB session already has a reference to srvTcp,
* so we can put back the extra one we got before
*/
cifs_put_tcp_session
(
srvTcp
);
down
(
&
pSesInfo
->
sesSem
);
if
(
pSesInfo
->
status
==
CifsNeedR
econnect
)
{
if
(
pSesInfo
->
need_r
econnect
)
{
cFYI
(
1
,
(
"Session needs reconnect"
));
rc
=
cifs_setup_session
(
xid
,
pSesInfo
,
cifs_sb
->
local_nls
);
...
...
@@ -2032,15 +2208,20 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
}
else
if
(
!
rc
)
{
cFYI
(
1
,
(
"Existing smb sess not found"
));
pSesInfo
=
sesInfoAlloc
();
if
(
pSesInfo
==
NULL
)
if
(
pSesInfo
==
NULL
)
{
rc
=
-
ENOMEM
;
else
{
goto
mount_fail_check
;
}
/* new SMB session uses our srvTcp ref */
pSesInfo
->
server
=
srvTcp
;
sprintf
(
pSesInfo
->
serverName
,
"%u.%u.%u.%u"
,
NIPQUAD
(
sin_server
.
sin_addr
.
s_addr
));
}
NIPQUAD
(
sin_server
->
sin_addr
.
s_addr
));
write_lock
(
&
cifs_tcp_ses_lock
);
list_add
(
&
pSesInfo
->
smb_ses_list
,
&
srvTcp
->
smb_ses_list
);
write_unlock
(
&
cifs_tcp_ses_lock
);
if
(
!
rc
)
{
/* volume_info.password freed at unmount */
if
(
volume_info
.
password
)
{
pSesInfo
->
password
=
volume_info
.
password
;
...
...
@@ -2048,13 +2229,11 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
volume_info
.
password
=
NULL
;
}
if
(
volume_info
.
username
)
strncpy
(
pSesInfo
->
userName
,
volume_info
.
username
,
strncpy
(
pSesInfo
->
userName
,
volume_info
.
username
,
MAX_USERNAME_SIZE
);
if
(
volume_info
.
domainname
)
{
int
len
=
strlen
(
volume_info
.
domainname
);
pSesInfo
->
domainName
=
kmalloc
(
len
+
1
,
GFP_KERNEL
);
pSesInfo
->
domainName
=
kmalloc
(
len
+
1
,
GFP_KERNEL
);
if
(
pSesInfo
->
domainName
)
strcpy
(
pSesInfo
->
domainName
,
volume_info
.
domainname
);
...
...
@@ -2062,150 +2241,61 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
pSesInfo
->
linux_uid
=
volume_info
.
linux_uid
;
pSesInfo
->
overrideSecFlg
=
volume_info
.
secFlg
;
down
(
&
pSesInfo
->
sesSem
);
/* BB FIXME need to pass vol->secFlgs BB */
rc
=
cifs_setup_session
(
xid
,
pSesInfo
,
cifs_sb
->
local_nls
);
up
(
&
pSesInfo
->
sesSem
);
if
(
!
rc
)
atomic_inc
(
&
srvTcp
->
socketUseCount
);
}
}
/* search for existing tcon to this server share */
if
(
!
rc
)
{
if
(
volume_info
.
rsize
>
CIFSMaxBufSize
)
{
cERROR
(
1
,
(
"rsize %d too large, using MaxBufSize"
,
volume_info
.
rsize
));
cifs_sb
->
rsize
=
CIFSMaxBufSize
;
}
else
if
((
volume_info
.
rsize
)
&&
(
volume_info
.
rsize
<=
CIFSMaxBufSize
))
cifs_sb
->
rsize
=
volume_info
.
rsize
;
else
/* default */
cifs_sb
->
rsize
=
CIFSMaxBufSize
;
if
(
volume_info
.
wsize
>
PAGEVEC_SIZE
*
PAGE_CACHE_SIZE
)
{
cERROR
(
1
,
(
"wsize %d too large, using 4096 instead"
,
volume_info
.
wsize
));
cifs_sb
->
wsize
=
4096
;
}
else
if
(
volume_info
.
wsize
)
cifs_sb
->
wsize
=
volume_info
.
wsize
;
else
cifs_sb
->
wsize
=
min_t
(
const
int
,
PAGEVEC_SIZE
*
PAGE_CACHE_SIZE
,
127
*
1024
);
/* old default of CIFSMaxBufSize was too small now
that SMB Write2 can send multiple pages in kvec.
RFC1001 does not describe what happens when frame
bigger than 128K is sent so use that as max in
conjunction with 52K kvec constraint on arch with 4K
page size */
if
(
cifs_sb
->
rsize
<
2048
)
{
cifs_sb
->
rsize
=
2048
;
/* Windows ME may prefer this */
cFYI
(
1
,
(
"readsize set to minimum: 2048"
));
}
/* calculate prepath */
cifs_sb
->
prepath
=
volume_info
.
prepath
;
if
(
cifs_sb
->
prepath
)
{
cifs_sb
->
prepathlen
=
strlen
(
cifs_sb
->
prepath
);
/* we can not convert the / to \ in the path
separators in the prefixpath yet because we do not
know (until reset_cifs_unix_caps is called later)
whether POSIX PATH CAP is available. We normalize
the / to \ after reset_cifs_unix_caps is called */
volume_info
.
prepath
=
NULL
;
}
else
cifs_sb
->
prepathlen
=
0
;
cifs_sb
->
mnt_uid
=
volume_info
.
linux_uid
;
cifs_sb
->
mnt_gid
=
volume_info
.
linux_gid
;
cifs_sb
->
mnt_file_mode
=
volume_info
.
file_mode
;
cifs_sb
->
mnt_dir_mode
=
volume_info
.
dir_mode
;
cFYI
(
1
,
(
"file mode: 0x%x dir mode: 0x%x"
,
cifs_sb
->
mnt_file_mode
,
cifs_sb
->
mnt_dir_mode
));
if
(
volume_info
.
noperm
)
cifs_sb
->
mnt_cifs_flags
|=
CIFS_MOUNT_NO_PERM
;
if
(
volume_info
.
setuids
)
cifs_sb
->
mnt_cifs_flags
|=
CIFS_MOUNT_SET_UID
;
if
(
volume_info
.
server_ino
)
cifs_sb
->
mnt_cifs_flags
|=
CIFS_MOUNT_SERVER_INUM
;
if
(
volume_info
.
remap
)
cifs_sb
->
mnt_cifs_flags
|=
CIFS_MOUNT_MAP_SPECIAL_CHR
;
if
(
volume_info
.
no_xattr
)
cifs_sb
->
mnt_cifs_flags
|=
CIFS_MOUNT_NO_XATTR
;
if
(
volume_info
.
sfu_emul
)
cifs_sb
->
mnt_cifs_flags
|=
CIFS_MOUNT_UNX_EMUL
;
if
(
volume_info
.
nobrl
)
cifs_sb
->
mnt_cifs_flags
|=
CIFS_MOUNT_NO_BRL
;
if
(
volume_info
.
cifs_acl
)
cifs_sb
->
mnt_cifs_flags
|=
CIFS_MOUNT_CIFS_ACL
;
if
(
volume_info
.
override_uid
)
cifs_sb
->
mnt_cifs_flags
|=
CIFS_MOUNT_OVERR_UID
;
if
(
volume_info
.
override_gid
)
cifs_sb
->
mnt_cifs_flags
|=
CIFS_MOUNT_OVERR_GID
;
if
(
volume_info
.
dynperm
)
cifs_sb
->
mnt_cifs_flags
|=
CIFS_MOUNT_DYNPERM
;
if
(
volume_info
.
direct_io
)
{
cFYI
(
1
,
(
"mounting share using direct i/o"
));
cifs_sb
->
mnt_cifs_flags
|=
CIFS_MOUNT_DIRECT_IO
;
}
if
((
volume_info
.
cifs_acl
)
&&
(
volume_info
.
dynperm
))
cERROR
(
1
,
(
"mount option dynperm ignored if cifsacl "
"mount option supported"
));
tcon
=
find_unc
(
sin_server
.
sin_addr
.
s_addr
,
volume_info
.
UNC
,
volume_info
.
username
);
setup_cifs_sb
(
&
volume_info
,
cifs_sb
);
tcon
=
cifs_find_tcon
(
pSesInfo
,
volume_info
.
UNC
);
if
(
tcon
)
{
cFYI
(
1
,
(
"Found match on UNC path"
));
/* we can have only one retry value for a connection
to a share so for resources mounted more than once
to the same server share the last value passed in
for the retry flag is used */
tcon
->
retry
=
volume_info
.
retry
;
tcon
->
nocase
=
volume_info
.
nocase
;
/* existing tcon already has a reference */
cifs_put_smb_ses
(
pSesInfo
);
if
(
tcon
->
seal
!=
volume_info
.
seal
)
cERROR
(
1
,
(
"transport encryption setting "
"conflicts with existing tid"
));
}
else
{
tcon
=
tconInfoAlloc
();
if
(
tcon
==
NULL
)
if
(
tcon
==
NULL
)
{
rc
=
-
ENOMEM
;
else
{
/* check for null share name ie connecting to
* dfs root */
goto
mount_fail_check
;
}
tcon
->
ses
=
pSesInfo
;
/* BB check if this works for exactly length
* three strings */
/* check for null share name ie connect to dfs root */
if
((
strchr
(
volume_info
.
UNC
+
3
,
'\\'
)
==
NULL
)
&&
(
strchr
(
volume_info
.
UNC
+
3
,
'/'
)
==
NULL
))
{
/* rc = connect_to_dfs_path(xid, pSesInfo,
"", cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);*/
&&
(
strchr
(
volume_info
.
UNC
+
3
,
'/'
)
==
NULL
))
{
/* rc = connect_to_dfs_path(...) */
cFYI
(
1
,
(
"DFS root not supported"
));
rc
=
-
ENODEV
;
goto
out
;
goto
mount_fail_check
;
}
else
{
/* BB Do we need to wrap sesSem around
* this TCon call and Unix SetFS as
* we do on SessSetup and reconnect? */
rc
=
CIFSTCon
(
xid
,
pSesInfo
,
volume_info
.
UNC
,
rc
=
CIFSTCon
(
xid
,
pSesInfo
,
volume_info
.
UNC
,
tcon
,
cifs_sb
->
local_nls
);
cFYI
(
1
,
(
"CIFS Tcon rc = %d"
,
rc
));
}
if
(
!
rc
)
{
atomic_inc
(
&
pSesInfo
->
inUse
);
tcon
->
retry
=
volume_info
.
retry
;
tcon
->
nocase
=
volume_info
.
nocase
;
if
(
rc
)
goto
mount_fail_check
;
tcon
->
seal
=
volume_info
.
seal
;
write_lock
(
&
cifs_tcp_ses_lock
);
list_add
(
&
tcon
->
tcon_list
,
&
pSesInfo
->
tcon_list
);
write_unlock
(
&
cifs_tcp_ses_lock
);
}
}
}
/* we can have only one retry value for a connection
to a share so for resources mounted more than once
to the same server share the last value passed in
for the retry flag is used */
tcon
->
retry
=
volume_info
.
retry
;
tcon
->
nocase
=
volume_info
.
nocase
;
}
if
(
pSesInfo
)
{
if
(
pSesInfo
->
capabilities
&
CAP_LARGE_FILES
)
{
...
...
@@ -2217,57 +2307,20 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
/* BB FIXME fix time_gran to be larger for LANMAN sessions */
sb
->
s_time_gran
=
100
;
/* on error free sesinfo and tcon struct if needed */
/* on error free sesinfo and tcon struct if needed */
mount_fail_check:
if
(
rc
)
{
/* if session setup failed, use count is zero but
we still need to free cifsd thread */
if
(
atomic_read
(
&
srvTcp
->
socketUseCount
)
==
0
)
{
spin_lock
(
&
GlobalMid_Lock
);
srvTcp
->
tcpStatus
=
CifsExiting
;
spin_unlock
(
&
GlobalMid_Lock
);
if
(
srvTcp
->
tsk
)
{
/* If we could verify that kthread_stop would
always wake up processes blocked in
tcp in recv_mesg then we could remove the
send_sig call */
force_sig
(
SIGKILL
,
srvTcp
->
tsk
);
kthread_stop
(
srvTcp
->
tsk
);
}
}
/* If find_unc succeeded then rc == 0 so we can not end */
if
(
tcon
)
/* up accidently freeing someone elses tcon struct */
tconInfoFree
(
tcon
);
if
(
existingCifsSes
==
NULL
)
{
if
(
pSesInfo
)
{
if
((
pSesInfo
->
server
)
&&
(
pSesInfo
->
status
==
CifsGood
))
{
int
temp_rc
;
temp_rc
=
CIFSSMBLogoff
(
xid
,
pSesInfo
);
/* if the socketUseCount is now zero */
if
((
temp_rc
==
-
ESHUTDOWN
)
&&
(
pSesInfo
->
server
)
&&
(
pSesInfo
->
server
->
tsk
))
{
force_sig
(
SIGKILL
,
pSesInfo
->
server
->
tsk
);
kthread_stop
(
pSesInfo
->
server
->
tsk
);
}
}
else
{
cFYI
(
1
,
(
"No session or bad tcon"
));
if
((
pSesInfo
->
server
)
&&
(
pSesInfo
->
server
->
tsk
))
{
force_sig
(
SIGKILL
,
pSesInfo
->
server
->
tsk
);
kthread_stop
(
pSesInfo
->
server
->
tsk
);
}
}
sesInfoFree
(
pSesInfo
);
/* pSesInfo = NULL; */
}
/* up accidently freeing someone elses tcon struct */
if
(
tcon
)
cifs_put_tcon
(
tcon
);
else
if
(
pSesInfo
)
cifs_put_smb_ses
(
pSesInfo
);
else
cifs_put_tcp_session
(
srvTcp
);
goto
out
;
}
}
else
{
atomic_inc
(
&
tcon
->
useCount
);
cifs_sb
->
tcon
=
tcon
;
tcon
->
ses
=
pSesInfo
;
/* do not care if following two calls succeed - informational */
if
(
!
tcon
->
ipc
)
{
...
...
@@ -2285,23 +2338,18 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
/* convert forward to back slashes in prepath here if needed */
if
((
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_POSIX_PATHS
)
==
0
)
convert_delimiter
(
cifs_sb
->
prepath
,
CIFS_DIR_SEP
(
cifs_sb
));
convert_delimiter
(
cifs_sb
->
prepath
,
CIFS_DIR_SEP
(
cifs_sb
));
if
((
tcon
->
unix_ext
==
0
)
&&
(
cifs_sb
->
rsize
>
(
1024
*
127
)))
{
cifs_sb
->
rsize
=
1024
*
127
;
cFYI
(
DBG2
,
(
"no very large read support, rsize now 127K"
));
cFYI
(
DBG2
,
(
"no very large read support, rsize now 127K"
));
}
if
(
!
(
tcon
->
ses
->
capabilities
&
CAP_LARGE_WRITE_X
))
cifs_sb
->
wsize
=
min
(
cifs_sb
->
wsize
,
(
tcon
->
ses
->
server
->
maxBuf
-
MAX_CIFS_HDR_SIZE
));
(
tcon
->
ses
->
server
->
maxBuf
-
MAX_CIFS_HDR_SIZE
));
if
(
!
(
tcon
->
ses
->
capabilities
&
CAP_LARGE_READ_X
))
cifs_sb
->
rsize
=
min
(
cifs_sb
->
rsize
,
(
tcon
->
ses
->
server
->
maxBuf
-
MAX_CIFS_HDR_SIZE
));
}
(
tcon
->
ses
->
server
->
maxBuf
-
MAX_CIFS_HDR_SIZE
));
/* volume_info.password is freed above when existing session found
(in which case it is not needed anymore) but when new sesion is created
...
...
@@ -3471,6 +3519,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
/* above now done in SendReceive */
if
((
rc
==
0
)
&&
(
tcon
!=
NULL
))
{
tcon
->
tidStatus
=
CifsGood
;
tcon
->
need_reconnect
=
false
;
tcon
->
tid
=
smb_buffer_response
->
Tid
;
bcc_ptr
=
pByteArea
(
smb_buffer_response
);
length
=
strnlen
(
bcc_ptr
,
BCC
(
smb_buffer_response
)
-
2
);
...
...
@@ -3542,52 +3591,17 @@ int
cifs_umount
(
struct
super_block
*
sb
,
struct
cifs_sb_info
*
cifs_sb
)
{
int
rc
=
0
;
int
xid
;
struct
cifsSesInfo
*
ses
=
NULL
;
struct
task_struct
*
cifsd_task
;
char
*
tmp
;
xid
=
GetXid
();
if
(
cifs_sb
->
tcon
)
{
ses
=
cifs_sb
->
tcon
->
ses
;
/* save ptr to ses before delete tcon!*/
rc
=
CIFSSMBTDis
(
xid
,
cifs_sb
->
tcon
);
if
(
rc
==
-
EBUSY
)
{
FreeXid
(
xid
);
return
0
;
}
DeleteTconOplockQEntries
(
cifs_sb
->
tcon
);
tconInfoFree
(
cifs_sb
->
tcon
);
if
((
ses
)
&&
(
ses
->
server
))
{
/* save off task so we do not refer to ses later */
cifsd_task
=
ses
->
server
->
tsk
;
cFYI
(
1
,
(
"About to do SMBLogoff "
));
rc
=
CIFSSMBLogoff
(
xid
,
ses
);
if
(
rc
==
-
EBUSY
)
{
FreeXid
(
xid
);
return
0
;
}
else
if
(
rc
==
-
ESHUTDOWN
)
{
cFYI
(
1
,
(
"Waking up socket by sending signal"
));
if
(
cifsd_task
)
{
force_sig
(
SIGKILL
,
cifsd_task
);
kthread_stop
(
cifsd_task
);
}
rc
=
0
;
}
/* else - we have an smb session
left on this socket do not kill cifsd */
}
else
cFYI
(
1
,
(
"No session or bad tcon"
));
}
if
(
cifs_sb
->
tcon
)
cifs_put_tcon
(
cifs_sb
->
tcon
);
cifs_sb
->
tcon
=
NULL
;
tmp
=
cifs_sb
->
prepath
;
cifs_sb
->
prepathlen
=
0
;
cifs_sb
->
prepath
=
NULL
;
kfree
(
tmp
);
if
(
ses
)
sesInfoFree
(
ses
);
FreeXid
(
xid
);
return
rc
;
}
...
...
@@ -3702,6 +3716,7 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
}
else
{
cFYI
(
1
,
(
"CIFS Session Established successfully"
));
pSesInfo
->
status
=
CifsGood
;
pSesInfo
->
need_reconnect
=
false
;
}
ss_err_exit:
...
...
sources/2.6.27/file.c
View file @
4a267003
...
...
@@ -502,7 +502,7 @@ int cifs_close(struct inode *inode, struct file *file)
if
(
pTcon
)
{
/* no sense reconnecting to close a file that is
already closed */
if
(
pTcon
->
tidStatus
!=
CifsNeedR
econnect
)
{
if
(
!
pTcon
->
need_r
econnect
)
{
timeout
=
2
;
while
((
atomic_read
(
&
pSMBFile
->
wrtPending
)
!=
0
)
&&
(
timeout
<=
2048
))
{
...
...
@@ -1405,7 +1405,10 @@ retry:
if
((
wbc
->
nr_to_write
-=
n_iov
)
<=
0
)
done
=
1
;
index
=
next
;
}
}
else
/* Need to re-find the pages we skipped */
index
=
pvec
.
pages
[
0
]
->
index
+
1
;
pagevec_release
(
&
pvec
);
}
if
(
!
scanned
&&
!
done
)
{
...
...
sources/2.6.27/misc.c
View file @
4a267003
...
...
@@ -75,12 +75,12 @@ sesInfoAlloc(void)
ret_buf
=
kzalloc
(
sizeof
(
struct
cifsSesInfo
),
GFP_KERNEL
);
if
(
ret_buf
)
{
write_lock
(
&
GlobalSMBSeslock
);
atomic_inc
(
&
sesInfoAllocCount
);
ret_buf
->
status
=
CifsNew
;
list_add
(
&
ret_buf
->
cifsSessionList
,
&
GlobalSMBSessionList
);
++
ret_buf
->
ses_count
;
INIT_LIST_HEAD
(
&
ret_buf
->
smb_ses_list
);
INIT_LIST_HEAD
(
&
ret_buf
->
tcon_list
);
init_MUTEX
(
&
ret_buf
->
sesSem
);
write_unlock
(
&
GlobalSMBSeslock
);
}
return
ret_buf
;
}
...
...
@@ -93,10 +93,7 @@ sesInfoFree(struct cifsSesInfo *buf_to_free)
return
;
}
write_lock
(
&
GlobalSMBSeslock
);
atomic_dec
(
&
sesInfoAllocCount
);
list_del
(
&
buf_to_free
->
cifsSessionList
);
write_unlock
(
&
GlobalSMBSeslock
);
kfree
(
buf_to_free
->
serverOS
);
kfree
(
buf_to_free
->
serverDomain
);
kfree
(
buf_to_free
->
serverNOS
);
...
...
@@ -111,17 +108,14 @@ tconInfoAlloc(void)
struct
cifsTconInfo
*
ret_buf
;
ret_buf
=
kzalloc
(
sizeof
(
struct
cifsTconInfo
),
GFP_KERNEL
);
if
(
ret_buf
)
{
write_lock
(
&
GlobalSMBSeslock
);
atomic_inc
(
&
tconInfoAllocCount
);
list_add
(
&
ret_buf
->
cifsConnectionList
,
&
GlobalTreeConnectionList
);
ret_buf
->
tidStatus
=
CifsNew
;
++
ret_buf
->
tc_count
;
INIT_LIST_HEAD
(
&
ret_buf
->
openFileList
);
init_MUTEX
(
&
ret_buf
->
tconSem
);
INIT_LIST_HEAD
(
&
ret_buf
->
tcon_list
);
#ifdef CONFIG_CIFS_STATS
spin_lock_init
(
&
ret_buf
->
stat_lock
);
#endif
write_unlock
(
&
GlobalSMBSeslock
);
}
return
ret_buf
;
}
...
...
@@ -133,10 +127,7 @@ tconInfoFree(struct cifsTconInfo *buf_to_free)
cFYI
(
1
,
(
"Null buffer passed to tconInfoFree"
));
return
;
}
write_lock
(
&
GlobalSMBSeslock
);
atomic_dec
(
&
tconInfoAllocCount
);
list_del
(
&
buf_to_free
->
cifsConnectionList
);
write_unlock
(
&
GlobalSMBSeslock
);
kfree
(
buf_to_free
->
nativeFileSystem
);
kfree
(
buf_to_free
);
}
...
...
@@ -354,9 +345,9 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
if
(
current
->
fsuid
!=
treeCon
->
ses
->
linux_uid
)
{
cFYI
(
1
,
(
"Multiuser mode and UID "
"did not match tcon uid"
));
read_lock
(
&
GlobalSMBSes
lock
);
list_for_each
(
temp_item
,
&
GlobalSMBSessionL
ist
)
{
ses
=
list_entry
(
temp_item
,
struct
cifsSesInfo
,
cifsSessionL
ist
);
read_lock
(
&
cifs_tcp_ses_
lock
);
list_for_each
(
temp_item
,
&
treeCon
->
ses
->
server
->
smb_ses_l
ist
)
{
ses
=
list_entry
(
temp_item
,
struct
cifsSesInfo
,
smb_ses_l
ist
);
if
(
ses
->
linux_uid
==
current
->
fsuid
)
{
if
(
ses
->
server
==
treeCon
->
ses
->
server
)
{
cFYI
(
1
,
(
"found matching uid substitute right smb_uid"
));
...
...
@@ -368,7 +359,7 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
}
}
}
read_unlock
(
&
GlobalSMBSes
lock
);
read_unlock
(
&
cifs_tcp_ses_
lock
);
}
}
}
...
...
@@ -501,9 +492,10 @@ bool
is_valid_oplock_break
(
struct
smb_hdr
*
buf
,
struct
TCP_Server_Info
*
srv
)
{
struct
smb_com_lock_req
*
pSMB
=
(
struct
smb_com_lock_req
*
)
buf
;
struct
list_head
*
tmp
;
struct
list_head
*
tmp1
;
struct
list_head
*
tmp
,
*
tmp1
,
*
tmp2
;
struct
cifsSesInfo
*
ses
;
struct
cifsTconInfo
*
tcon
;
struct
cifsInodeInfo
*
pCifsInode
;
struct
cifsFileInfo
*
netfile
;
cFYI
(
1
,
(
"Checking for oplock break or dnotify response"
));
...
...
@@ -558,42 +550,42 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
return
false
;
/* look up tcon based on tid & uid */
read_lock
(
&
GlobalSMBSeslock
);
list_for_each
(
tmp
,
&
GlobalTreeConnectionList
)
{
tcon
=
list_entry
(
tmp
,
struct
cifsTconInfo
,
cifsConnectionList
);
if
((
tcon
->
tid
==
buf
->
Tid
)
&&
(
srv
==
tcon
->
ses
->
server
))
{
read_lock
(
&
cifs_tcp_ses_lock
);
list_for_each
(
tmp
,
&
srv
->
smb_ses_list
)
{
ses
=
list_entry
(
tmp
,
struct
cifsSesInfo
,
smb_ses_list
);
list_for_each
(
tmp1
,
&
ses
->
tcon_list
)
{
tcon
=
list_entry
(
tmp1
,
struct
cifsTconInfo
,
tcon_list
);
if
(
tcon
->
tid
!=
buf
->
Tid
)
continue
;
cifs_stats_inc
(
&
tcon
->
num_oplock_brks
);
list_for_each
(
tmp
1
,
&
tcon
->
openFileList
)
{
netfile
=
list_entry
(
tmp
1
,
struct
cifsFileInfo
,
list_for_each
(
tmp
2
,
&
tcon
->
openFileList
)
{
netfile
=
list_entry
(
tmp
2
,
struct
cifsFileInfo
,
tlist
);
if
(
pSMB
->
Fid
==
netfile
->
netfid
)
{
struct
cifsInodeInfo
*
pCifsInode
;
read_unlock
(
&
GlobalSMBSeslock
);
cFYI
(
1
,
(
"file id match, oplock break"
));
pCifsInode
=
CIFS_I
(
netfile
->
pInode
);
if
(
pSMB
->
Fid
!=
netfile
->
netfid
)
continue
;
read_unlock
(
&
cifs_tcp_ses_lock
);
cFYI
(
1
,
(
"file id match, oplock break"
));
pCifsInode
=
CIFS_I
(
netfile
->
pInode
);
pCifsInode
->
clientCanCacheAll
=
false
;
if
(
pSMB
->
OplockLevel
==
0
)
pCifsInode
->
clientCanCacheRead
=
false
;
pCifsInode
->
clientCanCacheRead
=
false
;
pCifsInode
->
oplockPending
=
true
;
AllocOplockQEntry
(
netfile
->
pInode
,
netfile
->
netfid
,
tcon
);
cFYI
(
1
,
(
"about to wake up oplock thread"
));
netfile
->
netfid
,
tcon
);
cFYI
(
1
,
(
"about to wake up oplock thread"
));
if
(
oplockThread
)
wake_up_process
(
oplockThread
);
return
true
;
}
}
read_unlock
(
&
GlobalSMBSeslock
);
read_unlock
(
&
cifs_tcp_ses_lock
);
cFYI
(
1
,
(
"No matching file for oplock break"
));
return
true
;
}
}
read_unlock
(
&
GlobalSMBSes
lock
);
read_unlock
(
&
cifs_tcp_ses_
lock
);
cFYI
(
1
,
(
"Can not process oplock break for non-existent connection"
));
return
true
;
}
...
...
sources/2.6.27/transport.c
View file @
4a267003
...
...
@@ -162,7 +162,7 @@ void DeleteTconOplockQEntries(struct cifsTconInfo *tcon)
int
smb_send
(
struct
socket
*
ssocket
,
struct
smb_hdr
*
smb_buffer
,
unsigned
int
smb_buf_length
,
struct
sockaddr
*
sin
)
unsigned
int
smb_buf_length
,
struct
sockaddr
*
sin
,
bool
noblocksnd
)
{
int
rc
=
0
;
int
i
=
0
;
...
...
@@ -179,7 +179,10 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
smb_msg
.
msg_namelen
=
sizeof
(
struct
sockaddr
);
smb_msg
.
msg_control
=
NULL
;
smb_msg
.
msg_controllen
=
0
;
smb_msg
.
msg_flags
=
MSG_DONTWAIT
+
MSG_NOSIGNAL
;
/* BB add more flags?*/
if
(
noblocksnd
)
smb_msg
.
msg_flags
=
MSG_DONTWAIT
+
MSG_NOSIGNAL
;
else
smb_msg
.
msg_flags
=
MSG_NOSIGNAL
;
/* smb header is converted in header_assemble. bcc and rest of SMB word
area, and byte area if necessary, is converted to littleendian in
...
...
@@ -230,8 +233,8 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
}
static
int
smb_send2
(
struct
socket
*
ssocket
,
struct
kvec
*
iov
,
int
n_vec
,
struct
sockaddr
*
sin
)
smb_send2
(
struct
TCP_Server_Info
*
server
,
struct
kvec
*
iov
,
int
n_vec
,
struct
sockaddr
*
sin
,
bool
noblocksnd
)
{
int
rc
=
0
;
int
i
=
0
;
...
...
@@ -241,6 +244,7 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
unsigned
int
total_len
;
int
first_vec
=
0
;
unsigned
int
smb_buf_length
=
smb_buffer
->
smb_buf_length
;
struct
socket
*
ssocket
=
server
->
ssocket
;
if
(
ssocket
==
NULL
)
return
-
ENOTSOCK
;
/* BB eventually add reconnect code here */
...
...
@@ -249,7 +253,10 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
smb_msg
.
msg_namelen
=
sizeof
(
struct
sockaddr
);
smb_msg
.
msg_control
=
NULL
;
smb_msg
.
msg_controllen
=
0
;
smb_msg
.
msg_flags
=
MSG_DONTWAIT
+
MSG_NOSIGNAL
;
/* BB add more flags?*/
if
(
noblocksnd
)
smb_msg
.
msg_flags
=
MSG_DONTWAIT
+
MSG_NOSIGNAL
;
else
smb_msg
.
msg_flags
=
MSG_NOSIGNAL
;
/* smb header is converted in header_assemble. bcc and rest of SMB word
area, and byte area if necessary, is converted to littleendian in
...
...
@@ -284,8 +291,11 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
if
(
rc
<
0
)
break
;
if
(
rc
>=
total_len
)
{
WARN_ON
(
rc
>
total_len
);
if
(
rc
==
total_len
)
{
total_len
=
0
;
break
;
}
else
if
(
rc
>
total_len
)
{
cERROR
(
1
,
(
"sent %d requested %d"
,
rc
,
total_len
));
break
;
}
if
(
rc
==
0
)
{
...
...
@@ -313,6 +323,16 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
i
=
0
;
/* in case we get ENOSPC on the next send */
}
if
((
total_len
>
0
)
&&
(
total_len
!=
smb_buf_length
+
4
))
{
cFYI
(
1
,
(
"partial send (%d remaining), terminating session"
,
total_len
));
/* If we have only sent part of an SMB then the next SMB
could be taken as the remainder of this one. We need
to kill the socket so the server throws away the partial
SMB */
server
->
tcpStatus
=
CifsNeedReconnect
;
}
if
(
rc
<
0
)
{
cERROR
(
1
,
(
"Error %d sending data on socket to server"
,
rc
));
}
else
...
...
@@ -519,8 +539,9 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
#ifdef CONFIG_CIFS_STATS2
atomic_inc
(
&
ses
->
server
->
inSend
);
#endif
rc
=
smb_send2
(
ses
->
server
->
ssocket
,
iov
,
n_vec
,
(
struct
sockaddr
*
)
&
(
ses
->
server
->
addr
.
sockAddr
));
rc
=
smb_send2
(
ses
->
server
,
iov
,
n_vec
,
(
struct
sockaddr
*
)
&
(
ses
->
server
->
addr
.
sockAddr
),
ses
->
server
->
noblocksnd
);
#ifdef CONFIG_CIFS_STATS2
atomic_dec
(
&
ses
->
server
->
inSend
);
midQ
->
when_sent
=
jiffies
;
...
...
@@ -712,7 +733,8 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
atomic_inc
(
&
ses
->
server
->
inSend
);
#endif
rc
=
smb_send
(
ses
->
server
->
ssocket
,
in_buf
,
in_buf
->
smb_buf_length
,
(
struct
sockaddr
*
)
&
(
ses
->
server
->
addr
.
sockAddr
));
(
struct
sockaddr
*
)
&
(
ses
->
server
->
addr
.
sockAddr
),
ses
->
server
->
noblocksnd
);
#ifdef CONFIG_CIFS_STATS2
atomic_dec
(
&
ses
->
server
->
inSend
);
midQ
->
when_sent
=
jiffies
;
...
...
@@ -852,7 +874,8 @@ send_nt_cancel(struct cifsTconInfo *tcon, struct smb_hdr *in_buf,
return
rc
;
}
rc
=
smb_send
(
ses
->
server
->
ssocket
,
in_buf
,
in_buf
->
smb_buf_length
,
(
struct
sockaddr
*
)
&
(
ses
->
server
->
addr
.
sockAddr
));
(
struct
sockaddr
*
)
&
(
ses
->
server
->
addr
.
sockAddr
),
ses
->
server
->
noblocksnd
);
up
(
&
ses
->
server
->
tcpSem
);
return
rc
;
}
...
...
@@ -942,7 +965,8 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
atomic_inc
(
&
ses
->
server
->
inSend
);
#endif
rc
=
smb_send
(
ses
->
server
->
ssocket
,
in_buf
,
in_buf
->
smb_buf_length
,
(
struct
sockaddr
*
)
&
(
ses
->
server
->
addr
.
sockAddr
));
(
struct
sockaddr
*
)
&
(
ses
->
server
->
addr
.
sockAddr
),
ses
->
server
->
noblocksnd
);
#ifdef CONFIG_CIFS_STATS2
atomic_dec
(
&
ses
->
server
->
inSend
);
midQ
->
when_sent
=
jiffies
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment