Moved scst_register() call from srpt_detect() to srpt_add_one(). Added

call to scst_unregister() in srpt_remove_one(). Result:
- The kernel oops triggered by loading the ib_srpt kernel module before
  the InfiniBand subnet manager became active is now fixed.
- It is now possible to log in via the SRP protocol through HCA's that
  became active after the ib_srpt kernel module finished module
  initialization.


git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@878 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Bart Van Assche
2009-05-21 12:34:11 +00:00
parent 106acdb7d6
commit 7519550fcb

View File

@@ -1496,6 +1496,7 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id,
(unsigned long long)be64_to_cpu(*(u64 *)ch->i_port_id),
(unsigned long long)be64_to_cpu(*(u64 *)(ch->i_port_id + 8)));
BUG_ON(!sdev->scst_tgt);
ch->scst_sess = scst_register_session(sdev->scst_tgt, 0, ch->sess_name,
NULL, NULL);
if (!ch->scst_sess) {
@@ -2148,49 +2149,26 @@ static void srpt_refresh_port_work(struct work_struct *work)
static int srpt_detect(struct scst_tgt_template *tp)
{
struct srpt_device *sdev;
struct srpt_port *sport;
int i;
int count = 0;
list_for_each_entry(sdev, &srpt_devices, list) {
sdev->scst_tgt = scst_register(tp, NULL);
if (!sdev->scst_tgt)
goto out;
scst_tgt_set_tgt_priv(sdev->scst_tgt, sdev);
for (i = 1; i <= sdev->device->phys_port_cnt; i++) {
sport = &sdev->port[i - 1];
sport->sdev = sdev;
sport->port = i;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) && ! defined(BACKPORT_LINUX_WORKQUEUE_TO_2_6_19)
INIT_WORK(&sport->work, srpt_refresh_port_work, sport);
#else
INIT_WORK(&sport->work, srpt_refresh_port_work);
#endif
if (srpt_refresh_port(sport)) {
scst_unregister(sdev->scst_tgt);
goto out;
}
}
list_for_each_entry(sdev, &srpt_devices, list)
++count;
}
out:
return count;
}
/*
* Called by the SCST core to free up the resources associated with device
* 'scst_tgt'.
* Callback function called by the SCST core from scst_unregister() to free up
* the resources associated with device scst_tgt.
*/
static int srpt_release(struct scst_tgt *scst_tgt)
{
struct srpt_device *sdev = scst_tgt_get_tgt_priv(scst_tgt);
struct srpt_rdma_ch *ch, *tmp_ch;
BUG_ON(!scst_tgt);
if (WARN_ON(!sdev))
return -ENODEV;
list_for_each_entry_safe(ch, tmp_ch, &sdev->rch_list, list)
srpt_release_channel(ch, 1);
@@ -2357,6 +2335,7 @@ static DEVICE_ATTR(login_info, S_IRUGO, show_login_info, NULL);
static void srpt_add_one(struct ib_device *device)
{
struct srpt_device *sdev;
struct srpt_port *sport;
struct ib_srq_init_attr srq_attr;
int i;
@@ -2457,8 +2436,39 @@ static void srpt_add_one(struct ib_device *device)
ib_set_client_data(device, &srpt_client, sdev);
sdev->scst_tgt = scst_register(&srpt_template, NULL);
if (!sdev->scst_tgt) {
printk(KERN_ERR PFX "SCST registration failed for %s.\n",
sdev->device->name);
goto err_ring;
}
scst_tgt_set_tgt_priv(sdev->scst_tgt, sdev);
for (i = 1; i <= sdev->device->phys_port_cnt; i++) {
sport = &sdev->port[i - 1];
sport->sdev = sdev;
sport->port = i;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) && ! defined(BACKPORT_LINUX_WORKQUEUE_TO_2_6_19)
INIT_WORK(&sport->work, srpt_refresh_port_work, sport);
#else
INIT_WORK(&sport->work, srpt_refresh_port_work);
#endif
if (srpt_refresh_port(sport)) {
printk(KERN_ERR PFX "MAD registration failed"
" for %s-%d.\n", sdev->device->name, i);
goto err_refresh_port;
}
}
return;
err_refresh_port:
scst_unregister(sdev->scst_tgt);
err_ring:
ib_set_client_data(device, &srpt_client, NULL);
list_del(&sdev->list);
srpt_free_ioctx_ring(sdev);
err_event:
ib_unregister_event_handler(&sdev->event_handler);
err_cm:
@@ -2492,6 +2502,9 @@ static void srpt_remove_one(struct ib_device *device)
if (WARN_ON(!sdev))
return;
scst_unregister(sdev->scst_tgt);
sdev->scst_tgt = NULL;
wait_for_completion(&sdev->scst_released);
ib_unregister_event_handler(&sdev->event_handler);
@@ -2510,6 +2523,14 @@ static void srpt_remove_one(struct ib_device *device)
kfree(sdev);
}
/*
* Module initialization.
*
* Note: since ib_register_client() registers callback functions, and since at
* least one of these callback functions (srpt_add_one()) calls SCST functions,
* the SCST target template must be registered before ib_register_client() is
* called.
*/
static int __init srpt_init_module(void)
{
int ret;
@@ -2522,17 +2543,17 @@ static int __init srpt_init_module(void)
return ret;
}
ret = ib_register_client(&srpt_client);
if (ret) {
printk(KERN_ERR PFX "couldn't register IB client\n");
goto mem_out;
}
ret = scst_register_target_template(&srpt_template);
if (ret < 0) {
printk(KERN_ERR PFX "couldn't register with scst\n");
ret = -ENODEV;
goto ib_out;
goto mem_out;
}
ret = ib_register_client(&srpt_client);
if (ret) {
printk(KERN_ERR PFX "couldn't register IB client\n");
goto scst_out;
}
if (thread) {
@@ -2548,8 +2569,8 @@ static int __init srpt_init_module(void)
return 0;
ib_out:
ib_unregister_client(&srpt_client);
scst_out:
scst_unregister_target_template(&srpt_template);
mem_out:
class_unregister(&srpt_class);
return ret;
@@ -2559,8 +2580,8 @@ static void __exit srpt_cleanup_module(void)
{
if (srpt_thread.thread)
kthread_stop(srpt_thread.thread);
scst_unregister_target_template(&srpt_template);
ib_unregister_client(&srpt_client);
scst_unregister_target_template(&srpt_template);
class_unregister(&srpt_class);
}