diff options
author | Jens Axboe <axboe@suse.de> | 2006-04-19 09:56:40 -0400 |
---|---|---|
committer | Jens Axboe <axboe@suse.de> | 2006-04-19 09:56:40 -0400 |
commit | 2a27250e6cf47ca1ea3bea0a55e4b7889c097627 (patch) | |
tree | 3dbd4747df21e72420ab6fb91fc174173903c803 /fs/splice.c | |
parent | c4f895cbe1e95aab633207fb19c650b7c984c01a (diff) |
[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>
Diffstat (limited to 'fs/splice.c')
-rw-r--r-- | fs/splice.c | 18 |
1 files changed, 14 insertions, 4 deletions
diff --git a/fs/splice.c b/fs/splice.c index 78cd264340f2..4f5e6b09fb26 100644 --- a/fs/splice.c +++ b/fs/splice.c | |||
@@ -1012,7 +1012,9 @@ static int link_pipe(struct pipe_inode_info *ipipe, | |||
1012 | size_t len, unsigned int flags) | 1012 | size_t len, unsigned int flags) |
1013 | { | 1013 | { |
1014 | struct pipe_buffer *ibuf, *obuf; | 1014 | struct pipe_buffer *ibuf, *obuf; |
1015 | int ret = 0, do_wakeup = 0, i; | 1015 | int ret, do_wakeup, i, ipipe_first; |
1016 | |||
1017 | ret = do_wakeup = ipipe_first = 0; | ||
1016 | 1018 | ||
1017 | /* | 1019 | /* |
1018 | * Potential ABBA deadlock, work around it by ordering lock | 1020 | * Potential ABBA deadlock, work around it by ordering lock |
@@ -1020,6 +1022,7 @@ static int link_pipe(struct pipe_inode_info *ipipe, | |||
1020 | * could deadlock (one doing tee from A -> B, the other from B -> A). | 1022 | * could deadlock (one doing tee from A -> B, the other from B -> A). |
1021 | */ | 1023 | */ |
1022 | if (ipipe->inode < opipe->inode) { | 1024 | if (ipipe->inode < opipe->inode) { |
1025 | ipipe_first = 1; | ||
1023 | mutex_lock(&ipipe->inode->i_mutex); | 1026 | mutex_lock(&ipipe->inode->i_mutex); |
1024 | mutex_lock(&opipe->inode->i_mutex); | 1027 | mutex_lock(&opipe->inode->i_mutex); |
1025 | } else { | 1028 | } else { |
@@ -1068,9 +1071,11 @@ static int link_pipe(struct pipe_inode_info *ipipe, | |||
1068 | 1071 | ||
1069 | /* | 1072 | /* |
1070 | * We have input available, but no output room. | 1073 | * We have input available, but no output room. |
1071 | * If we already copied data, return that. | 1074 | * If we already copied data, return that. If we |
1075 | * need to drop the opipe lock, it must be ordered | ||
1076 | * last to avoid deadlocks. | ||
1072 | */ | 1077 | */ |
1073 | if (flags & SPLICE_F_NONBLOCK) { | 1078 | if ((flags & SPLICE_F_NONBLOCK) || !ipipe_first) { |
1074 | if (!ret) | 1079 | if (!ret) |
1075 | ret = -EAGAIN; | 1080 | ret = -EAGAIN; |
1076 | break; | 1081 | break; |
@@ -1104,7 +1109,12 @@ static int link_pipe(struct pipe_inode_info *ipipe, | |||
1104 | if (ret) | 1109 | if (ret) |
1105 | break; | 1110 | break; |
1106 | } | 1111 | } |
1107 | if (flags & SPLICE_F_NONBLOCK) { | 1112 | /* |
1113 | * pipe_wait() drops the ipipe mutex. To avoid deadlocks | ||
1114 | * with another process, we can only safely do that if | ||
1115 | * the ipipe lock is ordered last. | ||
1116 | */ | ||
1117 | if ((flags & SPLICE_F_NONBLOCK) || ipipe_first) { | ||
1108 | if (!ret) | 1118 | if (!ret) |
1109 | ret = -EAGAIN; | 1119 | ret = -EAGAIN; |
1110 | break; | 1120 | break; |