From: David Howells <dhowells@redhat.com>
Subject: FS-Cache: Handle removal of unadded object to the fscache_object_list rb tree
Patch-mainline: submitted for 3.15
References: bnc#855885

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@suse.de>
Signed-off-by: David Howells <dhowells@redhat.com>
Acked-by: Neil Brown <neilb@suse.de>

---
 fs/fscache/object-list.c      |    3 +++
 include/linux/fscache-cache.h |    1 +
 2 files changed, 4 insertions(+)

--- linux-3.0-SLE11-SP2.orig/fs/fscache/object-list.c
+++ linux-3.0-SLE11-SP2/fs/fscache/object-list.c
@@ -78,6 +78,9 @@ void fscache_objlist_add(struct fscache_
  */
 void fscache_object_destroy(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));
--- linux-3.0-SLE11-SP2.orig/include/linux/fscache-cache.h
+++ linux-3.0-SLE11-SP2/include/linux/fscache-cache.h
@@ -419,6 +419,9 @@ void fscache_object_init(struct fscache_
 	object->cache = cache;
 	object->cookie = cookie;
 	object->parent = NULL;
+#ifdef CONFIG_FSCACHE_OBJECT_LIST
+	rb_init_node(&object->objlist_link);
+#endif
 }
 
 extern void fscache_object_lookup_negative(struct fscache_object *object);
