Preempt reservation
A reservation can be preempted by issuing the appropriate IOCTL. The current reservation key is
needed to successfully preempt the reservation. The current reservation key can be queried by
issuing an IOCTL_STORAGE_PERSISTENT_RESERVE_IN
IOCTL:
PERSISTENT_RESERVE_COMMAND prcmd = { 0 };
PPRI_RESERVATION_LIST prsl = NULL;
ULONG AdditionalLength = 0;
DWORD BytesReturned = 0;
INT iStatus = 0, i, j;
UCHAR *bufDataRead = (UCHAR *) malloc(SENSE_BUFFER_SIZE * 2);
ZeroMemory(bufDataRead, SENSE_BUFFER_SIZE * 2);
prcmd.Size = sizeof(PERSISTENT_RESERVE_COMMAND);
prcmd.PR_IN.ServiceAction = RESERVATION_ACTION_READ_KEYS;
prcmd.PR_IN.AllocationLength = sizeof(PRI_REGISTRATION_LIST);
for (i = 0; i < 2; i++) {
if (0 == i)
AdditionalLength = sizeof(PRI_RESERVATION_LIST);
iStatus = DeviceIoControl(tape,
IOCTL_STORAGE_PERSISTENT_RESERVE_IN,
&prcmd,
prcmd.Size,
bufDataRead,
AdditionalLength,
&BytesReturned,
NULL);
if (0 == iStatus) {
free(bufDataRead);
return FALSE;
}
prsl = (PPRI_RESERVATION_LIST)bufDataRead;
if (0 == i) {
AdditionalLength = (ULONG)((prsl->AdditionalLength[0] & 0xff) << 12);
AdditionalLength |= (ULONG)((prsl->AdditionalLength[1] & 0xff) << 8);
AdditionalLength |= (ULONG)((prsl->AdditionalLength[2] & 0xff) << 4);
AdditionalLength |= (ULONG) (prsl->AdditionalLength[3] & 0xff);
AdditionalLength += sizeof(PRI_RESERVATION_LIST);
prcmd.PR_IN.AllocationLength = AdditionalLength;
} else if (1 == i) {
for (j = 0; (j * sizeof(PRI_RESERVATION_DESCRIPTOR)
+ sizeof(PRI_RESERVATION_LIST))<= AdditionalLength; j++) {
printf("\nReservation 0x%08x%08x being examined at
descriptor index %d.\n",
((LARGE_INTEGER*)(prsl->Reservations[j].ReservationKey))
->HighPart,
((LARGE_INTEGER*)(prsl->Reservations[j].ReservationKey))
->LowPart,
j);
}
}
}
When the reservation key is known, it can be preempted, meaning a new host can be the reservation
holder, thus being able to interact with the target as
needed.
PRI_RESERVATION_DESCRIPTOR reservation = { 0 };
PERSISTENT_RESERVE_COMMAND prcmd = { 0 };
PRO_PARAMETER_LIST prolist = { 0 };
DWORD BytesReturned = 0;
INT iStatus = 0;
UCHAR bufDataRead[sizeof(PERSISTENT_RESERVE_COMMAND)
+ sizeof(PRO_PARAMETER_LIST)] = { 0 };
prcmd.Size = sizeof(PERSISTENT_RESERVE_COMMAND) + sizeof(PRO_PARAMETER_LIST);
prcmd.PR_OUT.ParameterList[1] = 0x18;
prcmd.PR_OUT.ServiceAction = 0x3;
prcmd.PR_OUT.Type = 0x3;
query_reserve(tape, &reservation);
RtlCopyMemory(prolist.ReservationKey, reservation.ReservationKey, 8);
RtlCopyMemory(prolist.ServiceActionReservationKey,
reservation.ReservationKey, 8);
RtlCopyMemory(bufDataRead, &prcmd, sizeof(PERSISTENT_RESERVE_COMMAND));
RtlCopyMemory(bufDataRead + sizeof(PERSISTENT_RESERVE_COMMAND),
&prolist, sizeof(PRO_PARAMETER_LIST));
iStatus = DeviceIoControl(tape,
IOCTL_STORAGE_PERSISTENT_RESERVE_OUT,
bufDataRead,
sizeof(bufDataRead),
bufDataRead,
sizeof(bufDataRead),
&BytesReturned,
NULL);
The query_reserve function can be implemented as explained earlier. Finally, if the reservation needs to be preempted on a different system than the original reservation holder, the OPEN_ALWAYS flag comes in handy. It allows the user to query the target's serial number, then queries the reservation key, and preempts the reservation.
Caution is advised when preempting reservations due to inherent risk of data loss if done incorrectly. Applications must make sure that they are clearing or preempting the appropriate reservation.