diff options
author | Cyrill Gorcunov <gorcunov@openvz.org> | 2008-12-17 03:34:06 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-12-17 03:34:06 -0500 |
commit | 7a95d267fb62cd6b80ef73be0592bbbe1dbd5df7 (patch) | |
tree | 30d280777e087cc9c0e5686fc07c2b7d51af96d7 | |
parent | c0700f90e5300c63d01c70e157e75e4510dd2981 (diff) |
net: ppp_generic - use idr technique instead of cardmaps
Use idr technique instead of own implemented cardmaps.
It saves us a number of lines and gives an ability
to use library functions.
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/ppp_generic.c | 183 |
1 files changed, 48 insertions, 135 deletions
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index 1b15a088a3ba..3ee7830d458d 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/kmod.h> | 27 | #include <linux/kmod.h> |
28 | #include <linux/init.h> | 28 | #include <linux/init.h> |
29 | #include <linux/list.h> | 29 | #include <linux/list.h> |
30 | #include <linux/idr.h> | ||
30 | #include <linux/netdevice.h> | 31 | #include <linux/netdevice.h> |
31 | #include <linux/poll.h> | 32 | #include <linux/poll.h> |
32 | #include <linux/ppp_defs.h> | 33 | #include <linux/ppp_defs.h> |
@@ -172,35 +173,13 @@ struct channel { | |||
172 | */ | 173 | */ |
173 | 174 | ||
174 | /* | 175 | /* |
175 | * A cardmap represents a mapping from unsigned integers to pointers, | ||
176 | * and provides a fast "find lowest unused number" operation. | ||
177 | * It uses a broad (32-way) tree with a bitmap at each level. | ||
178 | * It is designed to be space-efficient for small numbers of entries | ||
179 | * and time-efficient for large numbers of entries. | ||
180 | */ | ||
181 | #define CARDMAP_ORDER 5 | ||
182 | #define CARDMAP_WIDTH (1U << CARDMAP_ORDER) | ||
183 | #define CARDMAP_MASK (CARDMAP_WIDTH - 1) | ||
184 | |||
185 | struct cardmap { | ||
186 | int shift; | ||
187 | unsigned long inuse; | ||
188 | struct cardmap *parent; | ||
189 | void *ptr[CARDMAP_WIDTH]; | ||
190 | }; | ||
191 | static void *cardmap_get(struct cardmap *map, unsigned int nr); | ||
192 | static int cardmap_set(struct cardmap **map, unsigned int nr, void *ptr); | ||
193 | static unsigned int cardmap_find_first_free(struct cardmap *map); | ||
194 | static void cardmap_destroy(struct cardmap **map); | ||
195 | |||
196 | /* | ||
197 | * all_ppp_mutex protects the all_ppp_units mapping. | 176 | * all_ppp_mutex protects the all_ppp_units mapping. |
198 | * It also ensures that finding a ppp unit in the all_ppp_units map | 177 | * It also ensures that finding a ppp unit in the all_ppp_units map |
199 | * and updating its file.refcnt field is atomic. | 178 | * and updating its file.refcnt field is atomic. |
200 | */ | 179 | */ |
201 | static DEFINE_MUTEX(all_ppp_mutex); | 180 | static DEFINE_MUTEX(all_ppp_mutex); |
202 | static struct cardmap *all_ppp_units; | ||
203 | static atomic_t ppp_unit_count = ATOMIC_INIT(0); | 181 | static atomic_t ppp_unit_count = ATOMIC_INIT(0); |
182 | static struct idr ppp_units_idr; | ||
204 | 183 | ||
205 | /* | 184 | /* |
206 | * all_channels_lock protects all_channels and last_channel_index, | 185 | * all_channels_lock protects all_channels and last_channel_index, |
@@ -269,6 +248,9 @@ static struct channel *ppp_find_channel(int unit); | |||
269 | static int ppp_connect_channel(struct channel *pch, int unit); | 248 | static int ppp_connect_channel(struct channel *pch, int unit); |
270 | static int ppp_disconnect_channel(struct channel *pch); | 249 | static int ppp_disconnect_channel(struct channel *pch); |
271 | static void ppp_destroy_channel(struct channel *pch); | 250 | static void ppp_destroy_channel(struct channel *pch); |
251 | static int unit_get(struct idr *p, void *ptr); | ||
252 | static void unit_put(struct idr *p, int n); | ||
253 | static void *unit_find(struct idr *p, int n); | ||
272 | 254 | ||
273 | static struct class *ppp_class; | 255 | static struct class *ppp_class; |
274 | 256 | ||
@@ -870,6 +852,8 @@ static int __init ppp_init(void) | |||
870 | "ppp"); | 852 | "ppp"); |
871 | } | 853 | } |
872 | 854 | ||
855 | idr_init(&ppp_units_idr); | ||
856 | |||
873 | out: | 857 | out: |
874 | if (err) | 858 | if (err) |
875 | printk(KERN_ERR "failed to register PPP device (%d)\n", err); | 859 | printk(KERN_ERR "failed to register PPP device (%d)\n", err); |
@@ -2440,10 +2424,22 @@ ppp_create_interface(int unit, int *retp) | |||
2440 | 2424 | ||
2441 | ret = -EEXIST; | 2425 | ret = -EEXIST; |
2442 | mutex_lock(&all_ppp_mutex); | 2426 | mutex_lock(&all_ppp_mutex); |
2443 | if (unit < 0) | 2427 | |
2444 | unit = cardmap_find_first_free(all_ppp_units); | 2428 | if (unit < 0) { |
2445 | else if (cardmap_get(all_ppp_units, unit) != NULL) | 2429 | unit = unit_get(&ppp_units_idr, ppp); |
2446 | goto out2; /* unit already exists */ | 2430 | if (unit < 0) { |
2431 | *retp = unit; | ||
2432 | goto out2; | ||
2433 | } | ||
2434 | } else { | ||
2435 | if (unit_find(&ppp_units_idr, unit)) | ||
2436 | goto out2; /* unit already exists */ | ||
2437 | else { | ||
2438 | /* darn, someone is cheatting us? */ | ||
2439 | *retp = -EINVAL; | ||
2440 | goto out2; | ||
2441 | } | ||
2442 | } | ||
2447 | 2443 | ||
2448 | /* Initialize the new ppp unit */ | 2444 | /* Initialize the new ppp unit */ |
2449 | ppp->file.index = unit; | 2445 | ppp->file.index = unit; |
@@ -2451,23 +2447,18 @@ ppp_create_interface(int unit, int *retp) | |||
2451 | 2447 | ||
2452 | ret = register_netdev(dev); | 2448 | ret = register_netdev(dev); |
2453 | if (ret != 0) { | 2449 | if (ret != 0) { |
2450 | unit_put(&ppp_units_idr, unit); | ||
2454 | printk(KERN_ERR "PPP: couldn't register device %s (%d)\n", | 2451 | printk(KERN_ERR "PPP: couldn't register device %s (%d)\n", |
2455 | dev->name, ret); | 2452 | dev->name, ret); |
2456 | goto out2; | 2453 | goto out2; |
2457 | } | 2454 | } |
2458 | 2455 | ||
2459 | atomic_inc(&ppp_unit_count); | 2456 | atomic_inc(&ppp_unit_count); |
2460 | ret = cardmap_set(&all_ppp_units, unit, ppp); | ||
2461 | if (ret != 0) | ||
2462 | goto out3; | ||
2463 | |||
2464 | mutex_unlock(&all_ppp_mutex); | 2457 | mutex_unlock(&all_ppp_mutex); |
2458 | |||
2465 | *retp = 0; | 2459 | *retp = 0; |
2466 | return ppp; | 2460 | return ppp; |
2467 | 2461 | ||
2468 | out3: | ||
2469 | atomic_dec(&ppp_unit_count); | ||
2470 | unregister_netdev(dev); | ||
2471 | out2: | 2462 | out2: |
2472 | mutex_unlock(&all_ppp_mutex); | 2463 | mutex_unlock(&all_ppp_mutex); |
2473 | free_netdev(dev); | 2464 | free_netdev(dev); |
@@ -2507,7 +2498,7 @@ static void ppp_shutdown_interface(struct ppp *ppp) | |||
2507 | unregister_netdev(dev); | 2498 | unregister_netdev(dev); |
2508 | free_netdev(dev); | 2499 | free_netdev(dev); |
2509 | } | 2500 | } |
2510 | cardmap_set(&all_ppp_units, ppp->file.index, NULL); | 2501 | unit_put(&ppp_units_idr, ppp->file.index); |
2511 | ppp->file.dead = 1; | 2502 | ppp->file.dead = 1; |
2512 | ppp->owner = NULL; | 2503 | ppp->owner = NULL; |
2513 | wake_up_interruptible(&ppp->file.rwait); | 2504 | wake_up_interruptible(&ppp->file.rwait); |
@@ -2561,7 +2552,7 @@ static void ppp_destroy_interface(struct ppp *ppp) | |||
2561 | static struct ppp * | 2552 | static struct ppp * |
2562 | ppp_find_unit(int unit) | 2553 | ppp_find_unit(int unit) |
2563 | { | 2554 | { |
2564 | return cardmap_get(all_ppp_units, unit); | 2555 | return unit_find(&ppp_units_idr, unit); |
2565 | } | 2556 | } |
2566 | 2557 | ||
2567 | /* | 2558 | /* |
@@ -2679,123 +2670,45 @@ static void __exit ppp_cleanup(void) | |||
2679 | /* should never happen */ | 2670 | /* should never happen */ |
2680 | if (atomic_read(&ppp_unit_count) || atomic_read(&channel_count)) | 2671 | if (atomic_read(&ppp_unit_count) || atomic_read(&channel_count)) |
2681 | printk(KERN_ERR "PPP: removing module but units remain!\n"); | 2672 | printk(KERN_ERR "PPP: removing module but units remain!\n"); |
2682 | cardmap_destroy(&all_ppp_units); | ||
2683 | unregister_chrdev(PPP_MAJOR, "ppp"); | 2673 | unregister_chrdev(PPP_MAJOR, "ppp"); |
2684 | device_destroy(ppp_class, MKDEV(PPP_MAJOR, 0)); | 2674 | device_destroy(ppp_class, MKDEV(PPP_MAJOR, 0)); |
2685 | class_destroy(ppp_class); | 2675 | class_destroy(ppp_class); |
2676 | idr_destroy(&ppp_units_idr); | ||
2686 | } | 2677 | } |
2687 | 2678 | ||
2688 | /* | 2679 | /* |
2689 | * Cardmap implementation. | 2680 | * Units handling. Caller must protect concurrent access |
2681 | * by holding all_ppp_mutex | ||
2690 | */ | 2682 | */ |
2691 | static void *cardmap_get(struct cardmap *map, unsigned int nr) | 2683 | |
2684 | /* get new free unit number and associate pointer with it */ | ||
2685 | static int unit_get(struct idr *p, void *ptr) | ||
2692 | { | 2686 | { |
2693 | struct cardmap *p; | 2687 | int unit, err; |
2694 | int i; | ||
2695 | 2688 | ||
2696 | for (p = map; p != NULL; ) { | 2689 | again: |
2697 | if ((i = nr >> p->shift) >= CARDMAP_WIDTH) | 2690 | if (idr_pre_get(p, GFP_KERNEL) == 0) { |
2698 | return NULL; | 2691 | printk(KERN_ERR "Out of memory expanding drawable idr\n"); |
2699 | if (p->shift == 0) | 2692 | return -ENOMEM; |
2700 | return p->ptr[i]; | ||
2701 | nr &= ~(CARDMAP_MASK << p->shift); | ||
2702 | p = p->ptr[i]; | ||
2703 | } | 2693 | } |
2704 | return NULL; | ||
2705 | } | ||
2706 | 2694 | ||
2707 | static int cardmap_set(struct cardmap **pmap, unsigned int nr, void *ptr) | 2695 | err = idr_get_new_above(p, ptr, 0, &unit); |
2708 | { | 2696 | if (err == -EAGAIN) |
2709 | struct cardmap *p; | 2697 | goto again; |
2710 | int i; | ||
2711 | 2698 | ||
2712 | p = *pmap; | 2699 | return unit; |
2713 | if (p == NULL || (nr >> p->shift) >= CARDMAP_WIDTH) { | ||
2714 | do { | ||
2715 | /* need a new top level */ | ||
2716 | struct cardmap *np = kzalloc(sizeof(*np), GFP_KERNEL); | ||
2717 | if (!np) | ||
2718 | goto enomem; | ||
2719 | np->ptr[0] = p; | ||
2720 | if (p != NULL) { | ||
2721 | np->shift = p->shift + CARDMAP_ORDER; | ||
2722 | p->parent = np; | ||
2723 | } else | ||
2724 | np->shift = 0; | ||
2725 | p = np; | ||
2726 | } while ((nr >> p->shift) >= CARDMAP_WIDTH); | ||
2727 | *pmap = p; | ||
2728 | } | ||
2729 | while (p->shift > 0) { | ||
2730 | i = (nr >> p->shift) & CARDMAP_MASK; | ||
2731 | if (p->ptr[i] == NULL) { | ||
2732 | struct cardmap *np = kzalloc(sizeof(*np), GFP_KERNEL); | ||
2733 | if (!np) | ||
2734 | goto enomem; | ||
2735 | np->shift = p->shift - CARDMAP_ORDER; | ||
2736 | np->parent = p; | ||
2737 | p->ptr[i] = np; | ||
2738 | } | ||
2739 | if (ptr == NULL) | ||
2740 | clear_bit(i, &p->inuse); | ||
2741 | p = p->ptr[i]; | ||
2742 | } | ||
2743 | i = nr & CARDMAP_MASK; | ||
2744 | p->ptr[i] = ptr; | ||
2745 | if (ptr != NULL) | ||
2746 | set_bit(i, &p->inuse); | ||
2747 | else | ||
2748 | clear_bit(i, &p->inuse); | ||
2749 | return 0; | ||
2750 | enomem: | ||
2751 | return -ENOMEM; | ||
2752 | } | 2700 | } |
2753 | 2701 | ||
2754 | static unsigned int cardmap_find_first_free(struct cardmap *map) | 2702 | /* put unit number back to a pool */ |
2703 | static void unit_put(struct idr *p, int n) | ||
2755 | { | 2704 | { |
2756 | struct cardmap *p; | 2705 | idr_remove(p, n); |
2757 | unsigned int nr = 0; | ||
2758 | int i; | ||
2759 | |||
2760 | if ((p = map) == NULL) | ||
2761 | return 0; | ||
2762 | for (;;) { | ||
2763 | i = find_first_zero_bit(&p->inuse, CARDMAP_WIDTH); | ||
2764 | if (i >= CARDMAP_WIDTH) { | ||
2765 | if (p->parent == NULL) | ||
2766 | return CARDMAP_WIDTH << p->shift; | ||
2767 | p = p->parent; | ||
2768 | i = (nr >> p->shift) & CARDMAP_MASK; | ||
2769 | set_bit(i, &p->inuse); | ||
2770 | continue; | ||
2771 | } | ||
2772 | nr = (nr & (~CARDMAP_MASK << p->shift)) | (i << p->shift); | ||
2773 | if (p->shift == 0 || p->ptr[i] == NULL) | ||
2774 | return nr; | ||
2775 | p = p->ptr[i]; | ||
2776 | } | ||
2777 | } | 2706 | } |
2778 | 2707 | ||
2779 | static void cardmap_destroy(struct cardmap **pmap) | 2708 | /* get pointer associated with the number */ |
2709 | static void *unit_find(struct idr *p, int n) | ||
2780 | { | 2710 | { |
2781 | struct cardmap *p, *np; | 2711 | return idr_find(p, n); |
2782 | int i; | ||
2783 | |||
2784 | for (p = *pmap; p != NULL; p = np) { | ||
2785 | if (p->shift != 0) { | ||
2786 | for (i = 0; i < CARDMAP_WIDTH; ++i) | ||
2787 | if (p->ptr[i] != NULL) | ||
2788 | break; | ||
2789 | if (i < CARDMAP_WIDTH) { | ||
2790 | np = p->ptr[i]; | ||
2791 | p->ptr[i] = NULL; | ||
2792 | continue; | ||
2793 | } | ||
2794 | } | ||
2795 | np = p->parent; | ||
2796 | kfree(p); | ||
2797 | } | ||
2798 | *pmap = NULL; | ||
2799 | } | 2712 | } |
2800 | 2713 | ||
2801 | /* Module/initialization stuff */ | 2714 | /* Module/initialization stuff */ |