static NTSTATUS NdNtfsFlushUserStream ( IN PIRP_CONTEXT IrpContext, IN PSCB Scb, IN PLONGLONG FileOffset OPTIONAL, IN ULONG Length ) /*++ Routine Description: This routine flushes a user stream as a top-level action. To do so it checkpoints the current transaction first and frees all of the caller's snapshots. After doing the flush, it snapshots the input Scb again, just in case the caller plans to do any more work on that stream. If the caller needs to modify any other streams (presumably metadata), it must know to snapshot them itself after calling this routine. Arguments: Scb - Stream to flush FileOffset - FileOffset at which the flush is to start, or NULL for entire stream. Length - Number of bytes to flush. Ignored if FileOffset not specified. Return Value: Status of the flush --*/ { IO_STATUS_BLOCK IoStatus; BOOLEAN ScbAcquired = FALSE; PAGED_CODE(); // // Checkpoint the current transaction and free all of its snapshots, // in order to treat the flush as a top-level action with his own // snapshots, etc. // #if 0 NtfsCheckpointCurrentTransaction( IrpContext ); NtfsFreeSnapshotsForFcb( IrpContext, NULL ); #endif // // Set the wait flag in the IrpContext so we don't hit a case where the // reacquire below fails because we can't wait. If our caller was asynchronous // and we get this far we will continue synchronously. // SetFlag( IrpContext->State, IRP_CONTEXT_STATE_WAIT ); // // We must free the Scb now before calling through MM to prevent // collided page deadlocks. // // // We are about to flush the stream. The Scb may be acquired exclusive // and, thus, is linked onto the IrpContext or onto one higher // up in the IoCallDriver stack. We are about to make a // call back into Ntfs which may acquire the Scb exclusive, but // NOT put it onto the nested IrpContext exclusive queue which prevents // the nested completion from freeing the Scb. // // This is only a problem for Scb's without a paging resource. // // We acquire the Scb via ExAcquireResourceExclusiveLite, sidestepping // Ntfs bookkeeping, and release it via NtfsReleaseScb. // ScbAcquired = NtfsIsExclusiveScb( Scb ); if (ScbAcquired) { if (Scb->Header.PagingIoResource == NULL) { NtfsAcquireResourceExclusive( IrpContext, Scb, TRUE ); } NtfsReleaseScb( IrpContext, Scb ); } #ifdef COMPRESS_ON_WIRE if (Scb->Header.FileObjectC != NULL) { PCOMPRESSION_SYNC CompressionSync = NULL; // // Use a try-finally to clean up the compression sync. // try { NtfsSynchronizeUncompressedIo( Scb, NULL, 0, TRUE, &CompressionSync ); } finally { NtfsReleaseCompressionSync( CompressionSync ); } }
VOID NtfsReleaseFcb ( IN PIRP_CONTEXT IrpContext, IN PFCB Fcb ) /*++ Routine Description: This routine releases the specified Fcb resource. If the Fcb is acquired exclusive, and a transaction is still active, then the release is nooped in order to preserve two-phase locking. If there is no longer an active transaction, then we remove the Fcb from the Exclusive Fcb List off the IrpContext, and clear the Flink as a sign. Fcbs are released when the transaction is commited. Arguments: Fcb - Fcb to release Return Value: None. --*/ { // // Check if this resource is owned exclusively and we are at the last // release for this transaction. // if (Fcb->ExclusiveFcbLinks.Flink != NULL) { if (Fcb->BaseExclusiveCount == 1) { // // If there is a transaction then noop this request. // if (IrpContext->TransactionId != 0) { return; } RemoveEntryList( &Fcb->ExclusiveFcbLinks ); Fcb->ExclusiveFcbLinks.Flink = NULL; // // This is a good time to free any Scb snapshots for this Fcb. // NtfsFreeSnapshotsForFcb( IrpContext, Fcb ); } Fcb->BaseExclusiveCount -= 1; } ASSERT((Fcb->ExclusiveFcbLinks.Flink == NULL && Fcb->BaseExclusiveCount == 0) || (Fcb->ExclusiveFcbLinks.Flink != NULL && Fcb->BaseExclusiveCount != 0)); ExReleaseResource( Fcb->Resource ); }