Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2a27250e authored by Jens Axboe's avatar Jens Axboe
Browse files

[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: default avatarJens Axboe <axboe@suse.de>
parent c4f895cb
Loading
Loading
Loading
Loading
+14 −4
Original line number Diff line number Diff line
@@ -1012,7 +1012,9 @@ static int link_pipe(struct pipe_inode_info *ipipe,
		     size_t len, unsigned int flags)
{
	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
@@ -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).
	 */
	if (ipipe->inode < opipe->inode) {
		ipipe_first = 1;
		mutex_lock(&ipipe->inode->i_mutex);
		mutex_lock(&opipe->inode->i_mutex);
	} else {
@@ -1068,9 +1071,11 @@ static int link_pipe(struct pipe_inode_info *ipipe,

			/*
			 * 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)
					ret = -EAGAIN;
				break;
@@ -1104,7 +1109,12 @@ static int link_pipe(struct pipe_inode_info *ipipe,
			if (ret)
				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)
				ret = -EAGAIN;
			break;