* [PATCH 0/4] idr: idr cleanups
@ 2014-04-22 10:16 Lai Jiangshan
2014-04-22 10:16 ` [PATCH 1/4] idr: proper invalid argument handling Lai Jiangshan
` (3 more replies)
0 siblings, 4 replies; 12+ messages in thread
From: Lai Jiangshan @ 2014-04-22 10:16 UTC (permalink / raw)
To: linux-kernel; +Cc: Andrew Morton, Tejun Heo, Lai Jiangshan
patch1 is the new version of previous pathset.(it is dropped by previous
patchset, this one is new)
patch2/3 save a lot memory
Lai Jiangshan (4):
idr: proper invalid argument handling
idr: reduce the number of MAX_IDR_FREE
ida: in-place ida allocation
idr: reorder the fields
include/linux/idr.h | 28 ++++--------
lib/idr.c | 119 ++++++++++++++++++---------------------------------
2 files changed, 51 insertions(+), 96 deletions(-)
--
1.7.4.4
^ permalink raw reply [flat|nested] 12+ messages in thread* [PATCH 1/4] idr: proper invalid argument handling 2014-04-22 10:16 [PATCH 0/4] idr: idr cleanups Lai Jiangshan @ 2014-04-22 10:16 ` Lai Jiangshan 2014-04-22 19:16 ` Andrew Morton 2014-04-22 19:54 ` Tejun Heo 2014-04-22 10:16 ` [PATCH 2/4] idr: reduce the number of MAX_IDR_FREE Lai Jiangshan ` (2 subsequent siblings) 3 siblings, 2 replies; 12+ messages in thread From: Lai Jiangshan @ 2014-04-22 10:16 UTC (permalink / raw) To: linux-kernel Cc: Andrew Morton, Tejun Heo, Lai Jiangshan, Jean Delvare, Monam Agarwal, Jeff Layton, Andreas Gruenbacher, Stephen Hemminger When the arguments passed by the caller are invalid, WARN_ON_ONCE() is proper than BUG_ON() which may crash the kernel. ida_remove()/idr_remove() add checks for "id < 0". BUG_ON() in ida_simple_remove() is simply removed, due to ida_remove() already checks for "id < 0". In idr_alloc(), it still returns -ENOSPC when "start == end", but it returns -EINVAL when "max < start" while old code returns -ENOSPC. -EINVAL is proper here, the caller must passed wrong arguments. ida_simple_get()'s argument-checks are changed as the same as idr_alloc(). Signed-off-by: Lai Jiangshan <laijs@cn.fujitsu.com> --- lib/idr.c | 25 +++++++++++++------------ 1 files changed, 13 insertions(+), 12 deletions(-) diff --git a/lib/idr.c b/lib/idr.c index 96bb252..87c98fc 100644 --- a/lib/idr.c +++ b/lib/idr.c @@ -457,8 +457,10 @@ int idr_alloc(struct idr *idr, void *ptr, int start, int end, gfp_t gfp_mask) /* sanity checks */ if (WARN_ON_ONCE(start < 0)) return -EINVAL; - if (unlikely(max < start)) + if (unlikely(end > 0 && start == end)) return -ENOSPC; + if (WARN_ON_ONCE(max < start)) + return -EINVAL; /* allocate id */ id = idr_get_empty_slot(idr, start, pa, gfp_mask, NULL); @@ -551,10 +553,7 @@ void idr_remove(struct idr *idp, int id) struct idr_layer *p; struct idr_layer *to_free; - if (id < 0) - return; - - if (id > idr_max(idp->layers)) { + if (id < 0 || id > idr_max(idp->layers)) { idr_remove_warning(id); return; } @@ -1012,7 +1011,7 @@ void ida_remove(struct ida *ida, int id) int n; struct ida_bitmap *bitmap; - if (idr_id > idr_max(ida->idr.layers)) + if (id < 0 || idr_id > idr_max(ida->idr.layers)) goto err; /* clear full bits while looking up the leaf idr_layer */ @@ -1078,14 +1077,17 @@ int ida_simple_get(struct ida *ida, unsigned int start, unsigned int end, unsigned int max; unsigned long flags; - BUG_ON((int)start < 0); - BUG_ON((int)end < 0); + if (WARN_ON_ONCE((int)start < 0)) + return -EINVAL; - if (end == 0) - max = 0x80000000; + if ((int)end <= 0) + max = INT_MAX; else { - BUG_ON(end < start); max = end - 1; + if (unlikely(start == end)) + return -ENOSPC; + if (WARN_ON_ONCE(max < start)) + return -EINVAL; } again: @@ -1120,7 +1122,6 @@ void ida_simple_remove(struct ida *ida, unsigned int id) { unsigned long flags; - BUG_ON((int)id < 0); spin_lock_irqsave(&simple_ida_lock, flags); ida_remove(ida, id); spin_unlock_irqrestore(&simple_ida_lock, flags); -- 1.7.4.4 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH 1/4] idr: proper invalid argument handling 2014-04-22 10:16 ` [PATCH 1/4] idr: proper invalid argument handling Lai Jiangshan @ 2014-04-22 19:16 ` Andrew Morton 2014-04-22 19:46 ` Andrew Morton 2014-04-22 19:54 ` Tejun Heo 1 sibling, 1 reply; 12+ messages in thread From: Andrew Morton @ 2014-04-22 19:16 UTC (permalink / raw) To: Lai Jiangshan Cc: linux-kernel, Tejun Heo, Jean Delvare, Monam Agarwal, Jeff Layton, Andreas Gruenbacher, Stephen Hemminger On Tue, 22 Apr 2014 18:16:18 +0800 Lai Jiangshan <laijs@cn.fujitsu.com> wrote: > When the arguments passed by the caller are invalid, WARN_ON_ONCE() > is proper than BUG_ON() which may crash the kernel. > > ida_remove()/idr_remove() add checks for "id < 0". > BUG_ON() in ida_simple_remove() is simply removed, due to > ida_remove() already checks for "id < 0". > > In idr_alloc(), it still returns -ENOSPC when "start == end", > but it returns -EINVAL when "max < start" while old code returns > -ENOSPC. -EINVAL is proper here, the caller must passed wrong > arguments. > > ida_simple_get()'s argument-checks are changed as the same as > idr_alloc(). This patch doesn't apply. > @@ -551,10 +553,7 @@ void idr_remove(struct idr *idp, int id) > struct idr_layer *p; > struct idr_layer *to_free; > > - if (id < 0) > - return; > - > - if (id > idr_max(idp->layers)) { > + if (id < 0 || id > idr_max(idp->layers)) { > idr_remove_warning(id); > return; > } 3.15-rc2's idr_remove() has a call to sub_remove() in there, but whatever-kernel-you're-using does not. ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 1/4] idr: proper invalid argument handling 2014-04-22 19:16 ` Andrew Morton @ 2014-04-22 19:46 ` Andrew Morton 0 siblings, 0 replies; 12+ messages in thread From: Andrew Morton @ 2014-04-22 19:46 UTC (permalink / raw) To: Lai Jiangshan, linux-kernel, Tejun Heo, Jean Delvare, Monam Agarwal, Jeff Layton, Andreas Gruenbacher, Stephen Hemminger On Tue, 22 Apr 2014 12:16:56 -0700 Andrew Morton <akpm@linux-foundation.org> wrote: > On Tue, 22 Apr 2014 18:16:18 +0800 Lai Jiangshan <laijs@cn.fujitsu.com> wrote: > > > When the arguments passed by the caller are invalid, WARN_ON_ONCE() > > is proper than BUG_ON() which may crash the kernel. > > > > ida_remove()/idr_remove() add checks for "id < 0". > > BUG_ON() in ida_simple_remove() is simply removed, due to > > ida_remove() already checks for "id < 0". > > > > In idr_alloc(), it still returns -ENOSPC when "start == end", > > but it returns -EINVAL when "max < start" while old code returns > > -ENOSPC. -EINVAL is proper here, the caller must passed wrong > > arguments. > > > > ida_simple_get()'s argument-checks are changed as the same as > > idr_alloc(). > > This patch doesn't apply. > > > @@ -551,10 +553,7 @@ void idr_remove(struct idr *idp, int id) > > struct idr_layer *p; > > struct idr_layer *to_free; > > > > - if (id < 0) > > - return; > > - > > - if (id > idr_max(idp->layers)) { > > + if (id < 0 || id > idr_max(idp->layers)) { > > idr_remove_warning(id); > > return; > > } > > 3.15-rc2's idr_remove() has a call to sub_remove() in there, but > whatever-kernel-you're-using does not. Ah, it's based on your other idr patchset. That's what I get for working in reverse time order. ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 1/4] idr: proper invalid argument handling 2014-04-22 10:16 ` [PATCH 1/4] idr: proper invalid argument handling Lai Jiangshan 2014-04-22 19:16 ` Andrew Morton @ 2014-04-22 19:54 ` Tejun Heo 1 sibling, 0 replies; 12+ messages in thread From: Tejun Heo @ 2014-04-22 19:54 UTC (permalink / raw) To: Lai Jiangshan Cc: linux-kernel, Andrew Morton, Jean Delvare, Monam Agarwal, Jeff Layton, Andreas Gruenbacher, Stephen Hemminger Hello, On Tue, Apr 22, 2014 at 06:16:18PM +0800, Lai Jiangshan wrote: > @@ -457,8 +457,10 @@ int idr_alloc(struct idr *idr, void *ptr, int start, int end, gfp_t gfp_mask) > /* sanity checks */ > if (WARN_ON_ONCE(start < 0)) > return -EINVAL; > - if (unlikely(max < start)) > + if (unlikely(end > 0 && start == end)) > return -ENOSPC; > + if (WARN_ON_ONCE(max < start)) > + return -EINVAL; Why is this change necessary? Now the code is inconsistent with the comment? This change looks very gratuituous. > @@ -1078,14 +1077,17 @@ int ida_simple_get(struct ida *ida, unsigned int start, unsigned int end, > unsigned int max; > unsigned long flags; > > - BUG_ON((int)start < 0); > - BUG_ON((int)end < 0); > + if (WARN_ON_ONCE((int)start < 0)) > + return -EINVAL; > > - if (end == 0) > - max = 0x80000000; > + if ((int)end <= 0) > + max = INT_MAX; Again, why are you changing this? What problem are you trying to fix? > else { > - BUG_ON(end < start); > max = end - 1; > + if (unlikely(start == end)) > + return -ENOSPC; > + if (WARN_ON_ONCE(max < start)) > + return -EINVAL; Please juts convert BUG_ON()s to WARNs. If you want to change how the paramters behave. Do those in a separate patch with proper rationales. Thanks. -- tejun ^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 2/4] idr: reduce the number of MAX_IDR_FREE 2014-04-22 10:16 [PATCH 0/4] idr: idr cleanups Lai Jiangshan 2014-04-22 10:16 ` [PATCH 1/4] idr: proper invalid argument handling Lai Jiangshan @ 2014-04-22 10:16 ` Lai Jiangshan 2014-04-22 19:58 ` Tejun Heo 2014-04-22 10:16 ` [PATCH 3/4] ida: in-place ida allocation Lai Jiangshan 2014-04-22 10:16 ` [PATCH 4/4] idr: reorder the fields Lai Jiangshan 3 siblings, 1 reply; 12+ messages in thread From: Lai Jiangshan @ 2014-04-22 10:16 UTC (permalink / raw) To: linux-kernel Cc: Andrew Morton, Tejun Heo, Lai Jiangshan, Jean Delvare, Monam Agarwal, Jeff Layton, Andreas Gruenbacher, Stephen Hemminger Whe need to prepare MAX_IDR_FREE idr_layers for allocation. But when idr is not empty, we need atmost (MAX_IDR_LEVEL - 1) idr_layers to build up and atmost (MAX_IDR_LEVEL - 1) idr_layers to allocate down. When idr is empty need atmost MAX_IDR_LEVEL layers. So max((MAX_IDR_LEVEL * 2 - 2), MAX_IDR_LEVEL) idr_layers is enough. Signed-off-by: Lai Jiangshan <laijs@cn.fujitsu.com> --- lib/idr.c | 9 +++++++-- 1 files changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/idr.c b/lib/idr.c index 87c98fc..871991b 100644 --- a/lib/idr.c +++ b/lib/idr.c @@ -36,8 +36,13 @@ /* Leave the possibility of an incomplete final layer */ #define MAX_IDR_LEVEL ((MAX_IDR_SHIFT + IDR_BITS - 1) / IDR_BITS) -/* Number of id_layer structs to leave in free list */ -#define MAX_IDR_FREE (MAX_IDR_LEVEL * 2) +/* + * Number of idr_layer structs to leave in free list. + * When idr is not empty, we need atmost (MAX_IDR_LEVEL - 1) idr_layers + * to build up and atmost (MAX_IDR_LEVEL - 1) idr_layers to allocate down. + * When idr is empty need atmost MAX_IDR_LEVEL layers. + */ +#define MAX_IDR_FREE max((MAX_IDR_LEVEL * 2 - 2), MAX_IDR_LEVEL) static struct kmem_cache *idr_layer_cache; static DEFINE_PER_CPU(struct idr_layer *, idr_preload_head); -- 1.7.4.4 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH 2/4] idr: reduce the number of MAX_IDR_FREE 2014-04-22 10:16 ` [PATCH 2/4] idr: reduce the number of MAX_IDR_FREE Lai Jiangshan @ 2014-04-22 19:58 ` Tejun Heo 2014-04-23 1:55 ` Lai Jiangshan 0 siblings, 1 reply; 12+ messages in thread From: Tejun Heo @ 2014-04-22 19:58 UTC (permalink / raw) To: Lai Jiangshan Cc: linux-kernel, Andrew Morton, Jean Delvare, Monam Agarwal, Jeff Layton, Andreas Gruenbacher, Stephen Hemminger On Tue, Apr 22, 2014 at 06:16:19PM +0800, Lai Jiangshan wrote: > +/* > + * Number of idr_layer structs to leave in free list. > + * When idr is not empty, we need atmost (MAX_IDR_LEVEL - 1) idr_layers > + * to build up and atmost (MAX_IDR_LEVEL - 1) idr_layers to allocate down. > + * When idr is empty need atmost MAX_IDR_LEVEL layers. > + */ > +#define MAX_IDR_FREE max((MAX_IDR_LEVEL * 2 - 2), MAX_IDR_LEVEL) I don't know. Do we really wanna be this sophiscated about it when the cost of mistake would be an unexpected id allocation failure which would *EXTREMELY* difficult to track down or reproduce? Let's please keep it dumb and safe. With preloading we aren't even caching it per-idr. I don't think this is something we want to do. Nacked-by: Tejun Heo <tj@kernel.org> Thanks. -- tejun ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 2/4] idr: reduce the number of MAX_IDR_FREE 2014-04-22 19:58 ` Tejun Heo @ 2014-04-23 1:55 ` Lai Jiangshan 0 siblings, 0 replies; 12+ messages in thread From: Lai Jiangshan @ 2014-04-23 1:55 UTC (permalink / raw) To: Tejun Heo Cc: linux-kernel, Andrew Morton, Jean Delvare, Monam Agarwal, Jeff Layton, Andreas Gruenbacher, Stephen Hemminger On 04/23/2014 03:58 AM, Tejun Heo wrote: > On Tue, Apr 22, 2014 at 06:16:19PM +0800, Lai Jiangshan wrote: >> +/* >> + * Number of idr_layer structs to leave in free list. >> + * When idr is not empty, we need atmost (MAX_IDR_LEVEL - 1) idr_layers >> + * to build up and atmost (MAX_IDR_LEVEL - 1) idr_layers to allocate down. >> + * When idr is empty need atmost MAX_IDR_LEVEL layers. >> + */ >> +#define MAX_IDR_FREE max((MAX_IDR_LEVEL * 2 - 2), MAX_IDR_LEVEL) > > I don't know. Do we really wanna be this sophiscated about it when > the cost of mistake would be an unexpected id allocation failure which > would *EXTREMELY* difficult to track down or reproduce? Let's please > keep it dumb and safe. Do you mean "I need additional free layers to hide any possible bugs"? let me nervous. > With preloading we aren't even caching it > per-idr. I don't think this is something we want to do. Understood. > > Nacked-by: Tejun Heo <tj@kernel.org> > > Thanks. > ^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 3/4] ida: in-place ida allocation 2014-04-22 10:16 [PATCH 0/4] idr: idr cleanups Lai Jiangshan 2014-04-22 10:16 ` [PATCH 1/4] idr: proper invalid argument handling Lai Jiangshan 2014-04-22 10:16 ` [PATCH 2/4] idr: reduce the number of MAX_IDR_FREE Lai Jiangshan @ 2014-04-22 10:16 ` Lai Jiangshan 2014-04-22 20:02 ` Tejun Heo 2014-04-22 10:16 ` [PATCH 4/4] idr: reorder the fields Lai Jiangshan 3 siblings, 1 reply; 12+ messages in thread From: Lai Jiangshan @ 2014-04-22 10:16 UTC (permalink / raw) To: linux-kernel Cc: Andrew Morton, Tejun Heo, Lai Jiangshan, Vladimir Davydov, Jiri Kosina, Jeff Layton, Andreas Gruenbacher, Stephen Hemminger, Jean Delvare, Monam Agarwal There are two stages of ida allocation/free, idr_layers and ida_bitmap. They add unneeded foot print and memory waste. When a single ID is first allocated from an ida, this ida requires two big chunks of memory. One idr_layer and one ida_bitmap. To reduce the foot print and memory, we reduce the ida_bitmap to a single "unsigned long" and place it in its own idr-slot and avoid to allocate the ida_bitmap. It also means ida bitmap is located on its coresponding idr-slot which size is the same as "unsigned long". Each ida bitmap(idr-slot) contains BITS_PER_LONG ida-slots. The struct ida_bitmap is not needed any more, we use "unsigned long" directly and remove all the code of alloc/free struct ida_bitmap. Signed-off-by: Lai Jiangshan <laijs@cn.fujitsu.com> --- include/linux/idr.h | 15 +-------- lib/idr.c | 85 +++++++++++++------------------------------------- 2 files changed, 23 insertions(+), 77 deletions(-) diff --git a/include/linux/idr.h b/include/linux/idr.h index 6af3400..3a77b33 100644 --- a/include/linux/idr.h +++ b/include/linux/idr.h @@ -135,25 +135,12 @@ static inline void *idr_find(struct idr *idr, int id) /* * IDA - IDR based id allocator, use when translation from id to * pointer isn't necessary. - * - * IDA_BITMAP_LONGS is calculated to be one less to accommodate - * ida_bitmap->nr_busy so that the whole struct fits in 128 bytes. */ -#define IDA_CHUNK_SIZE 128 /* 128 bytes per chunk */ -#define IDA_BITMAP_LONGS (IDA_CHUNK_SIZE / sizeof(long) - 1) -#define IDA_BITMAP_BITS (IDA_BITMAP_LONGS * sizeof(long) * 8) - -struct ida_bitmap { - long nr_busy; - unsigned long bitmap[IDA_BITMAP_LONGS]; -}; - struct ida { struct idr idr; - struct ida_bitmap *free_bitmap; }; -#define IDA_INIT(name) { .idr = IDR_INIT((name).idr), .free_bitmap = NULL, } +#define IDA_INIT(name) { .idr = IDR_INIT((name).idr), } #define DEFINE_IDA(name) struct ida name = IDA_INIT(name) int ida_pre_get(struct ida *ida, gfp_t gfp_mask); diff --git a/lib/idr.c b/lib/idr.c index 871991b..69f8d78 100644 --- a/lib/idr.c +++ b/lib/idr.c @@ -859,27 +859,15 @@ EXPORT_SYMBOL(idr_is_empty); * * This is id allocator without id -> pointer translation. Memory * usage is much lower than full blown idr because each id only - * occupies a bit. ida uses a custom leaf node which contains - * IDA_BITMAP_BITS slots. + * occupies a bit. ida uses the leaf idr-slot which contains + * IDA_BITMAP_BITS(BITS_PER_LONG) ida-slots. * * 2007-04-25 written by Tejun Heo <htejun@gmail.com> */ -static void free_bitmap(struct ida *ida, struct ida_bitmap *bitmap) -{ - unsigned long flags; - - if (!ida->free_bitmap) { - spin_lock_irqsave(&ida->idr.lock, flags); - if (!ida->free_bitmap) { - ida->free_bitmap = bitmap; - bitmap = NULL; - } - spin_unlock_irqrestore(&ida->idr.lock, flags); - } - - kfree(bitmap); -} +#define IDA_BITMAP_BITS BITS_PER_LONG +#define IDA_BITMAP_EMPTY 0UL +#define IDA_BITMAP_FULL (~0UL) /** * ida_pre_get - reserve resources for ida allocation @@ -896,21 +884,7 @@ static void free_bitmap(struct ida *ida, struct ida_bitmap *bitmap) int ida_pre_get(struct ida *ida, gfp_t gfp_mask) { /* allocate idr_layers */ - if (!__idr_pre_get(&ida->idr, gfp_mask)) - return 0; - - /* allocate free_bitmap */ - if (!ida->free_bitmap) { - struct ida_bitmap *bitmap; - - bitmap = kmalloc(sizeof(struct ida_bitmap), gfp_mask); - if (!bitmap) - return 0; - - free_bitmap(ida, bitmap); - } - - return 1; + return __idr_pre_get(&ida->idr, gfp_mask); } EXPORT_SYMBOL(ida_pre_get); @@ -932,8 +906,7 @@ EXPORT_SYMBOL(ida_pre_get); int ida_get_new_above(struct ida *ida, int starting_id, int *p_id) { struct idr_layer *pa[MAX_IDR_LEVEL + 1]; - struct ida_bitmap *bitmap; - unsigned long flags; + unsigned long *bitmap; int idr_id = starting_id / IDA_BITMAP_BITS; int offset = starting_id % IDA_BITMAP_BITS; int t, id; @@ -951,25 +924,11 @@ int ida_get_new_above(struct ida *ida, int starting_id, int *p_id) offset = 0; idr_id = t; - /* if bitmap isn't there, create a new one */ - bitmap = (void *)pa[0]->ary[idr_id & IDR_MASK]; - if (!bitmap) { - spin_lock_irqsave(&ida->idr.lock, flags); - bitmap = ida->free_bitmap; - ida->free_bitmap = NULL; - spin_unlock_irqrestore(&ida->idr.lock, flags); - - if (!bitmap) - return -EAGAIN; - - memset(bitmap, 0, sizeof(struct ida_bitmap)); - rcu_assign_pointer(pa[0]->ary[idr_id & IDR_MASK], - (void *)bitmap); - pa[0]->count++; - } + /* the lelf idr-slot is the bitmap for ida slots */ + bitmap = (void *)&pa[0]->ary[idr_id & IDR_MASK]; /* lookup for empty slot */ - t = find_next_zero_bit(bitmap->bitmap, IDA_BITMAP_BITS, offset); + t = find_next_zero_bit(bitmap, IDA_BITMAP_BITS, offset); if (t == IDA_BITMAP_BITS) { /* no empty slot after offset, continue to the next chunk */ idr_id++; @@ -981,18 +940,21 @@ int ida_get_new_above(struct ida *ida, int starting_id, int *p_id) if (id >= MAX_IDR_BIT) return -ENOSPC; - __set_bit(t, bitmap->bitmap); - if (++bitmap->nr_busy == IDA_BITMAP_BITS) + if (*bitmap == IDA_BITMAP_EMPTY) + pa[0]->count++; + + __set_bit(t, bitmap); + if (*bitmap == IDA_BITMAP_FULL) idr_mark_full(pa, idr_id); *p_id = id; - /* Each leaf node can handle nearly a thousand slots and the + /* Each leaf idr_layer can handle nearly a thousand slots and the * whole idea of ida is to have small memory foot print. * Throw away extra resources one by one after each successful * allocation. */ - if (ida->idr.id_free_cnt || ida->free_bitmap) { + if (ida->idr.id_free_cnt) { struct idr_layer *p = get_from_free_list(&ida->idr); if (p) kmem_cache_free(idr_layer_cache, p); @@ -1014,7 +976,7 @@ void ida_remove(struct ida *ida, int id) int idr_id = id / IDA_BITMAP_BITS; int offset = id % IDA_BITMAP_BITS; int n; - struct ida_bitmap *bitmap; + unsigned long *bitmap; if (id < 0 || idr_id > idr_max(ida->idr.layers)) goto err; @@ -1033,16 +995,15 @@ void ida_remove(struct ida *ida, int id) n = idr_id & IDR_MASK; __clear_bit(n, p->bitmap); - bitmap = (void *)p->ary[n]; - if (!bitmap || !test_bit(offset, bitmap->bitmap)) + bitmap = (void *)&p->ary[n]; + if (!test_bit(offset, bitmap)) goto err; /* update bitmap and remove it if empty */ - __clear_bit(offset, bitmap->bitmap); - if (--bitmap->nr_busy == 0) { + __clear_bit(offset, bitmap); + if (*bitmap == IDA_BITMAP_EMPTY) { __set_bit(n, p->bitmap); /* to please idr_remove() */ idr_remove(&ida->idr, idr_id); - free_bitmap(ida, bitmap); } return; @@ -1059,7 +1020,6 @@ EXPORT_SYMBOL(ida_remove); void ida_destroy(struct ida *ida) { idr_destroy(&ida->idr); - kfree(ida->free_bitmap); } EXPORT_SYMBOL(ida_destroy); @@ -1142,7 +1102,6 @@ EXPORT_SYMBOL(ida_simple_remove); */ void ida_init(struct ida *ida) { - memset(ida, 0, sizeof(struct ida)); idr_init(&ida->idr); } -- 1.7.4.4 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH 3/4] ida: in-place ida allocation 2014-04-22 10:16 ` [PATCH 3/4] ida: in-place ida allocation Lai Jiangshan @ 2014-04-22 20:02 ` Tejun Heo 2014-04-23 1:44 ` Lai Jiangshan 0 siblings, 1 reply; 12+ messages in thread From: Tejun Heo @ 2014-04-22 20:02 UTC (permalink / raw) To: Lai Jiangshan Cc: linux-kernel, Andrew Morton, Vladimir Davydov, Jiri Kosina, Jeff Layton, Andreas Gruenbacher, Stephen Hemminger, Jean Delvare, Monam Agarwal On Tue, Apr 22, 2014 at 06:16:20PM +0800, Lai Jiangshan wrote: > There are two stages of ida allocation/free, idr_layers and ida_bitmap. > They add unneeded foot print and memory waste. > > When a single ID is first allocated from an ida, this ida requires > two big chunks of memory. One idr_layer and one ida_bitmap. > > To reduce the foot print and memory, we reduce the ida_bitmap > to a single "unsigned long" and place it in its own idr-slot > and avoid to allocate the ida_bitmap. > > It also means ida bitmap is located on its coresponding idr-slot > which size is the same as "unsigned long". > Each ida bitmap(idr-slot) contains BITS_PER_LONG ida-slots. > > The struct ida_bitmap is not needed any more, we use "unsigned long" > directly and remove all the code of alloc/free struct ida_bitmap. Are you calling 128 byte a "big chunk of memory" while trading off tree depth for it? No, this level of space optimizaiton is completely uncalled for. Nacked-by: Tejun Heo <tj@kernel.org> Thanks. -- tejun ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 3/4] ida: in-place ida allocation 2014-04-22 20:02 ` Tejun Heo @ 2014-04-23 1:44 ` Lai Jiangshan 0 siblings, 0 replies; 12+ messages in thread From: Lai Jiangshan @ 2014-04-23 1:44 UTC (permalink / raw) To: Tejun Heo Cc: linux-kernel, Andrew Morton, Vladimir Davydov, Jiri Kosina, Jeff Layton, Andreas Gruenbacher, Stephen Hemminger, Jean Delvare, Monam Agarwal On 04/23/2014 04:02 AM, Tejun Heo wrote: > On Tue, Apr 22, 2014 at 06:16:20PM +0800, Lai Jiangshan wrote: >> There are two stages of ida allocation/free, idr_layers and ida_bitmap. >> They add unneeded foot print and memory waste. >> >> When a single ID is first allocated from an ida, this ida requires >> two big chunks of memory. One idr_layer and one ida_bitmap. >> >> To reduce the foot print and memory, we reduce the ida_bitmap >> to a single "unsigned long" and place it in its own idr-slot >> and avoid to allocate the ida_bitmap. >> >> It also means ida bitmap is located on its coresponding idr-slot >> which size is the same as "unsigned long". >> Each ida bitmap(idr-slot) contains BITS_PER_LONG ida-slots. >> >> The struct ida_bitmap is not needed any more, we use "unsigned long" >> directly and remove all the code of alloc/free struct ida_bitmap. > > Are you calling 128 byte a "big chunk of memory" while trading off > tree depth for it? No, this level of space optimizaiton is completely > uncalled for. I reduce the depth, you forgot that struct ida_bitmap is an additional depth which is removed in the patch. > > Nacked-by: Tejun Heo <tj@kernel.org> > > Thanks. > ^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 4/4] idr: reorder the fields 2014-04-22 10:16 [PATCH 0/4] idr: idr cleanups Lai Jiangshan ` (2 preceding siblings ...) 2014-04-22 10:16 ` [PATCH 3/4] ida: in-place ida allocation Lai Jiangshan @ 2014-04-22 10:16 ` Lai Jiangshan 3 siblings, 0 replies; 12+ messages in thread From: Lai Jiangshan @ 2014-04-22 10:16 UTC (permalink / raw) To: linux-kernel Cc: Andrew Morton, Tejun Heo, Lai Jiangshan, Vladimir Davydov, Jiri Kosina, Jeff Layton, Andreas Gruenbacher, Stephen Hemminger idr_layer->layer is always accessed in read path, move it in the front. idr_layer->bitmap is moved on the bottom. And rcu_head shares with bitmap due to they do not be accessed at the same time. idr->id_free/id_free_cnt/lock are free list fields, and moved to the bottom. They will be removed in near future. Signed-off-by: Lai Jiangshan <laijs@cn.fujitsu.com> --- include/linux/idr.h | 13 ++++++++----- 1 files changed, 8 insertions(+), 5 deletions(-) diff --git a/include/linux/idr.h b/include/linux/idr.h index 3a77b33..c537c55 100644 --- a/include/linux/idr.h +++ b/include/linux/idr.h @@ -29,21 +29,24 @@ struct idr_layer { int prefix; /* the ID prefix of this idr_layer */ - DECLARE_BITMAP(bitmap, IDR_SIZE); /* A zero bit means "space here" */ + int layer; /* distance from leaf */ struct idr_layer __rcu *ary[1<<IDR_BITS]; int count; /* When zero, we can release it */ - int layer; /* distance from leaf */ - struct rcu_head rcu_head; + union { + /* A zero bit means "space here" */ + DECLARE_BITMAP(bitmap, IDR_SIZE); + struct rcu_head rcu_head; + }; }; struct idr { struct idr_layer __rcu *hint; /* the last layer allocated from */ struct idr_layer __rcu *top; - struct idr_layer *id_free; int layers; /* only valid w/o concurrent changes */ - int id_free_cnt; int cur; /* current pos for cyclic allocation */ spinlock_t lock; + int id_free_cnt; + struct idr_layer *id_free; }; #define IDR_INIT(name) \ -- 1.7.4.4 ^ permalink raw reply related [flat|nested] 12+ messages in thread
end of thread, other threads:[~2014-04-23 1:52 UTC | newest] Thread overview: 12+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2014-04-22 10:16 [PATCH 0/4] idr: idr cleanups Lai Jiangshan 2014-04-22 10:16 ` [PATCH 1/4] idr: proper invalid argument handling Lai Jiangshan 2014-04-22 19:16 ` Andrew Morton 2014-04-22 19:46 ` Andrew Morton 2014-04-22 19:54 ` Tejun Heo 2014-04-22 10:16 ` [PATCH 2/4] idr: reduce the number of MAX_IDR_FREE Lai Jiangshan 2014-04-22 19:58 ` Tejun Heo 2014-04-23 1:55 ` Lai Jiangshan 2014-04-22 10:16 ` [PATCH 3/4] ida: in-place ida allocation Lai Jiangshan 2014-04-22 20:02 ` Tejun Heo 2014-04-23 1:44 ` Lai Jiangshan 2014-04-22 10:16 ` [PATCH 4/4] idr: reorder the fields Lai Jiangshan
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox