You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
224 lines
6.8 KiB
224 lines
6.8 KiB
/*
|
|
* LOCK.C
|
|
*
|
|
* RSM Service : Locking functions for Physical Media and Media Pools
|
|
*
|
|
* Author: ErvinP
|
|
*
|
|
* (c) 2001 Microsoft Corporation
|
|
*
|
|
*/
|
|
|
|
#include <windows.h>
|
|
#include <stdlib.h>
|
|
#include <wtypes.h>
|
|
|
|
#include <ntmsapi.h>
|
|
#include "internal.h"
|
|
#include "resource.h"
|
|
#include "debug.h"
|
|
|
|
BOOLEAN LockPhysicalMediaWithPool_Iter(PHYSICAL_MEDIA *physMedia, ULONG numTries);
|
|
BOOLEAN LockPhysicalMediaWithLibrary_Iter(PHYSICAL_MEDIA *physMedia, ULONG numTries);
|
|
|
|
/*
|
|
* LockPhysicalMediaWithPool
|
|
*
|
|
* Warning: ugly function
|
|
*
|
|
* We frequently need to lock a piece of media as well as
|
|
* its media pool.
|
|
* To avoid deadlock, we have to acquire the locks top-down
|
|
* (starting with the pool). But that's difficult since we're starting
|
|
* with the physical media pointer.
|
|
* This function enters the media pool and physical media
|
|
* critical sections in the right order.
|
|
* Subsequently, the caller can safely call subroutines that re-enter
|
|
* these critical sections in any order.
|
|
*/
|
|
BOOLEAN LockPhysicalMediaWithPool(PHYSICAL_MEDIA *physMedia)
|
|
{
|
|
return LockPhysicalMediaWithPool_Iter(physMedia, 10);
|
|
}
|
|
BOOLEAN LockPhysicalMediaWithPool_Iter(PHYSICAL_MEDIA *physMedia, ULONG numTries){
|
|
MEDIA_POOL *mediaPool;
|
|
BOOLEAN success = FALSE;
|
|
|
|
/*
|
|
* 1. Get an (unreliable) snapshot of the heirarchy without grabbing
|
|
* more than one lock at a time. If the media is in a pool,
|
|
* reference it temporarily so that it doesn't go away while
|
|
* we drop the media lock (which can then lose its ref on the pool).
|
|
*/
|
|
EnterCriticalSection(&physMedia->lock);
|
|
mediaPool = physMedia->owningMediaPool;
|
|
if (mediaPool){
|
|
RefObject(mediaPool);
|
|
}
|
|
LeaveCriticalSection(&physMedia->lock);
|
|
|
|
/*
|
|
* 2. Now grab the locks for the pool and media in the right order.
|
|
* Then check the hierarchy again.
|
|
* If its the same, we're done; otherwise, try again.
|
|
*
|
|
*/
|
|
if (mediaPool){
|
|
/*
|
|
* We referenced the media pool, so its guaranteed to still exist.
|
|
* But the media may have been moved out of it while we
|
|
* let go of the lock. If the hierarchy is still the same, then
|
|
* we've got both the media and pool locked in the right order.
|
|
* Otherwise, we have to back off and try again.
|
|
*/
|
|
EnterCriticalSection(&mediaPool->lock);
|
|
EnterCriticalSection(&physMedia->lock);
|
|
if (physMedia->owningMediaPool == mediaPool){
|
|
success = TRUE;
|
|
}
|
|
else {
|
|
LeaveCriticalSection(&physMedia->lock);
|
|
LeaveCriticalSection(&mediaPool->lock);
|
|
}
|
|
|
|
DerefObject(mediaPool);
|
|
}
|
|
else {
|
|
/*
|
|
* If after locking the media again it is still not in any pool,
|
|
* we are set to go.
|
|
*/
|
|
EnterCriticalSection(&physMedia->lock);
|
|
if (physMedia->owningMediaPool){
|
|
LeaveCriticalSection(&physMedia->lock);
|
|
}
|
|
else {
|
|
success = TRUE;
|
|
}
|
|
}
|
|
|
|
if (!success && (numTries > 0)){
|
|
/*
|
|
* Try again by calling ourselves RECURSIVELY.
|
|
*/
|
|
Sleep(1);
|
|
success = LockPhysicalMediaWithPool_Iter(physMedia, numTries-1);
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
|
|
/*
|
|
* UnlockPhysicalMediaWithPool
|
|
*
|
|
* Undo LockPhysicalMediaWithPool.
|
|
*/
|
|
VOID UnlockPhysicalMediaWithPool(PHYSICAL_MEDIA *physMedia)
|
|
{
|
|
if (physMedia->owningMediaPool){
|
|
LeaveCriticalSection(&physMedia->owningMediaPool->lock);
|
|
}
|
|
LeaveCriticalSection(&physMedia->lock);
|
|
}
|
|
|
|
|
|
/*
|
|
* LockPhysicalMediaWithLibrary
|
|
*
|
|
* Warning: ugly function
|
|
*
|
|
* Like LockPhysicalMediaWithPool, but locks the media pool
|
|
* and the library. Acquires locks in the right
|
|
* order (top to down) despite the fact that we're starting
|
|
* from the bottom with the media.
|
|
* Note that we don't have to actually grab locks for all
|
|
* the media sub-pools in the hierarchy. The media pool configuration
|
|
* does not change while the library lock is held.
|
|
*/
|
|
BOOLEAN LockPhysicalMediaWithLibrary(PHYSICAL_MEDIA *physMedia)
|
|
{
|
|
return LockPhysicalMediaWithLibrary_Iter(physMedia, 10);
|
|
}
|
|
BOOLEAN LockPhysicalMediaWithLibrary_Iter(PHYSICAL_MEDIA *physMedia, ULONG numTries)
|
|
{
|
|
LIBRARY *lib = NULL;
|
|
MEDIA_POOL *mediaPool = NULL;
|
|
BOOLEAN success = FALSE;
|
|
|
|
success = LockPhysicalMediaWithPool(physMedia);
|
|
if (success){
|
|
/*
|
|
* Reference the library so it doesn't go away while
|
|
* we drop the locks.
|
|
*/
|
|
mediaPool = physMedia->owningMediaPool;
|
|
if (mediaPool){
|
|
RefObject(mediaPool);
|
|
lib = mediaPool->owningLibrary;
|
|
if (lib){
|
|
RefObject(lib);
|
|
}
|
|
}
|
|
UnlockPhysicalMediaWithPool(physMedia);
|
|
|
|
/*
|
|
* Now grab the locks in the right order and check if
|
|
* the configuration hasn't changed while we dropped the lock.
|
|
*/
|
|
if (lib){
|
|
EnterCriticalSection(&lib->lock);
|
|
success = LockPhysicalMediaWithPool(physMedia);
|
|
if (success){
|
|
if (physMedia->owningMediaPool &&
|
|
(physMedia->owningMediaPool->owningLibrary == lib)){
|
|
|
|
}
|
|
else {
|
|
UnlockPhysicalMediaWithPool(physMedia);
|
|
success = FALSE;
|
|
}
|
|
}
|
|
|
|
if (!success){
|
|
LeaveCriticalSection(&lib->lock);
|
|
}
|
|
DerefObject(lib);
|
|
}
|
|
else {
|
|
/*
|
|
* Media is not in any pool or lib ?
|
|
* Just make sure nothing's changed while we dropped the lock.
|
|
*/
|
|
success = LockPhysicalMediaWithPool(physMedia);
|
|
if (mediaPool){
|
|
if ((physMedia->owningMediaPool == mediaPool) &&
|
|
(mediaPool->owningLibrary == lib)){
|
|
}
|
|
else {
|
|
UnlockPhysicalMediaWithPool(physMedia);
|
|
success = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if (!success && (numTries > 0)){
|
|
success = LockPhysicalMediaWithLibrary_Iter(physMedia, numTries-1);
|
|
}
|
|
return success;
|
|
}
|
|
|
|
|
|
VOID UnlockPhysicalMediaWithLibrary(PHYSICAL_MEDIA *physMedia)
|
|
{
|
|
if (physMedia->owningMediaPool &&
|
|
physMedia->owningMediaPool->owningLibrary){
|
|
|
|
LeaveCriticalSection(&physMedia->owningMediaPool->owningLibrary->lock);
|
|
}
|
|
UnlockPhysicalMediaWithPool(physMedia);
|
|
}
|
|
|
|
|