24
24
#include <linux/module.h>
25
25
#include <asm/unaligned.h>
26
26
#include <scsi/scsi.h>
27
+ #include <scsi/scsi_proto.h>
27
28
#include <scsi/scsi_dbg.h>
28
29
#include <scsi/scsi_eh.h>
29
30
#include <scsi/scsi_dh.h>
@@ -75,6 +76,7 @@ struct alua_port_group {
75
76
struct kref kref ;
76
77
struct rcu_head rcu ;
77
78
struct list_head node ;
79
+ struct list_head dh_list ;
78
80
unsigned char device_id_str [256 ];
79
81
int device_id_len ;
80
82
int group_id ;
@@ -92,6 +94,7 @@ struct alua_port_group {
92
94
};
93
95
94
96
struct alua_dh_data {
97
+ struct list_head node ;
95
98
struct alua_port_group * pg ;
96
99
int group_id ;
97
100
spinlock_t pg_lock ;
@@ -247,6 +250,7 @@ struct alua_port_group *alua_alloc_pg(struct scsi_device *sdev,
247
250
INIT_DELAYED_WORK (& pg -> rtpg_work , alua_rtpg_work );
248
251
INIT_LIST_HEAD (& pg -> rtpg_list );
249
252
INIT_LIST_HEAD (& pg -> node );
253
+ INIT_LIST_HEAD (& pg -> dh_list );
250
254
spin_lock_init (& pg -> lock );
251
255
252
256
spin_lock (& port_group_lock );
@@ -328,6 +332,8 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h,
328
332
{
329
333
int rel_port = -1 , group_id ;
330
334
struct alua_port_group * pg , * old_pg = NULL ;
335
+ bool pg_updated ;
336
+ unsigned long flags ;
331
337
332
338
group_id = scsi_vpd_tpg_id (sdev , & rel_port );
333
339
if (group_id < 0 ) {
@@ -357,10 +363,22 @@ static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h,
357
363
old_pg = h -> pg ;
358
364
if (old_pg != pg ) {
359
365
/* port group has changed. Update to new port group */
366
+ if (h -> pg ) {
367
+ spin_lock_irqsave (& old_pg -> lock , flags );
368
+ list_del_rcu (& h -> node );
369
+ spin_unlock_irqrestore (& old_pg -> lock , flags );
370
+ }
360
371
rcu_assign_pointer (h -> pg , pg );
372
+ pg_updated = true;
361
373
}
374
+
375
+ spin_lock_irqsave (& pg -> lock , flags );
362
376
if (sdev -> synchronous_alua )
363
377
pg -> flags |= ALUA_SYNC_STPG ;
378
+ if (pg_updated )
379
+ list_add_rcu (& h -> node , & pg -> dh_list );
380
+ spin_unlock_irqrestore (& pg -> lock , flags );
381
+
364
382
alua_rtpg_queue (h -> pg , sdev , NULL , true);
365
383
spin_unlock (& h -> pg_lock );
366
384
@@ -613,8 +631,18 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg)
613
631
if (spin_trylock_irqsave (& tmp_pg -> lock , flags )) {
614
632
if ((tmp_pg == pg ) ||
615
633
!(tmp_pg -> flags & ALUA_PG_RUNNING )) {
634
+ struct alua_dh_data * h ;
635
+
616
636
tmp_pg -> state = desc [0 ] & 0x0f ;
617
637
tmp_pg -> pref = desc [0 ] >> 7 ;
638
+ rcu_read_lock ();
639
+ list_for_each_entry_rcu (h ,
640
+ & tmp_pg -> dh_list , node ) {
641
+ /* h->sdev should always be valid */
642
+ BUG_ON (!h -> sdev );
643
+ h -> sdev -> access_state = desc [0 ];
644
+ }
645
+ rcu_read_unlock ();
618
646
}
619
647
if (tmp_pg == pg )
620
648
valid_states = desc [1 ];
@@ -645,10 +673,22 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg)
645
673
pg -> interval = 2 ;
646
674
err = SCSI_DH_RETRY ;
647
675
} else {
676
+ struct alua_dh_data * h ;
677
+
648
678
/* Transitioning time exceeded, set port to standby */
649
679
err = SCSI_DH_IO ;
650
680
pg -> state = SCSI_ACCESS_STATE_STANDBY ;
651
681
pg -> expiry = 0 ;
682
+ rcu_read_lock ();
683
+ list_for_each_entry_rcu (h , & pg -> dh_list , node ) {
684
+ BUG_ON (!h -> sdev );
685
+ h -> sdev -> access_state =
686
+ (pg -> state & SCSI_ACCESS_STATE_MASK );
687
+ if (pg -> pref )
688
+ h -> sdev -> access_state |=
689
+ SCSI_ACCESS_STATE_PREFERRED ;
690
+ }
691
+ rcu_read_unlock ();
652
692
}
653
693
break ;
654
694
case SCSI_ACCESS_STATE_OFFLINE :
@@ -1041,6 +1081,7 @@ static int alua_bus_attach(struct scsi_device *sdev)
1041
1081
rcu_assign_pointer (h -> pg , NULL );
1042
1082
h -> init_error = SCSI_DH_OK ;
1043
1083
h -> sdev = sdev ;
1084
+ INIT_LIST_HEAD (& h -> node );
1044
1085
1045
1086
mutex_init (& h -> init_mutex );
1046
1087
err = alua_initialize (sdev , h );
@@ -1070,9 +1111,12 @@ static void alua_bus_detach(struct scsi_device *sdev)
1070
1111
rcu_assign_pointer (h -> pg , NULL );
1071
1112
h -> sdev = NULL ;
1072
1113
spin_unlock (& h -> pg_lock );
1073
- if (pg )
1114
+ if (pg ) {
1115
+ spin_lock (& pg -> lock );
1116
+ list_del_rcu (& h -> node );
1117
+ spin_unlock (& pg -> lock );
1074
1118
kref_put (& pg -> kref , release_port_group );
1075
-
1119
+ }
1076
1120
sdev -> handler_data = NULL ;
1077
1121
kfree (h );
1078
1122
}
0 commit comments