Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
OpenHarmony
kernel_linux
提交
b7561e51
K
kernel_linux
项目概览
OpenHarmony
/
kernel_linux
上一次同步 4 年多
通知
15
Star
8
Fork
2
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
K
kernel_linux
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
提交
b7561e51
编写于
8月 18, 2017
作者:
T
Trond Myklebust
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'writeback'
上级
55cfcd12
ce7c252a
变更
20
显示空白变更内容
内联
并排
Showing
20 changed file
with
375 addition
and
407 deletion
+375
-407
fs/nfs/callback_proc.c
fs/nfs/callback_proc.c
+1
-1
fs/nfs/delegation.c
fs/nfs/delegation.c
+1
-1
fs/nfs/direct.c
fs/nfs/direct.c
+2
-2
fs/nfs/inode.c
fs/nfs/inode.c
+5
-5
fs/nfs/pagelist.c
fs/nfs/pagelist.c
+19
-48
fs/nfs/pnfs.c
fs/nfs/pnfs.c
+0
-41
fs/nfs/pnfs.h
fs/nfs/pnfs.h
+0
-2
fs/nfs/pnfs_nfs.c
fs/nfs/pnfs_nfs.c
+23
-14
fs/nfs/write.c
fs/nfs/write.c
+206
-234
include/linux/nfs_fs.h
include/linux/nfs_fs.h
+3
-2
include/linux/nfs_page.h
include/linux/nfs_page.h
+1
-2
include/linux/nfs_xdr.h
include/linux/nfs_xdr.h
+1
-1
include/linux/sunrpc/sched.h
include/linux/sunrpc/sched.h
+2
-0
include/linux/sunrpc/xprt.h
include/linux/sunrpc/xprt.h
+3
-0
net/sunrpc/backchannel_rqst.c
net/sunrpc/backchannel_rqst.c
+2
-2
net/sunrpc/svcsock.c
net/sunrpc/svcsock.c
+3
-3
net/sunrpc/xprt.c
net/sunrpc/xprt.c
+51
-4
net/sunrpc/xprtrdma/rpc_rdma.c
net/sunrpc/xprtrdma/rpc_rdma.c
+4
-4
net/sunrpc/xprtrdma/svc_rdma_backchannel.c
net/sunrpc/xprtrdma/svc_rdma_backchannel.c
+5
-2
net/sunrpc/xprtsock.c
net/sunrpc/xprtsock.c
+43
-39
未找到文件。
fs/nfs/callback_proc.c
浏览文件 @
b7561e51
...
...
@@ -51,7 +51,7 @@ __be32 nfs4_callback_getattr(void *argp, void *resp,
goto
out_iput
;
res
->
size
=
i_size_read
(
inode
);
res
->
change_attr
=
delegation
->
change_attr
;
if
(
nfs
i
->
nrequests
!=
0
)
if
(
nfs
_have_writebacks
(
inode
)
)
res
->
change_attr
++
;
res
->
ctime
=
inode
->
i_ctime
;
res
->
mtime
=
inode
->
i_mtime
;
...
...
fs/nfs/delegation.c
浏览文件 @
b7561e51
...
...
@@ -1089,7 +1089,7 @@ bool nfs4_delegation_flush_on_close(const struct inode *inode)
delegation
=
rcu_dereference
(
nfsi
->
delegation
);
if
(
delegation
==
NULL
||
!
(
delegation
->
type
&
FMODE_WRITE
))
goto
out
;
if
(
nfsi
->
nrequests
<
delegation
->
pagemod_limit
)
if
(
atomic_long_read
(
&
nfsi
->
nrequests
)
<
delegation
->
pagemod_limit
)
ret
=
false
;
out:
rcu_read_unlock
();
...
...
fs/nfs/direct.c
浏览文件 @
b7561e51
...
...
@@ -616,13 +616,13 @@ nfs_direct_write_scan_commit_list(struct inode *inode,
struct
list_head
*
list
,
struct
nfs_commit_info
*
cinfo
)
{
spin_lock
(
&
cinfo
->
inode
->
i_lock
);
mutex_lock
(
&
NFS_I
(
cinfo
->
inode
)
->
commit_mutex
);
#ifdef CONFIG_NFS_V4_1
if
(
cinfo
->
ds
!=
NULL
&&
cinfo
->
ds
->
nwritten
!=
0
)
NFS_SERVER
(
inode
)
->
pnfs_curr_ld
->
recover_commit_reqs
(
list
,
cinfo
);
#endif
nfs_scan_commit_list
(
&
cinfo
->
mds
->
list
,
list
,
cinfo
,
0
);
spin_unlock
(
&
cinfo
->
inode
->
i_lock
);
mutex_unlock
(
&
NFS_I
(
cinfo
->
inode
)
->
commit_mutex
);
}
static
void
nfs_direct_write_reschedule
(
struct
nfs_direct_req
*
dreq
)
...
...
fs/nfs/inode.c
浏览文件 @
b7561e51
...
...
@@ -1285,7 +1285,6 @@ static bool nfs_file_has_buffered_writers(struct nfs_inode *nfsi)
static
unsigned
long
nfs_wcc_update_inode
(
struct
inode
*
inode
,
struct
nfs_fattr
*
fattr
)
{
struct
nfs_inode
*
nfsi
=
NFS_I
(
inode
);
unsigned
long
ret
=
0
;
if
((
fattr
->
valid
&
NFS_ATTR_FATTR_PRECHANGE
)
...
...
@@ -1315,7 +1314,7 @@ static unsigned long nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr
if
((
fattr
->
valid
&
NFS_ATTR_FATTR_PRESIZE
)
&&
(
fattr
->
valid
&
NFS_ATTR_FATTR_SIZE
)
&&
i_size_read
(
inode
)
==
nfs_size_to_loff_t
(
fattr
->
pre_size
)
&&
nfsi
->
nrequests
==
0
)
{
&&
!
nfs_have_writebacks
(
inode
)
)
{
i_size_write
(
inode
,
nfs_size_to_loff_t
(
fattr
->
size
));
ret
|=
NFS_INO_INVALID_ATTR
;
}
...
...
@@ -1823,7 +1822,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
if
(
new_isize
!=
cur_isize
)
{
/* Do we perhaps have any outstanding writes, or has
* the file grown beyond our last write? */
if
(
nfsi
->
nrequests
==
0
||
new_isize
>
cur_isize
)
{
if
(
!
nfs_have_writebacks
(
inode
)
||
new_isize
>
cur_isize
)
{
i_size_write
(
inode
,
new_isize
);
if
(
!
have_writers
)
invalid
|=
NFS_INO_INVALID_ATTR
|
NFS_INO_INVALID_DATA
;
...
...
@@ -2012,10 +2011,11 @@ static void init_once(void *foo)
INIT_LIST_HEAD
(
&
nfsi
->
access_cache_entry_lru
);
INIT_LIST_HEAD
(
&
nfsi
->
access_cache_inode_lru
);
INIT_LIST_HEAD
(
&
nfsi
->
commit_info
.
list
);
nfsi
->
nrequests
=
0
;
nfsi
->
commit_info
.
ncommit
=
0
;
atomic_long_set
(
&
nfsi
->
nrequests
,
0
)
;
atomic_long_set
(
&
nfsi
->
commit_info
.
ncommit
,
0
)
;
atomic_set
(
&
nfsi
->
commit_info
.
rpcs_out
,
0
);
init_rwsem
(
&
nfsi
->
rmdir_sem
);
mutex_init
(
&
nfsi
->
commit_mutex
);
nfs4_init_once
(
nfsi
);
}
...
...
fs/nfs/pagelist.c
浏览文件 @
b7561e51
...
...
@@ -134,19 +134,14 @@ EXPORT_SYMBOL_GPL(nfs_async_iocounter_wait);
/*
* nfs_page_group_lock - lock the head of the page group
* @req - request in group that is to be locked
* @nonblock - if true don't block waiting for lock
*
* this lock must be held if modifying the page group list
* this lock must be held when traversing or modifying the page
* group list
*
* return 0 on success, < 0 on error: -EDELAY if nonblocking or the
* result from wait_on_bit_lock
*
* NOTE: calling with nonblock=false should always have set the
* lock bit (see fs/buffer.c and other uses of wait_on_bit_lock
* with TASK_UNINTERRUPTIBLE), so there is no need to check the result.
* return 0 on success, < 0 on error
*/
int
nfs_page_group_lock
(
struct
nfs_page
*
req
,
bool
nonblock
)
nfs_page_group_lock
(
struct
nfs_page
*
req
)
{
struct
nfs_page
*
head
=
req
->
wb_head
;
...
...
@@ -155,35 +150,10 @@ nfs_page_group_lock(struct nfs_page *req, bool nonblock)
if
(
!
test_and_set_bit
(
PG_HEADLOCK
,
&
head
->
wb_flags
))
return
0
;
if
(
!
nonblock
)
{
set_bit
(
PG_CONTENDED1
,
&
head
->
wb_flags
);
smp_mb__after_atomic
();
return
wait_on_bit_lock
(
&
head
->
wb_flags
,
PG_HEADLOCK
,
TASK_UNINTERRUPTIBLE
);
}
return
-
EAGAIN
;
}
/*
* nfs_page_group_lock_wait - wait for the lock to clear, but don't grab it
* @req - a request in the group
*
* This is a blocking call to wait for the group lock to be cleared.
*/
void
nfs_page_group_lock_wait
(
struct
nfs_page
*
req
)
{
struct
nfs_page
*
head
=
req
->
wb_head
;
WARN_ON_ONCE
(
head
!=
head
->
wb_head
);
if
(
!
test_bit
(
PG_HEADLOCK
,
&
head
->
wb_flags
))
return
;
set_bit
(
PG_CONTENDED1
,
&
head
->
wb_flags
);
smp_mb__after_atomic
();
wait_on_bit
(
&
head
->
wb_flags
,
PG_HEADLOCK
,
TASK_UNINTERRUPTIBLE
);
}
/*
...
...
@@ -246,7 +216,7 @@ bool nfs_page_group_sync_on_bit(struct nfs_page *req, unsigned int bit)
{
bool
ret
;
nfs_page_group_lock
(
req
,
false
);
nfs_page_group_lock
(
req
);
ret
=
nfs_page_group_sync_on_bit_locked
(
req
,
bit
);
nfs_page_group_unlock
(
req
);
...
...
@@ -288,9 +258,7 @@ nfs_page_group_init(struct nfs_page *req, struct nfs_page *prev)
inode
=
page_file_mapping
(
req
->
wb_page
)
->
host
;
set_bit
(
PG_INODE_REF
,
&
req
->
wb_flags
);
kref_get
(
&
req
->
wb_kref
);
spin_lock
(
&
inode
->
i_lock
);
NFS_I
(
inode
)
->
nrequests
++
;
spin_unlock
(
&
inode
->
i_lock
);
atomic_long_inc
(
&
NFS_I
(
inode
)
->
nrequests
);
}
}
}
...
...
@@ -306,14 +274,11 @@ static void
nfs_page_group_destroy
(
struct
kref
*
kref
)
{
struct
nfs_page
*
req
=
container_of
(
kref
,
struct
nfs_page
,
wb_kref
);
struct
nfs_page
*
head
=
req
->
wb_head
;
struct
nfs_page
*
tmp
,
*
next
;
/* subrequests must release the ref on the head request */
if
(
req
->
wb_head
!=
req
)
nfs_release_request
(
req
->
wb_head
);
if
(
!
nfs_page_group_sync_on_bit
(
req
,
PG_TEARDOWN
))
return
;
goto
out
;
tmp
=
req
;
do
{
...
...
@@ -324,6 +289,10 @@ nfs_page_group_destroy(struct kref *kref)
nfs_free_request
(
tmp
);
tmp
=
next
;
}
while
(
tmp
!=
req
);
out:
/* subrequests must release the ref on the head request */
if
(
head
!=
req
)
nfs_release_request
(
head
);
}
/**
...
...
@@ -465,6 +434,7 @@ void nfs_release_request(struct nfs_page *req)
{
kref_put
(
&
req
->
wb_kref
,
nfs_page_group_destroy
);
}
EXPORT_SYMBOL_GPL
(
nfs_release_request
);
/**
* nfs_wait_on_request - Wait for a request to complete.
...
...
@@ -483,6 +453,7 @@ nfs_wait_on_request(struct nfs_page *req)
return
wait_on_bit_io
(
&
req
->
wb_flags
,
PG_BUSY
,
TASK_UNINTERRUPTIBLE
);
}
EXPORT_SYMBOL_GPL
(
nfs_wait_on_request
);
/*
* nfs_generic_pg_test - determine if requests can be coalesced
...
...
@@ -1036,7 +1007,7 @@ static int __nfs_pageio_add_request(struct nfs_pageio_descriptor *desc,
unsigned
int
bytes_left
=
0
;
unsigned
int
offset
,
pgbase
;
nfs_page_group_lock
(
req
,
false
);
nfs_page_group_lock
(
req
);
subreq
=
req
;
bytes_left
=
subreq
->
wb_bytes
;
...
...
@@ -1058,7 +1029,7 @@ static int __nfs_pageio_add_request(struct nfs_pageio_descriptor *desc,
if
(
mirror
->
pg_recoalesce
)
return
0
;
/* retry add_request for this subreq */
nfs_page_group_lock
(
req
,
false
);
nfs_page_group_lock
(
req
);
continue
;
}
...
...
@@ -1155,7 +1126,7 @@ int nfs_pageio_add_request(struct nfs_pageio_descriptor *desc,
for
(
midx
=
0
;
midx
<
desc
->
pg_mirror_count
;
midx
++
)
{
if
(
midx
)
{
nfs_page_group_lock
(
req
,
false
);
nfs_page_group_lock
(
req
);
/* find the last request */
for
(
lastreq
=
req
->
wb_head
;
...
...
fs/nfs/pnfs.c
浏览文件 @
b7561e51
...
...
@@ -529,47 +529,6 @@ pnfs_put_lseg(struct pnfs_layout_segment *lseg)
}
EXPORT_SYMBOL_GPL
(
pnfs_put_lseg
);
static
void
pnfs_free_lseg_async_work
(
struct
work_struct
*
work
)
{
struct
pnfs_layout_segment
*
lseg
;
struct
pnfs_layout_hdr
*
lo
;
lseg
=
container_of
(
work
,
struct
pnfs_layout_segment
,
pls_work
);
lo
=
lseg
->
pls_layout
;
pnfs_free_lseg
(
lseg
);
pnfs_put_layout_hdr
(
lo
);
}
static
void
pnfs_free_lseg_async
(
struct
pnfs_layout_segment
*
lseg
)
{
INIT_WORK
(
&
lseg
->
pls_work
,
pnfs_free_lseg_async_work
);
schedule_work
(
&
lseg
->
pls_work
);
}
void
pnfs_put_lseg_locked
(
struct
pnfs_layout_segment
*
lseg
)
{
if
(
!
lseg
)
return
;
assert_spin_locked
(
&
lseg
->
pls_layout
->
plh_inode
->
i_lock
);
dprintk
(
"%s: lseg %p ref %d valid %d
\n
"
,
__func__
,
lseg
,
atomic_read
(
&
lseg
->
pls_refcount
),
test_bit
(
NFS_LSEG_VALID
,
&
lseg
->
pls_flags
));
if
(
atomic_dec_and_test
(
&
lseg
->
pls_refcount
))
{
struct
pnfs_layout_hdr
*
lo
=
lseg
->
pls_layout
;
if
(
test_bit
(
NFS_LSEG_VALID
,
&
lseg
->
pls_flags
))
return
;
pnfs_layout_remove_lseg
(
lo
,
lseg
);
if
(
!
pnfs_cache_lseg_for_layoutreturn
(
lo
,
lseg
))
{
pnfs_get_layout_hdr
(
lo
);
pnfs_free_lseg_async
(
lseg
);
}
}
}
/*
* is l2 fully contained in l1?
* start1 end1
...
...
fs/nfs/pnfs.h
浏览文件 @
b7561e51
...
...
@@ -67,7 +67,6 @@ struct pnfs_layout_segment {
u32
pls_seq
;
unsigned
long
pls_flags
;
struct
pnfs_layout_hdr
*
pls_layout
;
struct
work_struct
pls_work
;
};
enum
pnfs_try_status
{
...
...
@@ -230,7 +229,6 @@ extern int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp, bool sync);
/* pnfs.c */
void
pnfs_get_layout_hdr
(
struct
pnfs_layout_hdr
*
lo
);
void
pnfs_put_lseg
(
struct
pnfs_layout_segment
*
lseg
);
void
pnfs_put_lseg_locked
(
struct
pnfs_layout_segment
*
lseg
);
void
set_pnfs_layoutdriver
(
struct
nfs_server
*
,
const
struct
nfs_fh
*
,
struct
nfs_fsinfo
*
);
void
unset_pnfs_layoutdriver
(
struct
nfs_server
*
);
...
...
fs/nfs/pnfs_nfs.c
浏览文件 @
b7561e51
...
...
@@ -83,7 +83,7 @@ pnfs_generic_clear_request_commit(struct nfs_page *req,
}
out:
nfs_request_remove_commit_list
(
req
,
cinfo
);
pnfs_put_lseg
_locked
(
freeme
);
pnfs_put_lseg
(
freeme
);
}
EXPORT_SYMBOL_GPL
(
pnfs_generic_clear_request_commit
);
...
...
@@ -91,21 +91,30 @@ static int
pnfs_generic_transfer_commit_list
(
struct
list_head
*
src
,
struct
list_head
*
dst
,
struct
nfs_commit_info
*
cinfo
,
int
max
)
{
struct
nfs_page
*
req
,
*
tmp
;
struct
nfs_page
*
req
;
int
ret
=
0
;
list_for_each_entry_safe
(
req
,
tmp
,
src
,
wb_list
)
{
if
(
!
nfs_lock_request
(
req
))
continue
;
while
(
!
list_empty
(
src
)
)
{
req
=
list_first_entry
(
src
,
struct
nfs_page
,
wb_list
);
kref_get
(
&
req
->
wb_kref
);
if
(
cond_resched_lock
(
&
cinfo
->
inode
->
i_lock
))
list_safe_reset_next
(
req
,
tmp
,
wb_list
);
if
(
!
nfs_lock_request
(
req
))
{
int
status
;
mutex_unlock
(
&
NFS_I
(
cinfo
->
inode
)
->
commit_mutex
);
status
=
nfs_wait_on_request
(
req
);
nfs_release_request
(
req
);
mutex_lock
(
&
NFS_I
(
cinfo
->
inode
)
->
commit_mutex
);
if
(
status
<
0
)
break
;
continue
;
}
nfs_request_remove_commit_list
(
req
,
cinfo
);
clear_bit
(
PG_COMMIT_TO_DS
,
&
req
->
wb_flags
);
nfs_list_add_request
(
req
,
dst
);
ret
++
;
if
((
ret
==
max
)
&&
!
cinfo
->
dreq
)
break
;
cond_resched
();
}
return
ret
;
}
...
...
@@ -119,7 +128,7 @@ pnfs_generic_scan_ds_commit_list(struct pnfs_commit_bucket *bucket,
struct
list_head
*
dst
=
&
bucket
->
committing
;
int
ret
;
lockdep_assert_held
(
&
cinfo
->
inode
->
i_lock
);
lockdep_assert_held
(
&
NFS_I
(
cinfo
->
inode
)
->
commit_mutex
);
ret
=
pnfs_generic_transfer_commit_list
(
src
,
dst
,
cinfo
,
max
);
if
(
ret
)
{
cinfo
->
ds
->
nwritten
-=
ret
;
...
...
@@ -127,7 +136,7 @@ pnfs_generic_scan_ds_commit_list(struct pnfs_commit_bucket *bucket,
if
(
bucket
->
clseg
==
NULL
)
bucket
->
clseg
=
pnfs_get_lseg
(
bucket
->
wlseg
);
if
(
list_empty
(
src
))
{
pnfs_put_lseg
_locked
(
bucket
->
wlseg
);
pnfs_put_lseg
(
bucket
->
wlseg
);
bucket
->
wlseg
=
NULL
;
}
}
...
...
@@ -142,7 +151,7 @@ int pnfs_generic_scan_commit_lists(struct nfs_commit_info *cinfo,
{
int
i
,
rv
=
0
,
cnt
;
lockdep_assert_held
(
&
cinfo
->
inode
->
i_lock
);
lockdep_assert_held
(
&
NFS_I
(
cinfo
->
inode
)
->
commit_mutex
);
for
(
i
=
0
;
i
<
cinfo
->
ds
->
nbuckets
&&
max
!=
0
;
i
++
)
{
cnt
=
pnfs_generic_scan_ds_commit_list
(
&
cinfo
->
ds
->
buckets
[
i
],
cinfo
,
max
);
...
...
@@ -162,7 +171,7 @@ void pnfs_generic_recover_commit_reqs(struct list_head *dst,
int
nwritten
;
int
i
;
lockdep_assert_held
(
&
cinfo
->
inode
->
i_lock
);
lockdep_assert_held
(
&
NFS_I
(
cinfo
->
inode
)
->
commit_mutex
);
restart:
for
(
i
=
0
,
b
=
cinfo
->
ds
->
buckets
;
i
<
cinfo
->
ds
->
nbuckets
;
i
++
,
b
++
)
{
nwritten
=
pnfs_generic_transfer_commit_list
(
&
b
->
written
,
...
...
@@ -953,12 +962,12 @@ pnfs_layout_mark_request_commit(struct nfs_page *req,
struct
list_head
*
list
;
struct
pnfs_commit_bucket
*
buckets
;
spin_lock
(
&
cinfo
->
inode
->
i_lock
);
mutex_lock
(
&
NFS_I
(
cinfo
->
inode
)
->
commit_mutex
);
buckets
=
cinfo
->
ds
->
buckets
;
list
=
&
buckets
[
ds_commit_idx
].
written
;
if
(
list_empty
(
list
))
{
if
(
!
pnfs_is_valid_lseg
(
lseg
))
{
spin_unlock
(
&
cinfo
->
inode
->
i_lock
);
mutex_unlock
(
&
NFS_I
(
cinfo
->
inode
)
->
commit_mutex
);
cinfo
->
completion_ops
->
resched_write
(
cinfo
,
req
);
return
;
}
...
...
@@ -975,7 +984,7 @@ pnfs_layout_mark_request_commit(struct nfs_page *req,
cinfo
->
ds
->
nwritten
++
;
nfs_request_add_commit_list_locked
(
req
,
list
,
cinfo
);
spin_unlock
(
&
cinfo
->
inode
->
i_lock
);
mutex_unlock
(
&
NFS_I
(
cinfo
->
inode
)
->
commit_mutex
);
nfs_mark_page_unstable
(
req
->
wb_page
,
cinfo
);
}
EXPORT_SYMBOL_GPL
(
pnfs_layout_mark_request_commit
);
...
...
fs/nfs/write.c
浏览文件 @
b7561e51
...
...
@@ -154,6 +154,14 @@ static void nfs_context_set_write_error(struct nfs_open_context *ctx, int error)
set_bit
(
NFS_CONTEXT_ERROR_WRITE
,
&
ctx
->
flags
);
}
static
struct
nfs_page
*
nfs_page_private_request
(
struct
page
*
page
)
{
if
(
!
PagePrivate
(
page
))
return
NULL
;
return
(
struct
nfs_page
*
)
page_private
(
page
);
}
/*
* nfs_page_find_head_request_locked - find head request associated with @page
*
...
...
@@ -162,21 +170,41 @@ static void nfs_context_set_write_error(struct nfs_open_context *ctx, int error)
* returns matching head request with reference held, or NULL if not found.
*/
static
struct
nfs_page
*
nfs_page_find_
head_request_locked
(
struct
nfs_inode
*
nfsi
,
struct
page
*
page
)
nfs_page_find_
private_request
(
struct
page
*
page
)
{
struct
nfs_page
*
req
=
NULL
;
struct
address_space
*
mapping
=
page_file_mapping
(
page
);
struct
nfs_page
*
req
;
if
(
PagePrivate
(
page
))
req
=
(
struct
nfs_page
*
)
page_private
(
page
);
else
if
(
unlikely
(
PageSwapCache
(
page
)))
if
(
!
PagePrivate
(
page
))
return
NULL
;
spin_lock
(
&
mapping
->
private_lock
);
req
=
nfs_page_private_request
(
page
);
if
(
req
)
{
WARN_ON_ONCE
(
req
->
wb_head
!=
req
);
kref_get
(
&
req
->
wb_kref
);
}
spin_unlock
(
&
mapping
->
private_lock
);
return
req
;
}
static
struct
nfs_page
*
nfs_page_find_swap_request
(
struct
page
*
page
)
{
struct
inode
*
inode
=
page_file_mapping
(
page
)
->
host
;
struct
nfs_inode
*
nfsi
=
NFS_I
(
inode
);
struct
nfs_page
*
req
=
NULL
;
if
(
!
PageSwapCache
(
page
))
return
NULL
;
mutex_lock
(
&
nfsi
->
commit_mutex
);
if
(
PageSwapCache
(
page
))
{
req
=
nfs_page_search_commits_for_head_request_locked
(
nfsi
,
page
);
if
(
req
)
{
WARN_ON_ONCE
(
req
->
wb_head
!=
req
);
kref_get
(
&
req
->
wb_kref
);
}
}
mutex_unlock
(
&
nfsi
->
commit_mutex
);
return
req
;
}
...
...
@@ -187,12 +215,11 @@ nfs_page_find_head_request_locked(struct nfs_inode *nfsi, struct page *page)
*/
static
struct
nfs_page
*
nfs_page_find_head_request
(
struct
page
*
page
)
{
struct
inode
*
inode
=
page_file_mapping
(
page
)
->
host
;
struct
nfs_page
*
req
=
NULL
;
struct
nfs_page
*
req
;
spin_lock
(
&
inode
->
i_lock
);
req
=
nfs_page_find_head_request_locked
(
NFS_I
(
inode
),
page
);
spin_unlock
(
&
inode
->
i_lock
);
req
=
nfs_page_find_private_request
(
page
);
if
(
!
req
)
req
=
nfs_page_find_swap_request
(
page
);
return
req
;
}
...
...
@@ -241,9 +268,6 @@ nfs_page_group_search_locked(struct nfs_page *head, unsigned int page_offset)
{
struct
nfs_page
*
req
;
WARN_ON_ONCE
(
head
!=
head
->
wb_head
);
WARN_ON_ONCE
(
!
test_bit
(
PG_HEADLOCK
,
&
head
->
wb_head
->
wb_flags
));
req
=
head
;
do
{
if
(
page_offset
>=
req
->
wb_pgbase
&&
...
...
@@ -269,20 +293,17 @@ static bool nfs_page_group_covers_page(struct nfs_page *req)
unsigned
int
pos
=
0
;
unsigned
int
len
=
nfs_page_length
(
req
->
wb_page
);
nfs_page_group_lock
(
req
,
false
);
nfs_page_group_lock
(
req
);
do
{
for
(;;)
{
tmp
=
nfs_page_group_search_locked
(
req
->
wb_head
,
pos
);
if
(
tmp
)
{
/* no way this should happen */
WARN_ON_ONCE
(
tmp
->
wb_pgbase
!=
pos
);
pos
+=
tmp
->
wb_bytes
-
(
pos
-
tmp
->
wb_pgbase
);
if
(
!
tmp
)
break
;
pos
=
tmp
->
wb_pgbase
+
tmp
->
wb_bytes
;
}
}
while
(
tmp
&&
pos
<
len
);
nfs_page_group_unlock
(
req
);
WARN_ON_ONCE
(
pos
>
len
);
return
pos
==
len
;
return
pos
>=
len
;
}
/* We can set the PG_uptodate flag if we see that a write request
...
...
@@ -333,8 +354,11 @@ static void nfs_end_page_writeback(struct nfs_page *req)
{
struct
inode
*
inode
=
page_file_mapping
(
req
->
wb_page
)
->
host
;
struct
nfs_server
*
nfss
=
NFS_SERVER
(
inode
);
bool
is_done
;
if
(
!
nfs_page_group_sync_on_bit
(
req
,
PG_WB_END
))
is_done
=
nfs_page_group_sync_on_bit
(
req
,
PG_WB_END
);
nfs_unlock_request
(
req
);
if
(
!
is_done
)
return
;
end_page_writeback
(
req
->
wb_page
);
...
...
@@ -342,22 +366,6 @@ static void nfs_end_page_writeback(struct nfs_page *req)
clear_bdi_congested
(
inode_to_bdi
(
inode
),
BLK_RW_ASYNC
);
}
/* nfs_page_group_clear_bits
* @req - an nfs request
* clears all page group related bits from @req
*/
static
void
nfs_page_group_clear_bits
(
struct
nfs_page
*
req
)
{
clear_bit
(
PG_TEARDOWN
,
&
req
->
wb_flags
);
clear_bit
(
PG_UNLOCKPAGE
,
&
req
->
wb_flags
);
clear_bit
(
PG_UPTODATE
,
&
req
->
wb_flags
);
clear_bit
(
PG_WB_END
,
&
req
->
wb_flags
);
clear_bit
(
PG_REMOVE
,
&
req
->
wb_flags
);
}
/*
* nfs_unroll_locks_and_wait - unlock all newly locked reqs and wait on @req
*
...
...
@@ -366,43 +374,24 @@ nfs_page_group_clear_bits(struct nfs_page *req)
* @inode - inode associated with request page group, must be holding inode lock
* @head - head request of page group, must be holding head lock
* @req - request that couldn't lock and needs to wait on the req bit lock
* @nonblock - if true, don't actually wait
*
* NOTE: this must be called holding page_group bit lock
and inode spin lock
*
and BOTH
will be released before returning.
* NOTE: this must be called holding page_group bit lock
*
which
will be released before returning.
*
* returns 0 on success, < 0 on error.
*/
static
int
nfs_unroll_locks_and_wait
(
struct
inode
*
inode
,
struct
nfs_page
*
head
,
struct
nfs_page
*
req
,
bool
nonblock
)
__releases
(
&
inode
->
i_lock
)
static
void
nfs_unroll_locks
(
struct
inode
*
inode
,
struct
nfs_page
*
head
,
struct
nfs_page
*
req
)
{
struct
nfs_page
*
tmp
;
int
ret
;
/* relinquish all the locks successfully grabbed this run */
for
(
tmp
=
head
;
tmp
!=
req
;
tmp
=
tmp
->
wb_this_page
)
nfs_unlock_request
(
tmp
);
WARN_ON_ONCE
(
test_bit
(
PG_TEARDOWN
,
&
req
->
wb_flags
));
/* grab a ref on the request that will be waited on */
kref_get
(
&
req
->
wb_kref
);
nfs_page_group_unlock
(
head
);
spin_unlock
(
&
inode
->
i_lock
);
/* release ref from nfs_page_find_head_request_locked */
nfs_release_request
(
head
);
if
(
!
nonblock
)
ret
=
nfs_wait_on_request
(
req
);
else
ret
=
-
EAGAIN
;
nfs_release_request
(
req
);
return
ret
;
for
(
tmp
=
head
->
wb_this_page
;
tmp
!=
req
;
tmp
=
tmp
->
wb_this_page
)
{
if
(
!
kref_read
(
&
tmp
->
wb_kref
))
continue
;
nfs_unlock_and_release_request
(
tmp
);
}
}
/*
...
...
@@ -417,7 +406,8 @@ nfs_unroll_locks_and_wait(struct inode *inode, struct nfs_page *head,
*/
static
void
nfs_destroy_unlinked_subrequests
(
struct
nfs_page
*
destroy_list
,
struct
nfs_page
*
old_head
)
struct
nfs_page
*
old_head
,
struct
inode
*
inode
)
{
while
(
destroy_list
)
{
struct
nfs_page
*
subreq
=
destroy_list
;
...
...
@@ -428,33 +418,28 @@ nfs_destroy_unlinked_subrequests(struct nfs_page *destroy_list,
WARN_ON_ONCE
(
old_head
!=
subreq
->
wb_head
);
/* make sure old group is not used */
subreq
->
wb_head
=
subreq
;
subreq
->
wb_this_page
=
subreq
;
/* subreq is now totally disconnected from page group or any
* write / commit lists. last chance to wake any waiters */
nfs_unlock_request
(
subreq
);
clear_bit
(
PG_REMOVE
,
&
subreq
->
wb_flags
);
if
(
!
test_bit
(
PG_TEARDOWN
,
&
subreq
->
wb_flags
))
{
/* release ref on old head request */
nfs_release_request
(
old_head
);
/* Note: races with nfs_page_group_destroy() */
if
(
!
kref_read
(
&
subreq
->
wb_kref
))
{
/* Check if we raced with nfs_page_group_destroy() */
if
(
test_and_clear_bit
(
PG_TEARDOWN
,
&
subreq
->
wb_flags
))
nfs_free_request
(
subreq
);
continue
;
}
nfs_page_group_clear_bits
(
subreq
)
;
subreq
->
wb_head
=
subreq
;
/* release the PG_INODE_REF reference */
if
(
test_and_clear_bit
(
PG_INODE_REF
,
&
subreq
->
wb_flags
))
if
(
test_and_clear_bit
(
PG_INODE_REF
,
&
subreq
->
wb_flags
))
{
nfs_release_request
(
subreq
);
else
WARN_ON_ONCE
(
1
);
}
else
{
WARN_ON_ONCE
(
test_bit
(
PG_CLEAN
,
&
subreq
->
wb_flags
));
/* zombie requests have already released the last
* reference and were waiting on the rest of the
* group to complete. Since it's no longer part of a
* group, simply free the request */
nfs_page_group_clear_bits
(
subreq
);
nfs_free_request
(
subreq
);
atomic_long_dec
(
&
NFS_I
(
inode
)
->
nrequests
);
}
/* subreq is now totally disconnected from page group or any
* write / commit lists. last chance to wake any waiters */
nfs_unlock_and_release_request
(
subreq
);
}
}
...
...
@@ -464,7 +449,6 @@ nfs_destroy_unlinked_subrequests(struct nfs_page *destroy_list,
* operations for this page.
*
* @page - the page used to lookup the "page group" of nfs_page structures
* @nonblock - if true, don't block waiting for request locks
*
* This function joins all sub requests to the head request by first
* locking all requests in the group, cancelling any pending operations
...
...
@@ -478,7 +462,7 @@ nfs_destroy_unlinked_subrequests(struct nfs_page *destroy_list,
* error was encountered.
*/
static
struct
nfs_page
*
nfs_lock_and_join_requests
(
struct
page
*
page
,
bool
nonblock
)
nfs_lock_and_join_requests
(
struct
page
*
page
)
{
struct
inode
*
inode
=
page_file_mapping
(
page
)
->
host
;
struct
nfs_page
*
head
,
*
subreq
;
...
...
@@ -487,43 +471,59 @@ nfs_lock_and_join_requests(struct page *page, bool nonblock)
int
ret
;
try_again:
total_bytes
=
0
;
WARN_ON_ONCE
(
destroy_list
);
spin_lock
(
&
inode
->
i_lock
);
/*
* A reference is taken only on the head request which acts as a
* reference to the whole page group - the group will not be destroyed
* until the head reference is released.
*/
head
=
nfs_page_find_head_request_locked
(
NFS_I
(
inode
),
page
);
if
(
!
head
)
{
spin_unlock
(
&
inode
->
i_lock
);
head
=
nfs_page_find_head_request
(
page
);
if
(
!
head
)
return
NULL
;
}
/* holding inode lock, so always make a non-blocking call to try the
* page group lock */
ret
=
nfs_page_group_lock
(
head
,
true
);
if
(
ret
<
0
)
{
spin_unlock
(
&
inode
->
i_lock
);
if
(
!
nonblock
&&
ret
==
-
EAGAIN
)
{
nfs_page_group_lock_wait
(
head
);
/* lock the page head first in order to avoid an ABBA inefficiency */
if
(
!
nfs_lock_request
(
head
))
{
ret
=
nfs_wait_on_request
(
head
);
nfs_release_request
(
head
);
if
(
ret
<
0
)
return
ERR_PTR
(
ret
);
goto
try_again
;
}
nfs_release_request
(
head
);
/* Ensure that nobody removed the request before we locked it */
if
(
head
!=
nfs_page_private_request
(
page
)
&&
!
PageSwapCache
(
page
))
{
nfs_unlock_and_release_request
(
head
);
goto
try_again
;
}
ret
=
nfs_page_group_lock
(
head
);
if
(
ret
<
0
)
{
nfs_unlock_and_release_request
(
head
);
return
ERR_PTR
(
ret
);
}
/* lock each request in the page group */
subreq
=
head
;
do
{
total_bytes
=
head
->
wb_bytes
;
for
(
subreq
=
head
->
wb_this_page
;
subreq
!=
head
;
subreq
=
subreq
->
wb_this_page
)
{
if
(
!
kref_get_unless_zero
(
&
subreq
->
wb_kref
))
continue
;
while
(
!
nfs_lock_request
(
subreq
))
{
/*
* Unlock page to allow nfs_page_group_sync_on_bit()
* to succeed
*/
nfs_page_group_unlock
(
head
);
ret
=
nfs_wait_on_request
(
subreq
);
if
(
!
ret
)
ret
=
nfs_page_group_lock
(
head
);
if
(
ret
<
0
)
{
nfs_unroll_locks
(
inode
,
head
,
subreq
);
nfs_release_request
(
subreq
);
nfs_unlock_and_release_request
(
head
);
return
ERR_PTR
(
ret
);
}
}
/*
* Subrequests are always contiguous, non overlapping
* and in order - but may be repeated (mirrored writes).
...
...
@@ -534,26 +534,14 @@ nfs_lock_and_join_requests(struct page *page, bool nonblock)
}
else
if
(
WARN_ON_ONCE
(
subreq
->
wb_offset
<
head
->
wb_offset
||
((
subreq
->
wb_offset
+
subreq
->
wb_bytes
)
>
(
head
->
wb_offset
+
total_bytes
))))
{
nfs_unroll_locks
(
inode
,
head
,
subreq
);
nfs_unlock_and_release_request
(
subreq
);
nfs_page_group_unlock
(
head
);
spin_unlock
(
&
inode
->
i_lock
);
nfs_unlock_and_release_request
(
head
);
return
ERR_PTR
(
-
EIO
);
}
if
(
!
nfs_lock_request
(
subreq
))
{
/* releases page group bit lock and
* inode spin lock and all references */
ret
=
nfs_unroll_locks_and_wait
(
inode
,
head
,
subreq
,
nonblock
);
if
(
ret
==
0
)
goto
try_again
;
return
ERR_PTR
(
ret
);
}
subreq
=
subreq
->
wb_this_page
;
}
while
(
subreq
!=
head
);
/* Now that all requests are locked, make sure they aren't on any list.
* Commit list removal accounting is done after locks are dropped */
subreq
=
head
;
...
...
@@ -573,34 +561,30 @@ nfs_lock_and_join_requests(struct page *page, bool nonblock)
head
->
wb_bytes
=
total_bytes
;
}
/*
* prepare head request to be added to new pgio descriptor
*/
nfs_page_group_clear_bits
(
head
);
/*
* some part of the group was still on the inode list - otherwise
* the group wouldn't be involved in async write.
* grab a reference for the head request, iff it needs one.
*/
if
(
!
test_and_set_bit
(
PG_INODE_REF
,
&
head
->
wb_flags
))
/* Postpone destruction of this request */
if
(
test_and_clear_bit
(
PG_REMOVE
,
&
head
->
wb_flags
))
{
set_bit
(
PG_INODE_REF
,
&
head
->
wb_flags
);
kref_get
(
&
head
->
wb_kref
);
atomic_long_inc
(
&
NFS_I
(
inode
)
->
nrequests
);
}
nfs_page_group_unlock
(
head
);
/* drop lock to clean uprequests on destroy list */
spin_unlock
(
&
inode
->
i_lock
);
nfs_destroy_unlinked_subrequests
(
destroy_list
,
head
,
inode
);
nfs_destroy_unlinked_subrequests
(
destroy_list
,
head
);
/* Did we lose a race with nfs_inode_remove_request()? */
if
(
!
(
PagePrivate
(
page
)
||
PageSwapCache
(
page
)))
{
nfs_unlock_and_release_request
(
head
);
return
NULL
;
}
/* still holds ref on head from nfs_page_find_head_request
_locked
/* still holds ref on head from nfs_page_find_head_request
* and still has lock on head from lock loop */
return
head
;
}
static
void
nfs_write_error_remove_page
(
struct
nfs_page
*
req
)
{
nfs_unlock_request
(
req
);
nfs_end_page_writeback
(
req
);
generic_error_remove_page
(
page_file_mapping
(
req
->
wb_page
),
req
->
wb_page
);
...
...
@@ -624,12 +608,12 @@ nfs_error_is_fatal_on_server(int err)
* May return an error if the user signalled nfs_wait_on_request().
*/
static
int
nfs_page_async_flush
(
struct
nfs_pageio_descriptor
*
pgio
,
struct
page
*
page
,
bool
nonblock
)
struct
page
*
page
)
{
struct
nfs_page
*
req
;
int
ret
=
0
;
req
=
nfs_lock_and_join_requests
(
page
,
nonblock
);
req
=
nfs_lock_and_join_requests
(
page
);
if
(
!
req
)
goto
out
;
ret
=
PTR_ERR
(
req
);
...
...
@@ -672,7 +656,7 @@ static int nfs_do_writepage(struct page *page, struct writeback_control *wbc,
int
ret
;
nfs_pageio_cond_complete
(
pgio
,
page_index
(
page
));
ret
=
nfs_page_async_flush
(
pgio
,
page
,
wbc
->
sync_mode
==
WB_SYNC_NONE
);
ret
=
nfs_page_async_flush
(
pgio
,
page
);
if
(
ret
==
-
EAGAIN
)
{
redirty_page_for_writepage
(
wbc
,
page
);
ret
=
0
;
...
...
@@ -759,6 +743,7 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc)
*/
static
void
nfs_inode_add_request
(
struct
inode
*
inode
,
struct
nfs_page
*
req
)
{
struct
address_space
*
mapping
=
page_file_mapping
(
req
->
wb_page
);
struct
nfs_inode
*
nfsi
=
NFS_I
(
inode
);
WARN_ON_ONCE
(
req
->
wb_this_page
!=
req
);
...
...
@@ -766,27 +751,30 @@ static void nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
/* Lock the request! */
nfs_lock_request
(
req
);
spin_lock
(
&
inode
->
i_lock
);
if
(
!
nfsi
->
nrequests
&&
NFS_PROTO
(
inode
)
->
have_delegation
(
inode
,
FMODE_WRITE
))
inode
->
i_version
++
;
/*
* Swap-space should not get truncated. Hence no need to plug the race
* with invalidate/truncate.
*/
spin_lock
(
&
mapping
->
private_lock
);
if
(
!
nfs_have_writebacks
(
inode
)
&&
NFS_PROTO
(
inode
)
->
have_delegation
(
inode
,
FMODE_WRITE
))
{
spin_lock
(
&
inode
->
i_lock
);
inode
->
i_version
++
;
spin_unlock
(
&
inode
->
i_lock
);
}
if
(
likely
(
!
PageSwapCache
(
req
->
wb_page
)))
{
set_bit
(
PG_MAPPED
,
&
req
->
wb_flags
);
SetPagePrivate
(
req
->
wb_page
);
set_page_private
(
req
->
wb_page
,
(
unsigned
long
)
req
);
}
nfsi
->
nrequests
++
;
spin_unlock
(
&
mapping
->
private_lock
);
atomic_long_inc
(
&
nfsi
->
nrequests
);
/* this a head request for a page group - mark it as having an
* extra reference so sub groups can follow suit.
* This flag also informs pgio layer when to bump nrequests when
* adding subrequests. */
WARN_ON
(
test_and_set_bit
(
PG_INODE_REF
,
&
req
->
wb_flags
));
kref_get
(
&
req
->
wb_kref
);
spin_unlock
(
&
inode
->
i_lock
);
}
/*
...
...
@@ -794,25 +782,22 @@ static void nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
*/
static
void
nfs_inode_remove_request
(
struct
nfs_page
*
req
)
{
struct
inode
*
inode
=
d_inode
(
req
->
wb_context
->
dentry
);
struct
address_space
*
mapping
=
page_file_mapping
(
req
->
wb_page
);
struct
inode
*
inode
=
mapping
->
host
;
struct
nfs_inode
*
nfsi
=
NFS_I
(
inode
);
struct
nfs_page
*
head
;
atomic_long_dec
(
&
nfsi
->
nrequests
);
if
(
nfs_page_group_sync_on_bit
(
req
,
PG_REMOVE
))
{
head
=
req
->
wb_head
;
spin_lock
(
&
inode
->
i
_lock
);
spin_lock
(
&
mapping
->
private
_lock
);
if
(
likely
(
head
->
wb_page
&&
!
PageSwapCache
(
head
->
wb_page
)))
{
set_page_private
(
head
->
wb_page
,
0
);
ClearPagePrivate
(
head
->
wb_page
);
clear_bit
(
PG_MAPPED
,
&
head
->
wb_flags
);
}
nfsi
->
nrequests
--
;
spin_unlock
(
&
inode
->
i_lock
);
}
else
{
spin_lock
(
&
inode
->
i_lock
);
nfsi
->
nrequests
--
;
spin_unlock
(
&
inode
->
i_lock
);
spin_unlock
(
&
mapping
->
private_lock
);
}
if
(
test_and_clear_bit
(
PG_INODE_REF
,
&
req
->
wb_flags
))
...
...
@@ -868,7 +853,8 @@ nfs_page_search_commits_for_head_request_locked(struct nfs_inode *nfsi,
* number of outstanding requests requiring a commit as well as
* the MM page stats.
*
* The caller must hold cinfo->inode->i_lock, and the nfs_page lock.
* The caller must hold NFS_I(cinfo->inode)->commit_mutex, and the
* nfs_page lock.
*/
void
nfs_request_add_commit_list_locked
(
struct
nfs_page
*
req
,
struct
list_head
*
dst
,
...
...
@@ -876,7 +862,7 @@ nfs_request_add_commit_list_locked(struct nfs_page *req, struct list_head *dst,
{
set_bit
(
PG_CLEAN
,
&
req
->
wb_flags
);
nfs_list_add_request
(
req
,
dst
);
cinfo
->
mds
->
ncommit
++
;
atomic_long_inc
(
&
cinfo
->
mds
->
ncommit
)
;
}
EXPORT_SYMBOL_GPL
(
nfs_request_add_commit_list_locked
);
...
...
@@ -896,9 +882,9 @@ EXPORT_SYMBOL_GPL(nfs_request_add_commit_list_locked);
void
nfs_request_add_commit_list
(
struct
nfs_page
*
req
,
struct
nfs_commit_info
*
cinfo
)
{
spin_lock
(
&
cinfo
->
inode
->
i_lock
);
mutex_lock
(
&
NFS_I
(
cinfo
->
inode
)
->
commit_mutex
);
nfs_request_add_commit_list_locked
(
req
,
&
cinfo
->
mds
->
list
,
cinfo
);
spin_unlock
(
&
cinfo
->
inode
->
i_lock
);
mutex_unlock
(
&
NFS_I
(
cinfo
->
inode
)
->
commit_mutex
);
if
(
req
->
wb_page
)
nfs_mark_page_unstable
(
req
->
wb_page
,
cinfo
);
}
...
...
@@ -922,7 +908,7 @@ nfs_request_remove_commit_list(struct nfs_page *req,
if
(
!
test_and_clear_bit
(
PG_CLEAN
,
&
(
req
)
->
wb_flags
))
return
;
nfs_list_remove_request
(
req
);
cinfo
->
mds
->
ncommit
--
;
atomic_long_dec
(
&
cinfo
->
mds
->
ncommit
)
;
}
EXPORT_SYMBOL_GPL
(
nfs_request_remove_commit_list
);
...
...
@@ -967,7 +953,7 @@ nfs_clear_page_commit(struct page *page)
WB_RECLAIMABLE
);
}
/* Called holding
inode (/cinfo) lock
*/
/* Called holding
the request lock on @req
*/
static
void
nfs_clear_request_commit
(
struct
nfs_page
*
req
)
{
...
...
@@ -976,9 +962,11 @@ nfs_clear_request_commit(struct nfs_page *req)
struct
nfs_commit_info
cinfo
;
nfs_init_cinfo_from_inode
(
&
cinfo
,
inode
);
mutex_lock
(
&
NFS_I
(
inode
)
->
commit_mutex
);
if
(
!
pnfs_clear_request_commit
(
req
,
&
cinfo
))
{
nfs_request_remove_commit_list
(
req
,
&
cinfo
);
}
mutex_unlock
(
&
NFS_I
(
inode
)
->
commit_mutex
);
nfs_clear_page_commit
(
req
->
wb_page
);
}
}
...
...
@@ -1023,7 +1011,6 @@ static void nfs_write_completion(struct nfs_pgio_header *hdr)
remove_req:
nfs_inode_remove_request
(
req
);
next:
nfs_unlock_request
(
req
);
nfs_end_page_writeback
(
req
);
nfs_release_request
(
req
);
}
...
...
@@ -1035,28 +1022,36 @@ static void nfs_write_completion(struct nfs_pgio_header *hdr)
unsigned
long
nfs_reqs_to_commit
(
struct
nfs_commit_info
*
cinfo
)
{
return
cinfo
->
mds
->
ncommit
;
return
atomic_long_read
(
&
cinfo
->
mds
->
ncommit
)
;
}
/*
cinfo->inode->i_lock
held by caller */
/*
NFS_I(cinfo->inode)->commit_mutex
held by caller */
int
nfs_scan_commit_list
(
struct
list_head
*
src
,
struct
list_head
*
dst
,
struct
nfs_commit_info
*
cinfo
,
int
max
)
{
struct
nfs_page
*
req
,
*
tmp
;
struct
nfs_page
*
req
;
int
ret
=
0
;
list_for_each_entry_safe
(
req
,
tmp
,
src
,
wb_list
)
{
if
(
!
nfs_lock_request
(
req
))
continue
;
while
(
!
list_empty
(
src
))
{
req
=
list_first_entry
(
src
,
struct
nfs_page
,
wb_list
);
kref_get
(
&
req
->
wb_kref
);
if
(
cond_resched_lock
(
&
cinfo
->
inode
->
i_lock
))
list_safe_reset_next
(
req
,
tmp
,
wb_list
);
if
(
!
nfs_lock_request
(
req
))
{
int
status
;
mutex_unlock
(
&
NFS_I
(
cinfo
->
inode
)
->
commit_mutex
);
status
=
nfs_wait_on_request
(
req
);
nfs_release_request
(
req
);
mutex_lock
(
&
NFS_I
(
cinfo
->
inode
)
->
commit_mutex
);
if
(
status
<
0
)
break
;
continue
;
}
nfs_request_remove_commit_list
(
req
,
cinfo
);
nfs_list_add_request
(
req
,
dst
);
ret
++
;
if
((
ret
==
max
)
&&
!
cinfo
->
dreq
)
break
;
cond_resched
();
}
return
ret
;
}
...
...
@@ -1076,15 +1071,17 @@ nfs_scan_commit(struct inode *inode, struct list_head *dst,
{
int
ret
=
0
;
spin_lock
(
&
cinfo
->
inode
->
i_lock
);
if
(
cinfo
->
mds
->
ncommit
>
0
)
{
if
(
!
atomic_long_read
(
&
cinfo
->
mds
->
ncommit
))
return
0
;
mutex_lock
(
&
NFS_I
(
cinfo
->
inode
)
->
commit_mutex
);
if
(
atomic_long_read
(
&
cinfo
->
mds
->
ncommit
)
>
0
)
{
const
int
max
=
INT_MAX
;
ret
=
nfs_scan_commit_list
(
&
cinfo
->
mds
->
list
,
dst
,
cinfo
,
max
);
ret
+=
pnfs_scan_commit_lists
(
inode
,
cinfo
,
max
-
ret
);
}
spin_unlock
(
&
cinfo
->
inode
->
i_lock
);
mutex_unlock
(
&
NFS_I
(
cinfo
->
inode
)
->
commit_mutex
);
return
ret
;
}
...
...
@@ -1105,20 +1102,11 @@ static struct nfs_page *nfs_try_to_update_request(struct inode *inode,
unsigned
int
end
;
int
error
;
if
(
!
PagePrivate
(
page
))
return
NULL
;
end
=
offset
+
bytes
;
spin_lock
(
&
inode
->
i_lock
);
for
(;;)
{
req
=
nfs_page_find_head_request_locked
(
NFS_I
(
inode
),
page
);
if
(
req
==
NULL
)
goto
out_unlock
;
/* should be handled by nfs_flush_incompatible */
WARN_ON_ONCE
(
req
->
wb_head
!=
req
);
WARN_ON_ONCE
(
req
->
wb_this_page
!=
req
);
req
=
nfs_lock_and_join_requests
(
page
);
if
(
IS_ERR_OR_NULL
(
req
))
return
req
;
rqend
=
req
->
wb_offset
+
req
->
wb_bytes
;
/*
...
...
@@ -1127,22 +1115,9 @@ static struct nfs_page *nfs_try_to_update_request(struct inode *inode,
* Note: nfs_flush_incompatible() will already
* have flushed out requests having wrong owners.
*/
if
(
offset
>
rqend
||
end
<
req
->
wb_offset
)
if
(
offset
>
rqend
||
end
<
req
->
wb_offset
)
goto
out_flushme
;
if
(
nfs_lock_request
(
req
))
break
;
/* The request is locked, so wait and then retry */
spin_unlock
(
&
inode
->
i_lock
);
error
=
nfs_wait_on_request
(
req
);
nfs_release_request
(
req
);
if
(
error
!=
0
)
goto
out_err
;
spin_lock
(
&
inode
->
i_lock
);
}
/* Okay, the request matches. Update the region */
if
(
offset
<
req
->
wb_offset
)
{
req
->
wb_offset
=
offset
;
...
...
@@ -1152,17 +1127,17 @@ static struct nfs_page *nfs_try_to_update_request(struct inode *inode,
req
->
wb_bytes
=
end
-
req
->
wb_offset
;
else
req
->
wb_bytes
=
rqend
-
req
->
wb_offset
;
out_unlock:
if
(
req
)
nfs_clear_request_commit
(
req
);
spin_unlock
(
&
inode
->
i_lock
);
return
req
;
out_flushme:
spin_unlock
(
&
inode
->
i_lock
);
nfs_release_request
(
req
);
/*
* Note: we mark the request dirty here because
* nfs_lock_and_join_requests() cannot preserve
* commit flags, so we have to replay the write.
*/
nfs_mark_request_dirty
(
req
);
nfs_unlock_and_release_request
(
req
);
error
=
nfs_wb_page
(
inode
,
page
);
out_err:
return
ERR_PTR
(
error
);
return
(
error
<
0
)
?
ERR_PTR
(
error
)
:
NULL
;
}
/*
...
...
@@ -1227,8 +1202,6 @@ int nfs_flush_incompatible(struct file *file, struct page *page)
l_ctx
=
req
->
wb_lock_context
;
do_flush
=
req
->
wb_page
!=
page
||
!
nfs_match_open_context
(
req
->
wb_context
,
ctx
);
/* for now, flush if more than 1 request in page_group */
do_flush
|=
req
->
wb_this_page
!=
req
;
if
(
l_ctx
&&
flctx
&&
!
(
list_empty_careful
(
&
flctx
->
flc_posix
)
&&
list_empty_careful
(
&
flctx
->
flc_flock
)))
{
...
...
@@ -1412,7 +1385,6 @@ static void nfs_redirty_request(struct nfs_page *req)
{
nfs_mark_request_dirty
(
req
);
set_bit
(
NFS_CONTEXT_RESEND_WRITES
,
&
req
->
wb_context
->
flags
);
nfs_unlock_request
(
req
);
nfs_end_page_writeback
(
req
);
nfs_release_request
(
req
);
}
...
...
@@ -1934,7 +1906,7 @@ int nfs_write_inode(struct inode *inode, struct writeback_control *wbc)
int
ret
=
0
;
/* no commits means nothing needs to be done */
if
(
!
nfsi
->
commit_info
.
ncommit
)
if
(
!
atomic_long_read
(
&
nfsi
->
commit_info
.
ncommit
)
)
return
ret
;
if
(
wbc
->
sync_mode
==
WB_SYNC_NONE
)
{
...
...
@@ -2015,7 +1987,7 @@ int nfs_wb_page_cancel(struct inode *inode, struct page *page)
/* blocking call to cancel all requests and join to a single (head)
* request */
req
=
nfs_lock_and_join_requests
(
page
,
false
);
req
=
nfs_lock_and_join_requests
(
page
);
if
(
IS_ERR
(
req
))
{
ret
=
PTR_ERR
(
req
);
...
...
include/linux/nfs_fs.h
浏览文件 @
b7561e51
...
...
@@ -154,7 +154,7 @@ struct nfs_inode {
*/
__be32
cookieverf
[
2
];
unsigned
long
nrequests
;
atomic_long_t
nrequests
;
struct
nfs_mds_commit_info
commit_info
;
/* Open contexts for shared mmap writes */
...
...
@@ -163,6 +163,7 @@ struct nfs_inode {
/* Readers: in-flight sillydelete RPC calls */
/* Writers: rmdir */
struct
rw_semaphore
rmdir_sem
;
struct
mutex
commit_mutex
;
#if IS_ENABLED(CONFIG_NFS_V4)
struct
nfs4_cached_acl
*
nfs4_acl
;
...
...
@@ -510,7 +511,7 @@ extern void nfs_commit_free(struct nfs_commit_data *data);
static
inline
int
nfs_have_writebacks
(
struct
inode
*
inode
)
{
return
NFS_I
(
inode
)
->
nrequests
!=
0
;
return
atomic_long_read
(
&
NFS_I
(
inode
)
->
nrequests
)
!=
0
;
}
/*
...
...
include/linux/nfs_page.h
浏览文件 @
b7561e51
...
...
@@ -139,8 +139,7 @@ extern size_t nfs_generic_pg_test(struct nfs_pageio_descriptor *desc,
extern
int
nfs_wait_on_request
(
struct
nfs_page
*
);
extern
void
nfs_unlock_request
(
struct
nfs_page
*
req
);
extern
void
nfs_unlock_and_release_request
(
struct
nfs_page
*
);
extern
int
nfs_page_group_lock
(
struct
nfs_page
*
,
bool
);
extern
void
nfs_page_group_lock_wait
(
struct
nfs_page
*
);
extern
int
nfs_page_group_lock
(
struct
nfs_page
*
);
extern
void
nfs_page_group_unlock
(
struct
nfs_page
*
);
extern
bool
nfs_page_group_sync_on_bit
(
struct
nfs_page
*
,
unsigned
int
);
extern
bool
nfs_async_iocounter_wait
(
struct
rpc_task
*
,
struct
nfs_lock_context
*
);
...
...
include/linux/nfs_xdr.h
浏览文件 @
b7561e51
...
...
@@ -1476,7 +1476,7 @@ struct nfs_pgio_header {
struct
nfs_mds_commit_info
{
atomic_t
rpcs_out
;
unsigned
long
ncommit
;
atomic_long_t
ncommit
;
struct
list_head
list
;
};
...
...
include/linux/sunrpc/sched.h
浏览文件 @
b7561e51
...
...
@@ -139,6 +139,8 @@ struct rpc_task_setup {
#define RPC_TASK_RUNNING 0
#define RPC_TASK_QUEUED 1
#define RPC_TASK_ACTIVE 2
#define RPC_TASK_MSG_RECV 3
#define RPC_TASK_MSG_RECV_WAIT 4
#define RPC_IS_RUNNING(t) test_bit(RPC_TASK_RUNNING, &(t)->tk_runstate)
#define rpc_set_running(t) set_bit(RPC_TASK_RUNNING, &(t)->tk_runstate)
...
...
include/linux/sunrpc/xprt.h
浏览文件 @
b7561e51
...
...
@@ -232,6 +232,7 @@ struct rpc_xprt {
*/
spinlock_t
transport_lock
;
/* lock transport info */
spinlock_t
reserve_lock
;
/* lock slot table */
spinlock_t
recv_lock
;
/* lock receive list */
u32
xid
;
/* Next XID value to use */
struct
rpc_task
*
snd_task
;
/* Task blocked in send */
struct
svc_xprt
*
bc_xprt
;
/* NFSv4.1 backchannel */
...
...
@@ -372,6 +373,8 @@ void xprt_write_space(struct rpc_xprt *xprt);
void
xprt_adjust_cwnd
(
struct
rpc_xprt
*
xprt
,
struct
rpc_task
*
task
,
int
result
);
struct
rpc_rqst
*
xprt_lookup_rqst
(
struct
rpc_xprt
*
xprt
,
__be32
xid
);
void
xprt_complete_rqst
(
struct
rpc_task
*
task
,
int
copied
);
void
xprt_pin_rqst
(
struct
rpc_rqst
*
req
);
void
xprt_unpin_rqst
(
struct
rpc_rqst
*
req
);
void
xprt_release_rqst_cong
(
struct
rpc_task
*
task
);
void
xprt_disconnect_done
(
struct
rpc_xprt
*
xprt
);
void
xprt_force_disconnect
(
struct
rpc_xprt
*
xprt
);
...
...
net/sunrpc/backchannel_rqst.c
浏览文件 @
b7561e51
...
...
@@ -171,10 +171,10 @@ int xprt_setup_bc(struct rpc_xprt *xprt, unsigned int min_reqs)
/*
* Add the temporary list to the backchannel preallocation list
*/
spin_lock
_bh
(
&
xprt
->
bc_pa_lock
);
spin_lock
(
&
xprt
->
bc_pa_lock
);
list_splice
(
&
tmp_list
,
&
xprt
->
bc_pa_list
);
xprt_inc_alloc_count
(
xprt
,
min_reqs
);
spin_unlock
_bh
(
&
xprt
->
bc_pa_lock
);
spin_unlock
(
&
xprt
->
bc_pa_lock
);
dprintk
(
"RPC: setup backchannel transport done
\n
"
);
return
0
;
...
...
net/sunrpc/svcsock.c
浏览文件 @
b7561e51
...
...
@@ -1001,7 +1001,7 @@ static int receive_cb_reply(struct svc_sock *svsk, struct svc_rqst *rqstp)
if
(
!
bc_xprt
)
return
-
EAGAIN
;
spin_lock
_bh
(
&
bc_xprt
->
transport
_lock
);
spin_lock
(
&
bc_xprt
->
recv
_lock
);
req
=
xprt_lookup_rqst
(
bc_xprt
,
xid
);
if
(
!
req
)
goto
unlock_notfound
;
...
...
@@ -1019,7 +1019,7 @@ static int receive_cb_reply(struct svc_sock *svsk, struct svc_rqst *rqstp)
memcpy
(
dst
->
iov_base
,
src
->
iov_base
,
src
->
iov_len
);
xprt_complete_rqst
(
req
->
rq_task
,
rqstp
->
rq_arg
.
len
);
rqstp
->
rq_arg
.
len
=
0
;
spin_unlock
_bh
(
&
bc_xprt
->
transport
_lock
);
spin_unlock
(
&
bc_xprt
->
recv
_lock
);
return
0
;
unlock_notfound:
printk
(
KERN_NOTICE
...
...
@@ -1028,7 +1028,7 @@ static int receive_cb_reply(struct svc_sock *svsk, struct svc_rqst *rqstp)
__func__
,
ntohl
(
calldir
),
bc_xprt
,
ntohl
(
xid
));
unlock_eagain:
spin_unlock
_bh
(
&
bc_xprt
->
transport
_lock
);
spin_unlock
(
&
bc_xprt
->
recv
_lock
);
return
-
EAGAIN
;
}
...
...
net/sunrpc/xprt.c
浏览文件 @
b7561e51
...
...
@@ -844,6 +844,48 @@ struct rpc_rqst *xprt_lookup_rqst(struct rpc_xprt *xprt, __be32 xid)
}
EXPORT_SYMBOL_GPL
(
xprt_lookup_rqst
);
/**
* xprt_pin_rqst - Pin a request on the transport receive list
* @req: Request to pin
*
* Caller must ensure this is atomic with the call to xprt_lookup_rqst()
* so should be holding the xprt transport lock.
*/
void
xprt_pin_rqst
(
struct
rpc_rqst
*
req
)
{
set_bit
(
RPC_TASK_MSG_RECV
,
&
req
->
rq_task
->
tk_runstate
);
}
/**
* xprt_unpin_rqst - Unpin a request on the transport receive list
* @req: Request to pin
*
* Caller should be holding the xprt transport lock.
*/
void
xprt_unpin_rqst
(
struct
rpc_rqst
*
req
)
{
struct
rpc_task
*
task
=
req
->
rq_task
;
clear_bit
(
RPC_TASK_MSG_RECV
,
&
task
->
tk_runstate
);
if
(
test_bit
(
RPC_TASK_MSG_RECV_WAIT
,
&
task
->
tk_runstate
))
wake_up_bit
(
&
task
->
tk_runstate
,
RPC_TASK_MSG_RECV
);
}
static
void
xprt_wait_on_pinned_rqst
(
struct
rpc_rqst
*
req
)
__must_hold
(
&
req
->
rq_xprt
->
recv_lock
)
{
struct
rpc_task
*
task
=
req
->
rq_task
;
if
(
task
&&
test_bit
(
RPC_TASK_MSG_RECV
,
&
task
->
tk_runstate
))
{
spin_unlock
(
&
req
->
rq_xprt
->
recv_lock
);
set_bit
(
RPC_TASK_MSG_RECV_WAIT
,
&
task
->
tk_runstate
);
wait_on_bit
(
&
task
->
tk_runstate
,
RPC_TASK_MSG_RECV
,
TASK_UNINTERRUPTIBLE
);
clear_bit
(
RPC_TASK_MSG_RECV_WAIT
,
&
task
->
tk_runstate
);
spin_lock
(
&
req
->
rq_xprt
->
recv_lock
);
}
}
static
void
xprt_update_rtt
(
struct
rpc_task
*
task
)
{
struct
rpc_rqst
*
req
=
task
->
tk_rqstp
;
...
...
@@ -966,13 +1008,13 @@ void xprt_transmit(struct rpc_task *task)
/*
* Add to the list only if we're expecting a reply
*/
spin_lock_bh
(
&
xprt
->
transport_lock
);
/* Update the softirq receive buffer */
memcpy
(
&
req
->
rq_private_buf
,
&
req
->
rq_rcv_buf
,
sizeof
(
req
->
rq_private_buf
));
/* Add request to the receive list */
spin_lock
(
&
xprt
->
recv_lock
);
list_add_tail
(
&
req
->
rq_list
,
&
xprt
->
recv
);
spin_unlock
_bh
(
&
xprt
->
transport
_lock
);
spin_unlock
(
&
xprt
->
recv
_lock
);
xprt_reset_majortimeo
(
req
);
/* Turn off autodisconnect */
del_singleshot_timer_sync
(
&
xprt
->
timer
);
...
...
@@ -1287,12 +1329,16 @@ void xprt_release(struct rpc_task *task)
task
->
tk_ops
->
rpc_count_stats
(
task
,
task
->
tk_calldata
);
else
if
(
task
->
tk_client
)
rpc_count_iostats
(
task
,
task
->
tk_client
->
cl_metrics
);
spin_lock
(
&
xprt
->
recv_lock
);
if
(
!
list_empty
(
&
req
->
rq_list
))
{
list_del
(
&
req
->
rq_list
);
xprt_wait_on_pinned_rqst
(
req
);
}
spin_unlock
(
&
xprt
->
recv_lock
);
spin_lock_bh
(
&
xprt
->
transport_lock
);
xprt
->
ops
->
release_xprt
(
xprt
,
task
);
if
(
xprt
->
ops
->
release_request
)
xprt
->
ops
->
release_request
(
task
);
if
(
!
list_empty
(
&
req
->
rq_list
))
list_del
(
&
req
->
rq_list
);
xprt
->
last_used
=
jiffies
;
xprt_schedule_autodisconnect
(
xprt
);
spin_unlock_bh
(
&
xprt
->
transport_lock
);
...
...
@@ -1318,6 +1364,7 @@ static void xprt_init(struct rpc_xprt *xprt, struct net *net)
spin_lock_init
(
&
xprt
->
transport_lock
);
spin_lock_init
(
&
xprt
->
reserve_lock
);
spin_lock_init
(
&
xprt
->
recv_lock
);
INIT_LIST_HEAD
(
&
xprt
->
free
);
INIT_LIST_HEAD
(
&
xprt
->
recv
);
...
...
net/sunrpc/xprtrdma/rpc_rdma.c
浏览文件 @
b7561e51
...
...
@@ -1051,7 +1051,7 @@ rpcrdma_reply_handler(struct work_struct *work)
* RPC completion while holding the transport lock to ensure
* the rep, rqst, and rq_task pointers remain stable.
*/
spin_lock
_bh
(
&
xprt
->
transport
_lock
);
spin_lock
(
&
xprt
->
recv
_lock
);
rqst
=
xprt_lookup_rqst
(
xprt
,
headerp
->
rm_xid
);
if
(
!
rqst
)
goto
out_norqst
;
...
...
@@ -1136,7 +1136,7 @@ rpcrdma_reply_handler(struct work_struct *work)
xprt_release_rqst_cong
(
rqst
->
rq_task
);
xprt_complete_rqst
(
rqst
->
rq_task
,
status
);
spin_unlock
_bh
(
&
xprt
->
transport
_lock
);
spin_unlock
(
&
xprt
->
recv
_lock
);
dprintk
(
"RPC: %s: xprt_complete_rqst(0x%p, 0x%p, %d)
\n
"
,
__func__
,
xprt
,
rqst
,
status
);
return
;
...
...
@@ -1187,12 +1187,12 @@ rpcrdma_reply_handler(struct work_struct *work)
r_xprt
->
rx_stats
.
bad_reply_count
++
;
goto
out
;
/* The req was still available, but by the time the
transport
_lock
/* The req was still available, but by the time the
recv
_lock
* was acquired, the rqst and task had been released. Thus the RPC
* has already been terminated.
*/
out_norqst:
spin_unlock
_bh
(
&
xprt
->
transport
_lock
);
spin_unlock
(
&
xprt
->
recv
_lock
);
rpcrdma_buffer_put
(
req
);
dprintk
(
"RPC: %s: race, no rqst left for req %p
\n
"
,
__func__
,
req
);
...
...
net/sunrpc/xprtrdma/svc_rdma_backchannel.c
浏览文件 @
b7561e51
...
...
@@ -52,7 +52,7 @@ int svc_rdma_handle_bc_reply(struct rpc_xprt *xprt, __be32 *rdma_resp,
if
(
src
->
iov_len
<
24
)
goto
out_shortreply
;
spin_lock
_bh
(
&
xprt
->
transport
_lock
);
spin_lock
(
&
xprt
->
recv
_lock
);
req
=
xprt_lookup_rqst
(
xprt
,
xid
);
if
(
!
req
)
goto
out_notfound
;
...
...
@@ -69,17 +69,20 @@ int svc_rdma_handle_bc_reply(struct rpc_xprt *xprt, __be32 *rdma_resp,
else
if
(
credits
>
r_xprt
->
rx_buf
.
rb_bc_max_requests
)
credits
=
r_xprt
->
rx_buf
.
rb_bc_max_requests
;
spin_lock_bh
(
&
xprt
->
transport_lock
);
cwnd
=
xprt
->
cwnd
;
xprt
->
cwnd
=
credits
<<
RPC_CWNDSHIFT
;
if
(
xprt
->
cwnd
>
cwnd
)
xprt_release_rqst_cong
(
req
->
rq_task
);
spin_unlock_bh
(
&
xprt
->
transport_lock
);
ret
=
0
;
xprt_complete_rqst
(
req
->
rq_task
,
rcvbuf
->
len
);
rcvbuf
->
len
=
0
;
out_unlock:
spin_unlock
_bh
(
&
xprt
->
transport
_lock
);
spin_unlock
(
&
xprt
->
recv
_lock
);
out:
return
ret
;
...
...
net/sunrpc/xprtsock.c
浏览文件 @
b7561e51
...
...
@@ -969,10 +969,12 @@ static void xs_local_data_read_skb(struct rpc_xprt *xprt,
return
;
/* Look up and lock the request corresponding to the given XID */
spin_lock
_bh
(
&
xprt
->
transport
_lock
);
spin_lock
(
&
xprt
->
recv
_lock
);
rovr
=
xprt_lookup_rqst
(
xprt
,
*
xp
);
if
(
!
rovr
)
goto
out_unlock
;
xprt_pin_rqst
(
rovr
);
spin_unlock
(
&
xprt
->
recv_lock
);
task
=
rovr
->
rq_task
;
copied
=
rovr
->
rq_private_buf
.
buflen
;
...
...
@@ -981,13 +983,16 @@ static void xs_local_data_read_skb(struct rpc_xprt *xprt,
if
(
xs_local_copy_to_xdr
(
&
rovr
->
rq_private_buf
,
skb
))
{
dprintk
(
"RPC: sk_buff copy failed
\n
"
);
goto
out_unlock
;
spin_lock
(
&
xprt
->
recv_lock
);
goto
out_unpin
;
}
spin_lock
(
&
xprt
->
recv_lock
);
xprt_complete_rqst
(
task
,
copied
);
out_unpin:
xprt_unpin_rqst
(
rovr
);
out_unlock:
spin_unlock
_bh
(
&
xprt
->
transport
_lock
);
spin_unlock
(
&
xprt
->
recv
_lock
);
}
static
void
xs_local_data_receive
(
struct
sock_xprt
*
transport
)
...
...
@@ -1050,10 +1055,12 @@ static void xs_udp_data_read_skb(struct rpc_xprt *xprt,
return
;
/* Look up and lock the request corresponding to the given XID */
spin_lock
_bh
(
&
xprt
->
transport
_lock
);
spin_lock
(
&
xprt
->
recv
_lock
);
rovr
=
xprt_lookup_rqst
(
xprt
,
*
xp
);
if
(
!
rovr
)
goto
out_unlock
;
xprt_pin_rqst
(
rovr
);
spin_unlock
(
&
xprt
->
recv_lock
);
task
=
rovr
->
rq_task
;
if
((
copied
=
rovr
->
rq_private_buf
.
buflen
)
>
repsize
)
...
...
@@ -1062,16 +1069,21 @@ static void xs_udp_data_read_skb(struct rpc_xprt *xprt,
/* Suck it into the iovec, verify checksum if not done by hw. */
if
(
csum_partial_copy_to_xdr
(
&
rovr
->
rq_private_buf
,
skb
))
{
__UDPX_INC_STATS
(
sk
,
UDP_MIB_INERRORS
);
goto
out_unlock
;
spin_lock
(
&
xprt
->
recv_lock
);
goto
out_unpin
;
}
__UDPX_INC_STATS
(
sk
,
UDP_MIB_INDATAGRAMS
);
spin_lock_bh
(
&
xprt
->
transport_lock
);
xprt_adjust_cwnd
(
xprt
,
task
,
copied
);
spin_unlock_bh
(
&
xprt
->
transport_lock
);
spin_lock
(
&
xprt
->
recv_lock
);
xprt_complete_rqst
(
task
,
copied
);
out_unpin:
xprt_unpin_rqst
(
rovr
);
out_unlock:
spin_unlock
_bh
(
&
xprt
->
transport
_lock
);
spin_unlock
(
&
xprt
->
recv
_lock
);
}
static
void
xs_udp_data_receive
(
struct
sock_xprt
*
transport
)
...
...
@@ -1277,25 +1289,12 @@ static inline void xs_tcp_read_common(struct rpc_xprt *xprt,
}
len
=
desc
->
count
;
if
(
len
>
transport
->
tcp_reclen
-
transport
->
tcp_offset
)
{
struct
xdr_skb_reader
my_desc
;
len
=
transport
->
tcp_reclen
-
transport
->
tcp_offset
;
memcpy
(
&
my_desc
,
desc
,
sizeof
(
my_desc
));
my_desc
.
count
=
len
;
r
=
xdr_partial_copy_from_skb
(
rcvbuf
,
transport
->
tcp_copied
,
&
my_desc
,
xdr_skb_read_bits
);
desc
->
count
-=
r
;
desc
->
offset
+=
r
;
}
else
if
(
len
>
transport
->
tcp_reclen
-
transport
->
tcp_offset
)
desc
->
count
=
transport
->
tcp_reclen
-
transport
->
tcp_offset
;
r
=
xdr_partial_copy_from_skb
(
rcvbuf
,
transport
->
tcp_copied
,
desc
,
xdr_skb_read_bits
);
if
(
r
>
0
)
{
transport
->
tcp_copied
+=
r
;
transport
->
tcp_offset
+=
r
;
}
if
(
r
!=
len
)
{
if
(
desc
->
count
)
{
/* Error when copying to the receive buffer,
* usually because we weren't able to allocate
* additional buffer pages. All we can do now
...
...
@@ -1315,6 +1314,10 @@ static inline void xs_tcp_read_common(struct rpc_xprt *xprt,
return
;
}
transport
->
tcp_copied
+=
r
;
transport
->
tcp_offset
+=
r
;
desc
->
count
=
len
-
r
;
dprintk
(
"RPC: XID %08x read %zd bytes
\n
"
,
ntohl
(
transport
->
tcp_xid
),
r
);
dprintk
(
"RPC: xprt = %p, tcp_copied = %lu, tcp_offset = %u, "
...
...
@@ -1343,21 +1346,24 @@ static inline int xs_tcp_read_reply(struct rpc_xprt *xprt,
dprintk
(
"RPC: read reply XID %08x
\n
"
,
ntohl
(
transport
->
tcp_xid
));
/* Find and lock the request corresponding to this xid */
spin_lock
_bh
(
&
xprt
->
transport
_lock
);
spin_lock
(
&
xprt
->
recv
_lock
);
req
=
xprt_lookup_rqst
(
xprt
,
transport
->
tcp_xid
);
if
(
!
req
)
{
dprintk
(
"RPC: XID %08x request not found!
\n
"
,
ntohl
(
transport
->
tcp_xid
));
spin_unlock
_bh
(
&
xprt
->
transport
_lock
);
spin_unlock
(
&
xprt
->
recv
_lock
);
return
-
1
;
}
xprt_pin_rqst
(
req
);
spin_unlock
(
&
xprt
->
recv_lock
);
xs_tcp_read_common
(
xprt
,
desc
,
req
);
spin_lock
(
&
xprt
->
recv_lock
);
if
(
!
(
transport
->
tcp_flags
&
TCP_RCV_COPY_DATA
))
xprt_complete_rqst
(
req
->
rq_task
,
transport
->
tcp_copied
);
spin_unlock
_bh
(
&
xprt
->
transport
_lock
);
xprt_unpin_rqst
(
req
);
spin_unlock
(
&
xprt
->
recv
_lock
);
return
0
;
}
...
...
@@ -1376,11 +1382,9 @@ static int xs_tcp_read_callback(struct rpc_xprt *xprt,
container_of
(
xprt
,
struct
sock_xprt
,
xprt
);
struct
rpc_rqst
*
req
;
/* Look up and lock the request corresponding to the given XID */
spin_lock_bh
(
&
xprt
->
transport_lock
);
/* Look up the request corresponding to the given XID */
req
=
xprt_lookup_bc_request
(
xprt
,
transport
->
tcp_xid
);
if
(
req
==
NULL
)
{
spin_unlock_bh
(
&
xprt
->
transport_lock
);
printk
(
KERN_WARNING
"Callback slot table overflowed
\n
"
);
xprt_force_disconnect
(
xprt
);
return
-
1
;
...
...
@@ -1391,7 +1395,6 @@ static int xs_tcp_read_callback(struct rpc_xprt *xprt,
if
(
!
(
transport
->
tcp_flags
&
TCP_RCV_COPY_DATA
))
xprt_complete_bc_request
(
req
,
transport
->
tcp_copied
);
spin_unlock_bh
(
&
xprt
->
transport_lock
);
return
0
;
}
...
...
@@ -1516,6 +1519,7 @@ static void xs_tcp_data_receive(struct sock_xprt *transport)
.
arg
.
data
=
xprt
,
};
unsigned
long
total
=
0
;
int
loop
;
int
read
=
0
;
mutex_lock
(
&
transport
->
recv_mutex
);
...
...
@@ -1524,20 +1528,20 @@ static void xs_tcp_data_receive(struct sock_xprt *transport)
goto
out
;
/* We use rd_desc to pass struct xprt to xs_tcp_data_recv */
for
(
;;
)
{
for
(
loop
=
0
;
loop
<
64
;
loop
++
)
{
lock_sock
(
sk
);
read
=
tcp_read_sock
(
sk
,
&
rd_desc
,
xs_tcp_data_recv
);
if
(
read
<=
0
)
{
clear_bit
(
XPRT_SOCK_DATA_READY
,
&
transport
->
sock_state
);
release_sock
(
sk
);
if
(
!
test_bit
(
XPRT_SOCK_DATA_READY
,
&
transport
->
sock_state
))
break
;
}
else
{
}
release_sock
(
sk
);
total
+=
read
;
}
rd_desc
.
count
=
65536
;
}
if
(
test_bit
(
XPRT_SOCK_DATA_READY
,
&
transport
->
sock_state
))
queue_work
(
xprtiod_workqueue
,
&
transport
->
recv_worker
);
out:
mutex_unlock
(
&
transport
->
recv_mutex
);
trace_xs_tcp_data_ready
(
xprt
,
read
,
total
);
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录