diff options
author | Tim Sell <Timothy.Sell@unisys.com> | 2015-07-09 13:27:52 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2015-07-14 18:34:59 -0700 |
commit | 8d0119d8e81f93cf3c1bc2b6e7a39e28620cda1a (patch) | |
tree | eb5937e25c016c25ecb3c9897b38ebc1be4bc9aa /drivers/staging/unisys | |
parent | 051e9fbbba1594331a9b3b2b157b5a0ce54b9a43 (diff) | |
download | linux-8d0119d8e81f93cf3c1bc2b6e7a39e28620cda1a.tar.bz2 |
staging: unisys: visornic: prevent erroneous kfree of devdata pointer
A struct visornic_devdata for each visornic device is actually allocated as
part of alloc_etherdev(), here in visornic_probe():
netdev = alloc_etherdev(sizeof(struct visornic_devdata));
But code in devdata_release() was treating devdata as a pointer that needed
to be kfree()d! This was causing all sorts of weird behavior after doing
an rmmod of visornic, both because free_netdev() was actually freeing the
memory used for devdata, and because devdata wasn't pointing to
dynamically-allocated memory in the first place.
The kfree(devdata) and the kref that tracked devdata's usage have been
appropriately deleted.
Signed-off-by: Tim Sell <Timothy.Sell@unisys.com>
Signed-off-by: Benjamin Romer <benjamin.romer@unisys.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/staging/unisys')
-rw-r--r-- | drivers/staging/unisys/visornic/visornic_main.c | 20 |
1 files changed, 6 insertions, 14 deletions
diff --git a/drivers/staging/unisys/visornic/visornic_main.c b/drivers/staging/unisys/visornic/visornic_main.c index 9b3c5d876b86..9350473a732b 100644 --- a/drivers/staging/unisys/visornic/visornic_main.c +++ b/drivers/staging/unisys/visornic/visornic_main.c @@ -119,7 +119,6 @@ struct visornic_devdata { struct visor_device *dev; char name[99]; struct list_head list_all; /* < link within list_all_devices list */ - struct kref kref; struct net_device *netdev; struct net_device_stats net_stats; atomic_t interrupt_rcvd; @@ -1602,14 +1601,11 @@ devdata_initialize(struct visornic_devdata *devdata, struct visor_device *dev) spin_unlock(&dev_num_pool_lock); if (devnum == MAXDEVICES) devnum = -1; - if (devnum < 0) { - kfree(devdata); + if (devnum < 0) return NULL; - } devdata->devnum = devnum; devdata->dev = dev; strncpy(devdata->name, dev_name(&dev->device), sizeof(devdata->name)); - kref_init(&devdata->kref); spin_lock(&lock_all_devices); list_add_tail(&devdata->list_all, &list_all_devices); spin_unlock(&lock_all_devices); @@ -1617,17 +1613,14 @@ devdata_initialize(struct visornic_devdata *devdata, struct visor_device *dev) } /** - * devdata_release - Frees up a devdata - * @mykref: kref to the devdata + * devdata_release - Frees up references in devdata + * @devdata: struct to clean up * - * Frees up a devdata. + * Frees up references in devdata. * Returns void */ -static void devdata_release(struct kref *mykref) +static void devdata_release(struct visornic_devdata *devdata) { - struct visornic_devdata *devdata = - container_of(mykref, struct visornic_devdata, kref); - spin_lock(&dev_num_pool_lock); clear_bit(devdata->devnum, dev_num_pool); spin_unlock(&dev_num_pool_lock); @@ -1637,7 +1630,6 @@ static void devdata_release(struct kref *mykref) kfree(devdata->rcvbuf); kfree(devdata->cmdrsp_rcv); kfree(devdata->xmit_cmdrsp); - kfree(devdata); } static const struct net_device_ops visornic_dev_ops = { @@ -2089,8 +2081,8 @@ static void visornic_remove(struct visor_device *dev) dev_set_drvdata(&dev->device, NULL); host_side_disappeared(devdata); + devdata_release(devdata); free_netdev(netdev); - kref_put(&devdata->kref, devdata_release); } /** |