diff options
| author | Dan Williams <dan.j.williams@intel.com> | 2012-03-09 14:00:06 -0500 |
|---|---|---|
| committer | James Bottomley <JBottomley@Parallels.com> | 2012-04-23 07:03:39 -0400 |
| commit | 22b9153faa2263aa89625de25e71c7d44c8dbd16 (patch) | |
| tree | 1157d64a9c63c5b7b48b4a5b3610965d8d4c9624 /include | |
| parent | f8fc75dc576eac0c996e4a792a4701819d999260 (diff) | |
[SCSI] libsas: introduce sas_work to fix sas_drain_work vs sas_queue_work
When requeuing work to a draining workqueue the last work instance may
not be idle, so sas_queue_work() must not touch work->entry. Introduce
sas_work with a drain_node list_head to have a private list for
collecting work deferred due to drain collision.
Fixes reports like:
BUG: unable to handle kernel NULL pointer dereference at (null)
IP: [<ffffffff810410d4>] process_one_work+0x2e/0x338
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'include')
| -rw-r--r-- | include/scsi/libsas.h | 40 |
1 files changed, 36 insertions, 4 deletions
diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h index 5f5ed1b8b41b..f4f1c96dca72 100644 --- a/include/scsi/libsas.h +++ b/include/scsi/libsas.h | |||
| @@ -217,11 +217,29 @@ struct domain_device { | |||
| 217 | struct kref kref; | 217 | struct kref kref; |
| 218 | }; | 218 | }; |
| 219 | 219 | ||
| 220 | struct sas_discovery_event { | 220 | struct sas_work { |
| 221 | struct list_head drain_node; | ||
| 221 | struct work_struct work; | 222 | struct work_struct work; |
| 223 | }; | ||
| 224 | |||
| 225 | static inline void INIT_SAS_WORK(struct sas_work *sw, void (*fn)(struct work_struct *)) | ||
| 226 | { | ||
| 227 | INIT_WORK(&sw->work, fn); | ||
| 228 | INIT_LIST_HEAD(&sw->drain_node); | ||
| 229 | } | ||
| 230 | |||
| 231 | struct sas_discovery_event { | ||
| 232 | struct sas_work work; | ||
| 222 | struct asd_sas_port *port; | 233 | struct asd_sas_port *port; |
| 223 | }; | 234 | }; |
| 224 | 235 | ||
| 236 | static inline struct sas_discovery_event *to_sas_discovery_event(struct work_struct *work) | ||
| 237 | { | ||
| 238 | struct sas_discovery_event *ev = container_of(work, typeof(*ev), work.work); | ||
| 239 | |||
| 240 | return ev; | ||
| 241 | } | ||
| 242 | |||
| 225 | struct sas_discovery { | 243 | struct sas_discovery { |
| 226 | struct sas_discovery_event disc_work[DISC_NUM_EVENTS]; | 244 | struct sas_discovery_event disc_work[DISC_NUM_EVENTS]; |
| 227 | unsigned long pending; | 245 | unsigned long pending; |
| @@ -244,7 +262,7 @@ struct asd_sas_port { | |||
| 244 | struct list_head destroy_list; | 262 | struct list_head destroy_list; |
| 245 | enum sas_linkrate linkrate; | 263 | enum sas_linkrate linkrate; |
| 246 | 264 | ||
| 247 | struct work_struct work; | 265 | struct sas_work work; |
| 248 | 266 | ||
| 249 | /* public: */ | 267 | /* public: */ |
| 250 | int id; | 268 | int id; |
| @@ -270,10 +288,17 @@ struct asd_sas_port { | |||
| 270 | }; | 288 | }; |
| 271 | 289 | ||
| 272 | struct asd_sas_event { | 290 | struct asd_sas_event { |
| 273 | struct work_struct work; | 291 | struct sas_work work; |
| 274 | struct asd_sas_phy *phy; | 292 | struct asd_sas_phy *phy; |
| 275 | }; | 293 | }; |
| 276 | 294 | ||
| 295 | static inline struct asd_sas_event *to_asd_sas_event(struct work_struct *work) | ||
| 296 | { | ||
| 297 | struct asd_sas_event *ev = container_of(work, typeof(*ev), work.work); | ||
| 298 | |||
| 299 | return ev; | ||
| 300 | } | ||
| 301 | |||
| 277 | /* The phy pretty much is controlled by the LLDD. | 302 | /* The phy pretty much is controlled by the LLDD. |
| 278 | * The class only reads those fields. | 303 | * The class only reads those fields. |
| 279 | */ | 304 | */ |
| @@ -333,10 +358,17 @@ struct scsi_core { | |||
| 333 | }; | 358 | }; |
| 334 | 359 | ||
| 335 | struct sas_ha_event { | 360 | struct sas_ha_event { |
| 336 | struct work_struct work; | 361 | struct sas_work work; |
| 337 | struct sas_ha_struct *ha; | 362 | struct sas_ha_struct *ha; |
| 338 | }; | 363 | }; |
| 339 | 364 | ||
| 365 | static inline struct sas_ha_event *to_sas_ha_event(struct work_struct *work) | ||
| 366 | { | ||
| 367 | struct sas_ha_event *ev = container_of(work, typeof(*ev), work.work); | ||
| 368 | |||
| 369 | return ev; | ||
| 370 | } | ||
| 371 | |||
| 340 | enum sas_ha_state { | 372 | enum sas_ha_state { |
| 341 | SAS_HA_REGISTERED, | 373 | SAS_HA_REGISTERED, |
| 342 | SAS_HA_DRAINING, | 374 | SAS_HA_DRAINING, |
