Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
raspberrypi-kernel
提交
fbcae3ea
R
raspberrypi-kernel
项目概览
openeuler
/
raspberrypi-kernel
通知
13
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
raspberrypi-kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
fbcae3ea
编写于
10月 19, 2011
作者:
S
Steve French
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'cifs-3.2' of
git://git.samba.org/jlayton/linux
into temp-3.2-jeff
上级
71c424ba
f06ac72e
变更
9
展开全部
隐藏空白更改
内联
并排
Showing
9 changed file
with
897 addition
and
368 deletion
+897
-368
fs/cifs/cifsfs.c
fs/cifs/cifsfs.c
+1
-1
fs/cifs/cifsglob.h
fs/cifs/cifsglob.h
+26
-3
fs/cifs/cifspdu.h
fs/cifs/cifspdu.h
+1
-3
fs/cifs/cifsproto.h
fs/cifs/cifsproto.h
+27
-2
fs/cifs/cifssmb.c
fs/cifs/cifssmb.c
+362
-2
fs/cifs/connect.c
fs/cifs/connect.c
+334
-181
fs/cifs/file.c
fs/cifs/file.c
+124
-171
fs/cifs/transport.c
fs/cifs/transport.c
+5
-3
include/linux/freezer.h
include/linux/freezer.h
+17
-2
未找到文件。
fs/cifs/cifsfs.c
浏览文件 @
fbcae3ea
...
...
@@ -74,7 +74,7 @@ module_param(cifs_min_small, int, 0);
MODULE_PARM_DESC
(
cifs_min_small
,
"Small network buffers in pool. Default: 30 "
"Range: 2 to 256"
);
unsigned
int
cifs_max_pending
=
CIFS_MAX_REQ
;
module_param
(
cifs_max_pending
,
int
,
0
);
module_param
(
cifs_max_pending
,
int
,
0
444
);
MODULE_PARM_DESC
(
cifs_max_pending
,
"Simultaneous requests to server. "
"Default: 50 Range: 2 to 256"
);
unsigned
short
echo_retries
=
5
;
...
...
fs/cifs/cifsglob.h
浏览文件 @
fbcae3ea
...
...
@@ -291,7 +291,13 @@ struct TCP_Server_Info {
bool
sec_kerberosu2u
;
/* supports U2U Kerberos */
bool
sec_kerberos
;
/* supports plain Kerberos */
bool
sec_mskerberos
;
/* supports legacy MS Kerberos */
bool
large_buf
;
/* is current buffer large? */
struct
delayed_work
echo
;
/* echo ping workqueue job */
struct
kvec
*
iov
;
/* reusable kvec array for receives */
unsigned
int
nr_iov
;
/* number of kvecs in array */
char
*
smallbuf
;
/* pointer to current "small" buffer */
char
*
bigbuf
;
/* pointer to current "big" buffer */
unsigned
int
total_read
;
/* total amount of data read in this pass */
#ifdef CONFIG_CIFS_FSCACHE
struct
fscache_cookie
*
fscache
;
/* client index cache cookie */
#endif
...
...
@@ -650,8 +656,24 @@ static inline void cifs_stats_bytes_read(struct cifs_tcon *tcon,
struct
mid_q_entry
;
/*
* This is the prototype for the mid callback function. When creating one,
* take special care to avoid deadlocks. Things to bear in mind:
* This is the prototype for the mid receive function. This function is for
* receiving the rest of the SMB frame, starting with the WordCount (which is
* just after the MID in struct smb_hdr). Note:
*
* - This will be called by cifsd, with no locks held.
* - The mid will still be on the pending_mid_q.
* - mid->resp_buf will point to the current buffer.
*
* Returns zero on a successful receive, or an error. The receive state in
* the TCP_Server_Info will also be updated.
*/
typedef
int
(
mid_receive_t
)(
struct
TCP_Server_Info
*
server
,
struct
mid_q_entry
*
mid
);
/*
* This is the prototype for the mid callback function. This is called once the
* mid has been received off of the socket. When creating one, take special
* care to avoid deadlocks. Things to bear in mind:
*
* - it will be called by cifsd, with no locks held
* - the mid will be removed from any lists
...
...
@@ -669,9 +691,10 @@ struct mid_q_entry {
unsigned
long
when_sent
;
/* time when smb send finished */
unsigned
long
when_received
;
/* when demux complete (taken off wire) */
#endif
mid_receive_t
*
receive
;
/* call receive callback */
mid_callback_t
*
callback
;
/* call completion callback */
void
*
callback_data
;
/* general purpose pointer for callback */
struct
smb_hdr
*
resp_buf
;
/*
response buff
er */
struct
smb_hdr
*
resp_buf
;
/*
pointer to received SMB head
er */
int
midState
;
/* wish this were enum but can not pass to wait_event */
__u8
command
;
/* smb command code */
bool
largeBuf
:
1
;
/* if valid response, is pointer to large buf */
...
...
fs/cifs/cifspdu.h
浏览文件 @
fbcae3ea
...
...
@@ -1089,9 +1089,7 @@ typedef struct smb_com_read_rsp {
__le16
DataLengthHigh
;
__u64
Reserved2
;
__u16
ByteCount
;
__u8
Pad
;
/* BB check for whether padded to DWORD
boundary and optimum performance here */
char
Data
[
1
];
/* read response data immediately follows */
}
__attribute__
((
packed
))
READ_RSP
;
typedef
struct
locking_andx_range
{
...
...
fs/cifs/cifsproto.h
浏览文件 @
fbcae3ea
...
...
@@ -69,8 +69,9 @@ extern struct mid_q_entry *AllocMidQEntry(const struct smb_hdr *smb_buffer,
struct
TCP_Server_Info
*
server
);
extern
void
DeleteMidQEntry
(
struct
mid_q_entry
*
midEntry
);
extern
int
cifs_call_async
(
struct
TCP_Server_Info
*
server
,
struct
kvec
*
iov
,
unsigned
int
nvec
,
mid_callback_t
*
callback
,
void
*
cbdata
,
bool
ignore_pend
);
unsigned
int
nvec
,
mid_receive_t
*
receive
,
mid_callback_t
*
callback
,
void
*
cbdata
,
bool
ignore_pend
);
extern
int
SendReceive
(
const
unsigned
int
/* xid */
,
struct
cifs_ses
*
,
struct
smb_hdr
*
/* input */
,
struct
smb_hdr
*
/* out */
,
...
...
@@ -153,6 +154,12 @@ extern struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *, struct inode *,
extern
int
set_cifs_acl
(
struct
cifs_ntsd
*
,
__u32
,
struct
inode
*
,
const
char
*
,
int
);
extern
void
dequeue_mid
(
struct
mid_q_entry
*
mid
,
bool
malformed
);
extern
int
cifs_read_from_socket
(
struct
TCP_Server_Info
*
server
,
char
*
buf
,
unsigned
int
to_read
);
extern
int
cifs_readv_from_socket
(
struct
TCP_Server_Info
*
server
,
struct
kvec
*
iov_orig
,
unsigned
int
nr_segs
,
unsigned
int
to_read
);
extern
void
cifs_setup_cifs_sb
(
struct
smb_vol
*
pvolume_info
,
struct
cifs_sb_info
*
cifs_sb
);
extern
int
cifs_match_super
(
struct
super_block
*
,
void
*
);
...
...
@@ -442,6 +449,24 @@ extern int E_md4hash(const unsigned char *passwd, unsigned char *p16);
extern
int
SMBencrypt
(
unsigned
char
*
passwd
,
const
unsigned
char
*
c8
,
unsigned
char
*
p24
);
/* asynchronous read support */
struct
cifs_readdata
{
struct
cifsFileInfo
*
cfile
;
struct
address_space
*
mapping
;
__u64
offset
;
unsigned
int
bytes
;
pid_t
pid
;
int
result
;
struct
list_head
pages
;
struct
work_struct
work
;
unsigned
int
nr_iov
;
struct
kvec
iov
[
1
];
};
struct
cifs_readdata
*
cifs_readdata_alloc
(
unsigned
int
nr_pages
);
void
cifs_readdata_free
(
struct
cifs_readdata
*
rdata
);
int
cifs_async_readv
(
struct
cifs_readdata
*
rdata
);
/* asynchronous write support */
struct
cifs_writedata
{
struct
kref
refcount
;
...
...
fs/cifs/cifssmb.c
浏览文件 @
fbcae3ea
...
...
@@ -33,6 +33,8 @@
#include <linux/slab.h>
#include <linux/posix_acl_xattr.h>
#include <linux/pagemap.h>
#include <linux/swap.h>
#include <linux/task_io_accounting_ops.h>
#include <asm/uaccess.h>
#include "cifspdu.h"
#include "cifsglob.h"
...
...
@@ -40,6 +42,7 @@
#include "cifsproto.h"
#include "cifs_unicode.h"
#include "cifs_debug.h"
#include "fscache.h"
#ifdef CONFIG_CIFS_POSIX
static
struct
{
...
...
@@ -83,6 +86,9 @@ static struct {
#endif
/* CONFIG_CIFS_WEAK_PW_HASH */
#endif
/* CIFS_POSIX */
/* Forward declarations */
static
void
cifs_readv_complete
(
struct
work_struct
*
work
);
/* Mark as invalid, all open files on tree connections since they
were closed when session to server was lost */
static
void
mark_open_files_invalid
(
struct
cifs_tcon
*
pTcon
)
...
...
@@ -737,7 +743,8 @@ CIFSSMBEcho(struct TCP_Server_Info *server)
iov
.
iov_base
=
smb
;
iov
.
iov_len
=
be32_to_cpu
(
smb
->
hdr
.
smb_buf_length
)
+
4
;
rc
=
cifs_call_async
(
server
,
&
iov
,
1
,
cifs_echo_callback
,
server
,
true
);
rc
=
cifs_call_async
(
server
,
&
iov
,
1
,
NULL
,
cifs_echo_callback
,
server
,
true
);
if
(
rc
)
cFYI
(
1
,
"Echo request failed: %d"
,
rc
);
...
...
@@ -1374,6 +1381,359 @@ CIFSSMBOpen(const int xid, struct cifs_tcon *tcon,
return
rc
;
}
struct
cifs_readdata
*
cifs_readdata_alloc
(
unsigned
int
nr_pages
)
{
struct
cifs_readdata
*
rdata
;
/* readdata + 1 kvec for each page */
rdata
=
kzalloc
(
sizeof
(
*
rdata
)
+
sizeof
(
struct
kvec
)
*
nr_pages
,
GFP_KERNEL
);
if
(
rdata
!=
NULL
)
{
INIT_WORK
(
&
rdata
->
work
,
cifs_readv_complete
);
INIT_LIST_HEAD
(
&
rdata
->
pages
);
}
return
rdata
;
}
void
cifs_readdata_free
(
struct
cifs_readdata
*
rdata
)
{
cifsFileInfo_put
(
rdata
->
cfile
);
kfree
(
rdata
);
}
/*
* Discard any remaining data in the current SMB. To do this, we borrow the
* current bigbuf.
*/
static
int
cifs_readv_discard
(
struct
TCP_Server_Info
*
server
,
struct
mid_q_entry
*
mid
)
{
READ_RSP
*
rsp
=
(
READ_RSP
*
)
server
->
smallbuf
;
unsigned
int
rfclen
=
be32_to_cpu
(
rsp
->
hdr
.
smb_buf_length
);
int
remaining
=
rfclen
+
4
-
server
->
total_read
;
struct
cifs_readdata
*
rdata
=
mid
->
callback_data
;
while
(
remaining
>
0
)
{
int
length
;
length
=
cifs_read_from_socket
(
server
,
server
->
bigbuf
,
min_t
(
unsigned
int
,
remaining
,
CIFSMaxBufSize
+
MAX_CIFS_HDR_SIZE
));
if
(
length
<
0
)
return
length
;
server
->
total_read
+=
length
;
remaining
-=
length
;
}
dequeue_mid
(
mid
,
rdata
->
result
);
return
0
;
}
static
int
cifs_readv_receive
(
struct
TCP_Server_Info
*
server
,
struct
mid_q_entry
*
mid
)
{
int
length
,
len
;
unsigned
int
data_offset
,
remaining
,
data_len
;
struct
cifs_readdata
*
rdata
=
mid
->
callback_data
;
READ_RSP
*
rsp
=
(
READ_RSP
*
)
server
->
smallbuf
;
unsigned
int
rfclen
=
be32_to_cpu
(
rsp
->
hdr
.
smb_buf_length
)
+
4
;
u64
eof
;
pgoff_t
eof_index
;
struct
page
*
page
,
*
tpage
;
cFYI
(
1
,
"%s: mid=%u offset=%llu bytes=%u"
,
__func__
,
mid
->
mid
,
rdata
->
offset
,
rdata
->
bytes
);
/*
* read the rest of READ_RSP header (sans Data array), or whatever we
* can if there's not enough data. At this point, we've read down to
* the Mid.
*/
len
=
min_t
(
unsigned
int
,
rfclen
,
sizeof
(
*
rsp
))
-
sizeof
(
struct
smb_hdr
)
+
1
;
rdata
->
iov
[
0
].
iov_base
=
server
->
smallbuf
+
sizeof
(
struct
smb_hdr
)
-
1
;
rdata
->
iov
[
0
].
iov_len
=
len
;
length
=
cifs_readv_from_socket
(
server
,
rdata
->
iov
,
1
,
len
);
if
(
length
<
0
)
return
length
;
server
->
total_read
+=
length
;
/* Was the SMB read successful? */
rdata
->
result
=
map_smb_to_linux_error
(
&
rsp
->
hdr
,
false
);
if
(
rdata
->
result
!=
0
)
{
cFYI
(
1
,
"%s: server returned error %d"
,
__func__
,
rdata
->
result
);
return
cifs_readv_discard
(
server
,
mid
);
}
/* Is there enough to get to the rest of the READ_RSP header? */
if
(
server
->
total_read
<
sizeof
(
READ_RSP
))
{
cFYI
(
1
,
"%s: server returned short header. got=%u expected=%zu"
,
__func__
,
server
->
total_read
,
sizeof
(
READ_RSP
));
rdata
->
result
=
-
EIO
;
return
cifs_readv_discard
(
server
,
mid
);
}
data_offset
=
le16_to_cpu
(
rsp
->
DataOffset
)
+
4
;
if
(
data_offset
<
server
->
total_read
)
{
/*
* win2k8 sometimes sends an offset of 0 when the read
* is beyond the EOF. Treat it as if the data starts just after
* the header.
*/
cFYI
(
1
,
"%s: data offset (%u) inside read response header"
,
__func__
,
data_offset
);
data_offset
=
server
->
total_read
;
}
else
if
(
data_offset
>
MAX_CIFS_SMALL_BUFFER_SIZE
)
{
/* data_offset is beyond the end of smallbuf */
cFYI
(
1
,
"%s: data offset (%u) beyond end of smallbuf"
,
__func__
,
data_offset
);
rdata
->
result
=
-
EIO
;
return
cifs_readv_discard
(
server
,
mid
);
}
cFYI
(
1
,
"%s: total_read=%u data_offset=%u"
,
__func__
,
server
->
total_read
,
data_offset
);
len
=
data_offset
-
server
->
total_read
;
if
(
len
>
0
)
{
/* read any junk before data into the rest of smallbuf */
rdata
->
iov
[
0
].
iov_base
=
server
->
smallbuf
+
server
->
total_read
;
rdata
->
iov
[
0
].
iov_len
=
len
;
length
=
cifs_readv_from_socket
(
server
,
rdata
->
iov
,
1
,
len
);
if
(
length
<
0
)
return
length
;
server
->
total_read
+=
length
;
}
/* set up first iov for signature check */
rdata
->
iov
[
0
].
iov_base
=
server
->
smallbuf
;
rdata
->
iov
[
0
].
iov_len
=
server
->
total_read
;
cFYI
(
1
,
"0: iov_base=%p iov_len=%zu"
,
rdata
->
iov
[
0
].
iov_base
,
rdata
->
iov
[
0
].
iov_len
);
/* how much data is in the response? */
data_len
=
le16_to_cpu
(
rsp
->
DataLengthHigh
)
<<
16
;
data_len
+=
le16_to_cpu
(
rsp
->
DataLength
);
if
(
data_offset
+
data_len
>
rfclen
)
{
/* data_len is corrupt -- discard frame */
rdata
->
result
=
-
EIO
;
return
cifs_readv_discard
(
server
,
mid
);
}
/* marshal up the page array */
len
=
0
;
remaining
=
data_len
;
rdata
->
nr_iov
=
1
;
/* determine the eof that the server (probably) has */
eof
=
CIFS_I
(
rdata
->
mapping
->
host
)
->
server_eof
;
eof_index
=
eof
?
(
eof
-
1
)
>>
PAGE_CACHE_SHIFT
:
0
;
cFYI
(
1
,
"eof=%llu eof_index=%lu"
,
eof
,
eof_index
);
list_for_each_entry_safe
(
page
,
tpage
,
&
rdata
->
pages
,
lru
)
{
if
(
remaining
>=
PAGE_CACHE_SIZE
)
{
/* enough data to fill the page */
rdata
->
iov
[
rdata
->
nr_iov
].
iov_base
=
kmap
(
page
);
rdata
->
iov
[
rdata
->
nr_iov
].
iov_len
=
PAGE_CACHE_SIZE
;
cFYI
(
1
,
"%u: idx=%lu iov_base=%p iov_len=%zu"
,
rdata
->
nr_iov
,
page
->
index
,
rdata
->
iov
[
rdata
->
nr_iov
].
iov_base
,
rdata
->
iov
[
rdata
->
nr_iov
].
iov_len
);
++
rdata
->
nr_iov
;
len
+=
PAGE_CACHE_SIZE
;
remaining
-=
PAGE_CACHE_SIZE
;
}
else
if
(
remaining
>
0
)
{
/* enough for partial page, fill and zero the rest */
rdata
->
iov
[
rdata
->
nr_iov
].
iov_base
=
kmap
(
page
);
rdata
->
iov
[
rdata
->
nr_iov
].
iov_len
=
remaining
;
cFYI
(
1
,
"%u: idx=%lu iov_base=%p iov_len=%zu"
,
rdata
->
nr_iov
,
page
->
index
,
rdata
->
iov
[
rdata
->
nr_iov
].
iov_base
,
rdata
->
iov
[
rdata
->
nr_iov
].
iov_len
);
memset
(
rdata
->
iov
[
rdata
->
nr_iov
].
iov_base
+
remaining
,
'\0'
,
PAGE_CACHE_SIZE
-
remaining
);
++
rdata
->
nr_iov
;
len
+=
remaining
;
remaining
=
0
;
}
else
if
(
page
->
index
>
eof_index
)
{
/*
* The VFS will not try to do readahead past the
* i_size, but it's possible that we have outstanding
* writes with gaps in the middle and the i_size hasn't
* caught up yet. Populate those with zeroed out pages
* to prevent the VFS from repeatedly attempting to
* fill them until the writes are flushed.
*/
zero_user
(
page
,
0
,
PAGE_CACHE_SIZE
);
list_del
(
&
page
->
lru
);
lru_cache_add_file
(
page
);
flush_dcache_page
(
page
);
SetPageUptodate
(
page
);
unlock_page
(
page
);
page_cache_release
(
page
);
}
else
{
/* no need to hold page hostage */
list_del
(
&
page
->
lru
);
lru_cache_add_file
(
page
);
unlock_page
(
page
);
page_cache_release
(
page
);
}
}
/* issue the read if we have any iovecs left to fill */
if
(
rdata
->
nr_iov
>
1
)
{
length
=
cifs_readv_from_socket
(
server
,
&
rdata
->
iov
[
1
],
rdata
->
nr_iov
-
1
,
len
);
if
(
length
<
0
)
return
length
;
server
->
total_read
+=
length
;
}
else
{
length
=
0
;
}
rdata
->
bytes
=
length
;
cFYI
(
1
,
"total_read=%u rfclen=%u remaining=%u"
,
server
->
total_read
,
rfclen
,
remaining
);
/* discard anything left over */
if
(
server
->
total_read
<
rfclen
)
return
cifs_readv_discard
(
server
,
mid
);
dequeue_mid
(
mid
,
false
);
return
length
;
}
static
void
cifs_readv_complete
(
struct
work_struct
*
work
)
{
struct
cifs_readdata
*
rdata
=
container_of
(
work
,
struct
cifs_readdata
,
work
);
struct
page
*
page
,
*
tpage
;
list_for_each_entry_safe
(
page
,
tpage
,
&
rdata
->
pages
,
lru
)
{
list_del
(
&
page
->
lru
);
lru_cache_add_file
(
page
);
kunmap
(
page
);
if
(
rdata
->
result
==
0
)
{
flush_dcache_page
(
page
);
SetPageUptodate
(
page
);
}
unlock_page
(
page
);
if
(
rdata
->
result
==
0
)
cifs_readpage_to_fscache
(
rdata
->
mapping
->
host
,
page
);
page_cache_release
(
page
);
}
cifs_readdata_free
(
rdata
);
}
static
void
cifs_readv_callback
(
struct
mid_q_entry
*
mid
)
{
struct
cifs_readdata
*
rdata
=
mid
->
callback_data
;
struct
cifs_tcon
*
tcon
=
tlink_tcon
(
rdata
->
cfile
->
tlink
);
struct
TCP_Server_Info
*
server
=
tcon
->
ses
->
server
;
cFYI
(
1
,
"%s: mid=%u state=%d result=%d bytes=%u"
,
__func__
,
mid
->
mid
,
mid
->
midState
,
rdata
->
result
,
rdata
->
bytes
);
switch
(
mid
->
midState
)
{
case
MID_RESPONSE_RECEIVED
:
/* result already set, check signature */
if
(
server
->
sec_mode
&
(
SECMODE_SIGN_REQUIRED
|
SECMODE_SIGN_ENABLED
))
{
if
(
cifs_verify_signature
(
rdata
->
iov
,
rdata
->
nr_iov
,
server
,
mid
->
sequence_number
+
1
))
cERROR
(
1
,
"Unexpected SMB signature"
);
}
/* FIXME: should this be counted toward the initiating task? */
task_io_account_read
(
rdata
->
bytes
);
cifs_stats_bytes_read
(
tcon
,
rdata
->
bytes
);
break
;
case
MID_REQUEST_SUBMITTED
:
case
MID_RETRY_NEEDED
:
rdata
->
result
=
-
EAGAIN
;
break
;
default:
rdata
->
result
=
-
EIO
;
}
queue_work
(
system_nrt_wq
,
&
rdata
->
work
);
DeleteMidQEntry
(
mid
);
atomic_dec
(
&
server
->
inFlight
);
wake_up
(
&
server
->
request_q
);
}
/* cifs_async_readv - send an async write, and set up mid to handle result */
int
cifs_async_readv
(
struct
cifs_readdata
*
rdata
)
{
int
rc
;
READ_REQ
*
smb
=
NULL
;
int
wct
;
struct
cifs_tcon
*
tcon
=
tlink_tcon
(
rdata
->
cfile
->
tlink
);
cFYI
(
1
,
"%s: offset=%llu bytes=%u"
,
__func__
,
rdata
->
offset
,
rdata
->
bytes
);
if
(
tcon
->
ses
->
capabilities
&
CAP_LARGE_FILES
)
wct
=
12
;
else
{
wct
=
10
;
/* old style read */
if
((
rdata
->
offset
>>
32
)
>
0
)
{
/* can not handle this big offset for old */
return
-
EIO
;
}
}
rc
=
small_smb_init
(
SMB_COM_READ_ANDX
,
wct
,
tcon
,
(
void
**
)
&
smb
);
if
(
rc
)
return
rc
;
smb
->
hdr
.
Pid
=
cpu_to_le16
((
__u16
)
rdata
->
pid
);
smb
->
hdr
.
PidHigh
=
cpu_to_le16
((
__u16
)(
rdata
->
pid
>>
16
));
smb
->
AndXCommand
=
0xFF
;
/* none */
smb
->
Fid
=
rdata
->
cfile
->
netfid
;
smb
->
OffsetLow
=
cpu_to_le32
(
rdata
->
offset
&
0xFFFFFFFF
);
if
(
wct
==
12
)
smb
->
OffsetHigh
=
cpu_to_le32
(
rdata
->
offset
>>
32
);
smb
->
Remaining
=
0
;
smb
->
MaxCount
=
cpu_to_le16
(
rdata
->
bytes
&
0xFFFF
);
smb
->
MaxCountHigh
=
cpu_to_le32
(
rdata
->
bytes
>>
16
);
if
(
wct
==
12
)
smb
->
ByteCount
=
0
;
else
{
/* old style read */
struct
smb_com_readx_req
*
smbr
=
(
struct
smb_com_readx_req
*
)
smb
;
smbr
->
ByteCount
=
0
;
}
/* 4 for RFC1001 length + 1 for BCC */
rdata
->
iov
[
0
].
iov_base
=
smb
;
rdata
->
iov
[
0
].
iov_len
=
be32_to_cpu
(
smb
->
hdr
.
smb_buf_length
)
+
4
;
rc
=
cifs_call_async
(
tcon
->
ses
->
server
,
rdata
->
iov
,
1
,
cifs_readv_receive
,
cifs_readv_callback
,
rdata
,
false
);
if
(
rc
==
0
)
cifs_stats_inc
(
&
tcon
->
num_reads
);
cifs_small_buf_release
(
smb
);
return
rc
;
}
int
CIFSSMBRead
(
const
int
xid
,
struct
cifs_io_parms
*
io_parms
,
unsigned
int
*
nbytes
,
char
**
buf
,
int
*
pbuf_type
)
...
...
@@ -1834,7 +2194,7 @@ cifs_async_writev(struct cifs_writedata *wdata)
kref_get
(
&
wdata
->
refcount
);
rc
=
cifs_call_async
(
tcon
->
ses
->
server
,
iov
,
wdata
->
nr_pages
+
1
,
cifs_writev_callback
,
wdata
,
false
);
NULL
,
cifs_writev_callback
,
wdata
,
false
);
if
(
rc
==
0
)
cifs_stats_inc
(
&
tcon
->
num_writes
);
...
...
fs/cifs/connect.c
浏览文件 @
fbcae3ea
此差异已折叠。
点击以展开。
fs/cifs/file.c
浏览文件 @
fbcae3ea
...
...
@@ -32,6 +32,7 @@
#include <linux/delay.h>
#include <linux/mount.h>
#include <linux/slab.h>
#include <linux/swap.h>
#include <asm/div64.h>
#include "cifsfs.h"
#include "cifspdu.h"
...
...
@@ -1757,6 +1758,7 @@ cifs_iovec_read(struct file *file, const struct iovec *iov,
struct
smb_com_read_rsp
*
pSMBr
;
struct
cifs_io_parms
io_parms
;
char
*
read_data
;
unsigned
int
rsize
;
__u32
pid
;
if
(
!
nr_segs
)
...
...
@@ -1769,6 +1771,9 @@ cifs_iovec_read(struct file *file, const struct iovec *iov,
xid
=
GetXid
();
cifs_sb
=
CIFS_SB
(
file
->
f_path
.
dentry
->
d_sb
);
/* FIXME: set up handlers for larger reads and/or convert to async */
rsize
=
min_t
(
unsigned
int
,
cifs_sb
->
rsize
,
CIFSMaxBufSize
);
open_file
=
file
->
private_data
;
pTcon
=
tlink_tcon
(
open_file
->
tlink
);
...
...
@@ -1781,7 +1786,7 @@ cifs_iovec_read(struct file *file, const struct iovec *iov,
cFYI
(
1
,
"attempting read on write only file instance"
);
for
(
total_read
=
0
;
total_read
<
len
;
total_read
+=
bytes_read
)
{
cur_len
=
min_t
(
const
size_t
,
len
-
total_read
,
cifs_sb
->
rsize
);
cur_len
=
min_t
(
const
size_t
,
len
-
total_read
,
rsize
);
rc
=
-
EAGAIN
;
read_data
=
NULL
;
...
...
@@ -1873,6 +1878,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
unsigned
int
bytes_read
=
0
;
unsigned
int
total_read
;
unsigned
int
current_read_size
;
unsigned
int
rsize
;
struct
cifs_sb_info
*
cifs_sb
;
struct
cifs_tcon
*
pTcon
;
int
xid
;
...
...
@@ -1885,6 +1891,9 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
xid
=
GetXid
();
cifs_sb
=
CIFS_SB
(
file
->
f_path
.
dentry
->
d_sb
);
/* FIXME: set up handlers for larger reads and/or convert to async */
rsize
=
min_t
(
unsigned
int
,
cifs_sb
->
rsize
,
CIFSMaxBufSize
);
if
(
file
->
private_data
==
NULL
)
{
rc
=
-
EBADF
;
FreeXid
(
xid
);
...
...
@@ -1904,8 +1913,8 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
for
(
total_read
=
0
,
current_offset
=
read_data
;
read_size
>
total_read
;
total_read
+=
bytes_read
,
current_offset
+=
bytes_read
)
{
current_read_size
=
min_t
(
uint
,
read_size
-
total_read
,
cifs_sb
->
rsize
);
current_read_size
=
min_t
(
uint
,
read_size
-
total_read
,
rsize
);
/* For windows me and 9x we do not want to request more
than it negotiated since it will refuse the read then */
if
((
pTcon
->
ses
)
&&
...
...
@@ -2000,82 +2009,24 @@ int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
return
rc
;
}
static
void
cifs_copy_cache_pages
(
struct
address_space
*
mapping
,
struct
list_head
*
pages
,
int
bytes_read
,
char
*
data
)
{
struct
page
*
page
;
char
*
target
;
while
(
bytes_read
>
0
)
{
if
(
list_empty
(
pages
))
break
;
page
=
list_entry
(
pages
->
prev
,
struct
page
,
lru
);
list_del
(
&
page
->
lru
);
if
(
add_to_page_cache_lru
(
page
,
mapping
,
page
->
index
,
GFP_KERNEL
))
{
page_cache_release
(
page
);
cFYI
(
1
,
"Add page cache failed"
);
data
+=
PAGE_CACHE_SIZE
;
bytes_read
-=
PAGE_CACHE_SIZE
;
continue
;
}
page_cache_release
(
page
);
target
=
kmap_atomic
(
page
,
KM_USER0
);
if
(
PAGE_CACHE_SIZE
>
bytes_read
)
{
memcpy
(
target
,
data
,
bytes_read
);
/* zero the tail end of this partial page */
memset
(
target
+
bytes_read
,
0
,
PAGE_CACHE_SIZE
-
bytes_read
);
bytes_read
=
0
;
}
else
{
memcpy
(
target
,
data
,
PAGE_CACHE_SIZE
);
bytes_read
-=
PAGE_CACHE_SIZE
;
}
kunmap_atomic
(
target
,
KM_USER0
);
flush_dcache_page
(
page
);
SetPageUptodate
(
page
);
unlock_page
(
page
);
data
+=
PAGE_CACHE_SIZE
;
/* add page to FS-Cache */
cifs_readpage_to_fscache
(
mapping
->
host
,
page
);
}
return
;
}
static
int
cifs_readpages
(
struct
file
*
file
,
struct
address_space
*
mapping
,
struct
list_head
*
page_list
,
unsigned
num_pages
)
{
int
rc
=
-
EACCES
;
int
xid
;
loff_t
offset
;
struct
page
*
page
;
struct
cifs_sb_info
*
cifs_sb
;
struct
cifs_tcon
*
pTcon
;
unsigned
int
bytes_read
=
0
;
unsigned
int
read_size
,
i
;
char
*
smb_read_data
=
NULL
;
struct
smb_com_read_rsp
*
pSMBr
;
struct
cifsFileInfo
*
open_file
;
struct
cifs_io_parms
io_parms
;
int
buf_type
=
CIFS_NO_BUFFER
;
__u32
pid
;
int
rc
;
struct
list_head
tmplist
;
struct
cifsFileInfo
*
open_file
=
file
->
private_data
;
struct
cifs_sb_info
*
cifs_sb
=
CIFS_SB
(
file
->
f_path
.
dentry
->
d_sb
);
unsigned
int
rsize
=
cifs_sb
->
rsize
;
pid_t
pid
;
xid
=
GetXid
();
if
(
file
->
private_data
==
NULL
)
{
rc
=
-
EBADF
;
FreeXid
(
xid
);
return
rc
;
}
open_file
=
file
->
private_data
;
cifs_sb
=
CIFS_SB
(
file
->
f_path
.
dentry
->
d_sb
);
pTcon
=
tlink_tcon
(
open_file
->
tlink
);
/*
* Give up immediately if rsize is too small to read an entire page.
* The VFS will fall back to readpage. We should never reach this
* point however since we set ra_pages to 0 when the rsize is smaller
* than a cache page.
*/
if
(
unlikely
(
rsize
<
PAGE_CACHE_SIZE
))
return
0
;
/*
* Reads as many pages as possible from fscache. Returns -ENOBUFS
...
...
@@ -2084,125 +2035,127 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
rc
=
cifs_readpages_from_fscache
(
mapping
->
host
,
mapping
,
page_list
,
&
num_pages
);
if
(
rc
==
0
)
goto
read_complete
;
return
rc
;
cFYI
(
DBG2
,
"rpages: num pages %d"
,
num_pages
);
if
(
cifs_sb
->
mnt_cifs_flags
&
CIFS_MOUNT_RWPIDFORWARD
)
pid
=
open_file
->
pid
;
else
pid
=
current
->
tgid
;
for
(
i
=
0
;
i
<
num_pages
;
)
{
unsigned
contig_pages
;
struct
page
*
tmp_page
;
unsigned
long
expected_index
;
rc
=
0
;
INIT_LIST_HEAD
(
&
tmplist
);
cFYI
(
1
,
"%s: file=%p mapping=%p num_pages=%u"
,
__func__
,
file
,
mapping
,
num_pages
);
if
(
list_empty
(
page_list
))
break
;
/*
* Start with the page at end of list and move it to private
* list. Do the same with any following pages until we hit
* the rsize limit, hit an index discontinuity, or run out of
* pages. Issue the async read and then start the loop again
* until the list is empty.
*
* Note that list order is important. The page_list is in
* the order of declining indexes. When we put the pages in
* the rdata->pages, then we want them in increasing order.
*/
while
(
!
list_empty
(
page_list
))
{
unsigned
int
bytes
=
PAGE_CACHE_SIZE
;
unsigned
int
expected_index
;
unsigned
int
nr_pages
=
1
;
loff_t
offset
;
struct
page
*
page
,
*
tpage
;
struct
cifs_readdata
*
rdata
;
page
=
list_entry
(
page_list
->
prev
,
struct
page
,
lru
);
/*
* Lock the page and put it in the cache. Since no one else
* should have access to this page, we're safe to simply set
* PG_locked without checking it first.
*/
__set_page_locked
(
page
);
rc
=
add_to_page_cache_locked
(
page
,
mapping
,
page
->
index
,
GFP_KERNEL
);
/* give up if we can't stick it in the cache */
if
(
rc
)
{
__clear_page_locked
(
page
);
break
;
}
/* move first page to the tmplist */
offset
=
(
loff_t
)
page
->
index
<<
PAGE_CACHE_SHIFT
;
list_move_tail
(
&
page
->
lru
,
&
tmplist
);
/* count adjacent pages that we will read into */
contig_pages
=
0
;
expected_index
=
list_entry
(
page_list
->
prev
,
struct
page
,
lru
)
->
index
;
list_for_each_entry_reverse
(
tmp_page
,
page_list
,
lru
)
{
if
(
tmp_page
->
index
==
expected_index
)
{
contig_pages
++
;
expected_index
++
;
}
else
/* now try and add more pages onto the request */
expected_index
=
page
->
index
+
1
;
list_for_each_entry_safe_reverse
(
page
,
tpage
,
page_list
,
lru
)
{
/* discontinuity ? */
if
(
page
->
index
!=
expected_index
)
break
;
/* would this page push the read over the rsize? */
if
(
bytes
+
PAGE_CACHE_SIZE
>
rsize
)
break
;
__set_page_locked
(
page
);
if
(
add_to_page_cache_locked
(
page
,
mapping
,
page
->
index
,
GFP_KERNEL
))
{
__clear_page_locked
(
page
);
break
;
}
list_move_tail
(
&
page
->
lru
,
&
tmplist
);
bytes
+=
PAGE_CACHE_SIZE
;
expected_index
++
;
nr_pages
++
;
}
if
(
contig_pages
+
i
>
num_pages
)
contig_pages
=
num_pages
-
i
;
/* for reads over a certain size could initiate async
read ahead */
read_size
=
contig_pages
*
PAGE_CACHE_SIZE
;
/* Read size needs to be in multiples of one page */
read_size
=
min_t
(
const
unsigned
int
,
read_size
,
cifs_sb
->
rsize
&
PAGE_CACHE_MASK
);
cFYI
(
DBG2
,
"rpages: read size 0x%x contiguous pages %d"
,
read_size
,
contig_pages
);
rc
=
-
EAGAIN
;
while
(
rc
==
-
EAGAIN
)
{
rdata
=
cifs_readdata_alloc
(
nr_pages
);
if
(
!
rdata
)
{
/* best to give up if we're out of mem */
list_for_each_entry_safe
(
page
,
tpage
,
&
tmplist
,
lru
)
{
list_del
(
&
page
->
lru
);
lru_cache_add_file
(
page
);
unlock_page
(
page
);
page_cache_release
(
page
);
}
rc
=
-
ENOMEM
;
break
;
}
spin_lock
(
&
cifs_file_list_lock
);
cifsFileInfo_get
(
open_file
);
spin_unlock
(
&
cifs_file_list_lock
);
rdata
->
cfile
=
open_file
;
rdata
->
mapping
=
mapping
;
rdata
->
offset
=
offset
;
rdata
->
bytes
=
bytes
;
rdata
->
pid
=
pid
;
list_splice_init
(
&
tmplist
,
&
rdata
->
pages
);
do
{
if
(
open_file
->
invalidHandle
)
{
rc
=
cifs_reopen_file
(
open_file
,
true
);
if
(
rc
!=
0
)
break
;
continue
;
}
io_parms
.
netfid
=
open_file
->
netfid
;
io_parms
.
pid
=
pid
;
io_parms
.
tcon
=
pTcon
;
io_parms
.
offset
=
offset
;
io_parms
.
length
=
read_size
;
rc
=
CIFSSMBRead
(
xid
,
&
io_parms
,
&
bytes_read
,
&
smb_read_data
,
&
buf_type
);
/* BB more RC checks ? */
if
(
rc
==
-
EAGAIN
)
{
if
(
smb_read_data
)
{
if
(
buf_type
==
CIFS_SMALL_BUFFER
)
cifs_small_buf_release
(
smb_read_data
);
else
if
(
buf_type
==
CIFS_LARGE_BUFFER
)
cifs_buf_release
(
smb_read_data
);
smb_read_data
=
NULL
;
}
}
}
if
((
rc
<
0
)
||
(
smb_read_data
==
NULL
))
{
cFYI
(
1
,
"Read error in readpages: %d"
,
rc
);
break
;
}
else
if
(
bytes_read
>
0
)
{
task_io_account_read
(
bytes_read
);
pSMBr
=
(
struct
smb_com_read_rsp
*
)
smb_read_data
;
cifs_copy_cache_pages
(
mapping
,
page_list
,
bytes_read
,
smb_read_data
+
4
/* RFC1001 hdr */
+
le16_to_cpu
(
pSMBr
->
DataOffset
));
i
+=
bytes_read
>>
PAGE_CACHE_SHIFT
;
cifs_stats_bytes_read
(
pTcon
,
bytes_read
);
if
((
bytes_read
&
PAGE_CACHE_MASK
)
!=
bytes_read
)
{
i
++
;
/* account for partial page */
/* server copy of file can have smaller size
than client */
/* BB do we need to verify this common case ?
this case is ok - if we are at server EOF
we will hit it on next read */
rc
=
cifs_async_readv
(
rdata
);
}
while
(
rc
==
-
EAGAIN
);
/* break; */
if
(
rc
!=
0
)
{
list_for_each_entry_safe
(
page
,
tpage
,
&
rdata
->
pages
,
lru
)
{
list_del
(
&
page
->
lru
);
lru_cache_add_file
(
page
);
unlock_page
(
page
);
page_cache_release
(
page
);
}
}
else
{
cFYI
(
1
,
"No bytes read (%d) at offset %lld . "
"Cleaning remaining pages from readahead list"
,
bytes_read
,
offset
);
/* BB turn off caching and do new lookup on
file size at server? */
cifs_readdata_free
(
rdata
);
break
;
}
if
(
smb_read_data
)
{
if
(
buf_type
==
CIFS_SMALL_BUFFER
)
cifs_small_buf_release
(
smb_read_data
);
else
if
(
buf_type
==
CIFS_LARGE_BUFFER
)
cifs_buf_release
(
smb_read_data
);
smb_read_data
=
NULL
;
}
bytes_read
=
0
;
}
/* need to free smb_read_data buf before exit */
if
(
smb_read_data
)
{
if
(
buf_type
==
CIFS_SMALL_BUFFER
)
cifs_small_buf_release
(
smb_read_data
);
else
if
(
buf_type
==
CIFS_LARGE_BUFFER
)
cifs_buf_release
(
smb_read_data
);
smb_read_data
=
NULL
;
}
read_complete:
FreeXid
(
xid
);
return
rc
;
}
...
...
fs/cifs/transport.c
浏览文件 @
fbcae3ea
...
...
@@ -26,6 +26,7 @@
#include <linux/wait.h>
#include <linux/net.h>
#include <linux/delay.h>
#include <linux/freezer.h>
#include <asm/uaccess.h>
#include <asm/processor.h>
#include <linux/mempool.h>
...
...
@@ -324,7 +325,7 @@ wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *midQ)
{
int
error
;
error
=
wait_event_killable
(
server
->
response_q
,
error
=
wait_event_
freeze
killable
(
server
->
response_q
,
midQ
->
midState
!=
MID_REQUEST_SUBMITTED
);
if
(
error
<
0
)
return
-
ERESTARTSYS
;
...
...
@@ -339,8 +340,8 @@ wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *midQ)
*/
int
cifs_call_async
(
struct
TCP_Server_Info
*
server
,
struct
kvec
*
iov
,
unsigned
int
nvec
,
mid_
callback_t
*
callback
,
void
*
cbdata
,
bool
ignore_pend
)
unsigned
int
nvec
,
mid_
receive_t
*
receive
,
mid_callback_t
*
callback
,
void
*
cbdata
,
bool
ignore_pend
)
{
int
rc
;
struct
mid_q_entry
*
mid
;
...
...
@@ -374,6 +375,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
goto
out_err
;
}
mid
->
receive
=
receive
;
mid
->
callback
=
callback
;
mid
->
callback_data
=
cbdata
;
mid
->
midState
=
MID_REQUEST_SUBMITTED
;
...
...
include/linux/freezer.h
浏览文件 @
fbcae3ea
...
...
@@ -134,10 +134,25 @@ static inline void set_freezable_with_signal(void)
}
/*
* Freezer-friendly wrappers around wait_event_interruptible() and
* wait_event_interruptible_timeout(), originally defined in <linux/wait.h>
* Freezer-friendly wrappers around wait_event_interruptible(),
* wait_event_killable() and wait_event_interruptible_timeout(), originally
* defined in <linux/wait.h>
*/
#define wait_event_freezekillable(wq, condition) \
({ \
int __retval; \
do { \
__retval = wait_event_killable(wq, \
(condition) || freezing(current)); \
if (__retval && !freezing(current)) \
break; \
else if (!(condition)) \
__retval = -ERESTARTSYS; \
} while (try_to_freeze()); \
__retval; \
})
#define wait_event_freezable(wq, condition) \
({ \
int __retval; \
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录