summaryrefslogtreecommitdiffstats
path: root/kernel/softirq.c
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@suse.cz>2009-04-06 17:41:00 +0200
committerLinus Torvalds <torvalds@linux-foundation.org>2009-04-07 17:34:46 +0200
commit7bfac9ecf0585962fe13584f5cf526d8c8e76f17 (patch)
tree7e7c98311bb0d4c26e514b337216bbc8ade8d078 /kernel/softirq.c
parentnilfs2: support nanosecond timestamp (diff)
downloadlinux-7bfac9ecf0585962fe13584f5cf526d8c8e76f17.tar.xz
linux-7bfac9ecf0585962fe13584f5cf526d8c8e76f17.zip
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 'kernel/softirq.c')
0 files changed, 0 insertions, 0 deletions