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
Kirill Smelkov
linux
Commits
b7561e51
Commit
b7561e51
authored
Aug 18, 2017
by
Trond Myklebust
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'writeback'
parents
55cfcd12
ce7c252a
Changes
20
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
375 additions
and
407 deletions
+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
No files found.
fs/nfs/callback_proc.c
View file @
b7561e51
...
@@ -51,7 +51,7 @@ __be32 nfs4_callback_getattr(void *argp, void *resp,
...
@@ -51,7 +51,7 @@ __be32 nfs4_callback_getattr(void *argp, void *resp,
goto
out_iput
;
goto
out_iput
;
res
->
size
=
i_size_read
(
inode
);
res
->
size
=
i_size_read
(
inode
);
res
->
change_attr
=
delegation
->
change_attr
;
res
->
change_attr
=
delegation
->
change_attr
;
if
(
nfs
i
->
nrequests
!=
0
)
if
(
nfs
_have_writebacks
(
inode
)
)
res
->
change_attr
++
;
res
->
change_attr
++
;
res
->
ctime
=
inode
->
i_ctime
;
res
->
ctime
=
inode
->
i_ctime
;
res
->
mtime
=
inode
->
i_mtime
;
res
->
mtime
=
inode
->
i_mtime
;
...
...
fs/nfs/delegation.c
View file @
b7561e51
...
@@ -1089,7 +1089,7 @@ bool nfs4_delegation_flush_on_close(const struct inode *inode)
...
@@ -1089,7 +1089,7 @@ bool nfs4_delegation_flush_on_close(const struct inode *inode)
delegation
=
rcu_dereference
(
nfsi
->
delegation
);
delegation
=
rcu_dereference
(
nfsi
->
delegation
);
if
(
delegation
==
NULL
||
!
(
delegation
->
type
&
FMODE_WRITE
))
if
(
delegation
==
NULL
||
!
(
delegation
->
type
&
FMODE_WRITE
))
goto
out
;
goto
out
;
if
(
nfsi
->
nrequests
<
delegation
->
pagemod_limit
)
if
(
atomic_long_read
(
&
nfsi
->
nrequests
)
<
delegation
->
pagemod_limit
)
ret
=
false
;
ret
=
false
;
out:
out:
rcu_read_unlock
();
rcu_read_unlock
();
...
...
fs/nfs/direct.c
View file @
b7561e51
...
@@ -616,13 +616,13 @@ nfs_direct_write_scan_commit_list(struct inode *inode,
...
@@ -616,13 +616,13 @@ nfs_direct_write_scan_commit_list(struct inode *inode,
struct
list_head
*
list
,
struct
list_head
*
list
,
struct
nfs_commit_info
*
cinfo
)
struct
nfs_commit_info
*
cinfo
)
{
{
spin_lock
(
&
cinfo
->
inode
->
i_lock
);
mutex_lock
(
&
NFS_I
(
cinfo
->
inode
)
->
commit_mutex
);
#ifdef CONFIG_NFS_V4_1
#ifdef CONFIG_NFS_V4_1
if
(
cinfo
->
ds
!=
NULL
&&
cinfo
->
ds
->
nwritten
!=
0
)
if
(
cinfo
->
ds
!=
NULL
&&
cinfo
->
ds
->
nwritten
!=
0
)
NFS_SERVER
(
inode
)
->
pnfs_curr_ld
->
recover_commit_reqs
(
list
,
cinfo
);
NFS_SERVER
(
inode
)
->
pnfs_curr_ld
->
recover_commit_reqs
(
list
,
cinfo
);
#endif
#endif
nfs_scan_commit_list
(
&
cinfo
->
mds
->
list
,
list
,
cinfo
,
0
);
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
)
static
void
nfs_direct_write_reschedule
(
struct
nfs_direct_req
*
dreq
)
...
...
fs/nfs/inode.c
View file @
b7561e51
...
@@ -1285,7 +1285,6 @@ static bool nfs_file_has_buffered_writers(struct nfs_inode *nfsi)
...
@@ -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
)
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
;
unsigned
long
ret
=
0
;
if
((
fattr
->
valid
&
NFS_ATTR_FATTR_PRECHANGE
)
if
((
fattr
->
valid
&
NFS_ATTR_FATTR_PRECHANGE
)
...
@@ -1315,7 +1314,7 @@ static unsigned long nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr
...
@@ -1315,7 +1314,7 @@ static unsigned long nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr
if
((
fattr
->
valid
&
NFS_ATTR_FATTR_PRESIZE
)
if
((
fattr
->
valid
&
NFS_ATTR_FATTR_PRESIZE
)
&&
(
fattr
->
valid
&
NFS_ATTR_FATTR_SIZE
)
&&
(
fattr
->
valid
&
NFS_ATTR_FATTR_SIZE
)
&&
i_size_read
(
inode
)
==
nfs_size_to_loff_t
(
fattr
->
pre_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
));
i_size_write
(
inode
,
nfs_size_to_loff_t
(
fattr
->
size
));
ret
|=
NFS_INO_INVALID_ATTR
;
ret
|=
NFS_INO_INVALID_ATTR
;
}
}
...
@@ -1823,7 +1822,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
...
@@ -1823,7 +1822,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
if
(
new_isize
!=
cur_isize
)
{
if
(
new_isize
!=
cur_isize
)
{
/* Do we perhaps have any outstanding writes, or has
/* Do we perhaps have any outstanding writes, or has
* the file grown beyond our last write? */
* 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
);
i_size_write
(
inode
,
new_isize
);
if
(
!
have_writers
)
if
(
!
have_writers
)
invalid
|=
NFS_INO_INVALID_ATTR
|
NFS_INO_INVALID_DATA
;
invalid
|=
NFS_INO_INVALID_ATTR
|
NFS_INO_INVALID_DATA
;
...
@@ -2012,10 +2011,11 @@ static void init_once(void *foo)
...
@@ -2012,10 +2011,11 @@ static void init_once(void *foo)
INIT_LIST_HEAD
(
&
nfsi
->
access_cache_entry_lru
);
INIT_LIST_HEAD
(
&
nfsi
->
access_cache_entry_lru
);
INIT_LIST_HEAD
(
&
nfsi
->
access_cache_inode_lru
);
INIT_LIST_HEAD
(
&
nfsi
->
access_cache_inode_lru
);
INIT_LIST_HEAD
(
&
nfsi
->
commit_info
.
list
);
INIT_LIST_HEAD
(
&
nfsi
->
commit_info
.
list
);
nfsi
->
nrequests
=
0
;
atomic_long_set
(
&
nfsi
->
nrequests
,
0
)
;
nfsi
->
commit_info
.
ncommit
=
0
;
atomic_long_set
(
&
nfsi
->
commit_info
.
ncommit
,
0
)
;
atomic_set
(
&
nfsi
->
commit_info
.
rpcs_out
,
0
);
atomic_set
(
&
nfsi
->
commit_info
.
rpcs_out
,
0
);
init_rwsem
(
&
nfsi
->
rmdir_sem
);
init_rwsem
(
&
nfsi
->
rmdir_sem
);
mutex_init
(
&
nfsi
->
commit_mutex
);
nfs4_init_once
(
nfsi
);
nfs4_init_once
(
nfsi
);
}
}
...
...
fs/nfs/pagelist.c
View file @
b7561e51
...
@@ -134,19 +134,14 @@ EXPORT_SYMBOL_GPL(nfs_async_iocounter_wait);
...
@@ -134,19 +134,14 @@ EXPORT_SYMBOL_GPL(nfs_async_iocounter_wait);
/*
/*
* nfs_page_group_lock - lock the head of the page group
* nfs_page_group_lock - lock the head of the page group
* @req - request in group that is to be locked
* @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
* return 0 on success, < 0 on error
* 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.
*/
*/
int
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
;
struct
nfs_page
*
head
=
req
->
wb_head
;
...
@@ -155,35 +150,10 @@ nfs_page_group_lock(struct nfs_page *req, bool nonblock)
...
@@ -155,35 +150,10 @@ nfs_page_group_lock(struct nfs_page *req, bool nonblock)
if
(
!
test_and_set_bit
(
PG_HEADLOCK
,
&
head
->
wb_flags
))
if
(
!
test_and_set_bit
(
PG_HEADLOCK
,
&
head
->
wb_flags
))
return
0
;
return
0
;
if
(
!
nonblock
)
{
set_bit
(
PG_CONTENDED1
,
&
head
->
wb_flags
);
set_bit
(
PG_CONTENDED1
,
&
head
->
wb_flags
);
smp_mb__after_atomic
();
smp_mb__after_atomic
();
return
wait_on_bit_lock
(
&
head
->
wb_flags
,
PG_HEADLOCK
,
return
wait_on_bit_lock
(
&
head
->
wb_flags
,
PG_HEADLOCK
,
TASK_UNINTERRUPTIBLE
);
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)
...
@@ -246,7 +216,7 @@ bool nfs_page_group_sync_on_bit(struct nfs_page *req, unsigned int bit)
{
{
bool
ret
;
bool
ret
;
nfs_page_group_lock
(
req
,
false
);
nfs_page_group_lock
(
req
);
ret
=
nfs_page_group_sync_on_bit_locked
(
req
,
bit
);
ret
=
nfs_page_group_sync_on_bit_locked
(
req
,
bit
);
nfs_page_group_unlock
(
req
);
nfs_page_group_unlock
(
req
);
...
@@ -288,9 +258,7 @@ nfs_page_group_init(struct nfs_page *req, struct nfs_page *prev)
...
@@ -288,9 +258,7 @@ nfs_page_group_init(struct nfs_page *req, struct nfs_page *prev)
inode
=
page_file_mapping
(
req
->
wb_page
)
->
host
;
inode
=
page_file_mapping
(
req
->
wb_page
)
->
host
;
set_bit
(
PG_INODE_REF
,
&
req
->
wb_flags
);
set_bit
(
PG_INODE_REF
,
&
req
->
wb_flags
);
kref_get
(
&
req
->
wb_kref
);
kref_get
(
&
req
->
wb_kref
);
spin_lock
(
&
inode
->
i_lock
);
atomic_long_inc
(
&
NFS_I
(
inode
)
->
nrequests
);
NFS_I
(
inode
)
->
nrequests
++
;
spin_unlock
(
&
inode
->
i_lock
);
}
}
}
}
}
}
...
@@ -306,14 +274,11 @@ static void
...
@@ -306,14 +274,11 @@ static void
nfs_page_group_destroy
(
struct
kref
*
kref
)
nfs_page_group_destroy
(
struct
kref
*
kref
)
{
{
struct
nfs_page
*
req
=
container_of
(
kref
,
struct
nfs_page
,
wb_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
;
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
))
if
(
!
nfs_page_group_sync_on_bit
(
req
,
PG_TEARDOWN
))
return
;
goto
out
;
tmp
=
req
;
tmp
=
req
;
do
{
do
{
...
@@ -324,6 +289,10 @@ nfs_page_group_destroy(struct kref *kref)
...
@@ -324,6 +289,10 @@ nfs_page_group_destroy(struct kref *kref)
nfs_free_request
(
tmp
);
nfs_free_request
(
tmp
);
tmp
=
next
;
tmp
=
next
;
}
while
(
tmp
!=
req
);
}
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)
...
@@ -465,6 +434,7 @@ void nfs_release_request(struct nfs_page *req)
{
{
kref_put
(
&
req
->
wb_kref
,
nfs_page_group_destroy
);
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.
* nfs_wait_on_request - Wait for a request to complete.
...
@@ -483,6 +453,7 @@ nfs_wait_on_request(struct nfs_page *req)
...
@@ -483,6 +453,7 @@ nfs_wait_on_request(struct nfs_page *req)
return
wait_on_bit_io
(
&
req
->
wb_flags
,
PG_BUSY
,
return
wait_on_bit_io
(
&
req
->
wb_flags
,
PG_BUSY
,
TASK_UNINTERRUPTIBLE
);
TASK_UNINTERRUPTIBLE
);
}
}
EXPORT_SYMBOL_GPL
(
nfs_wait_on_request
);
/*
/*
* nfs_generic_pg_test - determine if requests can be coalesced
* 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,
...
@@ -1036,7 +1007,7 @@ static int __nfs_pageio_add_request(struct nfs_pageio_descriptor *desc,
unsigned
int
bytes_left
=
0
;
unsigned
int
bytes_left
=
0
;
unsigned
int
offset
,
pgbase
;
unsigned
int
offset
,
pgbase
;
nfs_page_group_lock
(
req
,
false
);
nfs_page_group_lock
(
req
);
subreq
=
req
;
subreq
=
req
;
bytes_left
=
subreq
->
wb_bytes
;
bytes_left
=
subreq
->
wb_bytes
;
...
@@ -1058,7 +1029,7 @@ static int __nfs_pageio_add_request(struct nfs_pageio_descriptor *desc,
...
@@ -1058,7 +1029,7 @@ static int __nfs_pageio_add_request(struct nfs_pageio_descriptor *desc,
if
(
mirror
->
pg_recoalesce
)
if
(
mirror
->
pg_recoalesce
)
return
0
;
return
0
;
/* retry add_request for this subreq */
/* retry add_request for this subreq */
nfs_page_group_lock
(
req
,
false
);
nfs_page_group_lock
(
req
);
continue
;
continue
;
}
}
...
@@ -1155,7 +1126,7 @@ int nfs_pageio_add_request(struct nfs_pageio_descriptor *desc,
...
@@ -1155,7 +1126,7 @@ int nfs_pageio_add_request(struct nfs_pageio_descriptor *desc,
for
(
midx
=
0
;
midx
<
desc
->
pg_mirror_count
;
midx
++
)
{
for
(
midx
=
0
;
midx
<
desc
->
pg_mirror_count
;
midx
++
)
{
if
(
midx
)
{
if
(
midx
)
{
nfs_page_group_lock
(
req
,
false
);
nfs_page_group_lock
(
req
);
/* find the last request */
/* find the last request */
for
(
lastreq
=
req
->
wb_head
;
for
(
lastreq
=
req
->
wb_head
;
...
...
fs/nfs/pnfs.c
View file @
b7561e51
...
@@ -529,47 +529,6 @@ pnfs_put_lseg(struct pnfs_layout_segment *lseg)
...
@@ -529,47 +529,6 @@ pnfs_put_lseg(struct pnfs_layout_segment *lseg)
}
}
EXPORT_SYMBOL_GPL
(
pnfs_put_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?
* is l2 fully contained in l1?
* start1 end1
* start1 end1
...
...
fs/nfs/pnfs.h
View file @
b7561e51
...
@@ -67,7 +67,6 @@ struct pnfs_layout_segment {
...
@@ -67,7 +67,6 @@ struct pnfs_layout_segment {
u32
pls_seq
;
u32
pls_seq
;
unsigned
long
pls_flags
;
unsigned
long
pls_flags
;
struct
pnfs_layout_hdr
*
pls_layout
;
struct
pnfs_layout_hdr
*
pls_layout
;
struct
work_struct
pls_work
;
};
};
enum
pnfs_try_status
{
enum
pnfs_try_status
{
...
@@ -230,7 +229,6 @@ extern int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp, bool sync);
...
@@ -230,7 +229,6 @@ extern int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp, bool sync);
/* pnfs.c */
/* pnfs.c */
void
pnfs_get_layout_hdr
(
struct
pnfs_layout_hdr
*
lo
);
void
pnfs_get_layout_hdr
(
struct
pnfs_layout_hdr
*
lo
);
void
pnfs_put_lseg
(
struct
pnfs_layout_segment
*
lseg
);
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
set_pnfs_layoutdriver
(
struct
nfs_server
*
,
const
struct
nfs_fh
*
,
struct
nfs_fsinfo
*
);
void
unset_pnfs_layoutdriver
(
struct
nfs_server
*
);
void
unset_pnfs_layoutdriver
(
struct
nfs_server
*
);
...
...
fs/nfs/pnfs_nfs.c
View file @
b7561e51
...
@@ -83,7 +83,7 @@ pnfs_generic_clear_request_commit(struct nfs_page *req,
...
@@ -83,7 +83,7 @@ pnfs_generic_clear_request_commit(struct nfs_page *req,
}
}
out:
out:
nfs_request_remove_commit_list
(
req
,
cinfo
);
nfs_request_remove_commit_list
(
req
,
cinfo
);
pnfs_put_lseg
_locked
(
freeme
);
pnfs_put_lseg
(
freeme
);
}
}
EXPORT_SYMBOL_GPL
(
pnfs_generic_clear_request_commit
);
EXPORT_SYMBOL_GPL
(
pnfs_generic_clear_request_commit
);
...
@@ -91,21 +91,30 @@ static int
...
@@ -91,21 +91,30 @@ static int
pnfs_generic_transfer_commit_list
(
struct
list_head
*
src
,
struct
list_head
*
dst
,
pnfs_generic_transfer_commit_list
(
struct
list_head
*
src
,
struct
list_head
*
dst
,
struct
nfs_commit_info
*
cinfo
,
int
max
)
struct
nfs_commit_info
*
cinfo
,
int
max
)
{
{
struct
nfs_page
*
req
,
*
tmp
;
struct
nfs_page
*
req
;
int
ret
=
0
;
int
ret
=
0
;
list_for_each_entry_safe
(
req
,
tmp
,
src
,
wb_list
)
{
while
(
!
list_empty
(
src
)
)
{
if
(
!
nfs_lock_request
(
req
))
req
=
list_first_entry
(
src
,
struct
nfs_page
,
wb_list
);
continue
;
kref_get
(
&
req
->
wb_kref
);
kref_get
(
&
req
->
wb_kref
);
if
(
cond_resched_lock
(
&
cinfo
->
inode
->
i_lock
))
if
(
!
nfs_lock_request
(
req
))
{
list_safe_reset_next
(
req
,
tmp
,
wb_list
);
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_request_remove_commit_list
(
req
,
cinfo
);
clear_bit
(
PG_COMMIT_TO_DS
,
&
req
->
wb_flags
);
clear_bit
(
PG_COMMIT_TO_DS
,
&
req
->
wb_flags
);
nfs_list_add_request
(
req
,
dst
);
nfs_list_add_request
(
req
,
dst
);
ret
++
;
ret
++
;
if
((
ret
==
max
)
&&
!
cinfo
->
dreq
)
if
((
ret
==
max
)
&&
!
cinfo
->
dreq
)
break
;
break
;
cond_resched
();
}
}
return
ret
;
return
ret
;
}
}
...
@@ -119,7 +128,7 @@ pnfs_generic_scan_ds_commit_list(struct pnfs_commit_bucket *bucket,
...
@@ -119,7 +128,7 @@ pnfs_generic_scan_ds_commit_list(struct pnfs_commit_bucket *bucket,
struct
list_head
*
dst
=
&
bucket
->
committing
;
struct
list_head
*
dst
=
&
bucket
->
committing
;
int
ret
;
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
);
ret
=
pnfs_generic_transfer_commit_list
(
src
,
dst
,
cinfo
,
max
);
if
(
ret
)
{
if
(
ret
)
{
cinfo
->
ds
->
nwritten
-=
ret
;
cinfo
->
ds
->
nwritten
-=
ret
;
...
@@ -127,7 +136,7 @@ pnfs_generic_scan_ds_commit_list(struct pnfs_commit_bucket *bucket,
...
@@ -127,7 +136,7 @@ pnfs_generic_scan_ds_commit_list(struct pnfs_commit_bucket *bucket,
if
(
bucket
->
clseg
==
NULL
)
if
(
bucket
->
clseg
==
NULL
)
bucket
->
clseg
=
pnfs_get_lseg
(
bucket
->
wlseg
);
bucket
->
clseg
=
pnfs_get_lseg
(
bucket
->
wlseg
);
if
(
list_empty
(
src
))
{
if
(
list_empty
(
src
))
{
pnfs_put_lseg
_locked
(
bucket
->
wlseg
);
pnfs_put_lseg
(
bucket
->
wlseg
);
bucket
->
wlseg
=
NULL
;
bucket
->
wlseg
=
NULL
;
}
}
}
}
...
@@ -142,7 +151,7 @@ int pnfs_generic_scan_commit_lists(struct nfs_commit_info *cinfo,
...
@@ -142,7 +151,7 @@ int pnfs_generic_scan_commit_lists(struct nfs_commit_info *cinfo,
{
{
int
i
,
rv
=
0
,
cnt
;
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
++
)
{
for
(
i
=
0
;
i
<
cinfo
->
ds
->
nbuckets
&&
max
!=
0
;
i
++
)
{
cnt
=
pnfs_generic_scan_ds_commit_list
(
&
cinfo
->
ds
->
buckets
[
i
],
cnt
=
pnfs_generic_scan_ds_commit_list
(
&
cinfo
->
ds
->
buckets
[
i
],
cinfo
,
max
);
cinfo
,
max
);
...
@@ -162,7 +171,7 @@ void pnfs_generic_recover_commit_reqs(struct list_head *dst,
...
@@ -162,7 +171,7 @@ void pnfs_generic_recover_commit_reqs(struct list_head *dst,
int
nwritten
;
int
nwritten
;
int
i
;
int
i
;
lockdep_assert_held
(
&
cinfo
->
inode
->
i_lock
);
lockdep_assert_held
(
&
NFS_I
(
cinfo
->
inode
)
->
commit_mutex
);
restart:
restart:
for
(
i
=
0
,
b
=
cinfo
->
ds
->
buckets
;
i
<
cinfo
->
ds
->
nbuckets
;
i
++
,
b
++
)
{
for
(
i
=
0
,
b
=
cinfo
->
ds
->
buckets
;
i
<
cinfo
->
ds
->
nbuckets
;
i
++
,
b
++
)
{
nwritten
=
pnfs_generic_transfer_commit_list
(
&
b
->
written
,
nwritten
=
pnfs_generic_transfer_commit_list
(
&
b
->
written
,
...
@@ -953,12 +962,12 @@ pnfs_layout_mark_request_commit(struct nfs_page *req,
...
@@ -953,12 +962,12 @@ pnfs_layout_mark_request_commit(struct nfs_page *req,
struct
list_head
*
list
;
struct
list_head
*
list
;
struct
pnfs_commit_bucket
*
buckets
;
struct
pnfs_commit_bucket
*
buckets
;
spin_lock
(
&
cinfo
->
inode
->
i_lock
);
mutex_lock
(
&
NFS_I
(
cinfo
->
inode
)
->
commit_mutex
);
buckets
=
cinfo
->
ds
->
buckets
;
buckets
=
cinfo
->
ds
->
buckets
;
list
=
&
buckets
[
ds_commit_idx
].
written
;
list
=
&
buckets
[
ds_commit_idx
].
written
;
if
(
list_empty
(
list
))
{
if
(
list_empty
(
list
))
{
if
(
!
pnfs_is_valid_lseg
(
lseg
))
{
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
);
cinfo
->
completion_ops
->
resched_write
(
cinfo
,
req
);
return
;
return
;
}
}
...
@@ -975,7 +984,7 @@ pnfs_layout_mark_request_commit(struct nfs_page *req,
...
@@ -975,7 +984,7 @@ pnfs_layout_mark_request_commit(struct nfs_page *req,
cinfo
->
ds
->
nwritten
++
;
cinfo
->
ds
->
nwritten
++
;
nfs_request_add_commit_list_locked
(
req
,
list
,
cinfo
);
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
);
nfs_mark_page_unstable
(
req
->
wb_page
,
cinfo
);
}
}
EXPORT_SYMBOL_GPL
(
pnfs_layout_mark_request_commit
);
EXPORT_SYMBOL_GPL
(
pnfs_layout_mark_request_commit
);
...
...
fs/nfs/write.c
View file @
b7561e51
This diff is collapsed.
Click to expand it.
include/linux/nfs_fs.h
View file @
b7561e51
...
@@ -154,7 +154,7 @@ struct nfs_inode {
...
@@ -154,7 +154,7 @@ struct nfs_inode {
*/
*/
__be32
cookieverf
[
2
];
__be32
cookieverf
[
2
];
unsigned
long
nrequests
;
atomic_long_t
nrequests
;
struct
nfs_mds_commit_info
commit_info
;
struct
nfs_mds_commit_info
commit_info
;
/* Open contexts for shared mmap writes */
/* Open contexts for shared mmap writes */
...
@@ -163,6 +163,7 @@ struct nfs_inode {
...
@@ -163,6 +163,7 @@ struct nfs_inode {
/* Readers: in-flight sillydelete RPC calls */
/* Readers: in-flight sillydelete RPC calls */
/* Writers: rmdir */
/* Writers: rmdir */
struct
rw_semaphore
rmdir_sem
;
struct
rw_semaphore
rmdir_sem
;
struct
mutex
commit_mutex
;
#if IS_ENABLED(CONFIG_NFS_V4)
#if IS_ENABLED(CONFIG_NFS_V4)
struct
nfs4_cached_acl
*
nfs4_acl
;
struct
nfs4_cached_acl
*
nfs4_acl
;
...
@@ -510,7 +511,7 @@ extern void nfs_commit_free(struct nfs_commit_data *data);
...
@@ -510,7 +511,7 @@ extern void nfs_commit_free(struct nfs_commit_data *data);
static
inline
int
static
inline
int
nfs_have_writebacks
(
struct
inode
*
inode
)
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
View file @
b7561e51
...
@@ -139,8 +139,7 @@ extern size_t nfs_generic_pg_test(struct nfs_pageio_descriptor *desc,
...
@@ -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
int
nfs_wait_on_request
(
struct
nfs_page
*
);
extern
void
nfs_unlock_request
(
struct
nfs_page
*
req
);
extern
void
nfs_unlock_request
(
struct
nfs_page
*
req
);
extern
void
nfs_unlock_and_release_request
(
struct
nfs_page
*
);
extern
void
nfs_unlock_and_release_request
(
struct
nfs_page
*
);
extern
int
nfs_page_group_lock
(
struct
nfs_page
*
,
bool
);
extern
int
nfs_page_group_lock
(
struct
nfs_page
*
);
extern
void
nfs_page_group_lock_wait
(
struct
nfs_page
*
);
extern
void
nfs_page_group_unlock
(
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_page_group_sync_on_bit
(
struct
nfs_page
*
,
unsigned
int
);
extern
bool
nfs_async_iocounter_wait
(
struct
rpc_task
*
,
struct
nfs_lock_context
*
);
extern
bool
nfs_async_iocounter_wait
(
struct
rpc_task
*
,
struct
nfs_lock_context
*
);
...
...
include/linux/nfs_xdr.h
View file @
b7561e51
...
@@ -1476,7 +1476,7 @@ struct nfs_pgio_header {
...
@@ -1476,7 +1476,7 @@ struct nfs_pgio_header {
struct
nfs_mds_commit_info
{
struct
nfs_mds_commit_info
{
atomic_t
rpcs_out
;
atomic_t
rpcs_out
;
unsigned
long
ncommit
;
atomic_long_t
ncommit
;
struct
list_head
list
;
struct
list_head
list
;
};
};
...
...
include/linux/sunrpc/sched.h
View file @
b7561e51
...
@@ -139,6 +139,8 @@ struct rpc_task_setup {
...
@@ -139,6 +139,8 @@ struct rpc_task_setup {
#define RPC_TASK_RUNNING 0
#define RPC_TASK_RUNNING 0
#define RPC_TASK_QUEUED 1
#define RPC_TASK_QUEUED 1
#define RPC_TASK_ACTIVE 2
#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_IS_RUNNING(t) test_bit(RPC_TASK_RUNNING, &(t)->tk_runstate)
#define rpc_set_running(t) set_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
View file @
b7561e51
...
@@ -232,6 +232,7 @@ struct rpc_xprt {
...
@@ -232,6 +232,7 @@ struct rpc_xprt {
*/
*/
spinlock_t
transport_lock
;
/* lock transport info */
spinlock_t
transport_lock
;
/* lock transport info */
spinlock_t
reserve_lock
;
/* lock slot table */
spinlock_t
reserve_lock
;
/* lock slot table */
spinlock_t
recv_lock
;
/* lock receive list */
u32
xid
;
/* Next XID value to use */
u32
xid
;
/* Next XID value to use */
struct
rpc_task
*
snd_task
;
/* Task blocked in send */
struct
rpc_task
*
snd_task
;
/* Task blocked in send */
struct
svc_xprt
*
bc_xprt
;
/* NFSv4.1 backchannel */
struct
svc_xprt
*
bc_xprt
;
/* NFSv4.1 backchannel */
...
@@ -372,6 +373,8 @@ void xprt_write_space(struct rpc_xprt *xprt);
...
@@ -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
);
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
);
struct
rpc_rqst
*
xprt_lookup_rqst
(
struct
rpc_xprt
*
xprt
,
__be32
xid
);
void
xprt_complete_rqst
(
struct
rpc_task
*
task
,
int
copied
);
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_release_rqst_cong
(
struct
rpc_task
*
task
);
void
xprt_disconnect_done
(
struct
rpc_xprt
*
xprt
);
void
xprt_disconnect_done
(
struct
rpc_xprt
*
xprt
);
void
xprt_force_disconnect
(
struct
rpc_xprt
*
xprt
);
void
xprt_force_disconnect
(
struct
rpc_xprt
*
xprt
);
...
...
net/sunrpc/backchannel_rqst.c
View file @
b7561e51
...
@@ -171,10 +171,10 @@ int xprt_setup_bc(struct rpc_xprt *xprt, unsigned int min_reqs)
...
@@ -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
* 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
);
list_splice
(
&
tmp_list
,
&
xprt
->
bc_pa_list
);
xprt_inc_alloc_count
(
xprt
,
min_reqs
);
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
"
);
dprintk
(
"RPC: setup backchannel transport done
\n
"
);
return
0
;
return
0
;
...
...
net/sunrpc/svcsock.c
View file @
b7561e51
...
@@ -1001,7 +1001,7 @@ static int receive_cb_reply(struct svc_sock *svsk, struct svc_rqst *rqstp)
...
@@ -1001,7 +1001,7 @@ static int receive_cb_reply(struct svc_sock *svsk, struct svc_rqst *rqstp)
if
(
!
bc_xprt
)
if
(
!
bc_xprt
)
return
-
EAGAIN
;
return
-
EAGAIN
;
spin_lock
_bh
(
&
bc_xprt
->
transport
_lock
);
spin_lock
(
&
bc_xprt
->
recv
_lock
);
req
=
xprt_lookup_rqst
(
bc_xprt
,
xid
);
req
=
xprt_lookup_rqst
(
bc_xprt
,
xid
);
if
(
!
req
)
if
(
!
req
)
goto
unlock_notfound
;
goto
unlock_notfound
;
...
@@ -1019,7 +1019,7 @@ static int receive_cb_reply(struct svc_sock *svsk, struct svc_rqst *rqstp)
...
@@ -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
);
memcpy
(
dst
->
iov_base
,
src
->
iov_base
,
src
->
iov_len
);
xprt_complete_rqst
(
req
->
rq_task
,
rqstp
->
rq_arg
.
len
);
xprt_complete_rqst
(
req
->
rq_task
,
rqstp
->
rq_arg
.
len
);
rqstp
->
rq_arg
.
len
=
0
;
rqstp
->
rq_arg
.
len
=
0
;
spin_unlock
_bh
(
&
bc_xprt
->
transport
_lock
);
spin_unlock
(
&
bc_xprt
->
recv
_lock
);
return
0
;
return
0
;
unlock_notfound:
unlock_notfound:
printk
(
KERN_NOTICE
printk
(
KERN_NOTICE
...
@@ -1028,7 +1028,7 @@ static int receive_cb_reply(struct svc_sock *svsk, struct svc_rqst *rqstp)
...
@@ -1028,7 +1028,7 @@ static int receive_cb_reply(struct svc_sock *svsk, struct svc_rqst *rqstp)
__func__
,
ntohl
(
calldir
),
__func__
,
ntohl
(
calldir
),
bc_xprt
,
ntohl
(
xid
));
bc_xprt
,
ntohl
(
xid
));
unlock_eagain:
unlock_eagain:
spin_unlock
_bh
(
&
bc_xprt
->
transport
_lock
);
spin_unlock
(
&
bc_xprt
->
recv
_lock
);
return
-
EAGAIN
;
return
-
EAGAIN
;
}
}
...
...
net/sunrpc/xprt.c
View file @
b7561e51
...
@@ -844,6 +844,48 @@ struct rpc_rqst *xprt_lookup_rqst(struct rpc_xprt *xprt, __be32 xid)
...
@@ -844,6 +844,48 @@ struct rpc_rqst *xprt_lookup_rqst(struct rpc_xprt *xprt, __be32 xid)
}
}
EXPORT_SYMBOL_GPL
(
xprt_lookup_rqst
);
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
)
static
void
xprt_update_rtt
(
struct
rpc_task
*
task
)
{
{
struct
rpc_rqst
*
req
=
task
->
tk_rqstp
;
struct
rpc_rqst
*
req
=
task
->
tk_rqstp
;
...
@@ -966,13 +1008,13 @@ void xprt_transmit(struct rpc_task *task)
...
@@ -966,13 +1008,13 @@ void xprt_transmit(struct rpc_task *task)
/*
/*
* Add to the list only if we're expecting a reply
* Add to the list only if we're expecting a reply
*/
*/
spin_lock_bh
(
&
xprt
->
transport_lock
);
/* Update the softirq receive buffer */
/* Update the softirq receive buffer */
memcpy
(
&
req
->
rq_private_buf
,
&
req
->
rq_rcv_buf
,
memcpy
(
&
req
->
rq_private_buf
,
&
req
->
rq_rcv_buf
,
sizeof
(
req
->
rq_private_buf
));
sizeof
(
req
->
rq_private_buf
));
/* Add request to the receive list */
/* Add request to the receive list */
spin_lock
(
&
xprt
->
recv_lock
);
list_add_tail
(
&
req
->
rq_list
,
&
xprt
->
recv
);
list_add_tail
(
&
req
->
rq_list
,
&
xprt
->
recv
);
spin_unlock
_bh
(
&
xprt
->
transport
_lock
);
spin_unlock
(
&
xprt
->
recv
_lock
);
xprt_reset_majortimeo
(
req
);
xprt_reset_majortimeo
(
req
);
/* Turn off autodisconnect */
/* Turn off autodisconnect */
del_singleshot_timer_sync
(
&
xprt
->
timer
);
del_singleshot_timer_sync
(
&
xprt
->
timer
);
...
@@ -1287,12 +1329,16 @@ void xprt_release(struct rpc_task *task)
...
@@ -1287,12 +1329,16 @@ void xprt_release(struct rpc_task *task)
task
->
tk_ops
->
rpc_count_stats
(
task
,
task
->
tk_calldata
);
task
->
tk_ops
->
rpc_count_stats
(
task
,
task
->
tk_calldata
);
else
if
(
task
->
tk_client
)
else
if
(
task
->
tk_client
)
rpc_count_iostats
(
task
,
task
->
tk_client
->
cl_metrics
);
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
);
spin_lock_bh
(
&
xprt
->
transport_lock
);
xprt
->
ops
->
release_xprt
(
xprt
,
task
);
xprt
->
ops
->
release_xprt
(
xprt
,
task
);
if
(
xprt
->
ops
->
release_request
)
if
(
xprt
->
ops
->
release_request
)
xprt
->
ops
->
release_request
(
task
);
xprt
->
ops
->
release_request
(
task
);
if
(
!
list_empty
(
&
req
->
rq_list
))
list_del
(
&
req
->
rq_list
);
xprt
->
last_used
=
jiffies
;
xprt
->
last_used
=
jiffies
;
xprt_schedule_autodisconnect
(
xprt
);
xprt_schedule_autodisconnect
(
xprt
);
spin_unlock_bh
(
&
xprt
->
transport_lock
);
spin_unlock_bh
(
&
xprt
->
transport_lock
);
...
@@ -1318,6 +1364,7 @@ static void xprt_init(struct rpc_xprt *xprt, struct net *net)
...
@@ -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
->
transport_lock
);
spin_lock_init
(
&
xprt
->
reserve_lock
);
spin_lock_init
(
&
xprt
->
reserve_lock
);
spin_lock_init
(
&
xprt
->
recv_lock
);
INIT_LIST_HEAD
(
&
xprt
->
free
);
INIT_LIST_HEAD
(
&
xprt
->
free
);
INIT_LIST_HEAD
(
&
xprt
->
recv
);
INIT_LIST_HEAD
(
&
xprt
->
recv
);
...
...
net/sunrpc/xprtrdma/rpc_rdma.c
View file @
b7561e51
...
@@ -1051,7 +1051,7 @@ rpcrdma_reply_handler(struct work_struct *work)
...
@@ -1051,7 +1051,7 @@ rpcrdma_reply_handler(struct work_struct *work)
* RPC completion while holding the transport lock to ensure
* RPC completion while holding the transport lock to ensure
* the rep, rqst, and rq_task pointers remain stable.
* 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
);
rqst
=
xprt_lookup_rqst
(
xprt
,
headerp
->
rm_xid
);
if
(
!
rqst
)
if
(
!
rqst
)
goto
out_norqst
;
goto
out_norqst
;
...
@@ -1136,7 +1136,7 @@ rpcrdma_reply_handler(struct work_struct *work)
...
@@ -1136,7 +1136,7 @@ rpcrdma_reply_handler(struct work_struct *work)
xprt_release_rqst_cong
(
rqst
->
rq_task
);
xprt_release_rqst_cong
(
rqst
->
rq_task
);
xprt_complete_rqst
(
rqst
->
rq_task
,
status
);
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
"
,
dprintk
(
"RPC: %s: xprt_complete_rqst(0x%p, 0x%p, %d)
\n
"
,
__func__
,
xprt
,
rqst
,
status
);
__func__
,
xprt
,
rqst
,
status
);
return
;
return
;
...
@@ -1187,12 +1187,12 @@ rpcrdma_reply_handler(struct work_struct *work)
...
@@ -1187,12 +1187,12 @@ rpcrdma_reply_handler(struct work_struct *work)
r_xprt
->
rx_stats
.
bad_reply_count
++
;
r_xprt
->
rx_stats
.
bad_reply_count
++
;
goto
out
;
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
* was acquired, the rqst and task had been released. Thus the RPC
* has already been terminated.
* has already been terminated.
*/
*/
out_norqst:
out_norqst:
spin_unlock
_bh
(
&
xprt
->
transport
_lock
);
spin_unlock
(
&
xprt
->
recv
_lock
);
rpcrdma_buffer_put
(
req
);
rpcrdma_buffer_put
(
req
);
dprintk
(
"RPC: %s: race, no rqst left for req %p
\n
"
,
dprintk
(
"RPC: %s: race, no rqst left for req %p
\n
"
,
__func__
,
req
);
__func__
,
req
);
...
...
net/sunrpc/xprtrdma/svc_rdma_backchannel.c
View file @
b7561e51
...
@@ -52,7 +52,7 @@ int svc_rdma_handle_bc_reply(struct rpc_xprt *xprt, __be32 *rdma_resp,
...
@@ -52,7 +52,7 @@ int svc_rdma_handle_bc_reply(struct rpc_xprt *xprt, __be32 *rdma_resp,
if
(
src
->
iov_len
<
24
)
if
(
src
->
iov_len
<
24
)
goto
out_shortreply
;
goto
out_shortreply
;
spin_lock
_bh
(
&
xprt
->
transport
_lock
);
spin_lock
(
&
xprt
->
recv
_lock
);
req
=
xprt_lookup_rqst
(
xprt
,
xid
);
req
=
xprt_lookup_rqst
(
xprt
,
xid
);
if
(
!
req
)
if
(
!
req
)
goto
out_notfound
;
goto
out_notfound
;
...
@@ -69,17 +69,20 @@ int svc_rdma_handle_bc_reply(struct rpc_xprt *xprt, __be32 *rdma_resp,
...
@@ -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
)
else
if
(
credits
>
r_xprt
->
rx_buf
.
rb_bc_max_requests
)
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
;
cwnd
=
xprt
->
cwnd
;
xprt
->
cwnd
=
credits
<<
RPC_CWNDSHIFT
;
xprt
->
cwnd
=
credits
<<
RPC_CWNDSHIFT
;
if
(
xprt
->
cwnd
>
cwnd
)
if
(
xprt
->
cwnd
>
cwnd
)
xprt_release_rqst_cong
(
req
->
rq_task
);
xprt_release_rqst_cong
(
req
->
rq_task
);
spin_unlock_bh
(
&
xprt
->
transport_lock
);
ret
=
0
;
ret
=
0
;
xprt_complete_rqst
(
req
->
rq_task
,
rcvbuf
->
len
);
xprt_complete_rqst
(
req
->
rq_task
,
rcvbuf
->
len
);
rcvbuf
->
len
=
0
;
rcvbuf
->
len
=
0
;
out_unlock:
out_unlock:
spin_unlock
_bh
(
&
xprt
->
transport
_lock
);
spin_unlock
(
&
xprt
->
recv
_lock
);
out:
out:
return
ret
;
return
ret
;
...
...
net/sunrpc/xprtsock.c
View file @
b7561e51
...
@@ -969,10 +969,12 @@ static void xs_local_data_read_skb(struct rpc_xprt *xprt,
...
@@ -969,10 +969,12 @@ static void xs_local_data_read_skb(struct rpc_xprt *xprt,
return
;
return
;
/* Look up and lock the request corresponding to the given XID */
/* 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
);
rovr
=
xprt_lookup_rqst
(
xprt
,
*
xp
);
if
(
!
rovr
)
if
(
!
rovr
)
goto
out_unlock
;
goto
out_unlock
;
xprt_pin_rqst
(
rovr
);
spin_unlock
(
&
xprt
->
recv_lock
);
task
=
rovr
->
rq_task
;
task
=
rovr
->
rq_task
;
copied
=
rovr
->
rq_private_buf
.
buflen
;
copied
=
rovr
->
rq_private_buf
.
buflen
;
...
@@ -981,13 +983,16 @@ static void xs_local_data_read_skb(struct rpc_xprt *xprt,
...
@@ -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
))
{
if
(
xs_local_copy_to_xdr
(
&
rovr
->
rq_private_buf
,
skb
))
{
dprintk
(
"RPC: sk_buff copy failed
\n
"
);
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
);
xprt_complete_rqst
(
task
,
copied
);
out_unpin:
xprt_unpin_rqst
(
rovr
);
out_unlock:
out_unlock:
spin_unlock
_bh
(
&
xprt
->
transport
_lock
);
spin_unlock
(
&
xprt
->
recv
_lock
);
}
}
static
void
xs_local_data_receive
(
struct
sock_xprt
*
transport
)
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,
...
@@ -1050,10 +1055,12 @@ static void xs_udp_data_read_skb(struct rpc_xprt *xprt,
return
;
return
;
/* Look up and lock the request corresponding to the given XID */
/* 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
);
rovr
=
xprt_lookup_rqst
(
xprt
,
*
xp
);
if
(
!
rovr
)
if
(
!
rovr
)
goto
out_unlock
;
goto
out_unlock
;
xprt_pin_rqst
(
rovr
);
spin_unlock
(
&
xprt
->
recv_lock
);
task
=
rovr
->
rq_task
;
task
=
rovr
->
rq_task
;
if
((
copied
=
rovr
->
rq_private_buf
.
buflen
)
>
repsize
)
if
((
copied
=
rovr
->
rq_private_buf
.
buflen
)
>
repsize
)
...
@@ -1062,16 +1069,21 @@ static void xs_udp_data_read_skb(struct rpc_xprt *xprt,
...
@@ -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. */
/* Suck it into the iovec, verify checksum if not done by hw. */
if
(
csum_partial_copy_to_xdr
(
&
rovr
->
rq_private_buf
,
skb
))
{
if
(
csum_partial_copy_to_xdr
(
&
rovr
->
rq_private_buf
,
skb
))
{
__UDPX_INC_STATS
(
sk
,
UDP_MIB_INERRORS
);
__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
);
__UDPX_INC_STATS
(
sk
,
UDP_MIB_INDATAGRAMS
);
spin_lock_bh
(
&
xprt
->
transport_lock
);
xprt_adjust_cwnd
(
xprt
,
task
,
copied
);
xprt_adjust_cwnd
(
xprt
,
task
,
copied
);
spin_unlock_bh
(
&
xprt
->
transport_lock
);
spin_lock
(
&
xprt
->
recv_lock
);
xprt_complete_rqst
(
task
,
copied
);
xprt_complete_rqst
(
task
,
copied
);
out_unpin:
xprt_unpin_rqst
(
rovr
);
out_unlock:
out_unlock:
spin_unlock
_bh
(
&
xprt
->
transport
_lock
);
spin_unlock
(
&
xprt
->
recv
_lock
);
}
}
static
void
xs_udp_data_receive
(
struct
sock_xprt
*
transport
)
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,
...
@@ -1277,25 +1289,12 @@ static inline void xs_tcp_read_common(struct rpc_xprt *xprt,
}
}
len
=
desc
->
count
;
len
=
desc
->
count
;
if
(
len
>
transport
->
tcp_reclen
-
transport
->
tcp_offset
)
{
if
(
len
>
transport
->
tcp_reclen
-
transport
->
tcp_offset
)
struct
xdr_skb_reader
my_desc
;
desc
->
count
=
transport
->
tcp_reclen
-
transport
->
tcp_offset
;
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
r
=
xdr_partial_copy_from_skb
(
rcvbuf
,
transport
->
tcp_copied
,
r
=
xdr_partial_copy_from_skb
(
rcvbuf
,
transport
->
tcp_copied
,
desc
,
xdr_skb_read_bits
);
desc
,
xdr_skb_read_bits
);
if
(
r
>
0
)
{
if
(
desc
->
count
)
{
transport
->
tcp_copied
+=
r
;
transport
->
tcp_offset
+=
r
;
}
if
(
r
!=
len
)
{
/* Error when copying to the receive buffer,
/* Error when copying to the receive buffer,
* usually because we weren't able to allocate
* usually because we weren't able to allocate
* additional buffer pages. All we can do now
* additional buffer pages. All we can do now
...
@@ -1315,6 +1314,10 @@ static inline void xs_tcp_read_common(struct rpc_xprt *xprt,
...
@@ -1315,6 +1314,10 @@ static inline void xs_tcp_read_common(struct rpc_xprt *xprt,
return
;
return
;
}
}
transport
->
tcp_copied
+=
r
;
transport
->
tcp_offset
+=
r
;
desc
->
count
=
len
-
r
;
dprintk
(
"RPC: XID %08x read %zd bytes
\n
"
,
dprintk
(
"RPC: XID %08x read %zd bytes
\n
"
,
ntohl
(
transport
->
tcp_xid
),
r
);
ntohl
(
transport
->
tcp_xid
),
r
);
dprintk
(
"RPC: xprt = %p, tcp_copied = %lu, tcp_offset = %u, "
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,
...
@@ -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
));
dprintk
(
"RPC: read reply XID %08x
\n
"
,
ntohl
(
transport
->
tcp_xid
));
/* Find and lock the request corresponding to this 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
);
req
=
xprt_lookup_rqst
(
xprt
,
transport
->
tcp_xid
);
if
(
!
req
)
{
if
(
!
req
)
{
dprintk
(
"RPC: XID %08x request not found!
\n
"
,
dprintk
(
"RPC: XID %08x request not found!
\n
"
,
ntohl
(
transport
->
tcp_xid
));
ntohl
(
transport
->
tcp_xid
));
spin_unlock
_bh
(
&
xprt
->
transport
_lock
);
spin_unlock
(
&
xprt
->
recv
_lock
);
return
-
1
;
return
-
1
;
}
}
xprt_pin_rqst
(
req
);
spin_unlock
(
&
xprt
->
recv_lock
);
xs_tcp_read_common
(
xprt
,
desc
,
req
);
xs_tcp_read_common
(
xprt
,
desc
,
req
);
spin_lock
(
&
xprt
->
recv_lock
);
if
(
!
(
transport
->
tcp_flags
&
TCP_RCV_COPY_DATA
))
if
(
!
(
transport
->
tcp_flags
&
TCP_RCV_COPY_DATA
))
xprt_complete_rqst
(
req
->
rq_task
,
transport
->
tcp_copied
);
xprt_complete_rqst
(
req
->
rq_task
,
transport
->
tcp_copied
);
xprt_unpin_rqst
(
req
);
spin_unlock
_bh
(
&
xprt
->
transport
_lock
);
spin_unlock
(
&
xprt
->
recv
_lock
);
return
0
;
return
0
;
}
}
...
@@ -1376,11 +1382,9 @@ static int xs_tcp_read_callback(struct rpc_xprt *xprt,
...
@@ -1376,11 +1382,9 @@ static int xs_tcp_read_callback(struct rpc_xprt *xprt,
container_of
(
xprt
,
struct
sock_xprt
,
xprt
);
container_of
(
xprt
,
struct
sock_xprt
,
xprt
);
struct
rpc_rqst
*
req
;
struct
rpc_rqst
*
req
;
/* Look up and lock the request corresponding to the given XID */
/* Look up the request corresponding to the given XID */
spin_lock_bh
(
&
xprt
->
transport_lock
);
req
=
xprt_lookup_bc_request
(
xprt
,
transport
->
tcp_xid
);
req
=
xprt_lookup_bc_request
(
xprt
,
transport
->
tcp_xid
);
if
(
req
==
NULL
)
{
if
(
req
==
NULL
)
{
spin_unlock_bh
(
&
xprt
->
transport_lock
);
printk
(
KERN_WARNING
"Callback slot table overflowed
\n
"
);
printk
(
KERN_WARNING
"Callback slot table overflowed
\n
"
);
xprt_force_disconnect
(
xprt
);
xprt_force_disconnect
(
xprt
);
return
-
1
;
return
-
1
;
...
@@ -1391,7 +1395,6 @@ static int xs_tcp_read_callback(struct rpc_xprt *xprt,
...
@@ -1391,7 +1395,6 @@ static int xs_tcp_read_callback(struct rpc_xprt *xprt,
if
(
!
(
transport
->
tcp_flags
&
TCP_RCV_COPY_DATA
))
if
(
!
(
transport
->
tcp_flags
&
TCP_RCV_COPY_DATA
))
xprt_complete_bc_request
(
req
,
transport
->
tcp_copied
);
xprt_complete_bc_request
(
req
,
transport
->
tcp_copied
);
spin_unlock_bh
(
&
xprt
->
transport_lock
);
return
0
;
return
0
;
}
}
...
@@ -1516,6 +1519,7 @@ static void xs_tcp_data_receive(struct sock_xprt *transport)
...
@@ -1516,6 +1519,7 @@ static void xs_tcp_data_receive(struct sock_xprt *transport)
.
arg
.
data
=
xprt
,
.
arg
.
data
=
xprt
,
};
};
unsigned
long
total
=
0
;
unsigned
long
total
=
0
;
int
loop
;
int
read
=
0
;
int
read
=
0
;
mutex_lock
(
&
transport
->
recv_mutex
);
mutex_lock
(
&
transport
->
recv_mutex
);
...
@@ -1524,20 +1528,20 @@ static void xs_tcp_data_receive(struct sock_xprt *transport)
...
@@ -1524,20 +1528,20 @@ static void xs_tcp_data_receive(struct sock_xprt *transport)
goto
out
;
goto
out
;
/* We use rd_desc to pass struct xprt to xs_tcp_data_recv */
/* We use rd_desc to pass struct xprt to xs_tcp_data_recv */
for
(
;;
)
{
for
(
loop
=
0
;
loop
<
64
;
loop
++
)
{
lock_sock
(
sk
);
lock_sock
(
sk
);
read
=
tcp_read_sock
(
sk
,
&
rd_desc
,
xs_tcp_data_recv
);
read
=
tcp_read_sock
(
sk
,
&
rd_desc
,
xs_tcp_data_recv
);
if
(
read
<=
0
)
{
if
(
read
<=
0
)
{
clear_bit
(
XPRT_SOCK_DATA_READY
,
&
transport
->
sock_state
);
clear_bit
(
XPRT_SOCK_DATA_READY
,
&
transport
->
sock_state
);
release_sock
(
sk
);
release_sock
(
sk
);
if
(
!
test_bit
(
XPRT_SOCK_DATA_READY
,
&
transport
->
sock_state
))
break
;
break
;
}
else
{
}
release_sock
(
sk
);
release_sock
(
sk
);
total
+=
read
;
total
+=
read
;
}
rd_desc
.
count
=
65536
;
rd_desc
.
count
=
65536
;
}
}
if
(
test_bit
(
XPRT_SOCK_DATA_READY
,
&
transport
->
sock_state
))
queue_work
(
xprtiod_workqueue
,
&
transport
->
recv_worker
);
out:
out:
mutex_unlock
(
&
transport
->
recv_mutex
);
mutex_unlock
(
&
transport
->
recv_mutex
);
trace_xs_tcp_data_ready
(
xprt
,
read
,
total
);
trace_xs_tcp_data_ready
(
xprt
,
read
,
total
);
...
...
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