On Thu, Feb 07, 2019 at 04:30:47PM +0000, Al Viro wrote: > Well, yes - once you receive it, you obviously have no references > sitting in SCM_RIGHTS anymore. > > Get rid of recv_fd() there (along with fork(), while we are at it - what's > it for?) and just do send_fd + these 3 close (or just exit, for that matter). If you pardon a bad ASCII graphics, ring_fd sv[0] sv[1] (descriptors) | | | V V V [io_uring] [socket1] [socket2] (struct file) ^ | ^ | ^ | | | | | | | | \_______________/__|________________/ | (after registering) | | | | V V | [unix_sock1]<---->[unix_sock2] (struct unix_sock) | | | V \----------------------------------[SCM_RIGHTS] (queue contents) References from io_uring to other two struct file are added when you register these suckers. Reference from SCM_RIGHTS appears when you do send_fd(). Now, each file has two references to it. And if you close all 3 descriptors (either explicitly, or by exiting) you will be left with this graph: [io_uring]------------\-------------------\ ^ | | | V V | [socket1] [socket2] | | | | V V | [unix_sock1]<---->[unix_sock2] | | | V \----------------------------------[SCM_RIGHTS] All struct file still have references, so they are all still alive, ->release() isn't called on any of them. And the entire thing is obviously unreachable from the rest of data structures. Of course recvmsg() would've removed the loop. The point is, with that situation you *can't* get it called - you'd need to reach socket2 to do that and you can't do that anymore.