diff options
author | Miklos Szeredi <mszeredi@suse.cz> | 2009-04-06 11:41:00 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-04-07 11:34:46 -0400 |
commit | 7bfac9ecf0585962fe13584f5cf526d8c8e76f17 (patch) | |
tree | 7e7c98311bb0d4c26e514b337216bbc8ade8d078 /fs | |
parent | 612392307cb09e49051225092cbbd7049bd8db93 (diff) |
splice: fix deadlock in splicing to file
There's a possible deadlock in generic_file_splice_write(),
splice_from_pipe() and ocfs2_file_splice_write():
- task A calls generic_file_splice_write()
- this calls inode_double_lock(), which locks i_mutex on both
pipe->inode and target inode
- ordering depends on inode pointers, can happen that pipe->inode is
locked first
- __splice_from_pipe() needs more data, calls pipe_wait()
- this releases lock on pipe->inode, goes to interruptible sleep
- task B calls generic_file_splice_write(), similarly to the first
- this locks pipe->inode, then tries to lock inode, but that is
already held by task A
- task A is interrupted, it tries to lock pipe->inode, but fails, as
it is already held by task B
- ABBA deadlock
Fix this by explicitly ordering locks: the outer lock must be on
target inode and the inner lock (which is later unlocked and relocked)
must be on pipe->inode. This is OK, pipe inodes and target inodes
form two nonoverlapping sets, generic_file_splice_write() and friends
are not called with a target which is a pipe.
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
Acked-by: Mark Fasheh <mfasheh@suse.com>
Acked-by: Jens Axboe <jens.axboe@oracle.com>
Cc: stable@kernel.org
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ocfs2/file.c | 8 | ||||
-rw-r--r-- | fs/splice.c | 25 |
2 files changed, 26 insertions, 7 deletions
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index a5887df2cd8a..8672b9536039 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c | |||
@@ -1926,7 +1926,7 @@ static ssize_t ocfs2_file_splice_write(struct pipe_inode_info *pipe, | |||
1926 | out->f_path.dentry->d_name.len, | 1926 | out->f_path.dentry->d_name.len, |
1927 | out->f_path.dentry->d_name.name); | 1927 | out->f_path.dentry->d_name.name); |
1928 | 1928 | ||
1929 | inode_double_lock(inode, pipe->inode); | 1929 | mutex_lock_nested(&inode->i_mutex, I_MUTEX_PARENT); |
1930 | 1930 | ||
1931 | ret = ocfs2_rw_lock(inode, 1); | 1931 | ret = ocfs2_rw_lock(inode, 1); |
1932 | if (ret < 0) { | 1932 | if (ret < 0) { |
@@ -1941,12 +1941,16 @@ static ssize_t ocfs2_file_splice_write(struct pipe_inode_info *pipe, | |||
1941 | goto out_unlock; | 1941 | goto out_unlock; |
1942 | } | 1942 | } |
1943 | 1943 | ||
1944 | if (pipe->inode) | ||
1945 | mutex_lock_nested(&pipe->inode->i_mutex, I_MUTEX_CHILD); | ||
1944 | ret = generic_file_splice_write_nolock(pipe, out, ppos, len, flags); | 1946 | ret = generic_file_splice_write_nolock(pipe, out, ppos, len, flags); |
1947 | if (pipe->inode) | ||
1948 | mutex_unlock(&pipe->inode->i_mutex); | ||
1945 | 1949 | ||
1946 | out_unlock: | 1950 | out_unlock: |
1947 | ocfs2_rw_unlock(inode, 1); | 1951 | ocfs2_rw_unlock(inode, 1); |
1948 | out: | 1952 | out: |
1949 | inode_double_unlock(inode, pipe->inode); | 1953 | mutex_unlock(&inode->i_mutex); |
1950 | 1954 | ||
1951 | mlog_exit(ret); | 1955 | mlog_exit(ret); |
1952 | return ret; | 1956 | return ret; |
diff --git a/fs/splice.c b/fs/splice.c index dd727d43e5b7..c18aa7e03e2b 100644 --- a/fs/splice.c +++ b/fs/splice.c | |||
@@ -737,10 +737,19 @@ ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out, | |||
737 | * ->write_end. Most of the time, these expect i_mutex to | 737 | * ->write_end. Most of the time, these expect i_mutex to |
738 | * be held. Since this may result in an ABBA deadlock with | 738 | * be held. Since this may result in an ABBA deadlock with |
739 | * pipe->inode, we have to order lock acquiry here. | 739 | * pipe->inode, we have to order lock acquiry here. |
740 | * | ||
741 | * Outer lock must be inode->i_mutex, as pipe_wait() will | ||
742 | * release and reacquire pipe->inode->i_mutex, AND inode must | ||
743 | * never be a pipe. | ||
740 | */ | 744 | */ |
741 | inode_double_lock(inode, pipe->inode); | 745 | WARN_ON(S_ISFIFO(inode->i_mode)); |
746 | mutex_lock_nested(&inode->i_mutex, I_MUTEX_PARENT); | ||
747 | if (pipe->inode) | ||
748 | mutex_lock_nested(&pipe->inode->i_mutex, I_MUTEX_CHILD); | ||
742 | ret = __splice_from_pipe(pipe, &sd, actor); | 749 | ret = __splice_from_pipe(pipe, &sd, actor); |
743 | inode_double_unlock(inode, pipe->inode); | 750 | if (pipe->inode) |
751 | mutex_unlock(&pipe->inode->i_mutex); | ||
752 | mutex_unlock(&inode->i_mutex); | ||
744 | 753 | ||
745 | return ret; | 754 | return ret; |
746 | } | 755 | } |
@@ -831,11 +840,17 @@ generic_file_splice_write(struct pipe_inode_info *pipe, struct file *out, | |||
831 | }; | 840 | }; |
832 | ssize_t ret; | 841 | ssize_t ret; |
833 | 842 | ||
834 | inode_double_lock(inode, pipe->inode); | 843 | WARN_ON(S_ISFIFO(inode->i_mode)); |
844 | mutex_lock_nested(&inode->i_mutex, I_MUTEX_PARENT); | ||
835 | ret = file_remove_suid(out); | 845 | ret = file_remove_suid(out); |
836 | if (likely(!ret)) | 846 | if (likely(!ret)) { |
847 | if (pipe->inode) | ||
848 | mutex_lock_nested(&pipe->inode->i_mutex, I_MUTEX_CHILD); | ||
837 | ret = __splice_from_pipe(pipe, &sd, pipe_to_file); | 849 | ret = __splice_from_pipe(pipe, &sd, pipe_to_file); |
838 | inode_double_unlock(inode, pipe->inode); | 850 | if (pipe->inode) |
851 | mutex_unlock(&pipe->inode->i_mutex); | ||
852 | } | ||
853 | mutex_unlock(&inode->i_mutex); | ||
839 | if (ret > 0) { | 854 | if (ret > 0) { |
840 | unsigned long nr_pages; | 855 | unsigned long nr_pages; |
841 | 856 | ||