Skip to content

Commit 7d7195a

Browse files
Juliet Kimdavem330
authored andcommitted
ibmvnic: Do not process device remove during device reset
The ibmvnic driver does not check the device state when the device is removed. If the device is removed while a device reset is being processed, the remove may free structures needed by the reset, causing an oops. Fix this by checking the device state before processing device remove. Signed-off-by: Juliet Kim <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent ece0d7b commit 7d7195a

File tree

2 files changed

+27
-3
lines changed

2 files changed

+27
-3
lines changed

drivers/net/ethernet/ibm/ibmvnic.c

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2142,6 +2142,8 @@ static void __ibmvnic_reset(struct work_struct *work)
21422142
{
21432143
struct ibmvnic_rwi *rwi;
21442144
struct ibmvnic_adapter *adapter;
2145+
bool saved_state = false;
2146+
unsigned long flags;
21452147
u32 reset_state;
21462148
int rc = 0;
21472149

@@ -2153,17 +2155,25 @@ static void __ibmvnic_reset(struct work_struct *work)
21532155
return;
21542156
}
21552157

2156-
reset_state = adapter->state;
2157-
21582158
rwi = get_next_rwi(adapter);
21592159
while (rwi) {
2160+
spin_lock_irqsave(&adapter->state_lock, flags);
2161+
21602162
if (adapter->state == VNIC_REMOVING ||
21612163
adapter->state == VNIC_REMOVED) {
2164+
spin_unlock_irqrestore(&adapter->state_lock, flags);
21622165
kfree(rwi);
21632166
rc = EBUSY;
21642167
break;
21652168
}
21662169

2170+
if (!saved_state) {
2171+
reset_state = adapter->state;
2172+
adapter->state = VNIC_RESETTING;
2173+
saved_state = true;
2174+
}
2175+
spin_unlock_irqrestore(&adapter->state_lock, flags);
2176+
21672177
if (rwi->reset_reason == VNIC_RESET_CHANGE_PARAM) {
21682178
/* CHANGE_PARAM requestor holds rtnl_lock */
21692179
rc = do_change_param_reset(adapter, rwi, reset_state);
@@ -5091,6 +5101,7 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
50915101
__ibmvnic_delayed_reset);
50925102
INIT_LIST_HEAD(&adapter->rwi_list);
50935103
spin_lock_init(&adapter->rwi_lock);
5104+
spin_lock_init(&adapter->state_lock);
50945105
mutex_init(&adapter->fw_lock);
50955106
init_completion(&adapter->init_done);
50965107
init_completion(&adapter->fw_done);
@@ -5163,8 +5174,17 @@ static int ibmvnic_remove(struct vio_dev *dev)
51635174
{
51645175
struct net_device *netdev = dev_get_drvdata(&dev->dev);
51655176
struct ibmvnic_adapter *adapter = netdev_priv(netdev);
5177+
unsigned long flags;
5178+
5179+
spin_lock_irqsave(&adapter->state_lock, flags);
5180+
if (adapter->state == VNIC_RESETTING) {
5181+
spin_unlock_irqrestore(&adapter->state_lock, flags);
5182+
return -EBUSY;
5183+
}
51665184

51675185
adapter->state = VNIC_REMOVING;
5186+
spin_unlock_irqrestore(&adapter->state_lock, flags);
5187+
51685188
rtnl_lock();
51695189
unregister_netdevice(netdev);
51705190

drivers/net/ethernet/ibm/ibmvnic.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -941,7 +941,8 @@ enum vnic_state {VNIC_PROBING = 1,
941941
VNIC_CLOSING,
942942
VNIC_CLOSED,
943943
VNIC_REMOVING,
944-
VNIC_REMOVED};
944+
VNIC_REMOVED,
945+
VNIC_RESETTING};
945946

946947
enum ibmvnic_reset_reason {VNIC_RESET_FAILOVER = 1,
947948
VNIC_RESET_MOBILITY,
@@ -1090,4 +1091,7 @@ struct ibmvnic_adapter {
10901091

10911092
struct ibmvnic_tunables desired;
10921093
struct ibmvnic_tunables fallback;
1094+
1095+
/* Used for serializatin of state field */
1096+
spinlock_t state_lock;
10931097
};

0 commit comments

Comments
 (0)