From: Stefan Hajnoczi <[email protected]>

The SCSI specification says PREEMPT without a reservation removes all
registrations with the given key. Try to register again after PREEMPT
since our key will have been removed.

In practice some SCSI targets keep the calling I_T nexus' registration
instead of removing it. Therefore we need to handle both the
spec-compliant and the non-compliant behavior.

Signed-off-by: Stefan Hajnoczi <[email protected]>
Reviewed-by: Paolo Bonzini <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
Signed-off-by: Paolo Bonzini <[email protected]>
---
 hw/scsi/scsi-generic.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c
index f1c328e6da6..29bc952af5d 100644
--- a/hw/scsi/scsi-generic.c
+++ b/hw/scsi/scsi-generic.c
@@ -513,6 +513,16 @@ bool scsi_generic_pr_state_preempt(SCSIDevice *s, Error 
**errp)
         if (!scsi_generic_pr_preempt(s, key, resv_type, errp)) {
             return false;
         }
+
+        /*
+         * Some SCSI targets, like the Linux LIO target, remove our
+         * registration when preempting without a reservation (resv_type is 0).
+         * Try to register again but ignore the error since a RESERVATION
+         * CONFLICT is expected if our registration remained in place.
+         */
+        if (resv_type == 0) {
+            scsi_generic_pr_register(s, key, NULL);
+        }
     }
     return true;
 }
-- 
2.54.0


Reply via email to