Commit 7026f192 authored by David Howells's avatar David Howells Committed by Linus Torvalds

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: default avatarNeilBrown <neilb@suse.de>
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
Tested-by: default avatar(a customer of) NeilBrown <neilb@suse.de>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 416e2abd
...@@ -50,6 +50,8 @@ void fscache_objlist_add(struct fscache_object *obj) ...@@ -50,6 +50,8 @@ void fscache_objlist_add(struct fscache_object *obj)
struct fscache_object *xobj; struct fscache_object *xobj;
struct rb_node **p = &fscache_object_list.rb_node, *parent = NULL; struct rb_node **p = &fscache_object_list.rb_node, *parent = NULL;
ASSERT(RB_EMPTY_NODE(&obj->objlist_link));
write_lock(&fscache_object_list_lock); write_lock(&fscache_object_list_lock);
while (*p) { while (*p) {
...@@ -75,6 +77,9 @@ void fscache_objlist_add(struct fscache_object *obj) ...@@ -75,6 +77,9 @@ void fscache_objlist_add(struct fscache_object *obj)
*/ */
void fscache_objlist_remove(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); write_lock(&fscache_object_list_lock);
BUG_ON(RB_EMPTY_ROOT(&fscache_object_list)); BUG_ON(RB_EMPTY_ROOT(&fscache_object_list));
......
...@@ -314,6 +314,9 @@ void fscache_object_init(struct fscache_object *object, ...@@ -314,6 +314,9 @@ void fscache_object_init(struct fscache_object *object,
object->cache = cache; object->cache = cache;
object->cookie = cookie; object->cookie = cookie;
object->parent = NULL; object->parent = NULL;
#ifdef CONFIG_FSCACHE_OBJECT_LIST
RB_CLEAR_NODE(&object->objlist_link);
#endif
object->oob_event_mask = 0; object->oob_event_mask = 0;
for (t = object->oob_table; t->events; t++) for (t = object->oob_table; t->events; t++)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment