Skip to content

Commit

Permalink
[SCSI] zfcp: Replace global config_lock with local list locks
Browse files Browse the repository at this point in the history
The global config_lock was used to protect the configuration organized
in independent lists. It is not necessary to have a lock on driver
level for this purpose.  This patch replaces the global config_lock
with a set of local list locks.

Signed-off-by: Swen Schillig <swen@vnet.ibm.com>
Signed-off-by: Christof Schmitt <christof.schmitt@de.ibm.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
  • Loading branch information
sswen authored and James Bottomley committed Dec 4, 2009
1 parent 0a55256 commit ecf0c77
Show file tree
Hide file tree
Showing 8 changed files with 199 additions and 200 deletions.
80 changes: 46 additions & 34 deletions drivers/s390/scsi/zfcp_aux.c
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,6 @@ static int __init zfcp_module_init(void)
goto out_gid_cache;

mutex_init(&zfcp_data.config_mutex);
rwlock_init(&zfcp_data.config_lock);

zfcp_data.scsi_transport_template =
fc_attach_transport(&zfcp_transport_functions);
Expand Down Expand Up @@ -238,12 +237,18 @@ module_init(zfcp_module_init);
*/
struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *port, u64 fcp_lun)
{
unsigned long flags;
struct zfcp_unit *unit;

list_for_each_entry(unit, &port->unit_list_head, list)
read_lock_irqsave(&port->unit_list_lock, flags);
list_for_each_entry(unit, &port->unit_list, list)
if ((unit->fcp_lun == fcp_lun) &&
!(atomic_read(&unit->status) & ZFCP_STATUS_COMMON_REMOVE))
return unit;
!(atomic_read(&unit->status) & ZFCP_STATUS_COMMON_REMOVE)) {
zfcp_unit_get(unit);
read_unlock_irqrestore(&port->unit_list_lock, flags);
return unit;
}
read_unlock_irqrestore(&port->unit_list_lock, flags);
return NULL;
}

Expand All @@ -257,12 +262,18 @@ struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *port, u64 fcp_lun)
struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *adapter,
u64 wwpn)
{
unsigned long flags;
struct zfcp_port *port;

list_for_each_entry(port, &adapter->port_list_head, list)
read_lock_irqsave(&adapter->port_list_lock, flags);
list_for_each_entry(port, &adapter->port_list, list)
if ((port->wwpn == wwpn) &&
!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_REMOVE))
!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_REMOVE)) {
zfcp_port_get(port);
read_unlock_irqrestore(&adapter->port_list_lock, flags);
return port;
}
read_unlock_irqrestore(&adapter->port_list_lock, flags);
return NULL;
}

Expand All @@ -284,12 +295,11 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun)
{
struct zfcp_unit *unit;

read_lock_irq(&zfcp_data.config_lock);
if (zfcp_get_unit_by_lun(port, fcp_lun)) {
read_unlock_irq(&zfcp_data.config_lock);
unit = zfcp_get_unit_by_lun(port, fcp_lun);
if (unit) {
zfcp_unit_put(unit);
return ERR_PTR(-EINVAL);
}
read_unlock_irq(&zfcp_data.config_lock);

unit = kzalloc(sizeof(struct zfcp_unit), GFP_KERNEL);
if (!unit)
Expand Down Expand Up @@ -335,13 +345,13 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun)

zfcp_unit_get(unit);

write_lock_irq(&zfcp_data.config_lock);
list_add_tail(&unit->list, &port->unit_list_head);
write_lock_irq(&port->unit_list_lock);
list_add_tail(&unit->list, &port->unit_list);
write_unlock_irq(&port->unit_list_lock);

atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status);
atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &unit->status);

write_unlock_irq(&zfcp_data.config_lock);

zfcp_port_get(port);

return unit;
Expand All @@ -356,11 +366,11 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun)
*/
void zfcp_unit_dequeue(struct zfcp_unit *unit)
{
struct zfcp_port *port = unit->port;

wait_event(unit->remove_wq, atomic_read(&unit->refcount) == 0);
write_lock_irq(&zfcp_data.config_lock);
list_del(&unit->list);
write_unlock_irq(&zfcp_data.config_lock);
zfcp_port_put(unit->port);
list_del(&unit->list); /* no list locking required */
zfcp_port_put(port);
sysfs_remove_group(&unit->sysfs_device.kobj, &zfcp_sysfs_unit_attrs);
device_unregister(&unit->sysfs_device);
}
Expand Down Expand Up @@ -539,11 +549,13 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device)
if (zfcp_fc_gs_setup(adapter))
goto generic_services_failed;

rwlock_init(&adapter->port_list_lock);
INIT_LIST_HEAD(&adapter->port_list);

init_waitqueue_head(&adapter->remove_wq);
init_waitqueue_head(&adapter->erp_ready_wq);
init_waitqueue_head(&adapter->erp_done_wqh);

INIT_LIST_HEAD(&adapter->port_list_head);
INIT_LIST_HEAD(&adapter->erp_ready_head);
INIT_LIST_HEAD(&adapter->erp_running_head);

