• Tejun Heo's avatar
    idr: implement idr_preload[_end]() and idr_alloc() · d5c7409f
    Tejun Heo authored
    The current idr interface is very cumbersome.
    
    * For all allocations, two function calls - idr_pre_get() and
      idr_get_new*() - should be made.
    
    * idr_pre_get() doesn't guarantee that the following idr_get_new*()
      will not fail from memory shortage.  If idr_get_new*() returns
      -EAGAIN, the caller is expected to retry pre_get and allocation.
    
    * idr_get_new*() can't enforce upper limit.  Upper limit can only be
      enforced by allocating and then freeing if above limit.
    
    * idr_layer buffer is unnecessarily per-idr.  Each idr ends up keeping
      around MAX_IDR_FREE idr_layers.  The memory consumed per idr is
      under two pages but it makes it difficult to make idr_layer larger.
    
    This patch implements the following new set of allocation functions.
    
    * idr_preload[_end]() - Similar to radix preload but doesn't fail.
      The first idr_alloc() inside preload section can be treated as if it
      were called with @gfp_mask used for idr_preload().
    
    * idr_alloc() - Allocate an ID w/ lower and upper limits.  Takes
      @gfp_flags and can be used w/o preloading.  When used inside
      preloaded section, the allocation mask of preloading can be assumed.
    
    If idr_alloc() can be called from a context which allows sufficiently
    relaxed @gfp_mask, it can be used by itself.  If, for example,
    idr_alloc() is called inside spinlock protected region, preloading can
    be used like the following.
    
    	idr_preload(GFP_KERNEL);
    	spin_lock(lock);
    
    	id = idr_alloc(idr, ptr, start, end, GFP_NOWAIT);
    
    	spin_unlock(lock);
    	idr_preload_end();
    	if (id < 0)
    		error;
    
    which is much simpler and less error-prone than idr_pre_get and
    idr_get_new*() loop.
    
    The new interface uses per-pcu idr_layer buffer and thus the number of
    idr's in the system doesn't affect the amount of memory used for
    preloading.
    
    idr_layer_alloc() is introduced to handle idr_layer allocations for
    both old and new ID allocation paths.  This is a bit hairy now but the
    new interface is expected to replace the old and the internal
    implementation eventually will become simpler.
    Signed-off-by: default avatarTejun Heo <tj@kernel.org>
    Cc: Rusty Russell <rusty@rustcorp.com.au>
    Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
    Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
    d5c7409f
idr.c 27.8 KB