2017-09-08 08:02:43 +00:00
/* Copyright (c) Mark Harmstone 2016-17
*
2016-03-23 20:35:05 +00:00
* This file is part of WinBtrfs .
2017-09-08 08:02:43 +00:00
*
2016-03-23 20:35:05 +00:00
* WinBtrfs is free software : you can redistribute it and / or modify
* it under the terms of the GNU Lesser General Public Licence as published by
* the Free Software Foundation , either version 3 of the Licence , or
* ( at your option ) any later version .
2017-09-08 08:02:43 +00:00
*
2016-03-23 20:35:05 +00:00
* WinBtrfs is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU Lesser General Public Licence for more details .
2017-09-08 08:02:43 +00:00
*
2016-03-23 20:35:05 +00:00
* You should have received a copy of the GNU Lesser General Public Licence
* along with WinBtrfs . If not , see < http : //www.gnu.org/licenses/>. */
# include "btrfs_drv.h"
2020-04-23 02:38:57 +00:00
# include "xxhash.h"
# include "crc32c.h"
2017-09-08 08:02:43 +00:00
# include <ata.h>
# include <ntddscsi.h>
# include <ntddstor.h>
2016-03-23 20:35:05 +00:00
2022-04-28 19:35:58 +00:00
/* cf. __MAX_CSUM_ITEMS in Linux - it needs sizeof(leaf_node) bytes free
* so it can do a split . Linux tries to get it so a run will fit in a
* sector , but the MAX_CSUM_ITEMS logic is wrong . . . */
# define MAX_CSUM_SIZE (4096 - sizeof(tree_header) - (2 * sizeof(leaf_node)))
2016-10-29 17:05:10 +00:00
// #define DEBUG_WRITE_LOOPS
2022-09-28 16:08:10 +00:00
# define BATCH_ITEM_LIMIT 1000
2016-10-29 17:05:10 +00:00
typedef struct {
KEVENT Event ;
IO_STATUS_BLOCK iosb ;
} write_context ;
typedef struct {
EXTENT_ITEM_TREE eit ;
2019-09-01 12:53:20 +00:00
uint8_t type ;
2016-10-29 17:05:10 +00:00
TREE_BLOCK_REF tbr ;
} EXTENT_ITEM_TREE2 ;
typedef struct {
EXTENT_ITEM ei ;
2019-09-01 12:53:20 +00:00
uint8_t type ;
2016-10-29 17:05:10 +00:00
TREE_BLOCK_REF tbr ;
} EXTENT_ITEM_SKINNY_METADATA ;
2017-09-08 08:02:43 +00:00
static NTSTATUS create_chunk ( device_extension * Vcb , chunk * c , PIRP Irp ) ;
2017-01-01 17:12:12 +00:00
static NTSTATUS update_tree_extents ( device_extension * Vcb , tree * t , PIRP Irp , LIST_ENTRY * rollback ) ;
2016-10-29 17:05:10 +00:00
2022-09-28 16:08:10 +00:00
static NTSTATUS insert_tree_item_batch ( LIST_ENTRY * batchlist , device_extension * Vcb , root * r , uint64_t objid ,
uint8_t objtype , uint64_t offset , _In_opt_ _When_ ( return > = 0 , __drv_aliasesMem ) void * data ,
uint16_t datalen , enum batch_operation operation ) ;
2017-09-08 08:02:43 +00:00
_Function_class_ ( IO_COMPLETION_ROUTINE )
2019-09-01 12:53:20 +00:00
static NTSTATUS __stdcall write_completion ( PDEVICE_OBJECT DeviceObject , PIRP Irp , PVOID conptr ) {
2016-10-29 17:05:10 +00:00
write_context * context = conptr ;
2017-09-08 08:02:43 +00:00
UNUSED ( DeviceObject ) ;
2016-10-29 17:05:10 +00:00
context - > iosb = Irp - > IoStatus ;
2019-09-01 12:53:20 +00:00
KeSetEvent ( & context - > Event , 0 , false ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
return STATUS_MORE_PROCESSING_REQUIRED ;
}
2019-09-01 12:53:20 +00:00
NTSTATUS write_data_phys ( _In_ PDEVICE_OBJECT device , _In_ PFILE_OBJECT fileobj , _In_ uint64_t address ,
_In_reads_bytes_ ( length ) void * data , _In_ uint32_t length ) {
2016-10-29 17:05:10 +00:00
NTSTATUS Status ;
LARGE_INTEGER offset ;
PIRP Irp ;
PIO_STACK_LOCATION IrpSp ;
2017-09-08 08:02:43 +00:00
write_context context ;
2019-09-01 12:53:20 +00:00
TRACE ( " (%p, %I64x, %p, %x) \n " , device , address , data , length ) ;
2017-09-08 08:02:43 +00:00
RtlZeroMemory ( & context , sizeof ( write_context ) ) ;
2019-09-01 12:53:20 +00:00
KeInitializeEvent ( & context . Event , NotificationEvent , false ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
offset . QuadPart = address ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Irp = IoAllocateIrp ( device - > StackSize , false ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! Irp ) {
ERR ( " IoAllocateIrp failed \n " ) ;
2017-09-08 08:02:43 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
IrpSp = IoGetNextIrpStackLocation ( Irp ) ;
IrpSp - > MajorFunction = IRP_MJ_WRITE ;
2019-09-01 12:53:20 +00:00
IrpSp - > FileObject = fileobj ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( device - > Flags & DO_BUFFERED_IO ) {
Irp - > AssociatedIrp . SystemBuffer = data ;
Irp - > Flags = IRP_BUFFERED_IO ;
} else if ( device - > Flags & DO_DIRECT_IO ) {
2019-09-01 12:53:20 +00:00
Irp - > MdlAddress = IoAllocateMdl ( data , length , false , false , NULL ) ;
2016-10-29 17:05:10 +00:00
if ( ! Irp - > MdlAddress ) {
DbgPrint ( " IoAllocateMdl failed \n " ) ;
2017-09-08 08:02:43 +00:00
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto exit ;
}
Status = STATUS_SUCCESS ;
_SEH2_TRY {
MmProbeAndLockPages ( Irp - > MdlAddress , KernelMode , IoReadAccess ) ;
} _SEH2_EXCEPT ( EXCEPTION_EXECUTE_HANDLER ) {
Status = _SEH2_GetExceptionCode ( ) ;
} _SEH2_END ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " MmProbeAndLockPages threw exception %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
IoFreeMdl ( Irp - > MdlAddress ) ;
2016-10-29 17:05:10 +00:00
goto exit ;
}
} else {
Irp - > UserBuffer = data ;
}
IrpSp - > Parameters . Write . Length = length ;
IrpSp - > Parameters . Write . ByteOffset = offset ;
2017-09-08 08:02:43 +00:00
Irp - > UserIosb = & context . iosb ;
2016-10-29 17:05:10 +00:00
2017-09-08 08:02:43 +00:00
Irp - > UserEvent = & context . Event ;
2019-09-01 12:53:20 +00:00
IoSetCompletionRoutine ( Irp , write_completion , & context , true , true , true ) ;
2016-10-29 17:05:10 +00:00
Status = IoCallDriver ( device , Irp ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( Status = = STATUS_PENDING ) {
2019-09-01 12:53:20 +00:00
KeWaitForSingleObject ( & context . Event , Executive , KernelMode , false , NULL ) ;
2017-09-08 08:02:43 +00:00
Status = context . iosb . Status ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " IoCallDriver returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( device - > Flags & DO_DIRECT_IO ) {
MmUnlockPages ( Irp - > MdlAddress ) ;
IoFreeMdl ( Irp - > MdlAddress ) ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
exit :
IoFreeIrp ( Irp ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
return Status ;
}
2019-09-01 12:53:20 +00:00
static void add_trim_entry ( device * dev , uint64_t address , uint64_t size ) {
2017-09-08 08:02:43 +00:00
space * s = ExAllocatePoolWithTag ( PagedPool , sizeof ( space ) , ALLOC_TAG ) ;
if ( ! s ) {
ERR ( " out of memory \n " ) ;
return ;
}
s - > address = address ;
s - > size = size ;
dev - > num_trim_entries + + ;
InsertTailList ( & dev - > trim_list , & s - > list_entry ) ;
}
2016-10-29 17:05:10 +00:00
static void clean_space_cache_chunk ( device_extension * Vcb , chunk * c ) {
2022-04-28 19:31:44 +00:00
LIST_ENTRY * le ;
2017-09-08 08:02:43 +00:00
ULONG type ;
2022-04-28 19:31:44 +00:00
if ( c - > chunk_item - > type & BLOCK_FLAG_DUPLICATE )
type = BLOCK_FLAG_DUPLICATE ;
else if ( c - > chunk_item - > type & BLOCK_FLAG_RAID0 )
type = BLOCK_FLAG_RAID0 ;
else if ( c - > chunk_item - > type & BLOCK_FLAG_RAID1 )
type = BLOCK_FLAG_DUPLICATE ;
else if ( c - > chunk_item - > type & BLOCK_FLAG_RAID10 )
type = BLOCK_FLAG_RAID10 ;
else if ( c - > chunk_item - > type & BLOCK_FLAG_RAID5 )
type = BLOCK_FLAG_RAID5 ;
else if ( c - > chunk_item - > type & BLOCK_FLAG_RAID6 )
type = BLOCK_FLAG_RAID6 ;
else if ( c - > chunk_item - > type & BLOCK_FLAG_RAID1C3 )
type = BLOCK_FLAG_DUPLICATE ;
else if ( c - > chunk_item - > type & BLOCK_FLAG_RAID1C4 )
type = BLOCK_FLAG_DUPLICATE ;
else // SINGLE
type = BLOCK_FLAG_DUPLICATE ;
le = c - > deleting . Flink ;
while ( le ! = & c - > deleting ) {
space * s = CONTAINING_RECORD ( le , space , list_entry ) ;
2017-09-08 08:02:43 +00:00
2022-04-28 19:31:44 +00:00
if ( ! Vcb - > options . no_barrier | | ! ( c - > chunk_item - > type & BLOCK_FLAG_METADATA ) ) {
2017-09-08 08:02:43 +00:00
CHUNK_ITEM_STRIPE * cis = ( CHUNK_ITEM_STRIPE * ) & c - > chunk_item [ 1 ] ;
if ( type = = BLOCK_FLAG_DUPLICATE ) {
2019-09-01 12:53:20 +00:00
uint16_t i ;
2017-09-08 08:02:43 +00:00
for ( i = 0 ; i < c - > chunk_item - > num_stripes ; i + + ) {
if ( c - > devices [ i ] & & c - > devices [ i ] - > devobj & & ! c - > devices [ i ] - > readonly & & c - > devices [ i ] - > trim )
add_trim_entry ( c - > devices [ i ] , s - > address - c - > offset + cis [ i ] . offset , s - > size ) ;
}
} else if ( type = = BLOCK_FLAG_RAID0 ) {
2019-09-01 12:53:20 +00:00
uint64_t startoff , endoff ;
uint16_t startoffstripe , endoffstripe , i ;
2017-09-08 08:02:43 +00:00
get_raid0_offset ( s - > address - c - > offset , c - > chunk_item - > stripe_length , c - > chunk_item - > num_stripes , & startoff , & startoffstripe ) ;
get_raid0_offset ( s - > address - c - > offset + s - > size - 1 , c - > chunk_item - > stripe_length , c - > chunk_item - > num_stripes , & endoff , & endoffstripe ) ;
for ( i = 0 ; i < c - > chunk_item - > num_stripes ; i + + ) {
if ( c - > devices [ i ] & & c - > devices [ i ] - > devobj & & ! c - > devices [ i ] - > readonly & & c - > devices [ i ] - > trim ) {
2019-09-01 12:53:20 +00:00
uint64_t stripestart , stripeend ;
2017-09-08 08:02:43 +00:00
if ( startoffstripe > i )
stripestart = startoff - ( startoff % c - > chunk_item - > stripe_length ) + c - > chunk_item - > stripe_length ;
else if ( startoffstripe = = i )
stripestart = startoff ;
else
stripestart = startoff - ( startoff % c - > chunk_item - > stripe_length ) ;
if ( endoffstripe > i )
stripeend = endoff - ( endoff % c - > chunk_item - > stripe_length ) + c - > chunk_item - > stripe_length ;
else if ( endoffstripe = = i )
stripeend = endoff + 1 ;
else
stripeend = endoff - ( endoff % c - > chunk_item - > stripe_length ) ;
if ( stripestart ! = stripeend )
add_trim_entry ( c - > devices [ i ] , stripestart + cis [ i ] . offset , stripeend - stripestart ) ;
}
}
} else if ( type = = BLOCK_FLAG_RAID10 ) {
2019-09-01 12:53:20 +00:00
uint64_t startoff , endoff ;
uint16_t sub_stripes , startoffstripe , endoffstripe , i ;
2017-09-08 08:02:43 +00:00
sub_stripes = max ( 1 , c - > chunk_item - > sub_stripes ) ;
get_raid0_offset ( s - > address - c - > offset , c - > chunk_item - > stripe_length , c - > chunk_item - > num_stripes / sub_stripes , & startoff , & startoffstripe ) ;
get_raid0_offset ( s - > address - c - > offset + s - > size - 1 , c - > chunk_item - > stripe_length , c - > chunk_item - > num_stripes / sub_stripes , & endoff , & endoffstripe ) ;
startoffstripe * = sub_stripes ;
endoffstripe * = sub_stripes ;
for ( i = 0 ; i < c - > chunk_item - > num_stripes ; i + = sub_stripes ) {
ULONG j ;
2019-09-01 12:53:20 +00:00
uint64_t stripestart , stripeend ;
2017-09-08 08:02:43 +00:00
if ( startoffstripe > i )
stripestart = startoff - ( startoff % c - > chunk_item - > stripe_length ) + c - > chunk_item - > stripe_length ;
else if ( startoffstripe = = i )
stripestart = startoff ;
else
stripestart = startoff - ( startoff % c - > chunk_item - > stripe_length ) ;
if ( endoffstripe > i )
stripeend = endoff - ( endoff % c - > chunk_item - > stripe_length ) + c - > chunk_item - > stripe_length ;
else if ( endoffstripe = = i )
stripeend = endoff + 1 ;
else
stripeend = endoff - ( endoff % c - > chunk_item - > stripe_length ) ;
if ( stripestart ! = stripeend ) {
for ( j = 0 ; j < sub_stripes ; j + + ) {
if ( c - > devices [ i + j ] & & c - > devices [ i + j ] - > devobj & & ! c - > devices [ i + j ] - > readonly & & c - > devices [ i + j ] - > trim )
add_trim_entry ( c - > devices [ i + j ] , stripestart + cis [ i + j ] . offset , stripeend - stripestart ) ;
}
}
}
}
// FIXME - RAID5(?), RAID6(?)
}
2022-04-28 19:31:44 +00:00
le = le - > Flink ;
2016-10-29 17:05:10 +00:00
}
}
2017-09-08 08:02:43 +00:00
typedef struct {
DEVICE_MANAGE_DATA_SET_ATTRIBUTES * dmdsa ;
ATA_PASS_THROUGH_EX apte ;
PIRP Irp ;
IO_STATUS_BLOCK iosb ;
2019-09-01 12:53:20 +00:00
# ifdef DEBUG_TRIM_EMULATION
PMDL mdl ;
void * buf ;
# endif
2017-09-08 08:02:43 +00:00
} ioctl_context_stripe ;
typedef struct {
KEVENT Event ;
LONG left ;
ioctl_context_stripe * stripes ;
} ioctl_context ;
_Function_class_ ( IO_COMPLETION_ROUTINE )
2019-09-01 12:53:20 +00:00
static NTSTATUS __stdcall ioctl_completion ( PDEVICE_OBJECT DeviceObject , PIRP Irp , PVOID conptr ) {
2017-09-08 08:02:43 +00:00
ioctl_context * context = ( ioctl_context * ) conptr ;
LONG left2 = InterlockedDecrement ( & context - > left ) ;
UNUSED ( DeviceObject ) ;
UNUSED ( Irp ) ;
if ( left2 = = 0 )
2019-09-01 12:53:20 +00:00
KeSetEvent ( & context - > Event , 0 , false ) ;
2017-09-08 08:02:43 +00:00
return STATUS_MORE_PROCESSING_REQUIRED ;
}
2019-09-01 12:53:20 +00:00
# ifdef DEBUG_TRIM_EMULATION
static void trim_emulation ( device * dev ) {
LIST_ENTRY * le ;
ioctl_context context ;
unsigned int i = 0 , count = 0 ;
le = dev - > trim_list . Flink ;
while ( le ! = & dev - > trim_list ) {
count + + ;
le = le - > Flink ;
}
context . left = count ;
KeInitializeEvent ( & context . Event , NotificationEvent , false ) ;
context . stripes = ExAllocatePoolWithTag ( NonPagedPool , sizeof ( ioctl_context_stripe ) * context . left , ALLOC_TAG ) ;
if ( ! context . stripes ) {
ERR ( " out of memory \n " ) ;
return ;
}
RtlZeroMemory ( context . stripes , sizeof ( ioctl_context_stripe ) * context . left ) ;
i = 0 ;
le = dev - > trim_list . Flink ;
while ( le ! = & dev - > trim_list ) {
ioctl_context_stripe * stripe = & context . stripes [ i ] ;
space * s = CONTAINING_RECORD ( le , space , list_entry ) ;
WARN ( " (%I64x, %I64x) \n " , s - > address , s - > size ) ;
stripe - > Irp = IoAllocateIrp ( dev - > devobj - > StackSize , false ) ;
if ( ! stripe - > Irp ) {
ERR ( " IoAllocateIrp failed \n " ) ;
} else {
PIO_STACK_LOCATION IrpSp = IoGetNextIrpStackLocation ( stripe - > Irp ) ;
IrpSp - > MajorFunction = IRP_MJ_WRITE ;
IrpSp - > FileObject = dev - > fileobj ;
stripe - > buf = ExAllocatePoolWithTag ( NonPagedPool , ( uint32_t ) s - > size , ALLOC_TAG ) ;
if ( ! stripe - > buf ) {
ERR ( " out of memory \n " ) ;
} else {
RtlZeroMemory ( stripe - > buf , ( uint32_t ) s - > size ) ; // FIXME - randomize instead?
stripe - > mdl = IoAllocateMdl ( stripe - > buf , ( uint32_t ) s - > size , false , false , NULL ) ;
if ( ! stripe - > mdl ) {
ERR ( " IoAllocateMdl failed \n " ) ;
} else {
MmBuildMdlForNonPagedPool ( stripe - > mdl ) ;
stripe - > Irp - > MdlAddress = stripe - > mdl ;
IrpSp - > Parameters . Write . ByteOffset . QuadPart = s - > address ;
IrpSp - > Parameters . Write . Length = s - > size ;
stripe - > Irp - > UserIosb = & stripe - > iosb ;
IoSetCompletionRoutine ( stripe - > Irp , ioctl_completion , & context , true , true , true ) ;
IoCallDriver ( dev - > devobj , stripe - > Irp ) ;
}
}
}
i + + ;
le = le - > Flink ;
}
KeWaitForSingleObject ( & context . Event , Executive , KernelMode , false , NULL ) ;
for ( i = 0 ; i < count ; i + + ) {
ioctl_context_stripe * stripe = & context . stripes [ i ] ;
if ( stripe - > mdl )
IoFreeMdl ( stripe - > mdl ) ;
if ( stripe - > buf )
ExFreePool ( stripe - > buf ) ;
}
ExFreePool ( context . stripes ) ;
}
# endif
2016-10-29 17:05:10 +00:00
static void clean_space_cache ( device_extension * Vcb ) {
2017-09-08 08:02:43 +00:00
LIST_ENTRY * le ;
2016-10-29 17:05:10 +00:00
chunk * c ;
2019-09-01 12:53:20 +00:00
# ifndef DEBUG_TRIM_EMULATION
2017-09-08 08:02:43 +00:00
ULONG num ;
2019-09-01 12:53:20 +00:00
# endif
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
TRACE ( " (%p) \n " , Vcb ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
ExAcquireResourceSharedLite ( & Vcb - > chunk_lock , true ) ;
2017-09-08 08:02:43 +00:00
le = Vcb - > chunks . Flink ;
while ( le ! = & Vcb - > chunks ) {
c = CONTAINING_RECORD ( le , chunk , list_entry ) ;
if ( c - > space_changed ) {
2018-12-16 11:03:16 +00:00
acquire_chunk_lock ( c , Vcb ) ;
2017-09-08 08:02:43 +00:00
2022-04-28 19:31:44 +00:00
if ( c - > space_changed ) {
if ( Vcb - > trim & & ! Vcb - > options . no_trim )
clean_space_cache_chunk ( Vcb , c ) ;
space_list_merge ( & c - > space , & c - > space_size , & c - > deleting ) ;
while ( ! IsListEmpty ( & c - > deleting ) ) {
space * s = CONTAINING_RECORD ( RemoveHeadList ( & c - > deleting ) , space , list_entry ) ;
ExFreePool ( s ) ;
}
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
c - > space_changed = false ;
2017-09-08 08:02:43 +00:00
2018-12-16 11:03:16 +00:00
release_chunk_lock ( c , Vcb ) ;
2017-09-08 08:02:43 +00:00
}
le = le - > Flink ;
}
ExReleaseResourceLite ( & Vcb - > chunk_lock ) ;
if ( Vcb - > trim & & ! Vcb - > options . no_trim ) {
2019-09-01 12:53:20 +00:00
# ifndef DEBUG_TRIM_EMULATION
2017-09-08 08:02:43 +00:00
ioctl_context context ;
ULONG total_num ;
context . left = 0 ;
le = Vcb - > devices . Flink ;
while ( le ! = & Vcb - > devices ) {
device * dev = CONTAINING_RECORD ( le , device , list_entry ) ;
if ( dev - > devobj & & ! dev - > readonly & & dev - > trim & & dev - > num_trim_entries > 0 )
context . left + + ;
le = le - > Flink ;
}
if ( context . left = = 0 )
return ;
total_num = context . left ;
num = 0 ;
2019-09-01 12:53:20 +00:00
KeInitializeEvent ( & context . Event , NotificationEvent , false ) ;
2017-09-08 08:02:43 +00:00
context . stripes = ExAllocatePoolWithTag ( NonPagedPool , sizeof ( ioctl_context_stripe ) * context . left , ALLOC_TAG ) ;
if ( ! context . stripes ) {
ERR ( " out of memory \n " ) ;
return ;
}
RtlZeroMemory ( context . stripes , sizeof ( ioctl_context_stripe ) * context . left ) ;
2019-09-01 12:53:20 +00:00
# endif
2017-09-08 08:02:43 +00:00
le = Vcb - > devices . Flink ;
while ( le ! = & Vcb - > devices ) {
device * dev = CONTAINING_RECORD ( le , device , list_entry ) ;
if ( dev - > devobj & & ! dev - > readonly & & dev - > trim & & dev - > num_trim_entries > 0 ) {
2019-09-01 12:53:20 +00:00
# ifdef DEBUG_TRIM_EMULATION
trim_emulation ( dev ) ;
# else
2017-09-08 08:02:43 +00:00
LIST_ENTRY * le2 ;
ioctl_context_stripe * stripe = & context . stripes [ num ] ;
DEVICE_DATA_SET_RANGE * ranges ;
2019-09-01 12:53:20 +00:00
ULONG datalen = ( ULONG ) sector_align ( sizeof ( DEVICE_MANAGE_DATA_SET_ATTRIBUTES ) , sizeof ( uint64_t ) ) + ( dev - > num_trim_entries * sizeof ( DEVICE_DATA_SET_RANGE ) ) , i ;
2017-09-08 08:02:43 +00:00
PIO_STACK_LOCATION IrpSp ;
stripe - > dmdsa = ExAllocatePoolWithTag ( PagedPool , datalen , ALLOC_TAG ) ;
if ( ! stripe - > dmdsa ) {
ERR ( " out of memory \n " ) ;
goto nextdev ;
}
stripe - > dmdsa - > Size = sizeof ( DEVICE_MANAGE_DATA_SET_ATTRIBUTES ) ;
stripe - > dmdsa - > Action = DeviceDsmAction_Trim ;
stripe - > dmdsa - > Flags = DEVICE_DSM_FLAG_TRIM_NOT_FS_ALLOCATED ;
stripe - > dmdsa - > ParameterBlockOffset = 0 ;
stripe - > dmdsa - > ParameterBlockLength = 0 ;
2019-09-01 12:53:20 +00:00
stripe - > dmdsa - > DataSetRangesOffset = ( ULONG ) sector_align ( sizeof ( DEVICE_MANAGE_DATA_SET_ATTRIBUTES ) , sizeof ( uint64_t ) ) ;
2017-09-08 08:02:43 +00:00
stripe - > dmdsa - > DataSetRangesLength = dev - > num_trim_entries * sizeof ( DEVICE_DATA_SET_RANGE ) ;
2019-09-01 12:53:20 +00:00
ranges = ( DEVICE_DATA_SET_RANGE * ) ( ( uint8_t * ) stripe - > dmdsa + stripe - > dmdsa - > DataSetRangesOffset ) ;
2017-09-08 08:02:43 +00:00
i = 0 ;
le2 = dev - > trim_list . Flink ;
while ( le2 ! = & dev - > trim_list ) {
space * s = CONTAINING_RECORD ( le2 , space , list_entry ) ;
ranges [ i ] . StartingOffset = s - > address ;
ranges [ i ] . LengthInBytes = s - > size ;
i + + ;
le2 = le2 - > Flink ;
}
2019-09-01 12:53:20 +00:00
stripe - > Irp = IoAllocateIrp ( dev - > devobj - > StackSize , false ) ;
2017-09-08 08:02:43 +00:00
if ( ! stripe - > Irp ) {
ERR ( " IoAllocateIrp failed \n " ) ;
goto nextdev ;
}
IrpSp = IoGetNextIrpStackLocation ( stripe - > Irp ) ;
IrpSp - > MajorFunction = IRP_MJ_DEVICE_CONTROL ;
2019-09-01 12:53:20 +00:00
IrpSp - > FileObject = dev - > fileobj ;
2017-09-08 08:02:43 +00:00
IrpSp - > Parameters . DeviceIoControl . IoControlCode = IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES ;
IrpSp - > Parameters . DeviceIoControl . InputBufferLength = datalen ;
IrpSp - > Parameters . DeviceIoControl . OutputBufferLength = 0 ;
stripe - > Irp - > AssociatedIrp . SystemBuffer = stripe - > dmdsa ;
stripe - > Irp - > Flags | = IRP_BUFFERED_IO ;
stripe - > Irp - > UserBuffer = NULL ;
stripe - > Irp - > UserIosb = & stripe - > iosb ;
2019-09-01 12:53:20 +00:00
IoSetCompletionRoutine ( stripe - > Irp , ioctl_completion , & context , true , true , true ) ;
2017-09-08 08:02:43 +00:00
IoCallDriver ( dev - > devobj , stripe - > Irp ) ;
nextdev :
2019-09-01 12:53:20 +00:00
# endif
2017-09-08 08:02:43 +00:00
while ( ! IsListEmpty ( & dev - > trim_list ) ) {
space * s = CONTAINING_RECORD ( RemoveHeadList ( & dev - > trim_list ) , space , list_entry ) ;
ExFreePool ( s ) ;
}
dev - > num_trim_entries = 0 ;
2019-09-01 12:53:20 +00:00
# ifndef DEBUG_TRIM_EMULATION
2017-09-08 08:02:43 +00:00
num + + ;
2019-09-01 12:53:20 +00:00
# endif
2017-09-08 08:02:43 +00:00
}
le = le - > Flink ;
}
2019-09-01 12:53:20 +00:00
# ifndef DEBUG_TRIM_EMULATION
KeWaitForSingleObject ( & context . Event , Executive , KernelMode , false , NULL ) ;
2017-09-08 08:02:43 +00:00
for ( num = 0 ; num < total_num ; num + + ) {
if ( context . stripes [ num ] . dmdsa )
ExFreePool ( context . stripes [ num ] . dmdsa ) ;
2019-11-12 18:32:46 +00:00
if ( context . stripes [ num ] . Irp )
IoFreeIrp ( context . stripes [ num ] . Irp ) ;
2017-09-08 08:02:43 +00:00
}
ExFreePool ( context . stripes ) ;
2019-09-01 12:53:20 +00:00
# endif
2016-10-29 17:05:10 +00:00
}
}
2019-09-01 12:53:20 +00:00
static bool trees_consistent ( device_extension * Vcb ) {
2016-10-29 17:05:10 +00:00
ULONG maxsize = Vcb - > superblock . node_size - sizeof ( tree_header ) ;
LIST_ENTRY * le ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = Vcb - > trees . Flink ;
while ( le ! = & Vcb - > trees ) {
tree * t = CONTAINING_RECORD ( le , tree , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( t - > write ) {
if ( t - > header . num_items = = 0 & & t - > parent ) {
# ifdef DEBUG_WRITE_LOOPS
ERR ( " empty tree found, looping again \n " ) ;
# endif
2019-09-01 12:53:20 +00:00
return false ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( t - > size > maxsize ) {
# ifdef DEBUG_WRITE_LOOPS
ERR ( " overlarge tree found (%u > %u), looping again \n " , t - > size , maxsize ) ;
# endif
2019-09-01 12:53:20 +00:00
return false ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! t - > has_new_address ) {
# ifdef DEBUG_WRITE_LOOPS
ERR ( " tree found without new address, looping again \n " ) ;
# endif
2019-09-01 12:53:20 +00:00
return false ;
2016-10-29 17:05:10 +00:00
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = le - > Flink ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
return true ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
static NTSTATUS add_parents ( device_extension * Vcb , PIRP Irp ) {
ULONG level ;
2016-10-29 17:05:10 +00:00
LIST_ENTRY * le ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
for ( level = 0 ; level < = 255 ; level + + ) {
2019-09-01 12:53:20 +00:00
bool nothing_found = true ;
2017-09-08 08:02:43 +00:00
2020-04-23 02:38:57 +00:00
TRACE ( " level = %lu \n " , level ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = Vcb - > trees . Flink ;
while ( le ! = & Vcb - > trees ) {
tree * t = CONTAINING_RECORD ( le , tree , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( t - > write & & t - > header . level = = level ) {
2019-09-01 12:53:20 +00:00
TRACE ( " tree %p: root = %I64x, level = %x, parent = %p \n " , t , t - > header . tree_id , t - > header . level , t - > parent ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
nothing_found = false ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( t - > parent ) {
if ( ! t - > parent - > write )
TRACE ( " adding tree %p (level %x) \n " , t - > parent , t - > header . level ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
t - > parent - > write = true ;
2016-10-29 17:05:10 +00:00
} else if ( t - > root ! = Vcb - > root_root & & t - > root ! = Vcb - > chunk_root ) {
KEY searchkey ;
traverse_ptr tp ;
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
searchkey . obj_id = t - > root - > id ;
searchkey . obj_type = TYPE_ROOT_ITEM ;
searchkey . offset = 0xffffffffffffffff ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > root_root , & tp , & searchkey , false , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - find_item returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( tp . item - > key . obj_id ! = searchkey . obj_id | | tp . item - > key . obj_type ! = searchkey . obj_type ) {
2019-09-01 12:53:20 +00:00
ERR ( " could not find ROOT_ITEM for tree %I64x \n " , searchkey . obj_id ) ;
2016-10-29 17:05:10 +00:00
return STATUS_INTERNAL_ERROR ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( tp . item - > size < sizeof ( ROOT_ITEM ) ) { // if not full length, delete and create new entry
ROOT_ITEM * ri = ExAllocatePoolWithTag ( PagedPool , sizeof ( ROOT_ITEM ) , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! ri ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
RtlCopyMemory ( ri , & t - > root - > root_item , sizeof ( ROOT_ITEM ) ) ;
2017-09-08 08:02:43 +00:00
Status = delete_tree_item ( Vcb , & tp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( ri ) ;
return Status ;
}
Status = insert_tree_item ( Vcb , Vcb - > root_root , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , ri , sizeof ( ROOT_ITEM ) , NULL , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( ri ) ;
return Status ;
2016-10-29 17:05:10 +00:00
}
}
2019-06-11 10:35:19 +00:00
tree * t2 = tp . tree ;
while ( t2 ) {
2019-09-01 12:53:20 +00:00
t2 - > write = true ;
2019-06-11 10:35:19 +00:00
t2 = t2 - > parent ;
}
2016-10-29 17:05:10 +00:00
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = le - > Flink ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( nothing_found )
break ;
}
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
static void add_parents_to_cache ( tree * t ) {
2016-10-29 17:05:10 +00:00
while ( t - > parent ) {
t = t - > parent ;
2019-09-01 12:53:20 +00:00
t - > write = true ;
2016-10-29 17:05:10 +00:00
}
}
2019-09-01 12:53:20 +00:00
static bool insert_tree_extent_skinny ( device_extension * Vcb , uint8_t level , uint64_t root_id , chunk * c , uint64_t address , PIRP Irp , LIST_ENTRY * rollback ) {
2017-09-08 08:02:43 +00:00
NTSTATUS Status ;
2016-10-29 17:05:10 +00:00
EXTENT_ITEM_SKINNY_METADATA * eism ;
traverse_ptr insert_tp ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
eism = ExAllocatePoolWithTag ( PagedPool , sizeof ( EXTENT_ITEM_SKINNY_METADATA ) , ALLOC_TAG ) ;
if ( ! eism ) {
ERR ( " out of memory \n " ) ;
2019-09-01 12:53:20 +00:00
return false ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
eism - > ei . refcount = 1 ;
eism - > ei . generation = Vcb - > superblock . generation ;
eism - > ei . flags = EXTENT_ITEM_TREE_BLOCK ;
eism - > type = TYPE_TREE_BLOCK_REF ;
eism - > tbr . offset = root_id ;
2017-09-08 08:02:43 +00:00
Status = insert_tree_item ( Vcb , Vcb - > extent_root , address , TYPE_METADATA_ITEM , level , eism , sizeof ( EXTENT_ITEM_SKINNY_METADATA ) , & insert_tp , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
ExFreePool ( eism ) ;
2019-09-01 12:53:20 +00:00
return false ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2018-12-16 11:03:16 +00:00
acquire_chunk_lock ( c , Vcb ) ;
2017-09-08 08:02:43 +00:00
2022-04-28 19:31:44 +00:00
space_list_subtract ( c , address , Vcb - > superblock . node_size , rollback ) ;
2016-10-29 17:05:10 +00:00
2018-12-16 11:03:16 +00:00
release_chunk_lock ( c , Vcb ) ;
2017-09-08 08:02:43 +00:00
add_parents_to_cache ( insert_tp . tree ) ;
2019-09-01 12:53:20 +00:00
return true ;
2016-10-29 17:05:10 +00:00
}
2019-09-01 12:53:20 +00:00
bool find_metadata_address_in_chunk ( device_extension * Vcb , chunk * c , uint64_t * address ) {
2017-01-01 17:12:12 +00:00
LIST_ENTRY * le ;
space * s ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
TRACE ( " (%p, %I64x, %p) \n " , Vcb , c - > offset , address ) ;
2017-09-08 08:02:43 +00:00
if ( Vcb - > superblock . node_size > c - > chunk_item - > size - c - > used )
2019-09-01 12:53:20 +00:00
return false ;
2017-09-08 08:02:43 +00:00
if ( ! c - > cache_loaded ) {
NTSTATUS Status = load_cache_chunk ( Vcb , c , NULL ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " load_cache_chunk returned %08lx \n " , Status ) ;
2019-09-01 12:53:20 +00:00
return false ;
2017-09-08 08:02:43 +00:00
}
}
2017-01-01 17:12:12 +00:00
if ( IsListEmpty ( & c - > space_size ) )
2019-09-01 12:53:20 +00:00
return false ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! c - > last_alloc_set ) {
s = CONTAINING_RECORD ( c - > space . Blink , space , list_entry ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
c - > last_alloc = s - > address ;
2019-09-01 12:53:20 +00:00
c - > last_alloc_set = true ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( s - > size > = Vcb - > superblock . node_size ) {
* address = s - > address ;
c - > last_alloc + = Vcb - > superblock . node_size ;
2019-09-01 12:53:20 +00:00
return true ;
2017-01-01 17:12:12 +00:00
}
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le = c - > space . Flink ;
while ( le ! = & c - > space ) {
s = CONTAINING_RECORD ( le , space , list_entry ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( s - > address < = c - > last_alloc & & s - > address + s - > size > = c - > last_alloc + Vcb - > superblock . node_size ) {
* address = c - > last_alloc ;
c - > last_alloc + = Vcb - > superblock . node_size ;
2019-09-01 12:53:20 +00:00
return true ;
2017-01-01 17:12:12 +00:00
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le = le - > Flink ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le = c - > space_size . Flink ;
while ( le ! = & c - > space_size ) {
s = CONTAINING_RECORD ( le , space , list_entry_size ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( s - > size = = Vcb - > superblock . node_size ) {
* address = s - > address ;
c - > last_alloc = s - > address + Vcb - > superblock . node_size ;
2019-09-01 12:53:20 +00:00
return true ;
2017-01-01 17:12:12 +00:00
} else if ( s - > size < Vcb - > superblock . node_size ) {
if ( le = = c - > space_size . Flink )
2019-09-01 12:53:20 +00:00
return false ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
s = CONTAINING_RECORD ( le - > Blink , space , list_entry_size ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
* address = s - > address ;
c - > last_alloc = s - > address + Vcb - > superblock . node_size ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
return true ;
2017-01-01 17:12:12 +00:00
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le = le - > Flink ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
s = CONTAINING_RECORD ( c - > space_size . Blink , space , list_entry_size ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( s - > size > Vcb - > superblock . node_size ) {
* address = s - > address ;
c - > last_alloc = s - > address + Vcb - > superblock . node_size ;
2019-09-01 12:53:20 +00:00
return true ;
2017-01-01 17:12:12 +00:00
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
return false ;
2017-01-01 17:12:12 +00:00
}
2019-09-01 12:53:20 +00:00
static bool insert_tree_extent ( device_extension * Vcb , uint8_t level , uint64_t root_id , chunk * c , uint64_t * new_address , PIRP Irp , LIST_ENTRY * rollback ) {
2017-09-08 08:02:43 +00:00
NTSTATUS Status ;
2019-09-01 12:53:20 +00:00
uint64_t address ;
2016-10-29 17:05:10 +00:00
EXTENT_ITEM_TREE2 * eit2 ;
traverse_ptr insert_tp ;
2017-09-08 08:02:43 +00:00
2020-04-23 02:38:57 +00:00
TRACE ( " (%p, %x, %I64x, %p, %p, %p, %p) \n " , Vcb , level , root_id , c , new_address , Irp , rollback ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! find_metadata_address_in_chunk ( Vcb , c , & address ) )
2019-09-01 12:53:20 +00:00
return false ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( Vcb - > superblock . incompat_flags & BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA ) {
2019-09-01 12:53:20 +00:00
bool b = insert_tree_extent_skinny ( Vcb , level , root_id , c , address , Irp , rollback ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( b )
* new_address = address ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
return b ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
eit2 = ExAllocatePoolWithTag ( PagedPool , sizeof ( EXTENT_ITEM_TREE2 ) , ALLOC_TAG ) ;
if ( ! eit2 ) {
ERR ( " out of memory \n " ) ;
2019-09-01 12:53:20 +00:00
return false ;
2016-10-29 17:05:10 +00:00
}
eit2 - > eit . extent_item . refcount = 1 ;
eit2 - > eit . extent_item . generation = Vcb - > superblock . generation ;
eit2 - > eit . extent_item . flags = EXTENT_ITEM_TREE_BLOCK ;
eit2 - > eit . level = level ;
eit2 - > type = TYPE_TREE_BLOCK_REF ;
eit2 - > tbr . offset = root_id ;
2017-09-08 08:02:43 +00:00
Status = insert_tree_item ( Vcb , Vcb - > extent_root , address , TYPE_EXTENT_ITEM , Vcb - > superblock . node_size , eit2 , sizeof ( EXTENT_ITEM_TREE2 ) , & insert_tp , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
ExFreePool ( eit2 ) ;
2019-09-01 12:53:20 +00:00
return false ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2018-12-16 11:03:16 +00:00
acquire_chunk_lock ( c , Vcb ) ;
2017-09-08 08:02:43 +00:00
2022-04-28 19:31:44 +00:00
space_list_subtract ( c , address , Vcb - > superblock . node_size , rollback ) ;
2017-09-08 08:02:43 +00:00
2018-12-16 11:03:16 +00:00
release_chunk_lock ( c , Vcb ) ;
2016-10-29 17:05:10 +00:00
2017-09-08 08:02:43 +00:00
add_parents_to_cache ( insert_tp . tree ) ;
2016-10-29 17:05:10 +00:00
* new_address = address ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
return true ;
2016-10-29 17:05:10 +00:00
}
NTSTATUS get_tree_new_address ( device_extension * Vcb , tree * t , PIRP Irp , LIST_ENTRY * rollback ) {
2017-09-08 08:02:43 +00:00
NTSTATUS Status ;
2016-10-29 17:05:10 +00:00
chunk * origchunk = NULL , * c ;
LIST_ENTRY * le ;
2019-09-01 12:53:20 +00:00
uint64_t flags , addr ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( t - > root - > id = = BTRFS_ROOT_CHUNK )
flags = Vcb - > system_flags ;
else
flags = Vcb - > metadata_flags ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( t - > has_address ) {
origchunk = get_chunk_from_address ( Vcb , t - > header . address ) ;
2017-09-08 08:02:43 +00:00
if ( origchunk & & ! origchunk - > readonly & & ! origchunk - > reloc & & origchunk - > chunk_item - > type = = flags & &
2017-01-01 17:12:12 +00:00
insert_tree_extent ( Vcb , t - > header . level , t - > root - > id , origchunk , & addr , Irp , rollback ) ) {
2016-10-29 17:05:10 +00:00
t - > new_address = addr ;
2019-09-01 12:53:20 +00:00
t - > has_new_address = true ;
2016-10-29 17:05:10 +00:00
return STATUS_SUCCESS ;
}
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( & Vcb - > chunk_lock , true ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = Vcb - > chunks . Flink ;
while ( le ! = & Vcb - > chunks ) {
c = CONTAINING_RECORD ( le , chunk , list_entry ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! c - > readonly & & ! c - > reloc ) {
2018-12-16 11:03:16 +00:00
acquire_chunk_lock ( c , Vcb ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( c ! = origchunk & & c - > chunk_item - > type = = flags & & ( c - > chunk_item - > size - c - > used ) > = Vcb - > superblock . node_size ) {
if ( insert_tree_extent ( Vcb , t - > header . level , t - > root - > id , c , & addr , Irp , rollback ) ) {
2018-12-16 11:03:16 +00:00
release_chunk_lock ( c , Vcb ) ;
2016-10-29 17:05:10 +00:00
ExReleaseResourceLite ( & Vcb - > chunk_lock ) ;
t - > new_address = addr ;
2019-09-01 12:53:20 +00:00
t - > has_new_address = true ;
2016-10-29 17:05:10 +00:00
return STATUS_SUCCESS ;
}
}
2017-09-08 08:02:43 +00:00
2018-12-16 11:03:16 +00:00
release_chunk_lock ( c , Vcb ) ;
2016-10-29 17:05:10 +00:00
}
le = le - > Flink ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
// allocate new chunk if necessary
2019-09-01 12:53:20 +00:00
Status = alloc_chunk ( Vcb , flags , & c , false ) ;
2016-10-29 17:05:10 +00:00
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " alloc_chunk returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
ExReleaseResourceLite ( & Vcb - > chunk_lock ) ;
return Status ;
}
2016-10-29 17:05:10 +00:00
2018-12-16 11:03:16 +00:00
acquire_chunk_lock ( c , Vcb ) ;
2017-09-08 08:02:43 +00:00
if ( ( c - > chunk_item - > size - c - > used ) > = Vcb - > superblock . node_size ) {
if ( insert_tree_extent ( Vcb , t - > header . level , t - > root - > id , c , & addr , Irp , rollback ) ) {
2018-12-16 11:03:16 +00:00
release_chunk_lock ( c , Vcb ) ;
2017-09-08 08:02:43 +00:00
ExReleaseResourceLite ( & Vcb - > chunk_lock ) ;
t - > new_address = addr ;
2019-09-01 12:53:20 +00:00
t - > has_new_address = true ;
2017-09-08 08:02:43 +00:00
return STATUS_SUCCESS ;
}
}
2018-12-16 11:03:16 +00:00
release_chunk_lock ( c , Vcb ) ;
2017-09-08 08:02:43 +00:00
ExReleaseResourceLite ( & Vcb - > chunk_lock ) ;
ERR ( " couldn't find any metadata chunks with %x bytes free \n " , Vcb - > superblock . node_size ) ;
return STATUS_DISK_FULL ;
}
2019-09-01 12:53:20 +00:00
static NTSTATUS reduce_tree_extent ( device_extension * Vcb , uint64_t address , tree * t , uint64_t parent_root , uint8_t level , PIRP Irp , LIST_ENTRY * rollback ) {
2017-09-08 08:02:43 +00:00
NTSTATUS Status ;
2019-09-01 12:53:20 +00:00
uint64_t rc , root ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
TRACE ( " (%p, %I64x, %p) \n " , Vcb , address , t ) ;
2016-10-29 17:05:10 +00:00
rc = get_extent_refcount ( Vcb , address , Vcb - > superblock . node_size , Irp ) ;
if ( rc = = 0 ) {
2019-09-01 12:53:20 +00:00
ERR ( " error - refcount for extent %I64x was 0 \n " , address ) ;
2016-10-29 17:05:10 +00:00
return STATUS_INTERNAL_ERROR ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! t | | t - > parent )
root = parent_root ;
2016-10-29 17:05:10 +00:00
else
root = t - > header . tree_id ;
2017-09-08 08:02:43 +00:00
Status = decrease_extent_refcount_tree ( Vcb , address , Vcb - > superblock . node_size , root , level , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " decrease_extent_refcount_tree returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
if ( rc = = 1 ) {
chunk * c = get_chunk_from_address ( Vcb , address ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( c ) {
2018-12-16 11:03:16 +00:00
acquire_chunk_lock ( c , Vcb ) ;
2017-09-08 08:02:43 +00:00
if ( ! c - > cache_loaded ) {
Status = load_cache_chunk ( Vcb , c , NULL ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " load_cache_chunk returned %08lx \n " , Status ) ;
2018-12-16 11:03:16 +00:00
release_chunk_lock ( c , Vcb ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
}
c - > used - = Vcb - > superblock . node_size ;
space_list_add ( c , address , Vcb - > superblock . node_size , rollback ) ;
2018-12-16 11:03:16 +00:00
release_chunk_lock ( c , Vcb ) ;
2016-10-29 17:05:10 +00:00
} else
2019-09-01 12:53:20 +00:00
ERR ( " could not find chunk for address %I64x \n " , address ) ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
return STATUS_SUCCESS ;
}
2019-09-01 12:53:20 +00:00
static NTSTATUS add_changed_extent_ref_edr ( changed_extent * ce , EXTENT_DATA_REF * edr , bool old ) {
2016-10-29 17:05:10 +00:00
LIST_ENTRY * le2 , * list ;
changed_extent_ref * cer ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
list = old ? & ce - > old_refs : & ce - > refs ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le2 = list - > Flink ;
while ( le2 ! = list ) {
cer = CONTAINING_RECORD ( le2 , changed_extent_ref , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( cer - > type = = TYPE_EXTENT_DATA_REF & & cer - > edr . root = = edr - > root & & cer - > edr . objid = = edr - > objid & & cer - > edr . offset = = edr - > offset ) {
cer - > edr . count + = edr - > count ;
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le2 = le2 - > Flink ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
cer = ExAllocatePoolWithTag ( PagedPool , sizeof ( changed_extent_ref ) , ALLOC_TAG ) ;
if ( ! cer ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
cer - > type = TYPE_EXTENT_DATA_REF ;
RtlCopyMemory ( & cer - > edr , edr , sizeof ( EXTENT_DATA_REF ) ) ;
InsertTailList ( list , & cer - > list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
end :
if ( old )
ce - > old_count + = edr - > count ;
else
ce - > count + = edr - > count ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
return STATUS_SUCCESS ;
}
2019-09-01 12:53:20 +00:00
static NTSTATUS add_changed_extent_ref_sdr ( changed_extent * ce , SHARED_DATA_REF * sdr , bool old ) {
2016-10-29 17:05:10 +00:00
LIST_ENTRY * le2 , * list ;
changed_extent_ref * cer ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
list = old ? & ce - > old_refs : & ce - > refs ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le2 = list - > Flink ;
while ( le2 ! = list ) {
cer = CONTAINING_RECORD ( le2 , changed_extent_ref , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( cer - > type = = TYPE_SHARED_DATA_REF & & cer - > sdr . offset = = sdr - > offset ) {
cer - > sdr . count + = sdr - > count ;
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le2 = le2 - > Flink ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
cer = ExAllocatePoolWithTag ( PagedPool , sizeof ( changed_extent_ref ) , ALLOC_TAG ) ;
if ( ! cer ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
cer - > type = TYPE_SHARED_DATA_REF ;
RtlCopyMemory ( & cer - > sdr , sdr , sizeof ( SHARED_DATA_REF ) ) ;
InsertTailList ( list , & cer - > list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
end :
if ( old )
ce - > old_count + = sdr - > count ;
else
ce - > count + = sdr - > count ;
return STATUS_SUCCESS ;
}
2019-09-01 12:53:20 +00:00
static bool shared_tree_is_unique ( device_extension * Vcb , tree * t , PIRP Irp , LIST_ENTRY * rollback ) {
2016-10-29 17:05:10 +00:00
KEY searchkey ;
traverse_ptr tp ;
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! t - > updated_extents & & t - > has_address ) {
Status = update_tree_extents ( Vcb , t , Irp , rollback ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " update_tree_extents returned %08lx \n " , Status ) ;
2019-09-01 12:53:20 +00:00
return false ;
2017-01-01 17:12:12 +00:00
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
searchkey . obj_id = t - > header . address ;
searchkey . obj_type = Vcb - > superblock . incompat_flags & BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA ? TYPE_METADATA_ITEM : TYPE_EXTENT_ITEM ;
searchkey . offset = 0xffffffffffffffff ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > extent_root , & tp , & searchkey , false , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - find_item returned %08lx \n " , Status ) ;
2019-09-01 12:53:20 +00:00
return false ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( tp . item - > key . obj_id = = t - > header . address & & ( tp . item - > key . obj_type = = TYPE_METADATA_ITEM | | tp . item - > key . obj_type = = TYPE_EXTENT_ITEM ) )
2019-09-01 12:53:20 +00:00
return false ;
2016-10-29 17:05:10 +00:00
else
2019-09-01 12:53:20 +00:00
return true ;
2016-10-29 17:05:10 +00:00
}
static NTSTATUS update_tree_extents ( device_extension * Vcb , tree * t , PIRP Irp , LIST_ENTRY * rollback ) {
NTSTATUS Status ;
2019-09-01 12:53:20 +00:00
uint64_t rc = get_extent_refcount ( Vcb , t - > header . address , Vcb - > superblock . node_size , Irp ) ;
uint64_t flags = get_extent_flags ( Vcb , t - > header . address , Irp ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( rc = = 0 ) {
2019-09-01 12:53:20 +00:00
ERR ( " refcount for extent %I64x was 0 \n " , t - > header . address ) ;
2016-10-29 17:05:10 +00:00
return STATUS_INTERNAL_ERROR ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( flags & EXTENT_ITEM_SHARED_BACKREFS | | t - > header . flags & HEADER_FLAG_SHARED_BACKREF | | ! ( t - > header . flags & HEADER_FLAG_MIXED_BACKREF ) ) {
TREE_BLOCK_REF tbr ;
2019-09-01 12:53:20 +00:00
bool unique = rc > 1 ? false : ( t - > parent ? shared_tree_is_unique ( Vcb , t - > parent , Irp , rollback ) : false ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( t - > header . level = = 0 ) {
LIST_ENTRY * le ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = t - > itemlist . Flink ;
while ( le ! = & t - > itemlist ) {
tree_data * td = CONTAINING_RECORD ( le , tree_data , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! td - > inserted & & td - > key . obj_type = = TYPE_EXTENT_DATA & & td - > size > = sizeof ( EXTENT_DATA ) - 1 + sizeof ( EXTENT_DATA2 ) ) {
EXTENT_DATA * ed = ( EXTENT_DATA * ) td - > data ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ed - > type = = EXTENT_TYPE_REGULAR | | ed - > type = = EXTENT_TYPE_PREALLOC ) {
EXTENT_DATA2 * ed2 = ( EXTENT_DATA2 * ) ed - > data ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ed2 - > size > 0 ) {
EXTENT_DATA_REF edr ;
changed_extent * ce = NULL ;
chunk * c = get_chunk_from_address ( Vcb , ed2 - > address ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( c ) {
LIST_ENTRY * le2 ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le2 = c - > changed_extents . Flink ;
while ( le2 ! = & c - > changed_extents ) {
changed_extent * ce2 = CONTAINING_RECORD ( le2 , changed_extent , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ce2 - > address = = ed2 - > address ) {
ce = ce2 ;
break ;
}
le2 = le2 - > Flink ;
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
edr . root = t - > root - > id ;
edr . objid = td - > key . obj_id ;
edr . offset = td - > key . offset - ed2 - > offset ;
edr . count = 1 ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ce ) {
2019-09-01 12:53:20 +00:00
Status = add_changed_extent_ref_edr ( ce , & edr , true ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " add_changed_extent_ref_edr returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = add_changed_extent_ref_edr ( ce , & edr , false ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " add_changed_extent_ref_edr returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
}
2017-09-08 08:02:43 +00:00
Status = increase_extent_refcount ( Vcb , ed2 - > address , ed2 - > size , TYPE_EXTENT_DATA_REF , & edr , NULL , 0 , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " increase_extent_refcount returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ( flags & EXTENT_ITEM_SHARED_BACKREFS & & unique ) | | ! ( t - > header . flags & HEADER_FLAG_MIXED_BACKREF ) ) {
2019-09-01 12:53:20 +00:00
uint64_t sdrrc = find_extent_shared_data_refcount ( Vcb , ed2 - > address , t - > header . address , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( sdrrc > 0 ) {
SHARED_DATA_REF sdr ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
sdr . offset = t - > header . address ;
2017-01-01 17:12:12 +00:00
sdr . count = 1 ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
Status = decrease_extent_refcount ( Vcb , ed2 - > address , ed2 - > size , TYPE_SHARED_DATA_REF , & sdr , NULL , 0 ,
2019-09-01 12:53:20 +00:00
t - > header . address , ce ? ce - > superseded : false , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " decrease_extent_refcount returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ce ) {
2017-01-01 17:12:12 +00:00
LIST_ENTRY * le2 ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le2 = ce - > refs . Flink ;
while ( le2 ! = & ce - > refs ) {
changed_extent_ref * cer = CONTAINING_RECORD ( le2 , changed_extent_ref , list_entry ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( cer - > type = = TYPE_SHARED_DATA_REF & & cer - > sdr . offset = = sdr . offset ) {
ce - > count - - ;
cer - > sdr . count - - ;
break ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le2 = le2 - > Flink ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le2 = ce - > old_refs . Flink ;
while ( le2 ! = & ce - > old_refs ) {
changed_extent_ref * cer = CONTAINING_RECORD ( le2 , changed_extent_ref , list_entry ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( cer - > type = = TYPE_SHARED_DATA_REF & & cer - > sdr . offset = = sdr . offset ) {
ce - > old_count - - ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( cer - > sdr . count > 1 )
cer - > sdr . count - - ;
else {
RemoveEntryList ( & cer - > list_entry ) ;
ExFreePool ( cer ) ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
break ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le2 = le2 - > Flink ;
}
2016-10-29 17:05:10 +00:00
}
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
// FIXME - clear shared flag if unique?
}
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = le - > Flink ;
}
} else {
LIST_ENTRY * le ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = t - > itemlist . Flink ;
while ( le ! = & t - > itemlist ) {
tree_data * td = CONTAINING_RECORD ( le , tree_data , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! td - > inserted ) {
tbr . offset = t - > root - > id ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
Status = increase_extent_refcount ( Vcb , td - > treeholder . address , Vcb - > superblock . node_size , TYPE_TREE_BLOCK_REF ,
2017-09-08 08:02:43 +00:00
& tbr , & td - > key , t - > header . level - 1 , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " increase_extent_refcount returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( unique | | ! ( t - > header . flags & HEADER_FLAG_MIXED_BACKREF ) ) {
2019-09-01 12:53:20 +00:00
uint64_t sbrrc = find_extent_shared_tree_refcount ( Vcb , td - > treeholder . address , t - > header . address , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( sbrrc > 0 ) {
SHARED_BLOCK_REF sbr ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
sbr . offset = t - > header . address ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
Status = decrease_extent_refcount ( Vcb , td - > treeholder . address , Vcb - > superblock . node_size , TYPE_SHARED_BLOCK_REF , & sbr , NULL , 0 ,
2019-09-01 12:53:20 +00:00
t - > header . address , false , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " decrease_extent_refcount returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
// FIXME - clear shared flag if unique?
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = le - > Flink ;
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( unique ) {
2019-09-01 12:53:20 +00:00
uint64_t sbrrc = find_extent_shared_tree_refcount ( Vcb , t - > header . address , t - > parent - > header . address , Irp ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( sbrrc = = 1 ) {
SHARED_BLOCK_REF sbr ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
sbr . offset = t - > parent - > header . address ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
Status = decrease_extent_refcount ( Vcb , t - > header . address , Vcb - > superblock . node_size , TYPE_SHARED_BLOCK_REF , & sbr , NULL , 0 ,
2019-09-01 12:53:20 +00:00
t - > parent - > header . address , false , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " decrease_extent_refcount returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( t - > parent )
tbr . offset = t - > parent - > header . tree_id ;
else
tbr . offset = t - > header . tree_id ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
Status = increase_extent_refcount ( Vcb , t - > header . address , Vcb - > superblock . node_size , TYPE_TREE_BLOCK_REF , & tbr ,
2017-09-08 08:02:43 +00:00
t - > parent ? & t - > paritem - > key : NULL , t - > header . level , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " increase_extent_refcount returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
// FIXME - clear shared flag if unique?
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
t - > header . flags & = ~ HEADER_FLAG_SHARED_BACKREF ;
}
2017-09-08 08:02:43 +00:00
if ( rc > 1 | | t - > header . tree_id = = t - > root - > id ) {
Status = reduce_tree_extent ( Vcb , t - > header . address , t , t - > parent ? t - > parent - > header . tree_id : t - > header . tree_id , t - > header . level , Irp , rollback ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " reduce_tree_extent returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
t - > has_address = false ;
2017-09-08 08:02:43 +00:00
if ( ( rc > 1 | | t - > header . tree_id ! = t - > root - > id ) & & ! ( flags & EXTENT_ITEM_SHARED_BACKREFS ) ) {
2016-10-29 17:05:10 +00:00
if ( t - > header . tree_id = = t - > root - > id ) {
flags | = EXTENT_ITEM_SHARED_BACKREFS ;
update_extent_flags ( Vcb , t - > header . address , flags , Irp ) ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( t - > header . level > 0 ) {
LIST_ENTRY * le ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = t - > itemlist . Flink ;
while ( le ! = & t - > itemlist ) {
tree_data * td = CONTAINING_RECORD ( le , tree_data , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! td - > inserted ) {
if ( t - > header . tree_id = = t - > root - > id ) {
SHARED_BLOCK_REF sbr ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
sbr . offset = t - > header . address ;
2017-09-08 08:02:43 +00:00
Status = increase_extent_refcount ( Vcb , td - > treeholder . address , Vcb - > superblock . node_size , TYPE_SHARED_BLOCK_REF , & sbr , & td - > key , t - > header . level - 1 , Irp ) ;
2016-10-29 17:05:10 +00:00
} else {
TREE_BLOCK_REF tbr ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
tbr . offset = t - > root - > id ;
2017-09-08 08:02:43 +00:00
Status = increase_extent_refcount ( Vcb , td - > treeholder . address , Vcb - > superblock . node_size , TYPE_TREE_BLOCK_REF , & tbr , & td - > key , t - > header . level - 1 , Irp ) ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " increase_extent_refcount returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = le - > Flink ;
}
} else {
LIST_ENTRY * le ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = t - > itemlist . Flink ;
while ( le ! = & t - > itemlist ) {
tree_data * td = CONTAINING_RECORD ( le , tree_data , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! td - > inserted & & td - > key . obj_type = = TYPE_EXTENT_DATA & & td - > size > = sizeof ( EXTENT_DATA ) - 1 + sizeof ( EXTENT_DATA2 ) ) {
EXTENT_DATA * ed = ( EXTENT_DATA * ) td - > data ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ed - > type = = EXTENT_TYPE_REGULAR | | ed - > type = = EXTENT_TYPE_PREALLOC ) {
EXTENT_DATA2 * ed2 = ( EXTENT_DATA2 * ) ed - > data ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ed2 - > size > 0 ) {
changed_extent * ce = NULL ;
chunk * c = get_chunk_from_address ( Vcb , ed2 - > address ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( c ) {
LIST_ENTRY * le2 ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le2 = c - > changed_extents . Flink ;
while ( le2 ! = & c - > changed_extents ) {
changed_extent * ce2 = CONTAINING_RECORD ( le2 , changed_extent , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ce2 - > address = = ed2 - > address ) {
ce = ce2 ;
break ;
}
le2 = le2 - > Flink ;
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( t - > header . tree_id = = t - > root - > id ) {
SHARED_DATA_REF sdr ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
sdr . offset = t - > header . address ;
sdr . count = 1 ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ce ) {
2019-09-01 12:53:20 +00:00
Status = add_changed_extent_ref_sdr ( ce , & sdr , true ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " add_changed_extent_ref_edr returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = add_changed_extent_ref_sdr ( ce , & sdr , false ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " add_changed_extent_ref_edr returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
}
2017-09-08 08:02:43 +00:00
Status = increase_extent_refcount ( Vcb , ed2 - > address , ed2 - > size , TYPE_SHARED_DATA_REF , & sdr , NULL , 0 , Irp ) ;
2016-10-29 17:05:10 +00:00
} else {
EXTENT_DATA_REF edr ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
edr . root = t - > root - > id ;
edr . objid = td - > key . obj_id ;
edr . offset = td - > key . offset - ed2 - > offset ;
edr . count = 1 ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ce ) {
2019-09-01 12:53:20 +00:00
Status = add_changed_extent_ref_edr ( ce , & edr , true ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " add_changed_extent_ref_edr returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = add_changed_extent_ref_edr ( ce , & edr , false ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " add_changed_extent_ref_edr returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
}
2017-09-08 08:02:43 +00:00
Status = increase_extent_refcount ( Vcb , ed2 - > address , ed2 - > size , TYPE_EXTENT_DATA_REF , & edr , NULL , 0 , Irp ) ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " increase_extent_refcount returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
}
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = le - > Flink ;
}
}
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
t - > updated_extents = true ;
2016-10-29 17:05:10 +00:00
t - > header . tree_id = t - > root - > id ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
return STATUS_SUCCESS ;
}
static NTSTATUS allocate_tree_extents ( device_extension * Vcb , PIRP Irp , LIST_ENTRY * rollback ) {
LIST_ENTRY * le ;
NTSTATUS Status ;
2019-09-01 12:53:20 +00:00
bool changed = false ;
uint8_t max_level = 0 , level ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
TRACE ( " (%p) \n " , Vcb ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = Vcb - > trees . Flink ;
while ( le ! = & Vcb - > trees ) {
tree * t = CONTAINING_RECORD ( le , tree , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( t - > write & & ! t - > has_new_address ) {
chunk * c ;
2017-09-08 08:02:43 +00:00
if ( t - > has_address ) {
c = get_chunk_from_address ( Vcb , t - > header . address ) ;
if ( c ) {
if ( ! c - > cache_loaded ) {
2018-12-16 11:03:16 +00:00
acquire_chunk_lock ( c , Vcb ) ;
2017-09-08 08:02:43 +00:00
if ( ! c - > cache_loaded ) {
Status = load_cache_chunk ( Vcb , c , NULL ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " load_cache_chunk returned %08lx \n " , Status ) ;
2018-12-16 11:03:16 +00:00
release_chunk_lock ( c , Vcb ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
}
2018-12-16 11:03:16 +00:00
release_chunk_lock ( c , Vcb ) ;
2017-09-08 08:02:43 +00:00
}
}
}
2016-10-29 17:05:10 +00:00
Status = get_tree_new_address ( Vcb , t , Irp , rollback ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " get_tree_new_address returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
TRACE ( " allocated extent %I64x \n " , t - > new_address ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
c = get_chunk_from_address ( Vcb , t - > new_address ) ;
2017-09-08 08:02:43 +00:00
if ( c )
c - > used + = Vcb - > superblock . node_size ;
else {
2019-09-01 12:53:20 +00:00
ERR ( " could not find chunk for address %I64x \n " , t - > new_address ) ;
2016-10-29 17:05:10 +00:00
return STATUS_INTERNAL_ERROR ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
changed = true ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( t - > header . level > max_level )
max_level = t - > header . level ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = le - > Flink ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! changed )
return STATUS_SUCCESS ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
level = max_level ;
do {
le = Vcb - > trees . Flink ;
while ( le ! = & Vcb - > trees ) {
tree * t = CONTAINING_RECORD ( le , tree , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( t - > write & & ! t - > updated_extents & & t - > has_address & & t - > header . level = = level ) {
Status = update_tree_extents ( Vcb , t , Irp , rollback ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " update_tree_extents returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = le - > Flink ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( level = = 0 )
break ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
level - - ;
2019-09-01 12:53:20 +00:00
} while ( true ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
return STATUS_SUCCESS ;
}
2019-09-01 12:53:20 +00:00
static NTSTATUS update_root_root ( device_extension * Vcb , bool no_cache , PIRP Irp , LIST_ENTRY * rollback ) {
2016-10-29 17:05:10 +00:00
LIST_ENTRY * le ;
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
TRACE ( " (%p) \n " , Vcb ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = Vcb - > trees . Flink ;
while ( le ! = & Vcb - > trees ) {
tree * t = CONTAINING_RECORD ( le , tree , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( t - > write & & ! t - > parent ) {
if ( t - > root ! = Vcb - > root_root & & t - > root ! = Vcb - > chunk_root ) {
KEY searchkey ;
traverse_ptr tp ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
searchkey . obj_id = t - > root - > id ;
searchkey . obj_type = TYPE_ROOT_ITEM ;
searchkey . offset = 0xffffffffffffffff ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > root_root , & tp , & searchkey , false , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - find_item returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( tp . item - > key . obj_id ! = searchkey . obj_id | | tp . item - > key . obj_type ! = searchkey . obj_type ) {
2019-09-01 12:53:20 +00:00
ERR ( " could not find ROOT_ITEM for tree %I64x \n " , searchkey . obj_id ) ;
2016-10-29 17:05:10 +00:00
return STATUS_INTERNAL_ERROR ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
TRACE ( " updating the address for root %I64x to %I64x \n " , searchkey . obj_id , t - > new_address ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
t - > root - > root_item . block_number = t - > new_address ;
t - > root - > root_item . root_level = t - > header . level ;
t - > root - > root_item . generation = Vcb - > superblock . generation ;
t - > root - > root_item . generation2 = Vcb - > superblock . generation ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
// item is guaranteed to be at least sizeof(ROOT_ITEM), due to add_parents
RtlCopyMemory ( tp . item - > data , & t - > root - > root_item , sizeof ( ROOT_ITEM ) ) ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
t - > root - > treeholder . address = t - > new_address ;
2017-09-08 08:02:43 +00:00
t - > root - > treeholder . generation = Vcb - > superblock . generation ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = le - > Flink ;
}
2017-09-08 08:02:43 +00:00
if ( ! no_cache & & ! ( Vcb - > superblock . compat_ro_flags & BTRFS_COMPAT_RO_FLAGS_FREE_SPACE_CACHE ) ) {
2019-09-01 12:53:20 +00:00
ExAcquireResourceSharedLite ( & Vcb - > chunk_lock , true ) ;
2017-09-08 08:02:43 +00:00
Status = update_chunk_caches ( Vcb , Irp , rollback ) ;
ExReleaseResourceLite ( & Vcb - > chunk_lock ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " update_chunk_caches returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
return STATUS_SUCCESS ;
}
2019-09-01 12:53:20 +00:00
NTSTATUS do_tree_writes ( device_extension * Vcb , LIST_ENTRY * tree_writes , bool no_free ) {
2017-01-01 17:12:12 +00:00
chunk * c ;
LIST_ENTRY * le ;
tree_write * tw ;
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
ULONG i , num_bits ;
2017-01-01 17:12:12 +00:00
write_data_context * wtc ;
2017-09-08 08:02:43 +00:00
ULONG bit_num = 0 ;
2019-09-01 12:53:20 +00:00
bool raid56 = false ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
// merge together runs
c = NULL ;
le = tree_writes - > Flink ;
while ( le ! = tree_writes ) {
tw = CONTAINING_RECORD ( le , tree_write , list_entry ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! c | | tw - > address < c - > offset | | tw - > address > = c - > offset + c - > chunk_item - > size )
c = get_chunk_from_address ( Vcb , tw - > address ) ;
else {
tree_write * tw2 = CONTAINING_RECORD ( le - > Blink , tree_write , list_entry ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( tw - > address = = tw2 - > address + tw2 - > length ) {
2019-09-01 12:53:20 +00:00
uint8_t * data = ExAllocatePoolWithTag ( NonPagedPool , tw2 - > length + tw - > length , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! data ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
RtlCopyMemory ( data , tw2 - > data , tw2 - > length ) ;
RtlCopyMemory ( & data [ tw2 - > length ] , tw - > data , tw - > length ) ;
2017-09-08 08:02:43 +00:00
2019-11-12 18:32:46 +00:00
if ( ! no_free | | tw2 - > allocated )
2017-09-08 08:02:43 +00:00
ExFreePool ( tw2 - > data ) ;
2017-01-01 17:12:12 +00:00
tw2 - > data = data ;
tw2 - > length + = tw - > length ;
2019-11-12 18:32:46 +00:00
tw2 - > allocated = true ;
2017-09-08 08:02:43 +00:00
2019-11-12 18:32:46 +00:00
if ( ! no_free | | tw - > allocated )
2017-09-08 08:02:43 +00:00
ExFreePool ( tw - > data ) ;
2017-01-01 17:12:12 +00:00
RemoveEntryList ( & tw - > list_entry ) ;
ExFreePool ( tw ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le = tw2 - > list_entry . Flink ;
continue ;
}
}
2017-09-08 08:02:43 +00:00
tw - > c = c ;
if ( c - > chunk_item - > type & ( BLOCK_FLAG_RAID5 | BLOCK_FLAG_RAID6 ) )
2019-09-01 12:53:20 +00:00
raid56 = true ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le = le - > Flink ;
}
2017-09-08 08:02:43 +00:00
num_bits = 0 ;
2017-01-01 17:12:12 +00:00
le = tree_writes - > Flink ;
while ( le ! = tree_writes ) {
tw = CONTAINING_RECORD ( le , tree_write , list_entry ) ;
2017-09-08 08:02:43 +00:00
num_bits + + ;
2017-01-01 17:12:12 +00:00
le = le - > Flink ;
}
2017-09-08 08:02:43 +00:00
wtc = ExAllocatePoolWithTag ( NonPagedPool , sizeof ( write_data_context ) * num_bits , ALLOC_TAG ) ;
if ( ! wtc ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-01-01 17:12:12 +00:00
le = tree_writes - > Flink ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
while ( le ! = tree_writes ) {
tw = CONTAINING_RECORD ( le , tree_write , list_entry ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
TRACE ( " address: %I64x, size: %x \n " , tw - > address , tw - > length ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
KeInitializeEvent ( & wtc [ bit_num ] . Event , NotificationEvent , false ) ;
2017-09-08 08:02:43 +00:00
InitializeListHead ( & wtc [ bit_num ] . stripes ) ;
2019-09-01 12:53:20 +00:00
wtc [ bit_num ] . need_wait = false ;
2017-09-08 08:02:43 +00:00
wtc [ bit_num ] . stripes_left = 0 ;
wtc [ bit_num ] . parity1 = wtc [ bit_num ] . parity2 = wtc [ bit_num ] . scratch = NULL ;
wtc [ bit_num ] . mdl = wtc [ bit_num ] . parity1_mdl = wtc [ bit_num ] . parity2_mdl = NULL ;
2019-09-01 12:53:20 +00:00
Status = write_data ( Vcb , tw - > address , tw - > data , tw - > length , & wtc [ bit_num ] , NULL , NULL , false , 0 , HighPagePriority ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " write_data returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
for ( i = 0 ; i < num_bits ; i + + ) {
free_write_data_stripes ( & wtc [ i ] ) ;
2017-01-01 17:12:12 +00:00
}
2017-09-08 08:02:43 +00:00
ExFreePool ( wtc ) ;
return Status ;
2017-01-01 17:12:12 +00:00
}
2017-09-08 08:02:43 +00:00
bit_num + + ;
2017-01-01 17:12:12 +00:00
le = le - > Flink ;
}
2017-09-08 08:02:43 +00:00
for ( i = 0 ; i < num_bits ; i + + ) {
if ( wtc [ i ] . stripes . Flink ! = & wtc [ i ] . stripes ) {
// launch writes and wait
le = wtc [ i ] . stripes . Flink ;
while ( le ! = & wtc [ i ] . stripes ) {
write_data_stripe * stripe = CONTAINING_RECORD ( le , write_data_stripe , list_entry ) ;
if ( stripe - > status ! = WriteDataStatus_Ignore ) {
2019-09-01 12:53:20 +00:00
wtc [ i ] . need_wait = true ;
2017-09-08 08:02:43 +00:00
IoCallDriver ( stripe - > device - > devobj , stripe - > Irp ) ;
}
le = le - > Flink ;
}
2017-01-01 17:12:12 +00:00
}
2017-09-08 08:02:43 +00:00
}
for ( i = 0 ; i < num_bits ; i + + ) {
if ( wtc [ i ] . need_wait )
2019-09-01 12:53:20 +00:00
KeWaitForSingleObject ( & wtc [ i ] . Event , Executive , KernelMode , false , NULL ) ;
2017-09-08 08:02:43 +00:00
}
for ( i = 0 ; i < num_bits ; i + + ) {
le = wtc [ i ] . stripes . Flink ;
while ( le ! = & wtc [ i ] . stripes ) {
2017-01-01 17:12:12 +00:00
write_data_stripe * stripe = CONTAINING_RECORD ( le , write_data_stripe , list_entry ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( stripe - > status ! = WriteDataStatus_Ignore & & ! NT_SUCCESS ( stripe - > iosb . Status ) ) {
Status = stripe - > iosb . Status ;
2017-09-08 08:02:43 +00:00
log_device_error ( Vcb , stripe - > device , BTRFS_DEV_STAT_WRITE_ERRORS ) ;
2017-01-01 17:12:12 +00:00
break ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le = le - > Flink ;
}
2017-09-08 08:02:43 +00:00
free_write_data_stripes ( & wtc [ i ] ) ;
2017-01-01 17:12:12 +00:00
}
2017-09-08 08:02:43 +00:00
ExFreePool ( wtc ) ;
if ( raid56 ) {
c = NULL ;
le = tree_writes - > Flink ;
while ( le ! = tree_writes ) {
tw = CONTAINING_RECORD ( le , tree_write , list_entry ) ;
if ( tw - > c ! = c ) {
c = tw - > c ;
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( & c - > partial_stripes_lock , true ) ;
2017-09-08 08:02:43 +00:00
while ( ! IsListEmpty ( & c - > partial_stripes ) ) {
partial_stripe * ps = CONTAINING_RECORD ( RemoveHeadList ( & c - > partial_stripes ) , partial_stripe , list_entry ) ;
Status = flush_partial_stripe ( Vcb , c , ps ) ;
if ( ps - > bmparr )
ExFreePool ( ps - > bmparr ) ;
ExFreePool ( ps ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " flush_partial_stripe returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
ExReleaseResourceLite ( & c - > partial_stripes_lock ) ;
return Status ;
}
}
ExReleaseResourceLite ( & c - > partial_stripes_lock ) ;
}
le = le - > Flink ;
}
}
return STATUS_SUCCESS ;
2017-01-01 17:12:12 +00:00
}
2020-04-23 02:38:57 +00:00
void calc_tree_checksum ( device_extension * Vcb , tree_header * th ) {
switch ( Vcb - > superblock . csum_type ) {
case CSUM_TYPE_CRC32C :
* ( ( uint32_t * ) th ) = ~ calc_crc32c ( 0xffffffff , ( uint8_t * ) & th - > fs_uuid , Vcb - > superblock . node_size - sizeof ( th - > csum ) ) ;
break ;
case CSUM_TYPE_XXHASH :
* ( ( uint64_t * ) th ) = XXH64 ( ( uint8_t * ) & th - > fs_uuid , Vcb - > superblock . node_size - sizeof ( th - > csum ) , 0 ) ;
break ;
case CSUM_TYPE_SHA256 :
calc_sha256 ( ( uint8_t * ) th , & th - > fs_uuid , Vcb - > superblock . node_size - sizeof ( th - > csum ) ) ;
break ;
case CSUM_TYPE_BLAKE2 :
blake2b ( ( uint8_t * ) th , BLAKE2_HASH_SIZE , & th - > fs_uuid , Vcb - > superblock . node_size - sizeof ( th - > csum ) ) ;
break ;
}
}
2016-10-29 17:05:10 +00:00
static NTSTATUS write_trees ( device_extension * Vcb , PIRP Irp ) {
2017-09-08 08:02:43 +00:00
ULONG level ;
2019-09-01 12:53:20 +00:00
uint8_t * data , * body ;
2016-10-29 17:05:10 +00:00
NTSTATUS Status ;
LIST_ENTRY * le ;
LIST_ENTRY tree_writes ;
tree_write * tw ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
TRACE ( " (%p) \n " , Vcb ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
InitializeListHead ( & tree_writes ) ;
for ( level = 0 ; level < = 255 ; level + + ) {
2019-09-01 12:53:20 +00:00
bool nothing_found = true ;
2017-09-08 08:02:43 +00:00
2020-04-23 02:38:57 +00:00
TRACE ( " level = %lu \n " , level ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = Vcb - > trees . Flink ;
while ( le ! = & Vcb - > trees ) {
tree * t = CONTAINING_RECORD ( le , tree , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( t - > write & & t - > header . level = = level ) {
KEY firstitem , searchkey ;
LIST_ENTRY * le2 ;
traverse_ptr tp ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! t - > has_new_address ) {
ERR ( " error - tried to write tree with no new address \n " ) ;
2017-09-08 08:02:43 +00:00
return STATUS_INTERNAL_ERROR ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le2 = t - > itemlist . Flink ;
while ( le2 ! = & t - > itemlist ) {
tree_data * td = CONTAINING_RECORD ( le2 , tree_data , list_entry ) ;
if ( ! td - > ignore ) {
firstitem = td - > key ;
break ;
}
le2 = le2 - > Flink ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( t - > parent ) {
t - > paritem - > key = firstitem ;
t - > paritem - > treeholder . address = t - > new_address ;
t - > paritem - > treeholder . generation = Vcb - > superblock . generation ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! ( Vcb - > superblock . incompat_flags & BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA ) ) {
2017-09-08 08:02:43 +00:00
EXTENT_ITEM_TREE * eit ;
2016-10-29 17:05:10 +00:00
searchkey . obj_id = t - > new_address ;
searchkey . obj_type = TYPE_EXTENT_ITEM ;
searchkey . offset = Vcb - > superblock . node_size ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > extent_root , & tp , & searchkey , false , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - find_item returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( keycmp ( searchkey , tp . item - > key ) ) {
2019-09-01 12:53:20 +00:00
ERR ( " could not find %I64x,%x,%I64x in extent_root (found %I64x,%x,%I64x instead) \n " , searchkey . obj_id , searchkey . obj_type , searchkey . offset , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset ) ;
2016-10-29 17:05:10 +00:00
return STATUS_INTERNAL_ERROR ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( tp . item - > size < sizeof ( EXTENT_ITEM_TREE ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " (%I64x,%x,%I64x) was %u bytes, expected at least %Iu \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , tp . item - > size , sizeof ( EXTENT_ITEM_TREE ) ) ;
2016-10-29 17:05:10 +00:00
return STATUS_INTERNAL_ERROR ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
eit = ( EXTENT_ITEM_TREE * ) tp . item - > data ;
eit - > firstitem = firstitem ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
nothing_found = false ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = le - > Flink ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( nothing_found )
break ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
TRACE ( " allocated tree extents \n " ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = Vcb - > trees . Flink ;
while ( le ! = & Vcb - > trees ) {
tree * t = CONTAINING_RECORD ( le , tree , list_entry ) ;
2017-09-08 08:02:43 +00:00
LIST_ENTRY * le2 ;
2016-10-29 17:05:10 +00:00
# ifdef DEBUG_PARANOID
2019-09-01 12:53:20 +00:00
uint32_t num_items = 0 , size = 0 ;
bool crash = false ;
2016-10-29 17:05:10 +00:00
# endif
if ( t - > write ) {
# ifdef DEBUG_PARANOID
2019-09-01 12:53:20 +00:00
bool first = true ;
2017-09-08 08:02:43 +00:00
KEY lastkey ;
2016-10-29 17:05:10 +00:00
le2 = t - > itemlist . Flink ;
while ( le2 ! = & t - > itemlist ) {
tree_data * td = CONTAINING_RECORD ( le2 , tree_data , list_entry ) ;
if ( ! td - > ignore ) {
num_items + + ;
2017-09-08 08:02:43 +00:00
if ( ! first ) {
if ( keycmp ( td - > key , lastkey ) = = 0 ) {
2019-09-01 12:53:20 +00:00
ERR ( " (%I64x,%x,%I64x): duplicate key \n " , td - > key . obj_id , td - > key . obj_type , td - > key . offset ) ;
crash = true ;
2017-09-08 08:02:43 +00:00
} else if ( keycmp ( td - > key , lastkey ) = = - 1 ) {
2019-09-01 12:53:20 +00:00
ERR ( " (%I64x,%x,%I64x): key out of order \n " , td - > key . obj_id , td - > key . obj_type , td - > key . offset ) ;
crash = true ;
2017-09-08 08:02:43 +00:00
}
} else
2019-09-01 12:53:20 +00:00
first = false ;
2017-09-08 08:02:43 +00:00
lastkey = td - > key ;
2016-10-29 17:05:10 +00:00
if ( t - > header . level = = 0 )
size + = td - > size ;
}
le2 = le2 - > Flink ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( t - > header . level = = 0 )
size + = num_items * sizeof ( leaf_node ) ;
else
size + = num_items * sizeof ( internal_node ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( num_items ! = t - > header . num_items ) {
2019-09-01 12:53:20 +00:00
ERR ( " tree %I64x, level %x: num_items was %x, expected %x \n " , t - > root - > id , t - > header . level , num_items , t - > header . num_items ) ;
crash = true ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( size ! = t - > size ) {
2019-09-01 12:53:20 +00:00
ERR ( " tree %I64x, level %x: size was %x, expected %x \n " , t - > root - > id , t - > header . level , size , t - > size ) ;
crash = true ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( t - > header . num_items = = 0 & & t - > parent ) {
2019-09-01 12:53:20 +00:00
ERR ( " tree %I64x, level %x: tried to write empty tree with parent \n " , t - > root - > id , t - > header . level ) ;
crash = true ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( t - > size > Vcb - > superblock . node_size - sizeof ( tree_header ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " tree %I64x, level %x: tried to write overlarge tree (%x > %Ix) \n " , t - > root - > id , t - > header . level , t - > size , Vcb - > superblock . node_size - sizeof ( tree_header ) ) ;
2019-09-01 12:53:20 +00:00
crash = true ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( crash ) {
ERR ( " tree %p \n " , t ) ;
le2 = t - > itemlist . Flink ;
while ( le2 ! = & t - > itemlist ) {
tree_data * td = CONTAINING_RECORD ( le2 , tree_data , list_entry ) ;
if ( ! td - > ignore ) {
2019-09-01 12:53:20 +00:00
ERR ( " %I64x,%x,%I64x inserted=%u \n " , td - > key . obj_id , td - > key . obj_type , td - > key . offset , td - > inserted ) ;
2016-10-29 17:05:10 +00:00
}
le2 = le2 - > Flink ;
}
int3 ;
}
# endif
t - > header . address = t - > new_address ;
t - > header . generation = Vcb - > superblock . generation ;
t - > header . tree_id = t - > root - > id ;
t - > header . flags | = HEADER_FLAG_MIXED_BACKREF ;
2020-04-23 02:38:57 +00:00
t - > header . fs_uuid = Vcb - > superblock . metadata_uuid ;
2019-09-01 12:53:20 +00:00
t - > has_address = true ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
data = ExAllocatePoolWithTag ( NonPagedPool , Vcb - > superblock . node_size , ALLOC_TAG ) ;
if ( ! data ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
body = data + sizeof ( tree_header ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
RtlCopyMemory ( data , & t - > header , sizeof ( tree_header ) ) ;
RtlZeroMemory ( body , Vcb - > superblock . node_size - sizeof ( tree_header ) ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( t - > header . level = = 0 ) {
leaf_node * itemptr = ( leaf_node * ) body ;
int i = 0 ;
2019-09-01 12:53:20 +00:00
uint8_t * dataptr = data + Vcb - > superblock . node_size ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le2 = t - > itemlist . Flink ;
while ( le2 ! = & t - > itemlist ) {
tree_data * td = CONTAINING_RECORD ( le2 , tree_data , list_entry ) ;
if ( ! td - > ignore ) {
dataptr = dataptr - td - > size ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
itemptr [ i ] . key = td - > key ;
2019-09-01 12:53:20 +00:00
itemptr [ i ] . offset = ( uint32_t ) ( ( uint8_t * ) dataptr - ( uint8_t * ) body ) ;
2016-10-29 17:05:10 +00:00
itemptr [ i ] . size = td - > size ;
i + + ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( td - > size > 0 )
RtlCopyMemory ( dataptr , td - > data , td - > size ) ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le2 = le2 - > Flink ;
}
} else {
internal_node * itemptr = ( internal_node * ) body ;
int i = 0 ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le2 = t - > itemlist . Flink ;
while ( le2 ! = & t - > itemlist ) {
tree_data * td = CONTAINING_RECORD ( le2 , tree_data , list_entry ) ;
if ( ! td - > ignore ) {
itemptr [ i ] . key = td - > key ;
itemptr [ i ] . address = td - > treeholder . address ;
itemptr [ i ] . generation = td - > treeholder . generation ;
i + + ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le2 = le2 - > Flink ;
}
}
2017-09-08 08:02:43 +00:00
2020-04-23 02:38:57 +00:00
calc_tree_checksum ( Vcb , ( tree_header * ) data ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
tw = ExAllocatePoolWithTag ( PagedPool , sizeof ( tree_write ) , ALLOC_TAG ) ;
if ( ! tw ) {
ERR ( " out of memory \n " ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( data ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto end ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
tw - > address = t - > new_address ;
tw - > length = Vcb - > superblock . node_size ;
tw - > data = data ;
2019-11-12 18:32:46 +00:00
tw - > allocated = false ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( IsListEmpty ( & tree_writes ) )
InsertTailList ( & tree_writes , & tw - > list_entry ) ;
else {
2019-09-01 12:53:20 +00:00
bool inserted = false ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le2 = tree_writes . Flink ;
while ( le2 ! = & tree_writes ) {
tree_write * tw2 = CONTAINING_RECORD ( le2 , tree_write , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( tw2 - > address > tw - > address ) {
InsertHeadList ( le2 - > Blink , & tw - > list_entry ) ;
2019-09-01 12:53:20 +00:00
inserted = true ;
2016-10-29 17:05:10 +00:00
break ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le2 = le2 - > Flink ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! inserted )
InsertTailList ( & tree_writes , & tw - > list_entry ) ;
}
}
le = le - > Flink ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = do_tree_writes ( Vcb , & tree_writes , false ) ;
2017-01-01 17:12:12 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " do_tree_writes returned %08lx \n " , Status ) ;
2017-01-01 17:12:12 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
Status = STATUS_SUCCESS ;
end :
while ( ! IsListEmpty ( & tree_writes ) ) {
le = RemoveHeadList ( & tree_writes ) ;
2016-10-29 17:05:10 +00:00
tw = CONTAINING_RECORD ( le , tree_write , list_entry ) ;
2017-09-08 08:02:43 +00:00
if ( tw - > data )
ExFreePool ( tw - > data ) ;
2017-01-01 17:12:12 +00:00
ExFreePool ( tw ) ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
return Status ;
}
static void update_backup_superblock ( device_extension * Vcb , superblock_backup * sb , PIRP Irp ) {
KEY searchkey ;
traverse_ptr tp ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
RtlZeroMemory ( sb , sizeof ( superblock_backup ) ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
sb - > root_tree_addr = Vcb - > superblock . root_tree_addr ;
sb - > root_tree_generation = Vcb - > superblock . generation ;
sb - > root_level = Vcb - > superblock . root_level ;
sb - > chunk_tree_addr = Vcb - > superblock . chunk_tree_addr ;
sb - > chunk_tree_generation = Vcb - > superblock . chunk_root_generation ;
sb - > chunk_root_level = Vcb - > superblock . chunk_root_level ;
searchkey . obj_id = BTRFS_ROOT_EXTENT ;
searchkey . obj_type = TYPE_ROOT_ITEM ;
searchkey . offset = 0xffffffffffffffff ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
if ( NT_SUCCESS ( find_item ( Vcb , Vcb - > root_root , & tp , & searchkey , false , Irp ) ) ) {
2016-10-29 17:05:10 +00:00
if ( tp . item - > key . obj_id = = searchkey . obj_id & & tp . item - > key . obj_type = = searchkey . obj_type & & tp . item - > size > = sizeof ( ROOT_ITEM ) ) {
ROOT_ITEM * ri = ( ROOT_ITEM * ) tp . item - > data ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
sb - > extent_tree_addr = ri - > block_number ;
sb - > extent_tree_generation = ri - > generation ;
sb - > extent_root_level = ri - > root_level ;
}
}
searchkey . obj_id = BTRFS_ROOT_FSTREE ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
if ( NT_SUCCESS ( find_item ( Vcb , Vcb - > root_root , & tp , & searchkey , false , Irp ) ) ) {
2016-10-29 17:05:10 +00:00
if ( tp . item - > key . obj_id = = searchkey . obj_id & & tp . item - > key . obj_type = = searchkey . obj_type & & tp . item - > size > = sizeof ( ROOT_ITEM ) ) {
ROOT_ITEM * ri = ( ROOT_ITEM * ) tp . item - > data ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
sb - > fs_tree_addr = ri - > block_number ;
sb - > fs_tree_generation = ri - > generation ;
sb - > fs_root_level = ri - > root_level ;
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
searchkey . obj_id = BTRFS_ROOT_DEVTREE ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
if ( NT_SUCCESS ( find_item ( Vcb , Vcb - > root_root , & tp , & searchkey , false , Irp ) ) ) {
2016-10-29 17:05:10 +00:00
if ( tp . item - > key . obj_id = = searchkey . obj_id & & tp . item - > key . obj_type = = searchkey . obj_type & & tp . item - > size > = sizeof ( ROOT_ITEM ) ) {
ROOT_ITEM * ri = ( ROOT_ITEM * ) tp . item - > data ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
sb - > dev_root_addr = ri - > block_number ;
sb - > dev_root_generation = ri - > generation ;
sb - > dev_root_level = ri - > root_level ;
}
}
searchkey . obj_id = BTRFS_ROOT_CHECKSUM ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
if ( NT_SUCCESS ( find_item ( Vcb , Vcb - > root_root , & tp , & searchkey , false , Irp ) ) ) {
2016-10-29 17:05:10 +00:00
if ( tp . item - > key . obj_id = = searchkey . obj_id & & tp . item - > key . obj_type = = searchkey . obj_type & & tp . item - > size > = sizeof ( ROOT_ITEM ) ) {
ROOT_ITEM * ri = ( ROOT_ITEM * ) tp . item - > data ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
sb - > csum_root_addr = ri - > block_number ;
sb - > csum_root_generation = ri - > generation ;
sb - > csum_root_level = ri - > root_level ;
}
}
sb - > total_bytes = Vcb - > superblock . total_bytes ;
sb - > bytes_used = Vcb - > superblock . bytes_used ;
sb - > num_devices = Vcb - > superblock . num_devices ;
}
2017-09-08 08:02:43 +00:00
typedef struct {
void * context ;
2019-09-01 12:53:20 +00:00
uint8_t * buf ;
2017-09-08 08:02:43 +00:00
PMDL mdl ;
device * device ;
2016-10-29 17:05:10 +00:00
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
PIRP Irp ;
LIST_ENTRY list_entry ;
} write_superblocks_stripe ;
typedef struct _write_superblocks_context {
KEVENT Event ;
LIST_ENTRY stripes ;
LONG left ;
} write_superblocks_context ;
_Function_class_ ( IO_COMPLETION_ROUTINE )
2019-09-01 12:53:20 +00:00
static NTSTATUS __stdcall write_superblock_completion ( PDEVICE_OBJECT DeviceObject , PIRP Irp , PVOID conptr ) {
2017-09-08 08:02:43 +00:00
write_superblocks_stripe * stripe = conptr ;
write_superblocks_context * context = stripe - > context ;
UNUSED ( DeviceObject ) ;
stripe - > Status = Irp - > IoStatus . Status ;
if ( InterlockedDecrement ( & context - > left ) = = 0 )
2019-09-01 12:53:20 +00:00
KeSetEvent ( & context - > Event , 0 , false ) ;
2017-09-08 08:02:43 +00:00
return STATUS_MORE_PROCESSING_REQUIRED ;
}
2020-04-23 02:38:57 +00:00
static void calc_superblock_checksum ( superblock * sb ) {
switch ( sb - > csum_type ) {
case CSUM_TYPE_CRC32C :
* ( uint32_t * ) sb = ~ calc_crc32c ( 0xffffffff , ( uint8_t * ) & sb - > uuid , ( ULONG ) sizeof ( superblock ) - sizeof ( sb - > checksum ) ) ;
break ;
case CSUM_TYPE_XXHASH :
* ( uint64_t * ) sb = XXH64 ( & sb - > uuid , sizeof ( superblock ) - sizeof ( sb - > checksum ) , 0 ) ;
break ;
case CSUM_TYPE_SHA256 :
calc_sha256 ( ( uint8_t * ) sb , & sb - > uuid , sizeof ( superblock ) - sizeof ( sb - > checksum ) ) ;
break ;
case CSUM_TYPE_BLAKE2 :
blake2b ( ( uint8_t * ) sb , BLAKE2_HASH_SIZE , & sb - > uuid , sizeof ( superblock ) - sizeof ( sb - > checksum ) ) ;
break ;
}
}
2017-09-08 08:02:43 +00:00
static NTSTATUS write_superblock ( device_extension * Vcb , device * device , write_superblocks_context * context ) {
unsigned int i = 0 ;
2016-10-29 17:05:10 +00:00
// All the documentation says that the Linux driver only writes one superblock
// if it thinks a disk is an SSD, but this doesn't seem to be the case!
2017-09-08 08:02:43 +00:00
while ( superblock_addrs [ i ] > 0 & & device - > devitem . num_bytes > = superblock_addrs [ i ] + sizeof ( superblock ) ) {
ULONG sblen = ( ULONG ) sector_align ( sizeof ( superblock ) , Vcb - > superblock . sector_size ) ;
superblock * sb ;
write_superblocks_stripe * stripe ;
PIO_STACK_LOCATION IrpSp ;
sb = ExAllocatePoolWithTag ( NonPagedPool , sblen , ALLOC_TAG ) ;
if ( ! sb ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
RtlCopyMemory ( sb , & Vcb - > superblock , sizeof ( superblock ) ) ;
if ( sblen > sizeof ( superblock ) )
2019-09-01 12:53:20 +00:00
RtlZeroMemory ( ( uint8_t * ) sb + sizeof ( superblock ) , sblen - sizeof ( superblock ) ) ;
2017-09-08 08:02:43 +00:00
RtlCopyMemory ( & sb - > dev_item , & device - > devitem , sizeof ( DEV_ITEM ) ) ;
sb - > sb_phys_addr = superblock_addrs [ i ] ;
2020-04-23 02:38:57 +00:00
calc_superblock_checksum ( sb ) ;
2017-09-08 08:02:43 +00:00
stripe = ExAllocatePoolWithTag ( NonPagedPool , sizeof ( write_superblocks_stripe ) , ALLOC_TAG ) ;
if ( ! stripe ) {
ERR ( " out of memory \n " ) ;
ExFreePool ( sb ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2019-09-01 12:53:20 +00:00
stripe - > buf = ( uint8_t * ) sb ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
stripe - > Irp = IoAllocateIrp ( device - > devobj - > StackSize , false ) ;
2017-09-08 08:02:43 +00:00
if ( ! stripe - > Irp ) {
ERR ( " IoAllocateIrp failed \n " ) ;
ExFreePool ( stripe ) ;
ExFreePool ( sb ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
IrpSp = IoGetNextIrpStackLocation ( stripe - > Irp ) ;
IrpSp - > MajorFunction = IRP_MJ_WRITE ;
2019-09-01 12:53:20 +00:00
IrpSp - > FileObject = device - > fileobj ;
2017-09-08 08:02:43 +00:00
if ( i = = 0 )
IrpSp - > Flags | = SL_WRITE_THROUGH ;
if ( device - > devobj - > Flags & DO_BUFFERED_IO ) {
stripe - > Irp - > AssociatedIrp . SystemBuffer = sb ;
stripe - > mdl = NULL ;
stripe - > Irp - > Flags = IRP_BUFFERED_IO ;
} else if ( device - > devobj - > Flags & DO_DIRECT_IO ) {
2019-09-01 12:53:20 +00:00
stripe - > mdl = IoAllocateMdl ( sb , sblen , false , false , NULL ) ;
2017-09-08 08:02:43 +00:00
if ( ! stripe - > mdl ) {
ERR ( " IoAllocateMdl failed \n " ) ;
IoFreeIrp ( stripe - > Irp ) ;
ExFreePool ( stripe ) ;
ExFreePool ( sb ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
stripe - > Irp - > MdlAddress = stripe - > mdl ;
MmBuildMdlForNonPagedPool ( stripe - > mdl ) ;
} else {
stripe - > Irp - > UserBuffer = sb ;
stripe - > mdl = NULL ;
}
IrpSp - > Parameters . Write . Length = sblen ;
IrpSp - > Parameters . Write . ByteOffset . QuadPart = superblock_addrs [ i ] ;
2019-09-01 12:53:20 +00:00
IoSetCompletionRoutine ( stripe - > Irp , write_superblock_completion , stripe , true , true , true ) ;
2017-09-08 08:02:43 +00:00
stripe - > context = context ;
stripe - > device = device ;
InsertTailList ( & context - > stripes , & stripe - > list_entry ) ;
context - > left + + ;
2016-10-29 17:05:10 +00:00
i + + ;
}
2017-09-08 08:02:43 +00:00
if ( i = = 0 )
2016-10-29 17:05:10 +00:00
ERR ( " no superblocks written! \n " ) ;
2017-09-08 08:02:43 +00:00
return STATUS_SUCCESS ;
2016-10-29 17:05:10 +00:00
}
static NTSTATUS write_superblocks ( device_extension * Vcb , PIRP Irp ) {
2019-09-01 12:53:20 +00:00
uint64_t i ;
2016-10-29 17:05:10 +00:00
NTSTATUS Status ;
LIST_ENTRY * le ;
2017-09-08 08:02:43 +00:00
write_superblocks_context context ;
2016-10-29 17:05:10 +00:00
TRACE ( " (%p) \n " , Vcb ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = Vcb - > trees . Flink ;
while ( le ! = & Vcb - > trees ) {
tree * t = CONTAINING_RECORD ( le , tree , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( t - > write & & ! t - > parent ) {
if ( t - > root = = Vcb - > root_root ) {
Vcb - > superblock . root_tree_addr = t - > new_address ;
Vcb - > superblock . root_level = t - > header . level ;
} else if ( t - > root = = Vcb - > chunk_root ) {
Vcb - > superblock . chunk_tree_addr = t - > new_address ;
Vcb - > superblock . chunk_root_generation = t - > header . generation ;
Vcb - > superblock . chunk_root_level = t - > header . level ;
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = le - > Flink ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
for ( i = 0 ; i < BTRFS_NUM_BACKUP_ROOTS - 1 ; i + + ) {
RtlCopyMemory ( & Vcb - > superblock . backup [ i ] , & Vcb - > superblock . backup [ i + 1 ] , sizeof ( superblock_backup ) ) ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
update_backup_superblock ( Vcb , & Vcb - > superblock . backup [ BTRFS_NUM_BACKUP_ROOTS - 1 ] , Irp ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
KeInitializeEvent ( & context . Event , NotificationEvent , false ) ;
2017-09-08 08:02:43 +00:00
InitializeListHead ( & context . stripes ) ;
context . left = 0 ;
2017-01-01 17:12:12 +00:00
le = Vcb - > devices . Flink ;
while ( le ! = & Vcb - > devices ) {
device * dev = CONTAINING_RECORD ( le , device , list_entry ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( dev - > devobj & & ! dev - > readonly ) {
2017-09-08 08:02:43 +00:00
Status = write_superblock ( Vcb , dev , & context ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " write_superblock returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
goto end ;
2016-10-29 17:05:10 +00:00
}
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le = le - > Flink ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
if ( IsListEmpty ( & context . stripes ) ) {
ERR ( " error - not writing any superblocks \n " ) ;
Status = STATUS_INTERNAL_ERROR ;
goto end ;
}
le = context . stripes . Flink ;
while ( le ! = & context . stripes ) {
write_superblocks_stripe * stripe = CONTAINING_RECORD ( le , write_superblocks_stripe , list_entry ) ;
IoCallDriver ( stripe - > device - > devobj , stripe - > Irp ) ;
le = le - > Flink ;
}
2019-09-01 12:53:20 +00:00
KeWaitForSingleObject ( & context . Event , Executive , KernelMode , false , NULL ) ;
2017-09-08 08:02:43 +00:00
le = context . stripes . Flink ;
while ( le ! = & context . stripes ) {
write_superblocks_stripe * stripe = CONTAINING_RECORD ( le , write_superblocks_stripe , list_entry ) ;
if ( ! NT_SUCCESS ( stripe - > Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " device %I64x returned %08lx \n " , stripe - > device - > devitem . dev_id , stripe - > Status ) ;
2017-09-08 08:02:43 +00:00
log_device_error ( Vcb , stripe - > device , BTRFS_DEV_STAT_WRITE_ERRORS ) ;
Status = stripe - > Status ;
goto end ;
}
le = le - > Flink ;
}
Status = STATUS_SUCCESS ;
end :
while ( ! IsListEmpty ( & context . stripes ) ) {
write_superblocks_stripe * stripe = CONTAINING_RECORD ( RemoveHeadList ( & context . stripes ) , write_superblocks_stripe , list_entry ) ;
if ( stripe - > mdl ) {
if ( stripe - > mdl - > MdlFlags & MDL_PAGES_LOCKED )
MmUnlockPages ( stripe - > mdl ) ;
IoFreeMdl ( stripe - > mdl ) ;
}
if ( stripe - > Irp )
IoFreeIrp ( stripe - > Irp ) ;
if ( stripe - > buf )
ExFreePool ( stripe - > buf ) ;
ExFreePool ( stripe ) ;
}
return Status ;
2016-10-29 17:05:10 +00:00
}
static NTSTATUS flush_changed_extent ( device_extension * Vcb , chunk * c , changed_extent * ce , PIRP Irp , LIST_ENTRY * rollback ) {
LIST_ENTRY * le , * le2 ;
NTSTATUS Status ;
2019-09-01 12:53:20 +00:00
uint64_t old_size ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ce - > count = = 0 & & ce - > old_count = = 0 ) {
while ( ! IsListEmpty ( & ce - > refs ) ) {
changed_extent_ref * cer = CONTAINING_RECORD ( RemoveHeadList ( & ce - > refs ) , changed_extent_ref , list_entry ) ;
ExFreePool ( cer ) ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
while ( ! IsListEmpty ( & ce - > old_refs ) ) {
changed_extent_ref * cer = CONTAINING_RECORD ( RemoveHeadList ( & ce - > old_refs ) , changed_extent_ref , list_entry ) ;
ExFreePool ( cer ) ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = ce - > refs . Flink ;
while ( le ! = & ce - > refs ) {
changed_extent_ref * cer = CONTAINING_RECORD ( le , changed_extent_ref , list_entry ) ;
2019-09-01 12:53:20 +00:00
uint32_t old_count = 0 ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( cer - > type = = TYPE_EXTENT_DATA_REF ) {
le2 = ce - > old_refs . Flink ;
while ( le2 ! = & ce - > old_refs ) {
changed_extent_ref * cer2 = CONTAINING_RECORD ( le2 , changed_extent_ref , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( cer2 - > type = = TYPE_EXTENT_DATA_REF & & cer2 - > edr . root = = cer - > edr . root & & cer2 - > edr . objid = = cer - > edr . objid & & cer2 - > edr . offset = = cer - > edr . offset ) {
old_count = cer2 - > edr . count ;
break ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le2 = le2 - > Flink ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
old_size = ce - > old_count > 0 ? ce - > old_size : ce - > size ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( cer - > edr . count > old_count ) {
2017-09-08 08:02:43 +00:00
Status = increase_extent_refcount_data ( Vcb , ce - > address , old_size , cer - > edr . root , cer - > edr . objid , cer - > edr . offset , cer - > edr . count - old_count , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " increase_extent_refcount_data returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
}
} else if ( cer - > type = = TYPE_SHARED_DATA_REF ) {
le2 = ce - > old_refs . Flink ;
while ( le2 ! = & ce - > old_refs ) {
changed_extent_ref * cer2 = CONTAINING_RECORD ( le2 , changed_extent_ref , list_entry ) ;
if ( cer2 - > type = = TYPE_SHARED_DATA_REF & & cer2 - > sdr . offset = = cer - > sdr . offset ) {
RemoveEntryList ( & cer2 - > list_entry ) ;
ExFreePool ( cer2 ) ;
break ;
}
le2 = le2 - > Flink ;
}
}
le = le - > Flink ;
}
le = ce - > refs . Flink ;
while ( le ! = & ce - > refs ) {
changed_extent_ref * cer = CONTAINING_RECORD ( le , changed_extent_ref , list_entry ) ;
LIST_ENTRY * le3 = le - > Flink ;
2019-09-01 12:53:20 +00:00
uint32_t old_count = 0 ;
2017-09-08 08:02:43 +00:00
if ( cer - > type = = TYPE_EXTENT_DATA_REF ) {
le2 = ce - > old_refs . Flink ;
while ( le2 ! = & ce - > old_refs ) {
changed_extent_ref * cer2 = CONTAINING_RECORD ( le2 , changed_extent_ref , list_entry ) ;
if ( cer2 - > type = = TYPE_EXTENT_DATA_REF & & cer2 - > edr . root = = cer - > edr . root & & cer2 - > edr . objid = = cer - > edr . objid & & cer2 - > edr . offset = = cer - > edr . offset ) {
old_count = cer2 - > edr . count ;
RemoveEntryList ( & cer2 - > list_entry ) ;
ExFreePool ( cer2 ) ;
break ;
}
le2 = le2 - > Flink ;
}
old_size = ce - > old_count > 0 ? ce - > old_size : ce - > size ;
if ( cer - > edr . count < old_count ) {
2016-10-29 17:05:10 +00:00
Status = decrease_extent_refcount_data ( Vcb , ce - > address , old_size , cer - > edr . root , cer - > edr . objid , cer - > edr . offset ,
2017-09-08 08:02:43 +00:00
old_count - cer - > edr . count , ce - > superseded , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " decrease_extent_refcount_data returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ce - > size ! = ce - > old_size & & ce - > old_count > 0 ) {
KEY searchkey ;
traverse_ptr tp ;
void * data ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
searchkey . obj_id = ce - > address ;
searchkey . obj_type = TYPE_EXTENT_ITEM ;
searchkey . offset = ce - > old_size ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > extent_root , & tp , & searchkey , false , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - find_item returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( keycmp ( searchkey , tp . item - > key ) ) {
2019-09-01 12:53:20 +00:00
ERR ( " could not find (%I64x,%x,%I64x) in extent tree \n " , searchkey . obj_id , searchkey . obj_type , searchkey . offset ) ;
2016-10-29 17:05:10 +00:00
return STATUS_INTERNAL_ERROR ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( tp . item - > size > 0 ) {
data = ExAllocatePoolWithTag ( PagedPool , tp . item - > size , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! data ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
RtlCopyMemory ( data , tp . item - > data , tp . item - > size ) ;
} else
data = NULL ;
2017-09-08 08:02:43 +00:00
Status = insert_tree_item ( Vcb , Vcb - > extent_root , ce - > address , TYPE_EXTENT_ITEM , ce - > size , data , tp . item - > size , NULL , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
if ( data ) ExFreePool ( data ) ;
return Status ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
Status = delete_tree_item ( Vcb , & tp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
}
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
RemoveEntryList ( & cer - > list_entry ) ;
ExFreePool ( cer ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = le3 ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
# ifdef DEBUG_PARANOID
if ( ! IsListEmpty ( & ce - > old_refs ) )
WARN ( " old_refs not empty \n " ) ;
# endif
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
end :
2016-10-29 17:05:10 +00:00
if ( ce - > count = = 0 & & ! ce - > superseded ) {
2017-09-08 08:02:43 +00:00
c - > used - = ce - > size ;
space_list_add ( c , ce - > address , ce - > size , rollback ) ;
2016-10-29 17:05:10 +00:00
}
RemoveEntryList ( & ce - > list_entry ) ;
ExFreePool ( ce ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
return STATUS_SUCCESS ;
}
2020-04-23 02:38:57 +00:00
void add_checksum_entry ( device_extension * Vcb , uint64_t address , ULONG length , void * csum , PIRP Irp ) {
2016-10-29 17:05:10 +00:00
KEY searchkey ;
2017-01-01 17:12:12 +00:00
traverse_ptr tp , next_tp ;
2016-10-29 17:05:10 +00:00
NTSTATUS Status ;
2019-09-01 12:53:20 +00:00
uint64_t startaddr , endaddr ;
2017-01-01 17:12:12 +00:00
ULONG len ;
RTL_BITMAP bmp ;
ULONG * bmparr ;
ULONG runlength , index ;
2017-09-08 08:02:43 +00:00
2020-04-23 02:38:57 +00:00
TRACE ( " (%p, %I64x, %lx, %p, %p) \n " , Vcb , address , length , csum , Irp ) ;
2019-09-01 12:53:20 +00:00
2017-01-01 17:12:12 +00:00
searchkey . obj_id = EXTENT_CSUM_ID ;
searchkey . obj_type = TYPE_EXTENT_CSUM ;
searchkey . offset = address ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
// FIXME - create checksum_root if it doesn't exist at all
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > checksum_root , & tp , & searchkey , false , Irp ) ;
2017-01-01 17:12:12 +00:00
if ( Status = = STATUS_NOT_FOUND ) { // tree is completely empty
if ( csum ) { // not deleted
ULONG length2 = length ;
2019-09-01 12:53:20 +00:00
uint64_t off = address ;
2020-04-23 02:38:57 +00:00
void * data = csum ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
do {
2020-04-23 02:38:57 +00:00
uint16_t il = ( uint16_t ) min ( length2 , MAX_CSUM_SIZE / Vcb - > csum_size ) ;
2017-09-08 08:02:43 +00:00
2020-04-23 02:38:57 +00:00
void * checksums = ExAllocatePoolWithTag ( PagedPool , il * Vcb - > csum_size , ALLOC_TAG ) ;
2016-10-29 17:05:10 +00:00
if ( ! checksums ) {
ERR ( " out of memory \n " ) ;
2017-01-01 17:12:12 +00:00
return ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2020-04-23 02:38:57 +00:00
RtlCopyMemory ( checksums , data , il * Vcb - > csum_size ) ;
2017-09-08 08:02:43 +00:00
Status = insert_tree_item ( Vcb , Vcb - > checksum_root , EXTENT_CSUM_ID , TYPE_EXTENT_CSUM , off , checksums ,
2020-04-23 02:38:57 +00:00
il * Vcb - > csum_size , NULL , Irp ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
ExFreePool ( checksums ) ;
2017-01-01 17:12:12 +00:00
return ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
length2 - = il ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( length2 > 0 ) {
2022-04-28 19:31:44 +00:00
off + = ( uint64_t ) il < < Vcb - > sector_shift ;
2020-04-23 02:38:57 +00:00
data = ( uint8_t * ) data + ( il * Vcb - > csum_size ) ;
2017-01-01 17:12:12 +00:00
}
} while ( length2 > 0 ) ;
}
} else if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " find_item returned %08lx \n " , Status ) ;
2017-01-01 17:12:12 +00:00
return ;
} else {
2019-09-01 12:53:20 +00:00
uint32_t tplen ;
2020-04-23 02:38:57 +00:00
void * checksums ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
// FIXME - check entry is TYPE_EXTENT_CSUM?
2017-09-08 08:02:43 +00:00
2022-04-28 19:31:44 +00:00
if ( tp . item - > key . offset < address & & tp . item - > key . offset + ( ( ( uint64_t ) tp . item - > size < < Vcb - > sector_shift ) / Vcb - > csum_size ) > = address )
2017-01-01 17:12:12 +00:00
startaddr = tp . item - > key . offset ;
else
startaddr = address ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
searchkey . obj_id = EXTENT_CSUM_ID ;
searchkey . obj_type = TYPE_EXTENT_CSUM ;
2022-04-28 19:31:44 +00:00
searchkey . offset = address + ( length < < Vcb - > sector_shift ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > checksum_root , & tp , & searchkey , false , Irp ) ;
2017-01-01 17:12:12 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " find_item returned %08lx \n " , Status ) ;
2017-01-01 17:12:12 +00:00
return ;
}
2017-09-08 08:02:43 +00:00
2020-04-23 02:38:57 +00:00
tplen = tp . item - > size / Vcb - > csum_size ;
2017-09-08 08:02:43 +00:00
2022-04-28 19:31:44 +00:00
if ( tp . item - > key . offset + ( tplen < < Vcb - > sector_shift ) > = address + ( length < < Vcb - > sector_shift ) )
endaddr = tp . item - > key . offset + ( tplen < < Vcb - > sector_shift ) ;
2017-01-01 17:12:12 +00:00
else
2022-04-28 19:31:44 +00:00
endaddr = address + ( length < < Vcb - > sector_shift ) ;
2017-09-08 08:02:43 +00:00
2020-04-23 02:38:57 +00:00
TRACE ( " cs starts at %I64x (%lx sectors) \n " , address , length ) ;
2019-09-01 12:53:20 +00:00
TRACE ( " startaddr = %I64x \n " , startaddr ) ;
TRACE ( " endaddr = %I64x \n " , endaddr ) ;
2017-09-08 08:02:43 +00:00
2022-04-28 19:31:44 +00:00
len = ( ULONG ) ( ( endaddr - startaddr ) > > Vcb - > sector_shift ) ;
2017-09-08 08:02:43 +00:00
2020-04-23 02:38:57 +00:00
checksums = ExAllocatePoolWithTag ( PagedPool , Vcb - > csum_size * len , ALLOC_TAG ) ;
2017-01-01 17:12:12 +00:00
if ( ! checksums ) {
ERR ( " out of memory \n " ) ;
return ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
bmparr = ExAllocatePoolWithTag ( PagedPool , sizeof ( ULONG ) * ( ( len / 8 ) + 1 ) , ALLOC_TAG ) ;
if ( ! bmparr ) {
ERR ( " out of memory \n " ) ;
ExFreePool ( checksums ) ;
return ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
RtlInitializeBitMap ( & bmp , bmparr , len ) ;
RtlSetAllBits ( & bmp ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
searchkey . obj_id = EXTENT_CSUM_ID ;
searchkey . obj_type = TYPE_EXTENT_CSUM ;
searchkey . offset = address ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > checksum_root , & tp , & searchkey , false , Irp ) ;
2017-01-01 17:12:12 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " find_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( checksums ) ;
ExFreePool ( bmparr ) ;
2017-01-01 17:12:12 +00:00
return ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
// set bit = free space, cleared bit = allocated sector
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
while ( tp . item - > key . offset < endaddr ) {
if ( tp . item - > key . offset > = startaddr ) {
if ( tp . item - > size > 0 ) {
2022-04-28 19:31:44 +00:00
ULONG itemlen = ( ULONG ) min ( ( len - ( ( tp . item - > key . offset - startaddr ) > > Vcb - > sector_shift ) ) * Vcb - > csum_size , tp . item - > size ) ;
2017-09-08 08:02:43 +00:00
2022-04-28 19:31:44 +00:00
RtlCopyMemory ( ( uint8_t * ) checksums + ( ( ( tp . item - > key . offset - startaddr ) * Vcb - > csum_size ) > > Vcb - > sector_shift ) ,
2020-04-23 02:38:57 +00:00
tp . item - > data , itemlen ) ;
2022-04-28 19:31:44 +00:00
RtlClearBits ( & bmp , ( ULONG ) ( ( tp . item - > key . offset - startaddr ) > > Vcb - > sector_shift ) , itemlen / Vcb - > csum_size ) ;
2017-09-08 08:02:43 +00:00
}
Status = delete_tree_item ( Vcb , & tp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( checksums ) ;
ExFreePool ( bmparr ) ;
return ;
2017-01-01 17:12:12 +00:00
}
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
if ( find_next_item ( Vcb , & tp , & next_tp , false , Irp ) ) {
2017-01-01 17:12:12 +00:00
tp = next_tp ;
} else
break ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! csum ) { // deleted
2022-04-28 19:31:44 +00:00
RtlSetBits ( & bmp , ( ULONG ) ( ( address - startaddr ) > > Vcb - > sector_shift ) , length ) ;
2017-01-01 17:12:12 +00:00
} else {
2022-04-28 19:31:44 +00:00
RtlCopyMemory ( ( uint8_t * ) checksums + ( ( ( address - startaddr ) * Vcb - > csum_size ) > > Vcb - > sector_shift ) ,
2020-04-23 02:38:57 +00:00
csum , length * Vcb - > csum_size ) ;
2022-04-28 19:31:44 +00:00
RtlClearBits ( & bmp , ( ULONG ) ( ( address - startaddr ) > > Vcb - > sector_shift ) , length ) ;
2017-01-01 17:12:12 +00:00
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
runlength = RtlFindFirstRunClear ( & bmp , & index ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
while ( runlength ! = 0 ) {
2019-09-01 12:53:20 +00:00
if ( index > = len )
break ;
if ( index + runlength > = len ) {
runlength = len - index ;
if ( runlength = = 0 )
break ;
}
2017-01-01 17:12:12 +00:00
do {
2019-09-01 12:53:20 +00:00
uint16_t rl ;
uint64_t off ;
2020-04-23 02:38:57 +00:00
void * data ;
2017-09-08 08:02:43 +00:00
2020-04-23 02:38:57 +00:00
if ( runlength * Vcb - > csum_size > MAX_CSUM_SIZE )
rl = ( uint16_t ) ( MAX_CSUM_SIZE / Vcb - > csum_size ) ;
2017-01-01 17:12:12 +00:00
else
2019-09-01 12:53:20 +00:00
rl = ( uint16_t ) runlength ;
2017-09-08 08:02:43 +00:00
2020-04-23 02:38:57 +00:00
data = ExAllocatePoolWithTag ( PagedPool , Vcb - > csum_size * rl , ALLOC_TAG ) ;
2017-01-01 17:12:12 +00:00
if ( ! data ) {
ERR ( " out of memory \n " ) ;
ExFreePool ( bmparr ) ;
ExFreePool ( checksums ) ;
return ;
}
2017-09-08 08:02:43 +00:00
2020-04-23 02:38:57 +00:00
RtlCopyMemory ( data , ( uint8_t * ) checksums + ( Vcb - > csum_size * index ) , Vcb - > csum_size * rl ) ;
2017-09-08 08:02:43 +00:00
2022-04-28 19:31:44 +00:00
off = startaddr + ( ( uint64_t ) index < < Vcb - > sector_shift ) ;
2017-09-08 08:02:43 +00:00
2020-04-23 02:38:57 +00:00
Status = insert_tree_item ( Vcb , Vcb - > checksum_root , EXTENT_CSUM_ID , TYPE_EXTENT_CSUM , off , data , Vcb - > csum_size * rl , NULL , Irp ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item returned %08lx \n " , Status ) ;
2017-01-01 17:12:12 +00:00
ExFreePool ( data ) ;
ExFreePool ( bmparr ) ;
ExFreePool ( checksums ) ;
return ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
runlength - = rl ;
index + = rl ;
} while ( runlength > 0 ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
runlength = RtlFindNextForwardRunClear ( & bmp , index , & index ) ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
ExFreePool ( bmparr ) ;
ExFreePool ( checksums ) ;
2016-10-29 17:05:10 +00:00
}
}
static NTSTATUS update_chunk_usage ( device_extension * Vcb , PIRP Irp , LIST_ENTRY * rollback ) {
LIST_ENTRY * le = Vcb - > chunks . Flink , * le2 ;
chunk * c ;
KEY searchkey ;
traverse_ptr tp ;
BLOCK_GROUP_ITEM * bgi ;
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
TRACE ( " (%p) \n " , Vcb ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
ExAcquireResourceSharedLite ( & Vcb - > chunk_lock , true ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
while ( le ! = & Vcb - > chunks ) {
c = CONTAINING_RECORD ( le , chunk , list_entry ) ;
2017-09-08 08:02:43 +00:00
2018-12-16 11:03:16 +00:00
acquire_chunk_lock ( c , Vcb ) ;
2017-09-08 08:02:43 +00:00
if ( ! c - > cache_loaded & & ( ! IsListEmpty ( & c - > changed_extents ) | | c - > used ! = c - > oldused ) ) {
Status = load_cache_chunk ( Vcb , c , NULL ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " load_cache_chunk returned %08lx \n " , Status ) ;
2018-12-16 11:03:16 +00:00
release_chunk_lock ( c , Vcb ) ;
2017-09-08 08:02:43 +00:00
goto end ;
}
}
2016-10-29 17:05:10 +00:00
le2 = c - > changed_extents . Flink ;
while ( le2 ! = & c - > changed_extents ) {
LIST_ENTRY * le3 = le2 - > Flink ;
changed_extent * ce = CONTAINING_RECORD ( le2 , changed_extent , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
Status = flush_changed_extent ( Vcb , c , ce , Irp , rollback ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " flush_changed_extent returned %08lx \n " , Status ) ;
2018-12-16 11:03:16 +00:00
release_chunk_lock ( c , Vcb ) ;
2016-10-29 17:05:10 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le2 = le3 ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
// This is usually done by update_chunks, but we have to check again in case any new chunks
// have been allocated since.
if ( c - > created ) {
2017-09-08 08:02:43 +00:00
Status = create_chunk ( Vcb , c , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " create_chunk returned %08lx \n " , Status ) ;
2018-12-16 11:03:16 +00:00
release_chunk_lock ( c , Vcb ) ;
2016-10-29 17:05:10 +00:00
goto end ;
}
}
2017-09-08 08:02:43 +00:00
if ( c - > old_cache ) {
if ( c - > old_cache - > dirty ) {
LIST_ENTRY batchlist ;
InitializeListHead ( & batchlist ) ;
2019-09-01 12:53:20 +00:00
Status = flush_fcb ( c - > old_cache , false , & batchlist , Irp ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " flush_fcb returned %08lx \n " , Status ) ;
2018-12-16 11:03:16 +00:00
release_chunk_lock ( c , Vcb ) ;
2017-09-08 08:02:43 +00:00
clear_batch_list ( Vcb , & batchlist ) ;
goto end ;
}
Status = commit_batch_list ( Vcb , & batchlist , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " commit_batch_list returned %08lx \n " , Status ) ;
2018-12-16 11:03:16 +00:00
release_chunk_lock ( c , Vcb ) ;
2017-09-08 08:02:43 +00:00
goto end ;
}
}
2019-05-11 09:20:02 +00:00
free_fcb ( c - > old_cache ) ;
if ( c - > old_cache - > refcount = = 0 )
reap_fcb ( c - > old_cache ) ;
2017-09-08 08:02:43 +00:00
c - > old_cache = NULL ;
}
2016-10-29 17:05:10 +00:00
if ( c - > used ! = c - > oldused ) {
searchkey . obj_id = c - > offset ;
searchkey . obj_type = TYPE_BLOCK_GROUP_ITEM ;
searchkey . offset = c - > chunk_item - > size ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > extent_root , & tp , & searchkey , false , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - find_item returned %08lx \n " , Status ) ;
2018-12-16 11:03:16 +00:00
release_chunk_lock ( c , Vcb ) ;
2016-10-29 17:05:10 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( keycmp ( searchkey , tp . item - > key ) ) {
2019-09-01 12:53:20 +00:00
ERR ( " could not find (%I64x,%x,%I64x) in extent_root \n " , searchkey . obj_id , searchkey . obj_type , searchkey . offset ) ;
2016-10-29 17:05:10 +00:00
Status = STATUS_INTERNAL_ERROR ;
2018-12-16 11:03:16 +00:00
release_chunk_lock ( c , Vcb ) ;
2016-10-29 17:05:10 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( tp . item - > size < sizeof ( BLOCK_GROUP_ITEM ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " (%I64x,%x,%I64x) was %u bytes, expected %Iu \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , tp . item - > size , sizeof ( BLOCK_GROUP_ITEM ) ) ;
2016-10-29 17:05:10 +00:00
Status = STATUS_INTERNAL_ERROR ;
2018-12-16 11:03:16 +00:00
release_chunk_lock ( c , Vcb ) ;
2016-10-29 17:05:10 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
bgi = ExAllocatePoolWithTag ( PagedPool , tp . item - > size , ALLOC_TAG ) ;
if ( ! bgi ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
2018-12-16 11:03:16 +00:00
release_chunk_lock ( c , Vcb ) ;
2016-10-29 17:05:10 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
RtlCopyMemory ( bgi , tp . item - > data , tp . item - > size ) ;
bgi - > used = c - > used ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
# ifdef DEBUG_PARANOID
if ( bgi - > used & 0x8000000000000000 ) {
2022-09-28 16:08:10 +00:00
ERR ( " refusing to write BLOCK_GROUP_ITEM with negative usage value (%I64x) \n " , bgi - > used ) ;
2019-09-01 12:53:20 +00:00
int3 ;
}
# endif
TRACE ( " adjusting usage of chunk %I64x to %I64x \n " , c - > offset , c - > used ) ;
2017-09-08 08:02:43 +00:00
Status = delete_tree_item ( Vcb , & tp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( bgi ) ;
2018-12-16 11:03:16 +00:00
release_chunk_lock ( c , Vcb ) ;
2017-09-08 08:02:43 +00:00
goto end ;
}
Status = insert_tree_item ( Vcb , Vcb - > extent_root , searchkey . obj_id , searchkey . obj_type , searchkey . offset , bgi , tp . item - > size , NULL , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
ExFreePool ( bgi ) ;
2018-12-16 11:03:16 +00:00
release_chunk_lock ( c , Vcb ) ;
2016-10-29 17:05:10 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
2022-04-28 19:37:02 +00:00
Vcb - > superblock . bytes_used + = c - > used - c - > oldused ;
2016-10-29 17:05:10 +00:00
c - > oldused = c - > used ;
}
2017-09-08 08:02:43 +00:00
2018-12-16 11:03:16 +00:00
release_chunk_lock ( c , Vcb ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = le - > Flink ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
Status = STATUS_SUCCESS ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
end :
ExReleaseResourceLite ( & Vcb - > chunk_lock ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
return Status ;
}
static void get_first_item ( tree * t , KEY * key ) {
LIST_ENTRY * le ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = t - > itemlist . Flink ;
while ( le ! = & t - > itemlist ) {
tree_data * td = CONTAINING_RECORD ( le , tree_data , list_entry ) ;
* key = td - > key ;
return ;
}
}
2019-09-01 12:53:20 +00:00
static NTSTATUS split_tree_at ( device_extension * Vcb , tree * t , tree_data * newfirstitem , uint32_t numitems , uint32_t size ) {
2016-10-29 17:05:10 +00:00
tree * nt , * pt ;
tree_data * td ;
tree_data * oldlastitem ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
TRACE ( " splitting tree in %I64x at (%I64x,%x,%I64x) \n " , t - > root - > id , newfirstitem - > key . obj_id , newfirstitem - > key . obj_type , newfirstitem - > key . offset ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
nt = ExAllocatePoolWithTag ( PagedPool , sizeof ( tree ) , ALLOC_TAG ) ;
if ( ! nt ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
if ( t - > header . level > 0 ) {
nt - > nonpaged = ExAllocatePoolWithTag ( NonPagedPool , sizeof ( tree_nonpaged ) , ALLOC_TAG ) ;
if ( ! nt - > nonpaged ) {
ERR ( " out of memory \n " ) ;
ExFreePool ( nt ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
ExInitializeFastMutex ( & nt - > nonpaged - > mutex ) ;
} else
nt - > nonpaged = NULL ;
2016-10-29 17:05:10 +00:00
RtlCopyMemory ( & nt - > header , & t - > header , sizeof ( tree_header ) ) ;
nt - > header . address = 0 ;
nt - > header . generation = Vcb - > superblock . generation ;
nt - > header . num_items = t - > header . num_items - numitems ;
2017-01-01 17:12:12 +00:00
nt - > header . flags = HEADER_FLAG_MIXED_BACKREF | HEADER_FLAG_WRITTEN ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
nt - > has_address = false ;
2016-10-29 17:05:10 +00:00
nt - > Vcb = Vcb ;
nt - > parent = t - > parent ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
# ifdef DEBUG_PARANOID
if ( nt - > parent & & nt - > parent - > header . level < = nt - > header . level ) int3 ;
# endif
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
nt - > root = t - > root ;
nt - > new_address = 0 ;
2019-09-01 12:53:20 +00:00
nt - > has_new_address = false ;
nt - > updated_extents = false ;
nt - > uniqueness_determined = true ;
nt - > is_unique = true ;
2017-01-01 17:12:12 +00:00
nt - > list_entry_hash . Flink = NULL ;
2017-09-08 08:02:43 +00:00
nt - > buf = NULL ;
2016-10-29 17:05:10 +00:00
InitializeListHead ( & nt - > itemlist ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
oldlastitem = CONTAINING_RECORD ( newfirstitem - > list_entry . Blink , tree_data , list_entry ) ;
nt - > itemlist . Flink = & newfirstitem - > list_entry ;
nt - > itemlist . Blink = t - > itemlist . Blink ;
nt - > itemlist . Flink - > Blink = & nt - > itemlist ;
nt - > itemlist . Blink - > Flink = & nt - > itemlist ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
t - > itemlist . Blink = & oldlastitem - > list_entry ;
t - > itemlist . Blink - > Flink = & t - > itemlist ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
nt - > size = t - > size - size ;
t - > size = size ;
t - > header . num_items = numitems ;
2019-09-01 12:53:20 +00:00
nt - > write = true ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
InsertTailList ( & Vcb - > trees , & nt - > list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( nt - > header . level > 0 ) {
LIST_ENTRY * le = nt - > itemlist . Flink ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
while ( le ! = & nt - > itemlist ) {
tree_data * td2 = CONTAINING_RECORD ( le , tree_data , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( td2 - > treeholder . tree ) {
td2 - > treeholder . tree - > parent = nt ;
# ifdef DEBUG_PARANOID
if ( td2 - > treeholder . tree - > parent & & td2 - > treeholder . tree - > parent - > header . level < = td2 - > treeholder . tree - > header . level ) int3 ;
# endif
}
2017-09-08 08:02:43 +00:00
le = le - > Flink ;
}
} else {
LIST_ENTRY * le = nt - > itemlist . Flink ;
while ( le ! = & nt - > itemlist ) {
tree_data * td2 = CONTAINING_RECORD ( le , tree_data , list_entry ) ;
if ( ! td2 - > inserted & & td2 - > data ) {
2019-09-01 12:53:20 +00:00
uint8_t * data = ExAllocatePoolWithTag ( PagedPool , td2 - > size , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
if ( ! data ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
RtlCopyMemory ( data , td2 - > data , td2 - > size ) ;
td2 - > data = data ;
2019-09-01 12:53:20 +00:00
td2 - > inserted = true ;
2017-09-08 08:02:43 +00:00
}
2016-10-29 17:05:10 +00:00
le = le - > Flink ;
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( nt - > parent ) {
td = ExAllocateFromPagedLookasideList ( & Vcb - > tree_data_lookaside ) ;
if ( ! td ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
td - > key = newfirstitem - > key ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
InsertHeadList ( & t - > paritem - > list_entry , & td - > list_entry ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
td - > ignore = false ;
td - > inserted = true ;
2016-10-29 17:05:10 +00:00
td - > treeholder . tree = nt ;
nt - > paritem = td ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
nt - > parent - > header . num_items + + ;
nt - > parent - > size + = sizeof ( internal_node ) ;
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
TRACE ( " adding new tree parent \n " ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( nt - > header . level = = 255 ) {
ERR ( " cannot add parent to tree at level 255 \n " ) ;
return STATUS_INTERNAL_ERROR ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
pt = ExAllocatePoolWithTag ( PagedPool , sizeof ( tree ) , ALLOC_TAG ) ;
if ( ! pt ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
pt - > nonpaged = ExAllocatePoolWithTag ( NonPagedPool , sizeof ( tree_nonpaged ) , ALLOC_TAG ) ;
if ( ! pt - > nonpaged ) {
ERR ( " out of memory \n " ) ;
ExFreePool ( pt ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
ExInitializeFastMutex ( & pt - > nonpaged - > mutex ) ;
2016-10-29 17:05:10 +00:00
RtlCopyMemory ( & pt - > header , & nt - > header , sizeof ( tree_header ) ) ;
pt - > header . address = 0 ;
pt - > header . num_items = 2 ;
pt - > header . level = nt - > header . level + 1 ;
pt - > header . flags = HEADER_FLAG_MIXED_BACKREF | HEADER_FLAG_WRITTEN ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
pt - > has_address = false ;
2016-10-29 17:05:10 +00:00
pt - > Vcb = Vcb ;
pt - > parent = NULL ;
pt - > paritem = NULL ;
pt - > root = t - > root ;
pt - > new_address = 0 ;
2019-09-01 12:53:20 +00:00
pt - > has_new_address = false ;
pt - > updated_extents = false ;
2016-10-29 17:05:10 +00:00
pt - > size = pt - > header . num_items * sizeof ( internal_node ) ;
2019-09-01 12:53:20 +00:00
pt - > uniqueness_determined = true ;
pt - > is_unique = true ;
2017-01-01 17:12:12 +00:00
pt - > list_entry_hash . Flink = NULL ;
2017-09-08 08:02:43 +00:00
pt - > buf = NULL ;
2016-10-29 17:05:10 +00:00
InitializeListHead ( & pt - > itemlist ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
InsertTailList ( & Vcb - > trees , & pt - > list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
td = ExAllocateFromPagedLookasideList ( & Vcb - > tree_data_lookaside ) ;
if ( ! td ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
get_first_item ( t , & td - > key ) ;
2019-09-01 12:53:20 +00:00
td - > ignore = false ;
td - > inserted = false ;
2016-10-29 17:05:10 +00:00
td - > treeholder . address = 0 ;
td - > treeholder . generation = Vcb - > superblock . generation ;
td - > treeholder . tree = t ;
InsertTailList ( & pt - > itemlist , & td - > list_entry ) ;
t - > paritem = td ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
td = ExAllocateFromPagedLookasideList ( & Vcb - > tree_data_lookaside ) ;
if ( ! td ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
td - > key = newfirstitem - > key ;
2019-09-01 12:53:20 +00:00
td - > ignore = false ;
td - > inserted = false ;
2016-10-29 17:05:10 +00:00
td - > treeholder . address = 0 ;
td - > treeholder . generation = Vcb - > superblock . generation ;
td - > treeholder . tree = nt ;
InsertTailList ( & pt - > itemlist , & td - > list_entry ) ;
nt - > paritem = td ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
pt - > write = true ;
2016-10-29 17:05:10 +00:00
t - > root - > treeholder . tree = pt ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
t - > parent = pt ;
nt - > parent = pt ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
# ifdef DEBUG_PARANOID
if ( t - > parent & & t - > parent - > header . level < = t - > header . level ) int3 ;
if ( nt - > parent & & nt - > parent - > header . level < = nt - > header . level ) int3 ;
# endif
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
end :
t - > root - > root_item . bytes_used + = Vcb - > superblock . node_size ;
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
static NTSTATUS split_tree ( device_extension * Vcb , tree * t ) {
2016-10-29 17:05:10 +00:00
LIST_ENTRY * le ;
2019-09-01 12:53:20 +00:00
uint32_t size , ds , numitems ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
size = 0 ;
numitems = 0 ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
// FIXME - naïve implementation: maximizes number of filled trees
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = t - > itemlist . Flink ;
while ( le ! = & t - > itemlist ) {
tree_data * td = CONTAINING_RECORD ( le , tree_data , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! td - > ignore ) {
if ( t - > header . level = = 0 )
ds = sizeof ( leaf_node ) + td - > size ;
else
ds = sizeof ( internal_node ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( numitems = = 0 & & ds > Vcb - > superblock . node_size - sizeof ( tree_header ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " (%I64x,%x,%I64x) in tree %I64x is too large (%x > %Ix) \n " ,
2017-01-01 17:12:12 +00:00
td - > key . obj_id , td - > key . obj_type , td - > key . offset , t - > root - > id ,
ds , Vcb - > superblock . node_size - sizeof ( tree_header ) ) ;
2017-09-08 08:02:43 +00:00
return STATUS_INTERNAL_ERROR ;
2017-01-01 17:12:12 +00:00
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
// FIXME - move back if previous item was deleted item with same key
if ( size + ds > Vcb - > superblock . node_size - sizeof ( tree_header ) )
2016-10-29 17:05:10 +00:00
return split_tree_at ( Vcb , t , td , numitems , size ) ;
size + = ds ;
numitems + + ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = le - > Flink ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
return STATUS_SUCCESS ;
}
2019-09-01 12:53:20 +00:00
bool is_tree_unique ( device_extension * Vcb , tree * t , PIRP Irp ) {
2016-10-29 17:05:10 +00:00
KEY searchkey ;
traverse_ptr tp ;
NTSTATUS Status ;
2019-09-01 12:53:20 +00:00
bool ret = false ;
2017-09-08 08:02:43 +00:00
EXTENT_ITEM * ei ;
2019-09-01 12:53:20 +00:00
uint8_t * type ;
2017-09-08 08:02:43 +00:00
if ( t - > uniqueness_determined )
return t - > is_unique ;
if ( t - > parent & & ! is_tree_unique ( Vcb , t - > parent , Irp ) )
goto end ;
if ( t - > has_address ) {
searchkey . obj_id = t - > header . address ;
searchkey . obj_type = Vcb - > superblock . incompat_flags & BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA ? TYPE_METADATA_ITEM : TYPE_EXTENT_ITEM ;
searchkey . offset = 0xffffffffffffffff ;
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > extent_root , & tp , & searchkey , false , Irp ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - find_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
goto end ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
if ( tp . item - > key . obj_id ! = t - > header . address | | ( tp . item - > key . obj_type ! = TYPE_METADATA_ITEM & & tp . item - > key . obj_type ! = TYPE_EXTENT_ITEM ) )
goto end ;
if ( tp . item - > key . obj_type = = TYPE_EXTENT_ITEM & & tp . item - > size = = sizeof ( EXTENT_ITEM_V0 ) )
goto end ;
if ( tp . item - > size < sizeof ( EXTENT_ITEM ) )
goto end ;
ei = ( EXTENT_ITEM * ) tp . item - > data ;
if ( ei - > refcount > 1 )
goto end ;
if ( tp . item - > key . obj_type = = TYPE_EXTENT_ITEM & & ei - > flags & EXTENT_ITEM_TREE_BLOCK ) {
EXTENT_ITEM2 * ei2 ;
if ( tp . item - > size < sizeof ( EXTENT_ITEM ) + sizeof ( EXTENT_ITEM2 ) )
goto end ;
ei2 = ( EXTENT_ITEM2 * ) & ei [ 1 ] ;
2019-09-01 12:53:20 +00:00
type = ( uint8_t * ) & ei2 [ 1 ] ;
2017-09-08 08:02:43 +00:00
} else
2019-09-01 12:53:20 +00:00
type = ( uint8_t * ) & ei [ 1 ] ;
2017-09-08 08:02:43 +00:00
if ( type > = tp . item - > data + tp . item - > size | | * type ! = TYPE_TREE_BLOCK_REF )
goto end ;
}
2019-09-01 12:53:20 +00:00
ret = true ;
2017-09-08 08:02:43 +00:00
end :
t - > is_unique = ret ;
2019-09-01 12:53:20 +00:00
t - > uniqueness_determined = true ;
2017-09-08 08:02:43 +00:00
return ret ;
2016-10-29 17:05:10 +00:00
}
2019-09-01 12:53:20 +00:00
static NTSTATUS try_tree_amalgamate ( device_extension * Vcb , tree * t , bool * done , bool * done_deletions , PIRP Irp , LIST_ENTRY * rollback ) {
2016-10-29 17:05:10 +00:00
LIST_ENTRY * le ;
tree_data * nextparitem = NULL ;
NTSTATUS Status ;
tree * next_tree , * par ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
* done = false ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
TRACE ( " trying to amalgamate tree in root %I64x, level %x (size %u) \n " , t - > root - > id , t - > header . level , t - > size ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
// FIXME - doesn't capture everything, as it doesn't ascend
le = t - > paritem - > list_entry . Flink ;
while ( le ! = & t - > parent - > itemlist ) {
tree_data * td = CONTAINING_RECORD ( le , tree_data , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! td - > ignore ) {
nextparitem = td ;
break ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = le - > Flink ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! nextparitem )
return STATUS_SUCCESS ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
TRACE ( " nextparitem: key = %I64x,%x,%I64x \n " , nextparitem - > key . obj_id , nextparitem - > key . obj_type , nextparitem - > key . offset ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
if ( ! nextparitem - > treeholder . tree ) {
Status = do_load_tree ( Vcb , & nextparitem - > treeholder , t - > root , t - > parent , nextparitem , NULL ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " do_load_tree returned %08lx \n " , Status ) ;
2019-05-11 09:20:02 +00:00
return Status ;
}
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! is_tree_unique ( Vcb , nextparitem - > treeholder . tree , Irp ) )
return STATUS_SUCCESS ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
next_tree = nextparitem - > treeholder . tree ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! next_tree - > updated_extents & & next_tree - > has_address ) {
Status = update_tree_extents ( Vcb , next_tree , Irp , rollback ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " update_tree_extents returned %08lx \n " , Status ) ;
2017-01-01 17:12:12 +00:00
return Status ;
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( t - > size + next_tree - > size < = Vcb - > superblock . node_size - sizeof ( tree_header ) ) {
// merge two trees into one
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
t - > header . num_items + = next_tree - > header . num_items ;
t - > size + = next_tree - > size ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( next_tree - > header . level > 0 ) {
le = next_tree - > itemlist . Flink ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
while ( le ! = & next_tree - > itemlist ) {
tree_data * td2 = CONTAINING_RECORD ( le , tree_data , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( td2 - > treeholder . tree ) {
td2 - > treeholder . tree - > parent = t ;
# ifdef DEBUG_PARANOID
if ( td2 - > treeholder . tree - > parent & & td2 - > treeholder . tree - > parent - > header . level < = td2 - > treeholder . tree - > header . level ) int3 ;
# endif
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
td2 - > inserted = true ;
2017-09-08 08:02:43 +00:00
le = le - > Flink ;
}
} else {
le = next_tree - > itemlist . Flink ;
while ( le ! = & next_tree - > itemlist ) {
tree_data * td2 = CONTAINING_RECORD ( le , tree_data , list_entry ) ;
if ( ! td2 - > inserted & & td2 - > data ) {
2019-09-01 12:53:20 +00:00
uint8_t * data = ExAllocatePoolWithTag ( PagedPool , td2 - > size , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
if ( ! data ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
RtlCopyMemory ( data , td2 - > data , td2 - > size ) ;
td2 - > data = data ;
2019-09-01 12:53:20 +00:00
td2 - > inserted = true ;
2017-09-08 08:02:43 +00:00
}
2016-10-29 17:05:10 +00:00
le = le - > Flink ;
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
t - > itemlist . Blink - > Flink = next_tree - > itemlist . Flink ;
t - > itemlist . Blink - > Flink - > Blink = t - > itemlist . Blink ;
t - > itemlist . Blink = next_tree - > itemlist . Blink ;
t - > itemlist . Blink - > Flink = & t - > itemlist ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
next_tree - > itemlist . Flink = next_tree - > itemlist . Blink = & next_tree - > itemlist ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
next_tree - > header . num_items = 0 ;
next_tree - > size = 0 ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( next_tree - > has_new_address ) { // delete associated EXTENT_ITEM
2017-01-01 17:12:12 +00:00
Status = reduce_tree_extent ( Vcb , next_tree - > new_address , next_tree , next_tree - > parent - > header . tree_id , next_tree - > header . level , Irp , rollback ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " reduce_tree_extent returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
} else if ( next_tree - > has_address ) {
2017-01-01 17:12:12 +00:00
Status = reduce_tree_extent ( Vcb , next_tree - > header . address , next_tree , next_tree - > parent - > header . tree_id , next_tree - > header . level , Irp , rollback ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " reduce_tree_extent returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! nextparitem - > ignore ) {
2019-09-01 12:53:20 +00:00
nextparitem - > ignore = true ;
2016-10-29 17:05:10 +00:00
next_tree - > parent - > header . num_items - - ;
next_tree - > parent - > size - = sizeof ( internal_node ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
* done_deletions = true ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
par = next_tree - > parent ;
while ( par ) {
2019-09-01 12:53:20 +00:00
par - > write = true ;
2016-10-29 17:05:10 +00:00
par = par - > parent ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
RemoveEntryList ( & nextparitem - > list_entry ) ;
ExFreePool ( next_tree - > paritem ) ;
next_tree - > paritem = NULL ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
next_tree - > root - > root_item . bytes_used - = Vcb - > superblock . node_size ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
free_tree ( next_tree ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
* done = true ;
2016-10-29 17:05:10 +00:00
} else {
// rebalance by moving items from second tree into first
ULONG avg_size = ( t - > size + next_tree - > size ) / 2 ;
KEY firstitem = { 0 , 0 , 0 } ;
2019-09-01 12:53:20 +00:00
bool changed = false ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
TRACE ( " attempting rebalance \n " ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = next_tree - > itemlist . Flink ;
while ( le ! = & next_tree - > itemlist & & t - > size < avg_size & & next_tree - > header . num_items > 1 ) {
tree_data * td = CONTAINING_RECORD ( le , tree_data , list_entry ) ;
ULONG size ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! td - > ignore ) {
if ( next_tree - > header . level = = 0 )
size = sizeof ( leaf_node ) + td - > size ;
else
size = sizeof ( internal_node ) ;
} else
size = 0 ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( t - > size + size < Vcb - > superblock . node_size - sizeof ( tree_header ) ) {
RemoveEntryList ( & td - > list_entry ) ;
InsertTailList ( & t - > itemlist , & td - > list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( next_tree - > header . level > 0 & & td - > treeholder . tree ) {
td - > treeholder . tree - > parent = t ;
# ifdef DEBUG_PARANOID
if ( td - > treeholder . tree - > parent & & td - > treeholder . tree - > parent - > header . level < = td - > treeholder . tree - > header . level ) int3 ;
# endif
2017-09-08 08:02:43 +00:00
} else if ( next_tree - > header . level = = 0 & & ! td - > inserted & & td - > size > 0 ) {
2019-09-01 12:53:20 +00:00
uint8_t * data = ExAllocatePoolWithTag ( PagedPool , td - > size , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
if ( ! data ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
RtlCopyMemory ( data , td - > data , td - > size ) ;
td - > data = data ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
td - > inserted = true ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! td - > ignore ) {
next_tree - > size - = size ;
t - > size + = size ;
next_tree - > header . num_items - - ;
t - > header . num_items + + ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
changed = true ;
2016-10-29 17:05:10 +00:00
} else
break ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = next_tree - > itemlist . Flink ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le = next_tree - > itemlist . Flink ;
while ( le ! = & next_tree - > itemlist ) {
tree_data * td = CONTAINING_RECORD ( le , tree_data , list_entry ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! td - > ignore ) {
firstitem = td - > key ;
break ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le = le - > Flink ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
// FIXME - once ascension is working, make this work with parent's parent, etc.
if ( next_tree - > paritem )
next_tree - > paritem - > key = firstitem ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
par = next_tree ;
while ( par ) {
2019-09-01 12:53:20 +00:00
par - > write = true ;
2017-01-01 17:12:12 +00:00
par = par - > parent ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( changed )
2019-09-01 12:53:20 +00:00
* done = true ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
return STATUS_SUCCESS ;
}
2019-09-01 12:53:20 +00:00
static NTSTATUS update_extent_level ( device_extension * Vcb , uint64_t address , tree * t , uint8_t level , PIRP Irp ) {
2016-10-29 17:05:10 +00:00
KEY searchkey ;
traverse_ptr tp ;
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( Vcb - > superblock . incompat_flags & BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA ) {
searchkey . obj_id = address ;
searchkey . obj_type = TYPE_METADATA_ITEM ;
searchkey . offset = t - > header . level ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > extent_root , & tp , & searchkey , false , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - find_item returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! keycmp ( tp . item - > key , searchkey ) ) {
EXTENT_ITEM_SKINNY_METADATA * eism ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( tp . item - > size > 0 ) {
eism = ExAllocatePoolWithTag ( PagedPool , tp . item - > size , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! eism ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
RtlCopyMemory ( eism , tp . item - > data , tp . item - > size ) ;
} else
eism = NULL ;
2017-09-08 08:02:43 +00:00
Status = delete_tree_item ( Vcb , & tp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
if ( eism ) ExFreePool ( eism ) ;
return Status ;
}
Status = insert_tree_item ( Vcb , Vcb - > extent_root , address , TYPE_METADATA_ITEM , level , eism , tp . item - > size , NULL , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
if ( eism ) ExFreePool ( eism ) ;
return Status ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
return STATUS_SUCCESS ;
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
searchkey . obj_id = address ;
searchkey . obj_type = TYPE_EXTENT_ITEM ;
searchkey . offset = 0xffffffffffffffff ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > extent_root , & tp , & searchkey , false , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - find_item returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( tp . item - > key . obj_id = = searchkey . obj_id & & tp . item - > key . obj_type = = searchkey . obj_type ) {
EXTENT_ITEM_TREE * eit ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( tp . item - > size < sizeof ( EXTENT_ITEM_TREE ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " (%I64x,%x,%I64x) was %u bytes, expected at least %Iu \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , tp . item - > size , sizeof ( EXTENT_ITEM_TREE ) ) ;
2016-10-29 17:05:10 +00:00
return STATUS_INTERNAL_ERROR ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
eit = ExAllocatePoolWithTag ( PagedPool , tp . item - > size , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! eit ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
RtlCopyMemory ( eit , tp . item - > data , tp . item - > size ) ;
2017-09-08 08:02:43 +00:00
Status = delete_tree_item ( Vcb , & tp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( eit ) ;
return Status ;
}
2016-10-29 17:05:10 +00:00
eit - > level = level ;
2017-09-08 08:02:43 +00:00
Status = insert_tree_item ( Vcb , Vcb - > extent_root , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , eit , tp . item - > size , NULL , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
ExFreePool ( eit ) ;
2017-09-08 08:02:43 +00:00
return Status ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
ERR ( " could not find EXTENT_ITEM for address %I64x \n " , address ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
return STATUS_INTERNAL_ERROR ;
}
2017-01-01 17:12:12 +00:00
static NTSTATUS update_tree_extents_recursive ( device_extension * Vcb , tree * t , PIRP Irp , LIST_ENTRY * rollback ) {
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( t - > parent & & ! t - > parent - > updated_extents & & t - > parent - > has_address ) {
Status = update_tree_extents_recursive ( Vcb , t - > parent , Irp , rollback ) ;
if ( ! NT_SUCCESS ( Status ) )
return Status ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
Status = update_tree_extents ( Vcb , t , Irp , rollback ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " update_tree_extents returned %08lx \n " , Status ) ;
2017-01-01 17:12:12 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
static NTSTATUS do_splits ( device_extension * Vcb , PIRP Irp , LIST_ENTRY * rollback ) {
ULONG level , max_level ;
2022-04-28 19:31:44 +00:00
uint32_t min_size , min_size_fst ;
2019-09-01 12:53:20 +00:00
bool empty , done_deletions = false ;
2016-10-29 17:05:10 +00:00
NTSTATUS Status ;
tree * t ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
TRACE ( " (%p) \n " , Vcb ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
max_level = 0 ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
for ( level = 0 ; level < = 255 ; level + + ) {
LIST_ENTRY * le , * nextle ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
empty = true ;
2017-09-08 08:02:43 +00:00
2020-04-23 02:38:57 +00:00
TRACE ( " doing level %lu \n " , level ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = Vcb - > trees . Flink ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
while ( le ! = & Vcb - > trees ) {
t = CONTAINING_RECORD ( le , tree , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
nextle = le - > Flink ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( t - > write & & t - > header . level = = level ) {
2019-09-01 12:53:20 +00:00
empty = false ;
2017-01-01 17:12:12 +00:00
2017-09-08 08:02:43 +00:00
if ( t - > header . num_items = = 0 ) {
2016-10-29 17:05:10 +00:00
if ( t - > parent ) {
2019-09-01 12:53:20 +00:00
done_deletions = true ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
TRACE ( " deleting tree in root %I64x \n " , t - > root - > id ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
t - > root - > root_item . bytes_used - = Vcb - > superblock . node_size ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( t - > has_new_address ) { // delete associated EXTENT_ITEM
2017-01-01 17:12:12 +00:00
Status = reduce_tree_extent ( Vcb , t - > new_address , t , t - > parent - > header . tree_id , t - > header . level , Irp , rollback ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " reduce_tree_extent returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
t - > has_new_address = false ;
2016-10-29 17:05:10 +00:00
} else if ( t - > has_address ) {
2017-01-01 17:12:12 +00:00
Status = reduce_tree_extent ( Vcb , t - > header . address , t , t - > parent - > header . tree_id , t - > header . level , Irp , rollback ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " reduce_tree_extent returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
t - > has_address = false ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! t - > paritem - > ignore ) {
2019-09-01 12:53:20 +00:00
t - > paritem - > ignore = true ;
2016-10-29 17:05:10 +00:00
t - > parent - > header . num_items - - ;
t - > parent - > size - = sizeof ( internal_node ) ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
RemoveEntryList ( & t - > paritem - > list_entry ) ;
ExFreePool ( t - > paritem ) ;
t - > paritem = NULL ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
free_tree ( t ) ;
} else if ( t - > header . level ! = 0 ) {
if ( t - > has_new_address ) {
2017-09-08 08:02:43 +00:00
Status = update_extent_level ( Vcb , t - > new_address , t , 0 , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " update_extent_level returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
t - > header . level = 0 ;
}
} else if ( t - > size > Vcb - > superblock . node_size - sizeof ( tree_header ) ) {
2020-04-23 02:38:57 +00:00
TRACE ( " splitting overlarge tree (%x > %Ix) \n " , t - > size , Vcb - > superblock . node_size - sizeof ( tree_header ) ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! t - > updated_extents & & t - > has_address ) {
Status = update_tree_extents_recursive ( Vcb , t , Irp , rollback ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " update_tree_extents_recursive returned %08lx \n " , Status ) ;
2017-01-01 17:12:12 +00:00
return Status ;
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
Status = split_tree ( Vcb , t ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " split_tree returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = nextle ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! empty ) {
max_level = level ;
} else {
2020-04-23 02:38:57 +00:00
TRACE ( " nothing found for level %lu \n " , level ) ;
2016-10-29 17:05:10 +00:00
break ;
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
min_size = ( Vcb - > superblock . node_size - sizeof ( tree_header ) ) / 2 ;
2022-04-28 19:31:44 +00:00
min_size_fst = ( Vcb - > superblock . node_size - sizeof ( tree_header ) ) / 4 ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
for ( level = 0 ; level < = max_level ; level + + ) {
LIST_ENTRY * le ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = Vcb - > trees . Flink ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
while ( le ! = & Vcb - > trees ) {
t = CONTAINING_RECORD ( le , tree , list_entry ) ;
2017-09-08 08:02:43 +00:00
2022-04-28 19:31:44 +00:00
if ( t - > write & & t - > header . level = = level & & t - > header . num_items > 0 & & t - > parent & &
( ( t - > size < min_size & & t - > root - > id ! = BTRFS_ROOT_FREE_SPACE ) | | ( t - > size < min_size_fst & & t - > root - > id = = BTRFS_ROOT_FREE_SPACE ) ) & &
is_tree_unique ( Vcb , t , Irp ) ) {
2019-09-01 12:53:20 +00:00
bool done ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
do {
2017-09-08 08:02:43 +00:00
Status = try_tree_amalgamate ( Vcb , t , & done , & done_deletions , Irp , rollback ) ;
2017-01-01 17:12:12 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " try_tree_amalgamate returned %08lx \n " , Status ) ;
2017-01-01 17:12:12 +00:00
return Status ;
}
} while ( done & & t - > size < min_size ) ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = le - > Flink ;
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
// simplify trees if top tree only has one entry
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( done_deletions ) {
for ( level = max_level ; level > 0 ; level - - ) {
LIST_ENTRY * le , * nextle ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = Vcb - > trees . Flink ;
while ( le ! = & Vcb - > trees ) {
nextle = le - > Flink ;
t = CONTAINING_RECORD ( le , tree , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( t - > write & & t - > header . level = = level ) {
if ( ! t - > parent & & t - > header . num_items = = 1 ) {
LIST_ENTRY * le2 = t - > itemlist . Flink ;
2017-09-08 08:02:43 +00:00
tree_data * td = NULL ;
2016-10-29 17:05:10 +00:00
tree * child_tree = NULL ;
while ( le2 ! = & t - > itemlist ) {
td = CONTAINING_RECORD ( le2 , tree_data , list_entry ) ;
if ( ! td - > ignore )
break ;
le2 = le2 - > Flink ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
TRACE ( " deleting top-level tree in root %I64x with one item \n " , t - > root - > id ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( t - > has_new_address ) { // delete associated EXTENT_ITEM
2017-01-01 17:12:12 +00:00
Status = reduce_tree_extent ( Vcb , t - > new_address , t , t - > header . tree_id , t - > header . level , Irp , rollback ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " reduce_tree_extent returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
t - > has_new_address = false ;
2016-10-29 17:05:10 +00:00
} else if ( t - > has_address ) {
2017-01-01 17:12:12 +00:00
Status = reduce_tree_extent ( Vcb , t - > header . address , t , t - > header . tree_id , t - > header . level , Irp , rollback ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " reduce_tree_extent returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
t - > has_address = false ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! td - > treeholder . tree ) { // load first item if not already loaded
KEY searchkey = { 0 , 0 , 0 } ;
traverse_ptr tp ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , t - > root , & tp , & searchkey , false , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - find_item returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
child_tree = td - > treeholder . tree ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( child_tree ) {
child_tree - > parent = NULL ;
child_tree - > paritem = NULL ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
t - > root - > root_item . bytes_used - = Vcb - > superblock . node_size ;
free_tree ( t ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( child_tree )
child_tree - > root - > treeholder . tree = child_tree ;
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = nextle ;
}
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
return STATUS_SUCCESS ;
}
2019-09-01 12:53:20 +00:00
static NTSTATUS remove_root_extents ( device_extension * Vcb , root * r , tree_holder * th , uint8_t level , tree * parent , PIRP Irp , LIST_ENTRY * rollback ) {
2016-10-29 17:05:10 +00:00
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! th - > tree ) {
2019-09-01 12:53:20 +00:00
uint8_t * buf ;
2019-05-11 09:20:02 +00:00
chunk * c ;
buf = ExAllocatePoolWithTag ( PagedPool , Vcb - > superblock . node_size , ALLOC_TAG ) ;
if ( ! buf ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2019-09-01 12:53:20 +00:00
Status = read_data ( Vcb , th - > address , Vcb - > superblock . node_size , NULL , true , buf , NULL ,
& c , Irp , th - > generation , false , NormalPagePriority ) ;
2019-05-11 09:20:02 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " read_data returned 0x%08lx \n " , Status ) ;
2019-05-11 09:20:02 +00:00
ExFreePool ( buf ) ;
return Status ;
}
Status = load_tree ( Vcb , th - > address , buf , r , & th - > tree ) ;
if ( ! th - > tree | | th - > tree - > buf ! = buf )
ExFreePool ( buf ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " load_tree(%I64x) returned %08lx \n " , th - > address , Status ) ;
2017-01-01 17:12:12 +00:00
return Status ;
2016-10-29 17:05:10 +00:00
}
2017-01-01 17:12:12 +00:00
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( level > 0 ) {
LIST_ENTRY * le = th - > tree - > itemlist . Flink ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
while ( le ! = & th - > tree - > itemlist ) {
tree_data * td = CONTAINING_RECORD ( le , tree_data , list_entry ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! td - > ignore ) {
Status = remove_root_extents ( Vcb , r , & td - > treeholder , th - > tree - > header . level - 1 , th - > tree , Irp , rollback ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " remove_root_extents returned %08lx \n " , Status ) ;
2017-01-01 17:12:12 +00:00
return Status ;
2016-10-29 17:05:10 +00:00
}
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le = le - > Flink ;
}
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( th - > tree & & ! th - > tree - > updated_extents & & th - > tree - > has_address ) {
Status = update_tree_extents ( Vcb , th - > tree , Irp , rollback ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " update_tree_extents returned %08lx \n " , Status ) ;
2017-01-01 17:12:12 +00:00
return Status ;
2016-10-29 17:05:10 +00:00
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! th - > tree | | th - > tree - > has_address ) {
2017-01-01 17:12:12 +00:00
Status = reduce_tree_extent ( Vcb , th - > address , NULL , parent ? parent - > header . tree_id : r - > id , level , Irp , rollback ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " reduce_tree_extent(%I64x) returned %08lx \n " , th - > address , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
return STATUS_SUCCESS ;
}
static NTSTATUS drop_root ( device_extension * Vcb , root * r , PIRP Irp , LIST_ENTRY * rollback ) {
NTSTATUS Status ;
KEY searchkey ;
traverse_ptr tp ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
Status = remove_root_extents ( Vcb , r , & r - > treeholder , r - > root_item . root_level , NULL , Irp , rollback ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " remove_root_extents returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
// remove entries in uuid root (tree 9)
2016-10-29 17:05:10 +00:00
if ( Vcb - > uuid_root ) {
2019-09-01 12:53:20 +00:00
RtlCopyMemory ( & searchkey . obj_id , & r - > root_item . uuid . uuid [ 0 ] , sizeof ( uint64_t ) ) ;
2016-10-29 17:05:10 +00:00
searchkey . obj_type = TYPE_SUBVOL_UUID ;
2019-09-01 12:53:20 +00:00
RtlCopyMemory ( & searchkey . offset , & r - > root_item . uuid . uuid [ sizeof ( uint64_t ) ] , sizeof ( uint64_t ) ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( searchkey . obj_id ! = 0 | | searchkey . offset ! = 0 ) {
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > uuid_root , & tp , & searchkey , false , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
WARN ( " find_item returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
} else {
2017-09-08 08:02:43 +00:00
if ( ! keycmp ( tp . item - > key , searchkey ) ) {
Status = delete_tree_item ( Vcb , & tp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
} else
2019-09-01 12:53:20 +00:00
WARN ( " could not find (%I64x,%x,%I64x) in uuid tree \n " , searchkey . obj_id , searchkey . obj_type , searchkey . offset ) ;
2017-09-08 08:02:43 +00:00
}
}
if ( r - > root_item . rtransid > 0 ) {
2019-09-01 12:53:20 +00:00
RtlCopyMemory ( & searchkey . obj_id , & r - > root_item . received_uuid . uuid [ 0 ] , sizeof ( uint64_t ) ) ;
2017-09-08 08:02:43 +00:00
searchkey . obj_type = TYPE_SUBVOL_REC_UUID ;
2019-09-01 12:53:20 +00:00
RtlCopyMemory ( & searchkey . offset , & r - > root_item . received_uuid . uuid [ sizeof ( uint64_t ) ] , sizeof ( uint64_t ) ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > uuid_root , & tp , & searchkey , false , Irp ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) )
2020-04-23 02:38:57 +00:00
WARN ( " find_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
else {
if ( ! keycmp ( tp . item - > key , searchkey ) ) {
2019-09-01 12:53:20 +00:00
if ( tp . item - > size = = sizeof ( uint64_t ) ) {
uint64_t * id = ( uint64_t * ) tp . item - > data ;
2017-09-08 08:02:43 +00:00
if ( * id = = r - > id ) {
Status = delete_tree_item ( Vcb , & tp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
}
2019-09-01 12:53:20 +00:00
} else if ( tp . item - > size > sizeof ( uint64_t ) ) {
2017-09-08 08:02:43 +00:00
ULONG i ;
2019-09-01 12:53:20 +00:00
uint64_t * ids = ( uint64_t * ) tp . item - > data ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
for ( i = 0 ; i < tp . item - > size / sizeof ( uint64_t ) ; i + + ) {
2017-09-08 08:02:43 +00:00
if ( ids [ i ] = = r - > id ) {
2019-09-01 12:53:20 +00:00
uint64_t * ne ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
ne = ExAllocatePoolWithTag ( PagedPool , tp . item - > size - sizeof ( uint64_t ) , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
if ( ! ne ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
if ( i > 0 )
2019-09-01 12:53:20 +00:00
RtlCopyMemory ( ne , ids , sizeof ( uint64_t ) * i ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
if ( ( i + 1 ) * sizeof ( uint64_t ) < tp . item - > size )
RtlCopyMemory ( & ne [ i ] , & ids [ i + 1 ] , tp . item - > size - ( ( i + 1 ) * sizeof ( uint64_t ) ) ) ;
2017-09-08 08:02:43 +00:00
Status = delete_tree_item ( Vcb , & tp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( ne ) ;
return Status ;
}
Status = insert_tree_item ( Vcb , Vcb - > uuid_root , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset ,
2019-09-01 12:53:20 +00:00
ne , tp . item - > size - sizeof ( uint64_t ) , NULL , Irp ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( ne ) ;
return Status ;
}
break ;
}
}
}
} else
2019-09-01 12:53:20 +00:00
WARN ( " could not find (%I64x,%x,%I64x) in uuid tree \n " , searchkey . obj_id , searchkey . obj_type , searchkey . offset ) ;
2016-10-29 17:05:10 +00:00
}
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
// delete ROOT_ITEM
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
searchkey . obj_id = r - > id ;
searchkey . obj_type = TYPE_ROOT_ITEM ;
searchkey . offset = 0xffffffffffffffff ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > root_root , & tp , & searchkey , false , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " find_item returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
if ( tp . item - > key . obj_id = = searchkey . obj_id & & tp . item - > key . obj_type = = searchkey . obj_type ) {
Status = delete_tree_item ( Vcb , & tp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
} else
2019-09-01 12:53:20 +00:00
WARN ( " could not find (%I64x,%x,%I64x) in root_root \n " , searchkey . obj_id , searchkey . obj_type , searchkey . offset ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
// delete items in tree cache
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
free_trees_root ( Vcb , r ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
return STATUS_SUCCESS ;
}
static NTSTATUS drop_roots ( device_extension * Vcb , PIRP Irp , LIST_ENTRY * rollback ) {
LIST_ENTRY * le = Vcb - > drop_roots . Flink , * le2 ;
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
while ( le ! = & Vcb - > drop_roots ) {
root * r = CONTAINING_RECORD ( le , root , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le2 = le - > Flink ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
Status = drop_root ( Vcb , r , Irp , rollback ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " drop_root(%I64x) returned %08lx \n " , r - > id , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = le2 ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
NTSTATUS update_dev_item ( device_extension * Vcb , device * device , PIRP Irp ) {
2016-10-29 17:05:10 +00:00
KEY searchkey ;
traverse_ptr tp ;
DEV_ITEM * di ;
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
searchkey . obj_id = 1 ;
searchkey . obj_type = TYPE_DEV_ITEM ;
searchkey . offset = device - > devitem . dev_id ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > chunk_root , & tp , & searchkey , false , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - find_item returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( keycmp ( tp . item - > key , searchkey ) ) {
2019-09-01 12:53:20 +00:00
ERR ( " error - could not find DEV_ITEM for device %I64x \n " , device - > devitem . dev_id ) ;
2016-10-29 17:05:10 +00:00
return STATUS_INTERNAL_ERROR ;
}
2017-09-08 08:02:43 +00:00
Status = delete_tree_item ( Vcb , & tp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
2016-10-29 17:05:10 +00:00
di = ExAllocatePoolWithTag ( PagedPool , sizeof ( DEV_ITEM ) , ALLOC_TAG ) ;
if ( ! di ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
RtlCopyMemory ( di , & device - > devitem , sizeof ( DEV_ITEM ) ) ;
2017-09-08 08:02:43 +00:00
Status = insert_tree_item ( Vcb , Vcb - > chunk_root , 1 , TYPE_DEV_ITEM , device - > devitem . dev_id , di , sizeof ( DEV_ITEM ) , NULL , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( di ) ;
return Status ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
return STATUS_SUCCESS ;
}
static void regen_bootstrap ( device_extension * Vcb ) {
sys_chunk * sc2 ;
USHORT i = 0 ;
LIST_ENTRY * le ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
i = 0 ;
le = Vcb - > sys_chunks . Flink ;
while ( le ! = & Vcb - > sys_chunks ) {
sc2 = CONTAINING_RECORD ( le , sys_chunk , list_entry ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
TRACE ( " %I64x,%x,%I64x \n " , sc2 - > key . obj_id , sc2 - > key . obj_type , sc2 - > key . offset ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
RtlCopyMemory ( & Vcb - > superblock . sys_chunk_array [ i ] , & sc2 - > key , sizeof ( KEY ) ) ;
i + = sizeof ( KEY ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
RtlCopyMemory ( & Vcb - > superblock . sys_chunk_array [ i ] , sc2 - > data , sc2 - > size ) ;
i + = sc2 - > size ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = le - > Flink ;
}
}
2019-09-01 12:53:20 +00:00
static NTSTATUS add_to_bootstrap ( device_extension * Vcb , uint64_t obj_id , uint8_t obj_type , uint64_t offset , void * data , uint16_t size ) {
2017-09-08 08:02:43 +00:00
sys_chunk * sc ;
2016-10-29 17:05:10 +00:00
LIST_ENTRY * le ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( Vcb - > superblock . n + sizeof ( KEY ) + size > SYS_CHUNK_ARRAY_SIZE ) {
ERR ( " error - bootstrap is full \n " ) ;
return STATUS_INTERNAL_ERROR ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
sc = ExAllocatePoolWithTag ( PagedPool , sizeof ( sys_chunk ) , ALLOC_TAG ) ;
if ( ! sc ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
sc - > key . obj_id = obj_id ;
sc - > key . obj_type = obj_type ;
sc - > key . offset = offset ;
sc - > size = size ;
sc - > data = ExAllocatePoolWithTag ( PagedPool , sc - > size , ALLOC_TAG ) ;
if ( ! sc - > data ) {
ERR ( " out of memory \n " ) ;
ExFreePool ( sc ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
RtlCopyMemory ( sc - > data , data , sc - > size ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = Vcb - > sys_chunks . Flink ;
while ( le ! = & Vcb - > sys_chunks ) {
2017-09-08 08:02:43 +00:00
sys_chunk * sc2 = CONTAINING_RECORD ( le , sys_chunk , list_entry ) ;
2016-10-29 17:05:10 +00:00
if ( keycmp ( sc2 - > key , sc - > key ) = = 1 )
break ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = le - > Flink ;
}
InsertTailList ( le , & sc - > list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
Vcb - > superblock . n + = sizeof ( KEY ) + size ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
regen_bootstrap ( Vcb ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
static NTSTATUS create_chunk ( device_extension * Vcb , chunk * c , PIRP Irp ) {
2016-10-29 17:05:10 +00:00
CHUNK_ITEM * ci ;
CHUNK_ITEM_STRIPE * cis ;
BLOCK_GROUP_ITEM * bgi ;
2019-09-01 12:53:20 +00:00
uint16_t i , factor ;
2016-10-29 17:05:10 +00:00
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ci = ExAllocatePoolWithTag ( PagedPool , c - > size , ALLOC_TAG ) ;
if ( ! ci ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
RtlCopyMemory ( ci , c - > chunk_item , c - > size ) ;
2017-09-08 08:02:43 +00:00
Status = insert_tree_item ( Vcb , Vcb - > chunk_root , 0x100 , TYPE_CHUNK_ITEM , c - > offset , ci , c - > size , NULL , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2016-10-29 17:05:10 +00:00
ERR ( " insert_tree_item failed \n " ) ;
ExFreePool ( ci ) ;
2017-09-08 08:02:43 +00:00
return Status ;
2016-10-29 17:05:10 +00:00
}
if ( c - > chunk_item - > type & BLOCK_FLAG_SYSTEM ) {
Status = add_to_bootstrap ( Vcb , 0x100 , TYPE_CHUNK_ITEM , c - > offset , ci , c - > size ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " add_to_bootstrap returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
}
// add BLOCK_GROUP_ITEM to tree 2
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
bgi = ExAllocatePoolWithTag ( PagedPool , sizeof ( BLOCK_GROUP_ITEM ) , ALLOC_TAG ) ;
if ( ! bgi ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
bgi - > used = c - > used ;
bgi - > chunk_tree = 0x100 ;
bgi - > flags = c - > chunk_item - > type ;
2017-09-08 08:02:43 +00:00
Status = insert_tree_item ( Vcb , Vcb - > extent_root , c - > offset , TYPE_BLOCK_GROUP_ITEM , c - > chunk_item - > size , bgi , sizeof ( BLOCK_GROUP_ITEM ) , NULL , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2016-10-29 17:05:10 +00:00
ERR ( " insert_tree_item failed \n " ) ;
ExFreePool ( bgi ) ;
2017-09-08 08:02:43 +00:00
return Status ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( c - > chunk_item - > type & BLOCK_FLAG_RAID0 )
factor = c - > chunk_item - > num_stripes ;
else if ( c - > chunk_item - > type & BLOCK_FLAG_RAID10 )
factor = c - > chunk_item - > num_stripes / c - > chunk_item - > sub_stripes ;
else if ( c - > chunk_item - > type & BLOCK_FLAG_RAID5 )
factor = c - > chunk_item - > num_stripes - 1 ;
else if ( c - > chunk_item - > type & BLOCK_FLAG_RAID6 )
factor = c - > chunk_item - > num_stripes - 2 ;
2020-04-23 02:38:57 +00:00
else // SINGLE, DUPLICATE, RAID1, RAID1C3, RAID1C4
2016-10-29 17:05:10 +00:00
factor = 1 ;
// add DEV_EXTENTs to tree 4
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
cis = ( CHUNK_ITEM_STRIPE * ) & c - > chunk_item [ 1 ] ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
for ( i = 0 ; i < c - > chunk_item - > num_stripes ; i + + ) {
DEV_EXTENT * de ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
de = ExAllocatePoolWithTag ( PagedPool , sizeof ( DEV_EXTENT ) , ALLOC_TAG ) ;
if ( ! de ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
de - > chunktree = Vcb - > chunk_root - > id ;
de - > objid = 0x100 ;
de - > address = c - > offset ;
de - > length = c - > chunk_item - > size / factor ;
de - > chunktree_uuid = Vcb - > chunk_root - > treeholder . tree - > header . chunk_tree_uuid ;
2017-09-08 08:02:43 +00:00
Status = insert_tree_item ( Vcb , Vcb - > dev_root , c - > devices [ i ] - > devitem . dev_id , TYPE_DEV_EXTENT , cis [ i ] . offset , de , sizeof ( DEV_EXTENT ) , NULL , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
ExFreePool ( de ) ;
2017-09-08 08:02:43 +00:00
return Status ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
// FIXME - no point in calling this twice for the same device
2017-09-08 08:02:43 +00:00
Status = update_dev_item ( Vcb , c - > devices [ i ] , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " update_dev_item returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
c - > created = false ;
2019-05-11 09:20:02 +00:00
c - > oldused = c - > used ;
2017-09-08 08:02:43 +00:00
2022-04-28 19:37:02 +00:00
Vcb - > superblock . bytes_used + = c - > used ;
2019-06-11 10:35:19 +00:00
2016-10-29 17:05:10 +00:00
return STATUS_SUCCESS ;
}
2019-09-01 12:53:20 +00:00
static void remove_from_bootstrap ( device_extension * Vcb , uint64_t obj_id , uint8_t obj_type , uint64_t offset ) {
2016-10-29 17:05:10 +00:00
sys_chunk * sc2 ;
LIST_ENTRY * le ;
le = Vcb - > sys_chunks . Flink ;
while ( le ! = & Vcb - > sys_chunks ) {
sc2 = CONTAINING_RECORD ( le , sys_chunk , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( sc2 - > key . obj_id = = obj_id & & sc2 - > key . obj_type = = obj_type & & sc2 - > key . offset = = offset ) {
RemoveEntryList ( & sc2 - > list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
Vcb - > superblock . n - = sizeof ( KEY ) + sc2 - > size ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ExFreePool ( sc2 - > data ) ;
ExFreePool ( sc2 ) ;
regen_bootstrap ( Vcb ) ;
return ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = le - > Flink ;
}
}
2019-09-01 12:53:20 +00:00
static NTSTATUS set_xattr ( device_extension * Vcb , LIST_ENTRY * batchlist , root * subvol , uint64_t inode , char * name , uint16_t namelen ,
uint32_t crc32 , uint8_t * data , uint16_t datalen ) {
2017-09-08 08:02:43 +00:00
NTSTATUS Status ;
2019-09-01 12:53:20 +00:00
uint16_t xasize ;
2016-10-29 17:05:10 +00:00
DIR_ITEM * xa ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
TRACE ( " (%p, %I64x, %I64x, %.*s, %08x, %p, %u) \n " , Vcb , subvol - > id , inode , namelen , name , crc32 , data , datalen ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
xasize = ( uint16_t ) offsetof ( DIR_ITEM , name [ 0 ] ) + namelen + datalen ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
xa = ExAllocatePoolWithTag ( PagedPool , xasize , ALLOC_TAG ) ;
if ( ! xa ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
xa - > key . obj_id = 0 ;
xa - > key . obj_type = 0 ;
xa - > key . offset = 0 ;
xa - > transid = Vcb - > superblock . generation ;
xa - > m = datalen ;
2017-09-08 08:02:43 +00:00
xa - > n = namelen ;
2016-10-29 17:05:10 +00:00
xa - > type = BTRFS_TYPE_EA ;
2017-09-08 08:02:43 +00:00
RtlCopyMemory ( xa - > name , name , namelen ) ;
RtlCopyMemory ( xa - > name + namelen , data , datalen ) ;
Status = insert_tree_item_batch ( batchlist , Vcb , subvol , inode , TYPE_XATTR_ITEM , crc32 , xa , xasize , Batch_SetXattr ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item_batch returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( xa ) ;
return Status ;
}
2016-10-29 17:05:10 +00:00
return STATUS_SUCCESS ;
}
2019-09-01 12:53:20 +00:00
static NTSTATUS delete_xattr ( device_extension * Vcb , LIST_ENTRY * batchlist , root * subvol , uint64_t inode , char * name ,
uint16_t namelen , uint32_t crc32 ) {
2016-10-29 17:05:10 +00:00
NTSTATUS Status ;
2019-09-01 12:53:20 +00:00
uint16_t xasize ;
2017-09-08 08:02:43 +00:00
DIR_ITEM * xa ;
2016-10-29 17:05:10 +00:00
2019-09-01 12:53:20 +00:00
TRACE ( " (%p, %I64x, %I64x, %.*s, %08x) \n " , Vcb , subvol - > id , inode , namelen , name , crc32 ) ;
2016-10-29 17:05:10 +00:00
2019-09-01 12:53:20 +00:00
xasize = ( uint16_t ) offsetof ( DIR_ITEM , name [ 0 ] ) + namelen ;
2016-10-29 17:05:10 +00:00
2017-09-08 08:02:43 +00:00
xa = ExAllocatePoolWithTag ( PagedPool , xasize , ALLOC_TAG ) ;
if ( ! xa ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
xa - > key . obj_id = 0 ;
xa - > key . obj_type = 0 ;
xa - > key . offset = 0 ;
xa - > transid = Vcb - > superblock . generation ;
xa - > m = 0 ;
xa - > n = namelen ;
xa - > type = BTRFS_TYPE_EA ;
RtlCopyMemory ( xa - > name , name , namelen ) ;
Status = insert_tree_item_batch ( batchlist , Vcb , subvol , inode , TYPE_XATTR_ITEM , crc32 , xa , xasize , Batch_DeleteXattr ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item_batch returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( xa ) ;
return Status ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
return STATUS_SUCCESS ;
2016-10-29 17:05:10 +00:00
}
2019-09-01 12:53:20 +00:00
static NTSTATUS insert_sparse_extent ( fcb * fcb , LIST_ENTRY * batchlist , uint64_t start , uint64_t length ) {
2017-09-08 08:02:43 +00:00
NTSTATUS Status ;
2016-10-29 17:05:10 +00:00
EXTENT_DATA * ed ;
EXTENT_DATA2 * ed2 ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
TRACE ( " ((%I64x, %I64x), %I64x, %I64x) \n " , fcb - > subvol - > id , fcb - > inode , start , length ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ed = ExAllocatePoolWithTag ( PagedPool , sizeof ( EXTENT_DATA ) - 1 + sizeof ( EXTENT_DATA2 ) , ALLOC_TAG ) ;
if ( ! ed ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ed - > generation = fcb - > Vcb - > superblock . generation ;
ed - > decoded_size = length ;
ed - > compression = BTRFS_COMPRESSION_NONE ;
ed - > encryption = BTRFS_ENCRYPTION_NONE ;
ed - > encoding = BTRFS_ENCODING_NONE ;
ed - > type = EXTENT_TYPE_REGULAR ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ed2 = ( EXTENT_DATA2 * ) ed - > data ;
ed2 - > address = 0 ;
ed2 - > size = 0 ;
ed2 - > offset = 0 ;
ed2 - > num_bytes = length ;
2017-09-08 08:02:43 +00:00
Status = insert_tree_item_batch ( batchlist , fcb - > Vcb , fcb - > subvol , fcb - > inode , TYPE_EXTENT_DATA , start , ed , sizeof ( EXTENT_DATA ) - 1 + sizeof ( EXTENT_DATA2 ) , Batch_Insert ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item_batch returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( ed ) ;
return Status ;
2016-10-29 17:05:10 +00:00
}
return STATUS_SUCCESS ;
}
2022-09-28 16:08:10 +00:00
static NTSTATUS split_batch_item_list ( batch_item_ind * bii ) {
LIST_ENTRY * le ;
unsigned int i = 0 ;
LIST_ENTRY * midpoint = NULL ;
batch_item_ind * bii2 ;
batch_item * midpoint_item ;
LIST_ENTRY * before_midpoint ;
le = bii - > items . Flink ;
while ( le ! = & bii - > items ) {
if ( i > = bii - > num_items / 2 ) {
midpoint = le ;
break ;
}
i + + ;
le = le - > Flink ;
}
if ( ! midpoint )
return STATUS_SUCCESS ;
// make sure items on either side of split don't have same key
while ( midpoint - > Blink ! = & bii - > items ) {
batch_item * item = CONTAINING_RECORD ( midpoint , batch_item , list_entry ) ;
batch_item * prev = CONTAINING_RECORD ( midpoint - > Blink , batch_item , list_entry ) ;
if ( item - > key . obj_id ! = prev - > key . obj_id )
break ;
if ( item - > key . obj_type ! = prev - > key . obj_type )
break ;
if ( item - > key . offset ! = prev - > key . offset )
break ;
midpoint = midpoint - > Blink ;
i - - ;
}
if ( midpoint - > Blink = = & bii - > items )
return STATUS_SUCCESS ;
bii2 = ExAllocatePoolWithTag ( PagedPool , sizeof ( batch_item_ind ) , ALLOC_TAG ) ;
if ( ! bii2 ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
midpoint_item = CONTAINING_RECORD ( midpoint , batch_item , list_entry ) ;
bii2 - > key . obj_id = midpoint_item - > key . obj_id ;
bii2 - > key . obj_type = midpoint_item - > key . obj_type ;
bii2 - > key . offset = midpoint_item - > key . offset ;
bii2 - > num_items = bii - > num_items - i ;
bii - > num_items = i ;
before_midpoint = midpoint - > Blink ;
bii2 - > items . Flink = midpoint ;
midpoint - > Blink = & bii2 - > items ;
bii2 - > items . Blink = bii - > items . Blink ;
bii - > items . Blink - > Flink = & bii2 - > items ;
bii - > items . Blink = before_midpoint ;
before_midpoint - > Flink = & bii - > items ;
InsertHeadList ( & bii - > list_entry , & bii2 - > list_entry ) ;
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
# ifdef _MSC_VER
# pragma warning(push)
# pragma warning(suppress: 28194)
# endif
2022-09-28 16:08:10 +00:00
static NTSTATUS insert_tree_item_batch ( LIST_ENTRY * batchlist , device_extension * Vcb , root * r , uint64_t objid ,
uint8_t objtype , uint64_t offset , _In_opt_ _When_ ( return > = 0 , __drv_aliasesMem ) void * data ,
uint16_t datalen , enum batch_operation operation ) {
2016-10-29 17:05:10 +00:00
LIST_ENTRY * le ;
batch_root * br = NULL ;
batch_item * bi ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = batchlist - > Flink ;
while ( le ! = batchlist ) {
batch_root * br2 = CONTAINING_RECORD ( le , batch_root , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( br2 - > r = = r ) {
br = br2 ;
break ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = le - > Flink ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! br ) {
br = ExAllocatePoolWithTag ( PagedPool , sizeof ( batch_root ) , ALLOC_TAG ) ;
if ( ! br ) {
ERR ( " out of memory \n " ) ;
2017-09-08 08:02:43 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
br - > r = r ;
2022-09-28 16:08:10 +00:00
InitializeListHead ( & br - > items_ind ) ;
2016-10-29 17:05:10 +00:00
InsertTailList ( batchlist , & br - > list_entry ) ;
}
2017-09-08 08:02:43 +00:00
2022-09-28 16:08:10 +00:00
if ( IsListEmpty ( & br - > items_ind ) ) {
batch_item_ind * bii ;
bii = ExAllocatePoolWithTag ( PagedPool , sizeof ( batch_item_ind ) , ALLOC_TAG ) ;
if ( ! bii ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
bii - > key . obj_id = 0 ;
bii - > key . obj_type = 0 ;
bii - > key . offset = 0 ;
InitializeListHead ( & bii - > items ) ;
bii - > num_items = 0 ;
InsertTailList ( & br - > items_ind , & bii - > list_entry ) ;
}
2016-10-29 17:05:10 +00:00
bi = ExAllocateFromPagedLookasideList ( & Vcb - > batch_item_lookaside ) ;
if ( ! bi ) {
ERR ( " out of memory \n " ) ;
2017-09-08 08:02:43 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
bi - > key . obj_id = objid ;
bi - > key . obj_type = objtype ;
bi - > key . offset = offset ;
bi - > data = data ;
bi - > datalen = datalen ;
bi - > operation = operation ;
2017-09-08 08:02:43 +00:00
2022-09-28 16:08:10 +00:00
le = br - > items_ind . Blink ;
while ( le ! = & br - > items_ind ) {
LIST_ENTRY * le2 ;
batch_item_ind * bii = CONTAINING_RECORD ( le , batch_item_ind , list_entry ) ;
2017-09-08 08:02:43 +00:00
2022-09-28 16:08:10 +00:00
if ( keycmp ( bii - > key , bi - > key ) = = 1 ) {
le = le - > Blink ;
continue ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2022-09-28 16:08:10 +00:00
le2 = bii - > items . Blink ;
while ( le2 ! = & bii - > items ) {
batch_item * bi2 = CONTAINING_RECORD ( le2 , batch_item , list_entry ) ;
int cmp = keycmp ( bi2 - > key , bi - > key ) ;
if ( cmp = = - 1 | | ( cmp = = 0 & & bi - > operation > = bi2 - > operation ) ) {
InsertHeadList ( & bi2 - > list_entry , & bi - > list_entry ) ;
bii - > num_items + + ;
goto end ;
}
2017-09-08 08:02:43 +00:00
2022-09-28 16:08:10 +00:00
le2 = le2 - > Blink ;
}
2017-09-08 08:02:43 +00:00
2022-09-28 16:08:10 +00:00
InsertHeadList ( & bii - > items , & bi - > list_entry ) ;
bii - > num_items + + ;
end :
if ( bii - > num_items > BATCH_ITEM_LIMIT )
return split_batch_item_list ( bii ) ;
return STATUS_SUCCESS ;
}
return STATUS_INTERNAL_ERROR ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
# ifdef _MSC_VER
# pragma warning(pop)
# endif
2016-10-29 17:05:10 +00:00
typedef struct {
2019-09-01 12:53:20 +00:00
uint64_t address ;
uint64_t length ;
uint64_t offset ;
bool changed ;
2016-10-29 17:05:10 +00:00
chunk * chunk ;
2019-09-01 12:53:20 +00:00
uint64_t skip_start ;
uint64_t skip_end ;
2016-10-29 17:05:10 +00:00
LIST_ENTRY list_entry ;
} extent_range ;
2017-09-08 08:02:43 +00:00
static void rationalize_extents ( fcb * fcb , PIRP Irp ) {
2016-10-29 17:05:10 +00:00
LIST_ENTRY * le ;
LIST_ENTRY extent_ranges ;
extent_range * er ;
2019-09-01 12:53:20 +00:00
bool changed = false , truncating = false ;
uint32_t num_extents = 0 ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
InitializeListHead ( & extent_ranges ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = fcb - > extents . Flink ;
while ( le ! = & fcb - > extents ) {
extent * ext = CONTAINING_RECORD ( le , extent , list_entry ) ;
2017-09-08 08:02:43 +00:00
if ( ( ext - > extent_data . type = = EXTENT_TYPE_REGULAR | | ext - > extent_data . type = = EXTENT_TYPE_PREALLOC ) & & ext - > extent_data . compression = = BTRFS_COMPRESSION_NONE & & ext - > unique ) {
EXTENT_DATA2 * ed2 = ( EXTENT_DATA2 * ) ext - > extent_data . data ;
2016-10-29 17:05:10 +00:00
if ( ed2 - > size ! = 0 ) {
LIST_ENTRY * le2 ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le2 = extent_ranges . Flink ;
while ( le2 ! = & extent_ranges ) {
extent_range * er2 = CONTAINING_RECORD ( le2 , extent_range , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( er2 - > address = = ed2 - > address ) {
er2 - > skip_start = min ( er2 - > skip_start , ed2 - > offset ) ;
er2 - > skip_end = min ( er2 - > skip_end , ed2 - > size - ed2 - > offset - ed2 - > num_bytes ) ;
goto cont ;
} else if ( er2 - > address > ed2 - > address )
break ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le2 = le2 - > Flink ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
er = ExAllocatePoolWithTag ( PagedPool , sizeof ( extent_range ) , ALLOC_TAG ) ; // FIXME - should be from lookaside?
if ( ! er ) {
ERR ( " out of memory \n " ) ;
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
er - > address = ed2 - > address ;
er - > length = ed2 - > size ;
er - > offset = ext - > offset - ed2 - > offset ;
2019-09-01 12:53:20 +00:00
er - > changed = false ;
2016-10-29 17:05:10 +00:00
er - > chunk = NULL ;
er - > skip_start = ed2 - > offset ;
er - > skip_end = ed2 - > size - ed2 - > offset - ed2 - > num_bytes ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( er - > skip_start ! = 0 | | er - > skip_end ! = 0 )
2019-09-01 12:53:20 +00:00
truncating = true ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
InsertHeadList ( le2 - > Blink , & er - > list_entry ) ;
num_extents + + ;
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
cont :
le = le - > Flink ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( num_extents = = 0 | | ( num_extents = = 1 & & ! truncating ) )
goto end ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = extent_ranges . Flink ;
while ( le ! = & extent_ranges ) {
er = CONTAINING_RECORD ( le , extent_range , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! er - > chunk ) {
LIST_ENTRY * le2 ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
er - > chunk = get_chunk_from_address ( fcb - > Vcb , er - > address ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! er - > chunk ) {
2019-09-01 12:53:20 +00:00
ERR ( " get_chunk_from_address(%I64x) failed \n " , er - > address ) ;
2016-10-29 17:05:10 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le2 = le - > Flink ;
while ( le2 ! = & extent_ranges ) {
extent_range * er2 = CONTAINING_RECORD ( le2 , extent_range , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! er2 - > chunk & & er2 - > address > = er - > chunk - > offset & & er2 - > address < er - > chunk - > offset + er - > chunk - > chunk_item - > size )
er2 - > chunk = er - > chunk ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le2 = le2 - > Flink ;
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = le - > Flink ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( truncating ) {
// truncate beginning or end of extent if unused
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = extent_ranges . Flink ;
while ( le ! = & extent_ranges ) {
er = CONTAINING_RECORD ( le , extent_range , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( er - > skip_start > 0 ) {
LIST_ENTRY * le2 = fcb - > extents . Flink ;
while ( le2 ! = & fcb - > extents ) {
extent * ext = CONTAINING_RECORD ( le2 , extent , list_entry ) ;
2017-09-08 08:02:43 +00:00
if ( ( ext - > extent_data . type = = EXTENT_TYPE_REGULAR | | ext - > extent_data . type = = EXTENT_TYPE_PREALLOC ) & & ext - > extent_data . compression = = BTRFS_COMPRESSION_NONE & & ext - > unique ) {
EXTENT_DATA2 * ed2 = ( EXTENT_DATA2 * ) ext - > extent_data . data ;
2016-10-29 17:05:10 +00:00
if ( ed2 - > size ! = 0 & & ed2 - > address = = er - > address ) {
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
Status = update_changed_extent_ref ( fcb - > Vcb , er - > chunk , ed2 - > address , ed2 - > size , fcb - > subvol - > id , fcb - > inode , ext - > offset - ed2 - > offset ,
2019-09-01 12:53:20 +00:00
- 1 , fcb - > inode_item . flags & BTRFS_INODE_NODATASUM , true , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " update_changed_extent_ref returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
ext - > extent_data . decoded_size - = er - > skip_start ;
2016-10-29 17:05:10 +00:00
ed2 - > size - = er - > skip_start ;
ed2 - > address + = er - > skip_start ;
ed2 - > offset - = er - > skip_start ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
add_changed_extent_ref ( er - > chunk , ed2 - > address , ed2 - > size , fcb - > subvol - > id , fcb - > inode , ext - > offset - ed2 - > offset ,
1 , fcb - > inode_item . flags & BTRFS_INODE_NODATASUM ) ;
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le2 = le2 - > Flink ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! ( fcb - > inode_item . flags & BTRFS_INODE_NODATASUM ) )
2022-04-28 19:31:44 +00:00
add_checksum_entry ( fcb - > Vcb , er - > address , ( ULONG ) ( er - > skip_start > > fcb - > Vcb - > sector_shift ) , NULL , NULL ) ;
2017-09-08 08:02:43 +00:00
2018-12-16 11:03:16 +00:00
acquire_chunk_lock ( er - > chunk , fcb - > Vcb ) ;
2017-09-08 08:02:43 +00:00
if ( ! er - > chunk - > cache_loaded ) {
NTSTATUS Status = load_cache_chunk ( fcb - > Vcb , er - > chunk , NULL ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " load_cache_chunk returned %08lx \n " , Status ) ;
2018-12-16 11:03:16 +00:00
release_chunk_lock ( er - > chunk , fcb - > Vcb ) ;
2017-09-08 08:02:43 +00:00
goto end ;
}
}
er - > chunk - > used - = er - > skip_start ;
space_list_add ( er - > chunk , er - > address , er - > skip_start , NULL ) ;
2018-12-16 11:03:16 +00:00
release_chunk_lock ( er - > chunk , fcb - > Vcb ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
er - > address + = er - > skip_start ;
er - > length - = er - > skip_start ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( er - > skip_end > 0 ) {
LIST_ENTRY * le2 = fcb - > extents . Flink ;
while ( le2 ! = & fcb - > extents ) {
extent * ext = CONTAINING_RECORD ( le2 , extent , list_entry ) ;
2017-09-08 08:02:43 +00:00
if ( ( ext - > extent_data . type = = EXTENT_TYPE_REGULAR | | ext - > extent_data . type = = EXTENT_TYPE_PREALLOC ) & & ext - > extent_data . compression = = BTRFS_COMPRESSION_NONE & & ext - > unique ) {
EXTENT_DATA2 * ed2 = ( EXTENT_DATA2 * ) ext - > extent_data . data ;
2016-10-29 17:05:10 +00:00
if ( ed2 - > size ! = 0 & & ed2 - > address = = er - > address ) {
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
Status = update_changed_extent_ref ( fcb - > Vcb , er - > chunk , ed2 - > address , ed2 - > size , fcb - > subvol - > id , fcb - > inode , ext - > offset - ed2 - > offset ,
2019-09-01 12:53:20 +00:00
- 1 , fcb - > inode_item . flags & BTRFS_INODE_NODATASUM , true , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " update_changed_extent_ref returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
ext - > extent_data . decoded_size - = er - > skip_end ;
2016-10-29 17:05:10 +00:00
ed2 - > size - = er - > skip_end ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
add_changed_extent_ref ( er - > chunk , ed2 - > address , ed2 - > size , fcb - > subvol - > id , fcb - > inode , ext - > offset - ed2 - > offset ,
1 , fcb - > inode_item . flags & BTRFS_INODE_NODATASUM ) ;
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le2 = le2 - > Flink ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! ( fcb - > inode_item . flags & BTRFS_INODE_NODATASUM ) )
2022-04-28 19:31:44 +00:00
add_checksum_entry ( fcb - > Vcb , er - > address + er - > length - er - > skip_end , ( ULONG ) ( er - > skip_end > > fcb - > Vcb - > sector_shift ) , NULL , NULL ) ;
2017-09-08 08:02:43 +00:00
2018-12-16 11:03:16 +00:00
acquire_chunk_lock ( er - > chunk , fcb - > Vcb ) ;
2017-09-08 08:02:43 +00:00
if ( ! er - > chunk - > cache_loaded ) {
NTSTATUS Status = load_cache_chunk ( fcb - > Vcb , er - > chunk , NULL ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " load_cache_chunk returned %08lx \n " , Status ) ;
2018-12-16 11:03:16 +00:00
release_chunk_lock ( er - > chunk , fcb - > Vcb ) ;
2017-09-08 08:02:43 +00:00
goto end ;
}
}
er - > chunk - > used - = er - > skip_end ;
space_list_add ( er - > chunk , er - > address + er - > length - er - > skip_end , er - > skip_end , NULL ) ;
2018-12-16 11:03:16 +00:00
release_chunk_lock ( er - > chunk , fcb - > Vcb ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
er - > length - = er - > skip_end ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = le - > Flink ;
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( num_extents < 2 )
goto end ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
// merge together adjacent extents
le = extent_ranges . Flink ;
while ( le ! = & extent_ranges ) {
er = CONTAINING_RECORD ( le , extent_range , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( le - > Flink ! = & extent_ranges & & er - > length < MAX_EXTENT_SIZE ) {
extent_range * er2 = CONTAINING_RECORD ( le - > Flink , extent_range , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( er - > chunk = = er2 - > chunk ) {
if ( er2 - > address = = er - > address + er - > length & & er2 - > offset > = er - > offset + er - > length ) {
if ( er - > length + er2 - > length < = MAX_EXTENT_SIZE ) {
er - > length + = er2 - > length ;
2019-09-01 12:53:20 +00:00
er - > changed = true ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
RemoveEntryList ( & er2 - > list_entry ) ;
ExFreePool ( er2 ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
changed = true ;
2016-10-29 17:05:10 +00:00
continue ;
}
}
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = le - > Flink ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! changed )
goto end ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = fcb - > extents . Flink ;
while ( le ! = & fcb - > extents ) {
extent * ext = CONTAINING_RECORD ( le , extent , list_entry ) ;
2017-09-08 08:02:43 +00:00
if ( ( ext - > extent_data . type = = EXTENT_TYPE_REGULAR | | ext - > extent_data . type = = EXTENT_TYPE_PREALLOC ) & & ext - > extent_data . compression = = BTRFS_COMPRESSION_NONE & & ext - > unique ) {
EXTENT_DATA2 * ed2 = ( EXTENT_DATA2 * ) ext - > extent_data . data ;
2016-10-29 17:05:10 +00:00
if ( ed2 - > size ! = 0 ) {
LIST_ENTRY * le2 ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le2 = extent_ranges . Flink ;
while ( le2 ! = & extent_ranges ) {
extent_range * er2 = CONTAINING_RECORD ( le2 , extent_range , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ed2 - > address > = er2 - > address & & ed2 - > address + ed2 - > size < = er2 - > address + er2 - > length & & er2 - > changed ) {
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
Status = update_changed_extent_ref ( fcb - > Vcb , er2 - > chunk , ed2 - > address , ed2 - > size , fcb - > subvol - > id , fcb - > inode , ext - > offset - ed2 - > offset ,
2019-09-01 12:53:20 +00:00
- 1 , fcb - > inode_item . flags & BTRFS_INODE_NODATASUM , true , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " update_changed_extent_ref returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ed2 - > offset + = ed2 - > address - er2 - > address ;
ed2 - > address = er2 - > address ;
ed2 - > size = er2 - > length ;
2017-09-08 08:02:43 +00:00
ext - > extent_data . decoded_size = ed2 - > size ;
2016-10-29 17:05:10 +00:00
add_changed_extent_ref ( er2 - > chunk , ed2 - > address , ed2 - > size , fcb - > subvol - > id , fcb - > inode , ext - > offset - ed2 - > offset ,
1 , fcb - > inode_item . flags & BTRFS_INODE_NODATASUM ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
break ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le2 = le2 - > Flink ;
}
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = le - > Flink ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
end :
while ( ! IsListEmpty ( & extent_ranges ) ) {
le = RemoveHeadList ( & extent_ranges ) ;
er = CONTAINING_RECORD ( le , extent_range , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ExFreePool ( er ) ;
}
}
2019-09-01 12:53:20 +00:00
NTSTATUS flush_fcb ( fcb * fcb , bool cache , LIST_ENTRY * batchlist , PIRP Irp ) {
2016-10-29 17:05:10 +00:00
traverse_ptr tp ;
KEY searchkey ;
NTSTATUS Status ;
INODE_ITEM * ii ;
2019-09-01 12:53:20 +00:00
uint64_t ii_offset ;
2016-10-29 17:05:10 +00:00
# ifdef DEBUG_PARANOID
2019-09-01 12:53:20 +00:00
uint64_t old_size = 0 ;
bool extents_changed ;
2016-10-29 17:05:10 +00:00
# endif
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( fcb - > ads ) {
2017-09-08 08:02:43 +00:00
if ( fcb - > deleted ) {
Status = delete_xattr ( fcb - > Vcb , batchlist , fcb - > subvol , fcb - > inode , fcb - > adsxattr . Buffer , fcb - > adsxattr . Length , fcb - > adshash ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_xattr returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
goto end ;
}
} else {
Status = set_xattr ( fcb - > Vcb , batchlist , fcb - > subvol , fcb - > inode , fcb - > adsxattr . Buffer , fcb - > adsxattr . Length ,
2019-09-01 12:53:20 +00:00
fcb - > adshash , ( uint8_t * ) fcb - > adsdata . Buffer , fcb - > adsdata . Length ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " set_xattr returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
goto end ;
}
}
2017-09-08 08:02:43 +00:00
Status = STATUS_SUCCESS ;
2016-10-29 17:05:10 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( fcb - > deleted ) {
2017-09-08 08:02:43 +00:00
Status = insert_tree_item_batch ( batchlist , fcb - > Vcb , fcb - > subvol , fcb - > inode , TYPE_INODE_ITEM , 0xffffffffffffffff , NULL , 0 , Batch_DeleteInode ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item_batch returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
goto end ;
}
2019-09-01 12:53:20 +00:00
if ( fcb - > marked_as_orphan ) {
Status = insert_tree_item_batch ( batchlist , fcb - > Vcb , fcb - > subvol , BTRFS_ORPHAN_INODE_OBJID , TYPE_ORPHAN_INODE ,
fcb - > inode , NULL , 0 , Batch_Delete ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item_batch returned %08lx \n " , Status ) ;
2019-09-01 12:53:20 +00:00
goto end ;
}
}
2017-09-08 08:02:43 +00:00
Status = STATUS_SUCCESS ;
2017-01-01 17:12:12 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
# ifdef DEBUG_PARANOID
extents_changed = fcb - > extents_changed ;
# endif
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( fcb - > extents_changed ) {
LIST_ENTRY * le ;
2019-09-01 12:53:20 +00:00
bool prealloc = false , extents_inline = false ;
uint64_t last_end ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
// delete ignored extent items
le = fcb - > extents . Flink ;
while ( le ! = & fcb - > extents ) {
LIST_ENTRY * le2 = le - > Flink ;
extent * ext = CONTAINING_RECORD ( le , extent , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ext - > ignore ) {
RemoveEntryList ( & ext - > list_entry ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ext - > csum )
ExFreePool ( ext - > csum ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ExFreePool ( ext ) ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = le2 ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le = fcb - > extents . Flink ;
while ( le ! = & fcb - > extents ) {
extent * ext = CONTAINING_RECORD ( le , extent , list_entry ) ;
2017-09-08 08:02:43 +00:00
if ( ext - > inserted & & ext - > csum & & ext - > extent_data . type = = EXTENT_TYPE_REGULAR ) {
EXTENT_DATA2 * ed2 = ( EXTENT_DATA2 * ) ext - > extent_data . data ;
2017-01-01 17:12:12 +00:00
if ( ed2 - > size > 0 ) { // not sparse
2017-09-08 08:02:43 +00:00
if ( ext - > extent_data . compression = = BTRFS_COMPRESSION_NONE )
2022-04-28 19:31:44 +00:00
add_checksum_entry ( fcb - > Vcb , ed2 - > address + ed2 - > offset , ( ULONG ) ( ed2 - > num_bytes > > fcb - > Vcb - > sector_shift ) , ext - > csum , Irp ) ;
2017-01-01 17:12:12 +00:00
else
2022-04-28 19:31:44 +00:00
add_checksum_entry ( fcb - > Vcb , ed2 - > address , ( ULONG ) ( ed2 - > size > > fcb - > Vcb - > sector_shift ) , ext - > csum , Irp ) ;
2017-01-01 17:12:12 +00:00
}
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le = le - > Flink ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! IsListEmpty ( & fcb - > extents ) ) {
2017-09-08 08:02:43 +00:00
rationalize_extents ( fcb , Irp ) ;
2016-10-29 17:05:10 +00:00
// merge together adjacent EXTENT_DATAs pointing to same extent
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = fcb - > extents . Flink ;
while ( le ! = & fcb - > extents ) {
LIST_ENTRY * le2 = le - > Flink ;
extent * ext = CONTAINING_RECORD ( le , extent , list_entry ) ;
2017-09-08 08:02:43 +00:00
if ( ( ext - > extent_data . type = = EXTENT_TYPE_REGULAR | | ext - > extent_data . type = = EXTENT_TYPE_PREALLOC ) & & le - > Flink ! = & fcb - > extents ) {
2016-10-29 17:05:10 +00:00
extent * nextext = CONTAINING_RECORD ( le - > Flink , extent , list_entry ) ;
2017-09-08 08:02:43 +00:00
if ( ext - > extent_data . type = = nextext - > extent_data . type ) {
EXTENT_DATA2 * ed2 = ( EXTENT_DATA2 * ) ext - > extent_data . data ;
EXTENT_DATA2 * ned2 = ( EXTENT_DATA2 * ) nextext - > extent_data . data ;
2016-10-29 17:05:10 +00:00
if ( ed2 - > size ! = 0 & & ed2 - > address = = ned2 - > address & & ed2 - > size = = ned2 - > size & &
nextext - > offset = = ext - > offset + ed2 - > num_bytes & & ned2 - > offset = = ed2 - > offset + ed2 - > num_bytes ) {
chunk * c ;
2017-09-08 08:02:43 +00:00
if ( ext - > extent_data . compression = = BTRFS_COMPRESSION_NONE & & ext - > csum ) {
2022-04-28 19:31:44 +00:00
ULONG len = ( ULONG ) ( ( ed2 - > num_bytes + ned2 - > num_bytes ) > > fcb - > Vcb - > sector_shift ) ;
2020-04-23 02:38:57 +00:00
void * csum ;
2017-09-08 08:02:43 +00:00
2020-04-23 02:38:57 +00:00
csum = ExAllocatePoolWithTag ( NonPagedPool , len * fcb - > Vcb - > csum_size , ALLOC_TAG ) ;
2017-01-01 17:12:12 +00:00
if ( ! csum ) {
ERR ( " out of memory \n " ) ;
2017-09-08 08:02:43 +00:00
Status = STATUS_INSUFFICIENT_RESOURCES ;
2017-01-01 17:12:12 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
2022-04-28 19:31:44 +00:00
RtlCopyMemory ( csum , ext - > csum , ( ULONG ) ( ( ed2 - > num_bytes * fcb - > Vcb - > csum_size ) > > fcb - > Vcb - > sector_shift ) ) ;
RtlCopyMemory ( ( uint8_t * ) csum + ( ( ed2 - > num_bytes * fcb - > Vcb - > csum_size ) > > fcb - > Vcb - > sector_shift ) , nextext - > csum ,
( ULONG ) ( ( ned2 - > num_bytes * fcb - > Vcb - > csum_size ) > > fcb - > Vcb - > sector_shift ) ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
ExFreePool ( ext - > csum ) ;
ext - > csum = csum ;
}
2017-09-08 08:02:43 +00:00
ext - > extent_data . generation = fcb - > Vcb - > superblock . generation ;
2016-10-29 17:05:10 +00:00
ed2 - > num_bytes + = ned2 - > num_bytes ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
RemoveEntryList ( & nextext - > list_entry ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( nextext - > csum )
ExFreePool ( nextext - > csum ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ExFreePool ( nextext ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
c = get_chunk_from_address ( fcb - > Vcb , ed2 - > address ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! c ) {
2019-09-01 12:53:20 +00:00
ERR ( " get_chunk_from_address(%I64x) failed \n " , ed2 - > address ) ;
2016-10-29 17:05:10 +00:00
} else {
Status = update_changed_extent_ref ( fcb - > Vcb , c , ed2 - > address , ed2 - > size , fcb - > subvol - > id , fcb - > inode , ext - > offset - ed2 - > offset , - 1 ,
2019-09-01 12:53:20 +00:00
fcb - > inode_item . flags & BTRFS_INODE_NODATASUM , false , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " update_changed_extent_ref returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
goto end ;
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le2 = le ;
}
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = le2 ;
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! fcb - > created ) {
// delete existing EXTENT_DATA items
2017-09-08 08:02:43 +00:00
Status = insert_tree_item_batch ( batchlist , fcb - > Vcb , fcb - > subvol , fcb - > inode , TYPE_EXTENT_DATA , 0 , NULL , 0 , Batch_DeleteExtentData ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item_batch returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
goto end ;
}
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
// add new EXTENT_DATAs
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
last_end = 0 ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le = fcb - > extents . Flink ;
while ( le ! = & fcb - > extents ) {
extent * ext = CONTAINING_RECORD ( le , extent , list_entry ) ;
EXTENT_DATA * ed ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
ext - > inserted = false ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! ( fcb - > Vcb - > superblock . incompat_flags & BTRFS_INCOMPAT_FLAGS_NO_HOLES ) & & ext - > offset > last_end ) {
2017-09-08 08:02:43 +00:00
Status = insert_sparse_extent ( fcb , batchlist , last_end , ext - > offset - last_end ) ;
2017-01-01 17:12:12 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_sparse_extent returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
goto end ;
}
2017-01-01 17:12:12 +00:00
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
ed = ExAllocatePoolWithTag ( PagedPool , ext - > datalen , ALLOC_TAG ) ;
if ( ! ed ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto end ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
RtlCopyMemory ( ed , & ext - > extent_data , ext - > datalen ) ;
Status = insert_tree_item_batch ( batchlist , fcb - > Vcb , fcb - > subvol , fcb - > inode , TYPE_EXTENT_DATA , ext - > offset ,
ed , ext - > datalen , Batch_Insert ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item_batch returned %08lx \n " , Status ) ;
2017-01-01 17:12:12 +00:00
goto end ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
if ( ed - > type = = EXTENT_TYPE_PREALLOC )
2019-09-01 12:53:20 +00:00
prealloc = true ;
2017-09-08 08:02:43 +00:00
if ( ed - > type = = EXTENT_TYPE_INLINE )
2019-09-01 12:53:20 +00:00
extents_inline = true ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! ( fcb - > Vcb - > superblock . incompat_flags & BTRFS_INCOMPAT_FLAGS_NO_HOLES ) ) {
if ( ed - > type = = EXTENT_TYPE_INLINE )
last_end = ext - > offset + ed - > decoded_size ;
else {
EXTENT_DATA2 * ed2 = ( EXTENT_DATA2 * ) ed - > data ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
last_end = ext - > offset + ed2 - > num_bytes ;
}
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le = le - > Flink ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! ( fcb - > Vcb - > superblock . incompat_flags & BTRFS_INCOMPAT_FLAGS_NO_HOLES ) & & ! extents_inline & &
sector_align ( fcb - > inode_item . st_size , fcb - > Vcb - > superblock . sector_size ) > last_end ) {
2017-09-08 08:02:43 +00:00
Status = insert_sparse_extent ( fcb , batchlist , last_end , sector_align ( fcb - > inode_item . st_size , fcb - > Vcb - > superblock . sector_size ) - last_end ) ;
2017-01-01 17:12:12 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_sparse_extent returned %08lx \n " , Status ) ;
2017-01-01 17:12:12 +00:00
goto end ;
}
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
// update prealloc flag in INODE_ITEM
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! prealloc )
fcb - > inode_item . flags & = ~ BTRFS_INODE_PREALLOC ;
else
fcb - > inode_item . flags | = BTRFS_INODE_PREALLOC ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
fcb - > inode_item_changed = true ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
fcb - > extents_changed = false ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ( ! fcb - > created & & fcb - > inode_item_changed ) | | cache ) {
searchkey . obj_id = fcb - > inode ;
searchkey . obj_type = TYPE_INODE_ITEM ;
searchkey . offset = 0xffffffffffffffff ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( fcb - > Vcb , fcb - > subvol , & tp , & searchkey , false , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - find_item returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( tp . item - > key . obj_id ! = searchkey . obj_id | | tp . item - > key . obj_type ! = searchkey . obj_type ) {
if ( cache ) {
ii = ExAllocatePoolWithTag ( PagedPool , sizeof ( INODE_ITEM ) , ALLOC_TAG ) ;
if ( ! ii ) {
ERR ( " out of memory \n " ) ;
2017-09-08 08:02:43 +00:00
Status = STATUS_INSUFFICIENT_RESOURCES ;
2016-10-29 17:05:10 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
RtlCopyMemory ( ii , & fcb - > inode_item , sizeof ( INODE_ITEM ) ) ;
2017-09-08 08:02:43 +00:00
Status = insert_tree_item ( fcb - > Vcb , fcb - > subvol , fcb - > inode , TYPE_INODE_ITEM , 0 , ii , sizeof ( INODE_ITEM ) , NULL , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ii_offset = 0 ;
} else {
2019-09-01 12:53:20 +00:00
ERR ( " could not find INODE_ITEM for inode %I64x in subvol %I64x \n " , fcb - > inode , fcb - > subvol - > id ) ;
2017-09-08 08:02:43 +00:00
Status = STATUS_INTERNAL_ERROR ;
2016-10-29 17:05:10 +00:00
goto end ;
}
} else {
# ifdef DEBUG_PARANOID
INODE_ITEM * ii2 = ( INODE_ITEM * ) tp . item - > data ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
old_size = ii2 - > st_size ;
# endif
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ii_offset = tp . item - > key . offset ;
}
2017-09-08 08:02:43 +00:00
if ( ! cache ) {
Status = delete_tree_item ( fcb - > Vcb , & tp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
goto end ;
}
} else {
2016-10-29 17:05:10 +00:00
searchkey . obj_id = fcb - > inode ;
searchkey . obj_type = TYPE_INODE_ITEM ;
searchkey . offset = ii_offset ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( fcb - > Vcb , fcb - > subvol , & tp , & searchkey , false , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - find_item returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( keycmp ( tp . item - > key , searchkey ) ) {
2019-09-01 12:53:20 +00:00
ERR ( " could not find INODE_ITEM for inode %I64x in subvol %I64x \n " , fcb - > inode , fcb - > subvol - > id ) ;
2017-09-08 08:02:43 +00:00
Status = STATUS_INTERNAL_ERROR ;
2016-10-29 17:05:10 +00:00
goto end ;
} else
RtlCopyMemory ( tp . item - > data , & fcb - > inode_item , min ( tp . item - > size , sizeof ( INODE_ITEM ) ) ) ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
# ifdef DEBUG_PARANOID
2017-09-08 08:02:43 +00:00
if ( ! extents_changed & & fcb - > type ! = BTRFS_TYPE_DIRECTORY & & old_size ! = fcb - > inode_item . st_size ) {
ERR ( " error - size has changed but extents not marked as changed \n " ) ;
int3 ;
}
2016-10-29 17:05:10 +00:00
# endif
2017-09-08 08:02:43 +00:00
} else
ii_offset = 0 ;
2019-09-01 12:53:20 +00:00
fcb - > created = false ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! cache & & fcb - > inode_item_changed ) {
ii = ExAllocatePoolWithTag ( PagedPool , sizeof ( INODE_ITEM ) , ALLOC_TAG ) ;
if ( ! ii ) {
ERR ( " out of memory \n " ) ;
2017-09-08 08:02:43 +00:00
Status = STATUS_INSUFFICIENT_RESOURCES ;
2016-10-29 17:05:10 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
RtlCopyMemory ( ii , & fcb - > inode_item , sizeof ( INODE_ITEM ) ) ;
2017-09-08 08:02:43 +00:00
Status = insert_tree_item_batch ( batchlist , fcb - > Vcb , fcb - > subvol , fcb - > inode , TYPE_INODE_ITEM , ii_offset , ii , sizeof ( INODE_ITEM ) ,
Batch_Insert ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item_batch returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
fcb - > inode_item_changed = false ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( fcb - > sd_dirty ) {
2017-09-08 08:02:43 +00:00
if ( ! fcb - > sd_deleted ) {
2018-12-16 11:03:16 +00:00
Status = set_xattr ( fcb - > Vcb , batchlist , fcb - > subvol , fcb - > inode , EA_NTACL , sizeof ( EA_NTACL ) - 1 ,
2019-09-01 12:53:20 +00:00
EA_NTACL_HASH , ( uint8_t * ) fcb - > sd , ( uint16_t ) RtlLengthSecurityDescriptor ( fcb - > sd ) ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " set_xattr returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
goto end ;
}
} else {
2018-12-16 11:03:16 +00:00
Status = delete_xattr ( fcb - > Vcb , batchlist , fcb - > subvol , fcb - > inode , EA_NTACL , sizeof ( EA_NTACL ) - 1 , EA_NTACL_HASH ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_xattr returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
goto end ;
}
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
fcb - > sd_deleted = false ;
fcb - > sd_dirty = false ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( fcb - > atts_changed ) {
if ( ! fcb - > atts_deleted ) {
2019-09-01 12:53:20 +00:00
uint8_t val [ 16 ] , * val2 ;
2016-10-29 17:05:10 +00:00
ULONG atts = fcb - > atts ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
TRACE ( " inserting new DOSATTRIB xattr \n " ) ;
2017-09-08 08:02:43 +00:00
if ( fcb - > inode = = SUBVOL_ROOT_INODE )
atts & = ~ FILE_ATTRIBUTE_READONLY ;
2016-10-29 17:05:10 +00:00
val2 = & val [ sizeof ( val ) - 1 ] ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
do {
2019-09-01 12:53:20 +00:00
uint8_t c = atts % 16 ;
2017-09-08 08:02:43 +00:00
* val2 = c < = 9 ? ( c + ' 0 ' ) : ( c - 0xa + ' a ' ) ;
2016-10-29 17:05:10 +00:00
val2 - - ;
atts > > = 4 ;
} while ( atts ! = 0 ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
* val2 = ' x ' ;
val2 - - ;
* val2 = ' 0 ' ;
2017-09-08 08:02:43 +00:00
2018-12-16 11:03:16 +00:00
Status = set_xattr ( fcb - > Vcb , batchlist , fcb - > subvol , fcb - > inode , EA_DOSATTRIB , sizeof ( EA_DOSATTRIB ) - 1 ,
2019-09-01 12:53:20 +00:00
EA_DOSATTRIB_HASH , val2 , ( uint16_t ) ( val + sizeof ( val ) - val2 ) ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " set_xattr returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
} else {
2018-12-16 11:03:16 +00:00
Status = delete_xattr ( fcb - > Vcb , batchlist , fcb - > subvol , fcb - > inode , EA_DOSATTRIB , sizeof ( EA_DOSATTRIB ) - 1 , EA_DOSATTRIB_HASH ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_xattr returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
goto end ;
}
}
2019-09-01 12:53:20 +00:00
fcb - > atts_changed = false ;
fcb - > atts_deleted = false ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( fcb - > reparse_xattr_changed ) {
if ( fcb - > reparse_xattr . Buffer & & fcb - > reparse_xattr . Length > 0 ) {
2018-12-16 11:03:16 +00:00
Status = set_xattr ( fcb - > Vcb , batchlist , fcb - > subvol , fcb - > inode , EA_REPARSE , sizeof ( EA_REPARSE ) - 1 ,
2019-09-01 12:53:20 +00:00
EA_REPARSE_HASH , ( uint8_t * ) fcb - > reparse_xattr . Buffer , ( uint16_t ) fcb - > reparse_xattr . Length ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " set_xattr returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
} else {
2018-12-16 11:03:16 +00:00
Status = delete_xattr ( fcb - > Vcb , batchlist , fcb - > subvol , fcb - > inode , EA_REPARSE , sizeof ( EA_REPARSE ) - 1 , EA_REPARSE_HASH ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_xattr returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
goto end ;
}
}
2019-09-01 12:53:20 +00:00
fcb - > reparse_xattr_changed = false ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( fcb - > ea_changed ) {
if ( fcb - > ea_xattr . Buffer & & fcb - > ea_xattr . Length > 0 ) {
2018-12-16 11:03:16 +00:00
Status = set_xattr ( fcb - > Vcb , batchlist , fcb - > subvol , fcb - > inode , EA_EA , sizeof ( EA_EA ) - 1 ,
2019-09-01 12:53:20 +00:00
EA_EA_HASH , ( uint8_t * ) fcb - > ea_xattr . Buffer , ( uint16_t ) fcb - > ea_xattr . Length ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " set_xattr returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
} else {
2018-12-16 11:03:16 +00:00
Status = delete_xattr ( fcb - > Vcb , batchlist , fcb - > subvol , fcb - > inode , EA_EA , sizeof ( EA_EA ) - 1 , EA_EA_HASH ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_xattr returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
goto end ;
}
}
2019-09-01 12:53:20 +00:00
fcb - > ea_changed = false ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
if ( fcb - > prop_compression_changed ) {
if ( fcb - > prop_compression = = PropCompression_None ) {
2018-12-16 11:03:16 +00:00
Status = delete_xattr ( fcb - > Vcb , batchlist , fcb - > subvol , fcb - > inode , EA_PROP_COMPRESSION , sizeof ( EA_PROP_COMPRESSION ) - 1 , EA_PROP_COMPRESSION_HASH ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_xattr returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
goto end ;
}
} else if ( fcb - > prop_compression = = PropCompression_Zlib ) {
2018-12-16 11:03:16 +00:00
static const char zlib [ ] = " zlib " ;
2017-09-08 08:02:43 +00:00
2018-12-16 11:03:16 +00:00
Status = set_xattr ( fcb - > Vcb , batchlist , fcb - > subvol , fcb - > inode , EA_PROP_COMPRESSION , sizeof ( EA_PROP_COMPRESSION ) - 1 ,
2019-09-01 12:53:20 +00:00
EA_PROP_COMPRESSION_HASH , ( uint8_t * ) zlib , sizeof ( zlib ) - 1 ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " set_xattr returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
goto end ;
}
} else if ( fcb - > prop_compression = = PropCompression_LZO ) {
2018-12-16 11:03:16 +00:00
static const char lzo [ ] = " lzo " ;
2017-09-08 08:02:43 +00:00
2018-12-16 11:03:16 +00:00
Status = set_xattr ( fcb - > Vcb , batchlist , fcb - > subvol , fcb - > inode , EA_PROP_COMPRESSION , sizeof ( EA_PROP_COMPRESSION ) - 1 ,
2019-09-01 12:53:20 +00:00
EA_PROP_COMPRESSION_HASH , ( uint8_t * ) lzo , sizeof ( lzo ) - 1 ) ;
2018-12-16 11:03:16 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " set_xattr returned %08lx \n " , Status ) ;
2018-12-16 11:03:16 +00:00
goto end ;
}
} else if ( fcb - > prop_compression = = PropCompression_ZSTD ) {
static const char zstd [ ] = " zstd " ;
Status = set_xattr ( fcb - > Vcb , batchlist , fcb - > subvol , fcb - > inode , EA_PROP_COMPRESSION , sizeof ( EA_PROP_COMPRESSION ) - 1 ,
2019-09-01 12:53:20 +00:00
EA_PROP_COMPRESSION_HASH , ( uint8_t * ) zstd , sizeof ( zstd ) - 1 ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " set_xattr returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
goto end ;
}
}
2019-09-01 12:53:20 +00:00
fcb - > prop_compression_changed = false ;
2017-09-08 08:02:43 +00:00
}
if ( fcb - > xattrs_changed ) {
LIST_ENTRY * le ;
le = fcb - > xattrs . Flink ;
while ( le ! = & fcb - > xattrs ) {
xattr * xa = CONTAINING_RECORD ( le , xattr , list_entry ) ;
LIST_ENTRY * le2 = le - > Flink ;
if ( xa - > dirty ) {
2019-09-01 12:53:20 +00:00
uint32_t hash = calc_crc32c ( 0xfffffffe , ( uint8_t * ) xa - > data , xa - > namelen ) ;
2017-09-08 08:02:43 +00:00
if ( xa - > valuelen = = 0 ) {
Status = delete_xattr ( fcb - > Vcb , batchlist , fcb - > subvol , fcb - > inode , xa - > data , xa - > namelen , hash ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_xattr returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
goto end ;
}
RemoveEntryList ( & xa - > list_entry ) ;
ExFreePool ( xa ) ;
} else {
Status = set_xattr ( fcb - > Vcb , batchlist , fcb - > subvol , fcb - > inode , xa - > data , xa - > namelen ,
2019-09-01 12:53:20 +00:00
hash , ( uint8_t * ) & xa - > data [ xa - > namelen ] , xa - > valuelen ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " set_xattr returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
goto end ;
}
2019-09-01 12:53:20 +00:00
xa - > dirty = false ;
2017-09-08 08:02:43 +00:00
}
}
le = le2 ;
}
2019-09-01 12:53:20 +00:00
fcb - > xattrs_changed = false ;
2017-09-08 08:02:43 +00:00
}
2019-06-11 10:35:19 +00:00
if ( ( fcb - > case_sensitive_set & & ! fcb - > case_sensitive ) ) {
Status = delete_xattr ( fcb - > Vcb , batchlist , fcb - > subvol , fcb - > inode , EA_CASE_SENSITIVE ,
sizeof ( EA_CASE_SENSITIVE ) - 1 , EA_CASE_SENSITIVE_HASH ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_xattr returned %08lx \n " , Status ) ;
2019-06-11 10:35:19 +00:00
goto end ;
}
2019-09-01 12:53:20 +00:00
fcb - > case_sensitive_set = false ;
2019-06-11 10:35:19 +00:00
} else if ( ( ! fcb - > case_sensitive_set & & fcb - > case_sensitive ) ) {
Status = set_xattr ( fcb - > Vcb , batchlist , fcb - > subvol , fcb - > inode , EA_CASE_SENSITIVE ,
2019-09-01 12:53:20 +00:00
sizeof ( EA_CASE_SENSITIVE ) - 1 , EA_CASE_SENSITIVE_HASH , ( uint8_t * ) " 1 " , 1 ) ;
2019-06-11 10:35:19 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " set_xattr returned %08lx \n " , Status ) ;
2019-06-11 10:35:19 +00:00
goto end ;
}
2019-09-01 12:53:20 +00:00
fcb - > case_sensitive_set = true ;
2019-06-11 10:35:19 +00:00
}
if ( fcb - > inode_item . st_nlink = = 0 & & ! fcb - > marked_as_orphan ) { // mark as orphan
Status = insert_tree_item_batch ( batchlist , fcb - > Vcb , fcb - > subvol , BTRFS_ORPHAN_INODE_OBJID , TYPE_ORPHAN_INODE ,
fcb - > inode , NULL , 0 , Batch_Insert ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item_batch returned %08lx \n " , Status ) ;
2019-06-11 10:35:19 +00:00
goto end ;
}
2019-09-01 12:53:20 +00:00
fcb - > marked_as_orphan = true ;
2019-06-11 10:35:19 +00:00
}
2017-09-08 08:02:43 +00:00
Status = STATUS_SUCCESS ;
2016-10-29 17:05:10 +00:00
end :
2017-09-08 08:02:43 +00:00
if ( fcb - > dirty ) {
2019-09-01 12:53:20 +00:00
bool lock = false ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
fcb - > dirty = false ;
2017-09-08 08:02:43 +00:00
if ( ! ExIsResourceAcquiredExclusiveLite ( & fcb - > Vcb - > dirty_fcbs_lock ) ) {
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( & fcb - > Vcb - > dirty_fcbs_lock , true ) ;
lock = true ;
2017-09-08 08:02:43 +00:00
}
RemoveEntryList ( & fcb - > list_entry_dirty ) ;
if ( lock )
ExReleaseResourceLite ( & fcb - > Vcb - > dirty_fcbs_lock ) ;
}
return Status ;
}
2019-09-01 12:53:20 +00:00
void add_trim_entry_avoid_sb ( device_extension * Vcb , device * dev , uint64_t address , uint64_t size ) {
2017-09-08 08:02:43 +00:00
int i ;
ULONG sblen = ( ULONG ) sector_align ( sizeof ( superblock ) , Vcb - > superblock . sector_size ) ;
i = 0 ;
while ( superblock_addrs [ i ] ! = 0 ) {
if ( superblock_addrs [ i ] + sblen > = address & & superblock_addrs [ i ] < address + size ) {
if ( superblock_addrs [ i ] > address )
add_trim_entry ( dev , address , superblock_addrs [ i ] - address ) ;
if ( size < = superblock_addrs [ i ] + sblen - address )
return ;
size - = superblock_addrs [ i ] + sblen - address ;
address = superblock_addrs [ i ] + sblen ;
} else if ( superblock_addrs [ i ] > address + size )
break ;
i + + ;
}
add_trim_entry ( dev , address , size ) ;
2016-10-29 17:05:10 +00:00
}
static NTSTATUS drop_chunk ( device_extension * Vcb , chunk * c , LIST_ENTRY * batchlist , PIRP Irp , LIST_ENTRY * rollback ) {
NTSTATUS Status ;
KEY searchkey ;
traverse_ptr tp ;
2019-09-01 12:53:20 +00:00
uint64_t i , factor ;
2017-09-08 08:02:43 +00:00
CHUNK_ITEM_STRIPE * cis = ( CHUNK_ITEM_STRIPE * ) & c - > chunk_item [ 1 ] ; ;
2019-09-01 12:53:20 +00:00
TRACE ( " dropping chunk %I64x \n " , c - > offset ) ;
2017-09-08 08:02:43 +00:00
if ( c - > chunk_item - > type & BLOCK_FLAG_RAID0 )
factor = c - > chunk_item - > num_stripes ;
else if ( c - > chunk_item - > type & BLOCK_FLAG_RAID10 )
factor = c - > chunk_item - > num_stripes / c - > chunk_item - > sub_stripes ;
else if ( c - > chunk_item - > type & BLOCK_FLAG_RAID5 )
factor = c - > chunk_item - > num_stripes - 1 ;
else if ( c - > chunk_item - > type & BLOCK_FLAG_RAID6 )
factor = c - > chunk_item - > num_stripes - 2 ;
2020-04-23 02:38:57 +00:00
else // SINGLE, DUPLICATE, RAID1, RAID1C3, RAID1C4
2017-09-08 08:02:43 +00:00
factor = 1 ;
// do TRIM
if ( Vcb - > trim & & ! Vcb - > options . no_trim ) {
2019-09-01 12:53:20 +00:00
uint64_t len = c - > chunk_item - > size / factor ;
2017-09-08 08:02:43 +00:00
for ( i = 0 ; i < c - > chunk_item - > num_stripes ; i + + ) {
if ( c - > devices [ i ] & & c - > devices [ i ] - > devobj & & ! c - > devices [ i ] - > readonly & & c - > devices [ i ] - > trim )
add_trim_entry_avoid_sb ( Vcb , c - > devices [ i ] , cis [ i ] . offset , len ) ;
}
}
if ( ! c - > cache ) {
2019-09-01 12:53:20 +00:00
Status = load_stored_free_space_cache ( Vcb , c , true , Irp ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) & & Status ! = STATUS_NOT_FOUND )
2020-04-23 02:38:57 +00:00
WARN ( " load_stored_free_space_cache returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
}
2016-10-29 17:05:10 +00:00
// remove free space cache
if ( c - > cache ) {
2019-09-01 12:53:20 +00:00
c - > cache - > deleted = true ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
Status = excise_extents ( Vcb , c - > cache , 0 , c - > cache - > inode_item . st_size , Irp , rollback ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " excise_extents returned %08lx \n " , Status ) ;
2017-01-01 17:12:12 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = flush_fcb ( c - > cache , true , batchlist , Irp ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
free_fcb ( c - > cache ) ;
if ( c - > cache - > refcount = = 0 )
reap_fcb ( c - > cache ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " flush_fcb returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
2016-10-29 17:05:10 +00:00
searchkey . obj_id = FREE_SPACE_CACHE_ID ;
searchkey . obj_type = 0 ;
searchkey . offset = c - > offset ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > root_root , & tp , & searchkey , false , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - find_item returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
if ( ! keycmp ( tp . item - > key , searchkey ) ) {
2017-09-08 08:02:43 +00:00
Status = delete_tree_item ( Vcb , & tp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
2016-10-29 17:05:10 +00:00
}
}
2017-09-08 08:02:43 +00:00
if ( Vcb - > space_root ) {
Status = insert_tree_item_batch ( batchlist , Vcb , Vcb - > space_root , c - > offset , TYPE_FREE_SPACE_INFO , c - > chunk_item - > size ,
NULL , 0 , Batch_DeleteFreeSpace ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item_batch returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
}
2016-10-29 17:05:10 +00:00
for ( i = 0 ; i < c - > chunk_item - > num_stripes ; i + + ) {
if ( ! c - > created ) {
// remove DEV_EXTENTs from tree 4
searchkey . obj_id = cis [ i ] . dev_id ;
searchkey . obj_type = TYPE_DEV_EXTENT ;
searchkey . offset = cis [ i ] . offset ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > dev_root , & tp , & searchkey , false , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - find_item returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! keycmp ( tp . item - > key , searchkey ) ) {
2017-09-08 08:02:43 +00:00
Status = delete_tree_item ( Vcb , & tp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
2016-10-29 17:05:10 +00:00
if ( tp . item - > size > = sizeof ( DEV_EXTENT ) ) {
DEV_EXTENT * de = ( DEV_EXTENT * ) tp . item - > data ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
c - > devices [ i ] - > devitem . bytes_used - = de - > length ;
2017-09-08 08:02:43 +00:00
if ( Vcb - > balance . thread & & Vcb - > balance . shrinking & & Vcb - > balance . opts [ 0 ] . devid = = c - > devices [ i ] - > devitem . dev_id ) {
if ( cis [ i ] . offset < Vcb - > balance . opts [ 0 ] . drange_start & & cis [ i ] . offset + de - > length > Vcb - > balance . opts [ 0 ] . drange_start )
space_list_add2 ( & c - > devices [ i ] - > space , NULL , cis [ i ] . offset , Vcb - > balance . opts [ 0 ] . drange_start - cis [ i ] . offset , NULL , rollback ) ;
} else
space_list_add2 ( & c - > devices [ i ] - > space , NULL , cis [ i ] . offset , de - > length , NULL , rollback ) ;
2016-10-29 17:05:10 +00:00
}
} else
2019-09-01 12:53:20 +00:00
WARN ( " could not find (%I64x,%x,%I64x) in dev tree \n " , searchkey . obj_id , searchkey . obj_type , searchkey . offset ) ;
2016-10-29 17:05:10 +00:00
} else {
2019-09-01 12:53:20 +00:00
uint64_t len = c - > chunk_item - > size / factor ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
c - > devices [ i ] - > devitem . bytes_used - = len ;
2017-09-08 08:02:43 +00:00
if ( Vcb - > balance . thread & & Vcb - > balance . shrinking & & Vcb - > balance . opts [ 0 ] . devid = = c - > devices [ i ] - > devitem . dev_id ) {
if ( cis [ i ] . offset < Vcb - > balance . opts [ 0 ] . drange_start & & cis [ i ] . offset + len > Vcb - > balance . opts [ 0 ] . drange_start )
space_list_add2 ( & c - > devices [ i ] - > space , NULL , cis [ i ] . offset , Vcb - > balance . opts [ 0 ] . drange_start - cis [ i ] . offset , NULL , rollback ) ;
} else
space_list_add2 ( & c - > devices [ i ] - > space , NULL , cis [ i ] . offset , len , NULL , rollback ) ;
2016-10-29 17:05:10 +00:00
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
// modify DEV_ITEMs in chunk tree
for ( i = 0 ; i < c - > chunk_item - > num_stripes ; i + + ) {
if ( c - > devices [ i ] ) {
2019-09-01 12:53:20 +00:00
uint64_t j ;
2016-10-29 17:05:10 +00:00
DEV_ITEM * di ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
searchkey . obj_id = 1 ;
searchkey . obj_type = TYPE_DEV_ITEM ;
searchkey . offset = c - > devices [ i ] - > devitem . dev_id ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > chunk_root , & tp , & searchkey , false , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - find_item returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2018-12-16 11:03:16 +00:00
if ( ! keycmp ( tp . item - > key , searchkey ) ) {
Status = delete_tree_item ( Vcb , & tp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2018-12-16 11:03:16 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2018-12-16 11:03:16 +00:00
di = ExAllocatePoolWithTag ( PagedPool , sizeof ( DEV_ITEM ) , ALLOC_TAG ) ;
if ( ! di ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2018-12-16 11:03:16 +00:00
RtlCopyMemory ( di , & c - > devices [ i ] - > devitem , sizeof ( DEV_ITEM ) ) ;
2017-09-08 08:02:43 +00:00
2018-12-16 11:03:16 +00:00
Status = insert_tree_item ( Vcb , Vcb - > chunk_root , 1 , TYPE_DEV_ITEM , c - > devices [ i ] - > devitem . dev_id , di , sizeof ( DEV_ITEM ) , NULL , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item returned %08lx \n " , Status ) ;
2018-12-16 11:03:16 +00:00
return Status ;
}
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
for ( j = i + 1 ; j < c - > chunk_item - > num_stripes ; j + + ) {
if ( c - > devices [ j ] = = c - > devices [ i ] )
c - > devices [ j ] = NULL ;
}
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! c - > created ) {
// remove CHUNK_ITEM from chunk tree
searchkey . obj_id = 0x100 ;
searchkey . obj_type = TYPE_CHUNK_ITEM ;
searchkey . offset = c - > offset ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > chunk_root , & tp , & searchkey , false , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - find_item returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
if ( ! keycmp ( tp . item - > key , searchkey ) ) {
Status = delete_tree_item ( Vcb , & tp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
} else
2019-09-01 12:53:20 +00:00
WARN ( " could not find CHUNK_ITEM for chunk %I64x \n " , c - > offset ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
// remove BLOCK_GROUP_ITEM from extent tree
searchkey . obj_id = c - > offset ;
searchkey . obj_type = TYPE_BLOCK_GROUP_ITEM ;
searchkey . offset = 0xffffffffffffffff ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > extent_root , & tp , & searchkey , false , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - find_item returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
if ( tp . item - > key . obj_id = = searchkey . obj_id & & tp . item - > key . obj_type = = searchkey . obj_type ) {
Status = delete_tree_item ( Vcb , & tp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
} else
2019-09-01 12:53:20 +00:00
WARN ( " could not find BLOCK_GROUP_ITEM for chunk %I64x \n " , c - > offset ) ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( c - > chunk_item - > type & BLOCK_FLAG_SYSTEM )
remove_from_bootstrap ( Vcb , 0x100 , TYPE_CHUNK_ITEM , c - > offset ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
RemoveEntryList ( & c - > list_entry ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
// clear raid56 incompat flag if dropping last RAID5/6 chunk
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( c - > chunk_item - > type & BLOCK_FLAG_RAID5 | | c - > chunk_item - > type & BLOCK_FLAG_RAID6 ) {
LIST_ENTRY * le ;
2019-09-01 12:53:20 +00:00
bool clear_flag = true ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le = Vcb - > chunks . Flink ;
while ( le ! = & Vcb - > chunks ) {
chunk * c2 = CONTAINING_RECORD ( le , chunk , list_entry ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( c2 - > chunk_item - > type & BLOCK_FLAG_RAID5 | | c2 - > chunk_item - > type & BLOCK_FLAG_RAID6 ) {
2019-09-01 12:53:20 +00:00
clear_flag = false ;
2017-01-01 17:12:12 +00:00
break ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le = le - > Flink ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( clear_flag )
Vcb - > superblock . incompat_flags & = ~ BTRFS_INCOMPAT_FLAGS_RAID56 ;
}
2017-09-08 08:02:43 +00:00
2020-04-23 02:38:57 +00:00
// clear raid1c34 incompat flag if dropping last RAID5/6 chunk
if ( c - > chunk_item - > type & BLOCK_FLAG_RAID1C3 | | c - > chunk_item - > type & BLOCK_FLAG_RAID1C4 ) {
LIST_ENTRY * le ;
bool clear_flag = true ;
le = Vcb - > chunks . Flink ;
while ( le ! = & Vcb - > chunks ) {
chunk * c2 = CONTAINING_RECORD ( le , chunk , list_entry ) ;
if ( c2 - > chunk_item - > type & BLOCK_FLAG_RAID1C3 | | c2 - > chunk_item - > type & BLOCK_FLAG_RAID1C4 ) {
clear_flag = false ;
break ;
}
le = le - > Flink ;
}
if ( clear_flag )
Vcb - > superblock . incompat_flags & = ~ BTRFS_INCOMPAT_FLAGS_RAID1C34 ;
}
2022-04-28 19:37:02 +00:00
Vcb - > superblock . bytes_used - = c - > oldused ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
ExFreePool ( c - > chunk_item ) ;
ExFreePool ( c - > devices ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
while ( ! IsListEmpty ( & c - > space ) ) {
space * s = CONTAINING_RECORD ( c - > space . Flink , space , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
RemoveEntryList ( & s - > list_entry ) ;
ExFreePool ( s ) ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
while ( ! IsListEmpty ( & c - > deleting ) ) {
space * s = CONTAINING_RECORD ( c - > deleting . Flink , space , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
RemoveEntryList ( & s - > list_entry ) ;
ExFreePool ( s ) ;
}
2017-09-08 08:02:43 +00:00
2018-12-16 11:03:16 +00:00
release_chunk_lock ( c , Vcb ) ;
2017-09-08 08:02:43 +00:00
ExDeleteResourceLite ( & c - > partial_stripes_lock ) ;
ExDeleteResourceLite ( & c - > range_locks_lock ) ;
2016-10-29 17:05:10 +00:00
ExDeleteResourceLite ( & c - > lock ) ;
ExDeleteResourceLite ( & c - > changed_extents_lock ) ;
ExFreePool ( c ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
return STATUS_SUCCESS ;
}
2019-09-01 12:53:20 +00:00
static NTSTATUS partial_stripe_read ( device_extension * Vcb , chunk * c , partial_stripe * ps , uint64_t startoff , uint16_t parity , ULONG offset , ULONG len ) {
2016-10-29 17:05:10 +00:00
NTSTATUS Status ;
2022-04-28 19:31:44 +00:00
ULONG sl = ( ULONG ) ( c - > chunk_item - > stripe_length > > Vcb - > sector_shift ) ;
2017-09-08 08:02:43 +00:00
CHUNK_ITEM_STRIPE * cis = ( CHUNK_ITEM_STRIPE * ) & c - > chunk_item [ 1 ] ;
while ( len > 0 ) {
ULONG readlen = min ( offset + len , offset + ( sl - ( offset % sl ) ) ) - offset ;
2019-09-01 12:53:20 +00:00
uint16_t stripe ;
2017-09-08 08:02:43 +00:00
stripe = ( parity + ( offset / sl ) + 1 ) % c - > chunk_item - > num_stripes ;
if ( c - > devices [ stripe ] - > devobj ) {
2022-04-28 19:31:44 +00:00
Status = sync_read_phys ( c - > devices [ stripe ] - > devobj , c - > devices [ stripe ] - > fileobj , cis [ stripe ] . offset + startoff + ( ( offset % sl ) < < Vcb - > sector_shift ) ,
readlen < < Vcb - > sector_shift , ps - > data + ( offset < < Vcb - > sector_shift ) , false ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " sync_read_phys returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
} else if ( c - > chunk_item - > type & BLOCK_FLAG_RAID5 ) {
2019-09-01 12:53:20 +00:00
uint16_t i ;
uint8_t * scratch ;
2017-09-08 08:02:43 +00:00
2022-04-28 19:31:44 +00:00
scratch = ExAllocatePoolWithTag ( NonPagedPool , readlen < < Vcb - > sector_shift , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
if ( ! scratch ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
for ( i = 0 ; i < c - > chunk_item - > num_stripes ; i + + ) {
if ( i ! = stripe ) {
if ( ! c - > devices [ i ] - > devobj ) {
ExFreePool ( scratch ) ;
return STATUS_UNEXPECTED_IO_ERROR ;
}
if ( i = = 0 | | ( stripe = = 0 & & i = = 1 ) ) {
2022-04-28 19:31:44 +00:00
Status = sync_read_phys ( c - > devices [ i ] - > devobj , c - > devices [ i ] - > fileobj , cis [ i ] . offset + startoff + ( ( offset % sl ) < < Vcb - > sector_shift ) ,
readlen < < Vcb - > sector_shift , ps - > data + ( offset < < Vcb - > sector_shift ) , false ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " sync_read_phys returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( scratch ) ;
return Status ;
}
} else {
2022-04-28 19:31:44 +00:00
Status = sync_read_phys ( c - > devices [ i ] - > devobj , c - > devices [ i ] - > fileobj , cis [ i ] . offset + startoff + ( ( offset % sl ) < < Vcb - > sector_shift ) ,
readlen < < Vcb - > sector_shift , scratch , false ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " sync_read_phys returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( scratch ) ;
return Status ;
}
2022-04-28 19:31:44 +00:00
do_xor ( ps - > data + ( offset < < Vcb - > sector_shift ) , scratch , readlen < < Vcb - > sector_shift ) ;
2017-09-08 08:02:43 +00:00
}
}
}
ExFreePool ( scratch ) ;
} else {
2019-09-01 12:53:20 +00:00
uint8_t * scratch ;
uint16_t k , i , logstripe , error_stripe , num_errors = 0 ;
2017-09-08 08:02:43 +00:00
2022-04-28 19:31:44 +00:00
scratch = ExAllocatePoolWithTag ( NonPagedPool , ( c - > chunk_item - > num_stripes + 2 ) * readlen < < Vcb - > sector_shift , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
if ( ! scratch ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
i = ( parity + 1 ) % c - > chunk_item - > num_stripes ;
2022-04-28 19:33:48 +00:00
logstripe = ( c - > chunk_item - > num_stripes + c - > chunk_item - > num_stripes - 1 - parity + stripe ) % c - > chunk_item - > num_stripes ;
2017-09-08 08:02:43 +00:00
for ( k = 0 ; k < c - > chunk_item - > num_stripes ; k + + ) {
if ( i ! = stripe ) {
if ( c - > devices [ i ] - > devobj ) {
2022-04-28 19:31:44 +00:00
Status = sync_read_phys ( c - > devices [ i ] - > devobj , c - > devices [ i ] - > fileobj , cis [ i ] . offset + startoff + ( ( offset % sl ) < < Vcb - > sector_shift ) ,
readlen < < Vcb - > sector_shift , scratch + ( k * readlen < < Vcb - > sector_shift ) , false ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " sync_read_phys returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
num_errors + + ;
error_stripe = k ;
}
} else {
num_errors + + ;
error_stripe = k ;
}
if ( num_errors > 1 ) {
ExFreePool ( scratch ) ;
return STATUS_UNEXPECTED_IO_ERROR ;
}
2022-04-28 19:33:48 +00:00
}
2017-09-08 08:02:43 +00:00
i = ( i + 1 ) % c - > chunk_item - > num_stripes ;
}
if ( num_errors = = 0 | | error_stripe = = c - > chunk_item - > num_stripes - 1 ) {
for ( k = 0 ; k < c - > chunk_item - > num_stripes - 1 ; k + + ) {
if ( k ! = logstripe ) {
if ( k = = 0 | | ( k = = 1 & & logstripe = = 0 ) ) {
2022-04-28 19:31:44 +00:00
RtlCopyMemory ( ps - > data + ( offset < < Vcb - > sector_shift ) , scratch + ( k * readlen < < Vcb - > sector_shift ) ,
readlen < < Vcb - > sector_shift ) ;
2017-09-08 08:02:43 +00:00
} else {
2022-04-28 19:31:44 +00:00
do_xor ( ps - > data + ( offset < < Vcb - > sector_shift ) , scratch + ( k * readlen < < Vcb - > sector_shift ) ,
readlen < < Vcb - > sector_shift ) ;
2017-09-08 08:02:43 +00:00
}
}
}
} else {
2022-04-28 19:31:44 +00:00
raid6_recover2 ( scratch , c - > chunk_item - > num_stripes , readlen < < Vcb - > sector_shift , logstripe ,
error_stripe , scratch + ( c - > chunk_item - > num_stripes * readlen < < Vcb - > sector_shift ) ) ;
2017-09-08 08:02:43 +00:00
2022-04-28 19:31:44 +00:00
RtlCopyMemory ( ps - > data + ( offset < < Vcb - > sector_shift ) , scratch + ( c - > chunk_item - > num_stripes * readlen < < Vcb - > sector_shift ) ,
readlen < < Vcb - > sector_shift ) ;
2017-09-08 08:02:43 +00:00
}
ExFreePool ( scratch ) ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
offset + = readlen ;
len - = readlen ;
}
return STATUS_SUCCESS ;
}
NTSTATUS flush_partial_stripe ( device_extension * Vcb , chunk * c , partial_stripe * ps ) {
NTSTATUS Status ;
2019-09-01 12:53:20 +00:00
uint16_t parity2 , stripe , startoffstripe ;
uint8_t * data ;
uint64_t startoff ;
2017-09-08 08:02:43 +00:00
ULONG runlength , index , last1 ;
CHUNK_ITEM_STRIPE * cis = ( CHUNK_ITEM_STRIPE * ) & c - > chunk_item [ 1 ] ;
LIST_ENTRY * le ;
2019-09-01 12:53:20 +00:00
uint16_t k , num_data_stripes = c - > chunk_item - > num_stripes - ( c - > chunk_item - > type & BLOCK_FLAG_RAID5 ? 1 : 2 ) ;
uint64_t ps_length = num_data_stripes * c - > chunk_item - > stripe_length ;
2017-09-08 08:02:43 +00:00
ULONG stripe_length = ( ULONG ) c - > chunk_item - > stripe_length ;
// FIXME - do writes asynchronously?
get_raid0_offset ( ps - > address - c - > offset , stripe_length , num_data_stripes , & startoff , & startoffstripe ) ;
parity2 = ( ( ( ps - > address - c - > offset ) / ps_length ) + c - > chunk_item - > num_stripes - 1 ) % c - > chunk_item - > num_stripes ;
// read data (or reconstruct if degraded)
runlength = RtlFindFirstRunClear ( & ps - > bmp , & index ) ;
last1 = 0 ;
while ( runlength ! = 0 ) {
2019-09-01 12:53:20 +00:00
if ( index > = ps - > bmplen )
break ;
if ( index + runlength > = ps - > bmplen ) {
runlength = ps - > bmplen - index ;
if ( runlength = = 0 )
break ;
}
2017-09-08 08:02:43 +00:00
if ( index > last1 ) {
Status = partial_stripe_read ( Vcb , c , ps , startoff , parity2 , last1 , index - last1 ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " partial_stripe_read returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
}
last1 = index + runlength ;
runlength = RtlFindNextForwardRunClear ( & ps - > bmp , index + runlength , & index ) ;
}
2022-04-28 19:31:44 +00:00
if ( last1 < ps_length > > Vcb - > sector_shift ) {
Status = partial_stripe_read ( Vcb , c , ps , startoff , parity2 , last1 , ( ULONG ) ( ( ps_length > > Vcb - > sector_shift ) - last1 ) ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " partial_stripe_read returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
}
// set unallocated data to 0
le = c - > space . Flink ;
while ( le ! = & c - > space ) {
space * s = CONTAINING_RECORD ( le , space , list_entry ) ;
if ( s - > address + s - > size > ps - > address & & s - > address < ps - > address + ps_length ) {
2019-09-01 12:53:20 +00:00
uint64_t start = max ( ps - > address , s - > address ) ;
uint64_t end = min ( ps - > address + ps_length , s - > address + s - > size ) ;
2017-09-08 08:02:43 +00:00
RtlZeroMemory ( ps - > data + start - ps - > address , ( ULONG ) ( end - start ) ) ;
} else if ( s - > address > = ps - > address + ps_length )
break ;
le = le - > Flink ;
}
le = c - > deleting . Flink ;
while ( le ! = & c - > deleting ) {
space * s = CONTAINING_RECORD ( le , space , list_entry ) ;
if ( s - > address + s - > size > ps - > address & & s - > address < ps - > address + ps_length ) {
2019-09-01 12:53:20 +00:00
uint64_t start = max ( ps - > address , s - > address ) ;
uint64_t end = min ( ps - > address + ps_length , s - > address + s - > size ) ;
2017-09-08 08:02:43 +00:00
RtlZeroMemory ( ps - > data + start - ps - > address , ( ULONG ) ( end - start ) ) ;
} else if ( s - > address > = ps - > address + ps_length )
break ;
le = le - > Flink ;
}
stripe = ( parity2 + 1 ) % c - > chunk_item - > num_stripes ;
data = ps - > data ;
for ( k = 0 ; k < num_data_stripes ; k + + ) {
if ( c - > devices [ stripe ] - > devobj ) {
2019-09-01 12:53:20 +00:00
Status = write_data_phys ( c - > devices [ stripe ] - > devobj , c - > devices [ stripe ] - > fileobj , cis [ stripe ] . offset + startoff , data , stripe_length ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " write_data_phys returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
}
2017-09-08 08:02:43 +00:00
data + = stripe_length ;
stripe = ( stripe + 1 ) % c - > chunk_item - > num_stripes ;
}
// write parity
if ( c - > chunk_item - > type & BLOCK_FLAG_RAID5 ) {
if ( c - > devices [ parity2 ] - > devobj ) {
2019-09-01 12:53:20 +00:00
uint16_t i ;
2017-09-08 08:02:43 +00:00
for ( i = 1 ; i < c - > chunk_item - > num_stripes - 1 ; i + + ) {
do_xor ( ps - > data , ps - > data + ( i * stripe_length ) , stripe_length ) ;
}
2019-09-01 12:53:20 +00:00
Status = write_data_phys ( c - > devices [ parity2 ] - > devobj , c - > devices [ parity2 ] - > fileobj , cis [ parity2 ] . offset + startoff , ps - > data , stripe_length ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " write_data_phys returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
}
} else {
2019-09-01 12:53:20 +00:00
uint16_t parity1 = ( parity2 + c - > chunk_item - > num_stripes - 1 ) % c - > chunk_item - > num_stripes ;
2017-09-08 08:02:43 +00:00
if ( c - > devices [ parity1 ] - > devobj | | c - > devices [ parity2 ] - > devobj ) {
2019-09-01 12:53:20 +00:00
uint8_t * scratch ;
uint16_t i ;
2017-09-08 08:02:43 +00:00
scratch = ExAllocatePoolWithTag ( NonPagedPool , stripe_length * 2 , ALLOC_TAG ) ;
if ( ! scratch ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
i = c - > chunk_item - > num_stripes - 3 ;
2019-09-01 12:53:20 +00:00
while ( true ) {
2017-09-08 08:02:43 +00:00
if ( i = = c - > chunk_item - > num_stripes - 3 ) {
RtlCopyMemory ( scratch , ps - > data + ( i * stripe_length ) , stripe_length ) ;
RtlCopyMemory ( scratch + stripe_length , ps - > data + ( i * stripe_length ) , stripe_length ) ;
} else {
do_xor ( scratch , ps - > data + ( i * stripe_length ) , stripe_length ) ;
galois_double ( scratch + stripe_length , stripe_length ) ;
do_xor ( scratch + stripe_length , ps - > data + ( i * stripe_length ) , stripe_length ) ;
}
if ( i = = 0 )
break ;
i - - ;
}
if ( c - > devices [ parity1 ] - > devobj ) {
2019-09-01 12:53:20 +00:00
Status = write_data_phys ( c - > devices [ parity1 ] - > devobj , c - > devices [ parity1 ] - > fileobj , cis [ parity1 ] . offset + startoff , scratch , stripe_length ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " write_data_phys returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( scratch ) ;
return Status ;
}
}
if ( c - > devices [ parity2 ] - > devobj ) {
2019-09-01 12:53:20 +00:00
Status = write_data_phys ( c - > devices [ parity2 ] - > devobj , c - > devices [ parity2 ] - > fileobj , cis [ parity2 ] . offset + startoff ,
scratch + stripe_length , stripe_length ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " write_data_phys returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( scratch ) ;
return Status ;
}
}
ExFreePool ( scratch ) ;
}
}
return STATUS_SUCCESS ;
}
static NTSTATUS update_chunks ( device_extension * Vcb , LIST_ENTRY * batchlist , PIRP Irp , LIST_ENTRY * rollback ) {
LIST_ENTRY * le , * le2 ;
NTSTATUS Status ;
2019-09-01 12:53:20 +00:00
uint64_t used_minus_cache ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( & Vcb - > chunk_lock , true ) ;
2017-09-08 08:02:43 +00:00
// FIXME - do tree chunks before data chunks
le = Vcb - > chunks . Flink ;
while ( le ! = & Vcb - > chunks ) {
chunk * c = CONTAINING_RECORD ( le , chunk , list_entry ) ;
le2 = le - > Flink ;
if ( c - > changed ) {
2018-12-16 11:03:16 +00:00
acquire_chunk_lock ( c , Vcb ) ;
2017-09-08 08:02:43 +00:00
// flush partial stripes
if ( ! Vcb - > readonly & & ( c - > chunk_item - > type & BLOCK_FLAG_RAID5 | | c - > chunk_item - > type & BLOCK_FLAG_RAID6 ) ) {
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( & c - > partial_stripes_lock , true ) ;
2017-09-08 08:02:43 +00:00
while ( ! IsListEmpty ( & c - > partial_stripes ) ) {
partial_stripe * ps = CONTAINING_RECORD ( RemoveHeadList ( & c - > partial_stripes ) , partial_stripe , list_entry ) ;
Status = flush_partial_stripe ( Vcb , c , ps ) ;
if ( ps - > bmparr )
ExFreePool ( ps - > bmparr ) ;
ExFreePool ( ps ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " flush_partial_stripe returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
ExReleaseResourceLite ( & c - > partial_stripes_lock ) ;
2018-12-16 11:03:16 +00:00
release_chunk_lock ( c , Vcb ) ;
2017-09-08 08:02:43 +00:00
ExReleaseResourceLite ( & Vcb - > chunk_lock ) ;
return Status ;
}
}
ExReleaseResourceLite ( & c - > partial_stripes_lock ) ;
}
if ( c - > list_entry_balance . Flink ) {
2018-12-16 11:03:16 +00:00
release_chunk_lock ( c , Vcb ) ;
2017-09-08 08:02:43 +00:00
le = le2 ;
continue ;
}
if ( c - > space_changed | | c - > created ) {
2019-09-01 12:53:20 +00:00
bool created = c - > created ;
2018-12-16 11:03:16 +00:00
2017-09-08 08:02:43 +00:00
used_minus_cache = c - > used ;
// subtract self-hosted cache
if ( used_minus_cache > 0 & & c - > chunk_item - > type & BLOCK_FLAG_DATA & & c - > cache & & c - > cache - > inode_item . st_size = = c - > used ) {
LIST_ENTRY * le3 ;
le3 = c - > cache - > extents . Flink ;
while ( le3 ! = & c - > cache - > extents ) {
extent * ext = CONTAINING_RECORD ( le3 , extent , list_entry ) ;
EXTENT_DATA * ed = & ext - > extent_data ;
if ( ! ext - > ignore ) {
if ( ed - > type = = EXTENT_TYPE_REGULAR | | ed - > type = = EXTENT_TYPE_PREALLOC ) {
EXTENT_DATA2 * ed2 = ( EXTENT_DATA2 * ) ed - > data ;
if ( ed2 - > size ! = 0 & & ed2 - > address > = c - > offset & & ed2 - > address + ed2 - > size < = c - > offset + c - > chunk_item - > size )
used_minus_cache - = ed2 - > size ;
}
}
le3 = le3 - > Flink ;
}
}
if ( used_minus_cache = = 0 ) {
Status = drop_chunk ( Vcb , c , batchlist , Irp , rollback ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " drop_chunk returned %08lx \n " , Status ) ;
2018-12-16 11:03:16 +00:00
release_chunk_lock ( c , Vcb ) ;
2017-09-08 08:02:43 +00:00
ExReleaseResourceLite ( & Vcb - > chunk_lock ) ;
return Status ;
}
2018-12-16 11:03:16 +00:00
// c is now freed, so avoid releasing non-existent lock
le = le2 ;
continue ;
2017-09-08 08:02:43 +00:00
} else if ( c - > created ) {
Status = create_chunk ( Vcb , c , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " create_chunk returned %08lx \n " , Status ) ;
2018-12-16 11:03:16 +00:00
release_chunk_lock ( c , Vcb ) ;
2017-09-08 08:02:43 +00:00
ExReleaseResourceLite ( & Vcb - > chunk_lock ) ;
return Status ;
}
}
2018-12-16 11:03:16 +00:00
if ( used_minus_cache > 0 | | created )
release_chunk_lock ( c , Vcb ) ;
} else
release_chunk_lock ( c , Vcb ) ;
2017-09-08 08:02:43 +00:00
}
2016-10-29 17:05:10 +00:00
le = le2 ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ExReleaseResourceLite ( & Vcb - > chunk_lock ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
return STATUS_SUCCESS ;
}
2019-09-01 12:53:20 +00:00
static NTSTATUS delete_root_ref ( device_extension * Vcb , uint64_t subvolid , uint64_t parsubvolid , uint64_t parinode , PANSI_STRING utf8 , PIRP Irp ) {
2016-10-29 17:05:10 +00:00
KEY searchkey ;
traverse_ptr tp ;
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
searchkey . obj_id = parsubvolid ;
searchkey . obj_type = TYPE_ROOT_REF ;
searchkey . offset = subvolid ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > root_root , & tp , & searchkey , false , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - find_item returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! keycmp ( searchkey , tp . item - > key ) ) {
if ( tp . item - > size < sizeof ( ROOT_REF ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " (%I64x,%x,%I64x) was %u bytes, expected at least %Iu \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , tp . item - > size , sizeof ( ROOT_REF ) ) ;
2016-10-29 17:05:10 +00:00
return STATUS_INTERNAL_ERROR ;
} else {
ROOT_REF * rr ;
ULONG len ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
rr = ( ROOT_REF * ) tp . item - > data ;
len = tp . item - > size ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
do {
2019-09-01 12:53:20 +00:00
uint16_t itemlen ;
2017-09-08 08:02:43 +00:00
if ( len < sizeof ( ROOT_REF ) | | len < offsetof ( ROOT_REF , name [ 0 ] ) + rr - > n ) {
2019-09-01 12:53:20 +00:00
ERR ( " (%I64x,%x,%I64x) was truncated \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset ) ;
2016-10-29 17:05:10 +00:00
break ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
itemlen = ( uint16_t ) offsetof ( ROOT_REF , name [ 0 ] ) + rr - > n ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( rr - > dir = = parinode & & rr - > n = = utf8 - > Length & & RtlCompareMemory ( rr - > name , utf8 - > Buffer , rr - > n ) = = rr - > n ) {
2019-09-01 12:53:20 +00:00
uint16_t newlen = tp . item - > size - itemlen ;
2017-09-08 08:02:43 +00:00
Status = delete_tree_item ( Vcb , & tp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
2016-10-29 17:05:10 +00:00
if ( newlen = = 0 ) {
2019-09-01 12:53:20 +00:00
TRACE ( " deleting (%I64x,%x,%I64x) \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset ) ;
2016-10-29 17:05:10 +00:00
} else {
2019-09-01 12:53:20 +00:00
uint8_t * newrr = ExAllocatePoolWithTag ( PagedPool , newlen , ALLOC_TAG ) , * rroff ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! newrr ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
TRACE ( " modifying (%I64x,%x,%I64x) \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset ) ;
2016-10-29 17:05:10 +00:00
2019-09-01 12:53:20 +00:00
if ( ( uint8_t * ) rr > tp . item - > data ) {
RtlCopyMemory ( newrr , tp . item - > data , ( uint8_t * ) rr - tp . item - > data ) ;
rroff = newrr + ( ( uint8_t * ) rr - tp . item - > data ) ;
2016-10-29 17:05:10 +00:00
} else {
rroff = newrr ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
if ( ( uint8_t * ) & rr - > name [ rr - > n ] < tp . item - > data + tp . item - > size )
RtlCopyMemory ( rroff , & rr - > name [ rr - > n ] , tp . item - > size - ( ( uint8_t * ) & rr - > name [ rr - > n ] - tp . item - > data ) ) ;
2017-09-08 08:02:43 +00:00
Status = insert_tree_item ( Vcb , Vcb - > root_root , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , newrr , newlen , NULL , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( newrr ) ;
return Status ;
}
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
break ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( len > itemlen ) {
len - = itemlen ;
rr = ( ROOT_REF * ) & rr - > name [ rr - > n ] ;
} else
break ;
} while ( len > 0 ) ;
}
} else {
2019-09-01 12:53:20 +00:00
WARN ( " could not find ROOT_REF entry for subvol %I64x in %I64x \n " , searchkey . offset , searchkey . obj_id ) ;
2016-10-29 17:05:10 +00:00
return STATUS_NOT_FOUND ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
# ifdef _MSC_VER
# pragma warning(push)
# pragma warning(suppress: 28194)
# endif
2019-09-01 12:53:20 +00:00
static NTSTATUS add_root_ref ( _In_ device_extension * Vcb , _In_ uint64_t subvolid , _In_ uint64_t parsubvolid , _In_ __drv_aliasesMem ROOT_REF * rr , _In_opt_ PIRP Irp ) {
2016-10-29 17:05:10 +00:00
KEY searchkey ;
traverse_ptr tp ;
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
searchkey . obj_id = parsubvolid ;
searchkey . obj_type = TYPE_ROOT_REF ;
searchkey . offset = subvolid ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > root_root , & tp , & searchkey , false , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - find_item returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! keycmp ( searchkey , tp . item - > key ) ) {
2019-09-01 12:53:20 +00:00
uint16_t rrsize = tp . item - > size + ( uint16_t ) offsetof ( ROOT_REF , name [ 0 ] ) + rr - > n ;
uint8_t * rr2 ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
rr2 = ExAllocatePoolWithTag ( PagedPool , rrsize , ALLOC_TAG ) ;
if ( ! rr2 ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( tp . item - > size > 0 )
RtlCopyMemory ( rr2 , tp . item - > data , tp . item - > size ) ;
2017-09-08 08:02:43 +00:00
RtlCopyMemory ( rr2 + tp . item - > size , rr , offsetof ( ROOT_REF , name [ 0 ] ) + rr - > n ) ;
2016-10-29 17:05:10 +00:00
ExFreePool ( rr ) ;
2017-09-08 08:02:43 +00:00
Status = delete_tree_item ( Vcb , & tp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
ExFreePool ( rr2 ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
Status = insert_tree_item ( Vcb , Vcb - > root_root , searchkey . obj_id , searchkey . obj_type , searchkey . offset , rr2 , rrsize , NULL , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( rr2 ) ;
return Status ;
2016-10-29 17:05:10 +00:00
}
} else {
2019-09-01 12:53:20 +00:00
Status = insert_tree_item ( Vcb , Vcb - > root_root , searchkey . obj_id , searchkey . obj_type , searchkey . offset , rr , ( uint16_t ) offsetof ( ROOT_REF , name [ 0 ] ) + rr - > n , NULL , Irp ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
ExFreePool ( rr ) ;
2017-09-08 08:02:43 +00:00
return Status ;
2016-10-29 17:05:10 +00:00
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
# ifdef _MSC_VER
# pragma warning(pop)
# endif
2016-10-29 17:05:10 +00:00
2019-09-01 12:53:20 +00:00
static NTSTATUS update_root_backref ( device_extension * Vcb , uint64_t subvolid , uint64_t parsubvolid , PIRP Irp ) {
2016-10-29 17:05:10 +00:00
KEY searchkey ;
traverse_ptr tp ;
2019-09-01 12:53:20 +00:00
uint8_t * data ;
uint16_t datalen ;
2016-10-29 17:05:10 +00:00
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
searchkey . obj_id = parsubvolid ;
searchkey . obj_type = TYPE_ROOT_REF ;
searchkey . offset = subvolid ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > root_root , & tp , & searchkey , false , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - find_item returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! keycmp ( tp . item - > key , searchkey ) & & tp . item - > size > 0 ) {
datalen = tp . item - > size ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
data = ExAllocatePoolWithTag ( PagedPool , datalen , ALLOC_TAG ) ;
if ( ! data ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
RtlCopyMemory ( data , tp . item - > data , datalen ) ;
} else {
datalen = 0 ;
2017-09-08 08:02:43 +00:00
data = NULL ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
searchkey . obj_id = subvolid ;
searchkey . obj_type = TYPE_ROOT_BACKREF ;
searchkey . offset = parsubvolid ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > root_root , & tp , & searchkey , false , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - find_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( datalen > 0 )
ExFreePool ( data ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
if ( ! keycmp ( tp . item - > key , searchkey ) ) {
Status = delete_tree_item ( Vcb , & tp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
if ( datalen > 0 )
ExFreePool ( data ) ;
return Status ;
}
}
2016-10-29 17:05:10 +00:00
if ( datalen > 0 ) {
2017-09-08 08:02:43 +00:00
Status = insert_tree_item ( Vcb , Vcb - > root_root , subvolid , TYPE_ROOT_BACKREF , parsubvolid , data , datalen , NULL , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
ExFreePool ( data ) ;
2017-09-08 08:02:43 +00:00
return Status ;
2016-10-29 17:05:10 +00:00
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
return STATUS_SUCCESS ;
}
2019-09-01 12:53:20 +00:00
static NTSTATUS add_root_item_to_cache ( device_extension * Vcb , uint64_t root , PIRP Irp ) {
2016-10-29 17:05:10 +00:00
KEY searchkey ;
traverse_ptr tp ;
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
searchkey . obj_id = root ;
searchkey . obj_type = TYPE_ROOT_ITEM ;
searchkey . offset = 0xffffffffffffffff ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > root_root , & tp , & searchkey , false , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - find_item returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( tp . item - > key . obj_id ! = searchkey . obj_id | | tp . item - > key . obj_type ! = searchkey . obj_type ) {
2019-09-01 12:53:20 +00:00
ERR ( " could not find ROOT_ITEM for tree %I64x \n " , searchkey . obj_id ) ;
2016-10-29 17:05:10 +00:00
return STATUS_INTERNAL_ERROR ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( tp . item - > size < sizeof ( ROOT_ITEM ) ) { // if not full length, create new entry with new bits zeroed
ROOT_ITEM * ri = ExAllocatePoolWithTag ( PagedPool , sizeof ( ROOT_ITEM ) , ALLOC_TAG ) ;
if ( ! ri ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( tp . item - > size > 0 )
RtlCopyMemory ( ri , tp . item - > data , tp . item - > size ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
RtlZeroMemory ( ( ( uint8_t * ) ri ) + tp . item - > size , sizeof ( ROOT_ITEM ) - tp . item - > size ) ;
2017-09-08 08:02:43 +00:00
Status = delete_tree_item ( Vcb , & tp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( ri ) ;
return Status ;
}
Status = insert_tree_item ( Vcb , Vcb - > root_root , searchkey . obj_id , searchkey . obj_type , tp . item - > key . offset , ri , sizeof ( ROOT_ITEM ) , NULL , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( ri ) ;
return Status ;
2016-10-29 17:05:10 +00:00
}
} else {
2019-09-01 12:53:20 +00:00
tp . tree - > write = true ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
static NTSTATUS flush_fileref ( file_ref * fileref , LIST_ENTRY * batchlist , PIRP Irp ) {
2016-10-29 17:05:10 +00:00
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
// if fileref created and then immediately deleted, do nothing
if ( fileref - > created & & fileref - > deleted ) {
2019-09-01 12:53:20 +00:00
fileref - > dirty = false ;
2016-10-29 17:05:10 +00:00
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( fileref - > fcb - > ads ) {
2019-09-01 12:53:20 +00:00
fileref - > dirty = false ;
2016-10-29 17:05:10 +00:00
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( fileref - > created ) {
2019-09-01 12:53:20 +00:00
uint16_t disize ;
2016-10-29 17:05:10 +00:00
DIR_ITEM * di , * di2 ;
2019-09-01 12:53:20 +00:00
uint32_t crc32 ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
crc32 = calc_crc32c ( 0xfffffffe , ( uint8_t * ) fileref - > dc - > utf8 . Buffer , fileref - > dc - > utf8 . Length ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
disize = ( uint16_t ) ( offsetof ( DIR_ITEM , name [ 0 ] ) + fileref - > dc - > utf8 . Length ) ;
2016-10-29 17:05:10 +00:00
di = ExAllocatePoolWithTag ( PagedPool , disize , ALLOC_TAG ) ;
if ( ! di ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( fileref - > parent - > fcb - > subvol = = fileref - > fcb - > subvol ) {
di - > key . obj_id = fileref - > fcb - > inode ;
di - > key . obj_type = TYPE_INODE_ITEM ;
di - > key . offset = 0 ;
} else { // subvolume
di - > key . obj_id = fileref - > fcb - > subvol - > id ;
di - > key . obj_type = TYPE_ROOT_ITEM ;
di - > key . offset = 0xffffffffffffffff ;
}
di - > transid = fileref - > fcb - > Vcb - > superblock . generation ;
di - > m = 0 ;
2019-09-01 12:53:20 +00:00
di - > n = ( uint16_t ) fileref - > dc - > utf8 . Length ;
2016-10-29 17:05:10 +00:00
di - > type = fileref - > fcb - > type ;
2017-09-08 08:02:43 +00:00
RtlCopyMemory ( di - > name , fileref - > dc - > utf8 . Buffer , fileref - > dc - > utf8 . Length ) ;
2016-10-29 17:05:10 +00:00
di2 = ExAllocatePoolWithTag ( PagedPool , disize , ALLOC_TAG ) ;
if ( ! di2 ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
RtlCopyMemory ( di2 , di , disize ) ;
2017-09-08 08:02:43 +00:00
Status = insert_tree_item_batch ( batchlist , fileref - > fcb - > Vcb , fileref - > parent - > fcb - > subvol , fileref - > parent - > fcb - > inode , TYPE_DIR_INDEX ,
fileref - > dc - > index , di , disize , Batch_Insert ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item_batch returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
Status = insert_tree_item_batch ( batchlist , fileref - > fcb - > Vcb , fileref - > parent - > fcb - > subvol , fileref - > parent - > fcb - > inode , TYPE_DIR_ITEM , crc32 ,
di2 , disize , Batch_DirItem ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item_batch returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( fileref - > parent - > fcb - > subvol = = fileref - > fcb - > subvol ) {
INODE_REF * ir ;
2017-09-08 08:02:43 +00:00
ir = ExAllocatePoolWithTag ( PagedPool , sizeof ( INODE_REF ) - 1 + fileref - > dc - > utf8 . Length , ALLOC_TAG ) ;
2016-10-29 17:05:10 +00:00
if ( ! ir ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
ir - > index = fileref - > dc - > index ;
ir - > n = fileref - > dc - > utf8 . Length ;
RtlCopyMemory ( ir - > name , fileref - > dc - > utf8 . Buffer , ir - > n ) ;
Status = insert_tree_item_batch ( batchlist , fileref - > fcb - > Vcb , fileref - > fcb - > subvol , fileref - > fcb - > inode , TYPE_INODE_REF , fileref - > parent - > fcb - > inode ,
ir , sizeof ( INODE_REF ) - 1 + ir - > n , Batch_InodeRef ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item_batch returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
} else if ( fileref - > fcb ! = fileref - > fcb - > Vcb - > dummy_fcb ) {
2016-10-29 17:05:10 +00:00
ULONG rrlen ;
ROOT_REF * rr ;
2017-09-08 08:02:43 +00:00
rrlen = sizeof ( ROOT_REF ) - 1 + fileref - > dc - > utf8 . Length ;
2016-10-29 17:05:10 +00:00
rr = ExAllocatePoolWithTag ( PagedPool , rrlen , ALLOC_TAG ) ;
if ( ! rr ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
rr - > dir = fileref - > parent - > fcb - > inode ;
2017-09-08 08:02:43 +00:00
rr - > index = fileref - > dc - > index ;
rr - > n = fileref - > dc - > utf8 . Length ;
RtlCopyMemory ( rr - > name , fileref - > dc - > utf8 . Buffer , fileref - > dc - > utf8 . Length ) ;
Status = add_root_ref ( fileref - > fcb - > Vcb , fileref - > fcb - > subvol - > id , fileref - > parent - > fcb - > subvol - > id , rr , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " add_root_ref returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
Status = update_root_backref ( fileref - > fcb - > Vcb , fileref - > fcb - > subvol - > id , fileref - > parent - > fcb - > subvol - > id , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " update_root_backref returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
fileref - > created = false ;
2016-10-29 17:05:10 +00:00
} else if ( fileref - > deleted ) {
2019-09-01 12:53:20 +00:00
uint32_t crc32 ;
2016-10-29 17:05:10 +00:00
ANSI_STRING * name ;
2017-01-01 17:12:12 +00:00
DIR_ITEM * di ;
2017-09-08 08:02:43 +00:00
name = & fileref - > oldutf8 ;
2016-10-29 17:05:10 +00:00
2019-09-01 12:53:20 +00:00
crc32 = calc_crc32c ( 0xfffffffe , ( uint8_t * ) name - > Buffer , name - > Length ) ;
2016-10-29 17:05:10 +00:00
2017-01-01 17:12:12 +00:00
di = ExAllocatePoolWithTag ( PagedPool , sizeof ( DIR_ITEM ) - 1 + name - > Length , ALLOC_TAG ) ;
if ( ! di ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
di - > m = 0 ;
di - > n = name - > Length ;
RtlCopyMemory ( di - > name , name - > Buffer , name - > Length ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
// delete DIR_ITEM (0x54)
2017-09-08 08:02:43 +00:00
Status = insert_tree_item_batch ( batchlist , fileref - > fcb - > Vcb , fileref - > parent - > fcb - > subvol , fileref - > parent - > fcb - > inode , TYPE_DIR_ITEM ,
crc32 , di , sizeof ( DIR_ITEM ) - 1 + name - > Length , Batch_DeleteDirItem ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item_batch returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( fileref - > parent - > fcb - > subvol = = fileref - > fcb - > subvol ) {
2017-01-01 17:12:12 +00:00
INODE_REF * ir ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
// delete INODE_REF (0xc)
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
ir = ExAllocatePoolWithTag ( PagedPool , sizeof ( INODE_REF ) - 1 + name - > Length , ALLOC_TAG ) ;
if ( ! ir ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
ir - > index = fileref - > oldindex ;
2017-01-01 17:12:12 +00:00
ir - > n = name - > Length ;
RtlCopyMemory ( ir - > name , name - > Buffer , name - > Length ) ;
2017-09-08 08:02:43 +00:00
Status = insert_tree_item_batch ( batchlist , fileref - > fcb - > Vcb , fileref - > parent - > fcb - > subvol , fileref - > fcb - > inode , TYPE_INODE_REF ,
fileref - > parent - > fcb - > inode , ir , sizeof ( INODE_REF ) - 1 + name - > Length , Batch_DeleteInodeRef ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item_batch returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
} else if ( fileref - > fcb ! = fileref - > fcb - > Vcb - > dummy_fcb ) { // subvolume
Status = delete_root_ref ( fileref - > fcb - > Vcb , fileref - > fcb - > subvol - > id , fileref - > parent - > fcb - > subvol - > id , fileref - > parent - > fcb - > inode , name , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_root_ref returned %08lx \n " , Status ) ;
2017-01-01 17:12:12 +00:00
return Status ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
Status = update_root_backref ( fileref - > fcb - > Vcb , fileref - > fcb - > subvol - > id , fileref - > parent - > fcb - > subvol - > id , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " update_root_backref returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
// delete DIR_INDEX (0x60)
2017-09-08 08:02:43 +00:00
Status = insert_tree_item_batch ( batchlist , fileref - > fcb - > Vcb , fileref - > parent - > fcb - > subvol , fileref - > parent - > fcb - > inode , TYPE_DIR_INDEX ,
fileref - > oldindex , NULL , 0 , Batch_Delete ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item_batch returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( fileref - > oldutf8 . Buffer ) {
ExFreePool ( fileref - > oldutf8 . Buffer ) ;
fileref - > oldutf8 . Buffer = NULL ;
}
} else { // rename or change type
2017-09-08 08:02:43 +00:00
PANSI_STRING oldutf8 = fileref - > oldutf8 . Buffer ? & fileref - > oldutf8 : & fileref - > dc - > utf8 ;
2019-09-01 12:53:20 +00:00
uint32_t crc32 , oldcrc32 ;
uint16_t disize ;
2017-01-01 17:12:12 +00:00
DIR_ITEM * olddi , * di , * di2 ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
crc32 = calc_crc32c ( 0xfffffffe , ( uint8_t * ) fileref - > dc - > utf8 . Buffer , fileref - > dc - > utf8 . Length ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! fileref - > oldutf8 . Buffer )
oldcrc32 = crc32 ;
else
2019-09-01 12:53:20 +00:00
oldcrc32 = calc_crc32c ( 0xfffffffe , ( uint8_t * ) fileref - > oldutf8 . Buffer , fileref - > oldutf8 . Length ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
olddi = ExAllocatePoolWithTag ( PagedPool , sizeof ( DIR_ITEM ) - 1 + oldutf8 - > Length , ALLOC_TAG ) ;
if ( ! olddi ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
olddi - > m = 0 ;
2019-09-01 12:53:20 +00:00
olddi - > n = ( uint16_t ) oldutf8 - > Length ;
2017-01-01 17:12:12 +00:00
RtlCopyMemory ( olddi - > name , oldutf8 - > Buffer , oldutf8 - > Length ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
// delete DIR_ITEM (0x54)
2017-09-08 08:02:43 +00:00
Status = insert_tree_item_batch ( batchlist , fileref - > fcb - > Vcb , fileref - > parent - > fcb - > subvol , fileref - > parent - > fcb - > inode , TYPE_DIR_ITEM ,
oldcrc32 , olddi , sizeof ( DIR_ITEM ) - 1 + oldutf8 - > Length , Batch_DeleteDirItem ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item_batch returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( olddi ) ;
return Status ;
2017-01-01 17:12:12 +00:00
}
2016-10-29 17:05:10 +00:00
// add DIR_ITEM (0x54)
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
disize = ( uint16_t ) ( offsetof ( DIR_ITEM , name [ 0 ] ) + fileref - > dc - > utf8 . Length ) ;
2016-10-29 17:05:10 +00:00
di = ExAllocatePoolWithTag ( PagedPool , disize , ALLOC_TAG ) ;
if ( ! di ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
di2 = ExAllocatePoolWithTag ( PagedPool , disize , ALLOC_TAG ) ;
if ( ! di2 ) {
ERR ( " out of memory \n " ) ;
ExFreePool ( di ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
if ( fileref - > dc )
di - > key = fileref - > dc - > key ;
else if ( fileref - > parent - > fcb - > subvol = = fileref - > fcb - > subvol ) {
2016-10-29 17:05:10 +00:00
di - > key . obj_id = fileref - > fcb - > inode ;
di - > key . obj_type = TYPE_INODE_ITEM ;
di - > key . offset = 0 ;
} else { // subvolume
di - > key . obj_id = fileref - > fcb - > subvol - > id ;
di - > key . obj_type = TYPE_ROOT_ITEM ;
di - > key . offset = 0xffffffffffffffff ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
di - > transid = fileref - > fcb - > Vcb - > superblock . generation ;
di - > m = 0 ;
2019-09-01 12:53:20 +00:00
di - > n = ( uint16_t ) fileref - > dc - > utf8 . Length ;
2016-10-29 17:05:10 +00:00
di - > type = fileref - > fcb - > type ;
2017-09-08 08:02:43 +00:00
RtlCopyMemory ( di - > name , fileref - > dc - > utf8 . Buffer , fileref - > dc - > utf8 . Length ) ;
2016-10-29 17:05:10 +00:00
RtlCopyMemory ( di2 , di , disize ) ;
2017-09-08 08:02:43 +00:00
Status = insert_tree_item_batch ( batchlist , fileref - > fcb - > Vcb , fileref - > parent - > fcb - > subvol , fileref - > parent - > fcb - > inode , TYPE_DIR_ITEM , crc32 ,
di , disize , Batch_DirItem ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item_batch returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( di2 ) ;
ExFreePool ( di ) ;
return Status ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( fileref - > parent - > fcb - > subvol = = fileref - > fcb - > subvol ) {
2017-01-01 17:12:12 +00:00
INODE_REF * ir , * ir2 ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
// delete INODE_REF (0xc)
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
ir = ExAllocatePoolWithTag ( PagedPool , sizeof ( INODE_REF ) - 1 + oldutf8 - > Length , ALLOC_TAG ) ;
if ( ! ir ) {
ERR ( " out of memory \n " ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( di2 ) ;
2017-01-01 17:12:12 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
ir - > index = fileref - > dc - > index ;
2017-01-01 17:12:12 +00:00
ir - > n = oldutf8 - > Length ;
RtlCopyMemory ( ir - > name , oldutf8 - > Buffer , ir - > n ) ;
2017-09-08 08:02:43 +00:00
Status = insert_tree_item_batch ( batchlist , fileref - > fcb - > Vcb , fileref - > fcb - > subvol , fileref - > fcb - > inode , TYPE_INODE_REF , fileref - > parent - > fcb - > inode ,
ir , sizeof ( INODE_REF ) - 1 + ir - > n , Batch_DeleteInodeRef ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item_batch returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( ir ) ;
ExFreePool ( di2 ) ;
return Status ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
// add INODE_REF (0xc)
2017-09-08 08:02:43 +00:00
ir2 = ExAllocatePoolWithTag ( PagedPool , sizeof ( INODE_REF ) - 1 + fileref - > dc - > utf8 . Length , ALLOC_TAG ) ;
2017-01-01 17:12:12 +00:00
if ( ! ir2 ) {
ERR ( " out of memory \n " ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( di2 ) ;
2017-01-01 17:12:12 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
ir2 - > index = fileref - > dc - > index ;
ir2 - > n = fileref - > dc - > utf8 . Length ;
RtlCopyMemory ( ir2 - > name , fileref - > dc - > utf8 . Buffer , ir2 - > n ) ;
Status = insert_tree_item_batch ( batchlist , fileref - > fcb - > Vcb , fileref - > fcb - > subvol , fileref - > fcb - > inode , TYPE_INODE_REF , fileref - > parent - > fcb - > inode ,
ir2 , sizeof ( INODE_REF ) - 1 + ir2 - > n , Batch_InodeRef ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item_batch returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( ir2 ) ;
ExFreePool ( di2 ) ;
return Status ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
} else if ( fileref - > fcb ! = fileref - > fcb - > Vcb - > dummy_fcb ) { // subvolume
2016-10-29 17:05:10 +00:00
ULONG rrlen ;
ROOT_REF * rr ;
2017-09-08 08:02:43 +00:00
Status = delete_root_ref ( fileref - > fcb - > Vcb , fileref - > fcb - > subvol - > id , fileref - > parent - > fcb - > subvol - > id , fileref - > parent - > fcb - > inode , oldutf8 , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_root_ref returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( di2 ) ;
return Status ;
}
rrlen = sizeof ( ROOT_REF ) - 1 + fileref - > dc - > utf8 . Length ;
rr = ExAllocatePoolWithTag ( PagedPool , rrlen , ALLOC_TAG ) ;
if ( ! rr ) {
ERR ( " out of memory \n " ) ;
ExFreePool ( di2 ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
rr - > dir = fileref - > parent - > fcb - > inode ;
rr - > index = fileref - > dc - > index ;
rr - > n = fileref - > dc - > utf8 . Length ;
RtlCopyMemory ( rr - > name , fileref - > dc - > utf8 . Buffer , fileref - > dc - > utf8 . Length ) ;
Status = add_root_ref ( fileref - > fcb - > Vcb , fileref - > fcb - > subvol - > id , fileref - > parent - > fcb - > subvol - > id , rr , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " add_root_ref returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( di2 ) ;
return Status ;
}
Status = update_root_backref ( fileref - > fcb - > Vcb , fileref - > fcb - > subvol - > id , fileref - > parent - > fcb - > subvol - > id , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " update_root_backref returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( di2 ) ;
return Status ;
}
}
// delete DIR_INDEX (0x60)
Status = insert_tree_item_batch ( batchlist , fileref - > fcb - > Vcb , fileref - > parent - > fcb - > subvol , fileref - > parent - > fcb - > inode , TYPE_DIR_INDEX ,
fileref - > dc - > index , NULL , 0 , Batch_Delete ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item_batch returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( di2 ) ;
return Status ;
}
// add DIR_INDEX (0x60)
Status = insert_tree_item_batch ( batchlist , fileref - > fcb - > Vcb , fileref - > parent - > fcb - > subvol , fileref - > parent - > fcb - > inode , TYPE_DIR_INDEX ,
fileref - > dc - > index , di2 , disize , Batch_Insert ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item_batch returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( di2 ) ;
return Status ;
}
if ( fileref - > oldutf8 . Buffer ) {
ExFreePool ( fileref - > oldutf8 . Buffer ) ;
fileref - > oldutf8 . Buffer = NULL ;
}
}
2019-09-01 12:53:20 +00:00
fileref - > dirty = false ;
2017-09-08 08:02:43 +00:00
return STATUS_SUCCESS ;
}
static void flush_disk_caches ( device_extension * Vcb ) {
LIST_ENTRY * le ;
ioctl_context context ;
ULONG num ;
context . left = 0 ;
le = Vcb - > devices . Flink ;
while ( le ! = & Vcb - > devices ) {
device * dev = CONTAINING_RECORD ( le , device , list_entry ) ;
if ( dev - > devobj & & ! dev - > readonly & & dev - > can_flush )
context . left + + ;
le = le - > Flink ;
}
if ( context . left = = 0 )
return ;
num = 0 ;
2019-09-01 12:53:20 +00:00
KeInitializeEvent ( & context . Event , NotificationEvent , false ) ;
2017-09-08 08:02:43 +00:00
context . stripes = ExAllocatePoolWithTag ( NonPagedPool , sizeof ( ioctl_context_stripe ) * context . left , ALLOC_TAG ) ;
if ( ! context . stripes ) {
ERR ( " out of memory \n " ) ;
return ;
}
RtlZeroMemory ( context . stripes , sizeof ( ioctl_context_stripe ) * context . left ) ;
le = Vcb - > devices . Flink ;
while ( le ! = & Vcb - > devices ) {
device * dev = CONTAINING_RECORD ( le , device , list_entry ) ;
if ( dev - > devobj & & ! dev - > readonly & & dev - > can_flush ) {
PIO_STACK_LOCATION IrpSp ;
ioctl_context_stripe * stripe = & context . stripes [ num ] ;
RtlZeroMemory ( & stripe - > apte , sizeof ( ATA_PASS_THROUGH_EX ) ) ;
stripe - > apte . Length = sizeof ( ATA_PASS_THROUGH_EX ) ;
stripe - > apte . TimeOutValue = 5 ;
stripe - > apte . CurrentTaskFile [ 6 ] = IDE_COMMAND_FLUSH_CACHE ;
2019-09-01 12:53:20 +00:00
stripe - > Irp = IoAllocateIrp ( dev - > devobj - > StackSize , false ) ;
2017-09-08 08:02:43 +00:00
if ( ! stripe - > Irp ) {
ERR ( " IoAllocateIrp failed \n " ) ;
goto nextdev ;
}
IrpSp = IoGetNextIrpStackLocation ( stripe - > Irp ) ;
IrpSp - > MajorFunction = IRP_MJ_DEVICE_CONTROL ;
2019-09-01 12:53:20 +00:00
IrpSp - > FileObject = dev - > fileobj ;
2017-09-08 08:02:43 +00:00
IrpSp - > Parameters . DeviceIoControl . IoControlCode = IOCTL_ATA_PASS_THROUGH ;
IrpSp - > Parameters . DeviceIoControl . InputBufferLength = sizeof ( ATA_PASS_THROUGH_EX ) ;
IrpSp - > Parameters . DeviceIoControl . OutputBufferLength = sizeof ( ATA_PASS_THROUGH_EX ) ;
stripe - > Irp - > AssociatedIrp . SystemBuffer = & stripe - > apte ;
stripe - > Irp - > Flags | = IRP_BUFFERED_IO | IRP_INPUT_OPERATION ;
stripe - > Irp - > UserBuffer = & stripe - > apte ;
stripe - > Irp - > UserIosb = & stripe - > iosb ;
2019-09-01 12:53:20 +00:00
IoSetCompletionRoutine ( stripe - > Irp , ioctl_completion , & context , true , true , true ) ;
2017-09-08 08:02:43 +00:00
IoCallDriver ( dev - > devobj , stripe - > Irp ) ;
nextdev :
num + + ;
}
le = le - > Flink ;
}
2019-09-01 12:53:20 +00:00
KeWaitForSingleObject ( & context . Event , Executive , KernelMode , false , NULL ) ;
2017-09-08 08:02:43 +00:00
2019-11-12 18:32:46 +00:00
for ( unsigned int i = 0 ; i < num ; i + + ) {
if ( context . stripes [ i ] . Irp )
IoFreeIrp ( context . stripes [ i ] . Irp ) ;
}
2017-09-08 08:02:43 +00:00
ExFreePool ( context . stripes ) ;
}
static NTSTATUS flush_changed_dev_stats ( device_extension * Vcb , device * dev , PIRP Irp ) {
NTSTATUS Status ;
KEY searchkey ;
traverse_ptr tp ;
2019-09-01 12:53:20 +00:00
uint16_t statslen ;
uint64_t * stats ;
2017-09-08 08:02:43 +00:00
searchkey . obj_id = 0 ;
searchkey . obj_type = TYPE_DEV_STATS ;
searchkey . offset = dev - > devitem . dev_id ;
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > dev_root , & tp , & searchkey , false , Irp ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " find_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
if ( ! keycmp ( tp . item - > key , searchkey ) ) {
Status = delete_tree_item ( Vcb , & tp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
}
2019-09-01 12:53:20 +00:00
statslen = sizeof ( uint64_t ) * 5 ;
2017-09-08 08:02:43 +00:00
stats = ExAllocatePoolWithTag ( PagedPool , statslen , ALLOC_TAG ) ;
if ( ! stats ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
RtlCopyMemory ( stats , dev - > stats , statslen ) ;
Status = insert_tree_item ( Vcb , Vcb - > dev_root , 0 , TYPE_DEV_STATS , dev - > devitem . dev_id , stats , statslen , NULL , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( stats ) ;
return Status ;
}
return STATUS_SUCCESS ;
}
static NTSTATUS flush_subvol ( device_extension * Vcb , root * r , PIRP Irp ) {
NTSTATUS Status ;
if ( r ! = Vcb - > root_root & & r ! = Vcb - > chunk_root ) {
KEY searchkey ;
traverse_ptr tp ;
ROOT_ITEM * ri ;
searchkey . obj_id = r - > id ;
searchkey . obj_type = TYPE_ROOT_ITEM ;
searchkey . offset = 0xffffffffffffffff ;
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > root_root , & tp , & searchkey , false , Irp ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - find_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
if ( tp . item - > key . obj_id ! = searchkey . obj_id | | tp . item - > key . obj_type ! = searchkey . obj_type ) {
2019-09-01 12:53:20 +00:00
ERR ( " could not find ROOT_ITEM for tree %I64x \n " , searchkey . obj_id ) ;
2017-09-08 08:02:43 +00:00
return STATUS_INTERNAL_ERROR ;
}
ri = ExAllocatePoolWithTag ( PagedPool , sizeof ( ROOT_ITEM ) , ALLOC_TAG ) ;
if ( ! ri ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
RtlCopyMemory ( ri , & r - > root_item , sizeof ( ROOT_ITEM ) ) ;
Status = delete_tree_item ( Vcb , & tp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
Status = insert_tree_item ( Vcb , Vcb - > root_root , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , ri , sizeof ( ROOT_ITEM ) , NULL , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
}
if ( r - > received ) {
KEY searchkey ;
traverse_ptr tp ;
if ( ! Vcb - > uuid_root ) {
root * uuid_root ;
TRACE ( " uuid root doesn't exist, creating it \n " ) ;
2019-09-01 12:53:20 +00:00
Status = create_root ( Vcb , BTRFS_ROOT_UUID , & uuid_root , false , 0 , Irp ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " create_root returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
Vcb - > uuid_root = uuid_root ;
}
2019-09-01 12:53:20 +00:00
RtlCopyMemory ( & searchkey . obj_id , & r - > root_item . received_uuid , sizeof ( uint64_t ) ) ;
2017-09-08 08:02:43 +00:00
searchkey . obj_type = TYPE_SUBVOL_REC_UUID ;
2019-09-01 12:53:20 +00:00
RtlCopyMemory ( & searchkey . offset , & r - > root_item . received_uuid . uuid [ sizeof ( uint64_t ) ] , sizeof ( uint64_t ) ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > uuid_root , & tp , & searchkey , false , Irp ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " find_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
if ( ! keycmp ( tp . item - > key , searchkey ) ) {
2019-09-01 12:53:20 +00:00
if ( tp . item - > size + sizeof ( uint64_t ) < = Vcb - > superblock . node_size - sizeof ( tree_header ) - sizeof ( leaf_node ) ) {
uint64_t * ids ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
ids = ExAllocatePoolWithTag ( PagedPool , tp . item - > size + sizeof ( uint64_t ) , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
if ( ! ids ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
RtlCopyMemory ( ids , tp . item - > data , tp . item - > size ) ;
2019-09-01 12:53:20 +00:00
RtlCopyMemory ( ( uint8_t * ) ids + tp . item - > size , & r - > id , sizeof ( uint64_t ) ) ;
2017-09-08 08:02:43 +00:00
Status = delete_tree_item ( Vcb , & tp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( ids ) ;
return Status ;
}
2019-09-01 12:53:20 +00:00
Status = insert_tree_item ( Vcb , Vcb - > uuid_root , searchkey . obj_id , searchkey . obj_type , searchkey . offset , ids , tp . item - > size + sizeof ( uint64_t ) , NULL , Irp ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( ids ) ;
return Status ;
}
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
} else {
2019-09-01 12:53:20 +00:00
uint64_t * root_num ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
root_num = ExAllocatePoolWithTag ( PagedPool , sizeof ( uint64_t ) , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
if ( ! root_num ) {
2016-10-29 17:05:10 +00:00
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
* root_num = r - > id ;
2019-09-01 12:53:20 +00:00
Status = insert_tree_item ( Vcb , Vcb - > uuid_root , searchkey . obj_id , searchkey . obj_type , searchkey . offset , root_num , sizeof ( uint64_t ) , NULL , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( root_num ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
}
2019-09-01 12:53:20 +00:00
r - > received = false ;
2017-09-08 08:02:43 +00:00
}
2019-09-01 12:53:20 +00:00
r - > dirty = false ;
2017-09-08 08:02:43 +00:00
return STATUS_SUCCESS ;
}
static NTSTATUS test_not_full ( device_extension * Vcb ) {
2019-09-01 12:53:20 +00:00
uint64_t reserve , could_alloc , free_space ;
2017-09-08 08:02:43 +00:00
LIST_ENTRY * le ;
// This function ensures we drop into readonly mode if we're about to leave very little
// space for metadata - this is similar to the "global reserve" of the Linux driver.
// Otherwise we might completely fill our space, at which point due to COW we can't
// delete anything in order to fix this.
reserve = Vcb - > extent_root - > root_item . bytes_used ;
reserve + = Vcb - > root_root - > root_item . bytes_used ;
if ( Vcb - > checksum_root ) reserve + = Vcb - > checksum_root - > root_item . bytes_used ;
reserve = max ( reserve , 0x1000000 ) ; // 16 M
reserve = min ( reserve , 0x20000000 ) ; // 512 M
// Find out how much space would be available for new metadata chunks
could_alloc = 0 ;
if ( Vcb - > metadata_flags & BLOCK_FLAG_RAID5 ) {
2019-09-01 12:53:20 +00:00
uint64_t s1 = 0 , s2 = 0 , s3 = 0 ;
2017-09-08 08:02:43 +00:00
le = Vcb - > devices . Flink ;
while ( le ! = & Vcb - > devices ) {
device * dev = CONTAINING_RECORD ( le , device , list_entry ) ;
if ( ! dev - > readonly ) {
2019-09-01 12:53:20 +00:00
uint64_t space = dev - > devitem . num_bytes - dev - > devitem . bytes_used ;
2017-09-08 08:02:43 +00:00
if ( space > = s1 ) {
s3 = s2 ;
s2 = s1 ;
s1 = space ;
} else if ( space > = s2 ) {
s3 = s2 ;
s2 = space ;
} else if ( space > = s3 )
s3 = space ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
le = le - > Flink ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
could_alloc = s3 * 2 ;
} else if ( Vcb - > metadata_flags & ( BLOCK_FLAG_RAID10 | BLOCK_FLAG_RAID6 ) ) {
2019-09-01 12:53:20 +00:00
uint64_t s1 = 0 , s2 = 0 , s3 = 0 , s4 = 0 ;
2017-09-08 08:02:43 +00:00
le = Vcb - > devices . Flink ;
while ( le ! = & Vcb - > devices ) {
device * dev = CONTAINING_RECORD ( le , device , list_entry ) ;
if ( ! dev - > readonly ) {
2019-09-01 12:53:20 +00:00
uint64_t space = dev - > devitem . num_bytes - dev - > devitem . bytes_used ;
2017-09-08 08:02:43 +00:00
if ( space > = s1 ) {
s4 = s3 ;
s3 = s2 ;
s2 = s1 ;
s1 = space ;
} else if ( space > = s2 ) {
s4 = s3 ;
s3 = s2 ;
s2 = space ;
} else if ( space > = s3 ) {
s4 = s3 ;
s3 = space ;
} else if ( space > = s4 )
s4 = space ;
}
le = le - > Flink ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
could_alloc = s4 * 2 ;
} else if ( Vcb - > metadata_flags & ( BLOCK_FLAG_RAID0 | BLOCK_FLAG_RAID1 ) ) {
2019-09-01 12:53:20 +00:00
uint64_t s1 = 0 , s2 = 0 ;
2017-09-08 08:02:43 +00:00
le = Vcb - > devices . Flink ;
while ( le ! = & Vcb - > devices ) {
device * dev = CONTAINING_RECORD ( le , device , list_entry ) ;
if ( ! dev - > readonly ) {
2019-09-01 12:53:20 +00:00
uint64_t space = dev - > devitem . num_bytes - dev - > devitem . bytes_used ;
2017-09-08 08:02:43 +00:00
if ( space > = s1 ) {
s2 = s1 ;
s1 = space ;
} else if ( space > = s2 )
s2 = space ;
}
le = le - > Flink ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
if ( Vcb - > metadata_flags & BLOCK_FLAG_RAID1 )
could_alloc = s2 ;
else // RAID0
could_alloc = s2 * 2 ;
} else if ( Vcb - > metadata_flags & BLOCK_FLAG_DUPLICATE ) {
le = Vcb - > devices . Flink ;
while ( le ! = & Vcb - > devices ) {
device * dev = CONTAINING_RECORD ( le , device , list_entry ) ;
if ( ! dev - > readonly ) {
2019-09-01 12:53:20 +00:00
uint64_t space = ( dev - > devitem . num_bytes - dev - > devitem . bytes_used ) / 2 ;
2017-09-08 08:02:43 +00:00
could_alloc = max ( could_alloc , space ) ;
}
le = le - > Flink ;
}
2020-04-23 02:38:57 +00:00
} else if ( Vcb - > metadata_flags & BLOCK_FLAG_RAID1C3 ) {
uint64_t s1 = 0 , s2 = 0 , s3 = 0 ;
le = Vcb - > devices . Flink ;
while ( le ! = & Vcb - > devices ) {
device * dev = CONTAINING_RECORD ( le , device , list_entry ) ;
if ( ! dev - > readonly ) {
uint64_t space = dev - > devitem . num_bytes - dev - > devitem . bytes_used ;
if ( space > = s1 ) {
s3 = s2 ;
s2 = s1 ;
s1 = space ;
} else if ( space > = s2 ) {
s3 = s2 ;
s2 = space ;
} else if ( space > = s3 )
s3 = space ;
}
le = le - > Flink ;
}
could_alloc = s3 ;
} else if ( Vcb - > metadata_flags & BLOCK_FLAG_RAID1C4 ) {
uint64_t s1 = 0 , s2 = 0 , s3 = 0 , s4 = 0 ;
le = Vcb - > devices . Flink ;
while ( le ! = & Vcb - > devices ) {
device * dev = CONTAINING_RECORD ( le , device , list_entry ) ;
if ( ! dev - > readonly ) {
uint64_t space = dev - > devitem . num_bytes - dev - > devitem . bytes_used ;
if ( space > = s1 ) {
s4 = s3 ;
s3 = s2 ;
s2 = s1 ;
s1 = space ;
} else if ( space > = s2 ) {
s4 = s3 ;
s3 = s2 ;
s2 = space ;
} else if ( space > = s3 ) {
s4 = s3 ;
s3 = space ;
} else if ( space > = s4 )
s4 = space ;
}
le = le - > Flink ;
}
could_alloc = s4 ;
2017-09-08 08:02:43 +00:00
} else { // SINGLE
le = Vcb - > devices . Flink ;
while ( le ! = & Vcb - > devices ) {
device * dev = CONTAINING_RECORD ( le , device , list_entry ) ;
if ( ! dev - > readonly ) {
2019-09-01 12:53:20 +00:00
uint64_t space = dev - > devitem . num_bytes - dev - > devitem . bytes_used ;
2017-09-08 08:02:43 +00:00
could_alloc = max ( could_alloc , space ) ;
}
le = le - > Flink ;
2016-10-29 17:05:10 +00:00
}
}
2017-09-08 08:02:43 +00:00
if ( could_alloc > = reserve )
return STATUS_SUCCESS ;
free_space = 0 ;
le = Vcb - > chunks . Flink ;
while ( le ! = & Vcb - > chunks ) {
chunk * c = CONTAINING_RECORD ( le , chunk , list_entry ) ;
if ( ! c - > reloc & & ! c - > readonly & & c - > chunk_item - > type & BLOCK_FLAG_METADATA ) {
free_space + = c - > chunk_item - > size - c - > used ;
if ( free_space + could_alloc > = reserve )
return STATUS_SUCCESS ;
}
le = le - > Flink ;
}
return STATUS_DISK_FULL ;
2016-10-29 17:05:10 +00:00
}
2019-06-11 10:35:19 +00:00
static NTSTATUS check_for_orphans_root ( device_extension * Vcb , root * r , PIRP Irp ) {
NTSTATUS Status ;
KEY searchkey ;
traverse_ptr tp ;
LIST_ENTRY rollback ;
TRACE ( " (%p, %p) \n " , Vcb , r ) ;
InitializeListHead ( & rollback ) ;
searchkey . obj_id = BTRFS_ORPHAN_INODE_OBJID ;
searchkey . obj_type = TYPE_ORPHAN_INODE ;
searchkey . offset = 0 ;
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , r , & tp , & searchkey , false , Irp ) ;
2019-06-11 10:35:19 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " find_item returned %08lx \n " , Status ) ;
2019-06-11 10:35:19 +00:00
return Status ;
}
do {
traverse_ptr next_tp ;
if ( tp . item - > key . obj_id > searchkey . obj_id | | ( tp . item - > key . obj_id = = searchkey . obj_id & & tp . item - > key . obj_type > searchkey . obj_type ) )
break ;
if ( tp . item - > key . obj_id = = searchkey . obj_id & & tp . item - > key . obj_type = = searchkey . obj_type ) {
fcb * fcb ;
2019-09-01 12:53:20 +00:00
TRACE ( " removing orphaned inode %I64x \n " , tp . item - > key . offset ) ;
2019-06-11 10:35:19 +00:00
2019-09-01 12:53:20 +00:00
Status = open_fcb ( Vcb , r , tp . item - > key . offset , 0 , NULL , false , NULL , & fcb , PagedPool , Irp ) ;
2019-06-11 10:35:19 +00:00
if ( ! NT_SUCCESS ( Status ) )
2020-04-23 02:38:57 +00:00
ERR ( " open_fcb returned %08lx \n " , Status ) ;
2019-06-11 10:35:19 +00:00
else {
if ( fcb - > inode_item . st_nlink = = 0 ) {
if ( fcb - > type ! = BTRFS_TYPE_DIRECTORY & & fcb - > inode_item . st_size > 0 ) {
Status = excise_extents ( Vcb , fcb , 0 , sector_align ( fcb - > inode_item . st_size , Vcb - > superblock . sector_size ) , Irp , & rollback ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " excise_extents returned %08lx \n " , Status ) ;
2019-06-11 10:35:19 +00:00
goto end ;
}
}
2019-09-01 12:53:20 +00:00
fcb - > deleted = true ;
2019-06-11 10:35:19 +00:00
mark_fcb_dirty ( fcb ) ;
}
free_fcb ( fcb ) ;
Status = delete_tree_item ( Vcb , & tp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2019-06-11 10:35:19 +00:00
goto end ;
}
}
}
2019-09-01 12:53:20 +00:00
if ( find_next_item ( Vcb , & tp , & next_tp , false , Irp ) )
2019-06-11 10:35:19 +00:00
tp = next_tp ;
else
break ;
2019-09-01 12:53:20 +00:00
} while ( true ) ;
2019-06-11 10:35:19 +00:00
Status = STATUS_SUCCESS ;
clear_rollback ( & rollback ) ;
end :
do_rollback ( Vcb , & rollback ) ;
return Status ;
}
static NTSTATUS check_for_orphans ( device_extension * Vcb , PIRP Irp ) {
NTSTATUS Status ;
LIST_ENTRY * le ;
if ( IsListEmpty ( & Vcb - > dirty_filerefs ) )
return STATUS_SUCCESS ;
le = Vcb - > dirty_filerefs . Flink ;
while ( le ! = & Vcb - > dirty_filerefs ) {
file_ref * fr = CONTAINING_RECORD ( le , file_ref , list_entry_dirty ) ;
if ( ! fr - > fcb - > subvol - > checked_for_orphans ) {
Status = check_for_orphans_root ( Vcb , fr - > fcb - > subvol , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " check_for_orphans_root returned %08lx \n " , Status ) ;
2019-06-11 10:35:19 +00:00
return Status ;
}
2019-09-01 12:53:20 +00:00
fr - > fcb - > subvol - > checked_for_orphans = true ;
2019-06-11 10:35:19 +00:00
}
le = le - > Flink ;
}
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
static NTSTATUS do_write2 ( device_extension * Vcb , PIRP Irp , LIST_ENTRY * rollback ) {
2016-10-29 17:05:10 +00:00
NTSTATUS Status ;
LIST_ENTRY * le , batchlist ;
2019-09-01 12:53:20 +00:00
bool cache_changed = false ;
2017-09-08 08:02:43 +00:00
volume_device_extension * vde ;
2019-09-01 12:53:20 +00:00
bool no_cache = false ;
2016-10-29 17:05:10 +00:00
# ifdef DEBUG_FLUSH_TIMES
2019-09-01 12:53:20 +00:00
uint64_t filerefs = 0 , fcbs = 0 ;
2016-10-29 17:05:10 +00:00
LARGE_INTEGER freq , time1 , time2 ;
# endif
# ifdef DEBUG_WRITE_LOOPS
UINT loops = 0 ;
# endif
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
TRACE ( " (%p) \n " , Vcb ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
InitializeListHead ( & batchlist ) ;
# ifdef DEBUG_FLUSH_TIMES
time1 = KeQueryPerformanceCounter ( & freq ) ;
# endif
2017-09-08 08:02:43 +00:00
2019-06-11 10:35:19 +00:00
Status = check_for_orphans ( Vcb , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " check_for_orphans returned %08lx \n " , Status ) ;
2019-06-11 10:35:19 +00:00
return Status ;
}
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( & Vcb - > dirty_filerefs_lock , true ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
while ( ! IsListEmpty ( & Vcb - > dirty_filerefs ) ) {
2017-09-08 08:02:43 +00:00
file_ref * fr = CONTAINING_RECORD ( RemoveHeadList ( & Vcb - > dirty_filerefs ) , file_ref , list_entry_dirty ) ;
flush_fileref ( fr , & batchlist , Irp ) ;
2019-05-11 09:20:02 +00:00
free_fileref ( fr ) ;
2016-10-29 17:05:10 +00:00
# ifdef DEBUG_FLUSH_TIMES
filerefs + + ;
# endif
}
2017-09-08 08:02:43 +00:00
ExReleaseResourceLite ( & Vcb - > dirty_filerefs_lock ) ;
Status = commit_batch_list ( Vcb , & batchlist , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " commit_batch_list returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
2016-10-29 17:05:10 +00:00
# ifdef DEBUG_FLUSH_TIMES
time2 = KeQueryPerformanceCounter ( NULL ) ;
2019-09-01 12:53:20 +00:00
ERR ( " flushed %I64u filerefs in %I64u (freq = %I64u) \n " , filerefs , time2 . QuadPart - time1 . QuadPart , freq . QuadPart ) ;
2016-10-29 17:05:10 +00:00
time1 = KeQueryPerformanceCounter ( & freq ) ;
# endif
// We process deleted streams first, so we don't run over our xattr
// limit unless we absolutely have to.
2017-09-08 08:02:43 +00:00
// We also process deleted normal files, to avoid any problems
// caused by inode collisions.
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( & Vcb - > dirty_fcbs_lock , true ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = Vcb - > dirty_fcbs . Flink ;
while ( le ! = & Vcb - > dirty_fcbs ) {
2017-09-08 08:02:43 +00:00
fcb * fcb = CONTAINING_RECORD ( le , struct _fcb , list_entry_dirty ) ;
2016-10-29 17:05:10 +00:00
LIST_ENTRY * le2 = le - > Flink ;
2017-09-08 08:02:43 +00:00
if ( fcb - > deleted ) {
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( fcb - > Header . Resource , true ) ;
Status = flush_fcb ( fcb , false , & batchlist , Irp ) ;
2017-09-08 08:02:43 +00:00
ExReleaseResourceLite ( fcb - > Header . Resource ) ;
2019-05-11 09:20:02 +00:00
free_fcb ( fcb ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " flush_fcb returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
clear_batch_list ( Vcb , & batchlist ) ;
ExReleaseResourceLite ( & Vcb - > dirty_fcbs_lock ) ;
return Status ;
}
2016-10-29 17:05:10 +00:00
# ifdef DEBUG_FLUSH_TIMES
fcbs + + ;
# endif
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = le2 ;
}
2017-09-08 08:02:43 +00:00
Status = commit_batch_list ( Vcb , & batchlist , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " commit_batch_list returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
ExReleaseResourceLite ( & Vcb - > dirty_fcbs_lock ) ;
return Status ;
}
2016-10-29 17:05:10 +00:00
le = Vcb - > dirty_fcbs . Flink ;
while ( le ! = & Vcb - > dirty_fcbs ) {
2017-09-08 08:02:43 +00:00
fcb * fcb = CONTAINING_RECORD ( le , struct _fcb , list_entry_dirty ) ;
2016-10-29 17:05:10 +00:00
LIST_ENTRY * le2 = le - > Flink ;
2017-09-08 08:02:43 +00:00
if ( fcb - > subvol ! = Vcb - > root_root ) {
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( fcb - > Header . Resource , true ) ;
Status = flush_fcb ( fcb , false , & batchlist , Irp ) ;
2017-09-08 08:02:43 +00:00
ExReleaseResourceLite ( fcb - > Header . Resource ) ;
2019-05-11 09:20:02 +00:00
free_fcb ( fcb ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " flush_fcb returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
ExReleaseResourceLite ( & Vcb - > dirty_fcbs_lock ) ;
return Status ;
}
2016-10-29 17:05:10 +00:00
# ifdef DEBUG_FLUSH_TIMES
fcbs + + ;
# endif
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = le2 ;
}
2017-09-08 08:02:43 +00:00
ExReleaseResourceLite ( & Vcb - > dirty_fcbs_lock ) ;
Status = commit_batch_list ( Vcb , & batchlist , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " commit_batch_list returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
2016-10-29 17:05:10 +00:00
# ifdef DEBUG_FLUSH_TIMES
time2 = KeQueryPerformanceCounter ( NULL ) ;
2019-09-01 12:53:20 +00:00
ERR ( " flushed %I64u fcbs in %I64u (freq = %I64u) \n " , filerefs , time2 . QuadPart - time1 . QuadPart , freq . QuadPart ) ;
2016-10-29 17:05:10 +00:00
# endif
2017-09-08 08:02:43 +00:00
// no need to get dirty_subvols_lock here, as we have tree_lock exclusively
while ( ! IsListEmpty ( & Vcb - > dirty_subvols ) ) {
root * r = CONTAINING_RECORD ( RemoveHeadList ( & Vcb - > dirty_subvols ) , root , list_entry_dirty ) ;
Status = flush_subvol ( Vcb , r , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " flush_subvol returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
}
2017-09-08 08:02:43 +00:00
if ( ! IsListEmpty ( & Vcb - > drop_roots ) ) {
Status = drop_roots ( Vcb , Irp , rollback ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " drop_roots returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
}
2017-09-08 08:02:43 +00:00
Status = update_chunks ( Vcb , & batchlist , Irp , rollback ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " update_chunks returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
Status = commit_batch_list ( Vcb , & batchlist , Irp ) ;
2016-10-29 17:05:10 +00:00
// If only changing superblock, e.g. changing label, we still need to rewrite
// the root tree so the generations match, otherwise you won't be able to mount on Linux.
if ( ! Vcb - > root_root - > treeholder . tree | | ! Vcb - > root_root - > treeholder . tree - > write ) {
KEY searchkey ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
traverse_ptr tp ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
searchkey . obj_id = 0 ;
searchkey . obj_type = 0 ;
searchkey . offset = 0 ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > root_root , & tp , & searchkey , false , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - find_item returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Vcb - > root_root - > treeholder . tree - > write = true ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
// make sure we always update the extent tree
2017-09-08 08:02:43 +00:00
Status = add_root_item_to_cache ( Vcb , BTRFS_ROOT_EXTENT , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " add_root_item_to_cache returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
if ( Vcb - > stats_changed ) {
le = Vcb - > devices . Flink ;
while ( le ! = & Vcb - > devices ) {
device * dev = CONTAINING_RECORD ( le , device , list_entry ) ;
if ( dev - > stats_changed ) {
Status = flush_changed_dev_stats ( Vcb , dev , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " flush_changed_dev_stats returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
2019-09-01 12:53:20 +00:00
dev - > stats_changed = false ;
2017-09-08 08:02:43 +00:00
}
le = le - > Flink ;
}
2019-09-01 12:53:20 +00:00
Vcb - > stats_changed = false ;
2017-09-08 08:02:43 +00:00
}
2016-10-29 17:05:10 +00:00
do {
2017-09-08 08:02:43 +00:00
Status = add_parents ( Vcb , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " add_parents returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
Status = allocate_tree_extents ( Vcb , Irp , rollback ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " allocate_tree_extents returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
Status = do_splits ( Vcb , Irp , rollback ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " do_splits returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
Status = update_chunk_usage ( Vcb , Irp , rollback ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " update_chunk_usage returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
if ( ! ( Vcb - > superblock . compat_ro_flags & BTRFS_COMPAT_RO_FLAGS_FREE_SPACE_CACHE ) ) {
if ( ! no_cache ) {
Status = allocate_cache ( Vcb , & cache_changed , Irp , rollback ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
WARN ( " allocate_cache returned %08lx \n " , Status ) ;
2019-09-01 12:53:20 +00:00
no_cache = true ;
cache_changed = false ;
2017-09-08 08:02:43 +00:00
}
}
} else {
Status = update_chunk_caches_tree ( Vcb , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " update_chunk_caches_tree returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
goto end ;
}
2016-10-29 17:05:10 +00:00
}
# ifdef DEBUG_WRITE_LOOPS
loops + + ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( cache_changed )
ERR ( " cache has changed, looping again \n " ) ;
# endif
2017-09-08 08:02:43 +00:00
} while ( cache_changed | | ! trees_consistent ( Vcb ) ) ;
2016-10-29 17:05:10 +00:00
# ifdef DEBUG_WRITE_LOOPS
ERR ( " %u loops \n " , loops ) ;
# endif
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
TRACE ( " trees consistent \n " ) ;
2017-09-08 08:02:43 +00:00
Status = update_root_root ( Vcb , no_cache , Irp , rollback ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " update_root_root returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
Status = write_trees ( Vcb , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " write_trees returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
Status = test_not_full ( Vcb ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " test_not_full returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
goto end ;
}
2017-01-01 17:12:12 +00:00
# ifdef DEBUG_PARANOID
2016-10-29 17:05:10 +00:00
le = Vcb - > trees . Flink ;
while ( le ! = & Vcb - > trees ) {
tree * t = CONTAINING_RECORD ( le , tree , list_entry ) ;
KEY searchkey ;
traverse_ptr tp ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
searchkey . obj_id = t - > header . address ;
searchkey . obj_type = TYPE_METADATA_ITEM ;
searchkey . offset = 0xffffffffffffffff ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > extent_root , & tp , & searchkey , false , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - find_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
goto end ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( tp . item - > key . obj_id ! = searchkey . obj_id | | tp . item - > key . obj_type ! = searchkey . obj_type ) {
searchkey . obj_id = t - > header . address ;
searchkey . obj_type = TYPE_EXTENT_ITEM ;
searchkey . offset = 0xffffffffffffffff ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > extent_root , & tp , & searchkey , false , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - find_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
goto end ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( tp . item - > key . obj_id ! = searchkey . obj_id | | tp . item - > key . obj_type ! = searchkey . obj_type ) {
2019-09-01 12:53:20 +00:00
ERR ( " error - could not find entry in extent tree for tree at %I64x \n " , t - > header . address ) ;
2017-09-08 08:02:43 +00:00
Status = STATUS_INTERNAL_ERROR ;
goto end ;
2016-10-29 17:05:10 +00:00
}
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le = le - > Flink ;
}
# endif
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
Vcb - > superblock . cache_generation = Vcb - > superblock . generation ;
2017-09-08 08:02:43 +00:00
if ( ! Vcb - > options . no_barrier )
flush_disk_caches ( Vcb ) ;
2017-01-01 17:12:12 +00:00
Status = write_superblocks ( Vcb , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " write_superblocks returned %08lx \n " , Status ) ;
2017-01-01 17:12:12 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
vde = Vcb - > vde ;
if ( vde ) {
pdo_device_extension * pdode = vde - > pdode ;
2019-09-01 12:53:20 +00:00
ExAcquireResourceSharedLite ( & pdode - > child_lock , true ) ;
2017-09-08 08:02:43 +00:00
le = pdode - > children . Flink ;
while ( le ! = & pdode - > children ) {
volume_child * vc = CONTAINING_RECORD ( le , volume_child , list_entry ) ;
vc - > generation = Vcb - > superblock . generation ;
le = le - > Flink ;
}
ExReleaseResourceLite ( & pdode - > child_lock ) ;
}
2017-01-01 17:12:12 +00:00
clean_space_cache ( Vcb ) ;
2017-09-08 08:02:43 +00:00
le = Vcb - > chunks . Flink ;
while ( le ! = & Vcb - > chunks ) {
chunk * c = CONTAINING_RECORD ( le , chunk , list_entry ) ;
2019-09-01 12:53:20 +00:00
c - > changed = false ;
c - > space_changed = false ;
2017-09-08 08:02:43 +00:00
le = le - > Flink ;
}
2017-01-01 17:12:12 +00:00
Vcb - > superblock . generation + + ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
Status = STATUS_SUCCESS ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le = Vcb - > trees . Flink ;
while ( le ! = & Vcb - > trees ) {
tree * t = CONTAINING_RECORD ( le , tree , list_entry ) ;
2019-09-01 12:53:20 +00:00
t - > write = false ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = le - > Flink ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Vcb - > need_write = false ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
while ( ! IsListEmpty ( & Vcb - > drop_roots ) ) {
2017-09-08 08:02:43 +00:00
root * r = CONTAINING_RECORD ( RemoveHeadList ( & Vcb - > drop_roots ) , root , list_entry ) ;
2016-10-29 17:05:10 +00:00
2020-04-23 02:38:57 +00:00
if ( IsListEmpty ( & r - > fcbs ) ) {
ExDeleteResourceLite ( & r - > nonpaged - > load_tree_lock ) ;
ExFreePool ( r - > nonpaged ) ;
ExFreePool ( r ) ;
} else
r - > dropped = true ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
end :
2020-04-23 02:38:57 +00:00
TRACE ( " do_write returning %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
NTSTATUS do_write ( device_extension * Vcb , PIRP Irp ) {
LIST_ENTRY rollback ;
NTSTATUS Status ;
InitializeListHead ( & rollback ) ;
Status = do_write2 ( Vcb , Irp , & rollback ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " do_write2 returned %08lx, dropping into readonly mode \n " , Status ) ;
2019-09-01 12:53:20 +00:00
Vcb - > readonly = true ;
2017-09-08 08:02:43 +00:00
FsRtlNotifyVolumeEvent ( Vcb - > root_file , FSRTL_VOLUME_FORCED_CLOSED ) ;
do_rollback ( Vcb , & rollback ) ;
} else
clear_rollback ( & rollback ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
2016-03-23 20:35:05 +00:00
static void do_flush ( device_extension * Vcb ) {
2017-09-08 08:02:43 +00:00
NTSTATUS Status ;
2016-03-23 20:35:05 +00:00
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( & Vcb - > tree_lock , true ) ;
2016-10-29 17:05:10 +00:00
2016-09-04 15:27:46 +00:00
if ( Vcb - > need_write & & ! Vcb - > readonly )
2017-09-08 08:02:43 +00:00
Status = do_write ( Vcb , NULL ) ;
else
Status = STATUS_SUCCESS ;
2016-05-05 17:26:47 +00:00
free_trees ( Vcb ) ;
2016-03-23 20:35:05 +00:00
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) )
2020-04-23 02:38:57 +00:00
ERR ( " do_write returned %08lx \n " , Status ) ;
2016-03-23 20:35:05 +00:00
2017-09-08 08:02:43 +00:00
ExReleaseResourceLite ( & Vcb - > tree_lock ) ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
_Function_class_ ( KSTART_ROUTINE )
2019-09-01 12:53:20 +00:00
void __stdcall flush_thread ( void * context ) {
2016-05-05 17:26:47 +00:00
DEVICE_OBJECT * devobj = context ;
device_extension * Vcb = devobj - > DeviceExtension ;
2016-03-23 20:35:05 +00:00
LARGE_INTEGER due_time ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
ObReferenceObject ( devobj ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
KeInitializeTimer ( & Vcb - > flush_thread_timer ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
due_time . QuadPart = ( uint64_t ) Vcb - > options . flush_interval * - 10000000 ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
KeSetTimer ( & Vcb - > flush_thread_timer , due_time , NULL ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
while ( true ) {
KeWaitForSingleObject ( & Vcb - > flush_thread_timer , Executive , KernelMode , false , NULL ) ;
2016-03-23 20:35:05 +00:00
2016-07-27 19:24:26 +00:00
if ( ! ( devobj - > Vpb - > Flags & VPB_MOUNTED ) | | Vcb - > removing )
2016-05-05 17:26:47 +00:00
break ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! Vcb - > locked )
do_flush ( Vcb ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
KeSetTimer ( & Vcb - > flush_thread_timer , due_time , NULL ) ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
ObDereferenceObject ( devobj ) ;
2016-07-27 19:24:26 +00:00
KeCancelTimer ( & Vcb - > flush_thread_timer ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
KeSetEvent ( & Vcb - > flush_thread_finished , 0 , false ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
PsTerminateSystemThread ( STATUS_SUCCESS ) ;
}