Commit 7a95d267 authored by Cyrill Gorcunov's avatar Cyrill Gorcunov Committed by David S. Miller

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: default avatarCyrill Gorcunov <gorcunov@openvz.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent c0700f90
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <linux/kmod.h> #include <linux/kmod.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/idr.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/poll.h> #include <linux/poll.h>
#include <linux/ppp_defs.h> #include <linux/ppp_defs.h>
...@@ -171,36 +172,14 @@ struct channel { ...@@ -171,36 +172,14 @@ struct channel {
* channel.downl. * channel.downl.
*/ */
/*
* A cardmap represents a mapping from unsigned integers to pointers,
* and provides a fast "find lowest unused number" operation.
* It uses a broad (32-way) tree with a bitmap at each level.
* It is designed to be space-efficient for small numbers of entries
* and time-efficient for large numbers of entries.
*/
#define CARDMAP_ORDER 5
#define CARDMAP_WIDTH (1U << CARDMAP_ORDER)
#define CARDMAP_MASK (CARDMAP_WIDTH - 1)
struct cardmap {
int shift;
unsigned long inuse;
struct cardmap *parent;
void *ptr[CARDMAP_WIDTH];
};
static void *cardmap_get(struct cardmap *map, unsigned int nr);
static int cardmap_set(struct cardmap **map, unsigned int nr, void *ptr);
static unsigned int cardmap_find_first_free(struct cardmap *map);
static void cardmap_destroy(struct cardmap **map);
/* /*
* all_ppp_mutex protects the all_ppp_units mapping. * all_ppp_mutex protects the all_ppp_units mapping.
* It also ensures that finding a ppp unit in the all_ppp_units map * It also ensures that finding a ppp unit in the all_ppp_units map
* and updating its file.refcnt field is atomic. * and updating its file.refcnt field is atomic.
*/ */
static DEFINE_MUTEX(all_ppp_mutex); static DEFINE_MUTEX(all_ppp_mutex);
static struct cardmap *all_ppp_units;
static atomic_t ppp_unit_count = ATOMIC_INIT(0); static atomic_t ppp_unit_count = ATOMIC_INIT(0);
static struct idr ppp_units_idr;
/* /*
* all_channels_lock protects all_channels and last_channel_index, * all_channels_lock protects all_channels and last_channel_index,
...@@ -269,6 +248,9 @@ static struct channel *ppp_find_channel(int unit); ...@@ -269,6 +248,9 @@ static struct channel *ppp_find_channel(int unit);
static int ppp_connect_channel(struct channel *pch, int unit); static int ppp_connect_channel(struct channel *pch, int unit);
static int ppp_disconnect_channel(struct channel *pch); static int ppp_disconnect_channel(struct channel *pch);
static void ppp_destroy_channel(struct channel *pch); static void ppp_destroy_channel(struct channel *pch);
static int unit_get(struct idr *p, void *ptr);
static void unit_put(struct idr *p, int n);
static void *unit_find(struct idr *p, int n);
static struct class *ppp_class; static struct class *ppp_class;
...@@ -870,6 +852,8 @@ static int __init ppp_init(void) ...@@ -870,6 +852,8 @@ static int __init ppp_init(void)
"ppp"); "ppp");
} }
idr_init(&ppp_units_idr);
out: out:
if (err) if (err)
printk(KERN_ERR "failed to register PPP device (%d)\n", err); printk(KERN_ERR "failed to register PPP device (%d)\n", err);
...@@ -2440,10 +2424,22 @@ ppp_create_interface(int unit, int *retp) ...@@ -2440,10 +2424,22 @@ ppp_create_interface(int unit, int *retp)
ret = -EEXIST; ret = -EEXIST;
mutex_lock(&all_ppp_mutex); mutex_lock(&all_ppp_mutex);
if (unit < 0)
unit = cardmap_find_first_free(all_ppp_units); if (unit < 0) {
else if (cardmap_get(all_ppp_units, unit) != NULL) unit = unit_get(&ppp_units_idr, ppp);
goto out2; /* unit already exists */ if (unit < 0) {
*retp = unit;
goto out2;
}
} else {
if (unit_find(&ppp_units_idr, unit))
goto out2; /* unit already exists */
else {
/* darn, someone is cheatting us? */
*retp = -EINVAL;
goto out2;
}
}
/* Initialize the new ppp unit */ /* Initialize the new ppp unit */
ppp->file.index = unit; ppp->file.index = unit;
...@@ -2451,23 +2447,18 @@ ppp_create_interface(int unit, int *retp) ...@@ -2451,23 +2447,18 @@ ppp_create_interface(int unit, int *retp)
ret = register_netdev(dev); ret = register_netdev(dev);
if (ret != 0) { if (ret != 0) {
unit_put(&ppp_units_idr, unit);
printk(KERN_ERR "PPP: couldn't register device %s (%d)\n", printk(KERN_ERR "PPP: couldn't register device %s (%d)\n",
dev->name, ret); dev->name, ret);
goto out2; goto out2;
} }
atomic_inc(&ppp_unit_count); atomic_inc(&ppp_unit_count);
ret = cardmap_set(&all_ppp_units, unit, ppp);
if (ret != 0)
goto out3;
mutex_unlock(&all_ppp_mutex); mutex_unlock(&all_ppp_mutex);
*retp = 0; *retp = 0;
return ppp; return ppp;
out3:
atomic_dec(&ppp_unit_count);
unregister_netdev(dev);
out2: out2:
mutex_unlock(&all_ppp_mutex); mutex_unlock(&all_ppp_mutex);
free_netdev(dev); free_netdev(dev);
...@@ -2507,7 +2498,7 @@ static void ppp_shutdown_interface(struct ppp *ppp) ...@@ -2507,7 +2498,7 @@ static void ppp_shutdown_interface(struct ppp *ppp)
unregister_netdev(dev); unregister_netdev(dev);
free_netdev(dev); free_netdev(dev);
} }
cardmap_set(&all_ppp_units, ppp->file.index, NULL); unit_put(&ppp_units_idr, ppp->file.index);
ppp->file.dead = 1; ppp->file.dead = 1;
ppp->owner = NULL; ppp->owner = NULL;
wake_up_interruptible(&ppp->file.rwait); wake_up_interruptible(&ppp->file.rwait);
...@@ -2561,7 +2552,7 @@ static void ppp_destroy_interface(struct ppp *ppp) ...@@ -2561,7 +2552,7 @@ static void ppp_destroy_interface(struct ppp *ppp)
static struct ppp * static struct ppp *
ppp_find_unit(int unit) ppp_find_unit(int unit)
{ {
return cardmap_get(all_ppp_units, unit); return unit_find(&ppp_units_idr, unit);
} }
/* /*
...@@ -2679,123 +2670,45 @@ static void __exit ppp_cleanup(void) ...@@ -2679,123 +2670,45 @@ static void __exit ppp_cleanup(void)
/* should never happen */ /* should never happen */
if (atomic_read(&ppp_unit_count) || atomic_read(&channel_count)) if (atomic_read(&ppp_unit_count) || atomic_read(&channel_count))
printk(KERN_ERR "PPP: removing module but units remain!\n"); printk(KERN_ERR "PPP: removing module but units remain!\n");
cardmap_destroy(&all_ppp_units);
unregister_chrdev(PPP_MAJOR, "ppp"); unregister_chrdev(PPP_MAJOR, "ppp");
device_destroy(ppp_class, MKDEV(PPP_MAJOR, 0)); device_destroy(ppp_class, MKDEV(PPP_MAJOR, 0));
class_destroy(ppp_class); class_destroy(ppp_class);
idr_destroy(&ppp_units_idr);
} }
/* /*
* Cardmap implementation. * Units handling. Caller must protect concurrent access
* by holding all_ppp_mutex
*/ */
static void *cardmap_get(struct cardmap *map, unsigned int nr)
/* get new free unit number and associate pointer with it */
static int unit_get(struct idr *p, void *ptr)
{ {
struct cardmap *p; int unit, err;
int i;
for (p = map; p != NULL; ) { again:
if ((i = nr >> p->shift) >= CARDMAP_WIDTH) if (idr_pre_get(p, GFP_KERNEL) == 0) {
return NULL; printk(KERN_ERR "Out of memory expanding drawable idr\n");
if (p->shift == 0) return -ENOMEM;
return p->ptr[i];
nr &= ~(CARDMAP_MASK << p->shift);
p = p->ptr[i];
} }
return NULL;
}
static int cardmap_set(struct cardmap **pmap, unsigned int nr, void *ptr) err = idr_get_new_above(p, ptr, 0, &unit);
{ if (err == -EAGAIN)
struct cardmap *p; goto again;
int i;
p = *pmap; return unit;
if (p == NULL || (nr >> p->shift) >= CARDMAP_WIDTH) {
do {
/* need a new top level */
struct cardmap *np = kzalloc(sizeof(*np), GFP_KERNEL);
if (!np)
goto enomem;
np->ptr[0] = p;
if (p != NULL) {
np->shift = p->shift + CARDMAP_ORDER;
p->parent = np;
} else
np->shift = 0;
p = np;
} while ((nr >> p->shift) >= CARDMAP_WIDTH);
*pmap = p;
}
while (p->shift > 0) {
i = (nr >> p->shift) & CARDMAP_MASK;
if (p->ptr[i] == NULL) {
struct cardmap *np = kzalloc(sizeof(*np), GFP_KERNEL);
if (!np)
goto enomem;
np->shift = p->shift - CARDMAP_ORDER;
np->parent = p;
p->ptr[i] = np;
}
if (ptr == NULL)
clear_bit(i, &p->inuse);
p = p->ptr[i];
}
i = nr & CARDMAP_MASK;
p->ptr[i] = ptr;
if (ptr != NULL)
set_bit(i, &p->inuse);
else
clear_bit(i, &p->inuse);
return 0;
enomem:
return -ENOMEM;
} }
static unsigned int cardmap_find_first_free(struct cardmap *map) /* put unit number back to a pool */
static void unit_put(struct idr *p, int n)
{ {
struct cardmap *p; idr_remove(p, n);
unsigned int nr = 0;
int i;
if ((p = map) == NULL)
return 0;
for (;;) {
i = find_first_zero_bit(&p->inuse, CARDMAP_WIDTH);
if (i >= CARDMAP_WIDTH) {
if (p->parent == NULL)
return CARDMAP_WIDTH << p->shift;
p = p->parent;
i = (nr >> p->shift) & CARDMAP_MASK;
set_bit(i, &p->inuse);
continue;
}
nr = (nr & (~CARDMAP_MASK << p->shift)) | (i << p->shift);
if (p->shift == 0 || p->ptr[i] == NULL)
return nr;
p = p->ptr[i];
}
} }
static void cardmap_destroy(struct cardmap **pmap) /* get pointer associated with the number */
static void *unit_find(struct idr *p, int n)
{ {
struct cardmap *p, *np; return idr_find(p, n);
int i;
for (p = *pmap; p != NULL; p = np) {
if (p->shift != 0) {
for (i = 0; i < CARDMAP_WIDTH; ++i)
if (p->ptr[i] != NULL)
break;
if (i < CARDMAP_WIDTH) {
np = p->ptr[i];
p->ptr[i] = NULL;
continue;
}
}
np = p->parent;
kfree(p);
}
*pmap = NULL;
} }
/* Module/initialization stuff */ /* Module/initialization stuff */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment