Thread (7 messages) 7 messages, 4 authors, 2015-11-23

Re: Deadlock between bind and splice

From: Al Viro <viro@ZenIV.linux.org.uk>
Date: 2015-11-10 02:31:38

On Fri, Nov 06, 2015 at 01:58:27PM +0100, Dmitry Vyukov wrote:
Hello,

I am on revision d1e41ff11941784f469f17795a4d9425c2eb4b7a (Nov 5) and
seeing the following lockdep reports. I don't have exact reproducer
program as it is caused by several independent programs (state
accumulated in kernel across invocations); if the report is not enough
I can try to cook a reproducer.

Thanks.

[ INFO: possible circular locking dependency detected ]
4.3.0+ #30 Not tainted
-------------------------------------------------------
a.out/9972 is trying to acquire lock:
 (&pipe->mutex/1){+.+.+.}, at: [<     inline     >] pipe_lock_nested
fs/pipe.c:59
 (&pipe->mutex/1){+.+.+.}, at: [<ffffffff814d6e46>]
pipe_lock+0x56/0x70 fs/pipe.c:67

but task is already holding lock:
 (sb_writers#5){.+.+.+}, at: [<ffffffff814c77ec>]
__sb_start_write+0xec/0x130 fs/super.c:1198

which lock already depends on the new lock.

the existing dependency chain (in reverse order) is:

-> #2
[AF_UNIX bind() does sb_start_write() while holding unix_sock locked]
-> #1
[splice() to AF_UNIX socket is trying to lock unix_sock while holding
the pipe locked]
-> #0 (&pipe->mutex/1){+.+.+.}:
[splice() to regular file is locking the pipe under sb_start_write()]

Cute...  The first impression is that in #1 you need the socket to
be connected, or it won't even reach that attempt to lock unix_sock,
while bind() on the same sucker ought to bugger off before getting
around to touching the filesystem, so it looks like a false positive,
but... socketpair() yields a connected socket and AFAICS there's
nothing in unix_bind() to bugger off on such.

So the scenario ought to be:
(a while ago) A: socketpair()
B: splice() from a pipe to /mnt/regular_file
	does sb_start_write() on /mnt
C: try to freeze /mnt
	wait for B to finish with /mnt
A: bind() try to bind our socket to /mnt/new_socket_name
	lock our socket, see it not bound yet
	decide that it needs to create something in /mnt
	try to do sb_start_write() on /mnt, block (it's
	waiting for C).
D: splice() from the same pipe to our socket
	lock the pipe, see that socket is connected
	try to lock the socket, block waiting for A
B:	get around to actually feeding a chunk from
	pipe to file, try to lock the pipe.  Deadlock.

Locking the socket is interruptible, though, so killing D will
untangle that mess - it's not quite a hopeless deadlock.

Deadlock or not, should bind() actually work on connected sockets?
AFAICS, socketpair() is the only way for it to happen...
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help