@@ -564,18 +564,23 @@ static int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope,
564564 return status ;
565565}
566566
567+ enum preempt_work {
568+ PREE_WORK_NONE ,
569+ PREE_WORK_REL ,
570+ PREE_WORK_REL_UNREG ,
571+ };
567572/*
568573 * Called to make a multipath device preempt its own reservation (and
569- * optionally release the reservation ). Doing this causes the reservation
570- * keys to be removed from all the device paths except that path used to issue
571- * the preempt, so they need to be restored. To avoid the chance that IO
572- * goes to these paths when they don't have a registered key, the device
573- * is suspended before issuing the preemption, and the keys are reregistered
574- * before resuming it.
574+ * optional extra work ). Doing this causes the reservation keys to be removed
575+ * from all the device paths except that path used to issue the preempt, so
576+ * they may need to be restored. To avoid the chance that IO goes to these
577+ * paths when they don't have a registered key and a reservation exists , the
578+ * device is suspended before issuing the preemption, and the keys are
579+ * reregistered (or the reservation is released) before resuming it.
575580 */
576581static int do_preempt_self (struct multipath * mpp , struct be64 sa_key ,
577582 int rq_servact , int rq_scope , unsigned int rq_type ,
578- int noisy , bool do_release )
583+ int noisy , enum preempt_work work )
579584{
580585 int status , rel_status = MPATH_PR_SUCCESS ;
581586 struct path * pp = NULL ;
@@ -596,23 +601,34 @@ static int do_preempt_self(struct multipath *mpp, struct be64 sa_key,
596601 goto fail_resume ;
597602 }
598603
599- if (do_release ) {
604+ if (work != PREE_WORK_NONE ) {
600605 memset (& paramp , 0 , sizeof (paramp ));
601606 memcpy (paramp .key , & mpp -> reservation_key , 8 );
602607 rel_status = prout_do_scsi_ioctl (pp -> dev , MPATH_PROUT_REL_SA ,
603608 rq_scope , rq_type , & paramp , noisy );
604609 if (rel_status != MPATH_PR_SUCCESS )
605610 condlog (0 , "%s: release on alternate path failed." ,
606611 mpp -> wwid );
612+ else if (work == PREE_WORK_REL_UNREG ) {
613+ /* unregister the last path */
614+ rel_status = prout_do_scsi_ioctl (pp -> dev ,
615+ MPATH_PROUT_REG_IGN_SA ,
616+ rq_scope , rq_type ,
617+ & paramp , noisy );
618+ if (rel_status != MPATH_PR_SUCCESS )
619+ condlog (0 , "%s: final self preempt unregister failed," ,
620+ mpp -> wwid );
621+ }
622+ }
623+ if (work != PREE_WORK_REL_UNREG ) {
624+ memset (& paramp , 0 , sizeof (paramp ));
625+ memcpy (paramp .sa_key , & mpp -> reservation_key , 8 );
626+ status = mpath_prout_reg (mpp , MPATH_PROUT_REG_IGN_SA , rq_scope ,
627+ rq_type , & paramp , noisy );
628+ if (status != MPATH_PR_SUCCESS )
629+ condlog (0 , "%s: self preempt failed to reregister paths." ,
630+ mpp -> wwid );
607631 }
608-
609- memset (& paramp , 0 , sizeof (paramp ));
610- memcpy (paramp .sa_key , & mpp -> reservation_key , 8 );
611- status = mpath_prout_reg (mpp , MPATH_PROUT_REG_IGN_SA , rq_scope ,
612- rq_type , & paramp , noisy );
613- if (status != MPATH_PR_SUCCESS )
614- condlog (0 , "%s: self preempt failed to reregister paths." ,
615- mpp -> wwid );
616632
617633fail_resume :
618634 if (!dm_simplecmd_noflush (DM_DEVICE_RESUME , mpp -> alias , udev_flags )) {
@@ -625,18 +641,18 @@ static int do_preempt_self(struct multipath *mpp, struct be64 sa_key,
625641}
626642
627643static int preempt_self (struct multipath * mpp , int rq_servact , int rq_scope ,
628- unsigned int rq_type , int noisy , bool do_release )
644+ unsigned int rq_type , int noisy , enum preempt_work work )
629645{
630646 return do_preempt_self (mpp , mpp -> reservation_key , rq_servact , rq_scope ,
631- rq_type , noisy , do_release );
647+ rq_type , noisy , work );
632648}
633649
634650static int preempt_all (struct multipath * mpp , int rq_servact , int rq_scope ,
635651 unsigned int rq_type , int noisy )
636652{
637653 struct be64 zerokey = {0 };
638654 return do_preempt_self (mpp , zerokey , rq_servact , rq_scope , rq_type ,
639- noisy , false );
655+ noisy , PREE_WORK_NONE );
640656}
641657
642658static int reservation_key_matches (struct multipath * mpp , uint8_t * key ,
@@ -661,18 +677,21 @@ static int reservation_key_matches(struct multipath *mpp, uint8_t *key,
661677 return YNU_NO ;
662678}
663679
664- static bool check_holding_reservation (struct multipath * mpp , unsigned int * type )
680+ static bool check_holding_reservation (struct multipath * mpp , uint8_t * curr_key ,
681+ unsigned int * type )
665682{
666- if (get_be64 (mpp -> reservation_key ) &&
683+ uint64_t zerokey = 0 ;
684+ if (memcmp (curr_key , & zerokey , 8 ) != 0 &&
667685 get_prhold (mpp -> alias ) == PR_SET &&
668- reservation_key_matches (mpp , ( uint8_t * ) & mpp -> reservation_key , type ) == YNU_YES )
686+ reservation_key_matches (mpp , curr_key , type ) == YNU_YES )
669687 return true;
670688 return false;
671689}
672690
673- static int mpath_prout_rel (struct multipath * mpp ,int rq_servact , int rq_scope ,
691+ static int mpath_prout_rel (struct multipath * mpp , int rq_servact , int rq_scope ,
674692 unsigned int rq_type ,
675- struct prout_param_descriptor * paramp , int noisy )
693+ struct prout_param_descriptor * paramp , int noisy ,
694+ bool unregister )
676695{
677696 int i , j ;
678697 struct pathgroup * pgp = NULL ;
@@ -762,7 +781,8 @@ static int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
762781 return status ;
763782 }
764783
765- if (!check_holding_reservation (mpp , & res_type )) {
784+ if (!check_holding_reservation (mpp , (uint8_t * )& mpp -> reservation_key ,
785+ & res_type )) {
766786 condlog (2 , "%s: Releasing key not holding reservation." , mpp -> wwid );
767787 return MPATH_PR_SUCCESS ;
768788 }
@@ -785,7 +805,13 @@ static int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
785805 * 4. Reregistering keys on all the paths
786806 * 5. Resuming the device
787807 */
788- return preempt_self (mpp , MPATH_PROUT_PREE_SA , rq_scope , rq_type , noisy , true);
808+ status = preempt_self (mpp , MPATH_PROUT_PREE_SA , rq_scope , rq_type ,
809+ noisy ,
810+ unregister ? PREE_WORK_REL_UNREG : PREE_WORK_REL );
811+ if (status == MPATH_PR_SUCCESS && unregister )
812+ return MPATH_PR_SUCCESS_UNREGISTER ;
813+ return status ;
814+
789815}
790816
791817/*
@@ -828,7 +854,7 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
828854 select_reservation_key (conf , mpp );
829855 put_multipath_config (conf );
830856
831- memcpy ( & oldkey , & mpp -> reservation_key , 8 ) ;
857+ oldkey = mpp -> reservation_key ;
832858 unregistering = (memcmp (& zerokey , paramp -> sa_key , 8 ) == 0 );
833859 if (mpp -> prkey_source == PRKEY_SOURCE_FILE &&
834860 (rq_servact == MPATH_PROUT_REG_IGN_SA ||
@@ -905,7 +931,27 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
905931 {
906932 case MPATH_PROUT_REG_SA :
907933 case MPATH_PROUT_REG_IGN_SA :
908- ret = mpath_prout_reg (mpp , rq_servact , rq_scope , rq_type , paramp , noisy );
934+ if (unregistering && check_holding_reservation (mpp , (uint8_t * )& oldkey , & rq_type )) {
935+ struct be64 newkey = mpp -> reservation_key ;
936+ /* temporarily restore reservation key */
937+ mpp -> reservation_key = oldkey ;
938+ ret = mpath_prout_rel (mpp , MPATH_PROUT_REL_SA , rq_scope ,
939+ rq_type , paramp , noisy , true);
940+ mpp -> reservation_key = newkey ;
941+ if (ret == MPATH_PR_SUCCESS )
942+ /*
943+ * Since unregistering it true, paramp->sa_key
944+ * must be zero here. So this command will
945+ * unregister the key.
946+ */
947+ ret = mpath_prout_reg (mpp , rq_servact , rq_scope ,
948+ rq_type , paramp , noisy );
949+ else if (ret == MPATH_PR_SUCCESS_UNREGISTER )
950+ /* We already unregistered the key */
951+ ret = MPATH_PR_SUCCESS ;
952+ } else
953+ ret = mpath_prout_reg (mpp , rq_servact , rq_scope ,
954+ rq_type , paramp , noisy );
909955 break ;
910956 case MPATH_PROUT_PREE_SA :
911957 case MPATH_PROUT_PREE_AB_SA :
@@ -921,7 +967,7 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
921967 /* if we are preempting ourself */
922968 if (memcmp (paramp -> sa_key , paramp -> key , 8 ) == 0 ) {
923969 ret = preempt_self (mpp , rq_servact , rq_scope , rq_type ,
924- noisy , false );
970+ noisy , PREE_WORK_NONE );
925971 break ;
926972 }
927973 /* fallthrough */
@@ -932,14 +978,14 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
932978 paramp , noisy , NULL , & failed_paths );
933979 if (rq_servact == MPATH_PROUT_RES_SA &&
934980 ret != MPATH_PR_SUCCESS && failed_paths &&
935- check_holding_reservation (mpp , & res_type ) &&
981+ check_holding_reservation (mpp , paramp -> key , & res_type ) &&
936982 res_type == rq_type )
937983 /* The reserve failed, but multipathd says we hold it */
938984 ret = MPATH_PR_SUCCESS ;
939985 break ;
940986 }
941987 case MPATH_PROUT_REL_SA :
942- ret = mpath_prout_rel (mpp , rq_servact , rq_scope , rq_type , paramp , noisy );
988+ ret = mpath_prout_rel (mpp , rq_servact , rq_scope , rq_type , paramp , noisy , false );
943989 break ;
944990 default :
945991 return MPATH_PR_OTHER ;
0 commit comments