flex_array: add flex_array_shrink function
David Rientjes [Tue, 22 Sep 2009 00:04:31 +0000 (17:04 -0700)]
Add a new function to the flex_array API:

int flex_array_shrink(struct flex_array *fa)

This function will free all unused second-level pages.  Since elements are
now poisoned if they are not allocated with __GFP_ZERO, it's possible to
identify parts that consist solely of unused elements.

flex_array_shrink() returns the number of pages freed.

Signed-off-by: David Rientjes <rientjes@google.com>
Cc: Dave Hansen <dave@linux.vnet.ibm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

include/linux/flex_array.h
lib/flex_array.c

index 3887b21..f12401e 100644 (file)
@@ -46,5 +46,6 @@ int flex_array_put(struct flex_array *fa, unsigned int element_nr, void *src,
                gfp_t flags);
 int flex_array_clear(struct flex_array *fa, unsigned int element_nr);
 void *flex_array_get(struct flex_array *fa, unsigned int element_nr);
+int flex_array_shrink(struct flex_array *fa);
 
 #endif /* _FLEX_ARRAY_H */
index e22d0e9..1b03bb5 100644 (file)
@@ -291,3 +291,43 @@ void *flex_array_get(struct flex_array *fa, unsigned int element_nr)
        }
        return &part->elements[index_inside_part(fa, element_nr)];
 }
+
+static int part_is_free(struct flex_array_part *part)
+{
+       int i;
+
+       for (i = 0; i < sizeof(struct flex_array_part); i++)
+               if (part->elements[i] != FLEX_ARRAY_FREE)
+                       return 0;
+       return 1;
+}
+
+/**
+ * flex_array_shrink - free unused second-level pages
+ *
+ * Frees all second-level pages that consist solely of unused
+ * elements.  Returns the number of pages freed.
+ *
+ * Locking must be provided by the caller.
+ */
+int flex_array_shrink(struct flex_array *fa)
+{
+       struct flex_array_part *part;
+       int max_part = nr_base_part_ptrs();
+       int part_nr;
+       int ret = 0;
+
+       if (elements_fit_in_base(fa))
+               return ret;
+       for (part_nr = 0; part_nr < max_part; part_nr++) {
+               part = fa->parts[part_nr];
+               if (!part)
+                       continue;
+               if (part_is_free(part)) {
+                       fa->parts[part_nr] = NULL;
+                       kfree(part);
+                       ret++;
+               }
+       }
+       return ret;
+}