[NTFS] - Fix IncreaseMftSize(); check IrpContext to see if waiting for exclusive access to the MFT is allowed. As pointed out by Pierre.

svn path=/branches/GSoC_2016/NTFS/; revision=75170
This commit is contained in:
Trevor Thompson 2017-06-23 17:30:13 +00:00 committed by Thomas Faber
parent 9ab86116a9
commit 98ddf610bc
3 changed files with 39 additions and 18 deletions

View file

@ -323,7 +323,7 @@ NtfsOpenFile(PDEVICE_EXTENSION DeviceExt,
static static
NTSTATUS NTSTATUS
NtfsCreateFile(PDEVICE_OBJECT DeviceObject, NtfsCreateFile(PDEVICE_OBJECT DeviceObject,
PIRP Irp) PNTFS_IRP_CONTEXT IrpContext)
{ {
PDEVICE_EXTENSION DeviceExt; PDEVICE_EXTENSION DeviceExt;
PIO_STACK_LOCATION Stack; PIO_STACK_LOCATION Stack;
@ -334,8 +334,9 @@ NtfsCreateFile(PDEVICE_OBJECT DeviceObject,
// PWSTR FileName; // PWSTR FileName;
NTSTATUS Status; NTSTATUS Status;
UNICODE_STRING FullPath; UNICODE_STRING FullPath;
PIRP Irp = IrpContext->Irp;
DPRINT1("NtfsCreateFile(%p, %p) called\n", DeviceObject, Irp); DPRINT1("NtfsCreateFile(%p, %p) called\n", DeviceObject, IrpContext);
DeviceExt = DeviceObject->DeviceExtension; DeviceExt = DeviceObject->DeviceExtension;
ASSERT(DeviceExt); ASSERT(DeviceExt);
@ -561,7 +562,7 @@ NtfsCreateFile(PDEVICE_OBJECT DeviceObject,
} }
// Create the file record on disk // Create the file record on disk
Status = NtfsCreateFileRecord(DeviceExt, FileObject); Status = NtfsCreateFileRecord(DeviceExt, FileObject, BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT));
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
DPRINT1("ERROR: Couldn't create file record!\n"); DPRINT1("ERROR: Couldn't create file record!\n");
@ -569,7 +570,7 @@ NtfsCreateFile(PDEVICE_OBJECT DeviceObject,
} }
// Now we should be able to open the file // Now we should be able to open the file
return NtfsCreateFile(DeviceObject, Irp); return NtfsCreateFile(DeviceObject, IrpContext);
} }
} }
@ -615,7 +616,7 @@ NtfsCreate(PNTFS_IRP_CONTEXT IrpContext)
ExAcquireResourceExclusiveLite(&DeviceExt->DirResource, ExAcquireResourceExclusiveLite(&DeviceExt->DirResource,
TRUE); TRUE);
Status = NtfsCreateFile(DeviceObject, Status = NtfsCreateFile(DeviceObject,
IrpContext->Irp); IrpContext);
ExReleaseResourceLite(&DeviceExt->DirResource); ExReleaseResourceLite(&DeviceExt->DirResource);
return Status; return Status;
@ -634,13 +635,20 @@ NtfsCreate(PNTFS_IRP_CONTEXT IrpContext)
* @param FileObject * @param FileObject
* Pointer to a FILE_OBJECT describing the file to be created * Pointer to a FILE_OBJECT describing the file to be created
* *
* @param CanWait
* Boolean indicating if the function is allowed to wait for exclusive access to the master file table.
* This will only be relevant if the MFT doesn't have any free file records and needs to be enlarged.
*
* @return * @return
* STATUS_SUCCESS on success. * STATUS_SUCCESS on success.
* STATUS_INSUFFICIENT_RESOURCES if unable to allocate memory for the file record. * STATUS_INSUFFICIENT_RESOURCES if unable to allocate memory for the file record.
* STATUS_CANT_WAIT if CanWait was FALSE and the function needed to resize the MFT but
* couldn't get immediate, exclusive access to it.
*/ */
NTSTATUS NTSTATUS
NtfsCreateFileRecord(PDEVICE_EXTENSION DeviceExt, NtfsCreateFileRecord(PDEVICE_EXTENSION DeviceExt,
PFILE_OBJECT FileObject) PFILE_OBJECT FileObject,
BOOLEAN CanWait)
{ {
NTSTATUS Status = STATUS_SUCCESS; NTSTATUS Status = STATUS_SUCCESS;
PFILE_RECORD_HEADER FileRecord; PFILE_RECORD_HEADER FileRecord;
@ -649,7 +657,7 @@ NtfsCreateFileRecord(PDEVICE_EXTENSION DeviceExt,
ULONGLONG ParentMftIndex; ULONGLONG ParentMftIndex;
ULONGLONG FileMftIndex; ULONGLONG FileMftIndex;
DPRINT1("NtfsCreateFileRecord(%p, %p)\n", DeviceExt, FileObject); DPRINT1("NtfsCreateFileRecord(%p, %p, %s)\n", DeviceExt, FileObject, CanWait ? "TRUE" : "FALSE");
// allocate memory for file record // allocate memory for file record
FileRecord = ExAllocatePoolWithTag(NonPagedPool, FileRecord = ExAllocatePoolWithTag(NonPagedPool,
@ -708,7 +716,7 @@ NtfsCreateFileRecord(PDEVICE_EXTENSION DeviceExt,
NtfsDumpFileRecord(DeviceExt, FileRecord); NtfsDumpFileRecord(DeviceExt, FileRecord);
// Now that we've built the file record in memory, we need to store it in the MFT. // Now that we've built the file record in memory, we need to store it in the MFT.
Status = AddNewMftEntry(FileRecord, DeviceExt, &FileMftIndex); Status = AddNewMftEntry(FileRecord, DeviceExt, &FileMftIndex, CanWait);
if (NT_SUCCESS(Status)) if (NT_SUCCESS(Status))
{ {
// The highest 2 bytes should be the sequence number, unless the parent happens to be root // The highest 2 bytes should be the sequence number, unless the parent happens to be root

View file

@ -195,10 +195,16 @@ AttributeDataLength(PNTFS_ATTR_RECORD AttrRecord)
* @param Vcb * @param Vcb
* Pointer to the VCB (DEVICE_EXTENSION) of the target volume. * Pointer to the VCB (DEVICE_EXTENSION) of the target volume.
* *
*
* @param CanWait
* Boolean indicating if the function is allowed to wait for exclusive access to the master file table.
* This will only be relevant if the MFT doesn't have any free file records and needs to be enlarged.
*
* @return * @return
* STATUS_SUCCESS on success. * STATUS_SUCCESS on success.
* STATUS_INSUFFICIENT_RESOURCES if an allocation fails. * STATUS_INSUFFICIENT_RESOURCES if an allocation fails.
* STATUS_INVALID_PARAMETER if there was an error reading the Mft's bitmap. * STATUS_INVALID_PARAMETER if there was an error reading the Mft's bitmap.
* STATUS_CANT_WAIT if CanWait was FALSE and the function could not get immediate, exclusive access to the MFT.
* *
* @remarks * @remarks
* Increases the size of the Master File Table by 8 records. Bitmap entries for the new records are cleared, * Increases the size of the Master File Table by 8 records. Bitmap entries for the new records are cleared,
@ -206,7 +212,7 @@ AttributeDataLength(PNTFS_ATTR_RECORD AttrRecord)
* This function will wait for exlusive access to the volume fcb. * This function will wait for exlusive access to the volume fcb.
*/ */
NTSTATUS NTSTATUS
IncreaseMftSize(PDEVICE_EXTENSION Vcb) IncreaseMftSize(PDEVICE_EXTENSION Vcb, BOOLEAN CanWait)
{ {
PNTFS_ATTR_CONTEXT BitmapContext; PNTFS_ATTR_CONTEXT BitmapContext;
LARGE_INTEGER BitmapSize; LARGE_INTEGER BitmapSize;
@ -221,10 +227,10 @@ IncreaseMftSize(PDEVICE_EXTENSION Vcb)
ULONG LengthWritten; ULONG LengthWritten;
NTSTATUS Status; NTSTATUS Status;
DPRINT1("IncreaseMftSize(%p)\n", Vcb); DPRINT1("IncreaseMftSize(%p, %s)\n", Vcb, CanWait ? "TRUE" : "FALSE");
// We need exclusive access to the mft while we change its size // We need exclusive access to the mft while we change its size
if (!ExAcquireResourceExclusiveLite(&(Vcb->DirResource), TRUE)) if (!ExAcquireResourceExclusiveLite(&(Vcb->DirResource), CanWait))
{ {
return STATUS_CANT_WAIT; return STATUS_CANT_WAIT;
} }
@ -1638,17 +1644,22 @@ FixupUpdateSequenceArray(PDEVICE_EXTENSION Vcb,
* @param DestinationIndex * @param DestinationIndex
* Pointer to a ULONGLONG which will receive the MFT index where the file record was stored. * Pointer to a ULONGLONG which will receive the MFT index where the file record was stored.
* *
* @param CanWait
* Boolean indicating if the function is allowed to wait for exclusive access to the master file table.
* This will only be relevant if the MFT doesn't have any free file records and needs to be enlarged.
*
* @return * @return
* STATUS_SUCCESS on success. * STATUS_SUCCESS on success.
* STATUS_OBJECT_NAME_NOT_FOUND if we can't find the MFT's $Bitmap or if we weren't able * STATUS_OBJECT_NAME_NOT_FOUND if we can't find the MFT's $Bitmap or if we weren't able
* to read the attribute. * to read the attribute.
* STATUS_INSUFFICIENT_RESOURCES if we can't allocate enough memory for a copy of $Bitmap. * STATUS_INSUFFICIENT_RESOURCES if we can't allocate enough memory for a copy of $Bitmap.
* * STATUS_CANT_WAIT if CanWait was FALSE and the function could not get immediate, exclusive access to the MFT.
*/ */
NTSTATUS NTSTATUS
AddNewMftEntry(PFILE_RECORD_HEADER FileRecord, AddNewMftEntry(PFILE_RECORD_HEADER FileRecord,
PDEVICE_EXTENSION DeviceExt, PDEVICE_EXTENSION DeviceExt,
PULONGLONG DestinationIndex) PULONGLONG DestinationIndex,
BOOLEAN CanWait)
{ {
NTSTATUS Status = STATUS_SUCCESS; NTSTATUS Status = STATUS_SUCCESS;
ULONGLONG MftIndex; ULONGLONG MftIndex;
@ -1661,7 +1672,7 @@ AddNewMftEntry(PFILE_RECORD_HEADER FileRecord,
LARGE_INTEGER BitmapBits; LARGE_INTEGER BitmapBits;
UCHAR SystemReservedBits; UCHAR SystemReservedBits;
DPRINT1("AddNewMftEntry(%p, %p, %p)\n", FileRecord, DeviceExt, DestinationIndex); DPRINT1("AddNewMftEntry(%p, %p, %p, %s)\n", FileRecord, DeviceExt, DestinationIndex, CanWait ? "TRUE" : "FALSE");
// First, we have to read the mft's $Bitmap attribute // First, we have to read the mft's $Bitmap attribute
Status = FindAttribute(DeviceExt, DeviceExt->MasterFileTable, AttributeBitmap, L"", 0, &BitmapContext, NULL); Status = FindAttribute(DeviceExt, DeviceExt->MasterFileTable, AttributeBitmap, L"", 0, &BitmapContext, NULL);
@ -1717,14 +1728,14 @@ AddNewMftEntry(PFILE_RECORD_HEADER FileRecord,
ReleaseAttributeContext(BitmapContext); ReleaseAttributeContext(BitmapContext);
// Couldn't find a free record in the MFT, add some blank records and try again // Couldn't find a free record in the MFT, add some blank records and try again
Status = IncreaseMftSize(DeviceExt); Status = IncreaseMftSize(DeviceExt, CanWait);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
DPRINT1("ERROR: Couldn't find space in MFT for file or increase MFT size!\n"); DPRINT1("ERROR: Couldn't find space in MFT for file or increase MFT size!\n");
return Status; return Status;
} }
return AddNewMftEntry(FileRecord, DeviceExt, DestinationIndex); return AddNewMftEntry(FileRecord, DeviceExt, DestinationIndex, CanWait);
} }
DPRINT1("Creating file record at MFT index: %I64u\n", MftIndex); DPRINT1("Creating file record at MFT index: %I64u\n", MftIndex);

View file

@ -667,7 +667,8 @@ NtfsCreate(PNTFS_IRP_CONTEXT IrpContext);
NTSTATUS NTSTATUS
NtfsCreateFileRecord(PDEVICE_EXTENSION DeviceExt, NtfsCreateFileRecord(PDEVICE_EXTENSION DeviceExt,
PFILE_OBJECT FileObject); PFILE_OBJECT FileObject,
BOOLEAN CanWait);
/* devctl.c */ /* devctl.c */
@ -825,7 +826,8 @@ NtfsFileSystemControl(PNTFS_IRP_CONTEXT IrpContext);
NTSTATUS NTSTATUS
AddNewMftEntry(PFILE_RECORD_HEADER FileRecord, AddNewMftEntry(PFILE_RECORD_HEADER FileRecord,
PDEVICE_EXTENSION DeviceExt, PDEVICE_EXTENSION DeviceExt,
PULONGLONG DestinationIndex); PULONGLONG DestinationIndex,
BOOLEAN CanWait);
PNTFS_ATTR_CONTEXT PNTFS_ATTR_CONTEXT
PrepareAttributeContext(PNTFS_ATTR_RECORD AttrRecord); PrepareAttributeContext(PNTFS_ATTR_RECORD AttrRecord);