Commit 72dba584b695d8bc8c1a50ed54ad4cba7c62314d
Committed by
Greg Kroah-Hartman
1 parent
e33ac8bdb0
Exists in
master
and in
4 other branches
ida: implement idr based id allocator
Implement idr based id allocator. ida is used the same way idr is used but lacks id -> ptr translation and thus consumes much less memory. struct ida_bitmap is attached as leaf nodes to idr tree which is managed by the idr code. Each ida_bitmap is 128bytes long and contains slightly less than a thousand slots. ida is more aggressive with releasing extra resources acquired using ida_pre_get(). After every successful id allocation, ida frees one reserved idr_layer if possible. Reserved ida_bitmap is not freed automatically but only one ida_bitmap is reserved and it's almost always used right away. Under most circumstances, ida won't hold on to memory for too long which isn't actively used. Signed-off-by: Tejun Heo <htejun@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Showing 2 changed files with 274 additions and 0 deletions Side-by-side Diff
include/linux/idr.h
... | ... | @@ -83,5 +83,34 @@ |
83 | 83 | void idr_destroy(struct idr *idp); |
84 | 84 | void idr_init(struct idr *idp); |
85 | 85 | |
86 | + | |
87 | +/* | |
88 | + * IDA - IDR based id allocator, use when translation from id to | |
89 | + * pointer isn't necessary. | |
90 | + */ | |
91 | +#define IDA_CHUNK_SIZE 128 /* 128 bytes per chunk */ | |
92 | +#define IDA_BITMAP_LONGS (128 / sizeof(long) - 1) | |
93 | +#define IDA_BITMAP_BITS (IDA_BITMAP_LONGS * sizeof(long) * 8) | |
94 | + | |
95 | +struct ida_bitmap { | |
96 | + long nr_busy; | |
97 | + unsigned long bitmap[IDA_BITMAP_LONGS]; | |
98 | +}; | |
99 | + | |
100 | +struct ida { | |
101 | + struct idr idr; | |
102 | + struct ida_bitmap *free_bitmap; | |
103 | +}; | |
104 | + | |
105 | +#define IDA_INIT(name) { .idr = IDR_INIT(name), .free_bitmap = NULL, } | |
106 | +#define DEFINE_IDA(name) struct ida name = IDA_INIT(name) | |
107 | + | |
108 | +int ida_pre_get(struct ida *ida, gfp_t gfp_mask); | |
109 | +int ida_get_new_above(struct ida *ida, int starting_id, int *p_id); | |
110 | +int ida_get_new(struct ida *ida, int *p_id); | |
111 | +void ida_remove(struct ida *ida, int id); | |
112 | +void ida_destroy(struct ida *ida); | |
113 | +void ida_init(struct ida *ida); | |
114 | + | |
86 | 115 | #endif /* __IDR_H__ */ |
lib/idr.c
... | ... | @@ -506,4 +506,249 @@ |
506 | 506 | spin_lock_init(&idp->lock); |
507 | 507 | } |
508 | 508 | EXPORT_SYMBOL(idr_init); |
509 | + | |
510 | + | |
511 | +/* | |
512 | + * IDA - IDR based ID allocator | |
513 | + * | |
514 | + * this is id allocator without id -> pointer translation. Memory | |
515 | + * usage is much lower than full blown idr because each id only | |
516 | + * occupies a bit. ida uses a custom leaf node which contains | |
517 | + * IDA_BITMAP_BITS slots. | |
518 | + * | |
519 | + * 2007-04-25 written by Tejun Heo <htejun@gmail.com> | |
520 | + */ | |
521 | + | |
522 | +static void free_bitmap(struct ida *ida, struct ida_bitmap *bitmap) | |
523 | +{ | |
524 | + unsigned long flags; | |
525 | + | |
526 | + if (!ida->free_bitmap) { | |
527 | + spin_lock_irqsave(&ida->idr.lock, flags); | |
528 | + if (!ida->free_bitmap) { | |
529 | + ida->free_bitmap = bitmap; | |
530 | + bitmap = NULL; | |
531 | + } | |
532 | + spin_unlock_irqrestore(&ida->idr.lock, flags); | |
533 | + } | |
534 | + | |
535 | + kfree(bitmap); | |
536 | +} | |
537 | + | |
538 | +/** | |
539 | + * ida_pre_get - reserve resources for ida allocation | |
540 | + * @ida: ida handle | |
541 | + * @gfp_mask: memory allocation flag | |
542 | + * | |
543 | + * This function should be called prior to locking and calling the | |
544 | + * following function. It preallocates enough memory to satisfy the | |
545 | + * worst possible allocation. | |
546 | + * | |
547 | + * If the system is REALLY out of memory this function returns 0, | |
548 | + * otherwise 1. | |
549 | + */ | |
550 | +int ida_pre_get(struct ida *ida, gfp_t gfp_mask) | |
551 | +{ | |
552 | + /* allocate idr_layers */ | |
553 | + if (!idr_pre_get(&ida->idr, gfp_mask)) | |
554 | + return 0; | |
555 | + | |
556 | + /* allocate free_bitmap */ | |
557 | + if (!ida->free_bitmap) { | |
558 | + struct ida_bitmap *bitmap; | |
559 | + | |
560 | + bitmap = kmalloc(sizeof(struct ida_bitmap), gfp_mask); | |
561 | + if (!bitmap) | |
562 | + return 0; | |
563 | + | |
564 | + free_bitmap(ida, bitmap); | |
565 | + } | |
566 | + | |
567 | + return 1; | |
568 | +} | |
569 | +EXPORT_SYMBOL(ida_pre_get); | |
570 | + | |
571 | +/** | |
572 | + * ida_get_new_above - allocate new ID above or equal to a start id | |
573 | + * @ida: ida handle | |
574 | + * @staring_id: id to start search at | |
575 | + * @p_id: pointer to the allocated handle | |
576 | + * | |
577 | + * Allocate new ID above or equal to @ida. It should be called with | |
578 | + * any required locks. | |
579 | + * | |
580 | + * If memory is required, it will return -EAGAIN, you should unlock | |
581 | + * and go back to the ida_pre_get() call. If the ida is full, it will | |
582 | + * return -ENOSPC. | |
583 | + * | |
584 | + * @p_id returns a value in the range 0 ... 0x7fffffff. | |
585 | + */ | |
586 | +int ida_get_new_above(struct ida *ida, int starting_id, int *p_id) | |
587 | +{ | |
588 | + struct idr_layer *pa[MAX_LEVEL]; | |
589 | + struct ida_bitmap *bitmap; | |
590 | + unsigned long flags; | |
591 | + int idr_id = starting_id / IDA_BITMAP_BITS; | |
592 | + int offset = starting_id % IDA_BITMAP_BITS; | |
593 | + int t, id; | |
594 | + | |
595 | + restart: | |
596 | + /* get vacant slot */ | |
597 | + t = idr_get_empty_slot(&ida->idr, idr_id, pa); | |
598 | + if (t < 0) { | |
599 | + if (t == -1) | |
600 | + return -EAGAIN; | |
601 | + else /* will be -3 */ | |
602 | + return -ENOSPC; | |
603 | + } | |
604 | + | |
605 | + if (t * IDA_BITMAP_BITS >= MAX_ID_BIT) | |
606 | + return -ENOSPC; | |
607 | + | |
608 | + if (t != idr_id) | |
609 | + offset = 0; | |
610 | + idr_id = t; | |
611 | + | |
612 | + /* if bitmap isn't there, create a new one */ | |
613 | + bitmap = (void *)pa[0]->ary[idr_id & IDR_MASK]; | |
614 | + if (!bitmap) { | |
615 | + spin_lock_irqsave(&ida->idr.lock, flags); | |
616 | + bitmap = ida->free_bitmap; | |
617 | + ida->free_bitmap = NULL; | |
618 | + spin_unlock_irqrestore(&ida->idr.lock, flags); | |
619 | + | |
620 | + if (!bitmap) | |
621 | + return -EAGAIN; | |
622 | + | |
623 | + memset(bitmap, 0, sizeof(struct ida_bitmap)); | |
624 | + pa[0]->ary[idr_id & IDR_MASK] = (void *)bitmap; | |
625 | + pa[0]->count++; | |
626 | + } | |
627 | + | |
628 | + /* lookup for empty slot */ | |
629 | + t = find_next_zero_bit(bitmap->bitmap, IDA_BITMAP_BITS, offset); | |
630 | + if (t == IDA_BITMAP_BITS) { | |
631 | + /* no empty slot after offset, continue to the next chunk */ | |
632 | + idr_id++; | |
633 | + offset = 0; | |
634 | + goto restart; | |
635 | + } | |
636 | + | |
637 | + id = idr_id * IDA_BITMAP_BITS + t; | |
638 | + if (id >= MAX_ID_BIT) | |
639 | + return -ENOSPC; | |
640 | + | |
641 | + __set_bit(t, bitmap->bitmap); | |
642 | + if (++bitmap->nr_busy == IDA_BITMAP_BITS) | |
643 | + idr_mark_full(pa, idr_id); | |
644 | + | |
645 | + *p_id = id; | |
646 | + | |
647 | + /* Each leaf node can handle nearly a thousand slots and the | |
648 | + * whole idea of ida is to have small memory foot print. | |
649 | + * Throw away extra resources one by one after each successful | |
650 | + * allocation. | |
651 | + */ | |
652 | + if (ida->idr.id_free_cnt || ida->free_bitmap) { | |
653 | + struct idr_layer *p = alloc_layer(&ida->idr); | |
654 | + if (p) | |
655 | + kmem_cache_free(idr_layer_cache, p); | |
656 | + } | |
657 | + | |
658 | + return 0; | |
659 | +} | |
660 | +EXPORT_SYMBOL(ida_get_new_above); | |
661 | + | |
662 | +/** | |
663 | + * ida_get_new - allocate new ID | |
664 | + * @ida: idr handle | |
665 | + * @p_id: pointer to the allocated handle | |
666 | + * | |
667 | + * Allocate new ID. It should be called with any required locks. | |
668 | + * | |
669 | + * If memory is required, it will return -EAGAIN, you should unlock | |
670 | + * and go back to the idr_pre_get() call. If the idr is full, it will | |
671 | + * return -ENOSPC. | |
672 | + * | |
673 | + * @id returns a value in the range 0 ... 0x7fffffff. | |
674 | + */ | |
675 | +int ida_get_new(struct ida *ida, int *p_id) | |
676 | +{ | |
677 | + return ida_get_new_above(ida, 0, p_id); | |
678 | +} | |
679 | +EXPORT_SYMBOL(ida_get_new); | |
680 | + | |
681 | +/** | |
682 | + * ida_remove - remove the given ID | |
683 | + * @ida: ida handle | |
684 | + * @id: ID to free | |
685 | + */ | |
686 | +void ida_remove(struct ida *ida, int id) | |
687 | +{ | |
688 | + struct idr_layer *p = ida->idr.top; | |
689 | + int shift = (ida->idr.layers - 1) * IDR_BITS; | |
690 | + int idr_id = id / IDA_BITMAP_BITS; | |
691 | + int offset = id % IDA_BITMAP_BITS; | |
692 | + int n; | |
693 | + struct ida_bitmap *bitmap; | |
694 | + | |
695 | + /* clear full bits while looking up the leaf idr_layer */ | |
696 | + while ((shift > 0) && p) { | |
697 | + n = (idr_id >> shift) & IDR_MASK; | |
698 | + __clear_bit(n, &p->bitmap); | |
699 | + p = p->ary[n]; | |
700 | + shift -= IDR_BITS; | |
701 | + } | |
702 | + | |
703 | + if (p == NULL) | |
704 | + goto err; | |
705 | + | |
706 | + n = idr_id & IDR_MASK; | |
707 | + __clear_bit(n, &p->bitmap); | |
708 | + | |
709 | + bitmap = (void *)p->ary[n]; | |
710 | + if (!test_bit(offset, bitmap->bitmap)) | |
711 | + goto err; | |
712 | + | |
713 | + /* update bitmap and remove it if empty */ | |
714 | + __clear_bit(offset, bitmap->bitmap); | |
715 | + if (--bitmap->nr_busy == 0) { | |
716 | + __set_bit(n, &p->bitmap); /* to please idr_remove() */ | |
717 | + idr_remove(&ida->idr, idr_id); | |
718 | + free_bitmap(ida, bitmap); | |
719 | + } | |
720 | + | |
721 | + return; | |
722 | + | |
723 | + err: | |
724 | + printk(KERN_WARNING | |
725 | + "ida_remove called for id=%d which is not allocated.\n", id); | |
726 | +} | |
727 | +EXPORT_SYMBOL(ida_remove); | |
728 | + | |
729 | +/** | |
730 | + * ida_destroy - release all cached layers within an ida tree | |
731 | + * ida: ida handle | |
732 | + */ | |
733 | +void ida_destroy(struct ida *ida) | |
734 | +{ | |
735 | + idr_destroy(&ida->idr); | |
736 | + kfree(ida->free_bitmap); | |
737 | +} | |
738 | +EXPORT_SYMBOL(ida_destroy); | |
739 | + | |
740 | +/** | |
741 | + * ida_init - initialize ida handle | |
742 | + * @ida: ida handle | |
743 | + * | |
744 | + * This function is use to set up the handle (@ida) that you will pass | |
745 | + * to the rest of the functions. | |
746 | + */ | |
747 | +void ida_init(struct ida *ida) | |
748 | +{ | |
749 | + memset(ida, 0, sizeof(struct ida)); | |
750 | + idr_init(&ida->idr); | |
751 | + | |
752 | +} | |
753 | +EXPORT_SYMBOL(ida_init); |