Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
754d4c9b
Commit
754d4c9b
authored
Jun 08, 2004
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Plain Diff
Merge
bk://cifs.bkbits.net/linux-2.5cifs
into ppc970.osdl.org:/home/torvalds/v2.6/linux
parents
b8611623
ce0025eb
Changes
13
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
376 additions
and
112 deletions
+376
-112
fs/cifs/AUTHORS
fs/cifs/AUTHORS
+4
-1
fs/cifs/CHANGES
fs/cifs/CHANGES
+9
-0
fs/cifs/cifs_debug.c
fs/cifs/cifs_debug.c
+63
-33
fs/cifs/cifsfs.h
fs/cifs/cifsfs.h
+1
-1
fs/cifs/cifspdu.h
fs/cifs/cifspdu.h
+37
-17
fs/cifs/cifsproto.h
fs/cifs/cifsproto.h
+3
-0
fs/cifs/cifssmb.c
fs/cifs/cifssmb.c
+54
-3
fs/cifs/connect.c
fs/cifs/connect.c
+43
-11
fs/cifs/dir.c
fs/cifs/dir.c
+16
-5
fs/cifs/fcntl.c
fs/cifs/fcntl.c
+17
-1
fs/cifs/file.c
fs/cifs/file.c
+113
-35
fs/cifs/inode.c
fs/cifs/inode.c
+16
-4
fs/cifs/transport.c
fs/cifs/transport.c
+0
-1
No files found.
fs/cifs/AUTHORS
View file @
754d4c9b
...
@@ -23,6 +23,7 @@ Amrut Joshi
...
@@ -23,6 +23,7 @@ Amrut Joshi
Shobhit Dayal
Shobhit Dayal
Sergey Vlasov
Sergey Vlasov
Richard Hughes
Richard Hughes
Yury Umanets
Test case and Bug Report contributors
Test case and Bug Report contributors
-------------------------------------
-------------------------------------
...
@@ -30,5 +31,7 @@ Thanks to those in the community who have submitted detailed bug reports
...
@@ -30,5 +31,7 @@ Thanks to those in the community who have submitted detailed bug reports
and debug of problems they have found: Jochen Dolze, David Blaine,
and debug of problems they have found: Jochen Dolze, David Blaine,
Rene Scharfe, Martin Josefsson, Alexander Wild, Anthony Liguori,
Rene Scharfe, Martin Josefsson, Alexander Wild, Anthony Liguori,
Lars Muller, Urban Widmark, Massimiliano Ferrero, Howard Owen,
Lars Muller, Urban Widmark, Massimiliano Ferrero, Howard Owen,
Kieron Briggs and others.
Olaf Kirch,
Kieron Briggs and others.
And thanks to the IBM LTC and Power test teams and SuSE testers for
finding multiple bugs during excellent stress test runs.
fs/cifs/CHANGES
View file @
754d4c9b
Version 1.17
------------
Update number of blocks in file so du command is happier (in Linux a fake
blocksize of 512 is required for calculating number of blocks in inode).
Fix prepare write of partial pages to read in data from server if possible.
Fix race on tcpStatus field between unmount and reconnection code, causing
cifsd process sometimes to hang around forever. Improve out of memory
checks in cifs_filldir
Version 1.16
Version 1.16
------------
------------
Fix incorrect file size in file handle based setattr on big endian hardware.
Fix incorrect file size in file handle based setattr on big endian hardware.
...
...
fs/cifs/cifs_debug.c
View file @
754d4c9b
...
@@ -142,30 +142,10 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
...
@@ -142,30 +142,10 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
sprintf
(
buf
,
" type: %d "
,
sprintf
(
buf
,
" type: %d "
,
tcon
->
fsDevInfo
.
DeviceType
);
tcon
->
fsDevInfo
.
DeviceType
);
buf
+=
length
;
buf
+=
length
;
if
(
tcon
->
tidStatus
==
CifsNeedReconnect
)
if
(
tcon
->
tidStatus
==
CifsNeedReconnect
)
{
buf
+=
sprintf
(
buf
,
"
\t
DISCONNECTED "
);
buf
+=
sprintf
(
buf
,
"
\t
DISCONNECTED "
);
#ifdef CONFIG_CIFS_STATS
length
+=
14
;
length
=
sprintf
(
buf
,
"
\n
SMBs: %d Oplock Breaks: %d"
,
}
atomic_read
(
&
tcon
->
num_smbs_sent
),
atomic_read
(
&
tcon
->
num_oplock_brks
));
buf
+=
length
;
length
=
sprintf
(
buf
,
"
\n
Reads: %d Bytes %lld"
,
atomic_read
(
&
tcon
->
num_reads
),
(
long
long
)(
tcon
->
bytes_read
));
buf
+=
length
;
length
=
sprintf
(
buf
,
"
\n
Writes: %d Bytes: %lld"
,
atomic_read
(
&
tcon
->
num_writes
),
(
long
long
)(
tcon
->
bytes_written
));
buf
+=
length
;
length
=
sprintf
(
buf
,
"
\n
Opens: %d Deletes: %d
\n
Mkdirs: %d Rmdirs: %d"
,
atomic_read
(
&
tcon
->
num_opens
),
atomic_read
(
&
tcon
->
num_deletes
),
atomic_read
(
&
tcon
->
num_mkdirs
),
atomic_read
(
&
tcon
->
num_rmdirs
));
buf
+=
length
;
#endif
}
}
read_unlock
(
&
GlobalSMBSeslock
);
read_unlock
(
&
GlobalSMBSeslock
);
...
@@ -200,32 +180,80 @@ cifs_total_xid_read(char *buf, char **beginBuffer, off_t offset,
...
@@ -200,32 +180,80 @@ cifs_total_xid_read(char *buf, char **beginBuffer, off_t offset,
return
length
;
return
length
;
}
}
#ifdef CONFIG_CIFS_STATS
int
int
cifs_stats_read
(
char
*
buf
,
char
**
beginBuffer
,
off_t
offset
,
cifs_stats_read
(
char
*
buf
,
char
**
beginBuffer
,
off_t
offset
,
int
length
,
int
*
eof
,
void
*
data
)
int
length
,
int
*
eof
,
void
*
data
)
{
{
int
item_length
;
int
item_length
,
i
;
length
=
struct
list_head
*
tmp
;
sprintf
(
buf
,
struct
cifsTconInfo
*
tcon
;
"Currently Allocated structures
\n
CIFS Sessions: %d
\n
"
,
sesInfoAllocCount
.
counter
);
length
=
sprintf
(
buf
,
"Currently Allocated structures
\n
CIFS Sessions: %d
\n
"
,
sesInfoAllocCount
.
counter
);
buf
+=
length
;
buf
+=
length
;
item_length
=
item_length
=
sprintf
(
buf
,
"Shares (unique mount targets): %d
\n
"
,
tconInfoAllocCount
.
counter
);
sprintf
(
buf
,
"Shares (unique mount targets): %d
\n
"
,
tconInfoAllocCount
.
counter
);
length
+=
item_length
;
length
+=
item_length
;
buf
+=
item_length
;
buf
+=
item_length
;
item_length
=
item_length
=
sprintf
(
buf
,
"Allocated SMB Request and Response Buffers: %d
\n
"
,
bufAllocCount
.
counter
);
sprintf
(
buf
,
"Allocated SMB Request/Response Buffers: %d
\n
"
,
bufAllocCount
.
counter
);
length
+=
item_length
;
length
+=
item_length
;
buf
+=
item_length
;
buf
+=
item_length
;
item_length
=
item_length
=
sprintf
(
buf
,
"Active Operations (MIDs in use): %d
\n
"
,
midCount
.
counter
);
sprintf
(
buf
,
"Active Operations (MIDs in use): %d
\n
"
,
midCount
.
counter
);
length
+=
item_length
;
length
+=
item_length
;
buf
+=
item_length
;
buf
+=
item_length
;
item_length
=
sprintf
(
buf
,
"%d sessions and %d shares reconnected after failure
\n
"
,
tcpSesReconnectCount
.
counter
,
tconInfoReconnectCount
.
counter
);
item_length
=
sprintf
(
buf
,
"%d sessions and %d shares reconnected after failure
\n
"
,
tcpSesReconnectCount
.
counter
,
tconInfoReconnectCount
.
counter
);
length
+=
item_length
;
length
+=
item_length
;
buf
+=
item_length
;
i
=
0
;
read_lock
(
&
GlobalSMBSeslock
);
list_for_each
(
tmp
,
&
GlobalTreeConnectionList
)
{
i
++
;
tcon
=
list_entry
(
tmp
,
struct
cifsTconInfo
,
cifsConnectionList
);
item_length
=
sprintf
(
buf
,
"
\n
%d) %s"
,
i
,
tcon
->
treeName
);
buf
+=
item_length
;
length
+=
item_length
;
if
(
tcon
->
tidStatus
==
CifsNeedReconnect
)
{
buf
+=
sprintf
(
buf
,
"
\t
DISCONNECTED "
);
length
+=
14
;
}
item_length
=
sprintf
(
buf
,
"
\n
SMBs: %d Oplock Breaks: %d"
,
atomic_read
(
&
tcon
->
num_smbs_sent
),
atomic_read
(
&
tcon
->
num_oplock_brks
));
buf
+=
item_length
;
length
+=
item_length
;
item_length
=
sprintf
(
buf
,
"
\n
Reads: %d Bytes %lld"
,
atomic_read
(
&
tcon
->
num_reads
),
(
long
long
)(
tcon
->
bytes_read
));
buf
+=
item_length
;
item_length
=
sprintf
(
buf
,
"
\n
Writes: %d Bytes: %lld"
,
atomic_read
(
&
tcon
->
num_writes
),
(
long
long
)(
tcon
->
bytes_written
));
buf
+=
item_length
;
item_length
=
sprintf
(
buf
,
"
\n
Opens: %d Deletes: %d
\n
Mkdirs: %d Rmdirs: %d"
,
atomic_read
(
&
tcon
->
num_opens
),
atomic_read
(
&
tcon
->
num_deletes
),
atomic_read
(
&
tcon
->
num_mkdirs
),
atomic_read
(
&
tcon
->
num_rmdirs
));
buf
+=
item_length
;
length
+=
item_length
;
}
read_unlock
(
&
GlobalSMBSeslock
);
return
length
;
return
length
;
}
}
#endif
struct
proc_dir_entry
*
proc_fs_cifs
;
struct
proc_dir_entry
*
proc_fs_cifs
;
read_proc_t
cifs_txanchor_read
;
read_proc_t
cifs_txanchor_read
;
...
@@ -265,10 +293,10 @@ cifs_proc_init(void)
...
@@ -265,10 +293,10 @@ cifs_proc_init(void)
create_proc_read_entry
(
"SimultaneousOps"
,
0
,
proc_fs_cifs
,
create_proc_read_entry
(
"SimultaneousOps"
,
0
,
proc_fs_cifs
,
cifs_total_xid_read
,
0
);
cifs_total_xid_read
,
0
);
#ifdef CONFIG_CIFS_STATS
create_proc_read_entry
(
"Stats"
,
0
,
proc_fs_cifs
,
create_proc_read_entry
(
"Stats"
,
0
,
proc_fs_cifs
,
cifs_stats_read
,
0
);
cifs_stats_read
,
0
);
#endif
pde
=
create_proc_read_entry
(
"cifsFYI"
,
0
,
proc_fs_cifs
,
pde
=
create_proc_read_entry
(
"cifsFYI"
,
0
,
proc_fs_cifs
,
cifsFYI_read
,
0
);
cifsFYI_read
,
0
);
if
(
pde
)
if
(
pde
)
...
@@ -336,7 +364,9 @@ cifs_proc_clean(void)
...
@@ -336,7 +364,9 @@ cifs_proc_clean(void)
remove_proc_entry
(
"cifsFYI"
,
proc_fs_cifs
);
remove_proc_entry
(
"cifsFYI"
,
proc_fs_cifs
);
remove_proc_entry
(
"traceSMB"
,
proc_fs_cifs
);
remove_proc_entry
(
"traceSMB"
,
proc_fs_cifs
);
remove_proc_entry
(
"SimultaneousOps"
,
proc_fs_cifs
);
remove_proc_entry
(
"SimultaneousOps"
,
proc_fs_cifs
);
#ifdef CONFIG_CIFS_STATS
remove_proc_entry
(
"Stats"
,
proc_fs_cifs
);
remove_proc_entry
(
"Stats"
,
proc_fs_cifs
);
#endif
remove_proc_entry
(
"MultiuserMount"
,
proc_fs_cifs
);
remove_proc_entry
(
"MultiuserMount"
,
proc_fs_cifs
);
remove_proc_entry
(
"OplockEnabled"
,
proc_fs_cifs
);
remove_proc_entry
(
"OplockEnabled"
,
proc_fs_cifs
);
remove_proc_entry
(
"NTLMV2Enabled"
,
proc_fs_cifs
);
remove_proc_entry
(
"NTLMV2Enabled"
,
proc_fs_cifs
);
...
...
fs/cifs/cifsfs.h
View file @
754d4c9b
...
@@ -93,5 +93,5 @@ extern int cifs_setxattr(struct dentry *, const char *, const void *,
...
@@ -93,5 +93,5 @@ extern int cifs_setxattr(struct dentry *, const char *, const void *,
size_t
,
int
);
size_t
,
int
);
extern
ssize_t
cifs_getxattr
(
struct
dentry
*
,
const
char
*
,
void
*
,
size_t
);
extern
ssize_t
cifs_getxattr
(
struct
dentry
*
,
const
char
*
,
void
*
,
size_t
);
extern
ssize_t
cifs_listxattr
(
struct
dentry
*
,
char
*
,
size_t
);
extern
ssize_t
cifs_listxattr
(
struct
dentry
*
,
char
*
,
size_t
);
#define CIFS_VERSION "1.1
6
"
#define CIFS_VERSION "1.1
7
"
#endif
/* _CIFSFS_H */
#endif
/* _CIFSFS_H */
fs/cifs/cifspdu.h
View file @
754d4c9b
...
@@ -862,6 +862,10 @@ typedef struct smb_com_create_directory_rsp {
...
@@ -862,6 +862,10 @@ typedef struct smb_com_create_directory_rsp {
__u16
ByteCount
;
/* bct = 0 */
__u16
ByteCount
;
/* bct = 0 */
}
CREATE_DIRECTORY_RSP
;
}
CREATE_DIRECTORY_RSP
;
/***************************************************/
/* NT Transact structure defintions follow */
/* Currently only ioctl and notify are implemented */
/***************************************************/
typedef
struct
smb_com_transaction_ioctl_req
{
typedef
struct
smb_com_transaction_ioctl_req
{
struct
smb_hdr
hdr
;
/* wct = 23 */
struct
smb_hdr
hdr
;
/* wct = 23 */
__u8
MaxSetupCount
;
__u8
MaxSetupCount
;
...
@@ -904,29 +908,45 @@ typedef struct smb_com_transaction_ioctl_rsp {
...
@@ -904,29 +908,45 @@ typedef struct smb_com_transaction_ioctl_rsp {
}
TRANSACT_IOCTL_RSP
;
}
TRANSACT_IOCTL_RSP
;
typedef
struct
smb_com_transaction_change_notify_req
{
typedef
struct
smb_com_transaction_change_notify_req
{
struct
smb_hdr
hdr
;
/* wct = 23 */
struct
smb_hdr
hdr
;
/* wct = 23 */
__u8
MaxSetupCount
;
__u8
MaxSetupCount
;
__u16
Reserved
;
__u16
Reserved
;
__u32
TotalParameterCount
;
__u32
TotalParameterCount
;
__u32
TotalDataCount
;
__u32
TotalDataCount
;
__u32
MaxParameterCount
;
__u32
MaxParameterCount
;
__u32
MaxDataCount
;
__u32
MaxDataCount
;
__u32
ParameterCount
;
__u32
ParameterCount
;
__u32
ParameterOffset
;
__u32
ParameterOffset
;
__u32
DataCount
;
__u32
DataCount
;
__u32
DataOffset
;
__u32
DataOffset
;
__u8
SetupCount
;
/* four setup words follow subcommand */
__u8
SetupCount
;
/* four setup words follow subcommand */
/* SNIA spec incorrectly included spurious pad here */
/* SNIA spec incorrectly included spurious pad here */
__u16
SubCommand
;
/* 4 = Change Notify */
__u16
SubCommand
;
/* 4 = Change Notify */
__u32
CompletionFilter
;
/* operation to monitor */
__u32
CompletionFilter
;
/* operation to monitor */
__u16
Fid
;
__u16
Fid
;
__u8
WatchTree
;
/* 1 = Monitor subdirectories */
__u8
WatchTree
;
/* 1 = Monitor subdirectories */
__u8
Reserved2
;
__u16
ByteCount
;
__u16
ByteCount
;
__u8
Pad
[
3
];
/* __u8 Pad[3];*/
__u8
Data
[
1
];
/* __u8 Data[1];*/
}
TRANSACT_CHANGE_NOTIFY_REQ
;
}
TRANSACT_CHANGE_NOTIFY_REQ
;
/* Completion Filter flags */
typedef
struct
smb_com_transaction_change_notify_rsp
{
struct
smb_hdr
hdr
;
/* wct = 18 */
__u8
Reserved
[
3
];
__u32
TotalParameterCount
;
__u32
TotalDataCount
;
__u32
ParameterCount
;
__u32
ParameterOffset
;
__u32
ParameterDisplacement
;
__u32
DataCount
;
__u32
DataOffset
;
__u32
DataDisplacement
;
__u8
SetupCount
;
/* 0 */
__u16
ByteCount
;
/* __u8 Pad[3]; */
}
TRANSACT_CHANGE_NOTIFY_RSP
;
/* Completion Filter flags for Notify */
#define FILE_NOTIFY_CHANGE_FILE_NAME 0x00000001
#define FILE_NOTIFY_CHANGE_FILE_NAME 0x00000001
#define FILE_NOTIFY_CHANGE_DIR_NAME 0x00000002
#define FILE_NOTIFY_CHANGE_DIR_NAME 0x00000002
#define FILE_NOTIFY_CHANGE_NAME 0x00000003
#define FILE_NOTIFY_CHANGE_NAME 0x00000003
...
...
fs/cifs/cifsproto.h
View file @
754d4c9b
...
@@ -244,4 +244,7 @@ extern int CIFSSMBCopy(int xid,
...
@@ -244,4 +244,7 @@ extern int CIFSSMBCopy(int xid,
const
__u16
target_tid
,
const
__u16
target_tid
,
const
char
*
toName
,
const
int
flags
,
const
char
*
toName
,
const
int
flags
,
const
struct
nls_table
*
nls_codepage
);
const
struct
nls_table
*
nls_codepage
);
extern
int
CIFSSMBNotify
(
const
int
xid
,
struct
cifsTconInfo
*
tcon
,
const
int
notify_subdirs
,
const
__u16
netfid
,
__u32
filter
,
const
struct
nls_table
*
nls_codepage
);
#endif
/* _CIFSPROTO_H */
#endif
/* _CIFSPROTO_H */
fs/cifs/cifssmb.c
View file @
754d4c9b
...
@@ -383,8 +383,11 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
...
@@ -383,8 +383,11 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
smb_buffer_response
,
&
length
,
0
);
smb_buffer_response
,
&
length
,
0
);
if
(
ses
->
server
)
{
if
(
ses
->
server
)
{
atomic_dec
(
&
ses
->
server
->
socketUseCount
);
atomic_dec
(
&
ses
->
server
->
socketUseCount
);
if
(
atomic_read
(
&
ses
->
server
->
socketUseCount
)
==
0
)
if
(
atomic_read
(
&
ses
->
server
->
socketUseCount
)
==
0
)
{
spin_lock
(
&
GlobalMid_Lock
);
ses
->
server
->
tcpStatus
=
CifsExiting
;
ses
->
server
->
tcpStatus
=
CifsExiting
;
spin_unlock
(
&
GlobalMid_Lock
);
}
}
}
if
(
pSMB
)
if
(
pSMB
)
cifs_buf_release
(
pSMB
);
cifs_buf_release
(
pSMB
);
...
@@ -1464,9 +1467,9 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
...
@@ -1464,9 +1467,9 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
pSMB
->
TotalParameterCount
=
0
;
pSMB
->
TotalParameterCount
=
0
;
pSMB
->
TotalDataCount
=
0
;
pSMB
->
TotalDataCount
=
0
;
pSMB
->
MaxParameterCount
=
cpu_to_le
16
(
2
);
pSMB
->
MaxParameterCount
=
cpu_to_le
32
(
2
);
/* BB find exact data count max from sess structure BB */
/* BB find exact data count max from sess structure BB */
pSMB
->
MaxDataCount
=
cpu_to_le
16
(
4000
);
pSMB
->
MaxDataCount
=
cpu_to_le
32
(
4000
);
pSMB
->
MaxSetupCount
=
4
;
pSMB
->
MaxSetupCount
=
4
;
pSMB
->
Reserved
=
0
;
pSMB
->
Reserved
=
0
;
pSMB
->
ParameterOffset
=
0
;
pSMB
->
ParameterOffset
=
0
;
...
@@ -2828,3 +2831,51 @@ CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
...
@@ -2828,3 +2831,51 @@ CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
goto
setPermsRetry
;
goto
setPermsRetry
;
return
rc
;
return
rc
;
}
}
int
CIFSSMBNotify
(
const
int
xid
,
struct
cifsTconInfo
*
tcon
,
const
int
notify_subdirs
,
const
__u16
netfid
,
__u32
filter
,
const
struct
nls_table
*
nls_codepage
)
{
int
rc
=
0
;
struct
smb_com_transaction_change_notify_req
*
pSMB
=
NULL
;
struct
smb_com_transaction_change_notify_rsp
*
pSMBr
=
NULL
;
int
bytes_returned
;
cFYI
(
1
,
(
"In CIFSSMBNotify for file handle %d"
,(
int
)
netfid
));
rc
=
smb_init
(
SMB_COM_NT_TRANSACT
,
23
,
tcon
,
(
void
**
)
&
pSMB
,
(
void
**
)
&
pSMBr
);
if
(
rc
)
return
rc
;
pSMB
->
TotalParameterCount
=
0
;
pSMB
->
TotalDataCount
=
0
;
pSMB
->
MaxParameterCount
=
cpu_to_le32
(
2
);
/* BB find exact data count max from sess structure BB */
pSMB
->
MaxDataCount
=
0
;
/* same in little endian or be */
pSMB
->
MaxSetupCount
=
4
;
pSMB
->
Reserved
=
0
;
pSMB
->
ParameterOffset
=
0
;
pSMB
->
DataCount
=
0
;
pSMB
->
DataOffset
=
0
;
pSMB
->
SetupCount
=
4
;
/* single byte does not need le conversion */
pSMB
->
SubCommand
=
cpu_to_le16
(
NT_TRANSACT_NOTIFY_CHANGE
);
pSMB
->
ParameterCount
=
pSMB
->
TotalParameterCount
;
if
(
notify_subdirs
)
pSMB
->
WatchTree
=
1
;
/* one byte - no le conversion needed */
pSMB
->
Reserved2
=
0
;
pSMB
->
CompletionFilter
=
cpu_to_le32
(
filter
);
pSMB
->
Fid
=
netfid
;
/* file handle always le */
pSMB
->
ByteCount
=
0
;
pSMB
->
hdr
.
smb_buf_length
+=
pSMB
->
ByteCount
;
rc
=
SendReceive
(
xid
,
tcon
->
ses
,
(
struct
smb_hdr
*
)
pSMB
,
(
struct
smb_hdr
*
)
pSMBr
,
&
bytes_returned
,
0
);
if
(
rc
)
{
cFYI
(
1
,
(
"Error in Notify = %d"
,
rc
));
}
if
(
pSMB
)
cifs_buf_release
(
pSMB
);
/* if (rc == -EAGAIN)
goto NotifyRetry; */
return
rc
;
}
fs/cifs/connect.c
View file @
754d4c9b
...
@@ -95,9 +95,15 @@ cifs_reconnect(struct TCP_Server_Info *server)
...
@@ -95,9 +95,15 @@ cifs_reconnect(struct TCP_Server_Info *server)
struct
cifsTconInfo
*
tcon
;
struct
cifsTconInfo
*
tcon
;
struct
mid_q_entry
*
mid_entry
;
struct
mid_q_entry
*
mid_entry
;
if
(
server
->
tcpStatus
==
CifsExiting
)
spin_lock
(
&
GlobalMid_Lock
);
if
(
server
->
tcpStatus
==
CifsExiting
)
{
/* the demux thread will exit normally
next time through the loop */
spin_unlock
(
&
GlobalMid_Lock
);
return
rc
;
return
rc
;
server
->
tcpStatus
=
CifsNeedReconnect
;
}
else
server
->
tcpStatus
=
CifsNeedReconnect
;
spin_unlock
(
&
GlobalMid_Lock
);
server
->
maxBuf
=
0
;
server
->
maxBuf
=
0
;
cFYI
(
1
,
(
"Reconnecting tcp session "
));
cFYI
(
1
,
(
"Reconnecting tcp session "
));
...
@@ -164,7 +170,10 @@ cifs_reconnect(struct TCP_Server_Info *server)
...
@@ -164,7 +170,10 @@ cifs_reconnect(struct TCP_Server_Info *server)
schedule_timeout
(
3
*
HZ
);
schedule_timeout
(
3
*
HZ
);
}
else
{
}
else
{
atomic_inc
(
&
tcpSesReconnectCount
);
atomic_inc
(
&
tcpSesReconnectCount
);
server
->
tcpStatus
=
CifsGood
;
spin_lock
(
&
GlobalMid_Lock
);
if
(
server
->
tcpStatus
!=
CifsExiting
)
server
->
tcpStatus
=
CifsGood
;
spin_unlock
(
&
GlobalMid_Lock
);
atomic_set
(
&
server
->
inFlight
,
0
);
atomic_set
(
&
server
->
inFlight
,
0
);
wake_up
(
&
server
->
response_q
);
wake_up
(
&
server
->
response_q
);
}
}
...
@@ -243,12 +252,14 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
...
@@ -243,12 +252,14 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
/* some servers kill tcp session rather than returning
/* some servers kill tcp session rather than returning
smb negprot error in which case reconnecting here is
smb negprot error in which case reconnecting here is
not going to help - return error to mount */
not going to help - return error to mount */
spin_lock
(
&
GlobalMid_Lock
);
server
->
tcpStatus
=
CifsExiting
;
server
->
tcpStatus
=
CifsExiting
;
spin_unlock
(
&
GlobalMid_Lock
);
wake_up
(
&
server
->
response_q
);
wake_up
(
&
server
->
response_q
);
break
;
break
;
}
}
cFYI
(
1
,(
"Reconnecting after unexpected
rcvmsg error "
));
cFYI
(
1
,(
"Reconnecting after unexpected
peek error %d"
,
length
));
cifs_reconnect
(
server
);
cifs_reconnect
(
server
);
csocket
=
server
->
ssocket
;
csocket
=
server
->
ssocket
;
wake_up
(
&
server
->
response_q
);
wake_up
(
&
server
->
response_q
);
...
@@ -280,7 +291,9 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
...
@@ -280,7 +291,9 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
/* if nack on negprot (rather than
/* if nack on negprot (rather than
ret of smb negprot error) reconnecting
ret of smb negprot error) reconnecting
not going to help, ret error to mount */
not going to help, ret error to mount */
spin_lock
(
&
GlobalMid_Lock
);
server
->
tcpStatus
=
CifsExiting
;
server
->
tcpStatus
=
CifsExiting
;
spin_unlock
(
&
GlobalMid_Lock
);
/* wake up thread doing negprot */
/* wake up thread doing negprot */
wake_up
(
&
server
->
response_q
);
wake_up
(
&
server
->
response_q
);
break
;
break
;
...
@@ -391,7 +404,9 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
...
@@ -391,7 +404,9 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
}
}
}
}
}
}
spin_lock
(
&
GlobalMid_Lock
);
server
->
tcpStatus
=
CifsExiting
;
server
->
tcpStatus
=
CifsExiting
;
spin_unlock
(
&
GlobalMid_Lock
);
atomic_set
(
&
server
->
inFlight
,
0
);
atomic_set
(
&
server
->
inFlight
,
0
);
/* Although there should not be any requests blocked on
/* Although there should not be any requests blocked on
this queue it can not hurt to be paranoid and try to wake up requests
this queue it can not hurt to be paranoid and try to wake up requests
...
@@ -595,6 +610,8 @@ cifs_parse_mount_options(char *options, const char *devname, struct smb_vol *vol
...
@@ -595,6 +610,8 @@ cifs_parse_mount_options(char *options, const char *devname, struct smb_vol *vol
}
}
if
((
temp_len
=
strnlen
(
value
,
300
))
<
300
)
{
if
((
temp_len
=
strnlen
(
value
,
300
))
<
300
)
{
vol
->
UNC
=
kmalloc
(
temp_len
+
1
,
GFP_KERNEL
);
vol
->
UNC
=
kmalloc
(
temp_len
+
1
,
GFP_KERNEL
);
if
(
vol
->
UNC
==
NULL
)
return
1
;
strcpy
(
vol
->
UNC
,
value
);
strcpy
(
vol
->
UNC
,
value
);
if
(
strncmp
(
vol
->
UNC
,
"//"
,
2
)
==
0
)
{
if
(
strncmp
(
vol
->
UNC
,
"//"
,
2
)
==
0
)
{
vol
->
UNC
[
0
]
=
'\\'
;
vol
->
UNC
[
0
]
=
'\\'
;
...
@@ -742,6 +759,8 @@ cifs_parse_mount_options(char *options, const char *devname, struct smb_vol *vol
...
@@ -742,6 +759,8 @@ cifs_parse_mount_options(char *options, const char *devname, struct smb_vol *vol
}
}
if
((
temp_len
=
strnlen
(
devname
,
300
))
<
300
)
{
if
((
temp_len
=
strnlen
(
devname
,
300
))
<
300
)
{
vol
->
UNC
=
kmalloc
(
temp_len
+
1
,
GFP_KERNEL
);
vol
->
UNC
=
kmalloc
(
temp_len
+
1
,
GFP_KERNEL
);
if
(
vol
->
UNC
==
NULL
)
return
1
;
strcpy
(
vol
->
UNC
,
devname
);
strcpy
(
vol
->
UNC
,
devname
);
if
(
strncmp
(
vol
->
UNC
,
"//"
,
2
)
==
0
)
{
if
(
strncmp
(
vol
->
UNC
,
"//"
,
2
)
==
0
)
{
vol
->
UNC
[
0
]
=
'\\'
;
vol
->
UNC
[
0
]
=
'\\'
;
...
@@ -1030,7 +1049,7 @@ ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
...
@@ -1030,7 +1049,7 @@ ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
}
else
{
}
else
{
/* BB other socket options to set KEEPALIVE, NODELAY? */
/* BB other socket options to set KEEPALIVE, NODELAY? */
cFYI
(
1
,(
"ipv6 Socket created"
));
cFYI
(
1
,(
"ipv6 Socket created"
));
(
*
csocket
)
->
sk
->
sk_allocation
=
GFP_NOFS
;
(
*
csocket
)
->
sk
->
sk_allocation
=
GFP_NOFS
;
}
}
}
}
...
@@ -1226,6 +1245,9 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
...
@@ -1226,6 +1245,9 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
init_waitqueue_head
(
&
srvTcp
->
response_q
);
init_waitqueue_head
(
&
srvTcp
->
response_q
);
init_waitqueue_head
(
&
srvTcp
->
request_q
);
init_waitqueue_head
(
&
srvTcp
->
request_q
);
INIT_LIST_HEAD
(
&
srvTcp
->
pending_mid_q
);
INIT_LIST_HEAD
(
&
srvTcp
->
pending_mid_q
);
/* at this point we are the only ones with the pointer
to the struct since the kernel thread not created yet
so no need to spinlock this init of tcpStatus */
srvTcp
->
tcpStatus
=
CifsNew
;
srvTcp
->
tcpStatus
=
CifsNew
;
init_MUTEX
(
&
srvTcp
->
tcpSem
);
init_MUTEX
(
&
srvTcp
->
tcpSem
);
kernel_thread
((
void
*
)(
void
*
)
cifs_demultiplex_thread
,
srvTcp
,
kernel_thread
((
void
*
)(
void
*
)
cifs_demultiplex_thread
,
srvTcp
,
...
@@ -1342,9 +1364,12 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
...
@@ -1342,9 +1364,12 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
/* on error free sesinfo and tcon struct if needed */
/* on error free sesinfo and tcon struct if needed */
if
(
rc
)
{
if
(
rc
)
{
if
(
atomic_read
(
&
srvTcp
->
socketUseCount
)
==
0
)
if
(
atomic_read
(
&
srvTcp
->
socketUseCount
)
==
0
)
{
srvTcp
->
tcpStatus
=
CifsExiting
;
spin_lock
(
&
GlobalMid_Lock
);
/* If find_unc succeeded then rc == 0 so we can not end */
srvTcp
->
tcpStatus
=
CifsExiting
;
spin_unlock
(
&
GlobalMid_Lock
);
}
/* If find_unc succeeded then rc == 0 so we can not end */
if
(
tcon
)
/* up here accidently freeing someone elses tcon struct */
if
(
tcon
)
/* up here accidently freeing someone elses tcon struct */
tconInfoFree
(
tcon
);
tconInfoFree
(
tcon
);
if
(
existingCifsSes
==
0
)
{
if
(
existingCifsSes
==
0
)
{
...
@@ -2791,7 +2816,7 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
...
@@ -2791,7 +2816,7 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
char
ntlm_session_key
[
CIFS_SESSION_KEY_SIZE
];
char
ntlm_session_key
[
CIFS_SESSION_KEY_SIZE
];
int
ntlmv2_flag
=
FALSE
;
int
ntlmv2_flag
=
FALSE
;
/* what if server changes its buffer size after dropping the session? */
/* what if server changes its buffer size after dropping the session? */
if
(
pSesInfo
->
server
->
maxBuf
==
0
)
/* no need to send on reconnect */
{
if
(
pSesInfo
->
server
->
maxBuf
==
0
)
/* no need to send on reconnect */
{
rc
=
CIFSSMBNegotiate
(
xid
,
pSesInfo
);
rc
=
CIFSSMBNegotiate
(
xid
,
pSesInfo
);
if
(
rc
==
-
EAGAIN
)
/* retry only once on 1st time connection */
{
if
(
rc
==
-
EAGAIN
)
/* retry only once on 1st time connection */
{
...
@@ -2799,8 +2824,15 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
...
@@ -2799,8 +2824,15 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
if
(
rc
==
-
EAGAIN
)
if
(
rc
==
-
EAGAIN
)
rc
=
-
EHOSTDOWN
;
rc
=
-
EHOSTDOWN
;
}
}
if
(
rc
==
0
)
if
(
rc
==
0
)
{
pSesInfo
->
server
->
tcpStatus
=
CifsGood
;
spin_lock
(
&
GlobalMid_Lock
);
if
(
pSesInfo
->
server
->
tcpStatus
!=
CifsExiting
)
pSesInfo
->
server
->
tcpStatus
=
CifsGood
;
else
rc
=
-
EHOSTDOWN
;
spin_unlock
(
&
GlobalMid_Lock
);
}
}
}
if
(
!
rc
)
{
if
(
!
rc
)
{
pSesInfo
->
capabilities
=
pSesInfo
->
server
->
capabilities
;
pSesInfo
->
capabilities
=
pSesInfo
->
server
->
capabilities
;
...
...
fs/cifs/dir.c
View file @
754d4c9b
...
@@ -159,6 +159,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
...
@@ -159,6 +159,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
struct
cifsFileInfo
*
pCifsFile
=
NULL
;
struct
cifsFileInfo
*
pCifsFile
=
NULL
;
struct
cifsInodeInfo
*
pCifsInode
;
struct
cifsInodeInfo
*
pCifsInode
;
int
disposition
=
FILE_OVERWRITE_IF
;
int
disposition
=
FILE_OVERWRITE_IF
;
int
write_only
=
FALSE
;
xid
=
GetXid
();
xid
=
GetXid
();
...
@@ -176,9 +177,10 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
...
@@ -176,9 +177,10 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
if
(
nd
)
{
if
(
nd
)
{
if
((
nd
->
intent
.
open
.
flags
&
O_ACCMODE
)
==
O_RDONLY
)
if
((
nd
->
intent
.
open
.
flags
&
O_ACCMODE
)
==
O_RDONLY
)
desiredAccess
=
GENERIC_READ
;
desiredAccess
=
GENERIC_READ
;
else
if
((
nd
->
intent
.
open
.
flags
&
O_ACCMODE
)
==
O_WRONLY
)
else
if
((
nd
->
intent
.
open
.
flags
&
O_ACCMODE
)
==
O_WRONLY
)
{
desiredAccess
=
GENERIC_WRITE
;
desiredAccess
=
GENERIC_WRITE
;
else
if
((
nd
->
intent
.
open
.
flags
&
O_ACCMODE
)
==
O_RDWR
)
{
write_only
=
TRUE
;
}
else
if
((
nd
->
intent
.
open
.
flags
&
O_ACCMODE
)
==
O_RDWR
)
{
/* GENERIC_ALL is too much permission to request */
/* GENERIC_ALL is too much permission to request */
/* can cause unnecessary access denied on create */
/* can cause unnecessary access denied on create */
/* desiredAccess = GENERIC_ALL; */
/* desiredAccess = GENERIC_ALL; */
...
@@ -262,16 +264,25 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
...
@@ -262,16 +264,25 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
pCifsFile
->
invalidHandle
=
FALSE
;
pCifsFile
->
invalidHandle
=
FALSE
;
pCifsFile
->
closePend
=
FALSE
;
pCifsFile
->
closePend
=
FALSE
;
init_MUTEX
(
&
pCifsFile
->
fh_sem
);
init_MUTEX
(
&
pCifsFile
->
fh_sem
);
/* pCifsFile->pfile = file; */
/* put in at open time */
/* put the following in at open now */
/* pCifsFile->pfile = file; */
write_lock
(
&
GlobalSMBSeslock
);
write_lock
(
&
GlobalSMBSeslock
);
list_add
(
&
pCifsFile
->
tlist
,
&
pTcon
->
openFileList
);
list_add
(
&
pCifsFile
->
tlist
,
&
pTcon
->
openFileList
);
pCifsInode
=
CIFS_I
(
newinode
);
pCifsInode
=
CIFS_I
(
newinode
);
if
(
pCifsInode
)
{
if
(
pCifsInode
)
{
list_add
(
&
pCifsFile
->
flist
,
&
pCifsInode
->
openFileList
);
/* if readable file instance put first in list*/
if
(
write_only
==
TRUE
)
{
list_add_tail
(
&
pCifsFile
->
flist
,
&
pCifsInode
->
openFileList
);
}
else
{
list_add
(
&
pCifsFile
->
flist
,
&
pCifsInode
->
openFileList
);
}
if
((
oplock
&
0xF
)
==
OPLOCK_EXCLUSIVE
)
{
if
((
oplock
&
0xF
)
==
OPLOCK_EXCLUSIVE
)
{
pCifsInode
->
clientCanCacheAll
=
TRUE
;
pCifsInode
->
clientCanCacheAll
=
TRUE
;
pCifsInode
->
clientCanCacheRead
=
TRUE
;
pCifsInode
->
clientCanCacheRead
=
TRUE
;
cFYI
(
1
,(
"Exclusive Oplock granted on inode %p"
,
newinode
));
cFYI
(
1
,(
"Exclusive Oplock granted on inode %p"
,
newinode
));
}
else
if
((
oplock
&
0xF
)
==
OPLOCK_READ
)
}
else
if
((
oplock
&
0xF
)
==
OPLOCK_READ
)
pCifsInode
->
clientCanCacheRead
=
TRUE
;
pCifsInode
->
clientCanCacheRead
=
TRUE
;
}
}
...
...
fs/cifs/fcntl.c
View file @
754d4c9b
...
@@ -32,9 +32,12 @@ int cifs_directory_notify(unsigned long arg, struct file * file)
...
@@ -32,9 +32,12 @@ int cifs_directory_notify(unsigned long arg, struct file * file)
{
{
int
xid
;
int
xid
;
int
rc
=
-
EINVAL
;
int
rc
=
-
EINVAL
;
int
oplock
=
FALSE
;
struct
cifs_sb_info
*
cifs_sb
;
struct
cifs_sb_info
*
cifs_sb
;
struct
cifsTconInfo
*
pTcon
;
struct
cifsTconInfo
*
pTcon
;
char
*
full_path
=
NULL
;
char
*
full_path
=
NULL
;
__u32
filter
=
FILE_NOTIFY_CHANGE_NAME
|
FILE_NOTIFY_CHANGE_ATTRIBUTES
;
__u16
netfid
;
xid
=
GetXid
();
xid
=
GetXid
();
cifs_sb
=
CIFS_SB
(
file
->
f_dentry
->
d_sb
);
cifs_sb
=
CIFS_SB
(
file
->
f_dentry
->
d_sb
);
...
@@ -48,7 +51,20 @@ int cifs_directory_notify(unsigned long arg, struct file * file)
...
@@ -48,7 +51,20 @@ int cifs_directory_notify(unsigned long arg, struct file * file)
rc
=
-
ENOMEM
;
rc
=
-
ENOMEM
;
}
else
{
}
else
{
cFYI
(
1
,(
"cifs dir notify on file %s"
,
full_path
));
cFYI
(
1
,(
"cifs dir notify on file %s"
,
full_path
));
/* CIFSSMBNotify(xid, pTcon, full_path, cifs_sb->local_nls);*/
rc
=
CIFSSMBOpen
(
xid
,
pTcon
,
full_path
,
FILE_OPEN
,
GENERIC_READ
|
SYNCHRONIZE
,
0
/* create options */
,
&
netfid
,
&
oplock
,
NULL
,
cifs_sb
->
local_nls
);
/* BB fixme - add this handle to a notify handle list */
if
(
rc
)
{
cFYI
(
1
,(
"Could not open directory for notify"
));
}
else
{
rc
=
CIFSSMBNotify
(
xid
,
pTcon
,
1
/* subdirs */
,
netfid
,
filter
,
cifs_sb
->
local_nls
);
/* BB add code to close file eventually (at unmount
it would close automatically but may be a way
to do it easily when inode freed or when
notify info is cleared/changed */
}
}
}
FreeXid
(
xid
);
FreeXid
(
xid
);
...
...
fs/cifs/file.c
View file @
754d4c9b
This diff is collapsed.
Click to expand it.
fs/cifs/inode.c
View file @
754d4c9b
...
@@ -130,8 +130,18 @@ cifs_get_inode_info_unix(struct inode **pinode,
...
@@ -130,8 +130,18 @@ cifs_get_inode_info_unix(struct inode **pinode,
and blkbits set in superblock so 2**blkbits and blksize will match */
and blkbits set in superblock so 2**blkbits and blksize will match */
/* inode->i_blksize =
/* inode->i_blksize =
(pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
(pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
inode
->
i_blocks
=
(
inode
->
i_blksize
-
1
+
findData
.
NumOfBytes
)
>>
inode
->
i_blkbits
;
/* This seems incredibly stupid but it turns out that
i_blocks is not related to (i_size / i_blksize), instead a
size of 512 is required to be used for calculating num blocks */
/* inode->i_blocks =
(inode->i_blksize - 1 + findData.NumOfBytes) >> inode->i_blkbits;*/
/* 512 bytes (2**9) is the fake blocksize that must be used */
/* for this calculation */
inode
->
i_blocks
=
(
512
-
1
+
findData
.
NumOfBytes
)
>>
9
;
if
(
findData
.
NumOfBytes
<
findData
.
EndOfFile
)
if
(
findData
.
NumOfBytes
<
findData
.
EndOfFile
)
cFYI
(
1
,
(
"Server inconsistency Error: it says allocation size less than end of file "
));
cFYI
(
1
,
(
"Server inconsistency Error: it says allocation size less than end of file "
));
...
@@ -275,8 +285,10 @@ cifs_get_inode_info(struct inode **pinode, const unsigned char *search_path,
...
@@ -275,8 +285,10 @@ cifs_get_inode_info(struct inode **pinode, const unsigned char *search_path,
}
}
i_size_write
(
inode
,
le64_to_cpu
(
pfindData
->
EndOfFile
));
i_size_write
(
inode
,
le64_to_cpu
(
pfindData
->
EndOfFile
));
pfindData
->
AllocationSize
=
le64_to_cpu
(
pfindData
->
AllocationSize
);
pfindData
->
AllocationSize
=
le64_to_cpu
(
pfindData
->
AllocationSize
);
inode
->
i_blocks
=
(
inode
->
i_blksize
-
1
+
pfindData
->
AllocationSize
)
>>
inode
->
i_blkbits
;
/* 512 bytes (2**9) is the fake blocksize that must be used */
/* for this calculation */
inode
->
i_blocks
=
(
512
-
1
+
pfindData
->
AllocationSize
)
>>
9
;
inode
->
i_nlink
=
le32_to_cpu
(
pfindData
->
NumberOfLinks
);
inode
->
i_nlink
=
le32_to_cpu
(
pfindData
->
NumberOfLinks
);
...
...
fs/cifs/transport.c
View file @
754d4c9b
...
@@ -126,7 +126,6 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
...
@@ -126,7 +126,6 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
if
(
ssocket
==
NULL
)
if
(
ssocket
==
NULL
)
return
-
ENOTSOCK
;
/* BB eventually add reconnect code here */
return
-
ENOTSOCK
;
/* BB eventually add reconnect code here */
/* ssocket->sk->allocation = GFP_BUFFER; *//* BB is this spurious? */
iov
.
iov_base
=
smb_buffer
;
iov
.
iov_base
=
smb_buffer
;
iov
.
iov_len
=
smb_buf_length
+
4
;
iov
.
iov_len
=
smb_buf_length
+
4
;
...
...
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