[Virtio-fs] [PATCH] virtiofsd: Fix lo_destroy crash in g_hash_table_foreach_remove

Stefan Hajnoczi stefanha at redhat.com
Thu Aug 8 09:45:46 UTC 2019


On Wed, Aug 07, 2019 at 09:29:55AM -0400, Vivek Goyal wrote:
> On Wed, Aug 07, 2019 at 02:17:15PM +0100, Dr. David Alan Gilbert wrote:
> > * Vivek Goyal (vgoyal at redhat.com) wrote:
> > > On Wed, Aug 07, 2019 at 10:31:52AM +0100, Dr. David Alan Gilbert (git) wrote:
> > > > From: "Dr. David Alan Gilbert" <dgilbert at redhat.com>
> > > > 
> > > > This fixes a crash in lo_destroy since g_hash_table_foreach_remove
> > > > doesn't like the hashtable changing as it iterates, and unref_inode
> > > > will remove entries.
> > > 
> > > Hi David,
> > > 
> > > Got two questions.
> > > 
> > > - Shouldn't we take a lo->mutex to make sure parallel hash table
> > >   modifications are not happening.
> > 
> > See Stefan's big comment (which I just changed the function name in)
> > which explains that we can't take lo->mutex
> 
> That comment says that unref_inode() takes the lock and that's why
> we can't take it.
> 
> But that's easy to fix. We just have to come up with another helper which
> does not take lock and asssumes lock has already been taken.
> 
> /* This assumes lo->lock is already held */
> __unref_inode()
> {
> }

Nice idea.  It would be cleaner to drop the comments and introduce a
unref_inode_locked() function so we can follow the usual locking regime.

(Linux uses __foo() but double underscore identifiers are reserved in
the C language standard, so IMO it's better to avoid them).

> > 
> > > - Also before destroying lo, should we sever connection so that any
> > >   requests which come after lo_destroy() are not entertained.
> > 
> > No, because in some situations lo_destroy does not happen at the end;
> > e.g. it happens during a umount and we still have the connection
> > to be able to remount it.
> 
> Ok, so we don't sever the connection completely. But we don't expect to
> process further requests till a new INIT has been done, isn't it?
> 
> IOW, once lo_destroy() is received, we cleanup any pending state from
> the mount and if any requests are received from client, we error them
> out.
> 
> And start processing requests normally when a new INIT has been
> received.
> 
> Atleast that was my understanding of the design.

There is a state machine that does:

1. Drain in-flight requests when DESTROY is received.
2. Process DESTROY in a serialized fashion.
3. Forbid any requests until the next INIT.  <-- requests queued after
						 DESTROY are rejected
						 here
4. Process INIT in a serialized fashion.

Stefan
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <http://listman.redhat.com/archives/virtio-fs/attachments/20190808/116689d1/attachment.sig>


More information about the Virtio-fs mailing list