diff options
Diffstat (limited to 'drivers/scsi/cxgbi/libcxgbi.c')
-rw-r--r-- | drivers/scsi/cxgbi/libcxgbi.c | 57 |
1 files changed, 51 insertions, 6 deletions
diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c index d65df6dc106f..addd1dddce14 100644 --- a/drivers/scsi/cxgbi/libcxgbi.c +++ b/drivers/scsi/cxgbi/libcxgbi.c | |||
@@ -57,6 +57,9 @@ MODULE_PARM_DESC(dbg_level, "libiscsi debug level (default=0)"); | |||
57 | static LIST_HEAD(cdev_list); | 57 | static LIST_HEAD(cdev_list); |
58 | static DEFINE_MUTEX(cdev_mutex); | 58 | static DEFINE_MUTEX(cdev_mutex); |
59 | 59 | ||
60 | static LIST_HEAD(cdev_rcu_list); | ||
61 | static DEFINE_SPINLOCK(cdev_rcu_lock); | ||
62 | |||
60 | int cxgbi_device_portmap_create(struct cxgbi_device *cdev, unsigned int base, | 63 | int cxgbi_device_portmap_create(struct cxgbi_device *cdev, unsigned int base, |
61 | unsigned int max_conn) | 64 | unsigned int max_conn) |
62 | { | 65 | { |
@@ -142,6 +145,10 @@ struct cxgbi_device *cxgbi_device_register(unsigned int extra, | |||
142 | list_add_tail(&cdev->list_head, &cdev_list); | 145 | list_add_tail(&cdev->list_head, &cdev_list); |
143 | mutex_unlock(&cdev_mutex); | 146 | mutex_unlock(&cdev_mutex); |
144 | 147 | ||
148 | spin_lock(&cdev_rcu_lock); | ||
149 | list_add_tail_rcu(&cdev->rcu_node, &cdev_rcu_list); | ||
150 | spin_unlock(&cdev_rcu_lock); | ||
151 | |||
145 | log_debug(1 << CXGBI_DBG_DEV, | 152 | log_debug(1 << CXGBI_DBG_DEV, |
146 | "cdev 0x%p, p# %u.\n", cdev, nports); | 153 | "cdev 0x%p, p# %u.\n", cdev, nports); |
147 | return cdev; | 154 | return cdev; |
@@ -153,9 +160,16 @@ void cxgbi_device_unregister(struct cxgbi_device *cdev) | |||
153 | log_debug(1 << CXGBI_DBG_DEV, | 160 | log_debug(1 << CXGBI_DBG_DEV, |
154 | "cdev 0x%p, p# %u,%s.\n", | 161 | "cdev 0x%p, p# %u,%s.\n", |
155 | cdev, cdev->nports, cdev->nports ? cdev->ports[0]->name : ""); | 162 | cdev, cdev->nports, cdev->nports ? cdev->ports[0]->name : ""); |
163 | |||
156 | mutex_lock(&cdev_mutex); | 164 | mutex_lock(&cdev_mutex); |
157 | list_del(&cdev->list_head); | 165 | list_del(&cdev->list_head); |
158 | mutex_unlock(&cdev_mutex); | 166 | mutex_unlock(&cdev_mutex); |
167 | |||
168 | spin_lock(&cdev_rcu_lock); | ||
169 | list_del_rcu(&cdev->rcu_node); | ||
170 | spin_unlock(&cdev_rcu_lock); | ||
171 | synchronize_rcu(); | ||
172 | |||
159 | cxgbi_device_destroy(cdev); | 173 | cxgbi_device_destroy(cdev); |
160 | } | 174 | } |
161 | EXPORT_SYMBOL_GPL(cxgbi_device_unregister); | 175 | EXPORT_SYMBOL_GPL(cxgbi_device_unregister); |
@@ -167,12 +181,9 @@ void cxgbi_device_unregister_all(unsigned int flag) | |||
167 | mutex_lock(&cdev_mutex); | 181 | mutex_lock(&cdev_mutex); |
168 | list_for_each_entry_safe(cdev, tmp, &cdev_list, list_head) { | 182 | list_for_each_entry_safe(cdev, tmp, &cdev_list, list_head) { |
169 | if ((cdev->flags & flag) == flag) { | 183 | if ((cdev->flags & flag) == flag) { |
170 | log_debug(1 << CXGBI_DBG_DEV, | 184 | mutex_unlock(&cdev_mutex); |
171 | "cdev 0x%p, p# %u,%s.\n", | 185 | cxgbi_device_unregister(cdev); |
172 | cdev, cdev->nports, cdev->nports ? | 186 | mutex_lock(&cdev_mutex); |
173 | cdev->ports[0]->name : ""); | ||
174 | list_del(&cdev->list_head); | ||
175 | cxgbi_device_destroy(cdev); | ||
176 | } | 187 | } |
177 | } | 188 | } |
178 | mutex_unlock(&cdev_mutex); | 189 | mutex_unlock(&cdev_mutex); |
@@ -191,6 +202,7 @@ struct cxgbi_device *cxgbi_device_find_by_lldev(void *lldev) | |||
191 | } | 202 | } |
192 | } | 203 | } |
193 | mutex_unlock(&cdev_mutex); | 204 | mutex_unlock(&cdev_mutex); |
205 | |||
194 | log_debug(1 << CXGBI_DBG_DEV, | 206 | log_debug(1 << CXGBI_DBG_DEV, |
195 | "lldev 0x%p, NO match found.\n", lldev); | 207 | "lldev 0x%p, NO match found.\n", lldev); |
196 | return NULL; | 208 | return NULL; |
@@ -230,6 +242,39 @@ struct cxgbi_device *cxgbi_device_find_by_netdev(struct net_device *ndev, | |||
230 | } | 242 | } |
231 | EXPORT_SYMBOL_GPL(cxgbi_device_find_by_netdev); | 243 | EXPORT_SYMBOL_GPL(cxgbi_device_find_by_netdev); |
232 | 244 | ||
245 | struct cxgbi_device *cxgbi_device_find_by_netdev_rcu(struct net_device *ndev, | ||
246 | int *port) | ||
247 | { | ||
248 | struct net_device *vdev = NULL; | ||
249 | struct cxgbi_device *cdev; | ||
250 | int i; | ||
251 | |||
252 | if (ndev->priv_flags & IFF_802_1Q_VLAN) { | ||
253 | vdev = ndev; | ||
254 | ndev = vlan_dev_real_dev(ndev); | ||
255 | pr_info("vlan dev %s -> %s.\n", vdev->name, ndev->name); | ||
256 | } | ||
257 | |||
258 | rcu_read_lock(); | ||
259 | list_for_each_entry_rcu(cdev, &cdev_rcu_list, rcu_node) { | ||
260 | for (i = 0; i < cdev->nports; i++) { | ||
261 | if (ndev == cdev->ports[i]) { | ||
262 | cdev->hbas[i]->vdev = vdev; | ||
263 | rcu_read_unlock(); | ||
264 | if (port) | ||
265 | *port = i; | ||
266 | return cdev; | ||
267 | } | ||
268 | } | ||
269 | } | ||
270 | rcu_read_unlock(); | ||
271 | |||
272 | log_debug(1 << CXGBI_DBG_DEV, | ||
273 | "ndev 0x%p, %s, NO match found.\n", ndev, ndev->name); | ||
274 | return NULL; | ||
275 | } | ||
276 | EXPORT_SYMBOL_GPL(cxgbi_device_find_by_netdev_rcu); | ||
277 | |||
233 | static struct cxgbi_device *cxgbi_device_find_by_mac(struct net_device *ndev, | 278 | static struct cxgbi_device *cxgbi_device_find_by_mac(struct net_device *ndev, |
234 | int *port) | 279 | int *port) |
235 | { | 280 | { |