@@ -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,33 @@ 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 , MPATH_PROUT_REG_IGN_SA ,
615+ rq_scope , rq_type ,
616+ & paramp , noisy );
617+ if (rel_status != MPATH_PR_SUCCESS )
618+ condlog (0 , "%s: final self preempt unregister failed," ,
619+ mpp -> wwid );
620+ }
621+ }
622+ if (work != PREE_WORK_REL_UNREG ) {
623+ memset (& paramp , 0 , sizeof (paramp ));
624+ memcpy (paramp .sa_key , & mpp -> reservation_key , 8 );
625+ status = mpath_prout_reg (mpp , MPATH_PROUT_REG_IGN_SA , rq_scope ,
626+ rq_type , & paramp , noisy );
627+ if (status != MPATH_PR_SUCCESS )
628+ condlog (0 , "%s: self preempt failed to reregister paths." ,
629+ mpp -> wwid );
607630 }
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 );
616631
617632fail_resume :
618633 if (!dm_simplecmd_noflush (DM_DEVICE_RESUME , mpp -> alias , udev_flags )) {
@@ -625,18 +640,18 @@ static int do_preempt_self(struct multipath *mpp, struct be64 sa_key,
625640}
626641
627642static int preempt_self (struct multipath * mpp , int rq_servact , int rq_scope ,
628- unsigned int rq_type , int noisy , bool do_release )
643+ unsigned int rq_type , int noisy , enum preempt_work work )
629644{
630645 return do_preempt_self (mpp , mpp -> reservation_key , rq_servact , rq_scope ,
631- rq_type , noisy , do_release );
646+ rq_type , noisy , work );
632647}
633648
634649static int preempt_all (struct multipath * mpp , int rq_servact , int rq_scope ,
635650 unsigned int rq_type , int noisy )
636651{
637652 struct be64 zerokey = {0 };
638653 return do_preempt_self (mpp , zerokey , rq_servact , rq_scope , rq_type ,
639- noisy , false );
654+ noisy , PREE_WORK_NONE );
640655}
641656
642657static int
@@ -661,18 +676,20 @@ reservation_key_matches(struct multipath *mpp, uint8_t *key, unsigned int *type)
661676 return YNU_NO ;
662677}
663678
664- static bool check_holding_reservation (struct multipath * mpp , unsigned int * type )
679+ static bool check_holding_reservation (struct multipath * mpp , uint8_t * curr_key ,
680+ unsigned int * type )
665681{
666- if ( get_be64 ( mpp -> reservation_key ) && get_prhold ( mpp -> alias ) == PR_SET &&
667- reservation_key_matches ( mpp , ( uint8_t * ) & mpp -> reservation_key , type ) ==
668- YNU_YES )
682+ uint64_t zerokey = 0 ;
683+ if ( memcmp ( curr_key , & zerokey , 8 ) != 0 && get_prhold ( mpp -> alias ) == PR_SET &&
684+ reservation_key_matches ( mpp , curr_key , type ) == YNU_YES )
669685 return true;
670686 return false;
671687}
672688
673- static int mpath_prout_rel (struct multipath * mpp ,int rq_servact , int rq_scope ,
674- unsigned int rq_type ,
675- struct prout_param_descriptor * paramp , int noisy )
689+ static int
690+ mpath_prout_rel (struct multipath * mpp , int rq_servact , int rq_scope ,
691+ unsigned int rq_type , struct prout_param_descriptor * paramp ,
692+ int noisy , bool unregister )
676693{
677694 int i , j ;
678695 struct pathgroup * pgp = NULL ;
@@ -762,7 +779,8 @@ static int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
762779 return status ;
763780 }
764781
765- if (!check_holding_reservation (mpp , & res_type )) {
782+ if (!check_holding_reservation (mpp , (uint8_t * )& mpp -> reservation_key ,
783+ & res_type )) {
766784 condlog (2 , "%s: Releasing key not holding reservation." , mpp -> wwid );
767785 return MPATH_PR_SUCCESS ;
768786 }
@@ -785,7 +803,11 @@ static int mpath_prout_rel(struct multipath *mpp,int rq_servact, int rq_scope,
785803 * 4. Reregistering keys on all the paths
786804 * 5. Resuming the device
787805 */
788- return preempt_self (mpp , MPATH_PROUT_PREE_SA , rq_scope , rq_type , noisy , true);
806+ status = preempt_self (mpp , MPATH_PROUT_PREE_SA , rq_scope , rq_type , noisy ,
807+ unregister ? PREE_WORK_REL_UNREG : PREE_WORK_REL );
808+ if (status == MPATH_PR_SUCCESS && unregister )
809+ return MPATH_PR_SUCCESS_UNREGISTER ;
810+ return status ;
789811}
790812
791813/*
@@ -827,7 +849,7 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
827849 select_reservation_key (conf , mpp );
828850 put_multipath_config (conf );
829851
830- memcpy ( & oldkey , & mpp -> reservation_key , 8 ) ;
852+ oldkey = mpp -> reservation_key ;
831853 unregistering = (memcmp (& zerokey , paramp -> sa_key , 8 ) == 0 );
832854 if (mpp -> prkey_source == PRKEY_SOURCE_FILE &&
833855 (rq_servact == MPATH_PROUT_REG_IGN_SA ||
@@ -904,7 +926,28 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
904926 {
905927 case MPATH_PROUT_REG_SA :
906928 case MPATH_PROUT_REG_IGN_SA :
907- ret = mpath_prout_reg (mpp , rq_servact , rq_scope , rq_type , paramp , noisy );
929+ if (unregistering &&
930+ check_holding_reservation (mpp , (uint8_t * )& oldkey , & rq_type )) {
931+ struct be64 newkey = mpp -> reservation_key ;
932+ /* temporarily restore reservation key */
933+ mpp -> reservation_key = oldkey ;
934+ ret = mpath_prout_rel (mpp , MPATH_PROUT_REL_SA , rq_scope ,
935+ rq_type , paramp , noisy , true);
936+ mpp -> reservation_key = newkey ;
937+ if (ret == MPATH_PR_SUCCESS )
938+ /*
939+ * Since unregistering it true, paramp->sa_key
940+ * must be zero here. So this command will
941+ * unregister the key.
942+ */
943+ ret = mpath_prout_reg (mpp , rq_servact , rq_scope ,
944+ rq_type , paramp , noisy );
945+ else if (ret == MPATH_PR_SUCCESS_UNREGISTER )
946+ /* We already unregistered the key */
947+ ret = MPATH_PR_SUCCESS ;
948+ } else
949+ ret = mpath_prout_reg (mpp , rq_servact , rq_scope ,
950+ rq_type , paramp , noisy );
908951 break ;
909952 case MPATH_PROUT_PREE_SA :
910953 case MPATH_PROUT_PREE_AB_SA :
@@ -920,7 +963,7 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
920963 /* if we are preempting ourself */
921964 if (memcmp (paramp -> sa_key , paramp -> key , 8 ) == 0 ) {
922965 ret = preempt_self (mpp , rq_servact , rq_scope , rq_type ,
923- noisy , false );
966+ noisy , PREE_WORK_NONE );
924967 break ;
925968 }
926969 /* fallthrough */
@@ -929,15 +972,17 @@ int do_mpath_persistent_reserve_out(vector curmp, vector pathvec, int fd,
929972 unsigned int res_type ;
930973 ret = mpath_prout_common (mpp , rq_servact , rq_scope , rq_type ,
931974 paramp , noisy , NULL , & failed_paths );
932- if (rq_servact == MPATH_PROUT_RES_SA && ret != MPATH_PR_SUCCESS &&
933- failed_paths && check_holding_reservation (mpp , & res_type ) &&
975+ if (rq_servact == MPATH_PROUT_RES_SA &&
976+ ret != MPATH_PR_SUCCESS && failed_paths &&
977+ check_holding_reservation (mpp , paramp -> key , & res_type ) &&
934978 res_type == rq_type )
935979 /* The reserve failed, but multipathd says we hold it */
936980 ret = MPATH_PR_SUCCESS ;
937981 break ;
938982 }
939983 case MPATH_PROUT_REL_SA :
940- ret = mpath_prout_rel (mpp , rq_servact , rq_scope , rq_type , paramp , noisy );
984+ ret = mpath_prout_rel (mpp , rq_servact , rq_scope , rq_type ,
985+ paramp , noisy , false);
941986 break ;
942987 default :
943988 return MPATH_PR_OTHER ;
0 commit comments