Expand Down Expand Up @@ -650,19 +662,20 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn,
{
struct zfcp_port *port;

read_lock_irq(&zfcp_data.config_lock);
if (zfcp_get_port_by_wwpn(adapter, wwpn)) {
read_unlock_irq(&zfcp_data.config_lock);
return ERR_PTR(-EINVAL);
port = zfcp_get_port_by_wwpn(adapter, wwpn);
if (port) {
zfcp_port_put(port);
return ERR_PTR(-EEXIST);
}
read_unlock_irq(&zfcp_data.config_lock);

port = kzalloc(sizeof(struct zfcp_port), GFP_KERNEL);
if (!port)
return ERR_PTR(-ENOMEM);

rwlock_init(&port->unit_list_lock);
INIT_LIST_HEAD(&port->unit_list);

init_waitqueue_head(&port->remove_wq);
INIT_LIST_HEAD(&port->unit_list_head);
INIT_WORK(&port->gid_pn_work, zfcp_fc_port_did_lookup);
INIT_WORK(&port->test_link_work, zfcp_fc_link_test_work);
INIT_WORK(&port->rport_work, zfcp_scsi_rport_work);
Expand Down Expand Up @@ -698,13 +711,13 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn,

zfcp_port_get(port);

write_lock_irq(&zfcp_data.config_lock);
list_add_tail(&port->list, &adapter->port_list_head);
write_lock_irq(&adapter->port_list_lock);
list_add_tail(&port->list, &adapter->port_list);
write_unlock_irq(&adapter->port_list_lock);

atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status);
atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &port->status);

write_unlock_irq(&zfcp_data.config_lock);

zfcp_adapter_get(adapter);
return port;
}
Expand All @@ -715,12 +728,11 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn,
*/
void zfcp_port_dequeue(struct zfcp_port *port)
{
write_lock_irq(&zfcp_data.config_lock);
list_del(&port->list);
write_unlock_irq(&zfcp_data.config_lock);
struct zfcp_adapter *adapter = port->adapter;

list_del(&port->list); /* no list locking required here */
wait_event(port->remove_wq, atomic_read(&port->refcount) == 0);
cancel_work_sync(&port->rport_work); /* usually not necessary */
zfcp_adapter_put(port->adapter);
zfcp_adapter_put(adapter);
sysfs_remove_group(&port->sysfs_device.kobj, &zfcp_sysfs_port_attrs);
device_unregister(&port->sysfs_device);
}
Expand Down
23 changes: 12 additions & 11 deletions drivers/s390/scsi/zfcp_ccw.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,29 +100,33 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device)

mutex_lock(&zfcp_data.config_mutex);
adapter = dev_get_drvdata(&ccw_device->dev);
if (!adapter)
goto out;
mutex_unlock(&zfcp_data.config_mutex);

if (!adapter)
return;

cancel_work_sync(&adapter->scan_work);

mutex_lock(&zfcp_data.config_mutex);

/* this also removes the scsi devices, so call it first */
zfcp_adapter_scsi_unregister(adapter);

write_lock_irq(&zfcp_data.config_lock);
list_for_each_entry_safe(port, p, &adapter->port_list_head, list) {
list_for_each_entry_safe(unit, u, &port->unit_list_head, list) {
list_move(&unit->list, &unit_remove_lh);
write_lock_irq(&adapter->port_list_lock);
list_for_each_entry_safe(port, p, &adapter->port_list, list) {
write_lock(&port->unit_list_lock);
list_for_each_entry_safe(unit, u, &port->unit_list, list) {
atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE,
&unit->status);
list_move(&unit->list, &unit_remove_lh);
}
list_move(&port->list, &port_remove_lh);
write_unlock(&port->unit_list_lock);
atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status);
list_move(&port->list, &port_remove_lh);
}
atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status);
write_unlock_irq(&zfcp_data.config_lock);
write_unlock_irq(&adapter->port_list_lock);
mutex_unlock(&zfcp_data.config_mutex);

list_for_each_entry_safe(port, p, &port_remove_lh, list) {
list_for_each_entry_safe(unit, u, &unit_remove_lh, list)
Expand All @@ -131,9 +135,6 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device)
}
wait_event(adapter->remove_wq, atomic_read(&adapter->refcount) == 0);
zfcp_adapter_dequeue(adapter);

out:
mutex_unlock(&zfcp_data.config_mutex);
}

/**
Expand Down
9 changes: 4 additions & 5 deletions drivers/s390/scsi/zfcp_def.h
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,8 @@ struct zfcp_adapter {
u32 hardware_version; /* of FCP channel */
u16 timer_ticks; /* time int for a tick */
struct Scsi_Host *scsi_host; /* Pointer to mid-layer */
struct list_head port_list_head; /* remote port list */
struct list_head port_list; /* remote port list */
rwlock_t port_list_lock; /* port list lock */
unsigned long req_no; /* unique FSF req number */
struct list_head *req_list; /* list of pending reqs */
spinlock_t req_list_lock; /* request list lock */
Expand Down Expand Up @@ -504,7 +505,8 @@ struct zfcp_port {
wait_queue_head_t remove_wq; /* can be used to wait for
refcount drop to zero */
struct zfcp_adapter *adapter; /* adapter used to access port */
struct list_head unit_list_head; /* head of logical unit list */
struct list_head unit_list; /* head of logical unit list */
rwlock_t unit_list_lock; /* unit list lock */
atomic_t status; /* status of this remote port */
u64 wwnn; /* WWNN if known */
u64 wwpn; /* WWPN */
Expand Down Expand Up @@ -601,9 +603,6 @@ struct zfcp_fsf_req {
struct zfcp_data {
struct scsi_host_template scsi_host_template;
struct scsi_transport_template *scsi_transport_template;
rwlock_t config_lock; /* serialises changes
to adapter/port/unit
lists */
struct mutex config_mutex;
struct kmem_cache *gpn_ft_cache;
struct kmem_cache *qtcb_cache;
Expand Down
Loading

0 comments on commit ecf0c77

Please sign in to comment.