Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

scsi: sas: scsi_queue_work can fail, so make callers aware

libsas uses scsi_queue_work() to queue its internal event notifications.
scsi_queue_work() can return -EINVAL if the work queue doesn't exist and
it does call queue_work() which can return false if the work is already
queued.

Make the SAS event code capable of returning errors up to the caller,
which is handy when changing to dynamically allocated work in libsas
as well, as discussed here: https://lkml.org/lkml/2017/6/14/121.

[mkp: fixed typo]

Signed-off-by: Johannes Thumshirn <jthumshirn@suse.de>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>

authored by

Johannes Thumshirn and committed by
Martin K. Petersen
6d311fa7 d06c587d

+27 -19
+22 -14
drivers/scsi/libsas/sas_event.c
··· 27 27 #include "sas_internal.h" 28 28 #include "sas_dump.h" 29 29 30 - void sas_queue_work(struct sas_ha_struct *ha, struct sas_work *sw) 30 + int sas_queue_work(struct sas_ha_struct *ha, struct sas_work *sw) 31 31 { 32 + int rc = 0; 33 + 32 34 if (!test_bit(SAS_HA_REGISTERED, &ha->state)) 33 - return; 35 + return 0; 34 36 35 37 if (test_bit(SAS_HA_DRAINING, &ha->state)) { 36 38 /* add it to the defer list, if not already pending */ 37 39 if (list_empty(&sw->drain_node)) 38 40 list_add(&sw->drain_node, &ha->defer_q); 39 41 } else 40 - scsi_queue_work(ha->core.shost, &sw->work); 42 + rc = scsi_queue_work(ha->core.shost, &sw->work); 43 + 44 + return rc; 41 45 } 42 46 43 - static void sas_queue_event(int event, unsigned long *pending, 47 + static int sas_queue_event(int event, unsigned long *pending, 44 48 struct sas_work *work, 45 49 struct sas_ha_struct *ha) 46 50 { 51 + int rc = 0; 52 + 47 53 if (!test_and_set_bit(event, pending)) { 48 54 unsigned long flags; 49 55 50 56 spin_lock_irqsave(&ha->lock, flags); 51 - sas_queue_work(ha, work); 57 + rc = sas_queue_work(ha, work); 52 58 spin_unlock_irqrestore(&ha->lock, flags); 53 59 } 60 + 61 + return rc; 54 62 } 55 63 56 64 ··· 124 116 mutex_unlock(&ha->disco_mutex); 125 117 } 126 118 127 - static void notify_ha_event(struct sas_ha_struct *sas_ha, enum ha_event event) 119 + static int notify_ha_event(struct sas_ha_struct *sas_ha, enum ha_event event) 128 120 { 129 121 BUG_ON(event >= HA_NUM_EVENTS); 130 122 131 - sas_queue_event(event, &sas_ha->pending, 132 - &sas_ha->ha_events[event].work, sas_ha); 123 + return sas_queue_event(event, &sas_ha->pending, 124 + &sas_ha->ha_events[event].work, sas_ha); 133 125 } 134 126 135 - static void notify_port_event(struct asd_sas_phy *phy, enum port_event event) 127 + static int notify_port_event(struct asd_sas_phy *phy, enum port_event event) 136 128 { 137 129 struct sas_ha_struct *ha = phy->ha; 138 130 139 131 BUG_ON(event >= PORT_NUM_EVENTS); 140 132 141 - sas_queue_event(event, &phy->port_events_pending, 142 - &phy->port_events[event].work, ha); 133 + return sas_queue_event(event, &phy->port_events_pending, 134 + &phy->port_events[event].work, ha); 143 135 } 144 136 145 - void sas_notify_phy_event(struct asd_sas_phy *phy, enum phy_event event) 137 + int sas_notify_phy_event(struct asd_sas_phy *phy, enum phy_event event) 146 138 { 147 139 struct sas_ha_struct *ha = phy->ha; 148 140 149 141 BUG_ON(event >= PHY_NUM_EVENTS); 150 142 151 - sas_queue_event(event, &phy->phy_events_pending, 152 - &phy->phy_events[event].work, ha); 143 + return sas_queue_event(event, &phy->phy_events_pending, 144 + &phy->phy_events[event].work, ha); 153 145 } 154 146 155 147 int sas_init_events(struct sas_ha_struct *sas_ha)
+2 -2
drivers/scsi/libsas/sas_internal.h
··· 76 76 void sas_porte_link_reset_err(struct work_struct *work); 77 77 void sas_porte_timer_event(struct work_struct *work); 78 78 void sas_porte_hard_reset(struct work_struct *work); 79 - void sas_queue_work(struct sas_ha_struct *ha, struct sas_work *sw); 79 + int sas_queue_work(struct sas_ha_struct *ha, struct sas_work *sw); 80 80 81 81 int sas_notify_lldd_dev_found(struct domain_device *); 82 82 void sas_notify_lldd_dev_gone(struct domain_device *); ··· 85 85 enum phy_func phy_func, struct sas_phy_linkrates *); 86 86 int sas_smp_get_phy_events(struct sas_phy *phy); 87 87 88 - void sas_notify_phy_event(struct asd_sas_phy *phy, enum phy_event event); 88 + int sas_notify_phy_event(struct asd_sas_phy *phy, enum phy_event event); 89 89 void sas_device_set_phy(struct domain_device *dev, struct sas_port *port); 90 90 struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy); 91 91 struct domain_device *sas_ex_to_ata(struct domain_device *ex_dev, int phy_id);
+3 -3
include/scsi/libsas.h
··· 415 415 * their siblings when forming wide ports */ 416 416 417 417 /* LLDD calls these to notify the class of an event. */ 418 - void (*notify_ha_event)(struct sas_ha_struct *, enum ha_event); 419 - void (*notify_port_event)(struct asd_sas_phy *, enum port_event); 420 - void (*notify_phy_event)(struct asd_sas_phy *, enum phy_event); 418 + int (*notify_ha_event)(struct sas_ha_struct *, enum ha_event); 419 + int (*notify_port_event)(struct asd_sas_phy *, enum port_event); 420 + int (*notify_phy_event)(struct asd_sas_phy *, enum phy_event); 421 421 422 422 void *lldd_ha; /* not touched by sas class code */ 423 423