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 "crc32c.h"
2016-03-23 20:35:05 +00:00
2022-04-28 19:31:44 +00:00
__attribute__ ( ( nonnull ( 1 , 3 , 4 , 5 ) ) )
2019-09-01 12:53:20 +00:00
NTSTATUS load_tree ( device_extension * Vcb , uint64_t addr , uint8_t * buf , root * r , tree * * pt ) {
2016-03-23 20:35:05 +00:00
tree_header * th ;
tree * t ;
tree_data * td ;
2019-09-01 12:53:20 +00:00
uint8_t h ;
bool inserted ;
2017-01-01 17:12:12 +00:00
LIST_ENTRY * le ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
th = ( tree_header * ) buf ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
t = ExAllocatePoolWithTag ( PagedPool , sizeof ( tree ) , ALLOC_TAG ) ;
if ( ! t ) {
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 ( th - > level > 0 ) {
t - > nonpaged = ExAllocatePoolWithTag ( NonPagedPool , sizeof ( tree_nonpaged ) , ALLOC_TAG ) ;
if ( ! t - > nonpaged ) {
ERR ( " out of memory \n " ) ;
ExFreePool ( t ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
ExInitializeFastMutex ( & t - > nonpaged - > mutex ) ;
} else
t - > nonpaged = NULL ;
2016-03-23 20:35:05 +00:00
RtlCopyMemory ( & t - > header , th , sizeof ( tree_header ) ) ;
2019-09-01 12:53:20 +00:00
t - > hash = calc_crc32c ( 0xffffffff , ( uint8_t * ) & addr , sizeof ( uint64_t ) ) ;
t - > has_address = true ;
2016-03-23 20:35:05 +00:00
t - > Vcb = Vcb ;
t - > parent = NULL ;
t - > root = r ;
t - > paritem = NULL ;
t - > size = 0 ;
t - > new_address = 0 ;
2019-09-01 12:53:20 +00:00
t - > has_new_address = false ;
t - > updated_extents = false ;
t - > write = false ;
t - > uniqueness_determined = false ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
InitializeListHead ( & t - > itemlist ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( t - > header . level = = 0 ) { // leaf node
leaf_node * ln = ( leaf_node * ) ( buf + sizeof ( tree_header ) ) ;
unsigned int i ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( ( t - > header . num_items * sizeof ( leaf_node ) ) + sizeof ( tree_header ) > Vcb - > superblock . node_size ) {
2020-04-23 02:38:57 +00:00
ERR ( " tree at %I64x has more items than expected (%x) \n " , addr , t - > header . num_items ) ;
2018-12-16 11:03:16 +00:00
ExFreePool ( t ) ;
2016-07-27 19:24:26 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
for ( i = 0 ; i < t - > header . num_items ; i + + ) {
2016-10-29 17:05:10 +00:00
td = ExAllocateFromPagedLookasideList ( & Vcb - > tree_data_lookaside ) ;
2016-03-23 20:35:05 +00:00
if ( ! td ) {
ERR ( " out of memory \n " ) ;
2018-12-16 11:03:16 +00:00
ExFreePool ( t ) ;
2016-03-23 20:35:05 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
td - > key = ln [ i ] . key ;
2017-09-08 08:02:43 +00:00
if ( ln [ i ] . size > 0 )
td - > data = buf + sizeof ( tree_header ) + ln [ i ] . offset ;
else
2016-03-23 20:35:05 +00:00
td - > data = NULL ;
2017-09-08 08:02:43 +00:00
if ( ln [ i ] . size + sizeof ( tree_header ) + sizeof ( leaf_node ) > Vcb - > superblock . node_size ) {
2020-04-23 02:38:57 +00:00
ERR ( " overlarge item in tree %I64x: %u > %Iu \n " , addr , ln [ i ] . size , Vcb - > superblock . node_size - sizeof ( tree_header ) - sizeof ( leaf_node ) ) ;
2018-12-16 11:03:16 +00:00
ExFreeToPagedLookasideList ( & t - > Vcb - > tree_data_lookaside , td ) ;
ExFreePool ( t ) ;
2017-09-08 08:02:43 +00:00
return STATUS_INTERNAL_ERROR ;
}
2019-09-01 12:53:20 +00:00
td - > size = ( uint16_t ) ln [ i ] . size ;
td - > ignore = false ;
td - > inserted = false ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
InsertTailList ( & t - > itemlist , & td - > list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
t - > size + = ln [ i ] . size ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
t - > size + = t - > header . num_items * sizeof ( leaf_node ) ;
2017-09-08 08:02:43 +00:00
t - > buf = buf ;
2016-03-23 20:35:05 +00:00
} else {
internal_node * in = ( internal_node * ) ( buf + sizeof ( tree_header ) ) ;
unsigned int i ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( ( t - > header . num_items * sizeof ( internal_node ) ) + sizeof ( tree_header ) > Vcb - > superblock . node_size ) {
2020-04-23 02:38:57 +00:00
ERR ( " tree at %I64x has more items than expected (%x) \n " , addr , t - > header . num_items ) ;
2018-12-16 11:03:16 +00:00
ExFreePool ( t ) ;
2016-07-27 19:24:26 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
for ( i = 0 ; i < t - > header . num_items ; i + + ) {
2016-10-29 17:05:10 +00:00
td = ExAllocateFromPagedLookasideList ( & Vcb - > tree_data_lookaside ) ;
2016-03-23 20:35:05 +00:00
if ( ! td ) {
ERR ( " out of memory \n " ) ;
2018-12-16 11:03:16 +00:00
ExFreePool ( t ) ;
2016-03-23 20:35:05 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
td - > key = in [ i ] . key ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
td - > treeholder . address = in [ i ] . address ;
td - > treeholder . generation = in [ i ] . generation ;
td - > treeholder . tree = NULL ;
2019-09-01 12:53:20 +00:00
td - > ignore = false ;
td - > inserted = false ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
InsertTailList ( & t - > itemlist , & td - > list_entry ) ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
t - > size = t - > header . num_items * sizeof ( internal_node ) ;
2017-09-08 08:02:43 +00:00
t - > buf = NULL ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
ExAcquireFastMutex ( & Vcb - > trees_list_mutex ) ;
2016-03-23 20:35:05 +00:00
InsertTailList ( & Vcb - > trees , & t - > list_entry ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
h = t - > hash > > 24 ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! Vcb - > trees_ptrs [ h ] ) {
2019-09-01 12:53:20 +00:00
uint8_t h2 = h ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le = Vcb - > trees_hash . Flink ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( h2 > 0 ) {
h2 - - ;
do {
if ( Vcb - > trees_ptrs [ h2 ] ) {
le = Vcb - > trees_ptrs [ h2 ] ;
break ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
h2 - - ;
} while ( h2 > 0 ) ;
}
} else
le = Vcb - > trees_ptrs [ h ] ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
inserted = false ;
2017-01-01 17:12:12 +00:00
while ( le ! = & Vcb - > trees_hash ) {
tree * t2 = CONTAINING_RECORD ( le , tree , list_entry_hash ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( t2 - > hash > = t - > hash ) {
InsertHeadList ( le - > Blink , & t - > list_entry_hash ) ;
2019-09-01 12:53:20 +00:00
inserted = true ;
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 ;
}
if ( ! inserted )
InsertTailList ( & Vcb - > trees_hash , & t - > list_entry_hash ) ;
if ( ! Vcb - > trees_ptrs [ h ] | | t - > list_entry_hash . Flink = = Vcb - > trees_ptrs [ h ] )
Vcb - > trees_ptrs [ h ] = & t - > list_entry_hash ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
ExReleaseFastMutex ( & Vcb - > trees_list_mutex ) ;
2016-03-23 20:35:05 +00:00
TRACE ( " returning %p \n " , t ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
* pt = t ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
return STATUS_SUCCESS ;
}
2022-04-28 19:31:44 +00:00
__attribute__ ( ( nonnull ( 1 , 2 , 3 , 4 ) ) )
2019-09-01 12:53:20 +00:00
static NTSTATUS do_load_tree2 ( device_extension * Vcb , tree_holder * th , uint8_t * buf , root * r , tree * t , tree_data * td ) {
2019-05-11 09:20:02 +00:00
if ( ! th - > tree ) {
NTSTATUS Status ;
tree * nt ;
Status = load_tree ( Vcb , th - > address , buf , r , & nt ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " load_tree returned %08lx \n " , Status ) ;
2019-05-11 09:20:02 +00:00
return Status ;
}
nt - > parent = t ;
# ifdef DEBUG_PARANOID
if ( t & & t - > header . level < = nt - > header . level ) int3 ;
# endif
nt - > paritem = td ;
th - > tree = nt ;
}
return STATUS_SUCCESS ;
}
2022-04-28 19:31:44 +00:00
__attribute__ ( ( nonnull ( 1 , 2 , 3 ) ) )
2019-05-11 09:20:02 +00:00
NTSTATUS do_load_tree ( device_extension * Vcb , tree_holder * th , root * r , tree * t , tree_data * td , PIRP Irp ) {
NTSTATUS Status ;
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 ;
}
if ( t )
ExAcquireFastMutex ( & t - > nonpaged - > mutex ) ;
else
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( & r - > nonpaged - > load_tree_lock , true ) ;
2019-05-11 09:20:02 +00:00
Status = do_load_tree2 ( Vcb , th , buf , r , t , td ) ;
if ( t )
ExReleaseFastMutex ( & t - > nonpaged - > mutex ) ;
else
ExReleaseResourceLite ( & r - > nonpaged - > load_tree_lock ) ;
if ( ! th - > tree | | th - > tree - > buf ! = buf )
ExFreePool ( buf ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " do_load_tree2 returned %08lx \n " , Status ) ;
2019-05-11 09:20:02 +00:00
return Status ;
}
return Status ;
}
2022-04-28 19:31:44 +00:00
__attribute__ ( ( nonnull ( 1 ) ) )
2019-05-11 09:20:02 +00:00
void free_tree ( tree * t ) {
2016-03-23 20:35:05 +00:00
tree * par ;
2016-05-05 17:26:47 +00:00
root * r = t - > root ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
// No need to acquire lock, as this is only ever called while Vcb->tree_lock held exclusively
2016-03-23 20:35:05 +00:00
par = t - > parent ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( r & & r - > treeholder . tree ! = t )
r = NULL ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( par ) {
if ( t - > paritem )
t - > paritem - > treeholder . tree = NULL ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
while ( ! IsListEmpty ( & t - > itemlist ) ) {
2017-09-08 08:02:43 +00:00
tree_data * td = CONTAINING_RECORD ( RemoveHeadList ( & t - > itemlist ) , tree_data , list_entry ) ;
if ( t - > header . level = = 0 & & td - > data & & td - > inserted )
2016-05-05 17:26:47 +00:00
ExFreePool ( td - > data ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ExFreeToPagedLookasideList ( & t - > Vcb - > tree_data_lookaside , td ) ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
RemoveEntryList ( & t - > list_entry ) ;
2017-09-08 08:02:43 +00:00
if ( r )
2016-05-05 17:26:47 +00:00
r - > treeholder . tree = NULL ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( t - > list_entry_hash . Flink ) {
2019-09-01 12:53:20 +00:00
uint8_t h = t - > hash > > 24 ;
2017-01-01 17:12:12 +00:00
if ( t - > Vcb - > trees_ptrs [ h ] = = & t - > list_entry_hash ) {
if ( t - > list_entry_hash . Flink ! = & t - > Vcb - > trees_hash ) {
tree * t2 = CONTAINING_RECORD ( t - > list_entry_hash . Flink , tree , list_entry_hash ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ( t2 - > hash > > 24 ) = = h )
t - > Vcb - > trees_ptrs [ h ] = & t2 - > list_entry_hash ;
else
t - > Vcb - > trees_ptrs [ h ] = NULL ;
} else
t - > Vcb - > trees_ptrs [ h ] = NULL ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
RemoveEntryList ( & t - > list_entry_hash ) ;
}
2017-09-08 08:02:43 +00:00
if ( t - > buf )
ExFreePool ( t - > buf ) ;
2019-05-11 09:20:02 +00:00
if ( t - > nonpaged )
ExFreePool ( t - > nonpaged ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
ExFreePool ( t ) ;
2016-03-23 20:35:05 +00:00
}
2022-04-28 19:31:44 +00:00
__attribute__ ( ( nonnull ( 1 ) ) )
2016-03-23 20:35:05 +00:00
static __inline tree_data * first_item ( tree * t ) {
LIST_ENTRY * le = t - > itemlist . Flink ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( le = = & t - > itemlist )
return NULL ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
return CONTAINING_RECORD ( le , tree_data , list_entry ) ;
}
2022-04-28 19:31:44 +00:00
__attribute__ ( ( nonnull ( 1 , 2 ) ) )
2016-03-23 20:35:05 +00:00
static __inline tree_data * prev_item ( tree * t , tree_data * td ) {
LIST_ENTRY * le = td - > list_entry . Blink ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( le = = & t - > itemlist )
return NULL ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
return CONTAINING_RECORD ( le , tree_data , list_entry ) ;
}
2022-04-28 19:31:44 +00:00
__attribute__ ( ( nonnull ( 1 , 2 ) ) )
2016-03-23 20:35:05 +00:00
static __inline tree_data * next_item ( tree * t , tree_data * td ) {
LIST_ENTRY * le = td - > list_entry . Flink ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( le = = & t - > itemlist )
return NULL ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
return CONTAINING_RECORD ( le , tree_data , list_entry ) ;
}
2022-04-28 19:31:44 +00:00
__attribute__ ( ( nonnull ( 1 , 2 , 3 , 4 ) ) )
2017-09-08 08:02:43 +00:00
static NTSTATUS next_item2 ( device_extension * Vcb , tree * t , tree_data * td , traverse_ptr * tp ) {
tree_data * td2 = next_item ( t , td ) ;
tree * t2 ;
if ( td2 ) {
tp - > tree = t ;
tp - > item = td2 ;
return STATUS_SUCCESS ;
}
t2 = t ;
do {
td2 = t2 - > paritem ;
t2 = t2 - > parent ;
} while ( td2 & & ! next_item ( t2 , td2 ) ) ;
if ( ! td2 )
return STATUS_NOT_FOUND ;
td2 = next_item ( t2 , td2 ) ;
2019-09-01 12:53:20 +00:00
return find_item_to_level ( Vcb , t2 - > root , tp , & td2 - > key , false , t - > header . level , NULL ) ;
2017-09-08 08:02:43 +00:00
}
2022-04-28 19:31:44 +00:00
__attribute__ ( ( nonnull ( 1 , 2 , 3 , 4 , 5 ) ) )
2019-09-01 12:53:20 +00:00
NTSTATUS skip_to_difference ( device_extension * Vcb , traverse_ptr * tp , traverse_ptr * tp2 , bool * ended1 , bool * ended2 ) {
2017-09-08 08:02:43 +00:00
NTSTATUS Status ;
tree * t1 , * t2 ;
tree_data * td1 , * td2 ;
t1 = tp - > tree ;
t2 = tp2 - > tree ;
do {
td1 = t1 - > paritem ;
td2 = t2 - > paritem ;
t1 = t1 - > parent ;
t2 = t2 - > parent ;
} while ( t1 & & t2 & & t1 - > header . address = = t2 - > header . address ) ;
2019-09-01 12:53:20 +00:00
while ( true ) {
2017-09-08 08:02:43 +00:00
traverse_ptr tp3 , tp4 ;
Status = next_item2 ( Vcb , t1 , td1 , & tp3 ) ;
if ( Status = = STATUS_NOT_FOUND )
2019-09-01 12:53:20 +00:00
* ended1 = true ;
2017-09-08 08:02:43 +00:00
else if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " next_item2 returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
Status = next_item2 ( Vcb , t2 , td2 , & tp4 ) ;
if ( Status = = STATUS_NOT_FOUND )
2019-09-01 12:53:20 +00:00
* ended2 = true ;
2017-09-08 08:02:43 +00:00
else if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " next_item2 returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
if ( * ended1 | | * ended2 ) {
if ( ! * ended1 ) {
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , t1 - > root , tp , & tp3 . item - > key , false , NULL ) ;
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 ;
}
} else if ( ! * ended2 ) {
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , t2 - > root , tp2 , & tp4 . item - > key , false , NULL ) ;
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 ;
}
}
return STATUS_SUCCESS ;
}
if ( tp3 . tree - > header . address ! = tp4 . tree - > header . address ) {
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , t1 - > root , tp , & tp3 . item - > key , false , NULL ) ;
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 ;
}
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , t2 - > root , tp2 , & tp4 . item - > key , false , NULL ) ;
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 ;
}
return STATUS_SUCCESS ;
}
t1 = tp3 . tree ;
td1 = tp3 . item ;
t2 = tp4 . tree ;
td2 = tp4 . item ;
}
}
2022-04-28 19:31:44 +00:00
__attribute__ ( ( nonnull ( 1 , 2 , 3 , 4 ) ) )
2019-09-01 12:53:20 +00:00
static NTSTATUS find_item_in_tree ( device_extension * Vcb , tree * t , traverse_ptr * tp , const KEY * searchkey , bool ignore , uint8_t level , PIRP Irp ) {
2016-03-23 20:35:05 +00:00
int cmp ;
tree_data * td , * lasttd ;
2016-10-29 17:05:10 +00:00
KEY key2 ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
cmp = 1 ;
td = first_item ( t ) ;
lasttd = NULL ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
if ( ! td ) return STATUS_NOT_FOUND ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
key2 = * searchkey ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
do {
2016-10-29 17:05:10 +00:00
cmp = keycmp ( key2 , td - > key ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( cmp = = 1 ) {
lasttd = td ;
td = next_item ( t , td ) ;
}
if ( t - > header . level = = 0 & & cmp = = 0 & & ! ignore & & td & & td - > ignore ) {
2016-03-26 11:53:07 +00:00
tree_data * origtd = td ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
while ( td & & td - > ignore )
td = next_item ( t , td ) ;
2017-09-08 08:02:43 +00:00
2016-03-26 11:53:07 +00:00
if ( td ) {
2016-10-29 17:05:10 +00:00
cmp = keycmp ( key2 , td - > key ) ;
2017-09-08 08:02:43 +00:00
2016-03-26 11:53:07 +00:00
if ( cmp ! = 0 ) {
td = origtd ;
cmp = 0 ;
}
} else
td = origtd ;
2016-03-23 20:35:05 +00:00
}
} while ( td & & cmp = = 1 ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( ( cmp = = - 1 | | ! td ) & & lasttd )
td = lasttd ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( t - > header . level = = 0 ) {
if ( td - > ignore & & ! ignore ) {
traverse_ptr oldtp ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
oldtp . tree = t ;
oldtp . item = td ;
2017-09-08 08:02:43 +00:00
while ( find_prev_item ( Vcb , & oldtp , tp , Irp ) ) {
2016-03-23 20:35:05 +00:00
if ( ! tp - > item - > ignore )
return STATUS_SUCCESS ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
oldtp = * tp ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
// if no valid entries before where item should be, look afterwards instead
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
oldtp . tree = t ;
oldtp . item = td ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
while ( find_next_item ( Vcb , & oldtp , tp , true , Irp ) ) {
2016-03-23 20:35:05 +00:00
if ( ! tp - > item - > ignore )
return STATUS_SUCCESS ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
oldtp = * tp ;
}
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
return STATUS_NOT_FOUND ;
2016-03-23 20:35:05 +00:00
} else {
tp - > tree = t ;
tp - > item = td ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
return STATUS_SUCCESS ;
} else {
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
while ( td & & td - > treeholder . tree & & IsListEmpty ( & td - > treeholder . tree - > itemlist ) ) {
td = prev_item ( t , td ) ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( ! td )
2016-09-04 15:27:46 +00:00
return STATUS_NOT_FOUND ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( t - > header . level < = level ) {
tp - > tree = t ;
tp - > item = td ;
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
if ( ! td - > treeholder . tree ) {
2019-05-11 09:20:02 +00:00
Status = do_load_tree ( Vcb , & td - > treeholder , t - > root , t , td , Irp ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " do_load_tree returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
Status = find_item_in_tree ( Vcb , td - > treeholder . tree , tp , searchkey , ignore , level , Irp ) ;
2016-03-23 20:35:05 +00:00
return Status ;
}
}
2022-04-28 19:31:44 +00:00
__attribute__ ( ( nonnull ( 1 , 2 , 3 , 4 ) ) )
2017-09-08 08:02:43 +00:00
NTSTATUS find_item ( _In_ _Requires_lock_held_ ( _Curr_ - > tree_lock ) device_extension * Vcb , _In_ root * r , _Out_ traverse_ptr * tp ,
2019-09-01 12:53:20 +00:00
_In_ const KEY * searchkey , _In_ bool ignore , _In_opt_ PIRP Irp ) {
2016-03-23 20:35:05 +00:00
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( ! r - > treeholder . tree ) {
2019-05-11 09:20:02 +00:00
Status = do_load_tree ( Vcb , & r - > treeholder , r , NULL , NULL , Irp ) ;
2016-05-05 17:26:47 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " do_load_tree returned %08lx \n " , Status ) ;
2016-05-05 17:26:47 +00:00
return Status ;
}
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
Status = find_item_in_tree ( Vcb , r - > treeholder . tree , tp , searchkey , ignore , 0 , Irp ) ;
2016-09-04 15:27:46 +00:00
if ( ! NT_SUCCESS ( Status ) & & Status ! = STATUS_NOT_FOUND ) {
2020-04-23 02:38:57 +00:00
ERR ( " find_item_in_tree returned %08lx \n " , Status ) ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
return Status ;
}
2022-04-28 19:31:44 +00:00
__attribute__ ( ( nonnull ( 1 , 2 , 3 , 4 ) ) )
2019-09-01 12:53:20 +00:00
NTSTATUS find_item_to_level ( device_extension * Vcb , root * r , traverse_ptr * tp , const KEY * searchkey , bool ignore , uint8_t level , PIRP Irp ) {
2017-01-01 17:12:12 +00:00
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! r - > treeholder . tree ) {
2019-05-11 09:20:02 +00:00
Status = do_load_tree ( Vcb , & r - > treeholder , r , NULL , NULL , Irp ) ;
2017-01-01 17:12:12 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " do_load_tree returned %08lx \n " , Status ) ;
2017-01-01 17:12:12 +00:00
return Status ;
}
}
2017-09-08 08:02:43 +00:00
Status = find_item_in_tree ( Vcb , r - > treeholder . tree , tp , searchkey , ignore , level , Irp ) ;
2017-01-01 17:12:12 +00:00
if ( ! NT_SUCCESS ( Status ) & & Status ! = STATUS_NOT_FOUND ) {
2020-04-23 02:38:57 +00:00
ERR ( " find_item_in_tree returned %08lx \n " , Status ) ;
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 ( Status = = STATUS_NOT_FOUND ) {
tp - > tree = r - > treeholder . tree ;
tp - > item = NULL ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
return Status ;
}
2022-04-28 19:31:44 +00:00
__attribute__ ( ( nonnull ( 1 , 2 , 3 ) ) )
2019-09-01 12:53:20 +00:00
bool find_next_item ( _Requires_lock_held_ ( _Curr_ - > tree_lock ) device_extension * Vcb , const traverse_ptr * tp , traverse_ptr * next_tp , bool ignore , PIRP Irp ) {
2016-03-23 20:35:05 +00:00
tree * t ;
2017-09-08 08:02:43 +00:00
tree_data * td = NULL , * next ;
2016-03-23 20:35:05 +00:00
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
next = next_item ( tp - > tree , tp - > item ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( ! ignore ) {
while ( next & & next - > ignore )
next = next_item ( tp - > tree , next ) ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( next ) {
next_tp - > tree = tp - > tree ;
next_tp - > item = next ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
# ifdef DEBUG_PARANOID
if ( ! ignore & & next_tp - > item - > ignore ) {
ERR ( " error - returning ignored item \n " ) ;
int3 ;
}
# endif
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
return true ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( ! tp - > tree - > parent )
2019-09-01 12:53:20 +00:00
return false ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
t = tp - > tree ;
do {
if ( t - > parent ) {
td = next_item ( t - > parent , t - > paritem ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( td ) break ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
t = t - > parent ;
} while ( t ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( ! t )
2019-09-01 12:53:20 +00:00
return false ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
if ( ! td - > treeholder . tree ) {
Status = do_load_tree ( Vcb , & td - > treeholder , t - > parent - > root , t - > parent , td , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " do_load_tree returned %08lx \n " , Status ) ;
2019-09-01 12:53:20 +00:00
return false ;
2019-05-11 09:20:02 +00:00
}
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
t = td - > treeholder . tree ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
while ( t - > header . level ! = 0 ) {
tree_data * fi ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
fi = first_item ( t ) ;
2017-09-08 08:02:43 +00:00
2022-04-28 19:31:44 +00:00
if ( ! fi )
return false ;
2019-05-11 09:20:02 +00:00
if ( ! fi - > treeholder . tree ) {
Status = do_load_tree ( Vcb , & fi - > treeholder , t - > parent - > root , t , fi , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " do_load_tree returned %08lx \n " , Status ) ;
2019-09-01 12:53:20 +00:00
return false ;
2019-05-11 09:20:02 +00:00
}
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
t = fi - > treeholder . tree ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
next_tp - > tree = t ;
next_tp - > item = first_item ( t ) ;
2017-09-08 08:02:43 +00:00
2022-04-28 19:31:44 +00:00
if ( ! next_tp - > item )
return false ;
2016-03-23 20:35:05 +00:00
if ( ! ignore & & next_tp - > item - > ignore ) {
traverse_ptr ntp2 ;
2019-09-01 12:53:20 +00:00
bool b ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
while ( ( b = find_next_item ( Vcb , next_tp , & ntp2 , true , Irp ) ) ) {
2016-03-23 20:35:05 +00:00
* next_tp = ntp2 ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( ! next_tp - > item - > ignore )
break ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( ! b )
2019-09-01 12:53:20 +00:00
return false ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
# ifdef DEBUG_PARANOID
if ( ! ignore & & next_tp - > item - > ignore ) {
ERR ( " error - returning ignored item \n " ) ;
int3 ;
}
# endif
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
return true ;
2016-03-23 20:35:05 +00:00
}
2022-04-28 19:31:44 +00:00
__attribute__ ( ( nonnull ( 1 ) ) )
2016-03-23 20:35:05 +00:00
static __inline tree_data * last_item ( tree * t ) {
LIST_ENTRY * le = t - > itemlist . Blink ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( le = = & t - > itemlist )
return NULL ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
return CONTAINING_RECORD ( le , tree_data , list_entry ) ;
}
2022-04-28 19:31:44 +00:00
__attribute__ ( ( nonnull ( 1 , 2 , 3 ) ) )
2019-09-01 12:53:20 +00:00
bool find_prev_item ( _Requires_lock_held_ ( _Curr_ - > tree_lock ) device_extension * Vcb , const traverse_ptr * tp , traverse_ptr * prev_tp , PIRP Irp ) {
2016-03-23 20:35:05 +00:00
tree * t ;
tree_data * td ;
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
// FIXME - support ignore flag
if ( prev_item ( tp - > tree , tp - > item ) ) {
prev_tp - > tree = tp - > tree ;
prev_tp - > item = prev_item ( tp - > tree , tp - > item ) ;
2019-09-01 12:53:20 +00:00
return true ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( ! tp - > tree - > parent )
2019-09-01 12:53:20 +00:00
return false ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
t = tp - > tree ;
while ( t & & ( ! t - > parent | | ! prev_item ( t - > parent , t - > paritem ) ) ) {
t = t - > parent ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( ! t )
2019-09-01 12:53:20 +00:00
return false ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
td = prev_item ( t - > parent , t - > paritem ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
if ( ! td - > treeholder . tree ) {
Status = do_load_tree ( Vcb , & td - > treeholder , t - > parent - > root , t - > parent , td , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " do_load_tree returned %08lx \n " , Status ) ;
2019-09-01 12:53:20 +00:00
return false ;
2019-05-11 09:20:02 +00:00
}
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
t = td - > treeholder . tree ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
while ( t - > header . level ! = 0 ) {
tree_data * li ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
li = last_item ( t ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
if ( ! li - > treeholder . tree ) {
Status = do_load_tree ( Vcb , & li - > treeholder , t - > parent - > root , t , li , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " do_load_tree returned %08lx \n " , Status ) ;
2019-09-01 12:53:20 +00:00
return false ;
2019-05-11 09:20:02 +00:00
}
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
t = li - > treeholder . tree ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
prev_tp - > tree = t ;
prev_tp - > item = last_item ( t ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
return true ;
2016-03-23 20:35:05 +00:00
}
2022-04-28 19:31:44 +00:00
__attribute__ ( ( nonnull ( 1 , 2 ) ) )
2016-05-05 17:26:47 +00:00
void free_trees_root ( device_extension * Vcb , root * r ) {
2016-03-23 20:35:05 +00:00
LIST_ENTRY * le ;
2017-09-08 08:02:43 +00:00
ULONG level ;
2016-05-05 17:26:47 +00:00
for ( level = 0 ; level < = 255 ; level + + ) {
2019-09-01 12:53:20 +00:00
bool empty = true ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
le = Vcb - > trees . Flink ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
while ( le ! = & Vcb - > trees ) {
2016-03-23 20:35:05 +00:00
LIST_ENTRY * nextle = le - > Flink ;
2016-05-05 17:26:47 +00:00
tree * t = CONTAINING_RECORD ( le , tree , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( t - > root = = r ) {
if ( t - > header . level = = level ) {
2019-09-01 12:53:20 +00:00
bool top = ! t - > paritem ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
empty = false ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
free_tree ( t ) ;
2016-07-27 19:24:26 +00:00
if ( top & & r - > treeholder . tree = = t )
r - > treeholder . tree = NULL ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( IsListEmpty ( & Vcb - > trees ) )
return ;
} else if ( t - > header . level > level )
2019-09-01 12:53:20 +00:00
empty = false ;
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
le = nextle ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( empty )
break ;
}
}
2022-04-28 19:31:44 +00:00
__attribute__ ( ( nonnull ( 1 ) ) )
2017-09-08 08:02:43 +00:00
void free_trees ( device_extension * Vcb ) {
2016-07-27 19:24:26 +00:00
LIST_ENTRY * le ;
2017-09-08 08:02:43 +00:00
ULONG level ;
2016-07-27 19:24:26 +00:00
for ( level = 0 ; level < = 255 ; level + + ) {
2019-09-01 12:53:20 +00:00
bool empty = true ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
le = Vcb - > trees . Flink ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
while ( le ! = & Vcb - > trees ) {
LIST_ENTRY * nextle = le - > Flink ;
tree * t = CONTAINING_RECORD ( le , tree , list_entry ) ;
root * r = t - > root ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( t - > header . level = = level ) {
2019-09-01 12:53:20 +00:00
bool top = ! t - > paritem ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
empty = false ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
free_tree ( t ) ;
2016-05-05 17:26:47 +00:00
if ( top & & r - > treeholder . tree = = t )
2016-03-23 20:35:05 +00:00
r - > treeholder . tree = NULL ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( IsListEmpty ( & Vcb - > trees ) )
2020-04-23 02:38:57 +00:00
break ;
2016-07-27 19:24:26 +00:00
} else if ( t - > header . level > level )
2019-09-01 12:53:20 +00:00
empty = false ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
le = nextle ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( empty )
break ;
2016-03-23 20:35:05 +00:00
}
2019-05-11 09:20:02 +00:00
reap_filerefs ( Vcb , Vcb - > root_fileref ) ;
reap_fcbs ( Vcb ) ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
# ifdef _MSC_VER
# pragma warning(push)
# pragma warning(suppress: 28194)
# endif
2022-04-28 19:31:44 +00:00
__attribute__ ( ( nonnull ( 1 , 3 ) ) )
2017-09-08 08:02:43 +00:00
void add_rollback ( _In_ LIST_ENTRY * rollback , _In_ enum rollback_type type , _In_ __drv_aliasesMem void * ptr ) {
2016-03-23 20:35:05 +00:00
rollback_item * ri ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
ri = ExAllocatePoolWithTag ( PagedPool , sizeof ( rollback_item ) , ALLOC_TAG ) ;
if ( ! ri ) {
ERR ( " out of memory \n " ) ;
return ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
ri - > type = type ;
ri - > ptr = ptr ;
InsertTailList ( rollback , & ri - > list_entry ) ;
}
2017-09-08 08:02:43 +00:00
# ifdef _MSC_VER
# pragma warning(pop)
# endif
2016-03-23 20:35:05 +00:00
2017-09-08 08:02:43 +00:00
# ifdef _MSC_VER
# pragma warning(push)
# pragma warning(suppress: 28194)
# endif
2022-04-28 19:31:44 +00:00
__attribute__ ( ( nonnull ( 1 , 2 ) ) )
2019-09-01 12:53:20 +00:00
NTSTATUS insert_tree_item ( _In_ _Requires_exclusive_lock_held_ ( _Curr_ - > tree_lock ) device_extension * Vcb , _In_ root * r , _In_ uint64_t obj_id ,
_In_ uint8_t obj_type , _In_ uint64_t offset , _In_reads_bytes_opt_ ( size ) _When_ ( return > = 0 , __drv_aliasesMem ) void * data ,
_In_ uint16_t size , _Out_opt_ traverse_ptr * ptp , _In_opt_ PIRP Irp ) {
2016-03-23 20:35:05 +00:00
traverse_ptr tp ;
KEY searchkey ;
int cmp ;
tree_data * td , * paritem ;
tree * t ;
# ifdef _DEBUG
LIST_ENTRY * le ;
KEY firstitem = { 0xcccccccccccccccc , 0xcc , 0xcccccccccccccccc } ;
# endif
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
TRACE ( " (%p, %p, %I64x, %x, %I64x, %p, %x, %p) \n " , Vcb , r , obj_id , obj_type , offset , data , size , ptp ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
searchkey . obj_id = obj_id ;
searchkey . obj_type = obj_type ;
searchkey . offset = offset ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , r , & tp , & searchkey , true , Irp ) ;
2016-09-04 15:27:46 +00:00
if ( Status = = STATUS_NOT_FOUND ) {
2022-04-28 19:31:44 +00:00
if ( ! r - > treeholder . tree ) {
Status = do_load_tree ( Vcb , & r - > treeholder , r , NULL , NULL , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " do_load_tree returned %08lx \n " , Status ) ;
return Status ;
2016-03-23 20:35:05 +00:00
}
2022-04-28 19:31:44 +00:00
}
2017-09-08 08:02:43 +00:00
2022-04-28 19:31:44 +00:00
if ( r - > treeholder . tree & & r - > treeholder . tree - > header . num_items = = 0 ) {
tp . tree = r - > treeholder . tree ;
tp . item = NULL ;
2016-03-23 20:35:05 +00:00
} else {
2022-04-28 19:31:44 +00:00
ERR ( " error: unable to load tree for root %I64x \n " , r - > id ) ;
return STATUS_INTERNAL_ERROR ;
2016-03-23 20:35:05 +00:00
}
2016-09-04 15:27:46 +00:00
} else 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 ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
TRACE ( " tp.item = %p \n " , tp . item ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( tp . item ) {
TRACE ( " tp.item->key = %p \n " , & tp . item - > key ) ;
2016-10-29 17:05:10 +00:00
cmp = keycmp ( searchkey , tp . item - > key ) ;
2017-09-08 08:02:43 +00:00
if ( cmp = = 0 & & ! tp . item - > ignore ) {
2019-09-01 12:53:20 +00:00
ERR ( " error: key (%I64x,%x,%I64x) already present \n " , obj_id , obj_type , offset ) ;
2017-09-08 08:02:43 +00:00
# ifdef DEBUG_PARANOID
2016-09-04 15:27:46 +00:00
int3 ;
2017-09-08 08:02:43 +00:00
# endif
return STATUS_INTERNAL_ERROR ;
2016-03-23 20:35:05 +00:00
}
} else
cmp = - 1 ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
td = ExAllocateFromPagedLookasideList ( & Vcb - > tree_data_lookaside ) ;
2016-03-23 20:35:05 +00:00
if ( ! td ) {
ERR ( " out of memory \n " ) ;
2017-09-08 08:02:43 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
td - > key = searchkey ;
td - > size = size ;
td - > data = data ;
2019-09-01 12:53:20 +00:00
td - > ignore = false ;
td - > inserted = true ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
# ifdef _DEBUG
le = tp . tree - > itemlist . Flink ;
while ( le ! = & tp . tree - > itemlist ) {
tree_data * td2 = CONTAINING_RECORD ( le , tree_data , list_entry ) ;
firstitem = td2 - > key ;
break ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
TRACE ( " inserting %I64x,%x,%I64x into tree beginning %I64x,%x,%I64x (num_items %x) \n " , obj_id , obj_type , offset , firstitem . obj_id , firstitem . obj_type , firstitem . offset , tp . tree - > header . num_items ) ;
2016-03-23 20:35:05 +00:00
# endif
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( cmp = = - 1 ) { // very first key in root
InsertHeadList ( & tp . tree - > itemlist , & td - > list_entry ) ;
paritem = tp . tree - > paritem ;
while ( paritem ) {
2016-10-29 17:05:10 +00:00
if ( ! keycmp ( paritem - > key , tp . item - > key ) ) {
2016-03-23 20:35:05 +00:00
paritem - > key = searchkey ;
} else
break ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
paritem = paritem - > treeholder . tree - > paritem ;
}
2016-10-29 17:05:10 +00:00
} else if ( cmp = = 0 )
InsertHeadList ( tp . item - > list_entry . Blink , & td - > list_entry ) ; // make sure non-deleted item is before deleted ones
else
InsertHeadList ( & tp . item - > list_entry , & td - > list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
tp . tree - > header . num_items + + ;
tp . tree - > size + = size + sizeof ( leaf_node ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( ! tp . tree - > write ) {
2019-09-01 12:53:20 +00:00
tp . tree - > write = true ;
Vcb - > need_write = true ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( ptp )
2016-03-23 20:35:05 +00:00
* ptp = tp ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
t = tp . tree ;
while ( t ) {
if ( t - > paritem & & t - > paritem - > ignore ) {
2019-09-01 12:53:20 +00:00
t - > paritem - > ignore = false ;
2016-03-23 20:35:05 +00:00
t - > parent - > header . num_items + + ;
t - > parent - > size + = sizeof ( internal_node ) ;
}
t - > header . generation = Vcb - > superblock . generation ;
t = t - > parent ;
}
2017-09-08 08:02:43 +00:00
return STATUS_SUCCESS ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
# ifdef _MSC_VER
# pragma warning(pop)
# endif
2016-03-23 20:35:05 +00:00
2022-04-28 19:31:44 +00:00
__attribute__ ( ( nonnull ( 1 , 2 ) ) )
2017-09-08 08:02:43 +00:00
NTSTATUS delete_tree_item ( _In_ _Requires_exclusive_lock_held_ ( _Curr_ - > tree_lock ) device_extension * Vcb , _Inout_ traverse_ptr * tp ) {
2016-03-23 20:35:05 +00:00
tree * t ;
2019-09-01 12:53:20 +00:00
uint64_t gen ;
2016-03-23 20:35:05 +00:00
2019-09-01 12:53:20 +00:00
TRACE ( " deleting item %I64x,%x,%I64x (ignore = %s) \n " , tp - > item - > key . obj_id , tp - > item - > key . obj_type , tp - > item - > key . offset , tp - > item - > ignore ? " true " : " false " ) ;
2016-07-27 19:24:26 +00:00
2017-09-08 08:02:43 +00:00
# ifdef DEBUG_PARANOID
2016-03-23 20:35:05 +00:00
if ( tp - > item - > ignore ) {
2019-09-01 12:53:20 +00:00
ERR ( " trying to delete already-deleted item %I64x,%x,%I64x \n " , tp - > item - > key . obj_id , tp - > item - > key . obj_type , tp - > item - > key . offset ) ;
2016-03-23 20:35:05 +00:00
int3 ;
2017-09-08 08:02:43 +00:00
return STATUS_INTERNAL_ERROR ;
2016-03-23 20:35:05 +00:00
}
# endif
2019-09-01 12:53:20 +00:00
tp - > item - > ignore = true ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( ! tp - > tree - > write ) {
2019-09-01 12:53:20 +00:00
tp - > tree - > write = true ;
Vcb - > need_write = true ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
tp - > tree - > header . num_items - - ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( tp - > tree - > header . level = = 0 )
tp - > tree - > size - = sizeof ( leaf_node ) + tp - > item - > size ;
else
tp - > tree - > size - = sizeof ( internal_node ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
gen = tp - > tree - > Vcb - > superblock . generation ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
t = tp - > tree ;
while ( t ) {
t - > header . generation = gen ;
t = t - > parent ;
}
2017-09-08 08:02:43 +00:00
return STATUS_SUCCESS ;
2016-03-23 20:35:05 +00:00
}
2022-04-28 19:31:44 +00:00
__attribute__ ( ( nonnull ( 1 ) ) )
2017-09-08 08:02:43 +00:00
void clear_rollback ( LIST_ENTRY * rollback ) {
2016-03-23 20:35:05 +00:00
while ( ! IsListEmpty ( rollback ) ) {
LIST_ENTRY * le = RemoveHeadList ( rollback ) ;
2017-09-08 08:02:43 +00:00
rollback_item * ri = CONTAINING_RECORD ( le , rollback_item , list_entry ) ;
2016-03-23 20:35:05 +00:00
switch ( ri - > type ) {
2016-09-04 15:27:46 +00:00
case ROLLBACK_ADD_SPACE :
case ROLLBACK_SUBTRACT_SPACE :
case ROLLBACK_INSERT_EXTENT :
case ROLLBACK_DELETE_EXTENT :
2016-03-23 20:35:05 +00:00
ExFreePool ( ri - > ptr ) ;
break ;
2016-07-27 19:24:26 +00:00
default :
break ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
ExFreePool ( ri ) ;
}
}
2022-04-28 19:31:44 +00:00
__attribute__ ( ( nonnull ( 1 , 2 ) ) )
2016-03-23 20:35:05 +00:00
void do_rollback ( device_extension * Vcb , LIST_ENTRY * rollback ) {
2016-09-04 15:27:46 +00:00
NTSTATUS Status ;
2016-03-23 20:35:05 +00:00
rollback_item * ri ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
while ( ! IsListEmpty ( rollback ) ) {
2016-07-27 19:24:26 +00:00
LIST_ENTRY * le = RemoveTailList ( rollback ) ;
2016-03-23 20:35:05 +00:00
ri = CONTAINING_RECORD ( le , rollback_item , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
switch ( ri - > type ) {
2016-07-27 19:24:26 +00:00
case ROLLBACK_INSERT_EXTENT :
{
2016-09-04 15:27:46 +00:00
rollback_extent * re = ri - > ptr ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
re - > ext - > ignore = true ;
2017-09-08 08:02:43 +00:00
2022-04-28 19:31:44 +00:00
switch ( re - > ext - > extent_data . type ) {
case EXTENT_TYPE_REGULAR :
case EXTENT_TYPE_PREALLOC : {
EXTENT_DATA2 * ed2 = ( EXTENT_DATA2 * ) re - > ext - > extent_data . data ;
2017-09-08 08:02:43 +00:00
2022-04-28 19:31:44 +00:00
if ( ed2 - > size ! = 0 ) {
chunk * c = get_chunk_from_address ( Vcb , ed2 - > address ) ;
2017-09-08 08:02:43 +00:00
2022-04-28 19:31:44 +00:00
if ( c ) {
Status = update_changed_extent_ref ( Vcb , c , ed2 - > address , ed2 - > size , re - > fcb - > subvol - > id ,
re - > fcb - > inode , re - > ext - > offset - ed2 - > offset , - 1 ,
re - > fcb - > inode_item . flags & BTRFS_INODE_NODATASUM , false , NULL ) ;
if ( ! NT_SUCCESS ( Status ) )
ERR ( " update_changed_extent_ref returned %08lx \n " , Status ) ;
}
2017-09-08 08:02:43 +00:00
2022-04-28 19:31:44 +00:00
re - > fcb - > inode_item . st_blocks - = ed2 - > num_bytes ;
2016-09-04 15:27:46 +00:00
}
2017-09-08 08:02:43 +00:00
2022-04-28 19:31:44 +00:00
break ;
2016-09-04 15:27:46 +00:00
}
2022-04-28 19:31:44 +00:00
case EXTENT_TYPE_INLINE :
re - > fcb - > inode_item . st_blocks - = re - > ext - > extent_data . decoded_size ;
break ;
2016-09-04 15:27:46 +00:00
}
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
ExFreePool ( re ) ;
2016-07-27 19:24:26 +00:00
break ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
case ROLLBACK_DELETE_EXTENT :
{
2016-09-04 15:27:46 +00:00
rollback_extent * re = ri - > ptr ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
re - > ext - > ignore = false ;
2017-09-08 08:02:43 +00:00
2022-04-28 19:31:44 +00:00
switch ( re - > ext - > extent_data . type ) {
case EXTENT_TYPE_REGULAR :
case EXTENT_TYPE_PREALLOC : {
EXTENT_DATA2 * ed2 = ( EXTENT_DATA2 * ) re - > ext - > extent_data . data ;
2017-09-08 08:02:43 +00:00
2022-04-28 19:31:44 +00:00
if ( ed2 - > size ! = 0 ) {
chunk * c = get_chunk_from_address ( Vcb , ed2 - > address ) ;
2017-09-08 08:02:43 +00:00
2022-04-28 19:31:44 +00:00
if ( c ) {
Status = update_changed_extent_ref ( Vcb , c , ed2 - > address , ed2 - > size , re - > fcb - > subvol - > id ,
re - > fcb - > inode , re - > ext - > offset - ed2 - > offset , 1 ,
re - > fcb - > inode_item . flags & BTRFS_INODE_NODATASUM , false , NULL ) ;
if ( ! NT_SUCCESS ( Status ) )
ERR ( " update_changed_extent_ref returned %08lx \n " , Status ) ;
}
2017-09-08 08:02:43 +00:00
2022-04-28 19:31:44 +00:00
re - > fcb - > inode_item . st_blocks + = ed2 - > num_bytes ;
2016-09-04 15:27:46 +00:00
}
2017-09-08 08:02:43 +00:00
2022-04-28 19:31:44 +00:00
break ;
2016-09-04 15:27:46 +00:00
}
2022-04-28 19:31:44 +00:00
case EXTENT_TYPE_INLINE :
re - > fcb - > inode_item . st_blocks + = re - > ext - > extent_data . decoded_size ;
break ;
2016-09-04 15:27:46 +00:00
}
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
ExFreePool ( re ) ;
break ;
}
case ROLLBACK_ADD_SPACE :
case ROLLBACK_SUBTRACT_SPACE :
{
rollback_space * rs = ri - > ptr ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
if ( rs - > chunk )
2018-12-16 11:03:16 +00:00
acquire_chunk_lock ( rs - > chunk , Vcb ) ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
if ( ri - > type = = ROLLBACK_ADD_SPACE )
2017-09-08 08:02:43 +00:00
space_list_subtract2 ( rs - > list , rs - > list_size , rs - > address , rs - > length , NULL , NULL ) ;
2016-09-04 15:27:46 +00:00
else
2017-09-08 08:02:43 +00:00
space_list_add2 ( rs - > list , rs - > list_size , rs - > address , rs - > length , NULL , NULL ) ;
if ( rs - > chunk ) {
if ( ri - > type = = ROLLBACK_ADD_SPACE )
rs - > chunk - > used + = rs - > length ;
else
rs - > chunk - > used - = rs - > length ;
}
2016-09-04 15:27:46 +00:00
if ( rs - > chunk ) {
LIST_ENTRY * le2 = le - > Blink ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
while ( le2 ! = rollback ) {
LIST_ENTRY * le3 = le2 - > Blink ;
rollback_item * ri2 = CONTAINING_RECORD ( le2 , rollback_item , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
if ( ri2 - > type = = ROLLBACK_ADD_SPACE | | ri2 - > type = = ROLLBACK_SUBTRACT_SPACE ) {
rollback_space * rs2 = ri2 - > ptr ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
if ( rs2 - > chunk = = rs - > chunk ) {
2017-09-08 08:02:43 +00:00
if ( ri2 - > type = = ROLLBACK_ADD_SPACE ) {
space_list_subtract2 ( rs2 - > list , rs2 - > list_size , rs2 - > address , rs2 - > length , NULL , NULL ) ;
rs - > chunk - > used + = rs2 - > length ;
} else {
space_list_add2 ( rs2 - > list , rs2 - > list_size , rs2 - > address , rs2 - > length , NULL , NULL ) ;
rs - > chunk - > used - = rs2 - > length ;
}
2016-09-04 15:27:46 +00:00
ExFreePool ( rs2 ) ;
RemoveEntryList ( & ri2 - > list_entry ) ;
ExFreePool ( ri2 ) ;
}
}
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
le2 = le3 ;
}
2017-09-08 08:02:43 +00:00
2018-12-16 11:03:16 +00:00
release_chunk_lock ( rs - > chunk , Vcb ) ;
2016-09-04 15:27:46 +00:00
}
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
ExFreePool ( rs ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
break ;
}
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
ExFreePool ( ri ) ;
}
}
2016-10-29 17:05:10 +00:00
2022-04-28 19:31:44 +00:00
__attribute__ ( ( nonnull ( 1 , 2 , 3 ) ) )
static NTSTATUS find_tree_end ( tree * t , KEY * tree_end , bool * no_end ) {
2016-10-29 17:05:10 +00:00
tree * p ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
p = t ;
do {
tree_data * pi ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! p - > parent ) {
2022-04-28 19:31:44 +00:00
tree_end - > obj_id = 0xffffffffffffffff ;
tree_end - > obj_type = 0xff ;
tree_end - > offset = 0xffffffffffffffff ;
2019-09-01 12:53:20 +00:00
* no_end = true ;
2022-04-28 19:31:44 +00:00
return STATUS_SUCCESS ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
pi = p - > paritem ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( pi - > list_entry . Flink ! = & p - > parent - > itemlist ) {
tree_data * td = CONTAINING_RECORD ( pi - > list_entry . Flink , tree_data , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
* tree_end = td - > key ;
2019-09-01 12:53:20 +00:00
* no_end = false ;
2022-04-28 19:31:44 +00:00
return STATUS_SUCCESS ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
p = p - > parent ;
} while ( p ) ;
2022-04-28 19:31:44 +00:00
return STATUS_INTERNAL_ERROR ;
2016-10-29 17:05:10 +00:00
}
2022-04-28 19:31:44 +00:00
__attribute__ ( ( nonnull ( 1 , 2 ) ) )
2016-10-29 17:05:10 +00:00
void clear_batch_list ( device_extension * Vcb , LIST_ENTRY * batchlist ) {
while ( ! IsListEmpty ( batchlist ) ) {
LIST_ENTRY * le = RemoveHeadList ( batchlist ) ;
batch_root * br = CONTAINING_RECORD ( le , batch_root , list_entry ) ;
2017-09-08 08:02:43 +00:00
2022-09-28 16:08:10 +00:00
while ( ! IsListEmpty ( & br - > items_ind ) ) {
batch_item_ind * bii = CONTAINING_RECORD ( RemoveHeadList ( & br - > items_ind ) , batch_item_ind , list_entry ) ;
2017-09-08 08:02:43 +00:00
2022-09-28 16:08:10 +00:00
while ( ! IsListEmpty ( & bii - > items ) ) {
batch_item * bi = CONTAINING_RECORD ( RemoveHeadList ( & bii - > items ) , batch_item , list_entry ) ;
ExFreeToPagedLookasideList ( & Vcb - > batch_item_lookaside , bi ) ;
}
ExFreePool ( bii ) ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ExFreePool ( br ) ;
}
}
2022-04-28 19:31:44 +00:00
__attribute__ ( ( nonnull ( 1 , 2 , 3 ) ) )
2017-01-01 17:12:12 +00:00
static void add_delete_inode_extref ( device_extension * Vcb , batch_item * bi , LIST_ENTRY * listhead ) {
batch_item * bi2 ;
LIST_ENTRY * le ;
INODE_REF * delir = ( INODE_REF * ) bi - > data ;
INODE_EXTREF * ier ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
TRACE ( " entry in INODE_REF not found, adding Batch_DeleteInodeExtRef entry \n " ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
bi2 = ExAllocateFromPagedLookasideList ( & Vcb - > batch_item_lookaside ) ;
if ( ! bi2 ) {
ERR ( " out of memory \n " ) ;
return ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
ier = ExAllocatePoolWithTag ( PagedPool , sizeof ( INODE_EXTREF ) - 1 + delir - > n , ALLOC_TAG ) ;
if ( ! ier ) {
ERR ( " out of memory \n " ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( bi2 ) ;
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
ier - > dir = bi - > key . offset ;
ier - > index = delir - > index ;
ier - > n = delir - > n ;
RtlCopyMemory ( ier - > name , delir - > name , delir - > n ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
bi2 - > key . obj_id = bi - > key . obj_id ;
bi2 - > key . obj_type = TYPE_INODE_EXTREF ;
2019-09-01 12:53:20 +00:00
bi2 - > key . offset = calc_crc32c ( ( uint32_t ) bi - > key . offset , ( uint8_t * ) ier - > name , ier - > n ) ;
2017-01-01 17:12:12 +00:00
bi2 - > data = ier ;
bi2 - > datalen = sizeof ( INODE_EXTREF ) - 1 + ier - > n ;
bi2 - > operation = Batch_DeleteInodeExtRef ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le = bi - > list_entry . Flink ;
while ( le ! = listhead ) {
batch_item * bi3 = CONTAINING_RECORD ( le , batch_item , list_entry ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( keycmp ( bi3 - > key , bi2 - > key ) ! = - 1 ) {
InsertHeadList ( le - > Blink , & bi2 - > list_entry ) ;
return ;
}
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
InsertTailList ( listhead , & bi2 - > list_entry ) ;
}
2022-04-28 19:31:44 +00:00
__attribute__ ( ( nonnull ( 1 , 2 , 3 , 4 , 6 , 7 ) ) )
2019-09-01 12:53:20 +00:00
static NTSTATUS handle_batch_collision ( device_extension * Vcb , batch_item * bi , tree * t , tree_data * td , tree_data * newtd , LIST_ENTRY * listhead , bool * ignore ) {
2017-01-01 17:12:12 +00:00
if ( bi - > operation = = Batch_Delete | | bi - > operation = = Batch_SetXattr | | bi - > operation = = Batch_DirItem | | bi - > operation = = Batch_InodeRef | |
bi - > operation = = Batch_InodeExtRef | | bi - > operation = = Batch_DeleteDirItem | | bi - > operation = = Batch_DeleteInodeRef | |
2017-09-08 08:02:43 +00:00
bi - > operation = = Batch_DeleteInodeExtRef | | bi - > operation = = Batch_DeleteXattr ) {
2019-09-01 12:53:20 +00:00
uint16_t maxlen = ( uint16_t ) ( Vcb - > superblock . node_size - sizeof ( tree_header ) - sizeof ( leaf_node ) ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
switch ( bi - > operation ) {
case Batch_SetXattr : {
if ( td - > size < sizeof ( DIR_ITEM ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " (%I64x,%x,%I64x) was %u bytes, expected at least %Iu \n " , bi - > key . obj_id , bi - > key . obj_type , bi - > key . offset , td - > size , sizeof ( DIR_ITEM ) ) ;
2017-01-01 17:12:12 +00:00
} else {
2019-09-01 12:53:20 +00:00
uint8_t * newdata ;
2017-01-01 17:12:12 +00:00
ULONG size = td - > size ;
DIR_ITEM * newxa = ( DIR_ITEM * ) bi - > data ;
DIR_ITEM * xa = ( DIR_ITEM * ) td - > data ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
while ( true ) {
2017-01-01 17:12:12 +00:00
ULONG oldxasize ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( size < sizeof ( DIR_ITEM ) | | size < sizeof ( DIR_ITEM ) - 1 + xa - > m + xa - > n ) {
2019-09-01 12:53:20 +00:00
ERR ( " (%I64x,%x,%I64x) was truncated \n " , bi - > key . obj_id , bi - > key . obj_type , bi - > key . offset ) ;
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
oldxasize = sizeof ( DIR_ITEM ) - 1 + xa - > m + xa - > n ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( xa - > n = = newxa - > n & & RtlCompareMemory ( newxa - > name , xa - > name , xa - > n ) = = xa - > n ) {
2019-09-01 12:53:20 +00:00
uint64_t pos ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
// replace
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( td - > size + bi - > datalen - oldxasize > maxlen )
2020-04-23 02:38:57 +00:00
ERR ( " DIR_ITEM would be over maximum size, truncating (%u + %u - %lu > %u) \n " , td - > size , bi - > datalen , oldxasize , maxlen ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
newdata = ExAllocatePoolWithTag ( PagedPool , td - > size + bi - > datalen - oldxasize , ALLOC_TAG ) ;
if ( ! newdata ) {
ERR ( " out of memory \n " ) ;
2017-09-08 08:02:43 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
2017-01-01 17:12:12 +00:00
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
pos = ( uint8_t * ) xa - td - > data ;
2017-09-08 08:02:43 +00:00
if ( pos + oldxasize < td - > size ) // copy after changed xattr
RtlCopyMemory ( newdata + pos + bi - > datalen , td - > data + pos + oldxasize , ( ULONG ) ( td - > size - pos - oldxasize ) ) ;
2017-01-01 17:12:12 +00:00
if ( pos > 0 ) { // copy before changed xattr
2017-09-08 08:02:43 +00:00
RtlCopyMemory ( newdata , td - > data , ( ULONG ) pos ) ;
2017-01-01 17:12:12 +00:00
xa = ( DIR_ITEM * ) ( newdata + pos ) ;
} else
xa = ( DIR_ITEM * ) newdata ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
RtlCopyMemory ( xa , bi - > data , bi - > datalen ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
bi - > datalen = ( uint16_t ) min ( td - > size + bi - > datalen - oldxasize , maxlen ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
ExFreePool ( bi - > data ) ;
bi - > data = newdata ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
break ;
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 ( ( uint8_t * ) xa - ( uint8_t * ) td - > data + oldxasize > = size ) {
2017-01-01 17:12:12 +00:00
// not found, add to end of data
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( td - > size + bi - > datalen > maxlen )
ERR ( " DIR_ITEM would be over maximum size, truncating (%u + %u > %u) \n " , td - > size , bi - > datalen , maxlen ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
newdata = ExAllocatePoolWithTag ( PagedPool , td - > size + bi - > datalen , ALLOC_TAG ) ;
if ( ! newdata ) {
ERR ( " out of memory \n " ) ;
2017-09-08 08:02:43 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
2017-01-01 17:12:12 +00:00
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
RtlCopyMemory ( newdata , td - > data , td - > size ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
xa = ( DIR_ITEM * ) ( ( uint8_t * ) newdata + td - > size ) ;
2017-01-01 17:12:12 +00:00
RtlCopyMemory ( xa , bi - > data , bi - > datalen ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
bi - > datalen = min ( bi - > datalen + td - > size , maxlen ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
ExFreePool ( bi - > data ) ;
bi - > data = newdata ;
break ;
} else {
xa = ( DIR_ITEM * ) & xa - > name [ xa - > m + xa - > n ] ;
size - = oldxasize ;
2016-10-29 17:05:10 +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
case Batch_DirItem : {
2019-09-01 12:53:20 +00:00
uint8_t * newdata ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( td - > size + bi - > datalen > maxlen ) {
ERR ( " DIR_ITEM would be over maximum size (%u + %u > %u) \n " , td - > size , bi - > datalen , maxlen ) ;
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
newdata = ExAllocatePoolWithTag ( PagedPool , td - > size + bi - > datalen , ALLOC_TAG ) ;
if ( ! newdata ) {
ERR ( " out of memory \n " ) ;
2017-09-08 08:02:43 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
2017-01-01 17:12:12 +00:00
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
RtlCopyMemory ( newdata , td - > data , td - > size ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
RtlCopyMemory ( newdata + td - > size , bi - > data , bi - > datalen ) ;
bi - > datalen + = td - > size ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
ExFreePool ( bi - > data ) ;
bi - > data = newdata ;
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
case Batch_InodeRef : {
2019-09-01 12:53:20 +00:00
uint8_t * newdata ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( td - > size + bi - > datalen > maxlen ) {
if ( Vcb - > superblock . incompat_flags & BTRFS_INCOMPAT_FLAGS_EXTENDED_IREF ) {
INODE_REF * ir = ( INODE_REF * ) bi - > data ;
INODE_EXTREF * ier ;
2019-09-01 12:53:20 +00:00
uint16_t ierlen ;
2017-01-01 17:12:12 +00:00
batch_item * bi2 ;
LIST_ENTRY * le ;
2019-09-01 12:53:20 +00:00
bool inserted = false ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
TRACE ( " INODE_REF would be too long, adding INODE_EXTREF instead \n " ) ;
2019-09-01 12:53:20 +00:00
ierlen = ( uint16_t ) ( offsetof ( INODE_EXTREF , name [ 0 ] ) + ir - > n ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
ier = ExAllocatePoolWithTag ( PagedPool , ierlen , ALLOC_TAG ) ;
if ( ! ier ) {
ERR ( " out of memory \n " ) ;
2017-09-08 08:02:43 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
2017-01-01 17:12:12 +00:00
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
ier - > dir = bi - > key . offset ;
ier - > index = ir - > index ;
ier - > n = ir - > n ;
RtlCopyMemory ( ier - > name , ir - > name , ier - > n ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
bi2 = ExAllocateFromPagedLookasideList ( & Vcb - > batch_item_lookaside ) ;
if ( ! bi2 ) {
2016-10-29 17:05:10 +00:00
ERR ( " out of memory \n " ) ;
2017-01-01 17:12:12 +00:00
ExFreePool ( ier ) ;
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
2017-01-01 17:12:12 +00:00
bi2 - > key . obj_id = bi - > key . obj_id ;
bi2 - > key . obj_type = TYPE_INODE_EXTREF ;
2019-09-01 12:53:20 +00:00
bi2 - > key . offset = calc_crc32c ( ( uint32_t ) ier - > dir , ( uint8_t * ) ier - > name , ier - > n ) ;
2017-01-01 17:12:12 +00:00
bi2 - > data = ier ;
bi2 - > datalen = ierlen ;
bi2 - > operation = Batch_InodeExtRef ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le = bi - > list_entry . Flink ;
while ( le ! = listhead ) {
batch_item * bi3 = CONTAINING_RECORD ( le , batch_item , list_entry ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( keycmp ( bi3 - > key , bi2 - > key ) ! = - 1 ) {
InsertHeadList ( le - > Blink , & bi2 - > list_entry ) ;
2019-09-01 12:53:20 +00:00
inserted = 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
if ( ! inserted )
InsertTailList ( listhead , & bi2 - > list_entry ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
* ignore = true ;
2017-09-08 08:02:43 +00:00
return STATUS_SUCCESS ;
2016-10-29 17:05:10 +00:00
} else {
2017-01-01 17:12:12 +00:00
ERR ( " INODE_REF would be over maximum size (%u + %u > %u) \n " , td - > size , bi - > datalen , maxlen ) ;
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
2017-01-01 17:12:12 +00:00
newdata = ExAllocatePoolWithTag ( PagedPool , td - > size + bi - > datalen , ALLOC_TAG ) ;
if ( ! newdata ) {
ERR ( " out of memory \n " ) ;
2017-09-08 08:02:43 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
2017-01-01 17:12:12 +00:00
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
RtlCopyMemory ( newdata , td - > data , td - > size ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
RtlCopyMemory ( newdata + td - > size , bi - > data , bi - > datalen ) ;
bi - > datalen + = td - > size ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
ExFreePool ( bi - > data ) ;
bi - > data = newdata ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
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
case Batch_InodeExtRef : {
2019-09-01 12:53:20 +00:00
uint8_t * newdata ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( td - > size + bi - > datalen > maxlen ) {
ERR ( " INODE_EXTREF would be over maximum size (%u + %u > %u) \n " , td - > size , bi - > datalen , maxlen ) ;
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
newdata = ExAllocatePoolWithTag ( PagedPool , td - > size + bi - > datalen , ALLOC_TAG ) ;
if ( ! newdata ) {
ERR ( " out of memory \n " ) ;
2017-09-08 08:02:43 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
2017-01-01 17:12:12 +00:00
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
RtlCopyMemory ( newdata , td - > data , td - > size ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
RtlCopyMemory ( newdata + td - > size , bi - > data , bi - > datalen ) ;
2016-10-29 17:05:10 +00:00
2017-01-01 17:12:12 +00:00
bi - > datalen + = td - > size ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
ExFreePool ( bi - > data ) ;
bi - > data = newdata ;
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
case Batch_DeleteDirItem : {
if ( td - > size < sizeof ( DIR_ITEM ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " DIR_ITEM was %u bytes, expected at least %Iu \n " , td - > size , sizeof ( DIR_ITEM ) ) ;
2017-09-08 08:02:43 +00:00
return STATUS_INTERNAL_ERROR ;
2017-01-01 17:12:12 +00:00
} else {
DIR_ITEM * di , * deldi ;
LONG len ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
deldi = ( DIR_ITEM * ) bi - > data ;
di = ( DIR_ITEM * ) td - > data ;
len = td - > size ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
do {
if ( di - > m = = deldi - > m & & di - > n = = deldi - > n & & RtlCompareMemory ( di - > name , deldi - > name , di - > n + di - > m ) = = di - > n + di - > m ) {
2019-09-01 12:53:20 +00:00
uint16_t newlen = td - > size - ( sizeof ( DIR_ITEM ) - sizeof ( char ) + di - > n + di - > m ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( newlen = = 0 ) {
TRACE ( " deleting DIR_ITEM \n " ) ;
} else {
2019-09-01 12:53:20 +00:00
uint8_t * newdi = ExAllocatePoolWithTag ( PagedPool , newlen , ALLOC_TAG ) , * dioff ;
2017-01-01 17:12:12 +00:00
tree_data * td2 ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! newdi ) {
ERR ( " out of memory \n " ) ;
2017-09-08 08:02:43 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
2017-01-01 17:12:12 +00:00
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
TRACE ( " modifying DIR_ITEM \n " ) ;
2016-10-29 17:05:10 +00:00
2019-09-01 12:53:20 +00:00
if ( ( uint8_t * ) di > td - > data ) {
RtlCopyMemory ( newdi , td - > data , ( uint8_t * ) di - td - > data ) ;
dioff = newdi + ( ( uint8_t * ) di - td - > data ) ;
2017-01-01 17:12:12 +00:00
} else {
dioff = newdi ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
if ( ( uint8_t * ) & di - > name [ di - > n + di - > m ] < td - > data + td - > size )
RtlCopyMemory ( dioff , & di - > name [ di - > n + di - > m ] , td - > size - ( ( uint8_t * ) & di - > name [ di - > n + di - > m ] - td - > data ) ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
td2 = ExAllocateFromPagedLookasideList ( & Vcb - > tree_data_lookaside ) ;
if ( ! td2 ) {
ERR ( " out of memory \n " ) ;
2018-12-16 11:03:16 +00:00
ExFreePool ( newdi ) ;
2017-09-08 08:02:43 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
2017-01-01 17:12:12 +00:00
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
td2 - > key = bi - > key ;
td2 - > size = newlen ;
td2 - > data = newdi ;
2019-09-01 12:53:20 +00:00
td2 - > ignore = false ;
td2 - > inserted = true ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
InsertHeadList ( td - > list_entry . Blink , & td2 - > list_entry ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
t - > header . num_items + + ;
t - > size + = newlen + sizeof ( leaf_node ) ;
2019-09-01 12:53:20 +00:00
t - > write = 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
break ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
len - = sizeof ( DIR_ITEM ) - sizeof ( char ) + di - > n + di - > m ;
di = ( DIR_ITEM * ) & di - > name [ di - > n + di - > m ] ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( len = = 0 ) {
TRACE ( " could not find DIR_ITEM to delete \n " ) ;
2019-09-01 12:53:20 +00:00
* ignore = true ;
2017-09-08 08:02:43 +00:00
return STATUS_SUCCESS ;
2017-01-01 17:12:12 +00:00
}
} while ( len > 0 ) ;
}
break ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
case Batch_DeleteInodeRef : {
if ( td - > size < sizeof ( INODE_REF ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " INODE_REF was %u bytes, expected at least %Iu \n " , td - > size , sizeof ( INODE_REF ) ) ;
2017-09-08 08:02:43 +00:00
return STATUS_INTERNAL_ERROR ;
2017-01-01 17:12:12 +00:00
} else {
INODE_REF * ir , * delir ;
ULONG len ;
2019-09-01 12:53:20 +00:00
bool changed = false ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
delir = ( INODE_REF * ) bi - > data ;
ir = ( INODE_REF * ) td - > data ;
len = td - > size ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +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 ( INODE_REF ) | | len < offsetof ( INODE_REF , name [ 0 ] ) + ir - > n ) {
2017-01-01 17:12:12 +00:00
ERR ( " INODE_REF was truncated \n " ) ;
break ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
itemlen = ( uint16_t ) offsetof ( INODE_REF , name [ 0 ] ) + ir - > n ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ir - > n = = delir - > n & & RtlCompareMemory ( ir - > name , delir - > name , ir - > n ) = = ir - > n ) {
2019-09-01 12:53:20 +00:00
uint16_t newlen = td - > size - itemlen ;
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
2017-01-01 17:12:12 +00:00
if ( newlen = = 0 )
TRACE ( " deleting INODE_REF \n " ) ;
else {
2019-09-01 12:53:20 +00:00
uint8_t * newir = ExAllocatePoolWithTag ( PagedPool , newlen , ALLOC_TAG ) , * iroff ;
2017-01-01 17:12:12 +00:00
tree_data * td2 ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! newir ) {
ERR ( " out of memory \n " ) ;
2017-09-08 08:02:43 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
2017-01-01 17:12:12 +00:00
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
TRACE ( " modifying INODE_REF \n " ) ;
2019-09-01 12:53:20 +00:00
if ( ( uint8_t * ) ir > td - > data ) {
RtlCopyMemory ( newir , td - > data , ( uint8_t * ) ir - td - > data ) ;
iroff = newir + ( ( uint8_t * ) ir - td - > data ) ;
2017-01-01 17:12:12 +00:00
} else {
iroff = newir ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
if ( ( uint8_t * ) & ir - > name [ ir - > n ] < td - > data + td - > size )
RtlCopyMemory ( iroff , & ir - > name [ ir - > n ] , td - > size - ( ( uint8_t * ) & ir - > name [ ir - > n ] - td - > data ) ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
td2 = ExAllocateFromPagedLookasideList ( & Vcb - > tree_data_lookaside ) ;
if ( ! td2 ) {
ERR ( " out of memory \n " ) ;
2018-12-16 11:03:16 +00:00
ExFreePool ( newir ) ;
2017-09-08 08:02:43 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
2017-01-01 17:12:12 +00:00
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
td2 - > key = bi - > key ;
td2 - > size = newlen ;
td2 - > data = newir ;
2019-09-01 12:53:20 +00:00
td2 - > ignore = false ;
td2 - > inserted = true ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
InsertHeadList ( td - > list_entry . Blink , & td2 - > list_entry ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
t - > header . num_items + + ;
t - > size + = newlen + sizeof ( leaf_node ) ;
2019-09-01 12:53:20 +00:00
t - > write = 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
break ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( len > itemlen ) {
len - = itemlen ;
ir = ( INODE_REF * ) & ir - > name [ ir - > n ] ;
} else
break ;
} while ( len > 0 ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! changed ) {
if ( Vcb - > superblock . incompat_flags & BTRFS_INCOMPAT_FLAGS_EXTENDED_IREF ) {
TRACE ( " entry in INODE_REF not found, adding Batch_DeleteInodeExtRef entry \n " ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
add_delete_inode_extref ( Vcb , bi , listhead ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
* ignore = true ;
2017-09-08 08:02:43 +00:00
return STATUS_SUCCESS ;
2017-01-01 17:12:12 +00:00
} else
WARN ( " entry not found in INODE_REF \n " ) ;
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
break ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
case Batch_DeleteInodeExtRef : {
if ( td - > size < sizeof ( INODE_EXTREF ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " INODE_EXTREF was %u bytes, expected at least %Iu \n " , td - > size , sizeof ( INODE_EXTREF ) ) ;
2017-09-08 08:02:43 +00:00
return STATUS_INTERNAL_ERROR ;
2017-01-01 17:12:12 +00:00
} else {
INODE_EXTREF * ier , * delier ;
ULONG len ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
delier = ( INODE_EXTREF * ) bi - > data ;
ier = ( INODE_EXTREF * ) td - > data ;
len = td - > size ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +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 ( INODE_EXTREF ) | | len < offsetof ( INODE_EXTREF , name [ 0 ] ) + ier - > n ) {
2017-01-01 17:12:12 +00:00
ERR ( " INODE_REF was truncated \n " ) ;
break ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
itemlen = ( uint16_t ) offsetof ( INODE_EXTREF , name [ 0 ] ) + ier - > n ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ier - > dir = = delier - > dir & & ier - > n = = delier - > n & & RtlCompareMemory ( ier - > name , delier - > name , ier - > n ) = = ier - > n ) {
2019-09-01 12:53:20 +00:00
uint16_t newlen = td - > size - itemlen ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( newlen = = 0 )
TRACE ( " deleting INODE_EXTREF \n " ) ;
else {
2019-09-01 12:53:20 +00:00
uint8_t * newier = ExAllocatePoolWithTag ( PagedPool , newlen , ALLOC_TAG ) , * ieroff ;
2017-01-01 17:12:12 +00:00
tree_data * td2 ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! newier ) {
ERR ( " out of memory \n " ) ;
2017-09-08 08:02:43 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
2017-01-01 17:12:12 +00:00
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
TRACE ( " modifying INODE_EXTREF \n " ) ;
2016-10-29 17:05:10 +00:00
2019-09-01 12:53:20 +00:00
if ( ( uint8_t * ) ier > td - > data ) {
RtlCopyMemory ( newier , td - > data , ( uint8_t * ) ier - td - > data ) ;
ieroff = newier + ( ( uint8_t * ) ier - td - > data ) ;
2017-01-01 17:12:12 +00:00
} else {
ieroff = newier ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
if ( ( uint8_t * ) & ier - > name [ ier - > n ] < td - > data + td - > size )
RtlCopyMemory ( ieroff , & ier - > name [ ier - > n ] , td - > size - ( ( uint8_t * ) & ier - > name [ ier - > n ] - td - > data ) ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
td2 = ExAllocateFromPagedLookasideList ( & Vcb - > tree_data_lookaside ) ;
if ( ! td2 ) {
ERR ( " out of memory \n " ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( newier ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
2017-01-01 17:12:12 +00:00
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
td2 - > key = bi - > key ;
td2 - > size = newlen ;
td2 - > data = newier ;
2019-09-01 12:53:20 +00:00
td2 - > ignore = false ;
td2 - > inserted = true ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
InsertHeadList ( td - > list_entry . Blink , & td2 - > list_entry ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
t - > header . num_items + + ;
t - > size + = newlen + sizeof ( leaf_node ) ;
2019-09-01 12:53:20 +00:00
t - > write = 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
break ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( len > itemlen ) {
len - = itemlen ;
ier = ( INODE_EXTREF * ) & ier - > name [ ier - > n ] ;
} else
break ;
} while ( len > 0 ) ;
}
break ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
case Batch_DeleteXattr : {
if ( td - > size < sizeof ( DIR_ITEM ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " XATTR_ITEM was %u bytes, expected at least %Iu \n " , td - > size , sizeof ( DIR_ITEM ) ) ;
2017-09-08 08:02:43 +00:00
return STATUS_INTERNAL_ERROR ;
} else {
DIR_ITEM * di , * deldi ;
LONG len ;
deldi = ( DIR_ITEM * ) bi - > data ;
di = ( DIR_ITEM * ) td - > data ;
len = td - > size ;
do {
if ( di - > n = = deldi - > n & & RtlCompareMemory ( di - > name , deldi - > name , di - > n ) = = di - > n ) {
2019-09-01 12:53:20 +00:00
uint16_t newlen = td - > size - ( ( uint16_t ) offsetof ( DIR_ITEM , name [ 0 ] ) + di - > n + di - > m ) ;
2017-09-08 08:02:43 +00:00
if ( newlen = = 0 )
TRACE ( " deleting XATTR_ITEM \n " ) ;
else {
2019-09-01 12:53:20 +00:00
uint8_t * newdi = ExAllocatePoolWithTag ( PagedPool , newlen , ALLOC_TAG ) , * dioff ;
2017-09-08 08:02:43 +00:00
tree_data * td2 ;
if ( ! newdi ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
TRACE ( " modifying XATTR_ITEM \n " ) ;
2019-09-01 12:53:20 +00:00
if ( ( uint8_t * ) di > td - > data ) {
RtlCopyMemory ( newdi , td - > data , ( uint8_t * ) di - td - > data ) ;
dioff = newdi + ( ( uint8_t * ) di - td - > data ) ;
2017-09-08 08:02:43 +00:00
} else
dioff = newdi ;
2019-09-01 12:53:20 +00:00
if ( ( uint8_t * ) & di - > name [ di - > n + di - > m ] < td - > data + td - > size )
RtlCopyMemory ( dioff , & di - > name [ di - > n + di - > m ] , td - > size - ( ( uint8_t * ) & di - > name [ di - > n + di - > m ] - td - > data ) ) ;
2017-09-08 08:02:43 +00:00
td2 = ExAllocateFromPagedLookasideList ( & Vcb - > tree_data_lookaside ) ;
if ( ! td2 ) {
ERR ( " out of memory \n " ) ;
ExFreePool ( newdi ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
td2 - > key = bi - > key ;
td2 - > size = newlen ;
td2 - > data = newdi ;
2019-09-01 12:53:20 +00:00
td2 - > ignore = false ;
td2 - > inserted = true ;
2017-09-08 08:02:43 +00:00
InsertHeadList ( td - > list_entry . Blink , & td2 - > list_entry ) ;
t - > header . num_items + + ;
t - > size + = newlen + sizeof ( leaf_node ) ;
2019-09-01 12:53:20 +00:00
t - > write = true ;
2017-09-08 08:02:43 +00:00
}
break ;
}
len - = sizeof ( DIR_ITEM ) - sizeof ( char ) + di - > n + di - > m ;
di = ( DIR_ITEM * ) & di - > name [ di - > n + di - > m ] ;
if ( len = = 0 ) {
TRACE ( " could not find DIR_ITEM to delete \n " ) ;
2019-09-01 12:53:20 +00:00
* ignore = true ;
2017-09-08 08:02:43 +00:00
return STATUS_SUCCESS ;
}
} while ( len > 0 ) ;
}
break ;
}
2017-01-01 17:12:12 +00:00
case Batch_Delete :
break ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
default :
ERR ( " unexpected batch operation type \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
// delete old item
if ( ! td - > ignore ) {
2019-09-01 12:53:20 +00:00
td - > ignore = true ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
t - > header . num_items - - ;
t - > size - = sizeof ( leaf_node ) + td - > size ;
2019-09-01 12:53:20 +00:00
t - > write = true ;
2016-10-29 17:05:10 +00:00
}
2017-01-01 17:12:12 +00:00
if ( newtd ) {
newtd - > data = bi - > data ;
newtd - > size = bi - > datalen ;
2017-09-08 08:02:43 +00:00
InsertHeadList ( td - > list_entry . Blink , & newtd - > list_entry ) ;
2017-01-01 17:12:12 +00:00
}
2016-10-29 17:05:10 +00:00
} else {
2019-09-01 12:53:20 +00:00
ERR ( " (%I64x,%x,%I64x) already exists \n " , bi - > key . obj_id , bi - > key . obj_type , bi - > key . offset ) ;
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
2019-09-01 12:53:20 +00:00
* ignore = false ;
2017-09-08 08:02:43 +00:00
return STATUS_SUCCESS ;
2016-10-29 17:05:10 +00:00
}
2022-04-28 19:31:44 +00:00
__attribute__ ( ( nonnull ( 1 , 2 ) ) )
2017-09-08 08:02:43 +00:00
static NTSTATUS commit_batch_list_root ( _Requires_exclusive_lock_held_ ( _Curr_ - > tree_lock ) device_extension * Vcb , batch_root * br , PIRP Irp ) {
2022-09-28 16:08:10 +00:00
LIST_ENTRY items ;
2016-10-29 17:05:10 +00:00
LIST_ENTRY * le ;
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
TRACE ( " root: %I64x \n " , br - > r - > id ) ;
2017-09-08 08:02:43 +00:00
2022-09-28 16:08:10 +00:00
InitializeListHead ( & items ) ;
// move sub-lists into one big list
while ( ! IsListEmpty ( & br - > items_ind ) ) {
batch_item_ind * bii = CONTAINING_RECORD ( RemoveHeadList ( & br - > items_ind ) , batch_item_ind , list_entry ) ;
items . Blink - > Flink = bii - > items . Flink ;
bii - > items . Flink - > Blink = items . Blink ;
items . Blink = bii - > items . Blink ;
bii - > items . Blink - > Flink = & items ;
ExFreePool ( bii ) ;
}
le = items . Flink ;
while ( le ! = & items ) {
2016-10-29 17:05:10 +00:00
batch_item * bi = CONTAINING_RECORD ( le , batch_item , list_entry ) ;
2022-09-28 16:08:10 +00:00
LIST_ENTRY * le2 ;
2017-09-08 08:02:43 +00:00
traverse_ptr tp ;
2016-10-29 17:05:10 +00:00
KEY tree_end ;
2019-09-01 12:53:20 +00:00
bool no_end ;
2017-09-08 08:02:43 +00:00
tree_data * td , * listhead ;
2016-10-29 17:05:10 +00:00
int cmp ;
tree * t ;
2019-09-01 12:53:20 +00:00
bool ignore = false ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
TRACE ( " (%I64x,%x,%I64x) \n " , bi - > key . obj_id , bi - > key . obj_type , bi - > key . offset ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , br - > r , & tp , & bi - > key , true , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) { // FIXME - handle STATUS_NOT_FOUND
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 ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2022-04-28 19:31:44 +00:00
Status = find_tree_end ( tp . tree , & tree_end , & no_end ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " find_tree_end returned %08lx \n " , Status ) ;
return Status ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( bi - > operation = = Batch_DeleteInode ) {
if ( tp . item - > key . obj_id = = bi - > key . obj_id ) {
2019-09-01 12:53:20 +00:00
bool ended = false ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
td = tp . item ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! tp . item - > ignore ) {
2019-09-01 12:53:20 +00:00
tp . item - > ignore = true ;
2017-01-01 17:12:12 +00:00
tp . tree - > header . num_items - - ;
tp . tree - > size - = tp . item - > size + sizeof ( leaf_node ) ;
2019-09-01 12:53:20 +00:00
tp . tree - > write = 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
le2 = tp . item - > list_entry . Flink ;
while ( le2 ! = & tp . tree - > itemlist ) {
td = CONTAINING_RECORD ( le2 , tree_data , list_entry ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( td - > key . obj_id = = bi - > key . obj_id ) {
if ( ! td - > ignore ) {
2019-09-01 12:53:20 +00:00
td - > ignore = true ;
2017-01-01 17:12:12 +00:00
tp . tree - > header . num_items - - ;
tp . tree - > size - = td - > size + sizeof ( leaf_node ) ;
2019-09-01 12:53:20 +00:00
tp . tree - > write = true ;
2017-01-01 17:12:12 +00:00
}
} else {
2019-09-01 12:53:20 +00:00
ended = true ;
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 ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
while ( ! ended ) {
traverse_ptr next_tp ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
tp . item = td ;
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
break ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
tp = next_tp ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le2 = & tp . item - > list_entry ;
while ( le2 ! = & tp . tree - > itemlist ) {
td = CONTAINING_RECORD ( le2 , tree_data , list_entry ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( td - > key . obj_id = = bi - > key . obj_id ) {
if ( ! td - > ignore ) {
2019-09-01 12:53:20 +00:00
td - > ignore = true ;
2017-01-01 17:12:12 +00:00
tp . tree - > header . num_items - - ;
tp . tree - > size - = td - > size + sizeof ( leaf_node ) ;
2019-09-01 12:53:20 +00:00
tp . tree - > write = true ;
2017-01-01 17:12:12 +00:00
}
} else {
2019-09-01 12:53:20 +00:00
ended = true ;
2017-01-01 17:12:12 +00:00
break ;
}
2017-09-08 08:02:43 +00:00
le2 = le2 - > Flink ;
}
}
}
} else if ( bi - > operation = = Batch_DeleteExtentData ) {
if ( tp . item - > key . obj_id < bi - > key . obj_id | | ( tp . item - > key . obj_id = = bi - > key . obj_id & & tp . item - > key . obj_type < bi - > key . obj_type ) ) {
traverse_ptr tp2 ;
2019-09-01 12:53:20 +00:00
if ( find_next_item ( Vcb , & tp , & tp2 , false , Irp ) ) {
2017-09-08 08:02:43 +00:00
if ( tp2 . item - > key . obj_id = = bi - > key . obj_id & & tp2 . item - > key . obj_type = = bi - > key . obj_type ) {
tp = tp2 ;
2022-04-28 19:31:44 +00:00
Status = find_tree_end ( tp . tree , & tree_end , & no_end ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " find_tree_end returned %08lx \n " , Status ) ;
return Status ;
}
2017-09-08 08:02:43 +00:00
}
}
}
if ( tp . item - > key . obj_id = = bi - > key . obj_id & & tp . item - > key . obj_type = = bi - > key . obj_type ) {
2019-09-01 12:53:20 +00:00
bool ended = false ;
2017-09-08 08:02:43 +00:00
td = tp . item ;
if ( ! tp . item - > ignore ) {
2019-09-01 12:53:20 +00:00
tp . item - > ignore = true ;
2017-09-08 08:02:43 +00:00
tp . tree - > header . num_items - - ;
tp . tree - > size - = tp . item - > size + sizeof ( leaf_node ) ;
2019-09-01 12:53:20 +00:00
tp . tree - > write = true ;
2017-09-08 08:02:43 +00:00
}
le2 = tp . item - > list_entry . Flink ;
while ( le2 ! = & tp . tree - > itemlist ) {
td = CONTAINING_RECORD ( le2 , tree_data , list_entry ) ;
if ( td - > key . obj_id = = bi - > key . obj_id & & td - > key . obj_type = = bi - > key . obj_type ) {
if ( ! td - > ignore ) {
2019-09-01 12:53:20 +00:00
td - > ignore = true ;
2017-09-08 08:02:43 +00:00
tp . tree - > header . num_items - - ;
tp . tree - > size - = td - > size + sizeof ( leaf_node ) ;
2019-09-01 12:53:20 +00:00
tp . tree - > write = true ;
2017-09-08 08:02:43 +00:00
}
} else {
2019-09-01 12:53:20 +00:00
ended = true ;
2017-09-08 08:02:43 +00:00
break ;
}
le2 = le2 - > Flink ;
}
while ( ! ended ) {
traverse_ptr next_tp ;
tp . item = td ;
2019-09-01 12:53:20 +00:00
if ( ! find_next_item ( Vcb , & tp , & next_tp , false , Irp ) )
2017-09-08 08:02:43 +00:00
break ;
tp = next_tp ;
le2 = & tp . item - > list_entry ;
while ( le2 ! = & tp . tree - > itemlist ) {
td = CONTAINING_RECORD ( le2 , tree_data , list_entry ) ;
if ( td - > key . obj_id = = bi - > key . obj_id & & td - > key . obj_type = = bi - > key . obj_type ) {
if ( ! td - > ignore ) {
2019-09-01 12:53:20 +00:00
td - > ignore = true ;
2017-09-08 08:02:43 +00:00
tp . tree - > header . num_items - - ;
tp . tree - > size - = td - > size + sizeof ( leaf_node ) ;
2019-09-01 12:53:20 +00:00
tp . tree - > write = true ;
2017-09-08 08:02:43 +00:00
}
} else {
2019-09-01 12:53:20 +00:00
ended = true ;
2017-09-08 08:02:43 +00:00
break ;
}
le2 = le2 - > Flink ;
}
}
}
} else if ( bi - > operation = = Batch_DeleteFreeSpace ) {
if ( tp . item - > key . obj_id > = bi - > key . obj_id & & tp . item - > key . obj_id < bi - > key . obj_id + bi - > key . offset ) {
2019-09-01 12:53:20 +00:00
bool ended = false ;
2017-09-08 08:02:43 +00:00
td = tp . item ;
if ( ! tp . item - > ignore ) {
2019-09-01 12:53:20 +00:00
tp . item - > ignore = true ;
2017-09-08 08:02:43 +00:00
tp . tree - > header . num_items - - ;
tp . tree - > size - = tp . item - > size + sizeof ( leaf_node ) ;
2019-09-01 12:53:20 +00:00
tp . tree - > write = true ;
2017-09-08 08:02:43 +00:00
}
le2 = tp . item - > list_entry . Flink ;
while ( le2 ! = & tp . tree - > itemlist ) {
td = CONTAINING_RECORD ( le2 , tree_data , list_entry ) ;
if ( td - > key . obj_id > = bi - > key . obj_id & & td - > key . obj_id < bi - > key . obj_id + bi - > key . offset ) {
if ( ! td - > ignore ) {
2019-09-01 12:53:20 +00:00
td - > ignore = true ;
2017-09-08 08:02:43 +00:00
tp . tree - > header . num_items - - ;
tp . tree - > size - = td - > size + sizeof ( leaf_node ) ;
2019-09-01 12:53:20 +00:00
tp . tree - > write = true ;
2017-09-08 08:02:43 +00:00
}
} else {
2019-09-01 12:53:20 +00:00
ended = true ;
2017-09-08 08:02:43 +00:00
break ;
}
le2 = le2 - > Flink ;
}
while ( ! ended ) {
traverse_ptr next_tp ;
tp . item = td ;
2019-09-01 12:53:20 +00:00
if ( ! find_next_item ( Vcb , & tp , & next_tp , false , Irp ) )
2017-09-08 08:02:43 +00:00
break ;
tp = next_tp ;
le2 = & tp . item - > list_entry ;
while ( le2 ! = & tp . tree - > itemlist ) {
td = CONTAINING_RECORD ( le2 , tree_data , list_entry ) ;
if ( td - > key . obj_id > = bi - > key . obj_id & & td - > key . obj_id < bi - > key . obj_id + bi - > key . offset ) {
if ( ! td - > ignore ) {
2019-09-01 12:53:20 +00:00
td - > ignore = true ;
2017-09-08 08:02:43 +00:00
tp . tree - > header . num_items - - ;
tp . tree - > size - = td - > size + sizeof ( leaf_node ) ;
2019-09-01 12:53:20 +00:00
tp . tree - > write = true ;
2017-09-08 08:02:43 +00:00
}
} else {
2019-09-01 12:53:20 +00:00
ended = true ;
2017-09-08 08:02:43 +00:00
break ;
}
2017-01-01 17:12:12 +00:00
le2 = le2 - > Flink ;
}
}
}
} else {
2017-09-08 08:02:43 +00:00
if ( bi - > operation = = Batch_Delete | | bi - > operation = = Batch_DeleteDirItem | | bi - > operation = = Batch_DeleteInodeRef | |
bi - > operation = = Batch_DeleteInodeExtRef | | bi - > operation = = Batch_DeleteXattr )
2017-01-01 17:12:12 +00:00
td = NULL ;
else {
2016-10-29 17:05:10 +00:00
td = ExAllocateFromPagedLookasideList ( & Vcb - > tree_data_lookaside ) ;
if ( ! td ) {
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
2017-01-01 17:12:12 +00:00
td - > key = bi - > key ;
td - > size = bi - > datalen ;
td - > data = bi - > data ;
2019-09-01 12:53:20 +00:00
td - > ignore = false ;
td - > inserted = 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
cmp = keycmp ( bi - > key , tp . item - > key ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( cmp = = - 1 ) { // very first key in root
if ( td ) {
tree_data * paritem ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
InsertHeadList ( & tp . tree - > itemlist , & td - > list_entry ) ;
2016-10-29 17:05:10 +00:00
2017-01-01 17:12:12 +00:00
paritem = tp . tree - > paritem ;
while ( paritem ) {
if ( ! keycmp ( paritem - > key , tp . item - > key ) ) {
paritem - > key = bi - > key ;
} else
2016-10-29 17:05:10 +00:00
break ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
paritem = paritem - > treeholder . tree - > paritem ;
}
}
} else if ( cmp = = 0 ) { // item already exists
2017-09-08 08:02:43 +00:00
if ( tp . item - > ignore ) {
if ( td )
InsertHeadList ( tp . item - > list_entry . Blink , & td - > list_entry ) ;
} else {
2022-09-28 16:08:10 +00:00
Status = handle_batch_collision ( Vcb , bi , tp . tree , tp . item , td , & items , & ignore ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " handle_batch_collision returned %08lx \n " , Status ) ;
2022-04-28 19:34:48 +00:00
# ifdef _DEBUG
int3 ;
# endif
2017-09-08 08:02:43 +00:00
if ( td )
ExFreeToPagedLookasideList ( & Vcb - > tree_data_lookaside , td ) ;
return Status ;
}
}
2017-01-01 17:12:12 +00:00
} else if ( td ) {
InsertHeadList ( & tp . item - > list_entry , & td - > list_entry ) ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( bi - > operation = = Batch_DeleteInodeRef & & cmp ! = 0 & & Vcb - > superblock . incompat_flags & BTRFS_INCOMPAT_FLAGS_EXTENDED_IREF ) {
2022-09-28 16:08:10 +00:00
add_delete_inode_extref ( Vcb , bi , & items ) ;
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 ( ! ignore & & td ) {
tp . tree - > header . num_items + + ;
tp . tree - > size + = bi - > datalen + sizeof ( leaf_node ) ;
2019-09-01 12:53:20 +00:00
tp . tree - > write = true ;
2017-01-01 17:12:12 +00:00
2017-09-08 08:02:43 +00:00
listhead = td ;
} else
listhead = tp . item ;
while ( listhead - > list_entry . Blink ! = & tp . tree - > itemlist ) {
tree_data * prevtd = CONTAINING_RECORD ( listhead - > list_entry . Blink , tree_data , list_entry ) ;
if ( ! keycmp ( prevtd - > key , listhead - > key ) )
listhead = prevtd ;
else
break ;
2017-01-01 17:12:12 +00:00
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le2 = le - > Flink ;
2022-09-28 16:08:10 +00:00
while ( le2 ! = & items ) {
2017-01-01 17:12:12 +00:00
batch_item * bi2 = CONTAINING_RECORD ( le2 , batch_item , list_entry ) ;
2017-09-08 08:02:43 +00:00
if ( bi2 - > operation = = Batch_DeleteInode | | bi2 - > operation = = Batch_DeleteExtentData | | bi2 - > operation = = Batch_DeleteFreeSpace )
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
if ( no_end | | keycmp ( bi2 - > key , tree_end ) = = - 1 ) {
LIST_ENTRY * le3 ;
2019-09-01 12:53:20 +00:00
bool inserted = false ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
ignore = false ;
2017-09-08 08:02:43 +00:00
if ( bi2 - > operation = = Batch_Delete | | bi2 - > operation = = Batch_DeleteDirItem | | bi2 - > operation = = Batch_DeleteInodeRef | |
bi2 - > operation = = Batch_DeleteInodeExtRef | | bi2 - > operation = = Batch_DeleteXattr )
2017-01-01 17:12:12 +00:00
td = NULL ;
else {
td = ExAllocateFromPagedLookasideList ( & Vcb - > tree_data_lookaside ) ;
if ( ! td ) {
2016-10-29 17:05:10 +00:00
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
2017-01-01 17:12:12 +00:00
td - > key = bi2 - > key ;
td - > size = bi2 - > datalen ;
td - > data = bi2 - > data ;
2019-09-01 12:53:20 +00:00
td - > ignore = false ;
td - > inserted = true ;
2017-01-01 17:12:12 +00:00
}
2017-09-08 08:02:43 +00:00
le3 = & listhead - > list_entry ;
2017-01-01 17:12:12 +00:00
while ( le3 ! = & tp . tree - > itemlist ) {
tree_data * td2 = CONTAINING_RECORD ( le3 , tree_data , list_entry ) ;
2017-09-08 08:02:43 +00:00
cmp = keycmp ( bi2 - > key , td2 - > key ) ;
if ( cmp = = 0 ) {
if ( td2 - > ignore ) {
2017-01-01 17:12:12 +00:00
if ( td ) {
InsertHeadList ( le3 - > Blink , & td - > list_entry ) ;
2019-09-01 12:53:20 +00:00
inserted = true ;
2017-01-01 17:12:12 +00:00
} else if ( bi2 - > operation = = Batch_DeleteInodeRef & & Vcb - > superblock . incompat_flags & BTRFS_INCOMPAT_FLAGS_EXTENDED_IREF ) {
2022-09-28 16:08:10 +00:00
add_delete_inode_extref ( Vcb , bi2 , & items ) ;
2017-01-01 17:12:12 +00:00
}
2017-09-08 08:02:43 +00:00
} else {
2022-09-28 16:08:10 +00:00
Status = handle_batch_collision ( Vcb , bi2 , tp . tree , td2 , td , & items , & ignore ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " handle_batch_collision returned %08lx \n " , Status ) ;
2022-04-28 19:34:48 +00:00
# ifdef _DEBUG
int3 ;
# endif
2017-09-08 08:02:43 +00:00
return Status ;
}
2017-01-01 17:12:12 +00:00
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
inserted = true ;
2017-09-08 08:02:43 +00:00
break ;
} else if ( cmp = = - 1 ) {
if ( td ) {
InsertHeadList ( le3 - > Blink , & td - > list_entry ) ;
2019-09-01 12:53:20 +00:00
inserted = true ;
2017-09-08 08:02:43 +00:00
} else if ( bi2 - > operation = = Batch_DeleteInodeRef & & Vcb - > superblock . incompat_flags & BTRFS_INCOMPAT_FLAGS_EXTENDED_IREF ) {
2022-09-28 16:08:10 +00:00
add_delete_inode_extref ( Vcb , bi2 , & items ) ;
2017-09-08 08:02:43 +00:00
}
break ;
2017-01-01 17:12:12 +00:00
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le3 = le3 - > Flink ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( td ) {
if ( ! inserted )
InsertTailList ( & tp . tree - > itemlist , & td - > list_entry ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! ignore ) {
tp . tree - > header . num_items + + ;
tp . tree - > size + = bi2 - > datalen + sizeof ( leaf_node ) ;
2017-09-08 08:02:43 +00:00
listhead = td ;
2017-01-01 17:12:12 +00:00
}
} else if ( ! inserted & & bi2 - > operation = = Batch_DeleteInodeRef & & Vcb - > superblock . incompat_flags & BTRFS_INCOMPAT_FLAGS_EXTENDED_IREF ) {
2022-09-28 16:08:10 +00:00
add_delete_inode_extref ( Vcb , bi2 , & items ) ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
while ( listhead - > list_entry . Blink ! = & tp . tree - > itemlist ) {
tree_data * prevtd = CONTAINING_RECORD ( listhead - > list_entry . Blink , tree_data , list_entry ) ;
if ( ! keycmp ( prevtd - > key , listhead - > key ) )
listhead = prevtd ;
else
break ;
}
2017-01-01 17:12:12 +00:00
le = le2 ;
} else
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
2017-01-01 17:12:12 +00:00
t = tp . tree ;
while ( t ) {
if ( t - > paritem & & t - > paritem - > ignore ) {
2019-09-01 12:53:20 +00:00
t - > paritem - > ignore = false ;
2017-01-01 17:12:12 +00:00
t - > parent - > header . num_items + + ;
t - > parent - > size + = sizeof ( internal_node ) ;
}
2016-10-29 17:05:10 +00:00
2017-01-01 17:12:12 +00:00
t - > header . generation = Vcb - > superblock . generation ;
t = t - > 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
// FIXME - remove as we are going along
2022-09-28 16:08:10 +00:00
while ( ! IsListEmpty ( & items ) ) {
batch_item * bi = CONTAINING_RECORD ( RemoveHeadList ( & items ) , batch_item , list_entry ) ;
2017-09-08 08:02:43 +00:00
if ( ( bi - > operation = = Batch_DeleteDirItem | | bi - > operation = = Batch_DeleteInodeRef | |
bi - > operation = = Batch_DeleteInodeExtRef | | bi - > operation = = Batch_DeleteXattr ) & & bi - > data )
2017-01-01 17:12:12 +00:00
ExFreePool ( bi - > data ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ExFreeToPagedLookasideList ( & Vcb - > batch_item_lookaside , bi ) ;
}
2017-09-08 08:02:43 +00:00
return STATUS_SUCCESS ;
2016-10-29 17:05:10 +00:00
}
2022-04-28 19:31:44 +00:00
__attribute__ ( ( nonnull ( 1 , 2 ) ) )
2017-09-08 08:02:43 +00:00
NTSTATUS commit_batch_list ( _Requires_exclusive_lock_held_ ( _Curr_ - > tree_lock ) device_extension * Vcb , LIST_ENTRY * batchlist , PIRP Irp ) {
NTSTATUS Status ;
2016-10-29 17:05:10 +00:00
while ( ! IsListEmpty ( batchlist ) ) {
LIST_ENTRY * le = RemoveHeadList ( batchlist ) ;
batch_root * br2 = CONTAINING_RECORD ( le , batch_root , list_entry ) ;
2017-09-08 08:02:43 +00:00
Status = commit_batch_list_root ( Vcb , br2 , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " commit_batch_list_root returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
2016-10-29 17:05:10 +00:00
ExFreePool ( br2 ) ;
}
2017-09-08 08:02:43 +00:00
return STATUS_SUCCESS ;
2016-10-29 17:05:10 +00:00
}