mirror of
https://github.com/adulau/aha.git
synced 2024-12-28 19:56:18 +00:00
[PATCH] tee: link_pipe() must be careful when dropping one of the pipe locks
We need to ensure that we only drop a lock that is ordered last, to avoid ABBA deadlocks with competing processes. Signed-off-by: Jens Axboe <axboe@suse.de>
This commit is contained in:
parent
c4f895cbe1
commit
2a27250e6c
1 changed files with 14 additions and 4 deletions
18
fs/splice.c
18
fs/splice.c
|
@ -1012,7 +1012,9 @@ static int link_pipe(struct pipe_inode_info *ipipe,
|
||||||
size_t len, unsigned int flags)
|
size_t len, unsigned int flags)
|
||||||
{
|
{
|
||||||
struct pipe_buffer *ibuf, *obuf;
|
struct pipe_buffer *ibuf, *obuf;
|
||||||
int ret = 0, do_wakeup = 0, i;
|
int ret, do_wakeup, i, ipipe_first;
|
||||||
|
|
||||||
|
ret = do_wakeup = ipipe_first = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Potential ABBA deadlock, work around it by ordering lock
|
* Potential ABBA deadlock, work around it by ordering lock
|
||||||
|
@ -1020,6 +1022,7 @@ static int link_pipe(struct pipe_inode_info *ipipe,
|
||||||
* could deadlock (one doing tee from A -> B, the other from B -> A).
|
* could deadlock (one doing tee from A -> B, the other from B -> A).
|
||||||
*/
|
*/
|
||||||
if (ipipe->inode < opipe->inode) {
|
if (ipipe->inode < opipe->inode) {
|
||||||
|
ipipe_first = 1;
|
||||||
mutex_lock(&ipipe->inode->i_mutex);
|
mutex_lock(&ipipe->inode->i_mutex);
|
||||||
mutex_lock(&opipe->inode->i_mutex);
|
mutex_lock(&opipe->inode->i_mutex);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1068,9 +1071,11 @@ static int link_pipe(struct pipe_inode_info *ipipe,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We have input available, but no output room.
|
* We have input available, but no output room.
|
||||||
* If we already copied data, return that.
|
* If we already copied data, return that. If we
|
||||||
|
* need to drop the opipe lock, it must be ordered
|
||||||
|
* last to avoid deadlocks.
|
||||||
*/
|
*/
|
||||||
if (flags & SPLICE_F_NONBLOCK) {
|
if ((flags & SPLICE_F_NONBLOCK) || !ipipe_first) {
|
||||||
if (!ret)
|
if (!ret)
|
||||||
ret = -EAGAIN;
|
ret = -EAGAIN;
|
||||||
break;
|
break;
|
||||||
|
@ -1104,7 +1109,12 @@ static int link_pipe(struct pipe_inode_info *ipipe,
|
||||||
if (ret)
|
if (ret)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (flags & SPLICE_F_NONBLOCK) {
|
/*
|
||||||
|
* pipe_wait() drops the ipipe mutex. To avoid deadlocks
|
||||||
|
* with another process, we can only safely do that if
|
||||||
|
* the ipipe lock is ordered last.
|
||||||
|
*/
|
||||||
|
if ((flags & SPLICE_F_NONBLOCK) || ipipe_first) {
|
||||||
if (!ret)
|
if (!ret)
|
||||||
ret = -EAGAIN;
|
ret = -EAGAIN;
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in a new issue