Commit 6cbe7210 authored by David S. Miller's avatar David S. Miller

Merge branch 'ibmvnic-Fix-reset-work-item-locking-bugs'

Thomas Falcon says:

====================
net/ibmvnic: Fix reset work item locking bugs

This patch set fixes issues with scheduling reset work items in
a tasklet context. Since ibmvnic_reset can called in an interrupt,
it should not use a mutex or allocate memory non-atomically.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 5648451e 1d1bbc37
...@@ -1939,8 +1939,9 @@ static int do_hard_reset(struct ibmvnic_adapter *adapter, ...@@ -1939,8 +1939,9 @@ static int do_hard_reset(struct ibmvnic_adapter *adapter,
static struct ibmvnic_rwi *get_next_rwi(struct ibmvnic_adapter *adapter) static struct ibmvnic_rwi *get_next_rwi(struct ibmvnic_adapter *adapter)
{ {
struct ibmvnic_rwi *rwi; struct ibmvnic_rwi *rwi;
unsigned long flags;
mutex_lock(&adapter->rwi_lock); spin_lock_irqsave(&adapter->rwi_lock, flags);
if (!list_empty(&adapter->rwi_list)) { if (!list_empty(&adapter->rwi_list)) {
rwi = list_first_entry(&adapter->rwi_list, struct ibmvnic_rwi, rwi = list_first_entry(&adapter->rwi_list, struct ibmvnic_rwi,
...@@ -1950,7 +1951,7 @@ static struct ibmvnic_rwi *get_next_rwi(struct ibmvnic_adapter *adapter) ...@@ -1950,7 +1951,7 @@ static struct ibmvnic_rwi *get_next_rwi(struct ibmvnic_adapter *adapter)
rwi = NULL; rwi = NULL;
} }
mutex_unlock(&adapter->rwi_lock); spin_unlock_irqrestore(&adapter->rwi_lock, flags);
return rwi; return rwi;
} }
...@@ -2025,6 +2026,7 @@ static int ibmvnic_reset(struct ibmvnic_adapter *adapter, ...@@ -2025,6 +2026,7 @@ static int ibmvnic_reset(struct ibmvnic_adapter *adapter,
struct list_head *entry, *tmp_entry; struct list_head *entry, *tmp_entry;
struct ibmvnic_rwi *rwi, *tmp; struct ibmvnic_rwi *rwi, *tmp;
struct net_device *netdev = adapter->netdev; struct net_device *netdev = adapter->netdev;
unsigned long flags;
int ret; int ret;
if (adapter->state == VNIC_REMOVING || if (adapter->state == VNIC_REMOVING ||
...@@ -2041,21 +2043,21 @@ static int ibmvnic_reset(struct ibmvnic_adapter *adapter, ...@@ -2041,21 +2043,21 @@ static int ibmvnic_reset(struct ibmvnic_adapter *adapter,
goto err; goto err;
} }
mutex_lock(&adapter->rwi_lock); spin_lock_irqsave(&adapter->rwi_lock, flags);
list_for_each(entry, &adapter->rwi_list) { list_for_each(entry, &adapter->rwi_list) {
tmp = list_entry(entry, struct ibmvnic_rwi, list); tmp = list_entry(entry, struct ibmvnic_rwi, list);
if (tmp->reset_reason == reason) { if (tmp->reset_reason == reason) {
netdev_dbg(netdev, "Skipping matching reset\n"); netdev_dbg(netdev, "Skipping matching reset\n");
mutex_unlock(&adapter->rwi_lock); spin_unlock_irqrestore(&adapter->rwi_lock, flags);
ret = EBUSY; ret = EBUSY;
goto err; goto err;
} }
} }
rwi = kzalloc(sizeof(*rwi), GFP_KERNEL); rwi = kzalloc(sizeof(*rwi), GFP_ATOMIC);
if (!rwi) { if (!rwi) {
mutex_unlock(&adapter->rwi_lock); spin_unlock_irqrestore(&adapter->rwi_lock, flags);
ibmvnic_close(netdev); ibmvnic_close(netdev);
ret = ENOMEM; ret = ENOMEM;
goto err; goto err;
...@@ -2069,7 +2071,7 @@ static int ibmvnic_reset(struct ibmvnic_adapter *adapter, ...@@ -2069,7 +2071,7 @@ static int ibmvnic_reset(struct ibmvnic_adapter *adapter,
} }
rwi->reset_reason = reason; rwi->reset_reason = reason;
list_add_tail(&rwi->list, &adapter->rwi_list); list_add_tail(&rwi->list, &adapter->rwi_list);
mutex_unlock(&adapter->rwi_lock); spin_unlock_irqrestore(&adapter->rwi_lock, flags);
adapter->resetting = true; adapter->resetting = true;
netdev_dbg(adapter->netdev, "Scheduling reset (reason %d)\n", reason); netdev_dbg(adapter->netdev, "Scheduling reset (reason %d)\n", reason);
schedule_work(&adapter->ibmvnic_reset); schedule_work(&adapter->ibmvnic_reset);
...@@ -4759,7 +4761,7 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id) ...@@ -4759,7 +4761,7 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
INIT_WORK(&adapter->ibmvnic_reset, __ibmvnic_reset); INIT_WORK(&adapter->ibmvnic_reset, __ibmvnic_reset);
INIT_LIST_HEAD(&adapter->rwi_list); INIT_LIST_HEAD(&adapter->rwi_list);
mutex_init(&adapter->rwi_lock); spin_lock_init(&adapter->rwi_lock);
adapter->resetting = false; adapter->resetting = false;
adapter->mac_change_pending = false; adapter->mac_change_pending = false;
......
...@@ -1075,7 +1075,7 @@ struct ibmvnic_adapter { ...@@ -1075,7 +1075,7 @@ struct ibmvnic_adapter {
struct tasklet_struct tasklet; struct tasklet_struct tasklet;
enum vnic_state state; enum vnic_state state;
enum ibmvnic_reset_reason reset_reason; enum ibmvnic_reset_reason reset_reason;
struct mutex rwi_lock; spinlock_t rwi_lock;
struct list_head rwi_list; struct list_head rwi_list;
struct work_struct ibmvnic_reset; struct work_struct ibmvnic_reset;
bool resetting; bool resetting;
......
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