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.
241 lines
8.5 KiB
241 lines
8.5 KiB
/*++ BUILD Version: 0009 // Increment this if a change has global effect
|
|
Copyright (c) 1987-1998 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
remoteboot.c
|
|
|
|
Abstract:
|
|
|
|
This is the source file that implements the silent reconnection form the client to the server.
|
|
|
|
Author:
|
|
|
|
Yun Lin (YunLin) 21-April-98 Created
|
|
|
|
Notes:
|
|
|
|
The remote boot client is the workstation that boots up from the boot server. The connection
|
|
between the remote boot client and server is different from the one between ordinary client
|
|
server in such a way that losing the connection to the boot server, the remote boot client
|
|
may not function properly, sometime even crash.
|
|
|
|
The make the connection between the remote boot client and server more relaible, we introduce
|
|
a machanism that in case of connection fails, the RDR try to reconnect to the boot server
|
|
transparently to the applications.
|
|
|
|
The reconnection can be initiated in three places: initialize a exchange, in the middle of read
|
|
and write. The reconnection is triggered by the mis-matching of server verion stored on the
|
|
server and the one stored on smbSrvOpen which happens on a remote boot session.
|
|
|
|
The reconnection process starts with seting up a new session to the boot server. If it succeed,
|
|
it checks if the paging file is on the boot (in case of diskless client). If ture, it re-opens
|
|
the paging file with the same create options stored on the deferred open context created. When
|
|
a file is successful opened on the boot server at first time, the client creates a open context
|
|
for the file storing all the desired access and create options.
|
|
|
|
After re-opens the paging file or it is on the local disk, the reconnection code re-opens the
|
|
file as if it is a deferred open file. As the file is successfully opened, the old FID and the
|
|
server version are updated. The operation on the file can be resumed without noticing of the
|
|
user.
|
|
|
|
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
RXDT_DefineCategory(RECONNECT);
|
|
#define Dbg (DEBUG_TRACE_RECONNECT)
|
|
|
|
BOOLEAN PagedFileReconnectInProgress = FALSE;
|
|
LIST_ENTRY PagedFileReconnectSynchronizationExchanges;
|
|
extern LIST_ENTRY MRxSmbPagingFilesSrvOpenList;
|
|
|
|
NTSTATUS
|
|
SmbCeRemoteBootReconnect(
|
|
PSMB_EXCHANGE pExchange,
|
|
PRX_CONTEXT RxContext)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine reconnects the paged file first, and then re-open the given file on the server
|
|
in case of remote boot client.
|
|
|
|
Arguments:
|
|
|
|
pExchange - the placeholder for the exchange instance.
|
|
|
|
pRxContext - the associated RxContext
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The return status for the operation
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
RxCaptureFcb;
|
|
RxCaptureFobx;
|
|
PLIST_ENTRY pListHead;
|
|
PLIST_ENTRY pListEntry;
|
|
KAPC_STATE ApcState;
|
|
PRX_CONTEXT RxContextOfPagedFile;
|
|
BOOLEAN AttachToSystemProcess = FALSE;
|
|
PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
|
|
PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
|
|
PSMBCEDB_SERVER_ENTRY pServerEntry = SmbCeGetExchangeServerEntry(pExchange);
|
|
|
|
DbgPrint("Re-open %wZ\n",GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext));
|
|
|
|
if (pServerEntry->Server.CscState == ServerCscDisconnected) {
|
|
return STATUS_CONNECTION_DISCONNECTED;
|
|
}
|
|
|
|
if (IoGetCurrentProcess() != RxGetRDBSSProcess()) {
|
|
KeStackAttachProcess(RxGetRDBSSProcess(),&ApcState);
|
|
AttachToSystemProcess = TRUE;
|
|
}
|
|
|
|
SmbCeAcquireResource();
|
|
SmbCeAcquireSpinLock();
|
|
|
|
if (!PagedFileReconnectInProgress) {
|
|
InitializeListHead(&PagedFileReconnectSynchronizationExchanges);
|
|
PagedFileReconnectInProgress = TRUE;
|
|
SmbCeReleaseSpinLock();
|
|
SmbCeReleaseResource();
|
|
|
|
SmbCeUninitializeExchangeTransport(pExchange);
|
|
|
|
SmbCeReferenceServerEntry(pServerEntry);
|
|
SmbCeResumeAllOutstandingRequestsOnError(pServerEntry);
|
|
|
|
if (pServerEntry->Header.State == SMBCEDB_INVALID &&
|
|
pServerEntry->Server.CscState != ServerCscDisconnected) {
|
|
|
|
do {
|
|
SmbCeUpdateServerEntryState(pServerEntry,
|
|
SMBCEDB_CONSTRUCTION_IN_PROGRESS);
|
|
|
|
Status = SmbCeInitializeServerTransport(pServerEntry,NULL,NULL);
|
|
|
|
if (Status == STATUS_SUCCESS) {
|
|
Status = SmbCeNegotiate(
|
|
pServerEntry,
|
|
pServerEntry->pRdbssSrvCall,
|
|
pServerEntry->Server.IsRemoteBootServer
|
|
);
|
|
}
|
|
} while ((Status == STATUS_IO_TIMEOUT ||
|
|
Status == STATUS_BAD_NETWORK_PATH ||
|
|
Status == STATUS_NETWORK_UNREACHABLE ||
|
|
Status == STATUS_USER_SESSION_DELETED ||
|
|
Status == STATUS_REMOTE_NOT_LISTENING ||
|
|
Status == STATUS_CONNECTION_DISCONNECTED) &&
|
|
pServerEntry->Server.CscState != ServerCscDisconnected);
|
|
|
|
SmbCeCompleteServerEntryInitialization(pServerEntry,Status);
|
|
}
|
|
|
|
if (pServerEntry->Server.CscState == ServerCscDisconnected) {
|
|
Status = STATUS_CONNECTION_DISCONNECTED;
|
|
}
|
|
|
|
SmbCeAcquireResource();
|
|
SmbCeAcquireSpinLock();
|
|
|
|
pListHead = &PagedFileReconnectSynchronizationExchanges;
|
|
pListEntry = pListHead->Flink;
|
|
|
|
while (pListEntry != pListHead) {
|
|
PSMB_EXCHANGE pWaitingExchange;
|
|
|
|
pWaitingExchange = (PSMB_EXCHANGE)CONTAINING_RECORD(pListEntry,SMB_EXCHANGE,ExchangeList);
|
|
|
|
pListEntry = pListEntry->Flink;
|
|
RemoveEntryList(&pWaitingExchange->ExchangeList);
|
|
InitializeListHead(&pWaitingExchange->ExchangeList);
|
|
|
|
pWaitingExchange->SmbStatus = Status;
|
|
|
|
//DbgPrint("Signal Exchange %x after reconnect.\n",pWaitingExchange);
|
|
RxSignalSynchronousWaiter(pWaitingExchange->RxContext);
|
|
}
|
|
|
|
PagedFileReconnectInProgress = FALSE;
|
|
|
|
SmbCeReleaseSpinLock();
|
|
SmbCeReleaseResource();
|
|
} else {
|
|
InsertTailList(
|
|
&PagedFileReconnectSynchronizationExchanges,
|
|
&pExchange->ExchangeList);
|
|
|
|
SmbCeReleaseSpinLock();
|
|
SmbCeReleaseResource();
|
|
|
|
SmbCeUninitializeExchangeTransport(pExchange);
|
|
|
|
//DbgPrint("Exchange %x waits for re-open paged file on %wZ\n",pExchange,&pServerEntry->Name);
|
|
RxWaitSync(RxContext);
|
|
//DbgPrint("Resume exchange %x\n",pExchange);
|
|
|
|
KeInitializeEvent(
|
|
&RxContext->SyncEvent,
|
|
SynchronizationEvent,
|
|
FALSE);
|
|
|
|
Status = pExchange->SmbStatus;
|
|
}
|
|
|
|
if (Status == STATUS_SUCCESS &&
|
|
!FlagOn(capFcb->FcbState, FCB_STATE_PAGING_FILE) &&
|
|
pServerEntry->Server.CscState != ServerCscDisconnected) {
|
|
LONG HotReconnecteInProgress;
|
|
|
|
HotReconnecteInProgress = InterlockedExchange(&smbSrvOpen->HotReconnectInProgress,1);
|
|
|
|
do {
|
|
Status = MRxSmbDeferredCreate(RxContext);
|
|
|
|
if (Status == STATUS_CONNECTION_DISCONNECTED) {
|
|
SmbCeTransportDisconnectIndicated(pServerEntry);
|
|
}
|
|
|
|
if (Status != STATUS_SUCCESS) {
|
|
LARGE_INTEGER time;
|
|
LARGE_INTEGER Delay = {0,-1};
|
|
ULONG Interval;
|
|
|
|
// Select a random delay within 6 seconds.
|
|
KeQuerySystemTime(&time);
|
|
Interval = RtlRandom(&time.LowPart) % 60000000;
|
|
Delay.LowPart = MAXULONG - Interval;
|
|
|
|
KeDelayExecutionThread(KernelMode, FALSE, &Delay);
|
|
}
|
|
} while ((Status == STATUS_RETRY ||
|
|
Status == STATUS_IO_TIMEOUT ||
|
|
Status == STATUS_BAD_NETWORK_PATH ||
|
|
Status == STATUS_NETWORK_UNREACHABLE ||
|
|
Status == STATUS_USER_SESSION_DELETED ||
|
|
Status == STATUS_REMOTE_NOT_LISTENING ||
|
|
Status == STATUS_CONNECTION_DISCONNECTED) &&
|
|
pServerEntry->Server.CscState != ServerCscDisconnected);
|
|
|
|
if (HotReconnecteInProgress == 0) {
|
|
smbSrvOpen->HotReconnectInProgress = 0;
|
|
}
|
|
}
|
|
|
|
if (AttachToSystemProcess) {
|
|
KeUnstackDetachProcess(&ApcState);
|
|
}
|
|
|
|
DbgPrint("Re-open return %x\n", Status);
|
|
|
|
return Status;
|
|
}
|