aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ppp_generic.c
diff options
context:
space:
mode:
authorCyrill Gorcunov <gorcunov@openvz.org>2008-12-17 03:34:06 -0500
committerDavid S. Miller <davem@davemloft.net>2008-12-17 03:34:06 -0500
commit7a95d267fb62cd6b80ef73be0592bbbe1dbd5df7 (patch)
tree30d280777e087cc9c0e5686fc07c2b7d51af96d7 /drivers/net/ppp_generic.c
parentc0700f90e5300c63d01c70e157e75e4510dd2981 (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>
Diffstat (limited to 'drivers/net/ppp_generic.c')
-rw-r--r--drivers/net/ppp_generic.c183
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
185struct cardmap {
186 int shift;
187 unsigned long inuse;
188 struct cardmap *parent;
189 void *ptr[CARDMAP_WIDTH];
190};
191static void *cardmap_get(struct cardmap *map, unsigned int nr);
192static int cardmap_set(struct cardmap **map, unsigned int nr, void *ptr);
193static unsigned int cardmap_find_first_free(struct cardmap *map);
194static 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 */
201static DEFINE_MUTEX(all_ppp_mutex); 180static DEFINE_MUTEX(all_ppp_mutex);
202static struct cardmap *all_ppp_units;
203static atomic_t ppp_unit_count = ATOMIC_INIT(0); 181static atomic_t ppp_unit_count = ATOMIC_INIT(0);
182static 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);
269static int ppp_connect_channel(struct channel *pch, int unit); 248static int ppp_connect_channel(struct channel *pch, int unit);
270static int ppp_disconnect_channel(struct channel *pch); 249static int ppp_disconnect_channel(struct channel *pch);
271static void ppp_destroy_channel(struct channel *pch); 250static void ppp_destroy_channel(struct channel *pch);
251static int unit_get(struct idr *p, void *ptr);
252static void unit_put(struct idr *p, int n);
253static void *unit_find(struct idr *p, int n);
272 254
273static struct class *ppp_class; 255static 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
873out: 857out:
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
2468out3:
2469 atomic_dec(&ppp_unit_count);
2470 unregister_netdev(dev);
2471out2: 2462out2:
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)
2561static struct ppp * 2552static struct ppp *
2562ppp_find_unit(int unit) 2553ppp_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 */
2691static void *cardmap_get(struct cardmap *map, unsigned int nr) 2683
2684/* get new free unit number and associate pointer with it */
2685static 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; ) { 2689again:
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
2707static 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
2754static unsigned int cardmap_find_first_free(struct cardmap *map) 2702/* put unit number back to a pool */
2703static 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
2779static void cardmap_destroy(struct cardmap **pmap) 2708/* get pointer associated with the number */
2709static 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 */