Leaked source code of windows server 2003
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.
 
 
 
 
 
 

550 lines
16 KiB

//////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 1999-2001 Microsoft Corporation
//
// Module Name:
// CClusDiskJoin.cpp
//
// Description:
// Contains the definition of the CClusDiskJoin class.
//
// Maintained By:
// David Potter (DavidP) 14-JUN-2001
// Vij Vasu (Vvasu) 08-MAR-2000
//
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
// Include Files
//////////////////////////////////////////////////////////////////////////////
// The precompiled header.
#include "Pch.h"
// The header for this file
#include "CClusDiskJoin.h"
// For the CBaseClusterJoin class.
#include "CBaseClusterJoin.h"
// For the CImpersonateUser class.
#include "CImpersonateUser.h"
//////////////////////////////////////////////////////////////////////////////
// Macro definitions
//////////////////////////////////////////////////////////////////////////////
// Name of the private property of a physical disk resouce that has its signature.
#define PHYSICAL_DISK_SIGNATURE_PRIVPROP_NAME L"Signature"
//////////////////////////////////////////////////////////////////////////////
//++
//
// CClusDiskJoin::CClusDiskJoin
//
// Description:
// Constructor of the CClusDiskJoin class
//
// Arguments:
// pbcjParentActionIn
// Pointer to the base cluster action of which this action is a part.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// Any exceptions thrown by underlying functions
//
//--
//////////////////////////////////////////////////////////////////////////////
CClusDiskJoin::CClusDiskJoin(
CBaseClusterJoin * pbcjParentActionIn
)
: BaseClass( pbcjParentActionIn )
, m_nSignatureArraySize( 0 )
, m_nSignatureCount( 0 )
{
TraceFunc( "" );
SetRollbackPossible( true );
TraceFuncExit();
} //*** CClusDiskJoin::CClusDiskJoin
//////////////////////////////////////////////////////////////////////////////
//++
//
// CClusDiskJoin::~CClusDiskJoin
//
// Description:
// Destructor of the CClusDiskJoin class.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// Any exceptions thrown by underlying functions
//
//--
//////////////////////////////////////////////////////////////////////////////
CClusDiskJoin::~CClusDiskJoin( void )
{
TraceFunc( "" );
TraceFuncExit();
} //*** CClusDiskJoin::~CClusDiskJoin
//////////////////////////////////////////////////////////////////////////////
//++
//
// CClusDiskJoin::Commit
//
// Description:
// Configure and start the service.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// Any that are thrown by the contained actions.
//
//--
//////////////////////////////////////////////////////////////////////////////
void
CClusDiskJoin::Commit( void )
{
TraceFunc( "" );
// Call the base class commit method.
BaseClass::Commit();
try
{
// Create and start the service.
ConfigureService();
// Try and attach to all the disks that the sponsor knows about.
AttachToClusteredDisks();
} // try:
catch( ... )
{
// If we are here, then something went wrong with the create.
LogMsg( "[BC] Caught exception during commit." );
//
// Cleanup anything that the failed create might have done.
// Catch any exceptions thrown during Cleanup to make sure that there
// is no collided unwind.
//
try
{
CleanupService();
}
catch( ... )
{
//
// The rollback of the committed action has failed.
// There is nothing that we can do.
// We certainly cannot rethrow this exception, since
// the exception that caused the rollback is more important.
//
TW32( ERROR_CLUSCFG_ROLLBACK_FAILED );
LogMsg( "[BC] THIS COMPUTER MAY BE IN AN INVALID STATE. Caught an exception during cleanup." );
} // catch: all
// Rethrow the exception thrown by commit.
throw;
} // catch: all
// If we are here, then everything went well.
SetCommitCompleted( true );
TraceFuncExit();
} //*** CClusDiskJoin::Commit
//////////////////////////////////////////////////////////////////////////////
//++
//
// CClusDiskJoin::Rollback
//
// Description:
// Cleanup the service.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// Any that are thrown by the underlying functions.
//
//--
//////////////////////////////////////////////////////////////////////////////
void
CClusDiskJoin::Rollback( void )
{
TraceFunc( "" );
// Call the base class rollback method.
BaseClass::Rollback();
// Cleanup the service.
CleanupService();
SetCommitCompleted( false );
TraceFuncExit();
} //*** CClusDiskJoin::Rollback
//////////////////////////////////////////////////////////////////////////////
//++
//
// CClusDiskJoin::AttachToClusteredDisks
//
// Description:
// Get the signatures of all disks that have been clustered from the sponsor.
// Attach to all these disks.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// CRuntimeError
// If any of the APIs fail.
//
// Any that are thrown by the underlying functions.
//
//--
//////////////////////////////////////////////////////////////////////////////
void
CClusDiskJoin::AttachToClusteredDisks( void )
{
TraceFunc( "" );
DWORD sc = ERROR_SUCCESS;
// Get the parent action pointer.
CBaseClusterJoin * pcjClusterJoin = dynamic_cast< CBaseClusterJoin *>( PbcaGetParent() );
// If the parent action of this action is not CBaseClusterJoin
if ( pcjClusterJoin == NULL )
{
THROW_ASSERT( E_POINTER, "The parent action of this action is not CBaseClusterJoin." );
} // an invalid pointer was passed in.
//
// Connect to the sponsor cluster and get the signatures of all clustered disks.
//
// Smart handle to sponsor cluster
SmartClusterHandle schSponsorCluster;
LogMsg( "[BC] Attempting to impersonate the cluster service account." );
// Impersonate the cluster service account, so that we can contact the sponsor cluster.
// The impersonation is automatically ended when this object is destroyed.
CImpersonateUser ciuImpersonateClusterServiceAccount( pcjClusterJoin->HGetClusterServiceAccountToken() );
{
LogMsg( "[BC] Opening a cluster handle to the sponsor cluster with the '%ws' binding string.", pcjClusterJoin->RStrGetClusterBindingString().PszData() );
// Open a handle to the sponsor cluster.
HCLUSTER hSponsorCluster = OpenCluster( pcjClusterJoin->RStrGetClusterBindingString().PszData() );
// Assign it to a smart handle for safe release.
schSponsorCluster.Assign( hSponsorCluster );
}
// Did we succeed in opening a handle to the sponsor cluster?
if ( schSponsorCluster.FIsInvalid() )
{
sc = TW32( GetLastError() );
LogMsg( "[BC] Error %#08x occurred trying to open a cluster handle to the sponsor cluster with the '%ws' binding string.", sc, pcjClusterJoin->RStrGetClusterBindingString().PszData() );
goto Cleanup;
} // if: OpenCluster() failed
LogMsg( "[BC] Enumerating all '%s' resources in the cluster.", CLUS_RESTYPE_NAME_PHYS_DISK );
// Enumerate all the physical disk resouces in the cluster and get their signatures.
sc = TW32( ResUtilEnumResourcesEx(
schSponsorCluster.HHandle()
, NULL
, CLUS_RESTYPE_NAME_PHYS_DISK
, S_ScResourceEnumCallback
, this
) );
if ( sc != ERROR_SUCCESS )
{
// Free the signature array.
m_rgdwSignatureArray.PRelease();
m_nSignatureArraySize = 0;
m_nSignatureCount = 0;
LogMsg( "[BC] An error occurred trying enumerate resources in the sponsor cluster." );
goto Cleanup;
} // if: ResUtilEnumResourcesEx() failed
Cleanup:
if ( sc != ERROR_SUCCESS )
{
LogMsg( "[BC] Error %#08x occurred trying to attach to the disks in the sponsor cluster. Throwing an exception.", sc );
THROW_RUNTIME_ERROR( HRESULT_FROM_WIN32( sc ), IDS_ERROR_CLUSDISK_CONFIGURE );
} // if: something has gone wrong
else
{
LogMsg( "[BC] Attaching to the %d disks in the sponsor cluster.", m_nSignatureCount );
AttachToDisks(
m_rgdwSignatureArray.PMem()
, m_nSignatureCount
);
} // else: everything has gone well so far
TraceFuncExit();
} //*** CClusDiskJoin::AttachToClusteredDisks
//////////////////////////////////////////////////////////////////////////////
//++
//
// CClusDiskJoin::ScAddSignature
//
// Description:
// Add a signature to the array of signatures of disks that ClusDisk should
// attach to. If the array is already full, grow the array.
//
// Arguments:
// dwSignatureIn
// Signature to be added to the array.
//
// Return Value:
// ERROR_SUCCESS
// If everything was ok.
//
// Other Win32 error codes on failure.
//
// Exceptions Thrown:
// None. This function is called from a callback routine and therefore
// cannot throw any exceptions.
//
//--
//////////////////////////////////////////////////////////////////////////////
DWORD
CClusDiskJoin::ScAddSignature( DWORD dwSignatureIn ) throw()
{
TraceFunc( "" );
DWORD sc = ERROR_SUCCESS;
// Is the capacity of the array reached?
if ( m_nSignatureCount == m_nSignatureArraySize )
{
// Increase the array size by a random amount.
const int nGrowSize = 256;
TraceFlow2( "Signature count has reached array size ( %d ). Growing array by %d.", m_nSignatureArraySize, nGrowSize );
m_nSignatureArraySize += nGrowSize;
// Grow the array.
DWORD * pdwNewArray = new DWORD[ m_nSignatureArraySize ];
if ( pdwNewArray == NULL )
{
LogMsg( "[BC] Memory allocation failed trying to allocate %d DWORDs for signatures.", m_nSignatureArraySize );
sc = TW32( ERROR_OUTOFMEMORY );
goto Cleanup;
} // if: memory allocation failed
// Copy the old array into the new one.
CopyMemory( pdwNewArray, m_rgdwSignatureArray.PMem(), m_nSignatureCount * sizeof( DWORD ) );
// Free the old array and store the new one.
m_rgdwSignatureArray.Assign( pdwNewArray );
} // if: the array capacity has been reached
// Store the new signature in next array location
( m_rgdwSignatureArray.PMem() )[ m_nSignatureCount ] = dwSignatureIn;
++m_nSignatureCount;
TraceFlow2( "Signature %#08X added to array. There are now %d signature in the array.", dwSignatureIn, m_nSignatureCount );
Cleanup:
W32RETURN( sc );
} //*** CClusDiskJoin::ScAddSignature
//////////////////////////////////////////////////////////////////////////////
//++
//
// static
// CClusDiskJoin::S_ScResourceEnumCallback
//
// Description:
// This function is called back for every physical disk resouce by
// ResUtilEnumResourcesEx() as a part of enumerating resources.
// This function gets the signature of the current physical disk
// resource and stores it in the object that initiated the enumeration
// ( the pointer to the object is in parameter 4 ).
//
// Arguments:
// hClusterIn
// Handle to the cluster whose resources are being enumerated.
//
// hSelfIn
// hSelfIn passed to ResUtilEnumResourcesEx(), if any.
//
// hCurrentResourceIn
// Handle to the current resource.
//
// pvParamIn
// Pointer to the object of this class that initiated this enumeration.
//
// Return Value:
// ERROR_SUCCESS
// If everything was ok.
//
// Other Win32 error codes on failure.
// Returning an error code will terminate the enumeration.
//
// Exceptions Thrown:
// None. This function is called from a callback routine and therefore
// cannot throw any exceptions.
//
//--
//////////////////////////////////////////////////////////////////////////////
DWORD
CClusDiskJoin::S_ScResourceEnumCallback(
HCLUSTER hClusterIn
, HRESOURCE hSelfIn
, HRESOURCE hCurrentResourceIn
, PVOID pvParamIn
)
{
TraceFunc( "" );
DWORD sc = ERROR_SUCCESS;
CClusDiskJoin * pcdjThisObject = reinterpret_cast< CClusDiskJoin * >( pvParamIn );
//
// Get the 'Signature' private property of this physical disk.
//
SmartByteArray sbaPropertyBuffer;
DWORD dwBytesReturned = 0;
DWORD dwBufferSize;
DWORD dwSignature = 0;
LogMsg( "[BC] Trying to get the signature of the disk resource whose handle is %p.", hCurrentResourceIn );
// Get the size of the buffer required to hold all the private properties of this resource.
sc = ClusterResourceControl(
hCurrentResourceIn
, NULL
, CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES
, NULL
, 0
, NULL
, 0
, &dwBytesReturned
);
if ( ( sc != ERROR_MORE_DATA ) && ( sc != ERROR_SUCCESS ) )
{
// Something went wrong.
TW32( sc );
LogMsg( "[BC] Error %#08x getting size of required buffer for private properties.", sc );
goto Cleanup;
} // if: the return value of ClusterResourceControl() was not ERROR_MORE_DATA
dwBufferSize = dwBytesReturned;
// Allocate the memory required for the property buffer.
sbaPropertyBuffer.Assign( new BYTE[ dwBufferSize ] );
if ( sbaPropertyBuffer.FIsEmpty() )
{
LogMsg( "[BC] Memory allocation failed trying to allocate %d bytes.", dwBufferSize );
sc = TW32( ERROR_OUTOFMEMORY );
goto Cleanup;
} // if: memory allocation failed
// Get the all the private properties of this resource.
sc = TW32( ClusterResourceControl(
hCurrentResourceIn
, NULL
, CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES
, NULL
, 0
, sbaPropertyBuffer.PMem()
, dwBufferSize
, &dwBytesReturned
) );
if ( sc != ERROR_SUCCESS )
{
LogMsg( "[BC] Error %#08x getting private properties.", sc );
goto Cleanup;
} // if: an error occurring trying to get the private properties.
// Get the signature of this disk resource.
sc = TW32( ResUtilFindDwordProperty(
sbaPropertyBuffer.PMem()
, dwBufferSize
, PHYSICAL_DISK_SIGNATURE_PRIVPROP_NAME
, &dwSignature
) );
if ( sc != ERROR_SUCCESS )
{
LogMsg( "[BC] Error %#08x occurred trying to get the value of the '%ws' property from the private property list.", sc, PHYSICAL_DISK_SIGNATURE_PRIVPROP_NAME );
goto Cleanup;
} // if: we could not get the signature
sc = TW32( pcdjThisObject->ScAddSignature( dwSignature ) );
if ( sc != ERROR_SUCCESS )
{
LogMsg( "[BC] Error %#08x occurred trying to add the signature to the signature array." );
goto Cleanup;
} // if: we could not store the signature
Cleanup:
W32RETURN( sc );
} //*** CClusDiskJoin::S_ScResourceEnumCallback