]> git.openfabrics.org - ~shefty/libibverbs.git/commitdiff
Undo changes in memory range tree when madvise() fails
authorAlex Vainman <alexonlists@gmail.com>
Sun, 28 Mar 2010 17:06:16 +0000 (20:06 +0300)
committerRoland Dreier <rolandd@cisco.com>
Wed, 21 Apr 2010 22:11:38 +0000 (15:11 -0700)
ibv_madvise_range() doesn't cleanup if madvise() fails.  This patch
rolls back changes already made in the memory range tracking tree by
madvise() calls before the one that failed.  We can do this fairly
simply by simply restarting ibv_madvise_range() from the original
start to the current location with the opposite advice/inc values.

Signed-off-by: Alex Vainman <alexv@voltaire.com>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
src/memory.c

index 03f49c89b0fa24a1e4f1e243529dd15fd936ce8e..ce58ae8c6f435434d19e8f9d6c3ab4061f948bd1 100644 (file)
@@ -527,18 +527,19 @@ static int ibv_madvise_range(void *base, size_t size, int advice)
        uintptr_t start, end;
        struct ibv_mem_node *node, *tmp;
        int inc;
+       int rolling_back = 0;
        int ret = 0;
 
        if (!size)
                return 0;
 
-       inc = advice == MADV_DONTFORK ? 1 : -1;
-
        start = (uintptr_t) base & ~(page_size - 1);
        end   = ((uintptr_t) (base + size + page_size - 1) &
                 ~(page_size - 1)) - 1;
 
        pthread_mutex_lock(&mm_mutex);
+again:
+       inc = advice == MADV_DONTFORK ? 1 : -1;
 
        node = get_start_node(start, end, inc);
        if (!node) {
@@ -576,7 +577,19 @@ static int ibv_madvise_range(void *base, size_t size, int advice)
                                              advice);
                        if (ret) {
                                node = undo_node(node, start, inc);
-                               goto out;
+
+                               if (rolling_back || !node)
+                                       goto out;
+
+                               /* madvise failed, roll back previous changes */
+                               rolling_back = 1;
+                               advice = advice == MADV_DONTFORK ?
+                                       MADV_DOFORK : MADV_DONTFORK;
+                               tmp = __mm_prev(node);
+                               if (!tmp || start > tmp->end)
+                                       goto out;
+                               end = tmp->end;
+                               goto again;
                        }
                }
 
@@ -591,6 +604,9 @@ static int ibv_madvise_range(void *base, size_t size, int advice)
        }
 
 out:
+       if (rolling_back)
+               ret = -1;
+
        pthread_mutex_unlock(&mm_mutex);
 
        return ret;