27 May, 2011

1 commit

  • On most architectures division is an expensive operation and accessing an
    element currently requires four of them. This performance penalty
    effectively precludes flex arrays from being used on any kind of fast
    path. However, two of these divisions can be handled at creation time and
    the others can be replaced by a reciprocal divide, completely avoiding
    real divisions on access.

    [eparis@redhat.com: rebase on top of changes to support 0 len elements]
    [eparis@redhat.com: initialize part_nr when array fits entirely in base]
    Signed-off-by: Jesse Gross
    Signed-off-by: Eric Paris
    Cc: Dave Hansen
    Cc: David Rientjes
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Jesse Gross
     

29 Apr, 2011

3 commits

  • flex_arrays are supposed to be a replacement for:
    kmalloc(num_elements * sizeof(element))

    If kmalloc is given 0 num_elements or a 0 size element it will happily return
    ZERO_SIZE_PTR. Which looks like a valid allocation, but which will explode if
    something actually try to use it. The current flex_array code will return an
    equivalent result if num_elements is 0, but will fail to work if
    sizeof(element) is 0. This patch allows allocation to work even for 0 size
    elements. It will cause flex_arrays to explode though if they are used.
    Imitating the kmalloc behavior.

    Based-on-patch-by: Steffen Klassert
    Signed-off-by: Eric Paris
    Acked-by: Dave Hansen

    Eric Paris
     
  • Just like kmalloc will allow one to allocate a 0 length segment of memory
    flex arrays should do the same thing. It should bomb if you try to use
    something, but it should at least allow the allocation.

    This is needed because when SELinux switched to using flex_arrays in 2.6.38
    the inability to allocate a 0 length array resulted in SELinux policy load
    returning -ENOSPC when previously it worked.

    Based-on-patch-by: Steffen Klassert
    Signed-off-by: Eric Paris
    Tested-by: Chris Richards
    Cc: stable@kernel.org [2.6.38+]

    Eric Paris
     
  • Change flex_array_prealloc to take the number of elements for which space
    should be allocated instead of the last (inclusive) element. Users
    and documentation are updated accordingly. flex_arrays got introduced before
    they had users. When folks started using it, they ended up needing a
    different API than was coded up originally. This swaps over to the API that
    folks apparently need.

    Based-on-patch-by: Steffen Klassert
    Signed-off-by: Eric Paris
    Tested-by: Chris Richards
    Acked-by: Dave Hansen
    Cc: stable@kernel.org [2.6.38+]

    Eric Paris
     

14 Jan, 2011

1 commit

  • Alex said:

    I want to use flex_array to store a sparse array of ATM cell
    re-assembly buffers for my ATM over Ethernet driver. Using the per-vcc
    user_back structure causes problems when stacked with things like
    br2684.

    Add EXPORT_SYMBOL() for all publically accessible flex array functions
    and move to obj-y so that modules may use this library.

    Signed-off-by: David Rientjes
    Cc: Dave Hansen
    Cc: Paul Mundt
    Reported-by: Alex Bennee
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    David Rientjes
     

10 Aug, 2010

1 commit

  • Getting and putting arrays of pointers with flex arrays is a PITA. You
    have to remember to pass &ptr to the _put and you have to do weird and
    wacky casting to get the ptr back from the _get. Add two functions
    flex_array_get_ptr() and flex_array_put_ptr() to handle all of the magic.

    [akpm@linux-foundation.org: simplification suggested by Joe]
    Signed-off-by: Eric Paris
    Cc: David Rientjes
    Cc: Dave Hansen
    Cc: Joe Perches
    Cc: James Morris
    Cc: Joe Perches
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Eric Paris
     

25 Apr, 2010

1 commit


22 Sep, 2009

