aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/cnic.c
diff options
context:
space:
mode:
authorMichael Chan <mchan@broadcom.com>2009-08-14 11:49:46 -0400
committerDavid S. Miller <davem@davemloft.net>2009-08-15 21:50:44 -0400
commit681dbd710779e8b8d5bae926f6b11f30df70638b (patch)
tree50605514ea7316f8a6316a93e205c0c9a3fb4399 /drivers/net/cnic.c
parentc5a889508203446c1abc1d670599b3a816841813 (diff)
cnic: Fix locking in start/stop calls.
The slow path ulp_start and ulp_stop calls to the bnx2i driver are sleepable calls and therefore should not be protected using rcu_read_lock. Fix it by using mutex and setting a bit during these calls. cnic_unregister_device() will now wait for the bit to clear before completing the call. Signed-off-by: Michael Chan <mchan@broadcom.com> Reviewed-by: Benjamin Li <benli@broadcom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/cnic.c')
-rw-r--r--drivers/net/cnic.c44
1 files changed, 28 insertions, 16 deletions
diff --git a/drivers/net/cnic.c b/drivers/net/cnic.c
index 2db81f0e4f72..4ff618a7afd2 100644
--- a/drivers/net/cnic.c
+++ b/drivers/net/cnic.c
@@ -466,6 +466,7 @@ EXPORT_SYMBOL(cnic_register_driver);
466static int cnic_unregister_device(struct cnic_dev *dev, int ulp_type) 466static int cnic_unregister_device(struct cnic_dev *dev, int ulp_type)
467{ 467{
468 struct cnic_local *cp = dev->cnic_priv; 468 struct cnic_local *cp = dev->cnic_priv;
469 int i = 0;
469 470
470 if (ulp_type >= MAX_CNIC_ULP_TYPE) { 471 if (ulp_type >= MAX_CNIC_ULP_TYPE) {
471 printk(KERN_ERR PFX "cnic_unregister_device: Bad type %d\n", 472 printk(KERN_ERR PFX "cnic_unregister_device: Bad type %d\n",
@@ -486,6 +487,15 @@ static int cnic_unregister_device(struct cnic_dev *dev, int ulp_type)
486 487
487 synchronize_rcu(); 488 synchronize_rcu();
488 489
490 while (test_bit(ULP_F_CALL_PENDING, &cp->ulp_flags[ulp_type]) &&
491 i < 20) {
492 msleep(100);
493 i++;
494 }
495 if (test_bit(ULP_F_CALL_PENDING, &cp->ulp_flags[ulp_type]))
496 printk(KERN_WARNING PFX "%s: Failed waiting for ULP up call"
497 " to complete.\n", dev->netdev->name);
498
489 return 0; 499 return 0;
490} 500}
491EXPORT_SYMBOL(cnic_unregister_driver); 501EXPORT_SYMBOL(cnic_unregister_driver);
@@ -1076,18 +1086,23 @@ static void cnic_ulp_stop(struct cnic_dev *dev)
1076 if (cp->cnic_uinfo) 1086 if (cp->cnic_uinfo)
1077 cnic_send_nlmsg(cp, ISCSI_KEVENT_IF_DOWN, NULL); 1087 cnic_send_nlmsg(cp, ISCSI_KEVENT_IF_DOWN, NULL);
1078 1088
1079 rcu_read_lock();
1080 for (if_type = 0; if_type < MAX_CNIC_ULP_TYPE; if_type++) { 1089 for (if_type = 0; if_type < MAX_CNIC_ULP_TYPE; if_type++) {
1081 struct cnic_ulp_ops *ulp_ops; 1090 struct cnic_ulp_ops *ulp_ops;
1082 1091
1083 ulp_ops = rcu_dereference(cp->ulp_ops[if_type]); 1092 mutex_lock(&cnic_lock);
1084 if (!ulp_ops) 1093 ulp_ops = cp->ulp_ops[if_type];
1094 if (!ulp_ops) {
1095 mutex_unlock(&cnic_lock);
1085 continue; 1096 continue;
1097 }
1098 set_bit(ULP_F_CALL_PENDING, &cp->ulp_flags[if_type]);
1099 mutex_unlock(&cnic_lock);
1086 1100
1087 if (test_and_clear_bit(ULP_F_START, &cp->ulp_flags[if_type])) 1101 if (test_and_clear_bit(ULP_F_START, &cp->ulp_flags[if_type]))
1088 ulp_ops->cnic_stop(cp->ulp_handle[if_type]); 1102 ulp_ops->cnic_stop(cp->ulp_handle[if_type]);
1103
1104 clear_bit(ULP_F_CALL_PENDING, &cp->ulp_flags[if_type]);
1089 } 1105 }
1090 rcu_read_unlock();
1091} 1106}
1092 1107
1093static void cnic_ulp_start(struct cnic_dev *dev) 1108static void cnic_ulp_start(struct cnic_dev *dev)
@@ -1095,18 +1110,23 @@ static void cnic_ulp_start(struct cnic_dev *dev)
1095 struct cnic_local *cp = dev->cnic_priv; 1110 struct cnic_local *cp = dev->cnic_priv;
1096 int if_type; 1111 int if_type;
1097 1112
1098 rcu_read_lock();
1099 for (if_type = 0; if_type < MAX_CNIC_ULP_TYPE; if_type++) { 1113 for (if_type = 0; if_type < MAX_CNIC_ULP_TYPE; if_type++) {
1100 struct cnic_ulp_ops *ulp_ops; 1114 struct cnic_ulp_ops *ulp_ops;
1101 1115
1102 ulp_ops = rcu_dereference(cp->ulp_ops[if_type]); 1116 mutex_lock(&cnic_lock);
1103 if (!ulp_ops || !ulp_ops->cnic_start) 1117 ulp_ops = cp->ulp_ops[if_type];
1118 if (!ulp_ops || !ulp_ops->cnic_start) {
1119 mutex_unlock(&cnic_lock);
1104 continue; 1120 continue;
1121 }
1122 set_bit(ULP_F_CALL_PENDING, &cp->ulp_flags[if_type]);
1123 mutex_unlock(&cnic_lock);
1105 1124
1106 if (!test_and_set_bit(ULP_F_START, &cp->ulp_flags[if_type])) 1125 if (!test_and_set_bit(ULP_F_START, &cp->ulp_flags[if_type]))
1107 ulp_ops->cnic_start(cp->ulp_handle[if_type]); 1126 ulp_ops->cnic_start(cp->ulp_handle[if_type]);
1127
1128 clear_bit(ULP_F_CALL_PENDING, &cp->ulp_flags[if_type]);
1108 } 1129 }
1109 rcu_read_unlock();
1110} 1130}
1111 1131
1112static int cnic_ctl(void *data, struct cnic_ctl_info *info) 1132static int cnic_ctl(void *data, struct cnic_ctl_info *info)
@@ -1116,22 +1136,18 @@ static int cnic_ctl(void *data, struct cnic_ctl_info *info)
1116 switch (info->cmd) { 1136 switch (info->cmd) {
1117 case CNIC_CTL_STOP_CMD: 1137 case CNIC_CTL_STOP_CMD:
1118 cnic_hold(dev); 1138 cnic_hold(dev);
1119 mutex_lock(&cnic_lock);
1120 1139
1121 cnic_ulp_stop(dev); 1140 cnic_ulp_stop(dev);
1122 cnic_stop_hw(dev); 1141 cnic_stop_hw(dev);
1123 1142
1124 mutex_unlock(&cnic_lock);
1125 cnic_put(dev); 1143 cnic_put(dev);
1126 break; 1144 break;
1127 case CNIC_CTL_START_CMD: 1145 case CNIC_CTL_START_CMD:
1128 cnic_hold(dev); 1146 cnic_hold(dev);
1129 mutex_lock(&cnic_lock);
1130 1147
1131 if (!cnic_start_hw(dev)) 1148 if (!cnic_start_hw(dev))
1132 cnic_ulp_start(dev); 1149 cnic_ulp_start(dev);
1133 1150
1134 mutex_unlock(&cnic_lock);
1135 cnic_put(dev); 1151 cnic_put(dev);
1136 break; 1152 break;
1137 default: 1153 default:
@@ -2667,10 +2683,8 @@ static int cnic_netdev_event(struct notifier_block *this, unsigned long event,
2667 cnic_put(dev); 2683 cnic_put(dev);
2668 goto done; 2684 goto done;
2669 } 2685 }
2670 mutex_lock(&cnic_lock);
2671 if (!cnic_start_hw(dev)) 2686 if (!cnic_start_hw(dev))
2672 cnic_ulp_start(dev); 2687 cnic_ulp_start(dev);
2673 mutex_unlock(&cnic_lock);
2674 } 2688 }
2675 2689
2676 rcu_read_lock(); 2690 rcu_read_lock();
@@ -2689,10 +2703,8 @@ static int cnic_netdev_event(struct notifier_block *this, unsigned long event,
2689 rcu_read_unlock(); 2703 rcu_read_unlock();
2690 2704
2691 if (event == NETDEV_GOING_DOWN) { 2705 if (event == NETDEV_GOING_DOWN) {
2692 mutex_lock(&cnic_lock);
2693 cnic_ulp_stop(dev); 2706 cnic_ulp_stop(dev);
2694 cnic_stop_hw(dev); 2707 cnic_stop_hw(dev);
2695 mutex_unlock(&cnic_lock);
2696 cnic_unregister_netdev(dev); 2708 cnic_unregister_netdev(dev);
2697 } else if (event == NETDEV_UNREGISTER) { 2709 } else if (event == NETDEV_UNREGISTER) {
2698 write_lock(&cnic_dev_lock); 2710 write_lock(&cnic_dev_lock);