2017-09-08 08:02:43 +00:00
/* Copyright (c) Mark Harmstone 2016-17
*
2016-05-05 17:26:47 +00:00
* This file is part of WinBtrfs .
2017-09-08 08:02:43 +00:00
*
2016-05-05 17:26:47 +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-05-05 17:26:47 +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-05-05 17:26:47 +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-05-05 17:26:47 +00:00
2016-10-29 17:05:10 +00:00
typedef struct {
2019-09-01 12:53:20 +00:00
uint8_t type ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
union {
EXTENT_DATA_REF edr ;
SHARED_DATA_REF sdr ;
TREE_BLOCK_REF tbr ;
SHARED_BLOCK_REF sbr ;
} ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
uint64_t hash ;
2016-10-29 17:05:10 +00:00
LIST_ENTRY list_entry ;
} extent_ref ;
2019-09-01 12:53:20 +00:00
uint64_t get_extent_data_ref_hash2 ( uint64_t root , uint64_t objid , uint64_t offset ) {
uint32_t high_crc = 0xffffffff , low_crc = 0xffffffff ;
2016-05-05 17:26:47 +00:00
2019-09-01 12:53:20 +00:00
high_crc = calc_crc32c ( high_crc , ( uint8_t * ) & root , sizeof ( uint64_t ) ) ;
low_crc = calc_crc32c ( low_crc , ( uint8_t * ) & objid , sizeof ( uint64_t ) ) ;
low_crc = calc_crc32c ( low_crc , ( uint8_t * ) & offset , sizeof ( uint64_t ) ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
return ( ( uint64_t ) high_crc < < 31 ) ^ ( uint64_t ) low_crc ;
2016-05-05 17:26:47 +00:00
}
2019-09-01 12:53:20 +00:00
static __inline uint64_t get_extent_data_ref_hash ( EXTENT_DATA_REF * edr ) {
2016-07-27 19:24:26 +00:00
return get_extent_data_ref_hash2 ( edr - > root , edr - > objid , edr - > offset ) ;
}
2019-09-01 12:53:20 +00:00
static uint64_t get_extent_hash ( uint8_t type , void * data ) {
2016-05-05 17:26:47 +00:00
if ( type = = TYPE_EXTENT_DATA_REF ) {
return get_extent_data_ref_hash ( ( EXTENT_DATA_REF * ) data ) ;
2016-10-29 17:05:10 +00:00
} else if ( type = = TYPE_SHARED_BLOCK_REF ) {
SHARED_BLOCK_REF * sbr = ( SHARED_BLOCK_REF * ) data ;
return sbr - > offset ;
} else if ( type = = TYPE_SHARED_DATA_REF ) {
SHARED_DATA_REF * sdr = ( SHARED_DATA_REF * ) data ;
return sdr - > offset ;
} else if ( type = = TYPE_TREE_BLOCK_REF ) {
TREE_BLOCK_REF * tbr = ( TREE_BLOCK_REF * ) data ;
return tbr - > offset ;
2016-05-05 17:26:47 +00:00
} else {
ERR ( " unhandled extent type %x \n " , type ) ;
return 0 ;
}
}
2016-10-29 17:05:10 +00:00
static void free_extent_refs ( LIST_ENTRY * extent_refs ) {
while ( ! IsListEmpty ( extent_refs ) ) {
LIST_ENTRY * le = RemoveHeadList ( extent_refs ) ;
extent_ref * er = CONTAINING_RECORD ( le , extent_ref , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ExFreePool ( er ) ;
}
}
2019-09-01 12:53:20 +00:00
static NTSTATUS add_shared_data_extent_ref ( LIST_ENTRY * extent_refs , uint64_t parent , uint32_t count ) {
2016-10-29 17:05:10 +00:00
extent_ref * er2 ;
LIST_ENTRY * le ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! IsListEmpty ( extent_refs ) ) {
le = extent_refs - > Flink ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
while ( le ! = extent_refs ) {
extent_ref * er = CONTAINING_RECORD ( le , extent_ref , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( er - > type = = TYPE_SHARED_DATA_REF & & er - > sdr . offset = = parent ) {
er - > sdr . count + = count ;
return STATUS_SUCCESS ;
}
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
er2 = ExAllocatePoolWithTag ( PagedPool , sizeof ( extent_ref ) , ALLOC_TAG ) ;
if ( ! er2 ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
er2 - > type = TYPE_SHARED_DATA_REF ;
er2 - > sdr . offset = parent ;
er2 - > sdr . count = count ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
InsertTailList ( extent_refs , & er2 - > list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
return STATUS_SUCCESS ;
}
2019-09-01 12:53:20 +00:00
static NTSTATUS add_shared_block_extent_ref ( LIST_ENTRY * extent_refs , uint64_t parent ) {
2016-10-29 17:05:10 +00:00
extent_ref * er2 ;
LIST_ENTRY * le ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! IsListEmpty ( extent_refs ) ) {
le = extent_refs - > Flink ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
while ( le ! = extent_refs ) {
extent_ref * er = CONTAINING_RECORD ( le , extent_ref , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( er - > type = = TYPE_SHARED_BLOCK_REF & & er - > sbr . offset = = parent )
return STATUS_SUCCESS ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = le - > Flink ;
2016-05-05 17:26:47 +00:00
}
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
er2 = ExAllocatePoolWithTag ( PagedPool , sizeof ( extent_ref ) , ALLOC_TAG ) ;
if ( ! er2 ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
er2 - > type = TYPE_SHARED_BLOCK_REF ;
er2 - > sbr . offset = parent ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
InsertTailList ( extent_refs , & er2 - > list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
return STATUS_SUCCESS ;
}
2019-09-01 12:53:20 +00:00
static NTSTATUS add_tree_block_extent_ref ( LIST_ENTRY * extent_refs , uint64_t root ) {
2016-10-29 17:05:10 +00:00
extent_ref * er2 ;
LIST_ENTRY * le ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! IsListEmpty ( extent_refs ) ) {
le = extent_refs - > Flink ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
while ( le ! = extent_refs ) {
extent_ref * er = CONTAINING_RECORD ( le , extent_ref , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( er - > type = = TYPE_TREE_BLOCK_REF & & er - > tbr . offset = = root )
return STATUS_SUCCESS ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = le - > Flink ;
2016-05-05 17:26:47 +00:00
}
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
er2 = ExAllocatePoolWithTag ( PagedPool , sizeof ( extent_ref ) , ALLOC_TAG ) ;
if ( ! er2 ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
er2 - > type = TYPE_TREE_BLOCK_REF ;
er2 - > tbr . offset = root ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
InsertTailList ( extent_refs , & er2 - > list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
return STATUS_SUCCESS ;
}
2016-05-05 17:26:47 +00:00
2017-09-08 08:02:43 +00:00
static void sort_extent_refs ( LIST_ENTRY * extent_refs ) {
LIST_ENTRY newlist ;
if ( IsListEmpty ( extent_refs ) )
return ;
// insertion sort
InitializeListHead ( & newlist ) ;
while ( ! IsListEmpty ( extent_refs ) ) {
extent_ref * er = CONTAINING_RECORD ( RemoveHeadList ( extent_refs ) , extent_ref , list_entry ) ;
LIST_ENTRY * le ;
2019-09-01 12:53:20 +00:00
bool inserted = false ;
2017-09-08 08:02:43 +00:00
le = newlist . Flink ;
while ( le ! = & newlist ) {
extent_ref * er2 = CONTAINING_RECORD ( le , extent_ref , list_entry ) ;
if ( er - > type < er2 - > type | | ( er - > type = = er2 - > type & & er - > hash > er2 - > hash ) ) {
InsertHeadList ( le - > Blink , & er - > list_entry ) ;
2019-09-01 12:53:20 +00:00
inserted = true ;
2017-09-08 08:02:43 +00:00
break ;
}
le = le - > Flink ;
}
if ( ! inserted )
InsertTailList ( & newlist , & er - > list_entry ) ;
}
newlist . Flink - > Blink = extent_refs ;
newlist . Blink - > Flink = extent_refs ;
extent_refs - > Flink = newlist . Flink ;
extent_refs - > Blink = newlist . Blink ;
}
2019-09-01 12:53:20 +00:00
static NTSTATUS construct_extent_item ( device_extension * Vcb , uint64_t address , uint64_t size , uint64_t flags , LIST_ENTRY * extent_refs ,
KEY * firstitem , uint8_t level , PIRP Irp ) {
2017-09-08 08:02:43 +00:00
NTSTATUS Status ;
2016-10-29 17:05:10 +00:00
LIST_ENTRY * le , * next_le ;
2019-09-01 12:53:20 +00:00
uint64_t refcount ;
uint16_t inline_len ;
bool all_inline = true ;
2017-09-08 08:02:43 +00:00
extent_ref * first_noninline = NULL ;
2016-10-29 17:05:10 +00:00
EXTENT_ITEM * ei ;
2019-09-01 12:53:20 +00:00
uint8_t * siptr ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
// FIXME - write skinny extents if is tree and incompat flag set
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( IsListEmpty ( extent_refs ) ) {
WARN ( " no extent refs found \n " ) ;
2016-05-05 17:26:47 +00:00
return STATUS_SUCCESS ;
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
refcount = 0 ;
inline_len = sizeof ( EXTENT_ITEM ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( flags & EXTENT_ITEM_TREE_BLOCK )
inline_len + = sizeof ( EXTENT_ITEM2 ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = extent_refs - > Flink ;
while ( le ! = extent_refs ) {
extent_ref * er = CONTAINING_RECORD ( le , extent_ref , list_entry ) ;
2019-09-01 12:53:20 +00:00
uint64_t rc ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
next_le = le - > Flink ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
rc = get_extent_data_refcount ( er - > type , & er - > edr ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( rc = = 0 ) {
RemoveEntryList ( & er - > list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ExFreePool ( er ) ;
} else {
2019-09-01 12:53:20 +00:00
uint16_t extlen = get_extent_data_len ( er - > type ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
refcount + = rc ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
er - > hash = get_extent_hash ( er - > type , & er - > edr ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( all_inline ) {
2019-09-01 12:53:20 +00:00
if ( ( uint16_t ) ( inline_len + 1 + extlen ) > Vcb - > superblock . node_size > > 2 ) {
all_inline = false ;
2016-10-29 17:05:10 +00:00
first_noninline = er ;
} else
inline_len + = extlen + 1 ;
}
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = next_le ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ei = ExAllocatePoolWithTag ( PagedPool , inline_len , ALLOC_TAG ) ;
if ( ! ei ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ei - > refcount = refcount ;
ei - > generation = Vcb - > superblock . generation ;
ei - > flags = flags ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( flags & EXTENT_ITEM_TREE_BLOCK ) {
EXTENT_ITEM2 * ei2 = ( EXTENT_ITEM2 * ) & ei [ 1 ] ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( firstitem ) {
ei2 - > firstitem . obj_id = firstitem - > obj_id ;
ei2 - > firstitem . obj_type = firstitem - > obj_type ;
ei2 - > firstitem . offset = firstitem - > offset ;
} else {
ei2 - > firstitem . obj_id = 0 ;
ei2 - > firstitem . obj_type = 0 ;
ei2 - > firstitem . offset = 0 ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ei2 - > level = level ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
siptr = ( uint8_t * ) & ei2 [ 1 ] ;
2016-10-29 17:05:10 +00:00
} else
2019-09-01 12:53:20 +00:00
siptr = ( uint8_t * ) & ei [ 1 ] ;
2017-09-08 08:02:43 +00:00
sort_extent_refs ( extent_refs ) ;
2016-10-29 17:05:10 +00:00
le = extent_refs - > Flink ;
while ( le ! = extent_refs ) {
extent_ref * er = CONTAINING_RECORD ( le , extent_ref , list_entry ) ;
ULONG extlen = get_extent_data_len ( er - > type ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! all_inline & & er = = first_noninline )
break ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
* siptr = er - > type ;
siptr + + ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( extlen > 0 ) {
RtlCopyMemory ( siptr , & er - > edr , extlen ) ;
siptr + = extlen ;
}
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
Status = insert_tree_item ( Vcb , Vcb - > extent_root , address , TYPE_EXTENT_ITEM , size , ei , inline_len , NULL , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
ExFreePool ( ei ) ;
2017-09-08 08:02:43 +00:00
return Status ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! all_inline ) {
le = & first_noninline - > list_entry ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
while ( le ! = extent_refs ) {
extent_ref * er = CONTAINING_RECORD ( le , extent_ref , list_entry ) ;
2019-09-01 12:53:20 +00:00
uint16_t len ;
uint8_t * data ;
2017-09-08 08:02:43 +00:00
if ( er - > type = = TYPE_EXTENT_DATA_REF ) {
len = sizeof ( EXTENT_DATA_REF ) ;
2016-10-29 17:05:10 +00:00
data = ExAllocatePoolWithTag ( PagedPool , len , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! data ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
RtlCopyMemory ( data , & er - > edr , len ) ;
2017-09-08 08:02:43 +00:00
} else if ( er - > type = = TYPE_SHARED_DATA_REF ) {
2019-09-01 12:53:20 +00:00
len = sizeof ( uint32_t ) ;
2017-09-08 08:02:43 +00:00
data = ExAllocatePoolWithTag ( PagedPool , len , ALLOC_TAG ) ;
if ( ! data ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2019-09-01 12:53:20 +00:00
* ( ( uint32_t * ) data ) = er - > sdr . count ;
2017-09-08 08:02:43 +00:00
} else {
len = 0 ;
2016-10-29 17:05:10 +00:00
data = NULL ;
}
2017-09-08 08:02:43 +00:00
Status = insert_tree_item ( Vcb , Vcb - > extent_root , address , er - > type , er - > hash , data , len , NULL , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
if ( data ) ExFreePool ( data ) ;
return Status ;
}
2016-10-29 17:05:10 +00:00
le = le - > Flink ;
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
return STATUS_SUCCESS ;
}
2019-09-01 12:53:20 +00:00
static NTSTATUS convert_old_extent ( device_extension * Vcb , uint64_t address , bool tree , KEY * firstitem , uint8_t level , PIRP Irp ) {
2016-10-29 17:05:10 +00:00
NTSTATUS Status ;
KEY searchkey ;
traverse_ptr tp , next_tp ;
LIST_ENTRY extent_refs ;
2019-09-01 12:53:20 +00:00
uint64_t size ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
InitializeListHead ( & extent_refs ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
searchkey . obj_id = address ;
searchkey . obj_type = TYPE_EXTENT_ITEM ;
searchkey . offset = 0xffffffffffffffff ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > extent_root , & tp , & searchkey , false , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " find_item returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( tp . item - > key . obj_id ! = searchkey . obj_id | | tp . item - > key . obj_type ! = searchkey . obj_type ) {
2019-09-01 12:53:20 +00:00
ERR ( " old-style extent %I64x not found \n " , address ) ;
2016-10-29 17:05:10 +00:00
return STATUS_INTERNAL_ERROR ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
size = tp . item - > key . offset ;
2017-09-08 08:02:43 +00:00
Status = delete_tree_item ( Vcb , & tp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
2019-09-01 12:53:20 +00:00
while ( find_next_item ( Vcb , & tp , & next_tp , false , Irp ) ) {
2016-10-29 17:05:10 +00:00
tp = next_tp ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( tp . item - > key . obj_id = = address & & tp . item - > key . obj_type = = TYPE_EXTENT_REF_V0 & & tp . item - > size > = sizeof ( EXTENT_REF_V0 ) ) {
EXTENT_REF_V0 * erv0 = ( EXTENT_REF_V0 * ) tp . item - > data ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( tree ) {
if ( tp . item - > key . offset = = tp . item - > key . obj_id ) { // top of the tree
Status = add_tree_block_extent_ref ( & extent_refs , erv0 - > root ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " add_tree_block_extent_ref returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
goto end ;
}
} else {
Status = add_shared_block_extent_ref ( & extent_refs , tp . item - > key . offset ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " add_shared_block_extent_ref returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
goto end ;
}
}
} else {
Status = add_shared_data_extent_ref ( & extent_refs , tp . item - > key . offset , erv0 - > count ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " add_shared_data_extent_ref returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
goto end ;
}
}
2017-09-08 08:02:43 +00:00
Status = delete_tree_item ( Vcb , & tp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
goto end ;
}
2016-10-29 17:05:10 +00:00
}
if ( tp . item - > key . obj_id > address | | tp . item - > key . obj_type > TYPE_EXTENT_REF_V0 )
break ;
}
Status = construct_extent_item ( Vcb , address , size , tree ? ( EXTENT_ITEM_TREE_BLOCK | EXTENT_ITEM_SHARED_BACKREFS ) : EXTENT_ITEM_DATA ,
2017-09-08 08:02:43 +00:00
& extent_refs , firstitem , level , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) )
2020-04-23 02:38:57 +00:00
ERR ( " construct_extent_item returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
end :
free_extent_refs ( & extent_refs ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
return Status ;
}
2019-09-01 12:53:20 +00:00
NTSTATUS increase_extent_refcount ( device_extension * Vcb , uint64_t address , uint64_t size , uint8_t type , void * data , KEY * firstitem , uint8_t level , PIRP Irp ) {
2016-10-29 17:05:10 +00:00
NTSTATUS Status ;
KEY searchkey ;
traverse_ptr tp ;
2017-09-08 08:02:43 +00:00
ULONG len , max_extent_item_size ;
2019-09-01 12:53:20 +00:00
uint16_t datalen = get_extent_data_len ( type ) ;
2016-10-29 17:05:10 +00:00
EXTENT_ITEM * ei ;
2019-09-01 12:53:20 +00:00
uint8_t * ptr ;
uint64_t inline_rc , offset ;
uint8_t * data2 ;
2016-10-29 17:05:10 +00:00
EXTENT_ITEM * newei ;
2019-09-01 12:53:20 +00:00
bool skinny ;
bool is_tree = type = = TYPE_TREE_BLOCK_REF | | type = = TYPE_SHARED_BLOCK_REF ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( datalen = = 0 ) {
ERR ( " unrecognized extent type %x \n " , type ) ;
return STATUS_INTERNAL_ERROR ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
searchkey . obj_id = address ;
searchkey . obj_type = Vcb - > superblock . incompat_flags & BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA ? TYPE_METADATA_ITEM : TYPE_EXTENT_ITEM ;
searchkey . offset = 0xffffffffffffffff ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > extent_root , & tp , & searchkey , false , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - find_item returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
// If entry doesn't exist yet, create new inline extent item
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( tp . item - > key . obj_id ! = searchkey . obj_id | | ( tp . item - > key . obj_type ! = TYPE_EXTENT_ITEM & & tp . item - > key . obj_type ! = TYPE_METADATA_ITEM ) ) {
2019-09-01 12:53:20 +00:00
uint16_t eisize ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
eisize = sizeof ( EXTENT_ITEM ) ;
2017-01-01 17:12:12 +00:00
if ( is_tree & & ! ( Vcb - > superblock . incompat_flags & BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA ) ) eisize + = sizeof ( EXTENT_ITEM2 ) ;
2019-09-01 12:53:20 +00:00
eisize + = sizeof ( uint8_t ) ;
2016-10-29 17:05:10 +00:00
eisize + = datalen ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ei = ExAllocatePoolWithTag ( PagedPool , eisize , ALLOC_TAG ) ;
if ( ! ei ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ei - > refcount = get_extent_data_refcount ( type , data ) ;
ei - > generation = Vcb - > superblock . generation ;
ei - > flags = is_tree ? EXTENT_ITEM_TREE_BLOCK : EXTENT_ITEM_DATA ;
2019-09-01 12:53:20 +00:00
ptr = ( uint8_t * ) & ei [ 1 ] ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( is_tree & & ! ( Vcb - > superblock . incompat_flags & BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA ) ) {
EXTENT_ITEM2 * ei2 = ( EXTENT_ITEM2 * ) ptr ;
ei2 - > firstitem = * firstitem ;
ei2 - > level = level ;
2019-09-01 12:53:20 +00:00
ptr = ( uint8_t * ) & ei2 [ 1 ] ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
* ptr = type ;
RtlCopyMemory ( ptr + 1 , data , datalen ) ;
2017-09-08 08:02:43 +00:00
if ( Vcb - > superblock . incompat_flags & BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA & & is_tree )
Status = insert_tree_item ( Vcb , Vcb - > extent_root , address , TYPE_METADATA_ITEM , level , ei , eisize , NULL , Irp ) ;
else
Status = insert_tree_item ( Vcb , Vcb - > extent_root , address , TYPE_EXTENT_ITEM , size , ei , eisize , NULL , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
2016-10-29 17:05:10 +00:00
}
return STATUS_SUCCESS ;
} else if ( tp . item - > key . obj_id = = address & & tp . item - > key . obj_type = = TYPE_EXTENT_ITEM & & tp . item - > key . offset ! = size ) {
2019-09-01 12:53:20 +00:00
ERR ( " extent %I64x exists, but with size %I64x rather than %I64x expected \n " , tp . item - > key . obj_id , tp . item - > key . offset , size ) ;
2016-10-29 17:05:10 +00:00
return STATUS_INTERNAL_ERROR ;
}
skinny = tp . item - > key . obj_type = = TYPE_METADATA_ITEM ;
if ( tp . item - > size = = sizeof ( EXTENT_ITEM_V0 ) & & ! skinny ) {
2017-09-08 08:02:43 +00:00
Status = convert_old_extent ( Vcb , address , is_tree , firstitem , level , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " convert_old_extent returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
return increase_extent_refcount ( Vcb , address , size , type , data , firstitem , level , Irp ) ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( tp . item - > size < sizeof ( EXTENT_ITEM ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " (%I64x,%x,%I64x) was %u bytes, expected at least %Iu \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , tp . item - > size , sizeof ( EXTENT_ITEM ) ) ;
2016-10-29 17:05:10 +00:00
return STATUS_INTERNAL_ERROR ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ei = ( EXTENT_ITEM * ) tp . item - > data ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
len = tp . item - > size - sizeof ( EXTENT_ITEM ) ;
2019-09-01 12:53:20 +00:00
ptr = ( uint8_t * ) & ei [ 1 ] ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ei - > flags & EXTENT_ITEM_TREE_BLOCK & & ! skinny ) {
if ( tp . item - > size < sizeof ( EXTENT_ITEM ) + sizeof ( EXTENT_ITEM2 ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " (%I64x,%x,%I64x) was %u bytes, expected at least %Iu \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , tp . item - > size , sizeof ( EXTENT_ITEM ) + sizeof ( EXTENT_ITEM2 ) ) ;
2016-10-29 17:05:10 +00:00
return STATUS_INTERNAL_ERROR ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
len - = sizeof ( EXTENT_ITEM2 ) ;
ptr + = sizeof ( EXTENT_ITEM2 ) ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
inline_rc = 0 ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
// Loop through existing inline extent entries
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
while ( len > 0 ) {
2019-09-01 12:53:20 +00:00
uint8_t secttype = * ptr ;
2016-10-29 17:05:10 +00:00
ULONG sectlen = get_extent_data_len ( secttype ) ;
2019-09-01 12:53:20 +00:00
uint64_t sectcount = get_extent_data_refcount ( secttype , ptr + sizeof ( uint8_t ) ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
len - - ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( sectlen > len ) {
2020-04-23 02:38:57 +00:00
ERR ( " (%I64x,%x,%I64x): %lx bytes left, expecting at least %lx \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , len , sectlen ) ;
2016-10-29 17:05:10 +00:00
return STATUS_INTERNAL_ERROR ;
}
if ( sectlen = = 0 ) {
2019-09-01 12:53:20 +00:00
ERR ( " (%I64x,%x,%I64x): unrecognized extent type %x \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , secttype ) ;
2016-10-29 17:05:10 +00:00
return STATUS_INTERNAL_ERROR ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
// If inline extent already present, increase refcount and return
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( secttype = = type ) {
if ( type = = TYPE_EXTENT_DATA_REF ) {
2019-09-01 12:53:20 +00:00
EXTENT_DATA_REF * sectedr = ( EXTENT_DATA_REF * ) ( ptr + sizeof ( uint8_t ) ) ;
2016-05-05 17:26:47 +00:00
EXTENT_DATA_REF * edr = ( EXTENT_DATA_REF * ) data ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( sectedr - > root = = edr - > root & & sectedr - > objid = = edr - > objid & & sectedr - > offset = = edr - > offset ) {
2019-09-01 12:53:20 +00:00
uint32_t rc = get_extent_data_refcount ( type , data ) ;
2016-05-05 17:26:47 +00:00
EXTENT_DATA_REF * sectedr2 ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
newei = ExAllocatePoolWithTag ( PagedPool , tp . item - > size , ALLOC_TAG ) ;
if ( ! newei ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
RtlCopyMemory ( newei , tp . item - > data , tp . item - > size ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
newei - > refcount + = rc ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
sectedr2 = ( EXTENT_DATA_REF * ) ( ( uint8_t * ) newei + ( ( uint8_t * ) sectedr - tp . item - > data ) ) ;
2016-05-05 17:26:47 +00:00
sectedr2 - > count + = rc ;
2017-09-08 08:02:43 +00:00
Status = delete_tree_item ( Vcb , & tp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
Status = insert_tree_item ( Vcb , Vcb - > extent_root , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , newei , tp . item - > size , NULL , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
return STATUS_SUCCESS ;
}
} else if ( type = = TYPE_TREE_BLOCK_REF ) {
2019-09-01 12:53:20 +00:00
TREE_BLOCK_REF * secttbr = ( TREE_BLOCK_REF * ) ( ptr + sizeof ( uint8_t ) ) ;
2016-10-29 17:05:10 +00:00
TREE_BLOCK_REF * tbr = ( TREE_BLOCK_REF * ) data ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( secttbr - > offset = = tbr - > offset ) {
TRACE ( " trying to increase refcount of non-shared tree extent \n " ) ;
return STATUS_SUCCESS ;
}
} else if ( type = = TYPE_SHARED_BLOCK_REF ) {
2019-09-01 12:53:20 +00:00
SHARED_BLOCK_REF * sectsbr = ( SHARED_BLOCK_REF * ) ( ptr + sizeof ( uint8_t ) ) ;
2016-10-29 17:05:10 +00:00
SHARED_BLOCK_REF * sbr = ( SHARED_BLOCK_REF * ) data ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( sectsbr - > offset = = sbr - > offset )
return STATUS_SUCCESS ;
} else if ( type = = TYPE_SHARED_DATA_REF ) {
2019-09-01 12:53:20 +00:00
SHARED_DATA_REF * sectsdr = ( SHARED_DATA_REF * ) ( ptr + sizeof ( uint8_t ) ) ;
2016-10-29 17:05:10 +00:00
SHARED_DATA_REF * sdr = ( SHARED_DATA_REF * ) data ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( sectsdr - > offset = = sdr - > offset ) {
2019-09-01 12:53:20 +00:00
uint32_t rc = get_extent_data_refcount ( type , data ) ;
2016-10-29 17:05:10 +00:00
SHARED_DATA_REF * sectsdr2 ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
newei = ExAllocatePoolWithTag ( PagedPool , tp . item - > size , ALLOC_TAG ) ;
if ( ! newei ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
RtlCopyMemory ( newei , tp . item - > data , tp . item - > size ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
newei - > refcount + = rc ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
sectsdr2 = ( SHARED_DATA_REF * ) ( ( uint8_t * ) newei + ( ( uint8_t * ) sectsdr - tp . item - > data ) ) ;
2016-10-29 17:05:10 +00:00
sectsdr2 - > count + = rc ;
2017-09-08 08:02:43 +00:00
Status = delete_tree_item ( Vcb , & tp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
Status = insert_tree_item ( Vcb , Vcb - > extent_root , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , newei , tp . item - > size , NULL , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
return STATUS_SUCCESS ;
}
2016-05-05 17:26:47 +00:00
} else {
ERR ( " unhandled extent type %x \n " , type ) ;
return STATUS_INTERNAL_ERROR ;
}
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
len - = sectlen ;
2019-09-01 12:53:20 +00:00
ptr + = sizeof ( uint8_t ) + sectlen ;
2016-05-05 17:26:47 +00:00
inline_rc + = sectcount ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
offset = get_extent_hash ( type , data ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
max_extent_item_size = ( Vcb - > superblock . node_size > > 4 ) - sizeof ( leaf_node ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
// If we can, add entry as inline extent item
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
if ( inline_rc = = ei - > refcount & & tp . item - > size + sizeof ( uint8_t ) + datalen < max_extent_item_size ) {
2016-05-05 17:26:47 +00:00
len = tp . item - > size - sizeof ( EXTENT_ITEM ) ;
2019-09-01 12:53:20 +00:00
ptr = ( uint8_t * ) & ei [ 1 ] ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ei - > flags & EXTENT_ITEM_TREE_BLOCK & & ! skinny ) {
2016-05-05 17:26:47 +00:00
len - = sizeof ( EXTENT_ITEM2 ) ;
ptr + = sizeof ( EXTENT_ITEM2 ) ;
}
2017-09-08 08:02:43 +00:00
// Confusingly, it appears that references are sorted forward by type (i.e. EXTENT_DATA_REFs before
// SHARED_DATA_REFs), but then backwards by hash...
2016-05-05 17:26:47 +00:00
while ( len > 0 ) {
2019-09-01 12:53:20 +00:00
uint8_t secttype = * ptr ;
2016-05-05 17:26:47 +00:00
ULONG sectlen = get_extent_data_len ( secttype ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( secttype > type )
break ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( secttype = = type ) {
2019-09-01 12:53:20 +00:00
uint64_t sectoff = get_extent_hash ( secttype , ptr + 1 ) ;
2017-09-08 08:02:43 +00:00
if ( sectoff < offset )
2016-05-05 17:26:47 +00:00
break ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
len - = sectlen + sizeof ( uint8_t ) ;
ptr + = sizeof ( uint8_t ) + sectlen ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
newei = ExAllocatePoolWithTag ( PagedPool , tp . item - > size + sizeof ( uint8_t ) + datalen , ALLOC_TAG ) ;
2016-05-05 17:26:47 +00:00
RtlCopyMemory ( newei , tp . item - > data , ptr - tp . item - > data ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
newei - > refcount + = get_extent_data_refcount ( type , data ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( len > 0 )
2019-09-01 12:53:20 +00:00
RtlCopyMemory ( ( uint8_t * ) newei + ( ptr - tp . item - > data ) + sizeof ( uint8_t ) + datalen , ptr , len ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
ptr = ( ptr - tp . item - > data ) + ( uint8_t * ) newei ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
* ptr = type ;
RtlCopyMemory ( ptr + 1 , data , datalen ) ;
2017-09-08 08:02:43 +00:00
Status = delete_tree_item ( Vcb , & tp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = insert_tree_item ( Vcb , Vcb - > extent_root , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , newei , tp . item - > size + sizeof ( uint8_t ) + datalen , NULL , Irp ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
2016-05-05 17:26:47 +00:00
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
// Look for existing non-inline entry, and increase refcount if found
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( inline_rc ! = ei - > refcount ) {
traverse_ptr tp2 ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
searchkey . obj_id = address ;
searchkey . obj_type = type ;
searchkey . offset = offset ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > extent_root , & tp2 , & searchkey , false , Irp ) ;
2016-05-05 17:26:47 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - find_item returned %08lx \n " , Status ) ;
2016-05-05 17:26:47 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! keycmp ( tp2 . item - > key , searchkey ) ) {
2019-09-01 12:53:20 +00:00
if ( type = = TYPE_SHARED_DATA_REF & & tp2 . item - > size < sizeof ( uint32_t ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " (%I64x,%x,%I64x) was %x bytes, expecting %Ix \n " , tp2 . item - > key . obj_id , tp2 . item - > key . obj_type , tp2 . item - > key . offset , tp2 . item - > size , sizeof ( uint32_t ) ) ;
2017-09-08 08:02:43 +00:00
return STATUS_INTERNAL_ERROR ;
} else if ( type ! = TYPE_SHARED_DATA_REF & & tp2 . item - > size < datalen ) {
2019-09-01 12:53:20 +00:00
ERR ( " (%I64x,%x,%I64x) was %x bytes, expecting %x \n " , tp2 . item - > key . obj_id , tp2 . item - > key . obj_type , tp2 . item - > key . offset , tp2 . item - > size , datalen ) ;
2016-05-05 17:26:47 +00:00
return STATUS_INTERNAL_ERROR ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
data2 = ExAllocatePoolWithTag ( PagedPool , tp2 . item - > size , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
if ( ! data2 ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2016-05-05 17:26:47 +00:00
RtlCopyMemory ( data2 , tp2 . item - > data , tp2 . item - > size ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( type = = TYPE_EXTENT_DATA_REF ) {
EXTENT_DATA_REF * edr = ( EXTENT_DATA_REF * ) data2 ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
edr - > count + = get_extent_data_refcount ( type , data ) ;
} else if ( type = = TYPE_TREE_BLOCK_REF ) {
2016-10-29 17:05:10 +00:00
TRACE ( " trying to increase refcount of non-shared tree extent \n " ) ;
return STATUS_SUCCESS ;
} else if ( type = = TYPE_SHARED_BLOCK_REF )
return STATUS_SUCCESS ;
else if ( type = = TYPE_SHARED_DATA_REF ) {
2019-09-01 12:53:20 +00:00
uint32_t * sdr = ( uint32_t * ) data2 ;
2017-09-08 08:02:43 +00:00
* sdr + = get_extent_data_refcount ( type , data ) ;
2016-05-05 17:26:47 +00:00
} else {
ERR ( " unhandled extent type %x \n " , type ) ;
return STATUS_INTERNAL_ERROR ;
}
2017-09-08 08:02:43 +00:00
Status = delete_tree_item ( Vcb , & tp2 ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
Status = insert_tree_item ( Vcb , Vcb - > extent_root , tp2 . item - > key . obj_id , tp2 . item - > key . obj_type , tp2 . item - > key . offset , data2 , tp2 . item - > size , NULL , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
2016-05-05 17:26:47 +00:00
newei = ExAllocatePoolWithTag ( PagedPool , tp . item - > size , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
if ( ! newei ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2016-05-05 17:26:47 +00:00
RtlCopyMemory ( newei , tp . item - > data , tp . item - > size ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
newei - > refcount + = get_extent_data_refcount ( type , data ) ;
2017-09-08 08:02:43 +00:00
Status = delete_tree_item ( Vcb , & tp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
Status = insert_tree_item ( Vcb , Vcb - > extent_root , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , newei , tp . item - > size , NULL , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
2016-05-05 17:26:47 +00:00
return STATUS_SUCCESS ;
}
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
// Otherwise, add new non-inline entry
2017-09-08 08:02:43 +00:00
if ( type = = TYPE_SHARED_DATA_REF ) {
SHARED_DATA_REF * sdr = ( SHARED_DATA_REF * ) data ;
2019-09-01 12:53:20 +00:00
data2 = ExAllocatePoolWithTag ( PagedPool , sizeof ( uint32_t ) , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
if ( ! data2 ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2019-09-01 12:53:20 +00:00
datalen = sizeof ( uint32_t ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
* ( ( uint32_t * ) data2 ) = sdr - > count ;
2017-09-08 08:02:43 +00:00
} else if ( type = = TYPE_TREE_BLOCK_REF | | type = = TYPE_SHARED_BLOCK_REF ) {
data2 = NULL ;
datalen = 0 ;
} else {
data2 = ExAllocatePoolWithTag ( PagedPool , datalen , ALLOC_TAG ) ;
if ( ! data2 ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
RtlCopyMemory ( data2 , data , datalen ) ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
Status = insert_tree_item ( Vcb , Vcb - > extent_root , address , type , offset , data2 , datalen , NULL , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
2016-05-05 17:26:47 +00:00
newei = ExAllocatePoolWithTag ( PagedPool , tp . item - > size , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
if ( ! newei ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2016-05-05 17:26:47 +00:00
RtlCopyMemory ( newei , tp . item - > data , tp . item - > size ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
newei - > refcount + = get_extent_data_refcount ( type , data ) ;
2017-09-08 08:02:43 +00:00
Status = delete_tree_item ( Vcb , & tp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
Status = insert_tree_item ( Vcb , Vcb - > extent_root , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , newei , tp . item - > size , NULL , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
2016-05-05 17:26:47 +00:00
return STATUS_SUCCESS ;
}
2019-09-01 12:53:20 +00:00
NTSTATUS increase_extent_refcount_data ( device_extension * Vcb , uint64_t address , uint64_t size , uint64_t root , uint64_t inode , uint64_t offset , uint32_t refcount , PIRP Irp ) {
2016-05-05 17:26:47 +00:00
EXTENT_DATA_REF edr ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
edr . root = root ;
2016-05-05 17:26:47 +00:00
edr . objid = inode ;
edr . offset = offset ;
edr . count = refcount ;
2017-09-08 08:02:43 +00:00
return increase_extent_refcount ( Vcb , address , size , TYPE_EXTENT_DATA_REF , & edr , NULL , 0 , Irp ) ;
2016-05-05 17:26:47 +00:00
}
2019-09-01 12:53:20 +00:00
NTSTATUS decrease_extent_refcount ( device_extension * Vcb , uint64_t address , uint64_t size , uint8_t type , void * data , KEY * firstitem ,
uint8_t level , uint64_t parent , bool superseded , PIRP Irp ) {
2016-05-05 17:26:47 +00:00
KEY searchkey ;
NTSTATUS Status ;
traverse_ptr tp , tp2 ;
EXTENT_ITEM * ei ;
ULONG len ;
2019-09-01 12:53:20 +00:00
uint64_t inline_rc ;
uint8_t * ptr ;
uint32_t rc = data ? get_extent_data_refcount ( type , data ) : 1 ;
2016-05-05 17:26:47 +00:00
ULONG datalen = get_extent_data_len ( type ) ;
2019-09-01 12:53:20 +00:00
bool is_tree = ( type = = TYPE_TREE_BLOCK_REF | | type = = TYPE_SHARED_BLOCK_REF ) , skinny = false ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( is_tree & & Vcb - > superblock . incompat_flags & BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA ) {
searchkey . obj_id = address ;
searchkey . obj_type = TYPE_METADATA_ITEM ;
searchkey . offset = 0xffffffffffffffff ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > extent_root , & tp , & searchkey , false , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - find_item returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( tp . item - > key . obj_id = = searchkey . obj_id & & tp . item - > key . obj_type = = searchkey . obj_type )
2019-09-01 12:53:20 +00:00
skinny = true ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! skinny ) {
searchkey . obj_id = address ;
searchkey . obj_type = TYPE_EXTENT_ITEM ;
searchkey . offset = 0xffffffffffffffff ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > extent_root , & tp , & searchkey , false , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - find_item returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( tp . item - > key . obj_id ! = searchkey . obj_id | | tp . item - > key . obj_type ! = searchkey . obj_type ) {
2019-09-01 12:53:20 +00:00
ERR ( " could not find EXTENT_ITEM for address %I64x \n " , address ) ;
2016-10-29 17:05:10 +00:00
return STATUS_INTERNAL_ERROR ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( tp . item - > key . offset ! = size ) {
2019-09-01 12:53:20 +00:00
ERR ( " extent %I64x had length %I64x, not %I64x as expected \n " , address , tp . item - > key . offset , size ) ;
2016-07-27 19:24:26 +00:00
return STATUS_INTERNAL_ERROR ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( tp . item - > size = = sizeof ( EXTENT_ITEM_V0 ) ) {
2017-09-08 08:02:43 +00:00
Status = convert_old_extent ( Vcb , address , is_tree , firstitem , level , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " convert_old_extent returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
return decrease_extent_refcount ( Vcb , address , size , type , data , firstitem , level , parent , superseded , Irp ) ;
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 ( tp . item - > size < sizeof ( EXTENT_ITEM ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " (%I64x,%x,%I64x) was %u bytes, expected at least %Iu \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , tp . item - > size , sizeof ( EXTENT_ITEM ) ) ;
2016-05-05 17:26:47 +00:00
return STATUS_INTERNAL_ERROR ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
ei = ( EXTENT_ITEM * ) tp . item - > data ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
len = tp . item - > size - sizeof ( EXTENT_ITEM ) ;
2019-09-01 12:53:20 +00:00
ptr = ( uint8_t * ) & ei [ 1 ] ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ei - > flags & EXTENT_ITEM_TREE_BLOCK & & ! skinny ) {
2016-05-05 17:26:47 +00:00
if ( tp . item - > size < sizeof ( EXTENT_ITEM ) + sizeof ( EXTENT_ITEM2 ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " (%I64x,%x,%I64x) was %u bytes, expected at least %Iu \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , tp . item - > size , sizeof ( EXTENT_ITEM ) + sizeof ( EXTENT_ITEM2 ) ) ;
2016-05-05 17:26:47 +00:00
return STATUS_INTERNAL_ERROR ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
len - = sizeof ( EXTENT_ITEM2 ) ;
ptr + = sizeof ( EXTENT_ITEM2 ) ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( ei - > refcount < rc ) {
2019-09-01 12:53:20 +00:00
ERR ( " error - extent has refcount %I64x, trying to reduce by %x \n " , ei - > refcount , rc ) ;
2016-05-05 17:26:47 +00:00
return STATUS_INTERNAL_ERROR ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
inline_rc = 0 ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
// Loop through inline extent entries
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
while ( len > 0 ) {
2019-09-01 12:53:20 +00:00
uint8_t secttype = * ptr ;
uint16_t sectlen = get_extent_data_len ( secttype ) ;
uint64_t sectcount = get_extent_data_refcount ( secttype , ptr + sizeof ( uint8_t ) ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
len - - ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( sectlen > len ) {
2020-04-23 02:38:57 +00:00
ERR ( " (%I64x,%x,%I64x): %lx bytes left, expecting at least %x \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , len , sectlen ) ;
2016-05-05 17:26:47 +00:00
return STATUS_INTERNAL_ERROR ;
}
if ( sectlen = = 0 ) {
2019-09-01 12:53:20 +00:00
ERR ( " (%I64x,%x,%I64x): unrecognized extent type %x \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , secttype ) ;
2016-05-05 17:26:47 +00:00
return STATUS_INTERNAL_ERROR ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( secttype = = type ) {
if ( type = = TYPE_EXTENT_DATA_REF ) {
2019-09-01 12:53:20 +00:00
EXTENT_DATA_REF * sectedr = ( EXTENT_DATA_REF * ) ( ptr + sizeof ( uint8_t ) ) ;
2016-05-05 17:26:47 +00:00
EXTENT_DATA_REF * edr = ( EXTENT_DATA_REF * ) data ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( sectedr - > root = = edr - > root & & sectedr - > objid = = edr - > objid & & sectedr - > offset = = edr - > offset ) {
2019-09-01 12:53:20 +00:00
uint16_t neweilen ;
2017-09-08 08:02:43 +00:00
EXTENT_ITEM * newei ;
2016-05-05 17:26:47 +00:00
if ( ei - > refcount = = edr - > count ) {
2017-09-08 08:02:43 +00:00
Status = delete_tree_item ( Vcb , & tp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
2017-01-01 17:12:12 +00:00
if ( ! superseded )
2022-04-28 19:31:44 +00:00
add_checksum_entry ( Vcb , address , ( ULONG ) ( size > > Vcb - > sector_shift ) , NULL , Irp ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( sectedr - > count < edr - > count ) {
ERR ( " error - extent section has refcount %x, trying to reduce by %x \n " , sectedr - > count , edr - > count ) ;
return STATUS_INTERNAL_ERROR ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( sectedr - > count > edr - > count ) // reduce section refcount
neweilen = tp . item - > size ;
else // remove section entirely
2019-09-01 12:53:20 +00:00
neweilen = tp . item - > size - sizeof ( uint8_t ) - sectlen ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
newei = ExAllocatePoolWithTag ( PagedPool , neweilen , ALLOC_TAG ) ;
if ( ! newei ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( sectedr - > count > edr - > count ) {
2019-09-01 12:53:20 +00:00
EXTENT_DATA_REF * newedr = ( EXTENT_DATA_REF * ) ( ( uint8_t * ) newei + ( ( uint8_t * ) sectedr - tp . item - > data ) ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
RtlCopyMemory ( newei , ei , neweilen ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
newedr - > count - = rc ;
} else {
RtlCopyMemory ( newei , ei , ptr - tp . item - > data ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( len > sectlen )
2019-09-01 12:53:20 +00:00
RtlCopyMemory ( ( uint8_t * ) newei + ( ptr - tp . item - > data ) , ptr + sectlen + sizeof ( uint8_t ) , len - sectlen ) ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
newei - > refcount - = rc ;
2017-09-08 08:02:43 +00:00
Status = delete_tree_item ( Vcb , & tp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
Status = insert_tree_item ( Vcb , Vcb - > extent_root , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , newei , neweilen , NULL , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
2016-05-05 17:26:47 +00:00
return STATUS_SUCCESS ;
}
2016-07-27 19:24:26 +00:00
} else if ( type = = TYPE_SHARED_DATA_REF ) {
2019-09-01 12:53:20 +00:00
SHARED_DATA_REF * sectsdr = ( SHARED_DATA_REF * ) ( ptr + sizeof ( uint8_t ) ) ;
2016-07-27 19:24:26 +00:00
SHARED_DATA_REF * sdr = ( SHARED_DATA_REF * ) data ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( sectsdr - > offset = = sdr - > offset ) {
2017-09-08 08:02:43 +00:00
EXTENT_ITEM * newei ;
2019-09-01 12:53:20 +00:00
uint16_t neweilen ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( ei - > refcount = = sectsdr - > count ) {
2017-09-08 08:02:43 +00:00
Status = delete_tree_item ( Vcb , & tp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
2017-01-01 17:12:12 +00:00
if ( ! superseded )
2022-04-28 19:31:44 +00:00
add_checksum_entry ( Vcb , address , ( ULONG ) ( size > > Vcb - > sector_shift ) , NULL , Irp ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( sectsdr - > count < sdr - > count ) {
ERR ( " error - SHARED_DATA_REF has refcount %x, trying to reduce by %x \n " , sectsdr - > count , sdr - > count ) ;
return STATUS_INTERNAL_ERROR ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( sectsdr - > count > sdr - > count ) // reduce section refcount
neweilen = tp . item - > size ;
else // remove section entirely
2019-09-01 12:53:20 +00:00
neweilen = tp . item - > size - sizeof ( uint8_t ) - sectlen ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
newei = ExAllocatePoolWithTag ( PagedPool , neweilen , ALLOC_TAG ) ;
if ( ! newei ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( sectsdr - > count > sdr - > count ) {
2019-09-01 12:53:20 +00:00
SHARED_DATA_REF * newsdr = ( SHARED_DATA_REF * ) ( ( uint8_t * ) newei + ( ( uint8_t * ) sectsdr - tp . item - > data ) ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
RtlCopyMemory ( newei , ei , neweilen ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
newsdr - > count - = rc ;
} else {
RtlCopyMemory ( newei , ei , ptr - tp . item - > data ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( len > sectlen )
2019-09-01 12:53:20 +00:00
RtlCopyMemory ( ( uint8_t * ) newei + ( ptr - tp . item - > data ) , ptr + sectlen + sizeof ( uint8_t ) , len - sectlen ) ;
2017-01-01 17:12:12 +00:00
}
2016-07-27 19:24:26 +00:00
newei - > refcount - = rc ;
2017-09-08 08:02:43 +00:00
Status = delete_tree_item ( Vcb , & tp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
Status = insert_tree_item ( Vcb , Vcb - > extent_root , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , newei , neweilen , NULL , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
2016-10-29 17:05:10 +00:00
return STATUS_SUCCESS ;
}
} else if ( type = = TYPE_TREE_BLOCK_REF ) {
2019-09-01 12:53:20 +00:00
TREE_BLOCK_REF * secttbr = ( TREE_BLOCK_REF * ) ( ptr + sizeof ( uint8_t ) ) ;
2016-10-29 17:05:10 +00:00
TREE_BLOCK_REF * tbr = ( TREE_BLOCK_REF * ) data ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( secttbr - > offset = = tbr - > offset ) {
2017-09-08 08:02:43 +00:00
EXTENT_ITEM * newei ;
2019-09-01 12:53:20 +00:00
uint16_t neweilen ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ei - > refcount = = 1 ) {
2017-09-08 08:02:43 +00:00
Status = delete_tree_item ( Vcb , & tp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
2016-10-29 17:05:10 +00:00
return STATUS_SUCCESS ;
}
2019-09-01 12:53:20 +00:00
neweilen = tp . item - > size - sizeof ( uint8_t ) - sectlen ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
newei = ExAllocatePoolWithTag ( PagedPool , neweilen , ALLOC_TAG ) ;
if ( ! newei ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
RtlCopyMemory ( newei , ei , ptr - tp . item - > data ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( len > sectlen )
2019-09-01 12:53:20 +00:00
RtlCopyMemory ( ( uint8_t * ) newei + ( ptr - tp . item - > data ) , ptr + sectlen + sizeof ( uint8_t ) , len - sectlen ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
newei - > refcount - - ;
2017-09-08 08:02:43 +00:00
Status = delete_tree_item ( Vcb , & tp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
Status = insert_tree_item ( Vcb , Vcb - > extent_root , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , newei , neweilen , NULL , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
2016-10-29 17:05:10 +00:00
return STATUS_SUCCESS ;
}
} else if ( type = = TYPE_SHARED_BLOCK_REF ) {
2019-09-01 12:53:20 +00:00
SHARED_BLOCK_REF * sectsbr = ( SHARED_BLOCK_REF * ) ( ptr + sizeof ( uint8_t ) ) ;
2016-10-29 17:05:10 +00:00
SHARED_BLOCK_REF * sbr = ( SHARED_BLOCK_REF * ) data ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( sectsbr - > offset = = sbr - > offset ) {
2017-09-08 08:02:43 +00:00
EXTENT_ITEM * newei ;
2019-09-01 12:53:20 +00:00
uint16_t neweilen ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ei - > refcount = = 1 ) {
2017-09-08 08:02:43 +00:00
Status = delete_tree_item ( Vcb , & tp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
2016-10-29 17:05:10 +00:00
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
neweilen = tp . item - > size - sizeof ( uint8_t ) - sectlen ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
newei = ExAllocatePoolWithTag ( PagedPool , neweilen , ALLOC_TAG ) ;
if ( ! newei ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
RtlCopyMemory ( newei , ei , ptr - tp . item - > data ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( len > sectlen )
2019-09-01 12:53:20 +00:00
RtlCopyMemory ( ( uint8_t * ) newei + ( ptr - tp . item - > data ) , ptr + sectlen + sizeof ( uint8_t ) , len - sectlen ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
newei - > refcount - - ;
2017-09-08 08:02:43 +00:00
Status = delete_tree_item ( Vcb , & tp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
Status = insert_tree_item ( Vcb , Vcb - > extent_root , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , newei , neweilen , NULL , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
return STATUS_SUCCESS ;
}
2016-05-05 17:26:47 +00:00
} else {
ERR ( " unhandled extent type %x \n " , type ) ;
return STATUS_INTERNAL_ERROR ;
}
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
len - = sectlen ;
2019-09-01 12:53:20 +00:00
ptr + = sizeof ( uint8_t ) + sectlen ;
2016-05-05 17:26:47 +00:00
inline_rc + = sectcount ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( inline_rc = = ei - > refcount ) {
2019-09-01 12:53:20 +00:00
ERR ( " entry not found in inline extent item for address %I64x \n " , address ) ;
2016-05-05 17:26:47 +00:00
return STATUS_INTERNAL_ERROR ;
}
2017-09-08 08:02:43 +00:00
if ( type = = TYPE_SHARED_DATA_REF )
2019-09-01 12:53:20 +00:00
datalen = sizeof ( uint32_t ) ;
2017-09-08 08:02:43 +00:00
else if ( type = = TYPE_TREE_BLOCK_REF | | type = = TYPE_SHARED_BLOCK_REF )
datalen = 0 ;
2016-05-05 17:26:47 +00:00
searchkey . obj_id = address ;
searchkey . obj_type = type ;
2016-07-27 19:24:26 +00:00
searchkey . offset = ( type = = TYPE_SHARED_DATA_REF | | type = = TYPE_EXTENT_REF_V0 ) ? parent : get_extent_hash ( type , data ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > extent_root , & tp2 , & searchkey , false , Irp ) ;
2016-05-05 17:26:47 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - find_item returned %08lx \n " , Status ) ;
2016-05-05 17:26:47 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( keycmp ( tp2 . item - > key , searchkey ) ) {
2019-09-01 12:53:20 +00:00
ERR ( " (%I64x,%x,%I64x) not found \n " , tp2 . item - > key . obj_id , tp2 . item - > key . obj_type , tp2 . item - > key . offset ) ;
2016-05-05 17:26:47 +00:00
return STATUS_INTERNAL_ERROR ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( tp2 . item - > size < datalen ) {
2020-04-23 02:38:57 +00:00
ERR ( " (%I64x,%x,%I64x) was %u bytes, expected at least %lu \n " , tp2 . item - > key . obj_id , tp2 . item - > key . obj_type , tp2 . item - > key . offset , tp2 . item - > size , datalen ) ;
2016-05-05 17:26:47 +00:00
return STATUS_INTERNAL_ERROR ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( type = = TYPE_EXTENT_DATA_REF ) {
EXTENT_DATA_REF * sectedr = ( EXTENT_DATA_REF * ) tp2 . item - > data ;
EXTENT_DATA_REF * edr = ( EXTENT_DATA_REF * ) data ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( sectedr - > root = = edr - > root & & sectedr - > objid = = edr - > objid & & sectedr - > offset = = edr - > offset ) {
2017-09-08 08:02:43 +00:00
EXTENT_ITEM * newei ;
2016-05-05 17:26:47 +00:00
if ( ei - > refcount = = edr - > count ) {
2017-09-08 08:02:43 +00:00
Status = delete_tree_item ( Vcb , & tp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
Status = delete_tree_item ( Vcb , & tp2 ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
2017-01-01 17:12:12 +00:00
if ( ! superseded )
2022-04-28 19:31:44 +00:00
add_checksum_entry ( Vcb , address , ( ULONG ) ( size > > Vcb - > sector_shift ) , NULL , Irp ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( sectedr - > count < edr - > count ) {
ERR ( " error - extent section has refcount %x, trying to reduce by %x \n " , sectedr - > count , edr - > count ) ;
return STATUS_INTERNAL_ERROR ;
}
2017-09-08 08:02:43 +00:00
Status = delete_tree_item ( Vcb , & tp2 ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
2016-05-05 17:26:47 +00:00
if ( sectedr - > count > edr - > count ) {
EXTENT_DATA_REF * newedr = ExAllocatePoolWithTag ( PagedPool , tp2 . item - > size , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( ! newedr ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
RtlCopyMemory ( newedr , sectedr , tp2 . item - > size ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
newedr - > count - = edr - > count ;
2017-09-08 08:02:43 +00:00
Status = insert_tree_item ( Vcb , Vcb - > extent_root , tp2 . item - > key . obj_id , tp2 . item - > key . obj_type , tp2 . item - > key . offset , newedr , tp2 . item - > size , NULL , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
2016-05-05 17:26:47 +00:00
}
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
newei = ExAllocatePoolWithTag ( PagedPool , tp . item - > size , ALLOC_TAG ) ;
if ( ! newei ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
RtlCopyMemory ( newei , tp . item - > data , tp . item - > size ) ;
newei - > refcount - = rc ;
2017-09-08 08:02:43 +00:00
Status = delete_tree_item ( Vcb , & tp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
Status = insert_tree_item ( Vcb , Vcb - > extent_root , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , newei , tp . item - > size , NULL , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
return STATUS_SUCCESS ;
} else {
ERR ( " error - hash collision? \n " ) ;
return STATUS_INTERNAL_ERROR ;
}
2016-07-27 19:24:26 +00:00
} else if ( type = = TYPE_SHARED_DATA_REF ) {
SHARED_DATA_REF * sdr = ( SHARED_DATA_REF * ) data ;
2017-09-08 08:02:43 +00:00
if ( tp2 . item - > key . offset = = sdr - > offset ) {
2019-09-01 12:53:20 +00:00
uint32_t * sectsdrcount = ( uint32_t * ) tp2 . item - > data ;
2017-09-08 08:02:43 +00:00
EXTENT_ITEM * newei ;
2017-01-01 17:12:12 +00:00
if ( ei - > refcount = = sdr - > count ) {
2017-09-08 08:02:43 +00:00
Status = delete_tree_item ( Vcb , & tp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
Status = delete_tree_item ( Vcb , & tp2 ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
2017-01-01 17:12:12 +00:00
if ( ! superseded )
2022-04-28 19:31:44 +00:00
add_checksum_entry ( Vcb , address , ( ULONG ) ( size > > Vcb - > sector_shift ) , NULL , Irp ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
if ( * sectsdrcount < sdr - > count ) {
ERR ( " error - extent section has refcount %x, trying to reduce by %x \n " , * sectsdrcount , sdr - > count ) ;
2017-01-01 17:12:12 +00:00
return STATUS_INTERNAL_ERROR ;
}
2017-09-08 08:02:43 +00:00
Status = delete_tree_item ( Vcb , & tp2 ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
if ( * sectsdrcount > sdr - > count ) {
2019-09-01 12:53:20 +00:00
uint32_t * newsdr = ExAllocatePoolWithTag ( PagedPool , tp2 . item - > size , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! newsdr ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2016-07-27 19:24:26 +00:00
2017-09-08 08:02:43 +00:00
* newsdr = * sectsdrcount - sdr - > count ;
Status = insert_tree_item ( Vcb , Vcb - > extent_root , tp2 . item - > key . obj_id , tp2 . item - > key . obj_type , tp2 . item - > key . offset , newsdr , tp2 . item - > size , NULL , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
newei = ExAllocatePoolWithTag ( PagedPool , tp . item - > size , ALLOC_TAG ) ;
if ( ! newei ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
RtlCopyMemory ( newei , tp . item - > data , tp . item - > size ) ;
newei - > refcount - = rc ;
2017-09-08 08:02:43 +00:00
Status = delete_tree_item ( Vcb , & tp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
Status = insert_tree_item ( Vcb , Vcb - > extent_root , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , newei , tp . item - > size , NULL , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
return STATUS_SUCCESS ;
} else {
ERR ( " error - collision? \n " ) ;
return STATUS_INTERNAL_ERROR ;
}
2017-09-08 08:02:43 +00:00
} else if ( type = = TYPE_TREE_BLOCK_REF | | type = = TYPE_SHARED_BLOCK_REF ) {
2016-10-29 17:05:10 +00:00
EXTENT_ITEM * newei ;
2017-09-08 08:02:43 +00:00
if ( ei - > refcount = = 1 ) {
Status = delete_tree_item ( Vcb , & tp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
Status = delete_tree_item ( Vcb , & tp2 ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
Status = delete_tree_item ( Vcb , & tp2 ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
newei = ExAllocatePoolWithTag ( PagedPool , tp . item - > size , ALLOC_TAG ) ;
if ( ! newei ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
RtlCopyMemory ( newei , tp . item - > data , tp . item - > size ) ;
newei - > refcount - = rc ;
Status = delete_tree_item ( Vcb , & tp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
Status = insert_tree_item ( Vcb , Vcb - > extent_root , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , newei , tp . item - > size , NULL , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
return STATUS_SUCCESS ;
2016-07-27 19:24:26 +00:00
} else if ( type = = TYPE_EXTENT_REF_V0 ) {
EXTENT_REF_V0 * erv0 = ( EXTENT_REF_V0 * ) tp2 . item - > data ;
EXTENT_ITEM * newei ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( ei - > refcount = = erv0 - > count ) {
2017-09-08 08:02:43 +00:00
Status = delete_tree_item ( Vcb , & tp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
Status = delete_tree_item ( Vcb , & tp2 ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
2017-01-01 17:12:12 +00:00
if ( ! superseded )
2022-04-28 19:31:44 +00:00
add_checksum_entry ( Vcb , address , ( ULONG ) ( size > > Vcb - > sector_shift ) , NULL , Irp ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
Status = delete_tree_item ( Vcb , & tp2 ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
2016-07-27 19:24:26 +00:00
newei = ExAllocatePoolWithTag ( PagedPool , tp . item - > size , ALLOC_TAG ) ;
if ( ! newei ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
RtlCopyMemory ( newei , tp . item - > data , tp . item - > size ) ;
newei - > refcount - = rc ;
2017-09-08 08:02:43 +00:00
Status = delete_tree_item ( Vcb , & tp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
Status = insert_tree_item ( Vcb , Vcb - > extent_root , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , newei , tp . item - > size , NULL , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
return STATUS_SUCCESS ;
2016-05-05 17:26:47 +00:00
} else {
ERR ( " unhandled extent type %x \n " , type ) ;
return STATUS_INTERNAL_ERROR ;
}
}
2019-09-01 12:53:20 +00:00
NTSTATUS decrease_extent_refcount_data ( device_extension * Vcb , uint64_t address , uint64_t size , uint64_t root , uint64_t inode ,
uint64_t offset , uint32_t refcount , bool superseded , PIRP Irp ) {
2016-05-05 17:26:47 +00:00
EXTENT_DATA_REF edr ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
edr . root = root ;
2016-05-05 17:26:47 +00:00
edr . objid = inode ;
edr . offset = offset ;
edr . count = refcount ;
2017-09-08 08:02:43 +00:00
return decrease_extent_refcount ( Vcb , address , size , TYPE_EXTENT_DATA_REF , & edr , NULL , 0 , 0 , superseded , Irp ) ;
2016-07-27 19:24:26 +00:00
}
2019-09-01 12:53:20 +00:00
NTSTATUS decrease_extent_refcount_tree ( device_extension * Vcb , uint64_t address , uint64_t size , uint64_t root ,
uint8_t level , PIRP Irp ) {
2016-10-29 17:05:10 +00:00
TREE_BLOCK_REF tbr ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
tbr . offset = root ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
return decrease_extent_refcount ( Vcb , address , size , TYPE_TREE_BLOCK_REF , & tbr , NULL /*FIXME*/ , level , 0 , false , Irp ) ;
2016-05-05 17:26:47 +00:00
}
2019-09-01 12:53:20 +00:00
static uint32_t find_extent_data_refcount ( device_extension * Vcb , uint64_t address , uint64_t size , uint64_t root , uint64_t objid , uint64_t offset , PIRP Irp ) {
2016-10-29 17:05:10 +00:00
NTSTATUS Status ;
KEY searchkey ;
traverse_ptr tp ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
searchkey . obj_id = address ;
searchkey . obj_type = TYPE_EXTENT_ITEM ;
searchkey . offset = 0xffffffffffffffff ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > extent_root , & tp , & searchkey , false , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - find_item returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return 0 ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( tp . item - > key . obj_id ! = searchkey . obj_id | | tp . item - > key . obj_type ! = searchkey . obj_type ) {
2019-09-01 12:53:20 +00:00
TRACE ( " could not find address %I64x in extent tree \n " , address ) ;
2016-10-29 17:05:10 +00:00
return 0 ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( tp . item - > key . offset ! = size ) {
2019-09-01 12:53:20 +00:00
ERR ( " extent %I64x had size %I64x, not %I64x as expected \n " , address , tp . item - > key . offset , size ) ;
2016-10-29 17:05:10 +00:00
return 0 ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( tp . item - > size > = sizeof ( EXTENT_ITEM ) ) {
EXTENT_ITEM * ei = ( EXTENT_ITEM * ) tp . item - > data ;
2019-09-01 12:53:20 +00:00
uint32_t len = tp . item - > size - sizeof ( EXTENT_ITEM ) ;
uint8_t * ptr = ( uint8_t * ) & ei [ 1 ] ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
while ( len > 0 ) {
2019-09-01 12:53:20 +00:00
uint8_t secttype = * ptr ;
2016-10-29 17:05:10 +00:00
ULONG sectlen = get_extent_data_len ( secttype ) ;
2019-09-01 12:53:20 +00:00
uint32_t sectcount = get_extent_data_refcount ( secttype , ptr + sizeof ( uint8_t ) ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
len - - ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( sectlen > len ) {
2020-04-23 02:38:57 +00:00
ERR ( " (%I64x,%x,%I64x): %x bytes left, expecting at least %lx \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , len , sectlen ) ;
2016-10-29 17:05:10 +00:00
return 0 ;
}
if ( sectlen = = 0 ) {
2019-09-01 12:53:20 +00:00
ERR ( " (%I64x,%x,%I64x): unrecognized extent type %x \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , secttype ) ;
2016-10-29 17:05:10 +00:00
return 0 ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( secttype = = TYPE_EXTENT_DATA_REF ) {
2019-09-01 12:53:20 +00:00
EXTENT_DATA_REF * sectedr = ( EXTENT_DATA_REF * ) ( ptr + sizeof ( uint8_t ) ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( sectedr - > root = = root & & sectedr - > objid = = objid & & sectedr - > offset = = offset )
return sectcount ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
len - = sectlen ;
2019-09-01 12:53:20 +00:00
ptr + = sizeof ( uint8_t ) + sectlen ;
2016-05-05 17:26:47 +00:00
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
searchkey . obj_id = address ;
searchkey . obj_type = TYPE_EXTENT_DATA_REF ;
searchkey . offset = get_extent_data_ref_hash2 ( root , objid , offset ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > extent_root , & tp , & searchkey , false , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - find_item returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return 0 ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
if ( ! keycmp ( searchkey , tp . item - > key ) ) {
2016-10-29 17:05:10 +00:00
if ( tp . item - > size < sizeof ( EXTENT_DATA_REF ) )
2020-04-23 02:38:57 +00:00
ERR ( " (%I64x,%x,%I64x) has size %u, not %Iu as expected \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , tp . item - > size , sizeof ( EXTENT_DATA_REF ) ) ;
2017-09-08 08:02:43 +00:00
else {
EXTENT_DATA_REF * edr = ( EXTENT_DATA_REF * ) tp . item - > data ;
2016-10-29 17:05:10 +00:00
return edr - > count ;
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
return 0 ;
2016-05-05 17:26:47 +00:00
}
2019-09-01 12:53:20 +00:00
uint64_t get_extent_refcount ( device_extension * Vcb , uint64_t address , uint64_t size , PIRP Irp ) {
2016-10-29 17:05:10 +00:00
KEY searchkey ;
traverse_ptr tp ;
NTSTATUS Status ;
2016-05-05 17:26:47 +00:00
EXTENT_ITEM * ei ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
searchkey . obj_id = address ;
searchkey . obj_type = Vcb - > superblock . incompat_flags & BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA ? TYPE_METADATA_ITEM : TYPE_EXTENT_ITEM ;
searchkey . offset = 0xffffffffffffffff ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > extent_root , & tp , & searchkey , false , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - find_item returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return 0 ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( Vcb - > superblock . incompat_flags & BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA & & tp . item - > key . obj_id = = address & &
tp . item - > key . obj_type = = TYPE_METADATA_ITEM & & tp . item - > size > = sizeof ( EXTENT_ITEM ) ) {
ei = ( EXTENT_ITEM * ) tp . item - > data ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
return ei - > refcount ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( tp . item - > key . obj_id ! = address | | tp . item - > key . obj_type ! = TYPE_EXTENT_ITEM ) {
2019-09-01 12:53:20 +00:00
ERR ( " couldn't find (%I64x,%x,%I64x) in extent tree \n " , address , TYPE_EXTENT_ITEM , size ) ;
2016-10-29 17:05:10 +00:00
return 0 ;
} else if ( tp . item - > key . offset ! = size ) {
2019-09-01 12:53:20 +00:00
ERR ( " extent %I64x had size %I64x, not %I64x as expected \n " , address , tp . item - > key . offset , size ) ;
2016-10-29 17:05:10 +00:00
return 0 ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( tp . item - > size = = sizeof ( EXTENT_ITEM_V0 ) ) {
EXTENT_ITEM_V0 * eiv0 = ( EXTENT_ITEM_V0 * ) tp . item - > data ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
return eiv0 - > refcount ;
} else if ( tp . item - > size < sizeof ( EXTENT_ITEM ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " (%I64x,%x,%I64x) was %x bytes, expected at least %Ix \n " , tp . item - > key . obj_id , tp . item - > key . obj_type ,
tp . item - > key . offset , tp . item - > size , sizeof ( EXTENT_ITEM ) ) ;
2016-10-29 17:05:10 +00:00
return 0 ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ei = ( EXTENT_ITEM * ) tp . item - > data ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
return ei - > refcount ;
}
2019-09-01 12:53:20 +00:00
bool is_extent_unique ( device_extension * Vcb , uint64_t address , uint64_t size , PIRP Irp ) {
2016-10-29 17:05:10 +00:00
KEY searchkey ;
traverse_ptr tp , next_tp ;
NTSTATUS Status ;
2019-09-01 12:53:20 +00:00
uint64_t rc , rcrun , root = 0 , inode = 0 , offset = 0 ;
uint32_t len ;
2016-10-29 17:05:10 +00:00
EXTENT_ITEM * ei ;
2019-09-01 12:53:20 +00:00
uint8_t * ptr ;
bool b ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
rc = get_extent_refcount ( Vcb , address , size , Irp ) ;
if ( rc = = 1 )
2019-09-01 12:53:20 +00:00
return true ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( rc = = 0 )
2019-09-01 12:53:20 +00:00
return false ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
searchkey . obj_id = address ;
searchkey . obj_type = TYPE_EXTENT_ITEM ;
searchkey . offset = size ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > extent_root , & tp , & searchkey , false , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
WARN ( " error - find_item returned %08lx \n " , Status ) ;
2019-09-01 12:53:20 +00:00
return false ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( keycmp ( tp . item - > key , searchkey ) ) {
2019-09-01 12:53:20 +00:00
WARN ( " could not find (%I64x,%x,%I64x) \n " , searchkey . obj_id , searchkey . obj_type , searchkey . offset ) ;
return false ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( tp . item - > size = = sizeof ( EXTENT_ITEM_V0 ) )
2019-09-01 12:53:20 +00:00
return false ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( tp . item - > size < sizeof ( EXTENT_ITEM ) ) {
2020-04-23 02:38:57 +00:00
WARN ( " (%I64x,%x,%I64x) was %u bytes, expected at least %Iu \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , tp . item - > size , sizeof ( EXTENT_ITEM ) ) ;
2019-09-01 12:53:20 +00:00
return false ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ei = ( EXTENT_ITEM * ) tp . item - > data ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
len = tp . item - > size - sizeof ( EXTENT_ITEM ) ;
2019-09-01 12:53:20 +00:00
ptr = ( uint8_t * ) & ei [ 1 ] ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ei - > flags & EXTENT_ITEM_TREE_BLOCK ) {
if ( tp . item - > size < sizeof ( EXTENT_ITEM ) + sizeof ( EXTENT_ITEM2 ) ) {
2020-04-23 02:38:57 +00:00
WARN ( " (%I64x,%x,%I64x) was %u bytes, expected at least %Iu \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , tp . item - > size , sizeof ( EXTENT_ITEM ) + sizeof ( EXTENT_ITEM2 ) ) ;
2019-09-01 12:53:20 +00:00
return false ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
len - = sizeof ( EXTENT_ITEM2 ) ;
ptr + = sizeof ( EXTENT_ITEM2 ) ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
rcrun = 0 ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
// Loop through inline extent entries
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
while ( len > 0 ) {
2019-09-01 12:53:20 +00:00
uint8_t secttype = * ptr ;
2016-10-29 17:05:10 +00:00
ULONG sectlen = get_extent_data_len ( secttype ) ;
2019-09-01 12:53:20 +00:00
uint64_t sectcount = get_extent_data_refcount ( secttype , ptr + sizeof ( uint8_t ) ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
len - - ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( sectlen > len ) {
2020-04-23 02:38:57 +00:00
WARN ( " (%I64x,%x,%I64x): %x bytes left, expecting at least %lx \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , len , sectlen ) ;
2019-09-01 12:53:20 +00:00
return false ;
2016-05-05 17:26:47 +00:00
}
2016-10-29 17:05:10 +00:00
if ( sectlen = = 0 ) {
2019-09-01 12:53:20 +00:00
WARN ( " (%I64x,%x,%I64x): unrecognized extent type %x \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , secttype ) ;
return false ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( secttype = = TYPE_EXTENT_DATA_REF ) {
2019-09-01 12:53:20 +00:00
EXTENT_DATA_REF * sectedr = ( EXTENT_DATA_REF * ) ( ptr + sizeof ( uint8_t ) ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( root = = 0 & & inode = = 0 ) {
root = sectedr - > root ;
inode = sectedr - > objid ;
2017-09-08 08:02:43 +00:00
offset = sectedr - > offset ;
} else if ( root ! = sectedr - > root | | inode ! = sectedr - > objid | | offset ! = sectedr - > offset )
2019-09-01 12:53:20 +00:00
return false ;
2016-10-29 17:05:10 +00:00
} else
2019-09-01 12:53:20 +00:00
return false ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
len - = sectlen ;
2019-09-01 12:53:20 +00:00
ptr + = sizeof ( uint8_t ) + sectlen ;
2016-10-29 17:05:10 +00:00
rcrun + = sectcount ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( rcrun = = rc )
2019-09-01 12:53:20 +00:00
return true ;
2016-10-29 17:05:10 +00:00
// Loop through non-inlines if some refs still unaccounted for
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
do {
2019-09-01 12:53:20 +00:00
b = find_next_item ( Vcb , & tp , & next_tp , false , Irp ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( tp . item - > key . obj_id = = searchkey . obj_id & & tp . item - > key . obj_type = = TYPE_EXTENT_DATA_REF ) {
EXTENT_DATA_REF * edr = ( EXTENT_DATA_REF * ) tp . item - > data ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( tp . item - > size < sizeof ( EXTENT_DATA_REF ) ) {
2020-04-23 02:38:57 +00:00
WARN ( " (%I64x,%x,%I64x) was %u bytes, expected at least %Iu \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset ,
2016-10-29 17:05:10 +00:00
tp . item - > size , sizeof ( EXTENT_ITEM ) + sizeof ( EXTENT_ITEM2 ) ) ;
2019-09-01 12:53:20 +00:00
return false ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( root = = 0 & & inode = = 0 ) {
root = edr - > root ;
inode = edr - > objid ;
2017-09-08 08:02:43 +00:00
offset = edr - > offset ;
} else if ( root ! = edr - > root | | inode ! = edr - > objid | | offset ! = edr - > offset )
2019-09-01 12:53:20 +00:00
return false ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
rcrun + = edr - > count ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( rcrun = = rc )
2019-09-01 12:53:20 +00:00
return true ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( b ) {
tp = next_tp ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( tp . item - > key . obj_id > searchkey . obj_id )
break ;
}
} while ( b ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
// If we reach this point, there's still some refs unaccounted for somewhere.
2019-09-01 12:53:20 +00:00
// Return false in case we mess things up elsewhere.
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
return false ;
2016-05-05 17:26:47 +00:00
}
2019-09-01 12:53:20 +00:00
uint64_t get_extent_flags ( device_extension * Vcb , uint64_t address , PIRP Irp ) {
2016-10-29 17:05:10 +00:00
KEY searchkey ;
traverse_ptr tp ;
2016-05-05 17:26:47 +00:00
NTSTATUS Status ;
2016-10-29 17:05:10 +00:00
EXTENT_ITEM * ei ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
searchkey . obj_id = address ;
searchkey . obj_type = Vcb - > superblock . incompat_flags & BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA ? TYPE_METADATA_ITEM : TYPE_EXTENT_ITEM ;
searchkey . offset = 0xffffffffffffffff ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > extent_root , & tp , & searchkey , false , Irp ) ;
2016-05-05 17:26:47 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - find_item returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return 0 ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( Vcb - > superblock . incompat_flags & BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA & & tp . item - > key . obj_id = = address & &
tp . item - > key . obj_type = = TYPE_METADATA_ITEM & & tp . item - > size > = sizeof ( EXTENT_ITEM ) ) {
ei = ( EXTENT_ITEM * ) tp . item - > data ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
return ei - > flags ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( tp . item - > key . obj_id ! = address | | tp . item - > key . obj_type ! = TYPE_EXTENT_ITEM ) {
2019-09-01 12:53:20 +00:00
ERR ( " couldn't find %I64x in extent tree \n " , address ) ;
2016-10-29 17:05:10 +00:00
return 0 ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( tp . item - > size = = sizeof ( EXTENT_ITEM_V0 ) )
return 0 ;
else if ( tp . item - > size < sizeof ( EXTENT_ITEM ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " (%I64x,%x,%I64x) was %x bytes, expected at least %Ix \n " , tp . item - > key . obj_id , tp . item - > key . obj_type ,
tp . item - > key . offset , tp . item - > size , sizeof ( EXTENT_ITEM ) ) ;
2016-10-29 17:05:10 +00:00
return 0 ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ei = ( EXTENT_ITEM * ) tp . item - > data ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
return ei - > flags ;
2016-05-05 17:26:47 +00:00
}
2019-09-01 12:53:20 +00:00
void update_extent_flags ( device_extension * Vcb , uint64_t address , uint64_t flags , PIRP Irp ) {
2016-05-05 17:26:47 +00:00
KEY searchkey ;
2016-10-29 17:05:10 +00:00
traverse_ptr tp ;
2016-05-05 17:26:47 +00:00
NTSTATUS Status ;
2016-10-29 17:05:10 +00:00
EXTENT_ITEM * ei ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
searchkey . obj_id = address ;
2016-10-29 17:05:10 +00:00
searchkey . obj_type = Vcb - > superblock . incompat_flags & BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA ? TYPE_METADATA_ITEM : TYPE_EXTENT_ITEM ;
searchkey . offset = 0xffffffffffffffff ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > extent_root , & tp , & searchkey , false , Irp ) ;
2016-05-05 17:26:47 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - find_item returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( Vcb - > superblock . incompat_flags & BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA & & tp . item - > key . obj_id = = address & &
tp . item - > key . obj_type = = TYPE_METADATA_ITEM & & tp . item - > size > = sizeof ( EXTENT_ITEM ) ) {
ei = ( EXTENT_ITEM * ) tp . item - > data ;
ei - > flags = flags ;
return ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( tp . item - > key . obj_id ! = address | | tp . item - > key . obj_type ! = TYPE_EXTENT_ITEM ) {
2019-09-01 12:53:20 +00:00
ERR ( " couldn't find %I64x in extent tree \n " , address ) ;
2016-10-29 17:05:10 +00:00
return ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( tp . item - > size = = sizeof ( EXTENT_ITEM_V0 ) )
return ;
else if ( tp . item - > size < sizeof ( EXTENT_ITEM ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " (%I64x,%x,%I64x) was %x bytes, expected at least %Ix \n " , tp . item - > key . obj_id , tp . item - > key . obj_type ,
tp . item - > key . offset , tp . item - > size , sizeof ( EXTENT_ITEM ) ) ;
2016-10-29 17:05:10 +00:00
return ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ei = ( EXTENT_ITEM * ) tp . item - > data ;
ei - > flags = flags ;
}
2019-09-01 12:53:20 +00:00
static changed_extent * get_changed_extent_item ( chunk * c , uint64_t address , uint64_t size , bool no_csum ) {
2016-10-29 17:05:10 +00:00
LIST_ENTRY * le ;
changed_extent * ce ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = c - > changed_extents . Flink ;
while ( le ! = & c - > changed_extents ) {
ce = CONTAINING_RECORD ( le , changed_extent , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ce - > address = = address & & ce - > size = = size )
return ce ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = le - > Flink ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ce = ExAllocatePoolWithTag ( PagedPool , sizeof ( changed_extent ) , ALLOC_TAG ) ;
if ( ! ce ) {
ERR ( " out of memory \n " ) ;
return NULL ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ce - > address = address ;
ce - > size = size ;
ce - > old_size = size ;
ce - > count = 0 ;
ce - > old_count = 0 ;
ce - > no_csum = no_csum ;
2019-09-01 12:53:20 +00:00
ce - > superseded = false ;
2016-10-29 17:05:10 +00:00
InitializeListHead ( & ce - > refs ) ;
InitializeListHead ( & ce - > old_refs ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
InsertTailList ( & c - > changed_extents , & ce - > list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
return ce ;
}
2019-09-01 12:53:20 +00:00
NTSTATUS update_changed_extent_ref ( device_extension * Vcb , chunk * c , uint64_t address , uint64_t size , uint64_t root , uint64_t objid , uint64_t offset , int32_t count ,
bool no_csum , bool superseded , PIRP Irp ) {
2016-10-29 17:05:10 +00:00
LIST_ENTRY * le ;
changed_extent * ce ;
changed_extent_ref * cer ;
NTSTATUS Status ;
KEY searchkey ;
traverse_ptr tp ;
2019-09-01 12:53:20 +00:00
uint32_t old_count ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( & c - > changed_extents_lock , true ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ce = get_changed_extent_item ( c , address , size , no_csum ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! ce ) {
ERR ( " get_changed_extent_item failed \n " ) ;
Status = STATUS_INTERNAL_ERROR ;
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( IsListEmpty ( & ce - > refs ) & & IsListEmpty ( & ce - > old_refs ) ) { // new entry
searchkey . obj_id = address ;
searchkey . obj_type = TYPE_EXTENT_ITEM ;
searchkey . offset = 0xffffffffffffffff ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > extent_root , & tp , & searchkey , false , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - find_item returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( tp . item - > key . obj_id ! = searchkey . obj_id | | tp . item - > key . obj_type ! = searchkey . obj_type ) {
2019-09-01 12:53:20 +00:00
ERR ( " could not find address %I64x in extent tree \n " , address ) ;
2016-10-29 17:05:10 +00:00
Status = STATUS_INTERNAL_ERROR ;
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( tp . item - > key . offset ! = size ) {
2019-09-01 12:53:20 +00:00
ERR ( " extent %I64x had size %I64x, not %I64x as expected \n " , address , tp . item - > key . offset , size ) ;
2016-10-29 17:05:10 +00:00
Status = STATUS_INTERNAL_ERROR ;
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( tp . item - > size = = sizeof ( EXTENT_ITEM_V0 ) ) {
EXTENT_ITEM_V0 * eiv0 = ( EXTENT_ITEM_V0 * ) tp . item - > data ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ce - > count = ce - > old_count = eiv0 - > refcount ;
} else if ( tp . item - > size > = sizeof ( EXTENT_ITEM ) ) {
EXTENT_ITEM * ei = ( EXTENT_ITEM * ) tp . item - > data ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ce - > count = ce - > old_count = ei - > refcount ;
} else {
2020-04-23 02:38:57 +00:00
ERR ( " (%I64x,%x,%I64x) was %u bytes, expected at least %Iu \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , tp . item - > size , sizeof ( EXTENT_ITEM ) ) ;
2016-10-29 17:05:10 +00:00
Status = STATUS_INTERNAL_ERROR ;
goto end ;
2016-07-27 19:24:26 +00:00
}
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = ce - > refs . Flink ;
while ( le ! = & ce - > refs ) {
cer = CONTAINING_RECORD ( le , changed_extent_ref , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( cer - > type = = TYPE_EXTENT_DATA_REF & & cer - > edr . root = = root & & cer - > edr . objid = = objid & & cer - > edr . offset = = offset ) {
ce - > count + = count ;
cer - > edr . count + = count ;
Status = STATUS_SUCCESS ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( superseded )
2019-09-01 12:53:20 +00:00
ce - > superseded = true ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
goto end ;
2016-05-05 17:26:47 +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
old_count = find_extent_data_refcount ( Vcb , address , size , root , objid , offset , Irp ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( old_count > 0 ) {
cer = ExAllocatePoolWithTag ( PagedPool , sizeof ( changed_extent_ref ) , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! cer ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
cer - > type = TYPE_EXTENT_DATA_REF ;
cer - > edr . root = root ;
cer - > edr . objid = objid ;
cer - > edr . offset = offset ;
cer - > edr . count = old_count ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
InsertTailList ( & ce - > old_refs , & cer - > list_entry ) ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
cer = ExAllocatePoolWithTag ( PagedPool , sizeof ( changed_extent_ref ) , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! cer ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
cer - > type = TYPE_EXTENT_DATA_REF ;
cer - > edr . root = root ;
cer - > edr . objid = objid ;
cer - > edr . offset = offset ;
cer - > edr . count = old_count + count ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
InsertTailList ( & ce - > refs , & cer - > list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ce - > count + = count ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( superseded )
2019-09-01 12:53:20 +00:00
ce - > superseded = true ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
Status = STATUS_SUCCESS ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
end :
ExReleaseResourceLite ( & c - > changed_extents_lock ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
return Status ;
}
2019-09-01 12:53:20 +00:00
void add_changed_extent_ref ( chunk * c , uint64_t address , uint64_t size , uint64_t root , uint64_t objid , uint64_t offset , uint32_t count , bool no_csum ) {
2016-10-29 17:05:10 +00:00
changed_extent * ce ;
changed_extent_ref * cer ;
LIST_ENTRY * le ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ce = get_changed_extent_item ( c , address , size , no_csum ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! ce ) {
ERR ( " get_changed_extent_item failed \n " ) ;
return ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = ce - > refs . Flink ;
while ( le ! = & ce - > refs ) {
cer = CONTAINING_RECORD ( le , changed_extent_ref , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( cer - > type = = TYPE_EXTENT_DATA_REF & & cer - > edr . root = = root & & cer - > edr . objid = = objid & & cer - > edr . offset = = offset ) {
ce - > count + = count ;
cer - > edr . count + = count ;
return ;
}
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
cer = ExAllocatePoolWithTag ( PagedPool , sizeof ( changed_extent_ref ) , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! cer ) {
ERR ( " out of memory \n " ) ;
return ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
cer - > type = TYPE_EXTENT_DATA_REF ;
cer - > edr . root = root ;
cer - > edr . objid = objid ;
cer - > edr . offset = offset ;
cer - > edr . count = count ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
InsertTailList ( & ce - > refs , & cer - > list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ce - > count + = count ;
2016-05-05 17:26:47 +00:00
}
2019-09-01 12:53:20 +00:00
uint64_t find_extent_shared_tree_refcount ( device_extension * Vcb , uint64_t address , uint64_t parent , PIRP Irp ) {
2016-05-05 17:26:47 +00:00
NTSTATUS Status ;
2016-07-27 19:24:26 +00:00
KEY searchkey ;
traverse_ptr tp ;
2019-09-01 12:53:20 +00:00
uint64_t inline_rc ;
2016-10-29 17:05:10 +00:00
EXTENT_ITEM * ei ;
2019-09-01 12:53:20 +00:00
uint32_t len ;
uint8_t * ptr ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
searchkey . obj_id = address ;
2016-10-29 17:05:10 +00:00
searchkey . obj_type = Vcb - > superblock . incompat_flags & BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA ? TYPE_METADATA_ITEM : TYPE_EXTENT_ITEM ;
2016-07-27 19:24:26 +00:00
searchkey . offset = 0xffffffffffffffff ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > extent_root , & tp , & searchkey , false , Irp ) ;
2016-05-05 17:26:47 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - find_item returned %08lx \n " , Status ) ;
2016-07-27 19:24:26 +00:00
return 0 ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( tp . item - > key . obj_id ! = searchkey . obj_id | | ( tp . item - > key . obj_type ! = TYPE_EXTENT_ITEM & & tp . item - > key . obj_type ! = TYPE_METADATA_ITEM ) ) {
2019-09-01 12:53:20 +00:00
TRACE ( " could not find address %I64x in extent tree \n " , address ) ;
2016-07-27 19:24:26 +00:00
return 0 ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( tp . item - > key . obj_type = = TYPE_EXTENT_ITEM & & tp . item - > key . offset ! = Vcb - > superblock . node_size ) {
2020-04-23 02:38:57 +00:00
ERR ( " extent %I64x had size %I64x, not %x as expected \n " , address , tp . item - > key . offset , Vcb - > superblock . node_size ) ;
2016-07-27 19:24:26 +00:00
return 0 ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( tp . item - > size < sizeof ( EXTENT_ITEM ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " (%I64x,%x,%I64x): size was %u, expected at least %Iu \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , tp . item - > size , sizeof ( EXTENT_ITEM ) ) ;
2016-10-29 17:05:10 +00:00
return 0 ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ei = ( EXTENT_ITEM * ) tp . item - > data ;
inline_rc = 0 ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
len = tp . item - > size - sizeof ( EXTENT_ITEM ) ;
2019-09-01 12:53:20 +00:00
ptr = ( uint8_t * ) & ei [ 1 ] ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( searchkey . obj_type = = TYPE_EXTENT_ITEM & & ei - > flags & EXTENT_ITEM_TREE_BLOCK ) {
if ( tp . item - > size < sizeof ( EXTENT_ITEM ) + sizeof ( EXTENT_ITEM2 ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " (%I64x,%x,%I64x): size was %u, expected at least %Iu \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset ,
tp . item - > size , sizeof ( EXTENT_ITEM ) + sizeof ( EXTENT_ITEM2 ) ) ;
2016-10-29 17:05:10 +00:00
return 0 ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
len - = sizeof ( EXTENT_ITEM2 ) ;
ptr + = sizeof ( EXTENT_ITEM2 ) ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
while ( len > 0 ) {
2019-09-01 12:53:20 +00:00
uint8_t secttype = * ptr ;
2016-10-29 17:05:10 +00:00
ULONG sectlen = get_extent_data_len ( secttype ) ;
2019-09-01 12:53:20 +00:00
uint64_t sectcount = get_extent_data_refcount ( secttype , ptr + sizeof ( uint8_t ) ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
len - - ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( sectlen > len ) {
2020-04-23 02:38:57 +00:00
ERR ( " (%I64x,%x,%I64x): %x bytes left, expecting at least %lx \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , len , sectlen ) ;
2016-10-29 17:05:10 +00:00
return 0 ;
}
2016-07-27 19:24:26 +00:00
2016-10-29 17:05:10 +00:00
if ( sectlen = = 0 ) {
2019-09-01 12:53:20 +00:00
ERR ( " (%I64x,%x,%I64x): unrecognized extent type %x \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , secttype ) ;
2016-10-29 17:05:10 +00:00
return 0 ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( secttype = = TYPE_SHARED_BLOCK_REF ) {
2019-09-01 12:53:20 +00:00
SHARED_BLOCK_REF * sectsbr = ( SHARED_BLOCK_REF * ) ( ptr + sizeof ( uint8_t ) ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( sectsbr - > offset = = parent )
return 1 ;
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
len - = sectlen ;
2019-09-01 12:53:20 +00:00
ptr + = sizeof ( uint8_t ) + sectlen ;
2016-10-29 17:05:10 +00:00
inline_rc + = sectcount ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
// FIXME - what if old?
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( inline_rc = = ei - > refcount )
return 0 ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
searchkey . obj_id = address ;
2016-10-29 17:05:10 +00:00
searchkey . obj_type = TYPE_SHARED_BLOCK_REF ;
searchkey . offset = parent ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > extent_root , & tp , & searchkey , false , Irp ) ;
2016-05-05 17:26:47 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - find_item returned %08lx \n " , Status ) ;
2016-07-27 19:24:26 +00:00
return 0 ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
if ( ! keycmp ( searchkey , tp . item - > key ) )
return 1 ;
2016-10-29 17:05:10 +00:00
return 0 ;
}
2019-09-01 12:53:20 +00:00
uint32_t find_extent_shared_data_refcount ( device_extension * Vcb , uint64_t address , uint64_t parent , PIRP Irp ) {
2016-10-29 17:05:10 +00:00
NTSTATUS Status ;
KEY searchkey ;
traverse_ptr tp ;
2019-09-01 12:53:20 +00:00
uint64_t inline_rc ;
2016-10-29 17:05:10 +00:00
EXTENT_ITEM * ei ;
2019-09-01 12:53:20 +00:00
uint32_t len ;
uint8_t * ptr ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
searchkey . obj_id = address ;
searchkey . obj_type = Vcb - > superblock . incompat_flags & BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA ? TYPE_METADATA_ITEM : TYPE_EXTENT_ITEM ;
searchkey . offset = 0xffffffffffffffff ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > extent_root , & tp , & searchkey , false , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - find_item returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return 0 ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( tp . item - > key . obj_id ! = searchkey . obj_id | | ( tp . item - > key . obj_type ! = TYPE_EXTENT_ITEM & & tp . item - > key . obj_type ! = TYPE_METADATA_ITEM ) ) {
2019-09-01 12:53:20 +00:00
TRACE ( " could not find address %I64x in extent tree \n " , address ) ;
2016-10-29 17:05:10 +00:00
return 0 ;
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( tp . item - > size < sizeof ( EXTENT_ITEM ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " (%I64x,%x,%I64x): size was %u, expected at least %Iu \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , tp . item - > size , sizeof ( EXTENT_ITEM ) ) ;
2016-10-29 17:05:10 +00:00
return 0 ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ei = ( EXTENT_ITEM * ) tp . item - > data ;
inline_rc = 0 ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
len = tp . item - > size - sizeof ( EXTENT_ITEM ) ;
2019-09-01 12:53:20 +00:00
ptr = ( uint8_t * ) & ei [ 1 ] ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
while ( len > 0 ) {
2019-09-01 12:53:20 +00:00
uint8_t secttype = * ptr ;
2016-10-29 17:05:10 +00:00
ULONG sectlen = get_extent_data_len ( secttype ) ;
2019-09-01 12:53:20 +00:00
uint64_t sectcount = get_extent_data_refcount ( secttype , ptr + sizeof ( uint8_t ) ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
len - - ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( sectlen > len ) {
2020-04-23 02:38:57 +00:00
ERR ( " (%I64x,%x,%I64x): %x bytes left, expecting at least %lx \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , len , sectlen ) ;
2016-07-27 19:24:26 +00:00
return 0 ;
}
2016-10-29 17:05:10 +00:00
if ( sectlen = = 0 ) {
2019-09-01 12:53:20 +00:00
ERR ( " (%I64x,%x,%I64x): unrecognized extent type %x \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , secttype ) ;
2016-07-27 19:24:26 +00:00
return 0 ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( secttype = = TYPE_SHARED_DATA_REF ) {
2019-09-01 12:53:20 +00:00
SHARED_DATA_REF * sectsdr = ( SHARED_DATA_REF * ) ( ptr + sizeof ( uint8_t ) ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( sectsdr - > offset = = parent )
return sectsdr - > count ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
len - = sectlen ;
2019-09-01 12:53:20 +00:00
ptr + = sizeof ( uint8_t ) + sectlen ;
2016-10-29 17:05:10 +00:00
inline_rc + = sectcount ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
// FIXME - what if old?
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( inline_rc = = ei - > refcount )
return 0 ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
searchkey . obj_id = address ;
searchkey . obj_type = TYPE_SHARED_DATA_REF ;
searchkey . offset = parent ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > extent_root , & tp , & searchkey , false , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - find_item returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
return 0 ;
}
2017-09-08 08:02:43 +00:00
if ( ! keycmp ( searchkey , tp . item - > key ) ) {
2019-09-01 12:53:20 +00:00
if ( tp . item - > size < sizeof ( uint32_t ) )
2020-04-23 02:38:57 +00:00
ERR ( " (%I64x,%x,%I64x) has size %u, not %Iu as expected \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , tp . item - > size , sizeof ( uint32_t ) ) ;
2016-10-29 17:05:10 +00:00
else {
2019-09-01 12:53:20 +00:00
uint32_t * count = ( uint32_t * ) tp . item - > data ;
2017-09-08 08:02:43 +00:00
return * count ;
2016-10-29 17:05:10 +00:00
}
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
return 0 ;
2016-05-05 17:26:47 +00:00
}