Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 343680
b: refs/heads/master
c: ef6c49d
h: refs/heads/master
v: v3
  • Loading branch information
Bart Van Assche authored and Roland Dreier committed Dec 1, 2012
1 parent ea9d287 commit 71d2fb8
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 57 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: ee12d6a80cfcd08b862ed3c8e109442e466b0302
refs/heads/master: ef6c49d87c3418c442a22e55e3ce2f91b163d69e
83 changes: 30 additions & 53 deletions trunk/drivers/infiniband/ulp/srp/ib_srp.c
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,23 @@ static int srp_send_req(struct srp_target_port *target)
return status;
}

static bool srp_queue_remove_work(struct srp_target_port *target)
{
bool changed = false;

spin_lock_irq(&target->lock);
if (target->state != SRP_TARGET_REMOVED) {
target->state = SRP_TARGET_REMOVED;
changed = true;
}
spin_unlock_irq(&target->lock);

if (changed)
queue_work(system_long_wq, &target->remove_work);

return changed;
}

static bool srp_change_conn_state(struct srp_target_port *target,
bool connected)
{
Expand Down Expand Up @@ -458,21 +475,6 @@ static void srp_disconnect_target(struct srp_target_port *target)
}
}

static bool srp_change_state(struct srp_target_port *target,
enum srp_target_state old,
enum srp_target_state new)
{
bool changed = false;

spin_lock_irq(&target->lock);
if (target->state == old) {
target->state = new;
changed = true;
}
spin_unlock_irq(&target->lock);
return changed;
}

static void srp_free_req_data(struct srp_target_port *target)
{
struct ib_device *ibdev = target->srp_host->srp_dev->dev;
Expand Down Expand Up @@ -508,9 +510,12 @@ static void srp_del_scsi_host_attr(struct Scsi_Host *shost)

static void srp_remove_target(struct srp_target_port *target)
{
WARN_ON_ONCE(target->state != SRP_TARGET_REMOVED);

srp_del_scsi_host_attr(target->scsi_host);
srp_remove_host(target->scsi_host);
scsi_remove_host(target->scsi_host);
srp_disconnect_target(target);
ib_destroy_cm_id(target->cm_id);
srp_free_target_ib(target);
srp_free_req_data(target);
Expand All @@ -520,10 +525,9 @@ static void srp_remove_target(struct srp_target_port *target)
static void srp_remove_work(struct work_struct *work)
{
struct srp_target_port *target =
container_of(work, struct srp_target_port, work);
container_of(work, struct srp_target_port, remove_work);

if (!srp_change_state(target, SRP_TARGET_DEAD, SRP_TARGET_REMOVED))
return;
WARN_ON_ONCE(target->state != SRP_TARGET_REMOVED);

spin_lock(&target->srp_host->target_lock);
list_del(&target->list);
Expand Down Expand Up @@ -738,17 +742,8 @@ static int srp_reconnect_target(struct srp_target_port *target)
* However, we have to defer the real removal because we
* are in the context of the SCSI error handler now, which
* will deadlock if we call scsi_remove_host().
*
* Schedule our work inside the lock to avoid a race with
* the flush_scheduled_work() in srp_remove_one().
*/
spin_lock_irq(&target->lock);
if (target->state == SRP_TARGET_LIVE) {
target->state = SRP_TARGET_DEAD;
INIT_WORK(&target->work, srp_remove_work);
queue_work(ib_wq, &target->work);
}
spin_unlock_irq(&target->lock);
srp_queue_remove_work(target);

return ret;
}
Expand Down Expand Up @@ -2258,6 +2253,7 @@ static ssize_t srp_create_target(struct device *dev,
sizeof (struct srp_indirect_buf) +
target->cmd_sg_cnt * sizeof (struct srp_direct_buf);

INIT_WORK(&target->remove_work, srp_remove_work);
spin_lock_init(&target->lock);
INIT_LIST_HEAD(&target->free_tx);
INIT_LIST_HEAD(&target->free_reqs);
Expand Down Expand Up @@ -2491,8 +2487,7 @@ static void srp_remove_one(struct ib_device *device)
{
struct srp_device *srp_dev;
struct srp_host *host, *tmp_host;
LIST_HEAD(target_list);
struct srp_target_port *target, *tmp_target;
struct srp_target_port *target;

srp_dev = ib_get_client_data(device, &srp_client);

Expand All @@ -2505,35 +2500,17 @@ static void srp_remove_one(struct ib_device *device)
wait_for_completion(&host->released);

/*
* Mark all target ports as removed, so we stop queueing
* commands and don't try to reconnect.
* Remove all target ports.
*/
spin_lock(&host->target_lock);
list_for_each_entry(target, &host->target_list, list) {
spin_lock_irq(&target->lock);
target->state = SRP_TARGET_REMOVED;
spin_unlock_irq(&target->lock);
}
list_for_each_entry(target, &host->target_list, list)
srp_queue_remove_work(target);
spin_unlock(&host->target_lock);

/*
* Wait for any reconnection tasks that may have
* started before we marked our target ports as
* removed, and any target port removal tasks.
* Wait for target port removal tasks.
*/
flush_workqueue(ib_wq);

list_for_each_entry_safe(target, tmp_target,
&host->target_list, list) {
srp_del_scsi_host_attr(target->scsi_host);
srp_remove_host(target->scsi_host);
scsi_remove_host(target->scsi_host);
srp_disconnect_target(target);
ib_destroy_cm_id(target->cm_id);
srp_free_target_ib(target);
srp_free_req_data(target);
scsi_host_put(target->scsi_host);
}
flush_workqueue(system_long_wq);

kfree(host);
}
Expand Down
5 changes: 2 additions & 3 deletions trunk/drivers/infiniband/ulp/srp/ib_srp.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,7 @@ enum {

enum srp_target_state {
SRP_TARGET_LIVE,
SRP_TARGET_DEAD,
SRP_TARGET_REMOVED
SRP_TARGET_REMOVED,
};

enum srp_iu_type {
Expand Down Expand Up @@ -175,7 +174,7 @@ struct srp_target_port {
struct srp_iu *rx_ring[SRP_RQ_SIZE];
struct srp_request req_ring[SRP_CMD_SQ_SIZE];

struct work_struct work;
struct work_struct remove_work;

struct list_head list;
struct completion done;
Expand Down

0 comments on commit 71d2fb8

Please sign in to comment.