Source code of Windows XP (NT5)
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.

2338 lines
62 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. fspinit.c
  5. Abstract:
  6. This module implements the initialization phase of the LAN Manager
  7. server File System Process.
  8. Author:
  9. Chuck Lenzmeier (chuckl) 22-Sep-1989
  10. David Treadwell (davidtr)
  11. Revision History:
  12. --*/
  13. #include "precomp.h"
  14. #include "fspinit.tmh"
  15. #pragma hdrstop
  16. #define BugCheckFileId SRV_FILE_FSPINIT
  17. //
  18. // Forward declarations.
  19. //
  20. PIRP
  21. DequeueConfigurationIrp (
  22. VOID
  23. );
  24. STATIC
  25. NTSTATUS
  26. InitializeServer (
  27. VOID
  28. );
  29. STATIC
  30. NTSTATUS
  31. TerminateServer (
  32. VOID
  33. );
  34. VOID
  35. SrvFreeRegTables (
  36. VOID
  37. );
  38. VOID
  39. SrvGetRegTables (
  40. VOID
  41. );
  42. #if SRVNTVERCHK
  43. VOID
  44. SrvGetRegClientNumber (
  45. VOID
  46. );
  47. #endif
  48. VOID
  49. StartQueueDepthComputations(
  50. PWORK_QUEUE queue
  51. );
  52. VOID
  53. StopQueueDepthComputations(
  54. PWORK_QUEUE queue
  55. );
  56. VOID
  57. ComputeAvgQueueDepth (
  58. IN PKDPC Dpc,
  59. IN PVOID DeferredContext,
  60. IN PVOID SystemArgument1,
  61. IN PVOID SystemArgument2
  62. );
  63. BOOLEAN
  64. GenerateCrcTable();
  65. BOOLEAN
  66. CleanupCrcTable();
  67. #ifdef ALLOC_PRAGMA
  68. #pragma alloc_text( PAGE, SrvConfigurationThread )
  69. #pragma alloc_text( PAGE, InitializeServer )
  70. #pragma alloc_text( PAGE, TerminateServer )
  71. #pragma alloc_text( PAGE, SrvFreeRegTables )
  72. #pragma alloc_text( PAGE, SrvGetRegTables )
  73. #if SRVNTVERCHK
  74. #pragma alloc_text( PAGE, SrvGetRegClientNumber )
  75. #endif
  76. #pragma alloc_text( PAGE, DequeueConfigurationIrp )
  77. #pragma alloc_text( PAGE, StartQueueDepthComputations )
  78. #endif
  79. VOID
  80. SrvConfigurationThread (
  81. IN PDEVICE_OBJECT pDevice,
  82. IN PIO_WORKITEM pWorkItem
  83. )
  84. /*++
  85. Routine Description:
  86. This routine processes configuration IRPs.
  87. Arguments:
  88. None.
  89. Return Value:
  90. None.
  91. --*/
  92. {
  93. NTSTATUS status;
  94. PIRP irp;
  95. PIO_STACK_LOCATION irpSp;
  96. ULONG code;
  97. PAGED_CODE( );
  98. IF_DEBUG(FSP1) KdPrint(( "SrvConfigurationThread entered\n" ));
  99. //
  100. // Loop processing requests.
  101. //
  102. while ( TRUE ) {
  103. irp = DequeueConfigurationIrp( );
  104. if ( irp == NULL ) break;
  105. ASSERT( (LONG)SrvConfigurationIrpsInProgress >= 1 );
  106. //
  107. // Get the IRP stack pointer.
  108. //
  109. irpSp = IoGetCurrentIrpStackLocation( irp );
  110. if( irpSp->MajorFunction == IRP_MJ_CLOSE ) {
  111. //
  112. // If the dispatcher routed this irp here, it means
  113. // that we unexpectededly got the last handle close without
  114. // having gotten cleanly terminated first. Ok, so we should
  115. // shut ourselves down, since we can't sensibly run without
  116. // our usermode counterpart.
  117. //
  118. ACQUIRE_LOCK( &SrvStartupShutdownLock );
  119. status = TerminateServer();
  120. RELEASE_LOCK( &SrvStartupShutdownLock );
  121. } else {
  122. ASSERT( irpSp->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL );
  123. try {
  124. //
  125. // Dispatch on the FsControlCode.
  126. //
  127. code = irpSp->Parameters.FileSystemControl.FsControlCode;
  128. switch ( code ) {
  129. case FSCTL_SRV_STARTUP:
  130. ACQUIRE_LOCK( &SrvStartupShutdownLock );
  131. status = InitializeServer();
  132. if ( !NT_SUCCESS(status) ) {
  133. //
  134. // Terminate the server FSP.
  135. //
  136. (void)TerminateServer();
  137. }
  138. RELEASE_LOCK( &SrvStartupShutdownLock );
  139. break;
  140. case FSCTL_SRV_SHUTDOWN:
  141. ACQUIRE_LOCK( &SrvStartupShutdownLock );
  142. status = TerminateServer();
  143. RELEASE_LOCK( &SrvStartupShutdownLock );
  144. //
  145. // If there is more than one handle open to the server
  146. // device (i.e., any handles other than the server service's
  147. // handle), return a special status code to the caller (who
  148. // should be the server service). This tells the caller to
  149. // NOT unload the driver, in order prevent weird situations
  150. // where the driver is sort of unloaded, so it can't be used
  151. // but also can't be reloaded, thus preventing the server
  152. // from being restarted.
  153. //
  154. if( NT_SUCCESS( status ) && SrvOpenCount != 1 ) {
  155. status = STATUS_SERVER_HAS_OPEN_HANDLES;
  156. }
  157. break;
  158. case FSCTL_SRV_REGISTRY_CHANGE:
  159. //
  160. // The Parameters section of the server service registry has changed.
  161. // That's likely due to somebody changing the Null Session pipe or
  162. // share lists. Pick up the new settings.
  163. //
  164. ACQUIRE_LOCK( &SrvConfigurationLock );
  165. SrvFreeRegTables();
  166. SrvGetRegTables();
  167. #if SRVNTVERCHK
  168. SrvGetRegClientNumber();
  169. #endif
  170. RELEASE_LOCK( &SrvConfigurationLock );
  171. status = STATUS_SUCCESS;
  172. break;
  173. case FSCTL_SRV_BEGIN_PNP_NOTIFICATIONS:
  174. //
  175. // If somebody tries to shut down the server while
  176. // we are registering our handlers, block them until
  177. // we are finished.
  178. //
  179. ACQUIRE_LOCK( &SrvStartupShutdownLock );
  180. {
  181. TDI_CLIENT_INTERFACE_INFO ClientInterfaceInfo;
  182. RtlZeroMemory(&ClientInterfaceInfo, sizeof(TDI_CLIENT_INTERFACE_INFO));
  183. ClientInterfaceInfo.MajorTdiVersion = 2;
  184. ClientInterfaceInfo.MinorTdiVersion = 0;
  185. ClientInterfaceInfo.ClientName = &StrRegSrvPnpClientName;
  186. ClientInterfaceInfo.BindingHandler = SrvPnpBindingHandler;
  187. ClientInterfaceInfo.PnPPowerHandler = SrvPnpPowerHandler;
  188. status = TdiRegisterPnPHandlers(
  189. &ClientInterfaceInfo,
  190. sizeof( ClientInterfaceInfo ),
  191. &SrvTdiNotificationHandle
  192. );
  193. if (status != STATUS_SUCCESS) {
  194. SrvTdiNotificationHandle = NULL;
  195. }
  196. }
  197. RELEASE_LOCK( &SrvStartupShutdownLock );
  198. if( !NT_SUCCESS( status ) ) {
  199. IF_DEBUG( PNP ) {
  200. KdPrint(("TdiRegisterNotificationHandler: status %X\n", status ));
  201. }
  202. SrvLogServiceFailure( SRV_SVC_PNP_TDI_NOTIFICATION, status );
  203. }
  204. //
  205. // Allow the transports to begin receiving connections
  206. //
  207. SrvCompletedPNPRegistration = TRUE;
  208. break;
  209. case FSCTL_SRV_XACTSRV_CONNECT:
  210. {
  211. ANSI_STRING ansiPortName;
  212. UNICODE_STRING portName;
  213. IF_DEBUG(XACTSRV) {
  214. KdPrint(( "SrvFspConfigurationThread: XACTSRV FSCTL "
  215. "received.\n" ));
  216. }
  217. ansiPortName.Buffer = irp->AssociatedIrp.SystemBuffer;
  218. ansiPortName.Length =
  219. (USHORT)irpSp->Parameters.FileSystemControl.InputBufferLength;
  220. status = RtlAnsiStringToUnicodeString(
  221. &portName,
  222. &ansiPortName,
  223. TRUE
  224. );
  225. if ( NT_SUCCESS(status) ) {
  226. status = SrvXsConnect( &portName );
  227. RtlFreeUnicodeString( &portName );
  228. }
  229. break;
  230. }
  231. case FSCTL_SRV_XACTSRV_DISCONNECT:
  232. {
  233. //
  234. // This is now obsolete
  235. //
  236. status = STATUS_SUCCESS;
  237. break;
  238. }
  239. case FSCTL_SRV_START_SMBTRACE:
  240. {
  241. KdPrint(( "SrvFspConfigurationThread: START_SMBTRACE FSCTL "
  242. "received.\n" ));
  243. //
  244. // Initialize the SmbTrace related events.
  245. //
  246. status = SmbTraceInitialize( SMBTRACE_SERVER );
  247. if ( NT_SUCCESS(status) ) {
  248. //
  249. // Create shared memory, create events, start SmbTrace thread,
  250. // and indicate that this is the server.
  251. //
  252. status = SmbTraceStart(
  253. irpSp->Parameters.FileSystemControl.InputBufferLength,
  254. irpSp->Parameters.FileSystemControl.OutputBufferLength,
  255. irp->AssociatedIrp.SystemBuffer,
  256. irpSp->FileObject,
  257. SMBTRACE_SERVER
  258. );
  259. if ( NT_SUCCESS(status) ) {
  260. //
  261. // Record the length of the return information, which is
  262. // simply the length of the output buffer, validated by
  263. // SmbTraceStart.
  264. //
  265. irp->IoStatus.Information =
  266. irpSp->Parameters.FileSystemControl.OutputBufferLength;
  267. }
  268. }
  269. break;
  270. }
  271. case FSCTL_SRV_SEND_DATAGRAM:
  272. {
  273. ANSI_STRING domain;
  274. ULONG buffer1Length;
  275. PVOID buffer2;
  276. PSERVER_REQUEST_PACKET srp;
  277. buffer1Length = ALIGN_UP(
  278. irpSp->Parameters.FileSystemControl.InputBufferLength,
  279. PVOID );
  280. buffer2 = (PCHAR)irp->AssociatedIrp.SystemBuffer + buffer1Length;
  281. srp = irp->AssociatedIrp.SystemBuffer;
  282. //
  283. // Send the second-class mailslot in Buffer2 to the domain
  284. // specified in srp->Name1 on transport specified by srp->Name2.
  285. //
  286. domain = *((PANSI_STRING) &srp->Name1);
  287. status = SrvSendDatagram(
  288. &domain,
  289. ( srp->Name2.Length != 0 ? &srp->Name2 : NULL ),
  290. buffer2,
  291. irpSp->Parameters.FileSystemControl.OutputBufferLength
  292. );
  293. ExFreePool( irp->AssociatedIrp.SystemBuffer );
  294. DEBUG irp->AssociatedIrp.SystemBuffer = NULL;
  295. break;
  296. }
  297. case FSCTL_SRV_NET_FILE_CLOSE:
  298. case FSCTL_SRV_NET_SERVER_XPORT_ADD:
  299. case FSCTL_SRV_NET_SERVER_XPORT_DEL:
  300. case FSCTL_SRV_NET_SESSION_DEL:
  301. case FSCTL_SRV_NET_SHARE_ADD:
  302. case FSCTL_SRV_NET_SHARE_DEL:
  303. {
  304. PSERVER_REQUEST_PACKET srp;
  305. PVOID buffer2;
  306. ULONG buffer1Length;
  307. ULONG buffer2Length;
  308. //
  309. // These APIs are handled in the server FSP because they
  310. // open or close FSP handles.
  311. //
  312. ACQUIRE_LOCK_SHARED( &SrvConfigurationLock );
  313. if( SrvFspTransitioning == TRUE && SrvFspActive == TRUE ) {
  314. //
  315. // The server is coming down. Do not allow these
  316. // irps to continue.
  317. //
  318. RELEASE_LOCK( &SrvConfigurationLock );
  319. status = STATUS_SERVER_NOT_STARTED;
  320. break;
  321. }
  322. RELEASE_LOCK( &SrvConfigurationLock );
  323. //
  324. // Get the server request packet and secondary input buffer
  325. // pointers.
  326. //
  327. buffer1Length = ALIGN_UP(
  328. irpSp->Parameters.FileSystemControl.InputBufferLength,
  329. PVOID );
  330. buffer2Length =
  331. irpSp->Parameters.FileSystemControl.OutputBufferLength;
  332. srp = irp->AssociatedIrp.SystemBuffer;
  333. buffer2 = (PCHAR)srp + buffer1Length;
  334. //
  335. // Dispatch the API request to the appripriate API processing
  336. // routine.
  337. //
  338. status = SrvApiDispatchTable[ SRV_API_INDEX(code) ](
  339. srp,
  340. buffer2,
  341. buffer2Length
  342. );
  343. break;
  344. }
  345. default:
  346. IF_DEBUG(ERRORS) {
  347. KdPrint((
  348. "SrvFspConfigurationThread: Invalid control code %lx\n",
  349. irpSp->Parameters.FileSystemControl.FsControlCode ));
  350. }
  351. status = STATUS_INVALID_PARAMETER;
  352. }
  353. } except(EXCEPTION_EXECUTE_HANDLER) {
  354. status = GetExceptionCode();
  355. }
  356. }
  357. //
  358. // Make sure we're still at PASSIVE_LEVEL
  359. //
  360. if( KeGetCurrentIrql() > PASSIVE_LEVEL )
  361. {
  362. goto bad_irql_failure;
  363. }
  364. //
  365. // Complete the IO request.
  366. //
  367. irp->IoStatus.Status = status;
  368. IoCompleteRequest( irp, 2 );
  369. //
  370. // Make sure we're still at PASSIVE_LEVEL
  371. //
  372. if( KeGetCurrentIrql() > PASSIVE_LEVEL )
  373. {
  374. goto bad_irql_failure;
  375. }
  376. ASSERT( (LONG)SrvConfigurationIrpsInProgress >= 0 );
  377. // Make sure we don't continue if there are no IRP's left
  378. if( InterlockedDecrement( (PLONG)&SrvConfigurationIrpsInProgress ) == 0 )
  379. {
  380. break;
  381. }
  382. }
  383. IoFreeWorkItem( pWorkItem );
  384. return;
  385. bad_irql_failure:
  386. DbgPrint( "ERROR: SrvConfigurationThread returning at >PASSIVE level\n" );
  387. DbgBreakPoint();
  388. IoFreeWorkItem( pWorkItem );
  389. return;
  390. } // SrvConfigurationThread
  391. PIRP
  392. DequeueConfigurationIrp (
  393. VOID
  394. )
  395. /*++
  396. Routine Description:
  397. This routine retrieves an IRP from the configuration work queue.
  398. Arguments:
  399. None.
  400. Return Value:
  401. PIRP - Pointer to configuration IRP, or NULL.
  402. --*/
  403. {
  404. PLIST_ENTRY listEntry;
  405. PIRP irp;
  406. PAGED_CODE( );
  407. //
  408. // Take an IRP off the configuration queue.
  409. //
  410. ACQUIRE_LOCK( &SrvConfigurationLock );
  411. listEntry = RemoveHeadList( &SrvConfigurationWorkQueue );
  412. if ( listEntry == &SrvConfigurationWorkQueue ) {
  413. //
  414. // The queue is empty.
  415. //
  416. irp = NULL;
  417. } else {
  418. irp = CONTAINING_RECORD( listEntry, IRP, Tail.Overlay.ListEntry );
  419. }
  420. RELEASE_LOCK( &SrvConfigurationLock );
  421. return irp;
  422. } // DequeueConfigurationIrp
  423. STATIC
  424. NTSTATUS
  425. InitializeServer (
  426. VOID
  427. )
  428. /*++
  429. Routine Description:
  430. This routine initializes the server.
  431. Arguments:
  432. None.
  433. Return Value:
  434. None.
  435. --*/
  436. {
  437. NTSTATUS status;
  438. CLONG i;
  439. PWORK_CONTEXT workContext;
  440. OBJECT_ATTRIBUTES objectAttributes;
  441. IO_STATUS_BLOCK ioStatusBlock;
  442. OBJECT_HANDLE_INFORMATION handleInformation;
  443. PSID AdminSid;
  444. PSID AnonymousSid;
  445. PACL Acl;
  446. ULONG length;
  447. SID_IDENTIFIER_AUTHORITY BuiltinAuthority = SECURITY_NT_AUTHORITY;
  448. PWORK_QUEUE queue;
  449. HANDLE handle;
  450. UNICODE_STRING string;
  451. PAGED_CODE();
  452. //
  453. // If running as an Advanced Server, lock all pageable server code.
  454. //
  455. if ( SrvProductTypeServer ) {
  456. for ( i = 0; i < SRV_CODE_SECTION_MAX; i++ ) {
  457. SrvReferenceUnlockableCodeSection( i );
  458. }
  459. }
  460. //
  461. // Initialize the server start time
  462. //
  463. KeQuerySystemTime( &SrvStatistics.StatisticsStartTime );
  464. //
  465. // Get actual alert service name using the display name found in the
  466. // registry.
  467. //
  468. SrvGetAlertServiceName( );
  469. //
  470. // Get the Os versions strings.
  471. //
  472. SrvGetOsVersionString( );
  473. //
  474. // Get the list of null session pipes and shares
  475. //
  476. SrvGetRegTables( );
  477. #if SRVNTVERCHK
  478. SrvGetRegClientNumber();
  479. #endif
  480. #if MULTIPROCESSOR
  481. //
  482. // Allocate and init the nonblocking work queues, paying attention to cache lines
  483. //
  484. i = SrvNumberOfProcessors * sizeof( *SrvWorkQueues );
  485. i += CACHE_LINE_SIZE;
  486. SrvWorkQueuesBase = ALLOCATE_NONPAGED_POOL( i, BlockTypeWorkQueue );
  487. if( SrvWorkQueuesBase == NULL ) {
  488. return STATUS_INSUFF_SERVER_RESOURCES;
  489. }
  490. //
  491. // Round up the start of the work queue data structure to
  492. // the next cache line boundry
  493. //
  494. SrvWorkQueues = (PWORK_QUEUE)(((ULONG_PTR)SrvWorkQueuesBase + CACHE_LINE_SIZE-1) &
  495. ~(CACHE_LINE_SIZE-1));
  496. #endif
  497. eSrvWorkQueues = SrvWorkQueues + SrvNumberOfProcessors;
  498. RtlZeroMemory( SrvWorkQueues, (char *)eSrvWorkQueues - (char *)SrvWorkQueues );
  499. for( queue = SrvWorkQueues; queue < eSrvWorkQueues; queue++ ) {
  500. KeInitializeQueue( &queue->Queue, 1 );
  501. queue->WaitMode = SrvProductTypeServer ? KernelMode : UserMode;
  502. queue->MaxThreads = SrvMaxThreadsPerQueue;
  503. queue->MaximumWorkItems = SrvMaxReceiveWorkItemCount / SrvNumberOfProcessors;
  504. queue->MinFreeWorkItems = SrvMinReceiveQueueLength / SrvNumberOfProcessors;
  505. queue->MaxFreeRfcbs = SrvMaxFreeRfcbs;
  506. queue->MaxFreeMfcbs = SrvMaxFreeMfcbs;
  507. ExInitializeSListHead(&queue->InitialWorkItemList);
  508. ExInitializeSListHead(&queue->NormalWorkItemList);
  509. ExInitializeSListHead(&queue->RawModeWorkItemList);
  510. ExInitializeSListHead(&queue->RfcbFreeList);
  511. ExInitializeSListHead(&queue->MfcbFreeList);
  512. queue->PagedPoolLookAsideList.MaxSize = SrvMaxPagedPoolChunkSize;
  513. queue->NonPagedPoolLookAsideList.MaxSize = SrvMaxNonPagedPoolChunkSize;
  514. queue->CreateMoreWorkItems.CurrentWorkQueue = queue;
  515. queue->CreateMoreWorkItems.BlockHeader.ReferenceCount = 1;
  516. queue->IdleTimeOut.QuadPart = SrvIdleThreadTimeOut;
  517. INITIALIZE_SPIN_LOCK( &queue->SpinLock );
  518. SET_SERVER_TIME( queue );
  519. #if MULTIPROCESSOR
  520. StartQueueDepthComputations( queue );
  521. #endif
  522. }
  523. RtlZeroMemory( &SrvDoSWorkItem, sizeof(SPECIAL_WORK_ITEM) );
  524. SrvDoSWorkItem.BlockHeader.ReferenceCount = 1;
  525. SrvDoSWorkItemTearDown = SRV_DOS_TEARDOWN_MIN;
  526. KeInitializeSpinLock( &SrvDosSpinLock );
  527. //
  528. // Init the Blocking work queue
  529. //
  530. RtlZeroMemory( &SrvBlockingWorkQueue, sizeof( SrvBlockingWorkQueue ) );
  531. KeInitializeQueue( &SrvBlockingWorkQueue.Queue, 0 );
  532. SrvBlockingWorkQueue.WaitMode =
  533. SrvProductTypeServer ? KernelMode : UserMode;
  534. SrvBlockingWorkQueue.MaxThreads = SrvMaxThreadsPerQueue;
  535. SrvBlockingWorkQueue.IdleTimeOut.QuadPart = SrvIdleThreadTimeOut;
  536. //
  537. // If we are a multiprocessor server system, increase the number of blocking worker threads.
  538. // Since most file opens end up being handled by the blocking queue, this can significantly
  539. // improve performance for open-intensive workloads.
  540. //
  541. if( SrvProductTypeServer == TRUE && SrvNumberOfProcessors > 1 ) {
  542. SrvBlockingWorkQueue.MaxThreads *= 2;
  543. }
  544. SET_SERVER_TIME( &SrvBlockingWorkQueue );
  545. //
  546. // Build the receive work item list.
  547. //
  548. status = SrvAllocateInitialWorkItems( );
  549. if ( !NT_SUCCESS(status) ) {
  550. return status;
  551. }
  552. //
  553. // Build the raw mode work item list, and spread it around
  554. // the processors
  555. //
  556. queue = SrvWorkQueues;
  557. for ( i = 0; i < SrvInitialRawModeWorkItemCount; i++ ) {
  558. SrvAllocateRawModeWorkItem( &workContext, queue );
  559. if ( workContext == NULL ) {
  560. return STATUS_INSUFFICIENT_RESOURCES;
  561. }
  562. GET_SERVER_TIME( queue, &workContext->Timestamp );
  563. SrvRequeueRawModeWorkItem( workContext );
  564. if( ++queue == eSrvWorkQueues )
  565. queue = SrvWorkQueues;
  566. }
  567. //
  568. // Create worker threads.
  569. //
  570. status = SrvCreateWorkerThreads( );
  571. if ( !NT_SUCCESS(status) ) {
  572. return status;
  573. }
  574. //
  575. // Initialize the scavenger.
  576. //
  577. status = SrvInitializeScavenger( );
  578. if ( !NT_SUCCESS(status) ) {
  579. return status;
  580. }
  581. //
  582. // Initialize the global ordered lists.
  583. //
  584. // *** WARNING: Be careful when changing the locks associated with
  585. // these ordered lists. Certain places in the code depend on
  586. // the level of the lock associated with a list. Examples
  587. // include (but are NOT limited to) SrvSmbSessionSetupAndX,
  588. // SrvSmbTreeConnect, SrvSmbTreeConnectAndX, and CompleteOpen.
  589. //
  590. SrvInitializeOrderedList(
  591. &SrvEndpointList,
  592. FIELD_OFFSET( ENDPOINT, GlobalEndpointListEntry ),
  593. SrvCheckAndReferenceEndpoint,
  594. SrvDereferenceEndpoint,
  595. &SrvEndpointLock
  596. );
  597. SrvInitializeOrderedList(
  598. &SrvRfcbList,
  599. FIELD_OFFSET( RFCB, GlobalRfcbListEntry ),
  600. SrvCheckAndReferenceRfcb,
  601. SrvDereferenceRfcb,
  602. &SrvOrderedListLock
  603. );
  604. SrvInitializeOrderedList(
  605. &SrvSessionList,
  606. FIELD_OFFSET( SESSION, GlobalSessionListEntry ),
  607. SrvCheckAndReferenceSession,
  608. SrvDereferenceSession,
  609. &SrvOrderedListLock
  610. );
  611. SrvInitializeOrderedList(
  612. &SrvTreeConnectList,
  613. FIELD_OFFSET( TREE_CONNECT, GlobalTreeConnectListEntry ),
  614. SrvCheckAndReferenceTreeConnect,
  615. SrvDereferenceTreeConnect,
  616. &SrvShareLock
  617. );
  618. //
  619. // Open handle to NPFS. Do not return an error if we fail so that
  620. // the server can still run without NPFS in the system.
  621. //
  622. SrvInitializeObjectAttributes_U(
  623. &objectAttributes,
  624. &SrvNamedPipeRootDirectory,
  625. 0,
  626. NULL,
  627. NULL
  628. );
  629. status = IoCreateFile(
  630. &SrvNamedPipeHandle,
  631. GENERIC_READ | GENERIC_WRITE,
  632. &objectAttributes,
  633. &ioStatusBlock,
  634. NULL,
  635. FILE_ATTRIBUTE_NORMAL,
  636. FILE_SHARE_READ | FILE_SHARE_WRITE,
  637. FILE_OPEN,
  638. 0, // Create Options
  639. NULL, // EA Buffer
  640. 0, // EA Length
  641. CreateFileTypeNone, // File type
  642. NULL, // ExtraCreateParameters
  643. IO_FORCE_ACCESS_CHECK // Options
  644. );
  645. if (!NT_SUCCESS(status)) {
  646. INTERNAL_ERROR (
  647. ERROR_LEVEL_EXPECTED,
  648. "InitializeServer: Failed to open NPFS, err=%X\n",
  649. status,
  650. NULL
  651. );
  652. SrvLogServiceFailure( SRV_SVC_IO_CREATE_FILE_NPFS, status );
  653. SrvNamedPipeHandle = NULL;
  654. return status;
  655. } else {
  656. //
  657. // Get a pointer to the NPFS device object
  658. //
  659. status = SrvVerifyDeviceStackSize(
  660. SrvNamedPipeHandle,
  661. TRUE,
  662. &SrvNamedPipeFileObject,
  663. &SrvNamedPipeDeviceObject,
  664. &handleInformation
  665. );
  666. if ( !NT_SUCCESS( status )) {
  667. INTERNAL_ERROR(
  668. ERROR_LEVEL_EXPECTED,
  669. "InitializeServer: Verify Device Stack Size failed: %X\n",
  670. status,
  671. NULL
  672. );
  673. SrvNtClose( SrvNamedPipeHandle, FALSE );
  674. SrvNamedPipeHandle = NULL;
  675. return status;
  676. }
  677. }
  678. //
  679. // Initialize Dfs operations
  680. //
  681. SrvInitializeDfs();
  682. //
  683. // Intialize SrvAdminSecurityDescriptor, which allows Administrators READ access.
  684. // This descriptor is used by the server to check if a user is an administrator
  685. // in SrvIsAdmin().
  686. status = RtlCreateSecurityDescriptor( &SrvAdminSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION );
  687. if( !NT_SUCCESS( status ) ) {
  688. return status;
  689. }
  690. //
  691. // Create an admin SID
  692. //
  693. AdminSid = ALLOCATE_HEAP_COLD( RtlLengthRequiredSid( 2 ), BlockTypeAdminCheck );
  694. if( AdminSid == NULL ) {
  695. return STATUS_INSUFFICIENT_RESOURCES;
  696. }
  697. RtlInitializeSid( AdminSid, &BuiltinAuthority, (UCHAR)2 );
  698. *(RtlSubAuthoritySid( AdminSid, 0 )) = SECURITY_BUILTIN_DOMAIN_RID;
  699. *(RtlSubAuthoritySid( AdminSid, 1 )) = DOMAIN_ALIAS_RID_ADMINS;
  700. length = sizeof(ACL) + sizeof( ACCESS_ALLOWED_ACE ) + RtlLengthSid( AdminSid );
  701. Acl = ALLOCATE_HEAP_COLD( length, BlockTypeAdminCheck );
  702. if( Acl == NULL ) {
  703. FREE_HEAP( AdminSid );
  704. return STATUS_INSUFFICIENT_RESOURCES;
  705. }
  706. status = RtlCreateAcl( Acl, length, ACL_REVISION2 );
  707. if( NT_SUCCESS( status ) ) {
  708. status = RtlAddAccessAllowedAce( Acl, ACL_REVISION2, FILE_GENERIC_READ, AdminSid );
  709. }
  710. if( NT_SUCCESS( status ) ) {
  711. status = RtlSetDaclSecurityDescriptor( &SrvAdminSecurityDescriptor, TRUE, Acl, FALSE );
  712. }
  713. if( NT_SUCCESS( status ) ) {
  714. status = RtlSetOwnerSecurityDescriptor( &SrvAdminSecurityDescriptor, AdminSid, FALSE );
  715. }
  716. if( !NT_SUCCESS( status ) ) {
  717. return status;
  718. }
  719. //
  720. // Intialize SrvNullSessionSecurityDescriptor, which allows anonymous
  721. // logons READ access. This descriptor is used by the server to check
  722. // if a user is an null session in SrvIsNullSession().
  723. //
  724. status = RtlCreateSecurityDescriptor( &SrvNullSessionSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION );
  725. if( !NT_SUCCESS( status ) ) {
  726. return status;
  727. }
  728. //
  729. // Create an anonymous SID
  730. //
  731. AnonymousSid = ALLOCATE_HEAP_COLD( RtlLengthRequiredSid( 1 ), BlockTypeAdminCheck );
  732. if( AnonymousSid == NULL ) {
  733. return STATUS_INSUFFICIENT_RESOURCES;
  734. }
  735. RtlInitializeSid( AnonymousSid, &BuiltinAuthority, (UCHAR)1 );
  736. *(RtlSubAuthoritySid( AnonymousSid, 0 )) = SECURITY_ANONYMOUS_LOGON_RID;
  737. length = sizeof(ACL) + sizeof( ACCESS_ALLOWED_ACE ) + RtlLengthSid( AnonymousSid );
  738. Acl = ALLOCATE_HEAP_COLD( length, BlockTypeAdminCheck );
  739. if( Acl == NULL ) {
  740. FREE_HEAP( AnonymousSid );
  741. return STATUS_INSUFFICIENT_RESOURCES;
  742. }
  743. status = RtlCreateAcl( Acl, length, ACL_REVISION2 );
  744. if( NT_SUCCESS( status ) ) {
  745. status = RtlAddAccessAllowedAce( Acl, ACL_REVISION2, FILE_GENERIC_READ, AnonymousSid );
  746. }
  747. if( NT_SUCCESS( status ) ) {
  748. status = RtlSetDaclSecurityDescriptor( &SrvNullSessionSecurityDescriptor, TRUE, Acl, FALSE );
  749. }
  750. if( NT_SUCCESS( status ) ) {
  751. status = RtlSetOwnerSecurityDescriptor( &SrvNullSessionSecurityDescriptor, AnonymousSid, FALSE );
  752. }
  753. if( !NT_SUCCESS( status ) ) {
  754. return status;
  755. }
  756. (VOID) InitSecurityInterface();
  757. status = SrvValidateUser(
  758. &SrvNullSessionToken,
  759. NULL,
  760. NULL,
  761. NULL,
  762. StrNullAnsi,
  763. 1,
  764. NULL,
  765. 0,
  766. FALSE,
  767. NULL
  768. );
  769. if ( !NT_SUCCESS(status) ) {
  770. //
  771. // LSA doesn't want to let the null session in. He's the boss!
  772. //
  773. INVALIDATE_SECURITY_HANDLE( SrvNullSessionToken );
  774. }
  775. //
  776. // See if the filesystems are allowing extended characters in 8.3 names. If
  777. // so, we need to filter them out ourself.
  778. //
  779. RtlInitUnicodeString( &string, StrRegExtendedCharsInPath );
  780. InitializeObjectAttributes( &objectAttributes,
  781. &string,
  782. OBJ_CASE_INSENSITIVE,
  783. NULL,
  784. NULL
  785. );
  786. status = ZwOpenKey( &handle, KEY_READ, &objectAttributes );
  787. if( NT_SUCCESS( status ) ) {
  788. ULONG resultLength;
  789. union {
  790. KEY_VALUE_FULL_INFORMATION;
  791. UCHAR buffer[ sizeof( KEY_VALUE_FULL_INFORMATION ) + 100 ];
  792. } keyValueInformation;
  793. RtlInitUnicodeString( &string, StrRegExtendedCharsInPathValue );
  794. status = ZwQueryValueKey( handle,
  795. &string,
  796. KeyValueFullInformation,
  797. &keyValueInformation,
  798. sizeof( keyValueInformation ),
  799. &resultLength
  800. );
  801. if( NT_SUCCESS( status ) &&
  802. keyValueInformation.Type == REG_DWORD &&
  803. keyValueInformation.DataLength != 0 ) {
  804. SrvFilterExtendedCharsInPath =
  805. *(PULONG)(((PUCHAR)(&keyValueInformation)) + keyValueInformation.DataOffset) ?
  806. TRUE : FALSE;
  807. }
  808. ZwClose( handle );
  809. }
  810. //
  811. // Get a handle to use in PoRegisterSystemState() calls
  812. //
  813. SrvPoRegistrationState = PoRegisterSystemState( NULL, 0 );
  814. //
  815. // Indicate that the server is active.
  816. //
  817. ACQUIRE_LOCK( &SrvConfigurationLock );
  818. SrvFspTransitioning = FALSE;
  819. SrvFspActive = TRUE;
  820. RELEASE_LOCK( &SrvConfigurationLock );
  821. return STATUS_SUCCESS;
  822. } // InitializeServer
  823. STATIC
  824. NTSTATUS
  825. TerminateServer ( VOID )
  826. /*++
  827. Routine Description:
  828. This routine terminates the server. The following steps are performed:
  829. - Walk through SrvEndpointList and close all open endpoints.
  830. - Walk through the work context blocks in the work queues
  831. getting rid of them as appropiate
  832. - Close all shares open in the server
  833. - Deallocate the search table
  834. Arguments:
  835. Return Value:
  836. None.
  837. --*/
  838. {
  839. PLIST_ENTRY listEntry;
  840. PSINGLE_LIST_ENTRY singleListEntry;
  841. PENDPOINT endpoint;
  842. ULONG numberOfThreads;
  843. PWORK_CONTEXT workContext;
  844. PSHARE share;
  845. ULONG i;
  846. SPECIAL_WORK_ITEM WorkItem;
  847. PSRV_TIMER timer;
  848. PSID adminsid;
  849. PSID anonymoussid;
  850. PACL acl;
  851. BOOLEAN defaulted;
  852. BOOLEAN daclpresent;
  853. NTSTATUS status;
  854. PWORK_QUEUE queue;
  855. PIRP irp;
  856. PLIST_ENTRY listEntryRoot;
  857. PAGED_CODE( );
  858. IF_DEBUG(FSP1) KdPrint(( "LAN Manager server FSP terminating.\n" ));
  859. //
  860. // Do not receive PNP notifications anymore
  861. //
  862. if( SrvTdiNotificationHandle != NULL ) {
  863. status = TdiDeregisterPnPHandlers( SrvTdiNotificationHandle );
  864. if( !NT_SUCCESS( status ) ) {
  865. KdPrint(( "TdiDeregisterPnPHandlers status %X\n", status ));
  866. SrvLogServiceFailure( SRV_SVC_PNP_TDI_NOTIFICATION, status );
  867. return status;
  868. }
  869. SrvTdiNotificationHandle = NULL;
  870. }
  871. //
  872. // Make sure we are not processing any other configuration IRPs. We know
  873. // that no new configuration IRPs can enter the queue because SrvFspTransitioning
  874. // has been set.
  875. //
  876. // First drain the configuration queue
  877. //
  878. while( 1 ) {
  879. ACQUIRE_LOCK( &SrvConfigurationLock );
  880. irp = DequeueConfigurationIrp( );
  881. RELEASE_LOCK( &SrvConfigurationLock );
  882. if( irp == NULL ) {
  883. break;
  884. }
  885. irp->IoStatus.Status = STATUS_SERVER_NOT_STARTED;
  886. IoCompleteRequest( irp, 2 );
  887. InterlockedDecrement( (PLONG)&SrvConfigurationIrpsInProgress );
  888. }
  889. //
  890. // Now wait until any already dequeued configuration IRPs have been completed. We
  891. // check for >1 because we need to account for our own IRP
  892. //
  893. while( SrvConfigurationIrpsInProgress > 1 ) {
  894. LARGE_INTEGER interval;
  895. interval.QuadPart = -1*10*1000*10; // .01 second
  896. ASSERT( (LONG)SrvConfigurationIrpsInProgress > 0 );
  897. KeDelayExecutionThread( KernelMode, FALSE, &interval );
  898. }
  899. //
  900. // If there are outstanding API requests in the server FSD,
  901. // wait for them to complete. The last one to complete will
  902. // set SrvApiCompletionEvent.
  903. //
  904. ACQUIRE_LOCK( &SrvConfigurationLock );
  905. if ( SrvApiRequestCount != 0 ) {
  906. //
  907. // We must release the lock before waiting so that the FSD
  908. // threads can get it to decrement SrvApiRequestCount.
  909. //
  910. RELEASE_LOCK( &SrvConfigurationLock );
  911. for (;;) {
  912. NTSTATUS WaitStatus;
  913. //
  914. // Wait until the last API has completed. Since
  915. // SrvFspTransitioning was set to TRUE earlier, we know that the
  916. // API that makes SrvApiRequestCount go to zero will set the
  917. // event.
  918. //
  919. // This wait allows us to make the assumption later on that no
  920. // other thread is operating on server data structures.
  921. //
  922. WaitStatus = KeWaitForSingleObject(
  923. &SrvApiCompletionEvent,
  924. UserRequest,
  925. UserMode, // let kernel stack be paged
  926. FALSE,
  927. NULL
  928. );
  929. if (WaitStatus != STATUS_USER_APC) {
  930. break;
  931. }
  932. }
  933. } else {
  934. RELEASE_LOCK( &SrvConfigurationLock );
  935. }
  936. //
  937. // Close all the endpoints opened by the server. This also results
  938. // in the connections, sessions, tree connects, and files opened
  939. // by the server being closed.
  940. //
  941. ACQUIRE_LOCK( &SrvEndpointLock );
  942. if ( SrvEndpointCount != 0 ) {
  943. listEntry = SrvEndpointList.ListHead.Flink;
  944. while ( listEntry != &SrvEndpointList.ListHead ) {
  945. endpoint = CONTAINING_RECORD(
  946. listEntry,
  947. ENDPOINT,
  948. GlobalEndpointListEntry
  949. );
  950. if ( GET_BLOCK_STATE(endpoint) != BlockStateActive ) {
  951. listEntry = listEntry->Flink;
  952. continue;
  953. }
  954. //
  955. // We don't want to hold the endpoint lock while we close
  956. // the endpoint (this causes lock level problems), so we have
  957. // to play some games.
  958. //
  959. // Reference the endpoint to ensure that it doesn't go away.
  960. // (We'll need its Flink later.) Close the endpoint. This
  961. // releases the endpoint lock. Reacquire the endpoint lock.
  962. // Capture the address of the next endpoint. Dereference the
  963. // current endpoint.
  964. //
  965. SrvReferenceEndpoint( endpoint );
  966. SrvCloseEndpoint( endpoint );
  967. ACQUIRE_LOCK( &SrvEndpointLock );
  968. listEntry = listEntry->Flink;
  969. SrvDereferenceEndpoint( endpoint );
  970. }
  971. RELEASE_LOCK( &SrvEndpointLock );
  972. for (;;) {
  973. NTSTATUS WaitStatus;
  974. //
  975. // Wait until all the endpoints have actually closed.
  976. //
  977. WaitStatus = KeWaitForSingleObject(
  978. &SrvEndpointEvent,
  979. UserRequest,
  980. UserMode, // let kernel stack be paged
  981. FALSE,
  982. NULL
  983. );
  984. if (WaitStatus != STATUS_USER_APC) {
  985. break;
  986. }
  987. }
  988. } else {
  989. RELEASE_LOCK( &SrvEndpointLock );
  990. }
  991. KeClearEvent( &SrvEndpointEvent );
  992. //
  993. // All the endpoints are closed, so it's impossible for there to
  994. // be any outstanding requests to xactsrv. So shut it down.
  995. //
  996. SrvXsDisconnect();
  997. //
  998. // Queue a special work item to each of the work queues. This
  999. // work item, when received by a worker thread. causes the thread
  1000. // to requeue the work item and terminate itself. In this way,
  1001. // each of the worker threads receives the work item and kills
  1002. // itself.
  1003. //
  1004. WorkItem.FspRestartRoutine = SrvTerminateWorkerThread;
  1005. SET_BLOCK_TYPE( &WorkItem, BlockTypeWorkContextSpecial );
  1006. //
  1007. // Kill the threads on the nonblocking work queues
  1008. //
  1009. if ( SrvWorkQueues != NULL ) {
  1010. for( queue=SrvWorkQueues; queue && queue < eSrvWorkQueues; queue++ ) {
  1011. WorkItem.CurrentWorkQueue = queue;
  1012. SrvInsertWorkQueueTail(
  1013. queue,
  1014. (PQUEUEABLE_BLOCK_HEADER)&WorkItem
  1015. );
  1016. //
  1017. // Wait for the threads to all die
  1018. //
  1019. while( queue->Threads != 0 ) {
  1020. LARGE_INTEGER interval;
  1021. interval.QuadPart = -1*10*1000*10; // .01 second
  1022. KeDelayExecutionThread( KernelMode, FALSE, &interval );
  1023. }
  1024. KeRundownQueue( &queue->Queue );
  1025. }
  1026. //
  1027. // Kill the threads on the blocking work queues
  1028. //
  1029. WorkItem.CurrentWorkQueue = &SrvBlockingWorkQueue;
  1030. SrvInsertWorkQueueTail(
  1031. &SrvBlockingWorkQueue,
  1032. (PQUEUEABLE_BLOCK_HEADER)&WorkItem
  1033. );
  1034. //
  1035. // Wait for the threads to all die
  1036. //
  1037. while( SrvBlockingWorkQueue.Threads != 0 ) {
  1038. LARGE_INTEGER interval;
  1039. interval.QuadPart = -1*10*1000*10; // .01 second
  1040. KeDelayExecutionThread( KernelMode, FALSE, &interval );
  1041. }
  1042. KeRundownQueue( &SrvBlockingWorkQueue.Queue );
  1043. }
  1044. //
  1045. // Free any space allocated for the Null Session pipe and share lists
  1046. //
  1047. SrvFreeRegTables();
  1048. //
  1049. // If we allocated memory for the os version strings, free it now.
  1050. //
  1051. if ( SrvNativeOS.Buffer != NULL &&
  1052. SrvNativeOS.Buffer != StrDefaultNativeOs ) {
  1053. FREE_HEAP( SrvNativeOS.Buffer );
  1054. SrvNativeOS.Buffer = NULL;
  1055. RtlFreeOemString( &SrvOemNativeOS );
  1056. SrvOemNativeOS.Buffer = NULL;
  1057. }
  1058. //
  1059. // If allocated memory for the display name, free it now.
  1060. //
  1061. if ( SrvAlertServiceName != NULL &&
  1062. SrvAlertServiceName != StrDefaultSrvDisplayName ) {
  1063. FREE_HEAP( SrvAlertServiceName );
  1064. SrvAlertServiceName = NULL;
  1065. }
  1066. //
  1067. // Make sure the scavenger is not running.
  1068. //
  1069. SrvTerminateScavenger( );
  1070. #if MULTIPROCESSOR
  1071. if( SrvWorkQueues ) {
  1072. for( queue = SrvWorkQueues; queue < eSrvWorkQueues; queue++ ) {
  1073. StopQueueDepthComputations( queue );
  1074. }
  1075. }
  1076. #endif
  1077. //
  1078. // Free the work items in the work queues and the receive work item
  1079. // list. This also deallocates the SMB buffers. Note that work
  1080. // items allocated dynamically may be deallocated singly, while work
  1081. // items allocated at server startup are part of one large block,
  1082. // and may not be deallocated singly.
  1083. //
  1084. // !!! Does this properly clean up buffers allocated during SMB
  1085. // processing? Probably not. Should probably allow the worker
  1086. // threads to run the work queue normally before they stop.
  1087. //
  1088. if( SrvWorkQueues ) {
  1089. for( queue = SrvWorkQueues; queue < eSrvWorkQueues; queue++ ) {
  1090. //
  1091. // Clean out the single FreeContext spot
  1092. //
  1093. workContext = NULL;
  1094. workContext = (PWORK_CONTEXT)InterlockedExchangePointer(
  1095. &queue->FreeContext, workContext );
  1096. if( workContext != NULL && workContext->PartOfInitialAllocation == FALSE ) {
  1097. SrvFreeNormalWorkItem( workContext );
  1098. }
  1099. //
  1100. // Clean out the normal work item list
  1101. //
  1102. while( 1 ) {
  1103. singleListEntry = ExInterlockedPopEntrySList(
  1104. &queue->NormalWorkItemList, &queue->SpinLock );
  1105. if( singleListEntry == NULL ) {
  1106. break;
  1107. }
  1108. workContext =
  1109. CONTAINING_RECORD( singleListEntry, WORK_CONTEXT, SingleListEntry );
  1110. SrvFreeNormalWorkItem( workContext );
  1111. queue->FreeWorkItems--;
  1112. }
  1113. //
  1114. // Clean out the raw mode work item list
  1115. //
  1116. while( 1 ) {
  1117. singleListEntry = ExInterlockedPopEntrySList(
  1118. &queue->RawModeWorkItemList, &queue->SpinLock );
  1119. if( singleListEntry == NULL ) {
  1120. break;
  1121. }
  1122. workContext =
  1123. CONTAINING_RECORD( singleListEntry, WORK_CONTEXT, SingleListEntry );
  1124. SrvFreeRawModeWorkItem( workContext );
  1125. }
  1126. //
  1127. // Free up any saved rfcbs
  1128. //
  1129. if( queue->CachedFreeRfcb != NULL ) {
  1130. FREE_HEAP( queue->CachedFreeRfcb->PagedRfcb );
  1131. DEALLOCATE_NONPAGED_POOL( queue->CachedFreeRfcb );
  1132. queue->CachedFreeRfcb = NULL;
  1133. }
  1134. while( 1 ) {
  1135. PRFCB Rfcb;
  1136. singleListEntry = ExInterlockedPopEntrySList( &queue->RfcbFreeList, &queue->SpinLock );
  1137. if( singleListEntry == NULL ) {
  1138. break;
  1139. }
  1140. Rfcb =
  1141. CONTAINING_RECORD( singleListEntry, RFCB, SingleListEntry );
  1142. FREE_HEAP( Rfcb->PagedRfcb );
  1143. DEALLOCATE_NONPAGED_POOL( Rfcb );
  1144. }
  1145. //
  1146. // Free up any saved mfcbs
  1147. //
  1148. if( queue->CachedFreeMfcb != NULL ) {
  1149. DEALLOCATE_NONPAGED_POOL( queue->CachedFreeMfcb );
  1150. queue->CachedFreeMfcb = NULL;
  1151. }
  1152. while( 1 ) {
  1153. PNONPAGED_MFCB nonpagedMfcb;
  1154. singleListEntry = ExInterlockedPopEntrySList( &queue->MfcbFreeList, &queue->SpinLock );
  1155. if( singleListEntry == NULL ) {
  1156. break;
  1157. }
  1158. nonpagedMfcb =
  1159. CONTAINING_RECORD( singleListEntry, NONPAGED_MFCB, SingleListEntry );
  1160. DEALLOCATE_NONPAGED_POOL( nonpagedMfcb );
  1161. }
  1162. }
  1163. } // SrvWorkQueues
  1164. //
  1165. // All dynamic work items have been freed, and the work item queues
  1166. // have been emptied. Release the initial work item allocation.
  1167. //
  1168. SrvFreeInitialWorkItems( );
  1169. //
  1170. // Walk through the global share list, closing them all.
  1171. //
  1172. for( listEntryRoot = SrvShareHashTable;
  1173. listEntryRoot < &SrvShareHashTable[ NSHARE_HASH_TABLE ];
  1174. listEntryRoot++ ) {
  1175. while( listEntryRoot->Flink != listEntryRoot ) {
  1176. share = CONTAINING_RECORD( listEntryRoot->Flink, SHARE, GlobalShareList );
  1177. SrvCloseShare( share );
  1178. }
  1179. }
  1180. //
  1181. // If we opened the NPFS during initialization, close the handle now
  1182. // and dereference the NPFS file object.
  1183. //
  1184. if ( SrvNamedPipeHandle != NULL) {
  1185. SrvNtClose( SrvNamedPipeHandle, FALSE );
  1186. ObDereferenceObject( SrvNamedPipeFileObject );
  1187. SrvNamedPipeHandle = NULL;
  1188. }
  1189. //
  1190. // Disconnect from the Dfs driver
  1191. //
  1192. SrvTerminateDfs();
  1193. //
  1194. // Clean up the Dns Domain Name if necessary
  1195. //
  1196. if( SrvDnsDomainName )
  1197. {
  1198. DEALLOCATE_NONPAGED_POOL( SrvDnsDomainName );
  1199. SrvDnsDomainName = NULL;
  1200. }
  1201. //
  1202. // Clean up the admin security descriptor
  1203. //
  1204. status = RtlGetDaclSecurityDescriptor( &SrvAdminSecurityDescriptor,
  1205. &daclpresent,
  1206. &acl,
  1207. &defaulted );
  1208. if( !NT_SUCCESS( status ) || !daclpresent ) {
  1209. acl = NULL;
  1210. }
  1211. status = RtlGetOwnerSecurityDescriptor( &SrvAdminSecurityDescriptor,
  1212. &adminsid,
  1213. &defaulted );
  1214. if( NT_SUCCESS( status ) && adminsid != NULL ) {
  1215. FREE_HEAP( adminsid );
  1216. }
  1217. if( acl != NULL ) {
  1218. FREE_HEAP( acl );
  1219. }
  1220. //
  1221. // Clean up the null session security descriptor
  1222. //
  1223. status = RtlGetDaclSecurityDescriptor( &SrvNullSessionSecurityDescriptor,
  1224. &daclpresent,
  1225. &acl,
  1226. &defaulted );
  1227. if( !NT_SUCCESS( status ) || !daclpresent ) {
  1228. acl = NULL;
  1229. }
  1230. status = RtlGetOwnerSecurityDescriptor( &SrvNullSessionSecurityDescriptor,
  1231. &anonymoussid,
  1232. &defaulted );
  1233. if( NT_SUCCESS( status ) && anonymoussid != NULL ) {
  1234. FREE_HEAP( anonymoussid );
  1235. }
  1236. if( acl != NULL ) {
  1237. FREE_HEAP( acl );
  1238. }
  1239. if (!CONTEXT_NULL(SrvNullSessionToken)) {
  1240. DeleteSecurityContext(&SrvNullSessionToken);
  1241. INVALIDATE_SECURITY_HANDLE( SrvNullSessionToken );
  1242. }
  1243. //
  1244. // Delete the global ordered lists.
  1245. //
  1246. SrvDeleteOrderedList( &SrvEndpointList );
  1247. SrvDeleteOrderedList( &SrvRfcbList );
  1248. SrvDeleteOrderedList( &SrvSessionList );
  1249. SrvDeleteOrderedList( &SrvTreeConnectList );
  1250. //
  1251. // Clear out the timer pool.
  1252. //
  1253. while ( (singleListEntry = ExInterlockedPopEntrySList(
  1254. &SrvTimerList,
  1255. &GLOBAL_SPIN_LOCK(Timer) )) != NULL ) {
  1256. timer = CONTAINING_RECORD( singleListEntry, SRV_TIMER, Next );
  1257. DEALLOCATE_NONPAGED_POOL( timer );
  1258. }
  1259. if( SrvWorkQueues ) {
  1260. //
  1261. // Clear out the saved pool chunks
  1262. //
  1263. for( queue = SrvWorkQueues; queue < eSrvWorkQueues; queue++ ) {
  1264. //
  1265. // Free up any paged pool that we've saved.
  1266. //
  1267. SrvClearLookAsideList( &queue->PagedPoolLookAsideList, SrvFreePagedPool );
  1268. //
  1269. // Free up any nonpaged pool that we've saved.
  1270. //
  1271. SrvClearLookAsideList( &queue->NonPagedPoolLookAsideList, SrvFreeNonPagedPool );
  1272. }
  1273. #if MULTIPROCESSOR
  1274. DEALLOCATE_NONPAGED_POOL( SrvWorkQueuesBase );
  1275. SrvWorkQueuesBase = NULL;
  1276. SrvWorkQueues = NULL;
  1277. #endif
  1278. }
  1279. //
  1280. // Unlock pageable sections.
  1281. //
  1282. for ( i = 0; i < SRV_CODE_SECTION_MAX; i++ ) {
  1283. if ( SrvSectionInfo[i].Handle != NULL ) {
  1284. ASSERT( SrvSectionInfo[i].ReferenceCount != 0 );
  1285. MmUnlockPagableImageSection( SrvSectionInfo[i].Handle );
  1286. SrvSectionInfo[i].Handle = 0;
  1287. SrvSectionInfo[i].ReferenceCount = 0;
  1288. }
  1289. }
  1290. //
  1291. // Zero out the statistics database.
  1292. //
  1293. RtlZeroMemory( &SrvStatistics, sizeof(SrvStatistics) );
  1294. #if SRVDBG_STATS || SRVDBG_STATS2
  1295. RtlZeroMemory( &SrvDbgStatistics, sizeof(SrvDbgStatistics) );
  1296. #endif
  1297. //
  1298. // Free the handle used in PoRegisterSystemState
  1299. //
  1300. if( SrvPoRegistrationState != NULL ) {
  1301. PoUnregisterSystemState( SrvPoRegistrationState );
  1302. SrvPoRegistrationState = NULL;
  1303. }
  1304. //
  1305. // Indicate that the server is no longer active.
  1306. //
  1307. ACQUIRE_LOCK( &SrvConfigurationLock );
  1308. SrvFspTransitioning = FALSE;
  1309. SrvFspActive = FALSE;
  1310. SrvSvcProcess = NULL;
  1311. RELEASE_LOCK( &SrvConfigurationLock );
  1312. IF_DEBUG(FSP1) KdPrint(( "LAN Manager server FSP termination complete.\n" ));
  1313. return STATUS_SUCCESS;
  1314. } // TerminateServer
  1315. VOID
  1316. SrvFreeRegTables (
  1317. VOID
  1318. )
  1319. /*++
  1320. Routine Description:
  1321. This routine frees space allocated for the list of legal Null session shares
  1322. and pipes. The SrvConfigurationLock must be held when this routine is called.
  1323. Arguments:
  1324. None.
  1325. Return Value:
  1326. None.
  1327. --*/
  1328. {
  1329. PAGED_CODE( );
  1330. //
  1331. // If we allocated a buffer for the list of null session pipes,
  1332. // free it now.
  1333. //
  1334. if ( SrvNullSessionPipes != NULL &&
  1335. SrvNullSessionPipes != StrDefaultNullSessionPipes ) {
  1336. FREE_HEAP( SrvNullSessionPipes );
  1337. }
  1338. SrvNullSessionPipes = NULL;
  1339. if( SrvNoRemapPipeNames != NULL &&
  1340. SrvNoRemapPipeNames != StrDefaultNoRemapPipeNames ) {
  1341. FREE_HEAP( SrvNoRemapPipeNames );
  1342. }
  1343. SrvNoRemapPipeNames = NULL;
  1344. if ( SrvPipesNeedLicense != NULL &&
  1345. SrvPipesNeedLicense != StrDefaultPipesNeedLicense ) {
  1346. FREE_HEAP( SrvPipesNeedLicense );
  1347. }
  1348. SrvPipesNeedLicense = NULL;
  1349. if ( SrvNullSessionShares != NULL &&
  1350. SrvNullSessionShares != StrDefaultNullSessionShares ) {
  1351. FREE_HEAP( SrvNullSessionShares );
  1352. }
  1353. SrvNullSessionShares = NULL;
  1354. #if SRVNTVERCHK
  1355. if( SrvInvalidDomainNames != NULL ) {
  1356. FREE_HEAP( SrvInvalidDomainNames );
  1357. }
  1358. SrvInvalidDomainNames = NULL;
  1359. #endif
  1360. #if SRVCATCH
  1361. if( SrvCatchBuf != NULL ) {
  1362. FREE_HEAP( SrvCatchBuf );
  1363. SrvCatchBuf = NULL;
  1364. }
  1365. if( SrvCatchExtBuf != NULL ) {
  1366. FREE_HEAP( SrvCatchExtBuf );
  1367. SrvCatchExtBuf = NULL;
  1368. }
  1369. if( SrvCatchShareNames != NULL ) {
  1370. FREE_HEAP( SrvCatchShareNames );
  1371. SrvCatchShareNames = NULL;
  1372. SrvCatchShares = 0;
  1373. CleanupCrcTable();
  1374. }
  1375. #endif
  1376. }
  1377. VOID
  1378. SrvGetRegTables (
  1379. VOID
  1380. )
  1381. /*++
  1382. Routine Description:
  1383. This routine loads the lists of valid shares and pipes for null sessions.
  1384. The SrvConfigurationLock must be held when this routine is called.
  1385. Arguments:
  1386. None.
  1387. Return Value:
  1388. None.
  1389. --*/
  1390. {
  1391. PWSTR *strErrorLogIgnore;
  1392. PAGED_CODE( );
  1393. //
  1394. // Get the list of null session pipes.
  1395. //
  1396. ASSERT( SrvNullSessionPipes == NULL );
  1397. SrvGetMultiSZList(
  1398. &SrvNullSessionPipes,
  1399. StrRegSrvParameterPath,
  1400. StrRegNullSessionPipes,
  1401. StrDefaultNullSessionPipes
  1402. );
  1403. //
  1404. // Get the list of non-remappable pipe names
  1405. //
  1406. ASSERT( SrvNoRemapPipeNames == NULL );
  1407. SrvGetMultiSZList(
  1408. &SrvNoRemapPipeNames,
  1409. StrRegSrvParameterPath,
  1410. StrRegNoRemapPipes,
  1411. StrDefaultNoRemapPipeNames
  1412. );
  1413. //
  1414. // Get the list of pipes requiring licenses
  1415. //
  1416. ASSERT( SrvPipesNeedLicense == NULL );
  1417. SrvGetMultiSZList(
  1418. &SrvPipesNeedLicense,
  1419. StrRegSrvParameterPath,
  1420. StrRegPipesNeedLicense,
  1421. StrDefaultPipesNeedLicense
  1422. );
  1423. //
  1424. // Get the list of null session pipes.
  1425. //
  1426. ASSERT( SrvNullSessionShares == NULL );
  1427. SrvGetMultiSZList(
  1428. &SrvNullSessionShares,
  1429. StrRegSrvParameterPath,
  1430. StrRegNullSessionShares,
  1431. StrDefaultNullSessionShares
  1432. );
  1433. #if SRVCATCH
  1434. {
  1435. USHORT i;
  1436. SrvCatch.Length = 0;
  1437. SrvCatch.Buffer = 0;
  1438. if( SrvCatchBuf != NULL ) {
  1439. FREE_HEAP( SrvCatchBuf );
  1440. SrvCatchBuf = NULL;
  1441. }
  1442. SrvGetMultiSZList(
  1443. &SrvCatchBuf,
  1444. StrRegSrvParameterPath,
  1445. L"CheckFile",
  1446. 0
  1447. );
  1448. if( SrvCatchBuf != NULL ) {
  1449. SrvCatch.Buffer = SrvCatchBuf[0];
  1450. for( i = 0; SrvCatch.Buffer[i]; i++ )
  1451. ;
  1452. SrvCatch.Length = i * sizeof( SrvCatch.Buffer[0] );
  1453. }
  1454. SrvCatchExt.Length = 0;
  1455. SrvCatchExt.Buffer = 0;
  1456. if( SrvCatchExtBuf != NULL )
  1457. {
  1458. FREE_HEAP( SrvCatchExtBuf );
  1459. SrvCatchExtBuf = NULL;
  1460. }
  1461. SrvGetMultiSZList(
  1462. &SrvCatchExtBuf,
  1463. StrRegSrvParameterPath,
  1464. L"CheckExtension",
  1465. 0
  1466. );
  1467. if( SrvCatchExtBuf != NULL ) {
  1468. SrvCatchExt.Buffer = SrvCatchExtBuf[0];
  1469. for( i = 0; SrvCatchExt.Buffer[i]; i++ )
  1470. ;
  1471. SrvCatchExt.Length = i * sizeof( SrvCatchExt.Buffer[0] );
  1472. }
  1473. if( SrvCatchShareNames != NULL )
  1474. {
  1475. FREE_HEAP( SrvCatchShareNames );
  1476. SrvCatchShareNames = NULL;
  1477. }
  1478. SrvGetMultiSZList(
  1479. &SrvCatchShareNames,
  1480. StrRegSrvParameterPath,
  1481. L"CheckShares",
  1482. 0
  1483. );
  1484. if( SrvCatchShareNames != NULL )
  1485. {
  1486. for( i=0; SrvCatchShareNames[i]; i++ ) ;
  1487. SrvCatchShares = i;
  1488. }
  1489. if( SrvCatchShares > 0 )
  1490. {
  1491. if( !GenerateCrcTable() )
  1492. {
  1493. FREE_HEAP( SrvCatchShareNames );
  1494. SrvCatchShareNames = NULL;
  1495. SrvCatchShares = 0;
  1496. }
  1497. }
  1498. }
  1499. #endif
  1500. //
  1501. // Get the list of error codes that we don't log
  1502. //
  1503. SrvGetMultiSZList(
  1504. &strErrorLogIgnore,
  1505. StrRegSrvParameterPath,
  1506. StrRegErrorLogIgnore,
  1507. StrDefaultErrorLogIgnore
  1508. );
  1509. if( strErrorLogIgnore != NULL ) {
  1510. DWORD i;
  1511. //
  1512. // They came in as strings, convert to NTSTATUS codes
  1513. //
  1514. for( i=0; i < SRVMAXERRLOGIGNORE; i++ ) {
  1515. NTSTATUS Status;
  1516. PWSTR p;
  1517. if( (p = strErrorLogIgnore[i]) == NULL )
  1518. break;
  1519. for( Status = 0; *p; p++ ) {
  1520. if( *p >= L'A' && *p <= L'F' ) {
  1521. Status <<= 4;
  1522. Status += 10 + (*p - L'A');
  1523. } else if( *p >= '0' && *p <= '9' ) {
  1524. Status <<= 4;
  1525. Status += *p - L'0';
  1526. }
  1527. }
  1528. SrvErrorLogIgnore[i] = Status;
  1529. IF_DEBUG(FSP1) KdPrint(( "LAN Manager server: %X errs not logged\n", Status ));
  1530. }
  1531. SrvErrorLogIgnore[i] = 0;
  1532. if( strErrorLogIgnore != StrDefaultErrorLogIgnore ) {
  1533. FREE_HEAP( strErrorLogIgnore );
  1534. }
  1535. }
  1536. #if SRVNTVERCHK
  1537. //
  1538. // Get the list of Domains that we disallow if the client
  1539. // is running NT5
  1540. //
  1541. ASSERT( SrvInvalidDomainNames == NULL );
  1542. SrvGetMultiSZList(
  1543. &SrvInvalidDomainNames,
  1544. StrRegSrvParameterPath,
  1545. StrRegInvalidDomainNames,
  1546. NULL
  1547. );
  1548. if( SrvInvalidDomainNames != NULL ) {
  1549. int i;
  1550. KdPrint(( "SRV disallows NT5 clients from the following domains:\n" ));
  1551. for( i = 0; SrvInvalidDomainNames[i]; i++ ) {
  1552. KdPrint(( " %ws\n", SrvInvalidDomainNames[i] ));
  1553. }
  1554. }
  1555. //
  1556. // Get the list of IP addresses of clients that we will allow to connect
  1557. // regardless of build number
  1558. //
  1559. {
  1560. PWSTR *strAllowedIPAddresses;
  1561. int i;
  1562. //
  1563. // Wipe out the current list
  1564. //
  1565. RtlZeroMemory( SrvAllowIPAddress, sizeof( SrvAllowIPAddress ) );
  1566. SrvGetMultiSZList(
  1567. &strAllowedIPAddresses,
  1568. StrRegSrvParameterPath,
  1569. StrRegAllowedIPAddresses,
  1570. NULL
  1571. );
  1572. if( strAllowedIPAddresses != NULL ) {
  1573. KdPrint(( "SRV ignores NT build version of clients at following IP addrs:\n" ));
  1574. //
  1575. // Fill it with the new ones
  1576. //
  1577. for(i = 0;
  1578. strAllowedIPAddresses[i] &&
  1579. i < (sizeof(SrvAllowIPAddress)/sizeof(SrvAllowIPAddress[0]))-1;
  1580. i++ ) {
  1581. LPWSTR p;
  1582. DWORD addr = 0;
  1583. char *s = (char *)&addr;
  1584. //
  1585. // Convert the IP address to a DWORD and store it
  1586. //
  1587. for( p = strAllowedIPAddresses[i]; *p && s < ((char *)&addr)+sizeof(addr); p++ ) {
  1588. if( *p == L'.' ) {
  1589. s++;
  1590. } else if( *p >= '0' && *p <= '9' ) {
  1591. *s = (*s * 10) + (*p - L'0');
  1592. }
  1593. }
  1594. SrvAllowIPAddress[i] = addr;
  1595. KdPrint(( " %ws\n", strAllowedIPAddresses[i] ));
  1596. }
  1597. FREE_HEAP( strAllowedIPAddresses );
  1598. }
  1599. }
  1600. #endif
  1601. }
  1602. #if SRVNTVERCHK
  1603. VOID
  1604. SrvGetRegClientNumber (
  1605. VOID
  1606. )
  1607. /*++
  1608. Routine Description:
  1609. This routine reads MinNt5Client REG_DWORD from the registry and sets
  1610. the global SrvMinNT5Client to the retrieved value. Later, if a client
  1611. running >= NT5 with a build number less than SrvMinNT5Client tries to
  1612. connect to a disk share, we reject the connection. This mechanism
  1613. is used on our SLM servers to ensure that people are upgrading to
  1614. current builds.
  1615. --*/
  1616. {
  1617. UNICODE_STRING unicodeKeyName;
  1618. UNICODE_STRING unicodeParamPath;
  1619. OBJECT_ATTRIBUTES objAttributes;
  1620. HANDLE keyHandle;
  1621. PKEY_VALUE_PARTIAL_INFORMATION infoBuffer;
  1622. ULONG lengthNeeded;
  1623. NTSTATUS status;
  1624. PAGED_CODE( );
  1625. SrvMinNT5Client = 0;
  1626. SrvMinNT5ClientIPCToo = FALSE;
  1627. RtlInitUnicodeString( &unicodeParamPath, StrRegSrvParameterPath );
  1628. RtlInitUnicodeString( &unicodeKeyName, L"MinNT5Client" );
  1629. InitializeObjectAttributes(
  1630. &objAttributes,
  1631. &unicodeParamPath,
  1632. OBJ_CASE_INSENSITIVE,
  1633. NULL,
  1634. NULL
  1635. );
  1636. status = ZwOpenKey(
  1637. &keyHandle,
  1638. KEY_QUERY_VALUE,
  1639. &objAttributes
  1640. );
  1641. if ( NT_SUCCESS(status) ) {
  1642. status = ZwQueryValueKey(
  1643. keyHandle,
  1644. &unicodeKeyName,
  1645. KeyValuePartialInformation,
  1646. NULL,
  1647. 0,
  1648. &lengthNeeded
  1649. );
  1650. if( status != STATUS_BUFFER_TOO_SMALL ) {
  1651. RtlInitUnicodeString( &unicodeKeyName, L"MinNT5ClientIPC" );
  1652. status = ZwQueryValueKey(
  1653. keyHandle,
  1654. &unicodeKeyName,
  1655. KeyValuePartialInformation,
  1656. NULL,
  1657. 0,
  1658. &lengthNeeded
  1659. );
  1660. SrvMinNT5ClientIPCToo = TRUE;
  1661. }
  1662. if( status == STATUS_BUFFER_TOO_SMALL ) {
  1663. infoBuffer = ALLOCATE_HEAP_COLD( lengthNeeded, BlockTypeDataBuffer );
  1664. if( infoBuffer ) {
  1665. status = ZwQueryValueKey(
  1666. keyHandle,
  1667. &unicodeKeyName,
  1668. KeyValuePartialInformation,
  1669. infoBuffer,
  1670. lengthNeeded,
  1671. &lengthNeeded
  1672. );
  1673. if( NT_SUCCESS( status ) &&
  1674. infoBuffer->Type == REG_DWORD &&
  1675. infoBuffer->DataLength == sizeof( DWORD ) ) {
  1676. SrvMinNT5Client = *(DWORD *)(&infoBuffer->Data[0]);
  1677. KdPrint(( "SRV: Restrict NT5 clients to builds >= %u\n",
  1678. SrvMinNT5Client ));
  1679. if( SrvMinNT5ClientIPCToo ) {
  1680. KdPrint(( " Restrict IPC clients\n" ));
  1681. }
  1682. }
  1683. FREE_HEAP( infoBuffer );
  1684. }
  1685. }
  1686. NtClose( keyHandle );
  1687. }
  1688. }
  1689. #endif
  1690. #if MULTIPROCESSOR
  1691. VOID
  1692. StartQueueDepthComputations(
  1693. PWORK_QUEUE queue
  1694. )
  1695. {
  1696. LARGE_INTEGER currentTime;
  1697. PAGED_CODE();
  1698. if( SrvNumberOfProcessors == 1 )
  1699. return;
  1700. //
  1701. // We're going to schedule a dpc to call the 'ComputeAvgQueueDepth' routine
  1702. // Initialize the dpc
  1703. //
  1704. KeInitializeDpc( &queue->QueueAvgDpc, ComputeAvgQueueDepth, queue );
  1705. //
  1706. // We want to make sure the dpc runs on the same processor handling the
  1707. // queue -- to avoid thrashing the cache
  1708. //
  1709. KeSetTargetProcessorDpc( &queue->QueueAvgDpc, (CCHAR)(queue - SrvWorkQueues));
  1710. //
  1711. // Initialize a timer object to schedule our dpc later
  1712. //
  1713. KeInitializeTimer( &queue->QueueAvgTimer );
  1714. KeQuerySystemTime( &currentTime );
  1715. queue->NextAvgUpdateTime.QuadPart = currentTime.QuadPart + SrvQueueCalc.QuadPart;
  1716. //
  1717. // Initialize the sample vector
  1718. //
  1719. queue->NextSample = queue->DepthSamples;
  1720. RtlZeroMemory( queue->DepthSamples, sizeof( queue->DepthSamples ) );
  1721. //
  1722. // And start it going!
  1723. //
  1724. KeSetTimer( &queue->QueueAvgTimer, queue->NextAvgUpdateTime, &queue->QueueAvgDpc );
  1725. }
  1726. VOID
  1727. StopQueueDepthComputations(
  1728. PWORK_QUEUE queue
  1729. )
  1730. {
  1731. KIRQL oldIrql;
  1732. if( SrvNumberOfProcessors == 1 )
  1733. return;
  1734. KeInitializeEvent( &queue->AvgQueueDepthTerminationEvent,
  1735. NotificationEvent,
  1736. FALSE
  1737. );
  1738. ACQUIRE_SPIN_LOCK( &queue->SpinLock, &oldIrql );
  1739. queue->NextSample = NULL;
  1740. RELEASE_SPIN_LOCK( &queue->SpinLock, oldIrql );
  1741. //
  1742. // Cancel the computation timer. If this works, then we know that
  1743. // the DPC code is not running. Otherwise, it is running or queued
  1744. // to run and we need to wait until it completes.
  1745. //
  1746. if( !KeCancelTimer( &queue->QueueAvgTimer ) ) {
  1747. KeWaitForSingleObject(
  1748. &queue->AvgQueueDepthTerminationEvent,
  1749. Executive,
  1750. KernelMode,
  1751. FALSE,
  1752. NULL
  1753. );
  1754. }
  1755. }
  1756. VOID
  1757. ComputeAvgQueueDepth (
  1758. IN PKDPC Dpc,
  1759. IN PVOID DeferredContext,
  1760. IN PVOID SystemArgument1,
  1761. IN PVOID SystemArgument2
  1762. )
  1763. {
  1764. LARGE_INTEGER currentTime;
  1765. PWORK_QUEUE queue = (PWORK_QUEUE)DeferredContext;
  1766. ACQUIRE_DPC_SPIN_LOCK( &queue->SpinLock );
  1767. if( queue->NextSample == NULL ) {
  1768. KeSetEvent( &queue->AvgQueueDepthTerminationEvent, 0, FALSE );
  1769. } else {
  1770. //
  1771. // Compute the sliding window average by taking a queue depth
  1772. // sample, removing the old sample value from the running sum
  1773. // and adding in the new value
  1774. //
  1775. currentTime.LowPart= PtrToUlong(SystemArgument1);
  1776. currentTime.HighPart = PtrToUlong(SystemArgument2);
  1777. queue->AvgQueueDepthSum -= *queue->NextSample;
  1778. *(queue->NextSample) = KeReadStateQueue( &queue->Queue );
  1779. queue->AvgQueueDepthSum += *queue->NextSample;
  1780. if( ++(queue->NextSample) == &queue->DepthSamples[ QUEUE_SAMPLES ] )
  1781. queue->NextSample = queue->DepthSamples;
  1782. queue->NextAvgUpdateTime.QuadPart =
  1783. currentTime.QuadPart + SrvQueueCalc.QuadPart;
  1784. KeSetTimer( &queue->QueueAvgTimer,
  1785. queue->NextAvgUpdateTime,
  1786. &queue->QueueAvgDpc );
  1787. }
  1788. RELEASE_DPC_SPIN_LOCK( &queue->SpinLock );
  1789. }
  1790. #endif // MULTIPROCESSOR