[Linux-cachefs] locking/refcount problems in cachefiles.
NeilBrown
neilb at suse.de
Fri Feb 14 21:50:38 UTC 2014
On Thu, 6 Feb 2014 11:45:10 +1100 NeilBrown <neilb at suse.de> wrote:
> On Wed, 05 Feb 2014 16:09:51 +0000 David Howells <dhowells at redhat.com> wrote:
>
> > NeilBrown <neilb at suse.de> wrote:
> >
> > > fscache_alloc_object() calls fscache_attach_object() and if that fails it
> > > calls cache->ops->put_object(), which is cachefiles_put_object() which calls
> > > fscache_object_destroy(), which calls fscache_objlist_remove() which calls
> > > rb_erase() to remove the object from fscache_object_list.
> > >
> > > However the object isn't added to fscache_object_list except on the success
> > > path of fscache_attach_object() where it calls fscache_objlist_add().
> > >
> > > So if fscache_attach_object() fails, then the object wasn't added to the
> > > objlist rbtree, but is removed from it. This causes a crash.
> > >
> > > One approach would be to rb_init_node(&object->objlist_link) in
> > > fscache_object_init, and the test !RB_EMPTY_NODE(&obj->objlist_link) before
> > > calling rb_erase().
> > >
> > > Does that make sense? Is the suggested fix best or is there a better way?
> >
> > Sounds very reasonable. Something like the attached patch?
>
> Yes, that looks just right. Thanks.
> I'll let you know when the customer confirms it fixes their problem.
I now have definite confirmation that this fixes the customer's problem.
So
Tested-by: (a customer of) NeilBrown <neilb at suse.de>
Thanks,
NeilBrown
>
> NeilBrown
>
> >
> > David
> > ---
> > commit fe02fb3ec10932ce07406b1581e28326181fc9d8
> > Author: David Howells <dhowells at redhat.com>
> > Date: Wed Feb 5 15:14:40 2014 +0000
> >
> > FS-Cache: Handle removal of unadded object to the fscache_object_list rb tree
> >
> > When FS-Cache allocates an object, the following sequence of events can occur:
> >
> > -->fscache_alloc_object()
> > -->cachefiles_alloc_object() [via cache->ops->alloc_object]
> > <--[returns new object]
> > -->fscache_attach_object()
> > <--[failed]
> > -->cachefiles_put_object() [via cache->ops->put_object]
> > -->fscache_object_destroy()
> > -->fscache_objlist_remove()
> > -->rb_erase() to remove the object from fscache_object_list.
> >
> > resulting in a crash in the rbtree code.
> >
> > The problem is that the object is only added to fscache_object_list on the
> > success path of fscache_attach_object() where it calls fscache_objlist_add().
> >
> > So if fscache_attach_object() fails, the object won't have been added to the
> > objlist rbtree. We do, however, unconditionally try to remove the object from
> > the tree.
> >
> > Thanks to NeilBrown for finding this and suggesting this solution.
> >
> > Reported-by: NeilBrown <neilb at suse.de>
> > Signed-off-by: David Howells <dhowells at redhat.com>
> >
> > diff --git a/fs/fscache/object-list.c b/fs/fscache/object-list.c
> > index e1959efad64f..b5ebc2d7d80d 100644
> > --- a/fs/fscache/object-list.c
> > +++ b/fs/fscache/object-list.c
> > @@ -50,6 +50,8 @@ void fscache_objlist_add(struct fscache_object *obj)
> > struct fscache_object *xobj;
> > struct rb_node **p = &fscache_object_list.rb_node, *parent = NULL;
> >
> > + ASSERT(RB_EMPTY_NODE(&obj->objlist_link));
> > +
> > write_lock(&fscache_object_list_lock);
> >
> > while (*p) {
> > @@ -75,6 +77,9 @@ void fscache_objlist_add(struct fscache_object *obj)
> > */
> > void fscache_objlist_remove(struct fscache_object *obj)
> > {
> > + if (RB_EMPTY_NODE(&obj->objlist_link))
> > + return;
> > +
> > write_lock(&fscache_object_list_lock);
> >
> > BUG_ON(RB_EMPTY_ROOT(&fscache_object_list));
> > diff --git a/fs/fscache/object.c b/fs/fscache/object.c
> > index 53d35c504240..d3b4539f1651 100644
> > --- a/fs/fscache/object.c
> > +++ b/fs/fscache/object.c
> > @@ -314,6 +314,9 @@ void fscache_object_init(struct fscache_object *object,
> > object->cache = cache;
> > object->cookie = cookie;
> > object->parent = NULL;
> > +#ifdef CONFIG_FSCACHE_OBJECT_LIST
> > + RB_CLEAR_NODE(&object->objlist_link);
> > +#endif
> >
> > object->oob_event_mask = 0;
> > for (t = object->oob_table; t->events; t++)
>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 828 bytes
Desc: not available
URL: <http://listman.redhat.com/archives/linux-cachefs/attachments/20140215/491e7f8f/attachment.sig>
More information about the Linux-cachefs
mailing list