On Tue, Feb 16, 2021 at 05:31:33PM +0300, Denis Kirjanov wrote:

> We had a change like that:
> Author: WANG Cong <xiyou.wangc...@gmail.com>
> Date:   Mon Jan 23 11:17:35 2017 -0800
> 
>     af_unix: move unix_mknod() out of bindlock
> 
>     Dmitry reported a deadlock scenario:
> 
>     unix_bind() path:
>     u->bindlock ==> sb_writer
> 
>     do_splice() path:
>     sb_writer ==> pipe->mutex ==> u->bindlock
> 
>     In the unix_bind() code path, unix_mknod() does not have to
>     be done with u->bindlock held, since it is a pure fs operation,
>     so we can just move unix_mknod() out.

*cringe*

I remember now...  Process set:

P1: bind() of AF_UNIX socket to /mnt/sock
P2: splice() from pipe to /mnt/foo
P3: freeze /mnt
P4: splice() from pipe to AF_UNIX socket

P1      grabs ->bindlock
P2      sb_start_write() for what's on /mnt
P2      grabs rwsem shared
P3      blocks in sb_wait_write() trying to grab the same rwsem exclusive
P1      sb_start_write() blocks trying to grab the same rwsem shared
P4      calls ->splice_write(), aka generic_splice_sendpage()
P4      grabs pipe->mutex
P4      calls ->sendpage(), aka sock_no_sendpage()
P4      calls ->sendmsg(), aka unix_dgram_sendmsg()
P4      calls unix_autobind()
P4      blocks trying to grab ->bindlock
P2      ->splice_write(), aka iter_file_splice_write()
P2      blocks trying to grab  pipe->mutex
        DEADLOCK

Sigh...  OK, so we want something like
        user_path_create()
        vfs_mknod()
        created = true
        grab bindlock
        ....
        drop bindlock
        if failed && created
                vfs_unlink()
        done_path_create()      
in unix_bind()...  That would push ->bindlock all way down in the hierarchy,
so that should be deadlock-free, but it looks like that'll be fucking ugly ;-/

Let me try and play with that a bit, maybe it can be massaged to something
relatively sane...

Reply via email to