5 commits

  • Add kerneldoc annotations for function formals of type struct flex_array
    and gfp_t which are currently lacking.

    Signed-off-by: David Rientjes
    Cc: Dave Hansen
    Cc: Randy Dunlap
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    David Rientjes
     
  • FLEX_ARRAY_INIT(element_size, total_nr_elements) cannot determine if
    either parameter is valid, so flex arrays which are statically allocated
    with this interface can easily become corrupted or reference beyond its
    allocated memory.

    This removes FLEX_ARRAY_INIT() as a struct flex_array initializer since no
    initializer may perform the required checking. Instead, the array is now
    defined with a new interface:

    DEFINE_FLEX_ARRAY(name, element_size, total_nr_elements)

    This may be prefixed with `static' for file scope.

    This interface includes compile-time checking of the parameters to ensure
    they are valid. Since the validity of both element_size and
    total_nr_elements depend on FLEX_ARRAY_BASE_SIZE and FLEX_ARRAY_PART_SIZE,
    the kernel build will fail if either of these predefined values changes
    such that the array parameters are no longer valid.

    Since BUILD_BUG_ON() requires compile time constants, several of the
    static inline functions that were once local to lib/flex_array.c had to be
    moved to include/linux/flex_array.h.

    Signed-off-by: David Rientjes
    Acked-by: Dave Hansen
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    David Rientjes
     
  • 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
    Cc: Dave Hansen
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    David Rientjes
     
  • Newly initialized flex_array's and/or flex_array_part's are now poisoned
    with a new poison value, FLEX_ARRAY_FREE. It's value is similar to
    POISON_FREE used in the various slab allocators, but is different to
    distinguish between flex array's poisoned kmem and slab allocator poisoned
    kmem.

    This will allow us to identify flex_array_part's that only contain free
    elements (and free them with an addition to the flex_array API). This
    could also be extended in the future to identify `get' uses on elements
    that have not been `put'.

    If __GFP_ZERO is passed for a part's gfp mask, the poisoning is avoided.
    These elements are considered to be in-use since they have been
    initialized.

    Signed-off-by: David Rientjes
    Cc: Dave Hansen
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    David Rientjes
     
  • Add a new function to the flex_array API:

    int flex_array_clear(struct flex_array *fa,
    unsigned int element_nr)

    This function will zero the element at element_nr in the flex_array.

    Although this is equivalent to using flex_array_put() and passing a
    pointer to zero'd memory, flex_array_clear() does not require such a
    pointer to memory that would most likely need to be allocated on the
    caller's stack which could be significantly large depending on
    element_size.

    Signed-off-by: David Rientjes
    Cc: Dave Hansen
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    David Rientjes
     

27 Aug, 2009

3 commits

  • It's problematic to allow signed element_nr's or total's to be passed as
    part of the flex array API.

    flex_array_alloc() allows total_nr_elements to be set to a negative
    quantity, which is obviously erroneous.

    flex_array_get() and flex_array_put() allows negative array indices in
    dereferencing an array part, which could address memory mapped before
    struct flex_array.

    The fix is to convert all existing element_nr formals to be qualified as
    unsigned. Existing checks to compare it to total_nr_elements or the max
    array size based on element_size need not be changed.

    Signed-off-by: David Rientjes
    Cc: Dave Hansen
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    David Rientjes
     
  • flex_array_free_parts() does not take `src' or `element_nr' formals, so
    remove their respective comments.

    Signed-off-by: David Rientjes
    Acked-by: Dave Hansen
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    David Rientjes
     
  • If all array elements fit into the base structure and data is copied using
    flex_array_put() starting at a non-zero index, flex_array_get() will fail
    to return the data.

    This fixes the bug by only checking for NULL parts when all elements do
    not fit in the base structure when flex_array_get() is used. Otherwise,
    fa_element_to_part_nr() will always be 0 since there are no parts
    structures needed and such element may never have been put. Thus, it will
    remain NULL due to the kzalloc() of the base.

    Additionally, flex_array_put() now only checks for a NULL part when all
    elements do not fit in the base structure. This is otherwise unnecessary
    since the base structure is guaranteed to exist (or we would have already
    hit a NULL pointer).

    Signed-off-by: David Rientjes
    Acked-by: Dave Hansen
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    David Rientjes
     

05 Aug, 2009

1 commit


30 Jul, 2009

1 commit

  • Once a structure goes over PAGE_SIZE*2, we see occasional allocation
    failures. Some people have chosen to switch over to things like vmalloc()
    that will let them keep array-like access to such a large structures.
    But, vmalloc() has plenty of downsides.

    Here's an alternative. I think it's what Andrew was suggesting here:

    http://lkml.org/lkml/2009/7/2/518

    I call it a flexible array. It does all of its work in PAGE_SIZE bits, so
    never does an order>0 allocation. The base level has
    PAGE_SIZE-2*sizeof(int) bytes of storage for pointers to the second level.
    So, with a 32-bit arch, you get about 4MB (4183112 bytes) of total
    storage when the objects pack nicely into a page. It is half that on
    64-bit because the pointers are twice the size. There's a table detailing
    this in the code.

    There are kerneldocs for the functions, but here's an
    overview:

    flex_array_alloc() - dynamically allocate a base structure
    flex_array_free() - free the array and all of the
    second-level pages
    flex_array_free_parts() - free the second-level pages, but
    not the base (for static bases)
    flex_array_put() - copy into the array at the given index
    flex_array_get() - copy out of the array at the given index
    flex_array_prealloc() - preallocate the second-level pages
    between the given indexes to
    guarantee no allocs will occur at
    put() time.

    We could also potentially just pass the "element_size" into each of the
    API functions instead of storing it internally. That would get us one
    more base pointer on 32-bit.

    I've been testing this by running it in userspace. The header and patch
    that I've been using are here, as well as the little script I'm using to
    generate the size table which goes in the kerneldocs.

    http://sr71.net/~dave/linux/flexarray/

    [akpm@linux-foundation.org: coding-style fixes]
    Signed-off-by: Dave Hansen
    Reviewed-by: KAMEZAWA Hiroyuki
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Dave Hansen