pool: handle ENOMEM case properly in kdbus_pool_slice_alloc
authorSergei Zviagintsev <sergei@s15v.net>
Tue, 16 Dec 2014 10:38:47 +0000 (13:38 +0300)
committerDavid Herrmann <dh.herrmann@gmail.com>
Wed, 17 Dec 2014 11:10:15 +0000 (12:10 +0100)
If we got larger slice than requested and could not allocate memory for
new slice to perform split operation, then free and busy trees will stay
in inconsistent state, as we already moved found slice between them.

Fix such behavior by doing split-off firstly and moving slice between
trees after. This also increases readability, as previously we checked
two times for the same condition (!n is equal to s->size > slice_size).

Signed-off-by: Sergei Zviagintsev <sergei@s15v.net>
Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
pool.c

diff --git a/pool.c b/pool.c
index 0b51199bb90040848556dc1da5a5021ecf262dbf..54b2af37da36b9e372eac2b21326733363e16a77 100644 (file)
--- a/pool.c
+++ b/pool.c
@@ -235,17 +235,11 @@ struct kdbus_pool_slice *kdbus_pool_slice_alloc(struct kdbus_pool *pool,
        }
 
        /* no exact match, use the closest one */
-       if (!n)
-               s = rb_entry(found, struct kdbus_pool_slice, rb_node);
-
-       /* move slice from free to the busy tree */
-       rb_erase(found, &pool->slices_free);
-       kdbus_pool_add_busy_slice(pool, s);
-
-       /* we got a slice larger than what we asked for? */
-       if (s->size > slice_size) {
+       if (!n) {
                struct kdbus_pool_slice *s_new;
 
+               s = rb_entry(found, struct kdbus_pool_slice, rb_node);
+
                /* split-off the remainder of the size to its own slice */
                s_new = kdbus_pool_slice_new(pool, s->off + slice_size,
                                             s->size - slice_size);
@@ -261,6 +255,10 @@ struct kdbus_pool_slice *kdbus_pool_slice_alloc(struct kdbus_pool *pool,
                s->size = slice_size;
        }
 
+       /* move slice from free to the busy tree */
+       rb_erase(found, &pool->slices_free);
+       kdbus_pool_add_busy_slice(pool, s);
+
        WARN_ON(s->ref_kernel || s->ref_user);
 
        s->ref_kernel = true;