mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-28 11:18:45 +07:00
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>
This commit is contained in:
parent
051e9fbbba
commit
8d0119d8e8
@ -119,7 +119,6 @@ struct visornic_devdata {
|
|||||||
struct visor_device *dev;
|
struct visor_device *dev;
|
||||||
char name[99];
|
char name[99];
|
||||||
struct list_head list_all; /* < link within list_all_devices list */
|
struct list_head list_all; /* < link within list_all_devices list */
|
||||||
struct kref kref;
|
|
||||||
struct net_device *netdev;
|
struct net_device *netdev;
|
||||||
struct net_device_stats net_stats;
|
struct net_device_stats net_stats;
|
||||||
atomic_t interrupt_rcvd;
|
atomic_t interrupt_rcvd;
|
||||||
@ -1602,14 +1601,11 @@ devdata_initialize(struct visornic_devdata *devdata, struct visor_device *dev)
|
|||||||
spin_unlock(&dev_num_pool_lock);
|
spin_unlock(&dev_num_pool_lock);
|
||||||
if (devnum == MAXDEVICES)
|
if (devnum == MAXDEVICES)
|
||||||
devnum = -1;
|
devnum = -1;
|
||||||
if (devnum < 0) {
|
if (devnum < 0)
|
||||||
kfree(devdata);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
|
||||||
devdata->devnum = devnum;
|
devdata->devnum = devnum;
|
||||||
devdata->dev = dev;
|
devdata->dev = dev;
|
||||||
strncpy(devdata->name, dev_name(&dev->device), sizeof(devdata->name));
|
strncpy(devdata->name, dev_name(&dev->device), sizeof(devdata->name));
|
||||||
kref_init(&devdata->kref);
|
|
||||||
spin_lock(&lock_all_devices);
|
spin_lock(&lock_all_devices);
|
||||||
list_add_tail(&devdata->list_all, &list_all_devices);
|
list_add_tail(&devdata->list_all, &list_all_devices);
|
||||||
spin_unlock(&lock_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
|
* devdata_release - Frees up references in devdata
|
||||||
* @mykref: kref to the devdata
|
* @devdata: struct to clean up
|
||||||
*
|
*
|
||||||
* Frees up a devdata.
|
* Frees up references in devdata.
|
||||||
* Returns void
|
* 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);
|
spin_lock(&dev_num_pool_lock);
|
||||||
clear_bit(devdata->devnum, dev_num_pool);
|
clear_bit(devdata->devnum, dev_num_pool);
|
||||||
spin_unlock(&dev_num_pool_lock);
|
spin_unlock(&dev_num_pool_lock);
|
||||||
@ -1637,7 +1630,6 @@ static void devdata_release(struct kref *mykref)
|
|||||||
kfree(devdata->rcvbuf);
|
kfree(devdata->rcvbuf);
|
||||||
kfree(devdata->cmdrsp_rcv);
|
kfree(devdata->cmdrsp_rcv);
|
||||||
kfree(devdata->xmit_cmdrsp);
|
kfree(devdata->xmit_cmdrsp);
|
||||||
kfree(devdata);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct net_device_ops visornic_dev_ops = {
|
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);
|
dev_set_drvdata(&dev->device, NULL);
|
||||||
host_side_disappeared(devdata);
|
host_side_disappeared(devdata);
|
||||||
|
devdata_release(devdata);
|
||||||
free_netdev(netdev);
|
free_netdev(netdev);
|
||||||
kref_put(&devdata->kref, devdata_release);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user