[BTRFS]
[reactos.git] / reactos / drivers / filesystems / btrfs / extent-tree.c
index 19b9232..8cd7000 100644 (file)
@@ -1,17 +1,17 @@
-/* Copyright (c) Mark Harmstone 2016
- * 
+/* Copyright (c) Mark Harmstone 2016-17
+ *
  * This file is part of WinBtrfs.
- * 
+ *
  * 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.
- * 
+ *
  * 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.
- * 
+ *
  * You should have received a copy of the GNU Lesser General Public Licence
  * along with WinBtrfs.  If not, see <http://www.gnu.org/licenses/>. */
 
 
 typedef struct {
     UINT8 type;
-    
+
     union {
         EXTENT_DATA_REF edr;
         SHARED_DATA_REF sdr;
         TREE_BLOCK_REF tbr;
         SHARED_BLOCK_REF sbr;
     };
-    
+
     UINT64 hash;
     LIST_ENTRY list_entry;
 } extent_ref;
 
-static __inline ULONG get_extent_data_len(UINT8 type) {
-    switch (type) {
-        case TYPE_TREE_BLOCK_REF:
-            return sizeof(TREE_BLOCK_REF);
-            
-        case TYPE_EXTENT_DATA_REF:
-            return sizeof(EXTENT_DATA_REF);
-            
-        case TYPE_EXTENT_REF_V0:
-            return sizeof(EXTENT_REF_V0);
-            
-        case TYPE_SHARED_BLOCK_REF:
-            return sizeof(SHARED_BLOCK_REF);
-            
-        case TYPE_SHARED_DATA_REF:
-            return sizeof(SHARED_DATA_REF);
-            
-        default:
-            return 0;
-    }
-}
-
-static __inline UINT64 get_extent_data_refcount(UINT8 type, void* data) {
-    switch (type) {
-        case TYPE_TREE_BLOCK_REF:
-            return 1;
-            
-        case TYPE_EXTENT_DATA_REF:
-        {
-            EXTENT_DATA_REF* edr = (EXTENT_DATA_REF*)data;
-            return edr->count;
-        }
-        
-        case TYPE_EXTENT_REF_V0:
-        {
-            EXTENT_REF_V0* erv0 = (EXTENT_REF_V0*)data;
-            return erv0->count;
-        }
-        
-        case TYPE_SHARED_BLOCK_REF:
-            return 1;
-        
-        case TYPE_SHARED_DATA_REF:
-        {
-            SHARED_DATA_REF* sdr = (SHARED_DATA_REF*)data;
-            return sdr->count;
-        }
-            
-        default:
-            return 0;
-    }
-}
-
 UINT64 get_extent_data_ref_hash2(UINT64 root, UINT64 objid, UINT64 offset) {
     UINT32 high_crc = 0xffffffff, low_crc = 0xffffffff;
 
     high_crc = calc_crc32c(high_crc, (UINT8*)&root, sizeof(UINT64));
     low_crc = calc_crc32c(low_crc, (UINT8*)&objid, sizeof(UINT64));
     low_crc = calc_crc32c(low_crc, (UINT8*)&offset, sizeof(UINT64));
-    
+
     return ((UINT64)high_crc << 31) ^ (UINT64)low_crc;
 }
 
@@ -120,7 +67,7 @@ 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);
-        
+
         ExFreePool(er);
     }
 }
@@ -128,167 +75,206 @@ static void free_extent_refs(LIST_ENTRY* extent_refs) {
 static NTSTATUS add_shared_data_extent_ref(LIST_ENTRY* extent_refs, UINT64 parent, UINT32 count) {
     extent_ref* er2;
     LIST_ENTRY* le;
-    
+
     if (!IsListEmpty(extent_refs)) {
         le = extent_refs->Flink;
-        
+
         while (le != extent_refs) {
             extent_ref* er = CONTAINING_RECORD(le, extent_ref, list_entry);
-            
+
             if (er->type == TYPE_SHARED_DATA_REF && er->sdr.offset == parent) {
                 er->sdr.count += count;
                 return STATUS_SUCCESS;
             }
-            
+
             le = le->Flink;
         }
     }
-    
+
     er2 = ExAllocatePoolWithTag(PagedPool, sizeof(extent_ref), ALLOC_TAG);
     if (!er2) {
         ERR("out of memory\n");
         return STATUS_INSUFFICIENT_RESOURCES;
     }
-    
+
     er2->type = TYPE_SHARED_DATA_REF;
     er2->sdr.offset = parent;
     er2->sdr.count = count;
-    
+
     InsertTailList(extent_refs, &er2->list_entry);
-    
+
     return STATUS_SUCCESS;
 }
 
 static NTSTATUS add_shared_block_extent_ref(LIST_ENTRY* extent_refs, UINT64 parent) {
     extent_ref* er2;
     LIST_ENTRY* le;
-    
+
     if (!IsListEmpty(extent_refs)) {
         le = extent_refs->Flink;
-        
+
         while (le != extent_refs) {
             extent_ref* er = CONTAINING_RECORD(le, extent_ref, list_entry);
-            
+
             if (er->type == TYPE_SHARED_BLOCK_REF && er->sbr.offset == parent)
                 return STATUS_SUCCESS;
-            
+
             le = le->Flink;
         }
     }
-    
+
     er2 = ExAllocatePoolWithTag(PagedPool, sizeof(extent_ref), ALLOC_TAG);
     if (!er2) {
         ERR("out of memory\n");
         return STATUS_INSUFFICIENT_RESOURCES;
     }
-    
+
     er2->type = TYPE_SHARED_BLOCK_REF;
     er2->sbr.offset = parent;
-    
+
     InsertTailList(extent_refs, &er2->list_entry);
-    
+
     return STATUS_SUCCESS;
 }
 
 static NTSTATUS add_tree_block_extent_ref(LIST_ENTRY* extent_refs, UINT64 root) {
     extent_ref* er2;
     LIST_ENTRY* le;
-    
+
     if (!IsListEmpty(extent_refs)) {
         le = extent_refs->Flink;
-        
+
         while (le != extent_refs) {
             extent_ref* er = CONTAINING_RECORD(le, extent_ref, list_entry);
-            
+
             if (er->type == TYPE_TREE_BLOCK_REF && er->tbr.offset == root)
                 return STATUS_SUCCESS;
-            
+
             le = le->Flink;
         }
     }
-    
+
     er2 = ExAllocatePoolWithTag(PagedPool, sizeof(extent_ref), ALLOC_TAG);
     if (!er2) {
         ERR("out of memory\n");
         return STATUS_INSUFFICIENT_RESOURCES;
     }
-    
+
     er2->type = TYPE_TREE_BLOCK_REF;
     er2->tbr.offset = root;
-    
+
     InsertTailList(extent_refs, &er2->list_entry);
-    
+
     return STATUS_SUCCESS;
 }
 
+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;
+        BOOL inserted = FALSE;
+
+        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);
+                inserted = TRUE;
+                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;
+}
+
 static NTSTATUS construct_extent_item(device_extension* Vcb, UINT64 address, UINT64 size, UINT64 flags, LIST_ENTRY* extent_refs,
-                                      KEY* firstitem, UINT8 level, PIRP Irp, LIST_ENTRY* rollback) {
+                                      KEY* firstitem, UINT8 level, PIRP Irp) {
+    NTSTATUS Status;
     LIST_ENTRY *le, *next_le;
     UINT64 refcount;
-    ULONG inline_len;
+    UINT16 inline_len;
     BOOL all_inline = TRUE;
-    extent_ref* first_noninline;
+    extent_ref* first_noninline = NULL;
     EXTENT_ITEM* ei;
     UINT8* siptr;
-    
+
     // FIXME - write skinny extents if is tree and incompat flag set
-    
+
     if (IsListEmpty(extent_refs)) {
         WARN("no extent refs found\n");
         return STATUS_SUCCESS;
     }
-    
+
     refcount = 0;
     inline_len = sizeof(EXTENT_ITEM);
-    
+
     if (flags & EXTENT_ITEM_TREE_BLOCK)
         inline_len += sizeof(EXTENT_ITEM2);
-    
+
     le = extent_refs->Flink;
     while (le != extent_refs) {
         extent_ref* er = CONTAINING_RECORD(le, extent_ref, list_entry);
         UINT64 rc;
-        
+
         next_le = le->Flink;
-        
+
         rc = get_extent_data_refcount(er->type, &er->edr);
-        
+
         if (rc == 0) {
             RemoveEntryList(&er->list_entry);
-            
+
             ExFreePool(er);
         } else {
-            ULONG extlen = get_extent_data_len(er->type);
-            
+            UINT16 extlen = get_extent_data_len(er->type);
+
             refcount += rc;
-            
+
             er->hash = get_extent_hash(er->type, &er->edr);
-            
+
             if (all_inline) {
-                if (inline_len + 1 + extlen > Vcb->superblock.node_size / 4) {
+                if ((UINT16)(inline_len + 1 + extlen) > Vcb->superblock.node_size >> 2) {
                     all_inline = FALSE;
                     first_noninline = er;
                 } else
                     inline_len += extlen + 1;
             }
         }
-        
+
         le = next_le;
     }
-    
+
     ei = ExAllocatePoolWithTag(PagedPool, inline_len, ALLOC_TAG);
     if (!ei) {
         ERR("out of memory\n");
         return STATUS_INSUFFICIENT_RESOURCES;
     }
-    
+
     ei->refcount = refcount;
     ei->generation = Vcb->superblock.generation;
     ei->flags = flags;
-    
+
     if (flags & EXTENT_ITEM_TREE_BLOCK) {
         EXTENT_ITEM2* ei2 = (EXTENT_ITEM2*)&ei[1];
-        
+
         if (firstitem) {
             ei2->firstitem.obj_id = firstitem->obj_id;
             ei2->firstitem.obj_type = firstitem->obj_type;
@@ -298,106 +284,128 @@ static NTSTATUS construct_extent_item(device_extension* Vcb, UINT64 address, UIN
             ei2->firstitem.obj_type = 0;
             ei2->firstitem.offset = 0;
         }
-        
+
         ei2->level = level;
-        
+
         siptr = (UINT8*)&ei2[1];
     } else
         siptr = (UINT8*)&ei[1];
-    
-    // Do we need to sort the inline extent refs? The Linux driver doesn't seem to bother.
-    
+
+    sort_extent_refs(extent_refs);
+
     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);
-        
+
         if (!all_inline && er == first_noninline)
             break;
-        
+
         *siptr = er->type;
         siptr++;
-        
+
         if (extlen > 0) {
             RtlCopyMemory(siptr, &er->edr, extlen);
             siptr += extlen;
         }
-         
+
         le = le->Flink;
     }
-    
-    if (!insert_tree_item(Vcb, Vcb->extent_root, address, TYPE_EXTENT_ITEM, size, ei, inline_len, NULL, Irp, rollback)) {
-        ERR("error - failed to insert item\n");
+
+    Status = insert_tree_item(Vcb, Vcb->extent_root, address, TYPE_EXTENT_ITEM, size, ei, inline_len, NULL, Irp);
+    if (!NT_SUCCESS(Status)) {
+        ERR("insert_tree_item returned %08x\n", Status);
         ExFreePool(ei);
-        return STATUS_INTERNAL_ERROR;
+        return Status;
     }
-    
+
     if (!all_inline) {
         le = &first_noninline->list_entry;
-        
+
         while (le != extent_refs) {
             extent_ref* er = CONTAINING_RECORD(le, extent_ref, list_entry);
-            ULONG len = get_extent_data_len(er->type);
+            UINT16 len;
             UINT8* data;
-            
-            if (len > 0) {
+
+            if (er->type == TYPE_EXTENT_DATA_REF) {
+                len = sizeof(EXTENT_DATA_REF);
+
                 data = ExAllocatePoolWithTag(PagedPool, len, ALLOC_TAG);
-                
+
                 if (!data) {
                     ERR("out of memory\n");
                     return STATUS_INSUFFICIENT_RESOURCES;
                 }
-                
+
                 RtlCopyMemory(data, &er->edr, len);
-            } else
+            } else if (er->type == TYPE_SHARED_DATA_REF) {
+                len = sizeof(UINT32);
+
+                data = ExAllocatePoolWithTag(PagedPool, len, ALLOC_TAG);
+
+                if (!data) {
+                    ERR("out of memory\n");
+                    return STATUS_INSUFFICIENT_RESOURCES;
+                }
+
+                *((UINT32*)data) = er->sdr.count;
+            } else {
+                len = 0;
                 data = NULL;
-            
-            if (!insert_tree_item(Vcb, Vcb->extent_root, address, er->type, er->hash, data, len, NULL, Irp, rollback)) {
-                ERR("error - failed to insert item\n");
-                return STATUS_INTERNAL_ERROR;
             }
-            
+
+            Status = insert_tree_item(Vcb, Vcb->extent_root, address, er->type, er->hash, data, len, NULL, Irp);
+            if (!NT_SUCCESS(Status)) {
+                ERR("insert_tree_item returned %08x\n", Status);
+                if (data) ExFreePool(data);
+                return Status;
+            }
+
             le = le->Flink;
         }
     }
-    
+
     return STATUS_SUCCESS;
 }
 
-static NTSTATUS convert_old_extent(device_extension* Vcb, UINT64 address, BOOL tree, KEY* firstitem, UINT8 level, PIRP Irp, LIST_ENTRY* rollback) {
+static NTSTATUS convert_old_extent(device_extension* Vcb, UINT64 address, BOOL tree, KEY* firstitem, UINT8 level, PIRP Irp) {
     NTSTATUS Status;
     KEY searchkey;
     traverse_ptr tp, next_tp;
     LIST_ENTRY extent_refs;
     UINT64 size;
-    
+
     InitializeListHead(&extent_refs);
-    
+
     searchkey.obj_id = address;
     searchkey.obj_type = TYPE_EXTENT_ITEM;
     searchkey.offset = 0xffffffffffffffff;
-    
+
     Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE, Irp);
     if (!NT_SUCCESS(Status)) {
         ERR("find_item returned %08x\n", Status);
         return Status;
     }
-    
+
     if (tp.item->key.obj_id != searchkey.obj_id || tp.item->key.obj_type != searchkey.obj_type) {
         ERR("old-style extent %llx not found\n", address);
         return STATUS_INTERNAL_ERROR;
     }
-    
+
     size = tp.item->key.offset;
-    
-    delete_tree_item(Vcb, &tp, rollback);
-    
+
+    Status = delete_tree_item(Vcb, &tp);
+    if (!NT_SUCCESS(Status)) {
+        ERR("delete_tree_item returned %08x\n", Status);
+        return Status;
+    }
+
     while (find_next_item(Vcb, &tp, &next_tp, FALSE, Irp)) {
         tp = next_tp;
-        
+
         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;
-            
+
             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);
@@ -419,8 +427,12 @@ static NTSTATUS convert_old_extent(device_extension* Vcb, UINT64 address, BOOL t
                     goto end;
                 }
             }
-            
-            delete_tree_item(Vcb, &tp, rollback);
+
+            Status = delete_tree_item(Vcb, &tp);
+            if (!NT_SUCCESS(Status)) {
+                ERR("delete_tree_item returned %08x\n", Status);
+                goto end;
+            }
         }
 
         if (tp.item->key.obj_id > address || tp.item->key.obj_type > TYPE_EXTENT_REF_V0)
@@ -428,21 +440,22 @@ static NTSTATUS convert_old_extent(device_extension* Vcb, UINT64 address, BOOL t
     }
 
     Status = construct_extent_item(Vcb, address, size, tree ? (EXTENT_ITEM_TREE_BLOCK | EXTENT_ITEM_SHARED_BACKREFS) : EXTENT_ITEM_DATA,
-                                   &extent_refs, firstitem, level, Irp, rollback);
+                                   &extent_refs, firstitem, level, Irp);
     if (!NT_SUCCESS(Status))
         ERR("construct_extent_item returned %08x\n", Status);
 
 end:
     free_extent_refs(&extent_refs);
-    
+
     return Status;
 }
 
-NTSTATUS increase_extent_refcount(device_extension* Vcb, UINT64 address, UINT64 size, UINT8 type, void* data, KEY* firstitem, UINT8 level, PIRP Irp, LIST_ENTRY* rollback) {
+NTSTATUS increase_extent_refcount(device_extension* Vcb, UINT64 address, UINT64 size, UINT8 type, void* data, KEY* firstitem, UINT8 level, PIRP Irp) {
     NTSTATUS Status;
     KEY searchkey;
     traverse_ptr tp;
-    ULONG datalen = get_extent_data_len(type), len, max_extent_item_size;
+    ULONG len, max_extent_item_size;
+    UINT16 datalen = get_extent_data_len(type);
     EXTENT_ITEM* ei;
     UINT8* ptr;
     UINT64 inline_rc, offset;
@@ -450,65 +463,61 @@ NTSTATUS increase_extent_refcount(device_extension* Vcb, UINT64 address, UINT64
     EXTENT_ITEM* newei;
     BOOL skinny;
     BOOL is_tree = type == TYPE_TREE_BLOCK_REF || type == TYPE_SHARED_BLOCK_REF;
-    
+
     if (datalen == 0) {
         ERR("unrecognized extent type %x\n", type);
         return STATUS_INTERNAL_ERROR;
     }
-    
+
     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;
-    
+
     Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE, Irp);
     if (!NT_SUCCESS(Status)) {
         ERR("error - find_item returned %08x\n", Status);
         return Status;
     }
-    
+
     // If entry doesn't exist yet, create new inline extent item
-    
+
     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)) {
-        ULONG eisize;
-        EXTENT_ITEM* ei;
-        UINT8* ptr;
-        
+        UINT16 eisize;
+
         eisize = sizeof(EXTENT_ITEM);
         if (is_tree && !(Vcb->superblock.incompat_flags & BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA)) eisize += sizeof(EXTENT_ITEM2);
         eisize += sizeof(UINT8);
         eisize += datalen;
-        
+
         ei = ExAllocatePoolWithTag(PagedPool, eisize, ALLOC_TAG);
         if (!ei) {
             ERR("out of memory\n");
             return STATUS_INSUFFICIENT_RESOURCES;
         }
-        
+
         ei->refcount = get_extent_data_refcount(type, data);
         ei->generation = Vcb->superblock.generation;
         ei->flags = is_tree ? EXTENT_ITEM_TREE_BLOCK : EXTENT_ITEM_DATA;
         ptr = (UINT8*)&ei[1];
-        
+
         if (is_tree && !(Vcb->superblock.incompat_flags & BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA)) {
             EXTENT_ITEM2* ei2 = (EXTENT_ITEM2*)ptr;
             ei2->firstitem = *firstitem;
             ei2->level = level;
             ptr = (UINT8*)&ei2[1];
         }
-        
+
         *ptr = type;
         RtlCopyMemory(ptr + 1, data, datalen);
-        
-        if (Vcb->superblock.incompat_flags & BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA && is_tree) {
-            if (!insert_tree_item(Vcb, Vcb->extent_root, address, TYPE_METADATA_ITEM, level, ei, eisize, NULL, Irp, rollback)) {
-                ERR("insert_tree_item failed\n");
-                return STATUS_INTERNAL_ERROR;
-            }
-        } else {
-            if (!insert_tree_item(Vcb, Vcb->extent_root, address, TYPE_EXTENT_ITEM, size, ei, eisize, NULL, Irp, rollback)) {
-                ERR("insert_tree_item failed\n");
-                return STATUS_INTERNAL_ERROR;
-            }
+
+        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)) {
+            ERR("insert_tree_item returned %08x\n", Status);
+            return Status;
         }
 
         return STATUS_SUCCESS;
@@ -520,47 +529,47 @@ NTSTATUS increase_extent_refcount(device_extension* Vcb, UINT64 address, UINT64
     skinny = tp.item->key.obj_type == TYPE_METADATA_ITEM;
 
     if (tp.item->size == sizeof(EXTENT_ITEM_V0) && !skinny) {
-        Status = convert_old_extent(Vcb, address, is_tree, firstitem, level, Irp, rollback);
-        
+        Status = convert_old_extent(Vcb, address, is_tree, firstitem, level, Irp);
+
         if (!NT_SUCCESS(Status)) {
             ERR("convert_old_extent returned %08x\n", Status);
             return Status;
         }
 
-        return increase_extent_refcount(Vcb, address, size, type, data, firstitem, level, Irp, rollback);
+        return increase_extent_refcount(Vcb, address, size, type, data, firstitem, level, Irp);
     }
-        
+
     if (tp.item->size < sizeof(EXTENT_ITEM)) {
         ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(EXTENT_ITEM));
         return STATUS_INTERNAL_ERROR;
     }
-    
+
     ei = (EXTENT_ITEM*)tp.item->data;
-    
+
     len = tp.item->size - sizeof(EXTENT_ITEM);
     ptr = (UINT8*)&ei[1];
-    
+
     if (ei->flags & EXTENT_ITEM_TREE_BLOCK && !skinny) {
         if (tp.item->size < sizeof(EXTENT_ITEM) + sizeof(EXTENT_ITEM2)) {
             ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(EXTENT_ITEM) + sizeof(EXTENT_ITEM2));
             return STATUS_INTERNAL_ERROR;
         }
-        
+
         len -= sizeof(EXTENT_ITEM2);
         ptr += sizeof(EXTENT_ITEM2);
     }
-    
+
     inline_rc = 0;
-    
+
     // Loop through existing inline extent entries
-    
+
     while (len > 0) {
         UINT8 secttype = *ptr;
         ULONG sectlen = get_extent_data_len(secttype);
         UINT64 sectcount = get_extent_data_refcount(secttype, ptr + sizeof(UINT8));
-        
+
         len--;
-        
+
         if (sectlen > len) {
             ERR("(%llx,%x,%llx): %x bytes left, expecting at least %x\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, len, sectlen);
             return STATUS_INTERNAL_ERROR;
@@ -570,44 +579,49 @@ NTSTATUS increase_extent_refcount(device_extension* Vcb, UINT64 address, UINT64
             ERR("(%llx,%x,%llx): unrecognized extent type %x\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, secttype);
             return STATUS_INTERNAL_ERROR;
         }
-        
+
         // If inline extent already present, increase refcount and return
-        
+
         if (secttype == type) {
             if (type == TYPE_EXTENT_DATA_REF) {
                 EXTENT_DATA_REF* sectedr = (EXTENT_DATA_REF*)(ptr + sizeof(UINT8));
                 EXTENT_DATA_REF* edr = (EXTENT_DATA_REF*)data;
-                
+
                 if (sectedr->root == edr->root && sectedr->objid == edr->objid && sectedr->offset == edr->offset) {
                     UINT32 rc = get_extent_data_refcount(type, data);
                     EXTENT_DATA_REF* sectedr2;
-                    
+
                     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;
-                    
+
                     sectedr2 = (EXTENT_DATA_REF*)((UINT8*)newei + ((UINT8*)sectedr - tp.item->data));
                     sectedr2->count += rc;
-                    
-                    delete_tree_item(Vcb, &tp, rollback);
-                    
-                    if (!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, rollback)) {
-                        ERR("insert_tree_item failed\n");
-                        return STATUS_INTERNAL_ERROR;
+
+                    Status = delete_tree_item(Vcb, &tp);
+                    if (!NT_SUCCESS(Status)) {
+                        ERR("delete_tree_item returned %08x\n", Status);
+                        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)) {
+                        ERR("insert_tree_item returned %08x\n", Status);
+                        return Status;
                     }
-                    
+
                     return STATUS_SUCCESS;
                 }
             } else if (type == TYPE_TREE_BLOCK_REF) {
                 TREE_BLOCK_REF* secttbr = (TREE_BLOCK_REF*)(ptr + sizeof(UINT8));
                 TREE_BLOCK_REF* tbr = (TREE_BLOCK_REF*)data;
-                
+
                 if (secttbr->offset == tbr->offset) {
                     TRACE("trying to increase refcount of non-shared tree extent\n");
                     return STATUS_SUCCESS;
@@ -615,37 +629,42 @@ NTSTATUS increase_extent_refcount(device_extension* Vcb, UINT64 address, UINT64
             } else if (type == TYPE_SHARED_BLOCK_REF) {
                 SHARED_BLOCK_REF* sectsbr = (SHARED_BLOCK_REF*)(ptr + sizeof(UINT8));
                 SHARED_BLOCK_REF* sbr = (SHARED_BLOCK_REF*)data;
-                
+
                 if (sectsbr->offset == sbr->offset)
                     return STATUS_SUCCESS;
             } else if (type == TYPE_SHARED_DATA_REF) {
                 SHARED_DATA_REF* sectsdr = (SHARED_DATA_REF*)(ptr + sizeof(UINT8));
                 SHARED_DATA_REF* sdr = (SHARED_DATA_REF*)data;
-                
+
                 if (sectsdr->offset == sdr->offset) {
                     UINT32 rc = get_extent_data_refcount(type, data);
                     SHARED_DATA_REF* sectsdr2;
-                    
+
                     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;
-                    
+
                     sectsdr2 = (SHARED_DATA_REF*)((UINT8*)newei + ((UINT8*)sectsdr - tp.item->data));
                     sectsdr2->count += rc;
-                    
-                    delete_tree_item(Vcb, &tp, rollback);
-                    
-                    if (!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, rollback)) {
-                        ERR("insert_tree_item failed\n");
-                        return STATUS_INTERNAL_ERROR;
+
+                    Status = delete_tree_item(Vcb, &tp);
+                    if (!NT_SUCCESS(Status)) {
+                        ERR("delete_tree_item returned %08x\n", Status);
+                        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)) {
+                        ERR("insert_tree_item returned %08x\n", Status);
+                        return Status;
                     }
-                    
+
                     return STATUS_SUCCESS;
                 }
             } else {
@@ -653,95 +672,111 @@ NTSTATUS increase_extent_refcount(device_extension* Vcb, UINT64 address, UINT64
                 return STATUS_INTERNAL_ERROR;
             }
         }
-        
+
         len -= sectlen;
         ptr += sizeof(UINT8) + sectlen;
         inline_rc += sectcount;
     }
-    
+
     offset = get_extent_hash(type, data);
-    
+
     max_extent_item_size = (Vcb->superblock.node_size >> 4) - sizeof(leaf_node);
-    
+
     // If we can, add entry as inline extent item
-    
+
     if (inline_rc == ei->refcount && tp.item->size + sizeof(UINT8) + datalen < max_extent_item_size) {
         len = tp.item->size - sizeof(EXTENT_ITEM);
         ptr = (UINT8*)&ei[1];
-        
+
         if (ei->flags & EXTENT_ITEM_TREE_BLOCK && !skinny) {
             len -= sizeof(EXTENT_ITEM2);
             ptr += sizeof(EXTENT_ITEM2);
         }
 
+        // Confusingly, it appears that references are sorted forward by type (i.e. EXTENT_DATA_REFs before
+        // SHARED_DATA_REFs), but then backwards by hash...
+
         while (len > 0) {
             UINT8 secttype = *ptr;
             ULONG sectlen = get_extent_data_len(secttype);
-            
+
             if (secttype > type)
                 break;
-            
+
             if (secttype == type) {
                 UINT64 sectoff = get_extent_hash(secttype, ptr + 1);
-                
-                if (sectoff > offset)
+
+                if (sectoff < offset)
                     break;
             }
-            
+
             len -= sectlen + sizeof(UINT8);
             ptr += sizeof(UINT8) + sectlen;
         }
-        
+
         newei = ExAllocatePoolWithTag(PagedPool, tp.item->size + sizeof(UINT8) + datalen, ALLOC_TAG);
         RtlCopyMemory(newei, tp.item->data, ptr - tp.item->data);
-        
+
         newei->refcount += get_extent_data_refcount(type, data);
-        
+
         if (len > 0)
             RtlCopyMemory((UINT8*)newei + (ptr - tp.item->data) + sizeof(UINT8) + datalen, ptr, len);
-        
+
         ptr = (ptr - tp.item->data) + (UINT8*)newei;
-        
+
         *ptr = type;
         RtlCopyMemory(ptr + 1, data, datalen);
-        
-        delete_tree_item(Vcb, &tp, rollback);
-        
-        if (!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) + datalen, NULL, Irp, rollback)) {
-            ERR("insert_tree_item failed\n");
-            return STATUS_INTERNAL_ERROR;
+
+        Status = delete_tree_item(Vcb, &tp);
+        if (!NT_SUCCESS(Status)) {
+            ERR("delete_tree_item returned %08x\n", Status);
+            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 + sizeof(UINT8) + datalen, NULL, Irp);
+        if (!NT_SUCCESS(Status)) {
+            ERR("insert_tree_item returned %08x\n", Status);
+            return Status;
+        }
+
         return STATUS_SUCCESS;
     }
-    
+
     // Look for existing non-inline entry, and increase refcount if found
-    
+
     if (inline_rc != ei->refcount) {
         traverse_ptr tp2;
-        
+
         searchkey.obj_id = address;
         searchkey.obj_type = type;
         searchkey.offset = offset;
-        
+
         Status = find_item(Vcb, Vcb->extent_root, &tp2, &searchkey, FALSE, Irp);
         if (!NT_SUCCESS(Status)) {
             ERR("error - find_item returned %08x\n", Status);
             return Status;
         }
-        
+
         if (!keycmp(tp2.item->key, searchkey)) {
-            if (tp2.item->size < datalen) {
+            if (type == TYPE_SHARED_DATA_REF && tp2.item->size < sizeof(UINT32)) {
+                ERR("(%llx,%x,%llx) was %x bytes, expecting %x\n", tp2.item->key.obj_id, tp2.item->key.obj_type, tp2.item->key.offset, tp2.item->size, sizeof(UINT32));
+                return STATUS_INTERNAL_ERROR;
+            } else if (type != TYPE_SHARED_DATA_REF && tp2.item->size < datalen) {
                 ERR("(%llx,%x,%llx) was %x bytes, expecting %x\n", tp2.item->key.obj_id, tp2.item->key.obj_type, tp2.item->key.offset, tp2.item->size, datalen);
                 return STATUS_INTERNAL_ERROR;
             }
-            
+
             data2 = ExAllocatePoolWithTag(PagedPool, tp2.item->size, ALLOC_TAG);
+            if (!data2) {
+                ERR("out of memory\n");
+                return STATUS_INSUFFICIENT_RESOURCES;
+            }
+
             RtlCopyMemory(data2, tp2.item->data, tp2.item->size);
-            
+
             if (type == TYPE_EXTENT_DATA_REF) {
                 EXTENT_DATA_REF* edr = (EXTENT_DATA_REF*)data2;
-                
+
                 edr->count += get_extent_data_refcount(type, data);
             } else if (type == TYPE_TREE_BLOCK_REF) {
                 TRACE("trying to increase refcount of non-shared tree extent\n");
@@ -749,81 +784,123 @@ NTSTATUS increase_extent_refcount(device_extension* Vcb, UINT64 address, UINT64
             } else if (type == TYPE_SHARED_BLOCK_REF)
                 return STATUS_SUCCESS;
             else if (type == TYPE_SHARED_DATA_REF) {
-                SHARED_DATA_REF* sdr = (SHARED_DATA_REF*)data2;
-                
-                sdr->count += get_extent_data_refcount(type, data);
+                UINT32* sdr = (UINT32*)data2;
+
+                *sdr += get_extent_data_refcount(type, data);
             } else {
                 ERR("unhandled extent type %x\n", type);
                 return STATUS_INTERNAL_ERROR;
             }
-            
-            delete_tree_item(Vcb, &tp2, rollback);
-            
-            if (!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, rollback)) {
-                ERR("insert_tree_item failed\n");
-                return STATUS_INTERNAL_ERROR;
+
+            Status = delete_tree_item(Vcb, &tp2);
+            if (!NT_SUCCESS(Status)) {
+                ERR("delete_tree_item returned %08x\n", Status);
+                return Status;
             }
-            
+
+            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)) {
+                ERR("insert_tree_item returned %08x\n", Status);
+                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 += get_extent_data_refcount(type, data);
-            
-            delete_tree_item(Vcb, &tp, rollback);
-            
-            if (!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, rollback)) {
-                ERR("insert_tree_item failed\n");
-                return STATUS_INTERNAL_ERROR;
+
+            Status = delete_tree_item(Vcb, &tp);
+            if (!NT_SUCCESS(Status)) {
+                ERR("delete_tree_item returned %08x\n", Status);
+                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)) {
+                ERR("insert_tree_item returned %08x\n", Status);
+                return Status;
+            }
+
             return STATUS_SUCCESS;
         }
     }
-    
+
     // Otherwise, add new non-inline entry
-    
-    data2 = ExAllocatePoolWithTag(PagedPool, datalen, ALLOC_TAG);
-    RtlCopyMemory(data2, data, datalen);
-    
-    if (!insert_tree_item(Vcb, Vcb->extent_root, address, type, offset, data2, datalen, NULL, Irp, rollback)) {
-        ERR("insert_tree_item failed\n");
-        return STATUS_INTERNAL_ERROR;
+
+    if (type == TYPE_SHARED_DATA_REF) {
+        SHARED_DATA_REF* sdr = (SHARED_DATA_REF*)data;
+
+        data2 = ExAllocatePoolWithTag(PagedPool, sizeof(UINT32), ALLOC_TAG);
+        if (!data2) {
+            ERR("out of memory\n");
+            return STATUS_INSUFFICIENT_RESOURCES;
+        }
+
+        datalen = sizeof(UINT32);
+
+        *((UINT32*)data2) = sdr->count;
+    } 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);
     }
-    
+
+    Status = insert_tree_item(Vcb, Vcb->extent_root, address, type, offset, data2, datalen, NULL, Irp);
+    if (!NT_SUCCESS(Status)) {
+        ERR("insert_tree_item returned %08x\n", Status);
+        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 += get_extent_data_refcount(type, data);
-    
-    delete_tree_item(Vcb, &tp, rollback);
-    
-    if (!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, rollback)) {
-        ERR("insert_tree_item failed\n");
-        return STATUS_INTERNAL_ERROR;
+
+    Status = delete_tree_item(Vcb, &tp);
+    if (!NT_SUCCESS(Status)) {
+        ERR("delete_tree_item returned %08x\n", Status);
+        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)) {
+        ERR("insert_tree_item returned %08x\n", Status);
+        return Status;
+    }
+
     return STATUS_SUCCESS;
 }
 
-NTSTATUS increase_extent_refcount_data(device_extension* Vcb, UINT64 address, UINT64 size, UINT64 root, UINT64 inode, UINT64 offset, UINT32 refcount, PIRP Irp, LIST_ENTRY* rollback) {
+NTSTATUS increase_extent_refcount_data(device_extension* Vcb, UINT64 address, UINT64 size, UINT64 root, UINT64 inode, UINT64 offset, UINT32 refcount, PIRP Irp) {
     EXTENT_DATA_REF edr;
-    
+
     edr.root = root;
     edr.objid = inode;
     edr.offset = offset;
     edr.count = refcount;
-    
-    return increase_extent_refcount(Vcb, address, size, TYPE_EXTENT_DATA_REF, &edr, NULL, 0, Irp, rollback);
-}
 
-void decrease_chunk_usage(chunk* c, UINT64 delta) {
-    c->used -= delta;
-    
-    TRACE("decreasing size of chunk %llx by %llx\n", c->offset, delta);
+    return increase_extent_refcount(Vcb, address, size, TYPE_EXTENT_DATA_REF, &edr, NULL, 0, Irp);
 }
 
 NTSTATUS decrease_extent_refcount(device_extension* Vcb, UINT64 address, UINT64 size, UINT8 type, void* data, KEY* firstitem,
-                                  UINT8 level, UINT64 parent, BOOL superseded, PIRP Irp, LIST_ENTRY* rollback) {
+                                  UINT8 level, UINT64 parent, BOOL superseded, PIRP Irp) {
     KEY searchkey;
     NTSTATUS Status;
     traverse_ptr tp, tp2;
@@ -834,91 +911,91 @@ NTSTATUS decrease_extent_refcount(device_extension* Vcb, UINT64 address, UINT64
     UINT32 rc = data ? get_extent_data_refcount(type, data) : 1;
     ULONG datalen = get_extent_data_len(type);
     BOOL is_tree = (type == TYPE_TREE_BLOCK_REF || type == TYPE_SHARED_BLOCK_REF), skinny = FALSE;
-    
+
     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;
-        
+
         Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE, Irp);
         if (!NT_SUCCESS(Status)) {
             ERR("error - find_item returned %08x\n", Status);
             return Status;
         }
-        
+
         if (tp.item->key.obj_id == searchkey.obj_id && tp.item->key.obj_type == searchkey.obj_type)
             skinny = TRUE;
     }
-    
+
     if (!skinny) {
         searchkey.obj_id = address;
         searchkey.obj_type = TYPE_EXTENT_ITEM;
         searchkey.offset = 0xffffffffffffffff;
-        
+
         Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE, Irp);
         if (!NT_SUCCESS(Status)) {
             ERR("error - find_item returned %08x\n", Status);
             return Status;
         }
-        
+
         if (tp.item->key.obj_id != searchkey.obj_id || tp.item->key.obj_type != searchkey.obj_type) {
             ERR("could not find EXTENT_ITEM for address %llx\n", address);
             return STATUS_INTERNAL_ERROR;
         }
-        
+
         if (tp.item->key.offset != size) {
             ERR("extent %llx had length %llx, not %llx as expected\n", address, tp.item->key.offset, size);
             return STATUS_INTERNAL_ERROR;
         }
-        
+
         if (tp.item->size == sizeof(EXTENT_ITEM_V0)) {
-            Status = convert_old_extent(Vcb, address, is_tree, firstitem, level, Irp, rollback);
-            
+            Status = convert_old_extent(Vcb, address, is_tree, firstitem, level, Irp);
+
             if (!NT_SUCCESS(Status)) {
                 ERR("convert_old_extent returned %08x\n", Status);
                 return Status;
             }
 
-            return decrease_extent_refcount(Vcb, address, size, type, data, firstitem, level, parent, superseded, Irp, rollback);
+            return decrease_extent_refcount(Vcb, address, size, type, data, firstitem, level, parent, superseded, Irp);
         }
     }
-    
+
     if (tp.item->size < sizeof(EXTENT_ITEM)) {
         ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(EXTENT_ITEM));
         return STATUS_INTERNAL_ERROR;
     }
-    
+
     ei = (EXTENT_ITEM*)tp.item->data;
-    
+
     len = tp.item->size - sizeof(EXTENT_ITEM);
     ptr = (UINT8*)&ei[1];
-    
+
     if (ei->flags & EXTENT_ITEM_TREE_BLOCK && !skinny) {
         if (tp.item->size < sizeof(EXTENT_ITEM) + sizeof(EXTENT_ITEM2)) {
             ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(EXTENT_ITEM) + sizeof(EXTENT_ITEM2));
             return STATUS_INTERNAL_ERROR;
         }
-        
+
         len -= sizeof(EXTENT_ITEM2);
         ptr += sizeof(EXTENT_ITEM2);
     }
-    
+
     if (ei->refcount < rc) {
         ERR("error - extent has refcount %llx, trying to reduce by %x\n", ei->refcount, rc);
         return STATUS_INTERNAL_ERROR;
     }
-    
+
     inline_rc = 0;
-    
+
     // Loop through inline extent entries
-    
+
     while (len > 0) {
         UINT8 secttype = *ptr;
-        ULONG sectlen = get_extent_data_len(secttype);
+        UINT16 sectlen = get_extent_data_len(secttype);
         UINT64 sectcount = get_extent_data_refcount(secttype, ptr + sizeof(UINT8));
-        
+
         len--;
-        
+
         if (sectlen > len) {
             ERR("(%llx,%x,%llx): %x bytes left, expecting at least %x\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, len, sectlen);
             return STATUS_INTERNAL_ERROR;
@@ -928,190 +1005,232 @@ NTSTATUS decrease_extent_refcount(device_extension* Vcb, UINT64 address, UINT64
             ERR("(%llx,%x,%llx): unrecognized extent type %x\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, secttype);
             return STATUS_INTERNAL_ERROR;
         }
-        
+
         if (secttype == type) {
             if (type == TYPE_EXTENT_DATA_REF) {
                 EXTENT_DATA_REF* sectedr = (EXTENT_DATA_REF*)(ptr + sizeof(UINT8));
                 EXTENT_DATA_REF* edr = (EXTENT_DATA_REF*)data;
-                ULONG neweilen;
-                EXTENT_ITEM* newei;
-                
+
                 if (sectedr->root == edr->root && sectedr->objid == edr->objid && sectedr->offset == edr->offset) {
+                    UINT16 neweilen;
+                    EXTENT_ITEM* newei;
+
                     if (ei->refcount == edr->count) {
-                        delete_tree_item(Vcb, &tp, rollback);
-                        
+                        Status = delete_tree_item(Vcb, &tp);
+                        if (!NT_SUCCESS(Status)) {
+                            ERR("delete_tree_item returned %08x\n", Status);
+                            return Status;
+                        }
+
                         if (!superseded)
-                            add_checksum_entry(Vcb, address, size / Vcb->superblock.sector_size, NULL, Irp, rollback);
-                        
+                            add_checksum_entry(Vcb, address, (ULONG)(size / Vcb->superblock.sector_size), NULL, Irp);
+
                         return STATUS_SUCCESS;
                     }
-                    
+
                     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;
                     }
-                    
+
                     if (sectedr->count > edr->count)    // reduce section refcount
                         neweilen = tp.item->size;
                     else                                // remove section entirely
                         neweilen = tp.item->size - sizeof(UINT8) - sectlen;
-                    
+
                     newei = ExAllocatePoolWithTag(PagedPool, neweilen, ALLOC_TAG);
                     if (!newei) {
                         ERR("out of memory\n");
                         return STATUS_INSUFFICIENT_RESOURCES;
                     }
-                    
+
                     if (sectedr->count > edr->count) {
                         EXTENT_DATA_REF* newedr = (EXTENT_DATA_REF*)((UINT8*)newei + ((UINT8*)sectedr - tp.item->data));
-                        
+
                         RtlCopyMemory(newei, ei, neweilen);
-                        
+
                         newedr->count -= rc;
                     } else {
                         RtlCopyMemory(newei, ei, ptr - tp.item->data);
-                        
+
                         if (len > sectlen)
                             RtlCopyMemory((UINT8*)newei + (ptr - tp.item->data), ptr + sectlen + sizeof(UINT8), len - sectlen);
                     }
-                    
+
                     newei->refcount -= rc;
-                    
-                    delete_tree_item(Vcb, &tp, rollback);
-                    
-                    if (!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, rollback)) {
-                        ERR("insert_tree_item failed\n");
-                        return STATUS_INTERNAL_ERROR;
+
+                    Status = delete_tree_item(Vcb, &tp);
+                    if (!NT_SUCCESS(Status)) {
+                        ERR("delete_tree_item returned %08x\n", Status);
+                        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)) {
+                        ERR("insert_tree_item returned %08x\n", Status);
+                        return Status;
+                    }
+
                     return STATUS_SUCCESS;
                 }
             } else if (type == TYPE_SHARED_DATA_REF) {
                 SHARED_DATA_REF* sectsdr = (SHARED_DATA_REF*)(ptr + sizeof(UINT8));
                 SHARED_DATA_REF* sdr = (SHARED_DATA_REF*)data;
-                ULONG neweilen;
-                EXTENT_ITEM* newei;
-                
+
                 if (sectsdr->offset == sdr->offset) {
+                    EXTENT_ITEM* newei;
+                    UINT16 neweilen;
+
                     if (ei->refcount == sectsdr->count) {
-                        delete_tree_item(Vcb, &tp, rollback);
-                        
+                        Status = delete_tree_item(Vcb, &tp);
+                        if (!NT_SUCCESS(Status)) {
+                            ERR("delete_tree_item returned %08x\n", Status);
+                            return Status;
+                        }
+
                         if (!superseded)
-                            add_checksum_entry(Vcb, address, size / Vcb->superblock.sector_size, NULL, Irp, rollback);
-                        
+                            add_checksum_entry(Vcb, address, (ULONG)(size / Vcb->superblock.sector_size), NULL, Irp);
+
                         return STATUS_SUCCESS;
                     }
-                    
+
                     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;
                     }
-                    
+
                     if (sectsdr->count > sdr->count)    // reduce section refcount
                         neweilen = tp.item->size;
                     else                                // remove section entirely
                         neweilen = tp.item->size - sizeof(UINT8) - sectlen;
-                    
+
                     newei = ExAllocatePoolWithTag(PagedPool, neweilen, ALLOC_TAG);
                     if (!newei) {
                         ERR("out of memory\n");
                         return STATUS_INSUFFICIENT_RESOURCES;
                     }
-                    
+
                     if (sectsdr->count > sdr->count) {
                         SHARED_DATA_REF* newsdr = (SHARED_DATA_REF*)((UINT8*)newei + ((UINT8*)sectsdr - tp.item->data));
-                        
+
                         RtlCopyMemory(newei, ei, neweilen);
-                        
+
                         newsdr->count -= rc;
                     } else {
                         RtlCopyMemory(newei, ei, ptr - tp.item->data);
-                        
+
                         if (len > sectlen)
                             RtlCopyMemory((UINT8*)newei + (ptr - tp.item->data), ptr + sectlen + sizeof(UINT8), len - sectlen);
                     }
 
                     newei->refcount -= rc;
-                    
-                    delete_tree_item(Vcb, &tp, rollback);
-                    
-                    if (!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, rollback)) {
-                        ERR("insert_tree_item failed\n");
-                        return STATUS_INTERNAL_ERROR;
+
+                    Status = delete_tree_item(Vcb, &tp);
+                    if (!NT_SUCCESS(Status)) {
+                        ERR("delete_tree_item returned %08x\n", Status);
+                        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)) {
+                        ERR("insert_tree_item returned %08x\n", Status);
+                        return Status;
+                    }
+
                     return STATUS_SUCCESS;
                 }
             } else if (type == TYPE_TREE_BLOCK_REF) {
                 TREE_BLOCK_REF* secttbr = (TREE_BLOCK_REF*)(ptr + sizeof(UINT8));
                 TREE_BLOCK_REF* tbr = (TREE_BLOCK_REF*)data;
-                ULONG neweilen;
-                EXTENT_ITEM* newei;
-                
+
                 if (secttbr->offset == tbr->offset) {
+                    EXTENT_ITEM* newei;
+                    UINT16 neweilen;
+
                     if (ei->refcount == 1) {
-                        delete_tree_item(Vcb, &tp, rollback);
+                        Status = delete_tree_item(Vcb, &tp);
+                        if (!NT_SUCCESS(Status)) {
+                            ERR("delete_tree_item returned %08x\n", Status);
+                            return Status;
+                        }
+
                         return STATUS_SUCCESS;
                     }
 
                     neweilen = tp.item->size - sizeof(UINT8) - sectlen;
-                    
+
                     newei = ExAllocatePoolWithTag(PagedPool, neweilen, ALLOC_TAG);
                     if (!newei) {
                         ERR("out of memory\n");
                         return STATUS_INSUFFICIENT_RESOURCES;
                     }
-                    
+
                     RtlCopyMemory(newei, ei, ptr - tp.item->data);
-                    
+
                     if (len > sectlen)
                         RtlCopyMemory((UINT8*)newei + (ptr - tp.item->data), ptr + sectlen + sizeof(UINT8), len - sectlen);
-                    
+
                     newei->refcount--;
-                    
-                    delete_tree_item(Vcb, &tp, rollback);
-                    
-                    if (!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, rollback)) {
-                        ERR("insert_tree_item failed\n");
-                        return STATUS_INTERNAL_ERROR;
+
+                    Status = delete_tree_item(Vcb, &tp);
+                    if (!NT_SUCCESS(Status)) {
+                        ERR("delete_tree_item returned %08x\n", Status);
+                        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)) {
+                        ERR("insert_tree_item returned %08x\n", Status);
+                        return Status;
+                    }
+
                     return STATUS_SUCCESS;
                 }
             } else if (type == TYPE_SHARED_BLOCK_REF) {
                 SHARED_BLOCK_REF* sectsbr = (SHARED_BLOCK_REF*)(ptr + sizeof(UINT8));
                 SHARED_BLOCK_REF* sbr = (SHARED_BLOCK_REF*)data;
-                ULONG neweilen;
-                EXTENT_ITEM* newei;
-                
+
                 if (sectsbr->offset == sbr->offset) {
+                    EXTENT_ITEM* newei;
+                    UINT16 neweilen;
+
                     if (ei->refcount == 1) {
-                        delete_tree_item(Vcb, &tp, rollback);
+                        Status = delete_tree_item(Vcb, &tp);
+                        if (!NT_SUCCESS(Status)) {
+                            ERR("delete_tree_item returned %08x\n", Status);
+                            return Status;
+                        }
+
                         return STATUS_SUCCESS;
                     }
-                    
+
                     neweilen = tp.item->size - sizeof(UINT8) - sectlen;
-                    
+
                     newei = ExAllocatePoolWithTag(PagedPool, neweilen, ALLOC_TAG);
                     if (!newei) {
                         ERR("out of memory\n");
                         return STATUS_INSUFFICIENT_RESOURCES;
                     }
-                    
+
                     RtlCopyMemory(newei, ei, ptr - tp.item->data);
-                    
+
                     if (len > sectlen)
                         RtlCopyMemory((UINT8*)newei + (ptr - tp.item->data), ptr + sectlen + sizeof(UINT8), len - sectlen);
-                    
+
                     newei->refcount--;
-                    
-                    delete_tree_item(Vcb, &tp, rollback);
-                    
-                    if (!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, rollback)) {
-                        ERR("insert_tree_item failed\n");
-                        return STATUS_INTERNAL_ERROR;
+
+                    Status = delete_tree_item(Vcb, &tp);
+                    if (!NT_SUCCESS(Status)) {
+                        ERR("delete_tree_item returned %08x\n", Status);
+                        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)) {
+                        ERR("insert_tree_item returned %08x\n", Status);
+                        return Status;
                     }
-                    
+
                     return STATUS_SUCCESS;
                 }
             } else {
@@ -1119,268 +1238,305 @@ NTSTATUS decrease_extent_refcount(device_extension* Vcb, UINT64 address, UINT64
                 return STATUS_INTERNAL_ERROR;
             }
         }
-        
+
         len -= sectlen;
         ptr += sizeof(UINT8) + sectlen;
         inline_rc += sectcount;
     }
-    
+
     if (inline_rc == ei->refcount) {
         ERR("entry not found in inline extent item for address %llx\n", address);
         return STATUS_INTERNAL_ERROR;
     }
-    
+
+    if (type == TYPE_SHARED_DATA_REF)
+        datalen = sizeof(UINT32);
+    else if (type == TYPE_TREE_BLOCK_REF || type == TYPE_SHARED_BLOCK_REF)
+        datalen = 0;
+
     searchkey.obj_id = address;
     searchkey.obj_type = type;
     searchkey.offset = (type == TYPE_SHARED_DATA_REF || type == TYPE_EXTENT_REF_V0) ? parent : get_extent_hash(type, data);
-    
+
     Status = find_item(Vcb, Vcb->extent_root, &tp2, &searchkey, FALSE, Irp);
     if (!NT_SUCCESS(Status)) {
         ERR("error - find_item returned %08x\n", Status);
         return Status;
     }
-    
+
     if (keycmp(tp2.item->key, searchkey)) {
         ERR("(%llx,%x,%llx) not found\n", tp2.item->key.obj_id, tp2.item->key.obj_type, tp2.item->key.offset);
         return STATUS_INTERNAL_ERROR;
     }
-    
+
     if (tp2.item->size < datalen) {
-        ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, datalen);
+        ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp2.item->key.obj_id, tp2.item->key.obj_type, tp2.item->key.offset, tp2.item->size, datalen);
         return STATUS_INTERNAL_ERROR;
     }
-    
+
     if (type == TYPE_EXTENT_DATA_REF) {
         EXTENT_DATA_REF* sectedr = (EXTENT_DATA_REF*)tp2.item->data;
         EXTENT_DATA_REF* edr = (EXTENT_DATA_REF*)data;
-        EXTENT_ITEM* newei;
-        
+
         if (sectedr->root == edr->root && sectedr->objid == edr->objid && sectedr->offset == edr->offset) {
+            EXTENT_ITEM* newei;
+
             if (ei->refcount == edr->count) {
-                delete_tree_item(Vcb, &tp, rollback);
-                delete_tree_item(Vcb, &tp2, rollback);
-                
+                Status = delete_tree_item(Vcb, &tp);
+                if (!NT_SUCCESS(Status)) {
+                    ERR("delete_tree_item returned %08x\n", Status);
+                    return Status;
+                }
+
+                Status = delete_tree_item(Vcb, &tp2);
+                if (!NT_SUCCESS(Status)) {
+                    ERR("delete_tree_item returned %08x\n", Status);
+                    return Status;
+                }
+
                 if (!superseded)
-                    add_checksum_entry(Vcb, address, size / Vcb->superblock.sector_size, NULL, Irp, rollback);
-                
+                    add_checksum_entry(Vcb, address, (ULONG)(size / Vcb->superblock.sector_size), NULL, Irp);
+
                 return STATUS_SUCCESS;
             }
-            
+
             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;
             }
-            
-            delete_tree_item(Vcb, &tp2, rollback);
-            
+
+            Status = delete_tree_item(Vcb, &tp2);
+            if (!NT_SUCCESS(Status)) {
+                ERR("delete_tree_item returned %08x\n", Status);
+                return Status;
+            }
+
             if (sectedr->count > edr->count) {
                 EXTENT_DATA_REF* newedr = ExAllocatePoolWithTag(PagedPool, tp2.item->size, ALLOC_TAG);
-                
+
                 if (!newedr) {
                     ERR("out of memory\n");
                     return STATUS_INSUFFICIENT_RESOURCES;
                 }
-                
+
                 RtlCopyMemory(newedr, sectedr, tp2.item->size);
-                
+
                 newedr->count -= edr->count;
-                
-                if (!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, rollback)) {
-                    ERR("insert_tree_item failed\n");
-                    return STATUS_INTERNAL_ERROR;
+
+                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)) {
+                    ERR("insert_tree_item returned %08x\n", Status);
+                    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;
-            
-            delete_tree_item(Vcb, &tp, rollback);
-            
-            if (!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, rollback)) {
-                ERR("insert_tree_item failed\n");
-                return STATUS_INTERNAL_ERROR;
+
+            Status = delete_tree_item(Vcb, &tp);
+            if (!NT_SUCCESS(Status)) {
+                ERR("delete_tree_item returned %08x\n", Status);
+                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)) {
+                ERR("insert_tree_item returned %08x\n", Status);
+                return Status;
             }
-            
+
             return STATUS_SUCCESS;
         } else {
             ERR("error - hash collision?\n");
             return STATUS_INTERNAL_ERROR;
         }
     } else if (type == TYPE_SHARED_DATA_REF) {
-        SHARED_DATA_REF* sectsdr = (SHARED_DATA_REF*)tp2.item->data;
         SHARED_DATA_REF* sdr = (SHARED_DATA_REF*)data;
-        EXTENT_ITEM* newei;
-        
-        if (sectsdr->offset == sdr->offset) {
+
+        if (tp2.item->key.offset == sdr->offset) {
+            UINT32* sectsdrcount = (UINT32*)tp2.item->data;
+            EXTENT_ITEM* newei;
+
             if (ei->refcount == sdr->count) {
-                delete_tree_item(Vcb, &tp, rollback);
-                delete_tree_item(Vcb, &tp2, rollback);
-                
+                Status = delete_tree_item(Vcb, &tp);
+                if (!NT_SUCCESS(Status)) {
+                    ERR("delete_tree_item returned %08x\n", Status);
+                    return Status;
+                }
+
+                Status = delete_tree_item(Vcb, &tp2);
+                if (!NT_SUCCESS(Status)) {
+                    ERR("delete_tree_item returned %08x\n", Status);
+                    return Status;
+                }
+
                 if (!superseded)
-                    add_checksum_entry(Vcb, address, size / Vcb->superblock.sector_size, NULL, Irp, rollback);
-                
+                    add_checksum_entry(Vcb, address, (ULONG)(size / Vcb->superblock.sector_size), NULL, Irp);
+
                 return STATUS_SUCCESS;
             }
-            
-            if (sectsdr->count < sdr->count) {
-                ERR("error - extent section has refcount %x, trying to reduce by %x\n", sectsdr->count, sdr->count);
+
+            if (*sectsdrcount < sdr->count) {
+                ERR("error - extent section has refcount %x, trying to reduce by %x\n", *sectsdrcount, sdr->count);
                 return STATUS_INTERNAL_ERROR;
             }
-            
-            delete_tree_item(Vcb, &tp2, rollback);
-            
-            if (sectsdr->count > sdr->count) {
-                SHARED_DATA_REF* newsdr = ExAllocatePoolWithTag(PagedPool, tp2.item->size, ALLOC_TAG);
-                
+
+            Status = delete_tree_item(Vcb, &tp2);
+            if (!NT_SUCCESS(Status)) {
+                ERR("delete_tree_item returned %08x\n", Status);
+                return Status;
+            }
+
+            if (*sectsdrcount > sdr->count) {
+                UINT32* newsdr = ExAllocatePoolWithTag(PagedPool, tp2.item->size, ALLOC_TAG);
+
                 if (!newsdr) {
                     ERR("out of memory\n");
                     return STATUS_INSUFFICIENT_RESOURCES;
                 }
-                
-                RtlCopyMemory(newsdr, sectsdr, tp2.item->size);
-                
-                newsdr->count -= sdr->count;
-                
-                if (!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, rollback)) {
-                    ERR("insert_tree_item failed\n");
-                    return STATUS_INTERNAL_ERROR;
-                }
-            }
-            
-            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;
-            
-            delete_tree_item(Vcb, &tp, rollback);
-            
-            if (!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, rollback)) {
-                ERR("insert_tree_item failed\n");
-                return STATUS_INTERNAL_ERROR;
-            }
-            
-            return STATUS_SUCCESS;
-        } else {
-            ERR("error - collision?\n");
-            return STATUS_INTERNAL_ERROR;
-        }
-    } else if (type == TYPE_SHARED_BLOCK_REF) {
-        SHARED_BLOCK_REF* sectsbr = (SHARED_BLOCK_REF*)tp2.item->data;
-        SHARED_BLOCK_REF* sbr = (SHARED_BLOCK_REF*)data;
-        EXTENT_ITEM* newei;
-        
-        if (sectsbr->offset == sbr->offset) {
-            if (ei->refcount == 1) {
-                delete_tree_item(Vcb, &tp, rollback);
-                delete_tree_item(Vcb, &tp2, rollback);
-                return STATUS_SUCCESS;
+                *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)) {
+                    ERR("insert_tree_item returned %08x\n", Status);
+                    return Status;
+                }
             }
-            
-            delete_tree_item(Vcb, &tp2, rollback);
-            
+
             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;
-            
-            delete_tree_item(Vcb, &tp, rollback);
-            
-            if (!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, rollback)) {
-                ERR("insert_tree_item failed\n");
-                return STATUS_INTERNAL_ERROR;
+
+            Status = delete_tree_item(Vcb, &tp);
+            if (!NT_SUCCESS(Status)) {
+                ERR("delete_tree_item returned %08x\n", Status);
+                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)) {
+                ERR("insert_tree_item returned %08x\n", Status);
+                return Status;
             }
-            
+
             return STATUS_SUCCESS;
         } else {
             ERR("error - collision?\n");
             return STATUS_INTERNAL_ERROR;
         }
-    } else if (type == TYPE_TREE_BLOCK_REF) {
-        TREE_BLOCK_REF* secttbr = (TREE_BLOCK_REF*)tp2.item->data;
-        TREE_BLOCK_REF* tbr = (TREE_BLOCK_REF*)data;
+    } else if (type == TYPE_TREE_BLOCK_REF || type == TYPE_SHARED_BLOCK_REF) {
         EXTENT_ITEM* newei;
-        
-        if (secttbr->offset == tbr->offset) {
-            if (ei->refcount == 1) {
-                delete_tree_item(Vcb, &tp, rollback);
-                delete_tree_item(Vcb, &tp2, rollback);
-                return STATUS_SUCCESS;
-            }
-            
-            delete_tree_item(Vcb, &tp2, rollback);
-            
-            newei = ExAllocatePoolWithTag(PagedPool, tp.item->size, ALLOC_TAG);
-            if (!newei) {
-                ERR("out of memory\n");
-                return STATUS_INSUFFICIENT_RESOURCES;
+
+        if (ei->refcount == 1) {
+            Status = delete_tree_item(Vcb, &tp);
+            if (!NT_SUCCESS(Status)) {
+                ERR("delete_tree_item returned %08x\n", Status);
+                return Status;
             }
-            
-            RtlCopyMemory(newei, tp.item->data, tp.item->size);
 
-            newei->refcount -= rc;
-            
-            delete_tree_item(Vcb, &tp, rollback);
-            
-            if (!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, rollback)) {
-                ERR("insert_tree_item failed\n");
-                return STATUS_INTERNAL_ERROR;
+            Status = delete_tree_item(Vcb, &tp2);
+            if (!NT_SUCCESS(Status)) {
+                ERR("delete_tree_item returned %08x\n", Status);
+                return Status;
             }
-            
+
             return STATUS_SUCCESS;
-        } else {
-            ERR("error - collision?\n");
-            return STATUS_INTERNAL_ERROR;
         }
+
+        Status = delete_tree_item(Vcb, &tp2);
+        if (!NT_SUCCESS(Status)) {
+            ERR("delete_tree_item returned %08x\n", Status);
+            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)) {
+            ERR("delete_tree_item returned %08x\n", Status);
+            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)) {
+            ERR("insert_tree_item returned %08x\n", Status);
+            return Status;
+        }
+
+        return STATUS_SUCCESS;
     } else if (type == TYPE_EXTENT_REF_V0) {
         EXTENT_REF_V0* erv0 = (EXTENT_REF_V0*)tp2.item->data;
         EXTENT_ITEM* newei;
-        
+
         if (ei->refcount == erv0->count) {
-            delete_tree_item(Vcb, &tp, rollback);
-            delete_tree_item(Vcb, &tp2, rollback);
-            
+            Status = delete_tree_item(Vcb, &tp);
+            if (!NT_SUCCESS(Status)) {
+                ERR("delete_tree_item returned %08x\n", Status);
+                return Status;
+            }
+
+            Status = delete_tree_item(Vcb, &tp2);
+            if (!NT_SUCCESS(Status)) {
+                ERR("delete_tree_item returned %08x\n", Status);
+                return Status;
+            }
+
             if (!superseded)
-                add_checksum_entry(Vcb, address, size / Vcb->superblock.sector_size, NULL, Irp, rollback);
-            
+                add_checksum_entry(Vcb, address, (ULONG)(size / Vcb->superblock.sector_size), NULL, Irp);
+
             return STATUS_SUCCESS;
         }
-        
-        delete_tree_item(Vcb, &tp2, rollback);
-        
+
+        Status = delete_tree_item(Vcb, &tp2);
+        if (!NT_SUCCESS(Status)) {
+            ERR("delete_tree_item returned %08x\n", Status);
+            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;
-        
-        delete_tree_item(Vcb, &tp, rollback);
-        
-        if (!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, rollback)) {
-            ERR("insert_tree_item failed\n");
-            return STATUS_INTERNAL_ERROR;
+
+        Status = delete_tree_item(Vcb, &tp);
+        if (!NT_SUCCESS(Status)) {
+            ERR("delete_tree_item returned %08x\n", Status);
+            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)) {
+            ERR("insert_tree_item returned %08x\n", Status);
+            return Status;
         }
-        
+
         return STATUS_SUCCESS;
     } else {
         ERR("unhandled extent type %x\n", type);
@@ -1389,64 +1545,63 @@ NTSTATUS decrease_extent_refcount(device_extension* Vcb, UINT64 address, UINT64
 }
 
 NTSTATUS decrease_extent_refcount_data(device_extension* Vcb, UINT64 address, UINT64 size, UINT64 root, UINT64 inode,
-                                       UINT64 offset, UINT32 refcount, BOOL superseded, PIRP Irp, LIST_ENTRY* rollback) {
+                                       UINT64 offset, UINT32 refcount, BOOL superseded, PIRP Irp) {
     EXTENT_DATA_REF edr;
-    
+
     edr.root = root;
     edr.objid = inode;
     edr.offset = offset;
     edr.count = refcount;
-    
-    return decrease_extent_refcount(Vcb, address, size, TYPE_EXTENT_DATA_REF, &edr, NULL, 0, 0, superseded, Irp, rollback);
+
+    return decrease_extent_refcount(Vcb, address, size, TYPE_EXTENT_DATA_REF, &edr, NULL, 0, 0, superseded, Irp);
 }
 
 NTSTATUS decrease_extent_refcount_tree(device_extension* Vcb, UINT64 address, UINT64 size, UINT64 root,
-                                       UINT8 level, PIRP Irp, LIST_ENTRY* rollback) {
+                                       UINT8 level, PIRP Irp) {
     TREE_BLOCK_REF tbr;
-    
+
     tbr.offset = root;
-    
-    return decrease_extent_refcount(Vcb, address, size, TYPE_TREE_BLOCK_REF, &tbr, NULL/*FIXME*/, level, 0, FALSE, Irp, rollback);
+
+    return decrease_extent_refcount(Vcb, address, size, TYPE_TREE_BLOCK_REF, &tbr, NULL/*FIXME*/, level, 0, FALSE, Irp);
 }
 
-static UINT64 find_extent_data_refcount(device_extension* Vcb, UINT64 address, UINT64 size, UINT64 root, UINT64 objid, UINT64 offset, PIRP Irp) {
+static UINT32 find_extent_data_refcount(device_extension* Vcb, UINT64 address, UINT64 size, UINT64 root, UINT64 objid, UINT64 offset, PIRP Irp) {
     NTSTATUS Status;
     KEY searchkey;
     traverse_ptr tp;
-    EXTENT_DATA_REF* edr;
-    
+
     searchkey.obj_id = address;
     searchkey.obj_type = TYPE_EXTENT_ITEM;
     searchkey.offset = 0xffffffffffffffff;
-    
+
     Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE, Irp);
     if (!NT_SUCCESS(Status)) {
         ERR("error - find_item returned %08x\n", Status);
         return 0;
     }
-    
+
     if (tp.item->key.obj_id != searchkey.obj_id || tp.item->key.obj_type != searchkey.obj_type) {
         TRACE("could not find address %llx in extent tree\n", address);
         return 0;
     }
-    
+
     if (tp.item->key.offset != size) {
         ERR("extent %llx had size %llx, not %llx as expected\n", address, tp.item->key.offset, size);
         return 0;
     }
-    
+
     if (tp.item->size >= sizeof(EXTENT_ITEM)) {
         EXTENT_ITEM* ei = (EXTENT_ITEM*)tp.item->data;
         UINT32 len = tp.item->size - sizeof(EXTENT_ITEM);
         UINT8* ptr = (UINT8*)&ei[1];
-        
+
         while (len > 0) {
             UINT8 secttype = *ptr;
             ULONG sectlen = get_extent_data_len(secttype);
-            UINT64 sectcount = get_extent_data_refcount(secttype, ptr + sizeof(UINT8));
-            
+            UINT32 sectcount = get_extent_data_refcount(secttype, ptr + sizeof(UINT8));
+
             len--;
-            
+
             if (sectlen > len) {
                 ERR("(%llx,%x,%llx): %x bytes left, expecting at least %x\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, len, sectlen);
                 return 0;
@@ -1456,39 +1611,39 @@ static UINT64 find_extent_data_refcount(device_extension* Vcb, UINT64 address, U
                 ERR("(%llx,%x,%llx): unrecognized extent type %x\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, secttype);
                 return 0;
             }
-            
+
             if (secttype == TYPE_EXTENT_DATA_REF) {
                 EXTENT_DATA_REF* sectedr = (EXTENT_DATA_REF*)(ptr + sizeof(UINT8));
-                
+
                 if (sectedr->root == root && sectedr->objid == objid && sectedr->offset == offset)
                     return sectcount;
             }
-            
+
             len -= sectlen;
             ptr += sizeof(UINT8) + sectlen;
         }
     }
-    
+
     searchkey.obj_id = address;
     searchkey.obj_type = TYPE_EXTENT_DATA_REF;
     searchkey.offset = get_extent_data_ref_hash2(root, objid, offset);
-    
+
     Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE, Irp);
     if (!NT_SUCCESS(Status)) {
         ERR("error - find_item returned %08x\n", Status);
         return 0;
     }
-    
-    if (!keycmp(searchkey, tp.item->key)) {    
+
+    if (!keycmp(searchkey, tp.item->key)) {
         if (tp.item->size < sizeof(EXTENT_DATA_REF))
             ERR("(%llx,%x,%llx) has size %u, not %u as expected\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(EXTENT_DATA_REF));
-        else {    
-            edr = (EXTENT_DATA_REF*)tp.item->data;
-            
+        else {
+            EXTENT_DATA_REF* edr = (EXTENT_DATA_REF*)tp.item->data;
+
             return edr->count;
         }
     }
-    
+
     return 0;
 }
 
@@ -1497,24 +1652,24 @@ UINT64 get_extent_refcount(device_extension* Vcb, UINT64 address, UINT64 size, P
     traverse_ptr tp;
     NTSTATUS Status;
     EXTENT_ITEM* ei;
-    
+
     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;
-    
+
     Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE, Irp);
     if (!NT_SUCCESS(Status)) {
         ERR("error - find_item returned %08x\n", Status);
         return 0;
     }
-    
+
     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;
-    
+
         return ei->refcount;
     }
-    
+
     if (tp.item->key.obj_id != address || tp.item->key.obj_type != TYPE_EXTENT_ITEM) {
         ERR("couldn't find (%llx,%x,%llx) in extent tree\n", address, TYPE_EXTENT_ITEM, size);
         return 0;
@@ -1522,19 +1677,19 @@ UINT64 get_extent_refcount(device_extension* Vcb, UINT64 address, UINT64 size, P
         ERR("extent %llx had size %llx, not %llx as expected\n", address, tp.item->key.offset, size);
         return 0;
     }
-    
+
     if (tp.item->size == sizeof(EXTENT_ITEM_V0)) {
         EXTENT_ITEM_V0* eiv0 = (EXTENT_ITEM_V0*)tp.item->data;
-        
+
         return eiv0->refcount;
     } else if (tp.item->size < sizeof(EXTENT_ITEM)) {
         ERR("(%llx,%x,%llx) was %x bytes, expected at least %x\n", tp.item->key.obj_id, tp.item->key.obj_type,
-                                                                       tp.item->key.offset, tp.item->size, sizeof(EXTENT_DATA));
+                                                                       tp.item->key.offset, tp.item->size, sizeof(EXTENT_ITEM));
         return 0;
     }
-    
+
     ei = (EXTENT_ITEM*)tp.item->data;
-    
+
     return ei->refcount;
 }
 
@@ -1542,69 +1697,69 @@ BOOL is_extent_unique(device_extension* Vcb, UINT64 address, UINT64 size, PIRP I
     KEY searchkey;
     traverse_ptr tp, next_tp;
     NTSTATUS Status;
-    UINT64 rc, rcrun, root = 0, inode = 0;
+    UINT64 rc, rcrun, root = 0, inode = 0, offset = 0;
     UINT32 len;
     EXTENT_ITEM* ei;
     UINT8* ptr;
     BOOL b;
-    
+
     rc = get_extent_refcount(Vcb, address, size, Irp);
 
     if (rc == 1)
         return TRUE;
-    
+
     if (rc == 0)
         return FALSE;
-    
+
     searchkey.obj_id = address;
     searchkey.obj_type = TYPE_EXTENT_ITEM;
     searchkey.offset = size;
-    
+
     Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE, Irp);
     if (!NT_SUCCESS(Status)) {
         WARN("error - find_item returned %08x\n", Status);
         return FALSE;
     }
-    
+
     if (keycmp(tp.item->key, searchkey)) {
         WARN("could not find (%llx,%x,%llx)\n", searchkey.obj_id, searchkey.obj_type, searchkey.offset);
         return FALSE;
     }
-    
+
     if (tp.item->size == sizeof(EXTENT_ITEM_V0))
         return FALSE;
-    
+
     if (tp.item->size < sizeof(EXTENT_ITEM)) {
         WARN("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(EXTENT_ITEM));
         return FALSE;
     }
-    
+
     ei = (EXTENT_ITEM*)tp.item->data;
-    
+
     len = tp.item->size - sizeof(EXTENT_ITEM);
     ptr = (UINT8*)&ei[1];
-    
+
     if (ei->flags & EXTENT_ITEM_TREE_BLOCK) {
         if (tp.item->size < sizeof(EXTENT_ITEM) + sizeof(EXTENT_ITEM2)) {
             WARN("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(EXTENT_ITEM) + sizeof(EXTENT_ITEM2));
             return FALSE;
         }
-        
+
         len -= sizeof(EXTENT_ITEM2);
         ptr += sizeof(EXTENT_ITEM2);
     }
-    
+
     rcrun = 0;
-    
+
     // Loop through inline extent entries
-    
+
     while (len > 0) {
         UINT8 secttype = *ptr;
         ULONG sectlen = get_extent_data_len(secttype);
         UINT64 sectcount = get_extent_data_refcount(secttype, ptr + sizeof(UINT8));
-        
+
         len--;
-        
+
         if (sectlen > len) {
             WARN("(%llx,%x,%llx): %x bytes left, expecting at least %x\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, len, sectlen);
             return FALSE;
@@ -1614,63 +1769,65 @@ BOOL is_extent_unique(device_extension* Vcb, UINT64 address, UINT64 size, PIRP I
             WARN("(%llx,%x,%llx): unrecognized extent type %x\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, secttype);
             return FALSE;
         }
-        
+
         if (secttype == TYPE_EXTENT_DATA_REF) {
             EXTENT_DATA_REF* sectedr = (EXTENT_DATA_REF*)(ptr + sizeof(UINT8));
-            
+
             if (root == 0 && inode == 0) {
                 root = sectedr->root;
                 inode = sectedr->objid;
-            } else if (root != sectedr->root || inode != sectedr->objid)
+                offset = sectedr->offset;
+            } else if (root != sectedr->root || inode != sectedr->objid || offset != sectedr->offset)
                 return FALSE;
         } else
             return FALSE;
-        
+
         len -= sectlen;
         ptr += sizeof(UINT8) + sectlen;
         rcrun += sectcount;
     }
-    
+
     if (rcrun == rc)
         return TRUE;
 
     // Loop through non-inlines if some refs still unaccounted for
-    
+
     do {
         b = find_next_item(Vcb, &tp, &next_tp, FALSE, Irp);
-        
+
         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;
-            
+
             if (tp.item->size < sizeof(EXTENT_DATA_REF)) {
                 WARN("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset,
                      tp.item->size, sizeof(EXTENT_ITEM) + sizeof(EXTENT_ITEM2));
                 return FALSE;
             }
-            
+
             if (root == 0 && inode == 0) {
                 root = edr->root;
                 inode = edr->objid;
-            } else if (root != edr->root || inode != edr->objid)
+                offset = edr->offset;
+            } else if (root != edr->root || inode != edr->objid || offset != edr->offset)
                 return FALSE;
-            
+
             rcrun += edr->count;
         }
-        
+
         if (rcrun == rc)
             return TRUE;
-        
+
         if (b) {
             tp = next_tp;
-            
+
             if (tp.item->key.obj_id > searchkey.obj_id)
                 break;
         }
     } while (b);
-    
+
     // If we reach this point, there's still some refs unaccounted for somewhere.
     // Return FALSE in case we mess things up elsewhere.
-    
+
     return FALSE;
 }
 
@@ -1679,39 +1836,39 @@ UINT64 get_extent_flags(device_extension* Vcb, UINT64 address, PIRP Irp) {
     traverse_ptr tp;
     NTSTATUS Status;
     EXTENT_ITEM* ei;
-    
+
     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;
-    
+
     Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE, Irp);
     if (!NT_SUCCESS(Status)) {
         ERR("error - find_item returned %08x\n", Status);
         return 0;
     }
-    
+
     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;
-    
+
         return ei->flags;
     }
-    
+
     if (tp.item->key.obj_id != address || tp.item->key.obj_type != TYPE_EXTENT_ITEM) {
         ERR("couldn't find %llx in extent tree\n", address);
         return 0;
     }
-    
+
     if (tp.item->size == sizeof(EXTENT_ITEM_V0))
         return 0;
     else if (tp.item->size < sizeof(EXTENT_ITEM)) {
         ERR("(%llx,%x,%llx) was %x bytes, expected at least %x\n", tp.item->key.obj_id, tp.item->key.obj_type,
-                                                                   tp.item->key.offset, tp.item->size, sizeof(EXTENT_DATA));
+                                                                   tp.item->key.offset, tp.item->size, sizeof(EXTENT_ITEM));
         return 0;
     }
-    
+
     ei = (EXTENT_ITEM*)tp.item->data;
-    
+
     return ei->flags;
 }
 
@@ -1720,37 +1877,37 @@ void update_extent_flags(device_extension* Vcb, UINT64 address, UINT64 flags, PI
     traverse_ptr tp;
     NTSTATUS Status;
     EXTENT_ITEM* ei;
-    
+
     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;
-    
+
     Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE, Irp);
     if (!NT_SUCCESS(Status)) {
         ERR("error - find_item returned %08x\n", Status);
         return;
     }
-    
+
     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;
     }
-    
+
     if (tp.item->key.obj_id != address || tp.item->key.obj_type != TYPE_EXTENT_ITEM) {
         ERR("couldn't find %llx in extent tree\n", address);
         return;
     }
-    
+
     if (tp.item->size == sizeof(EXTENT_ITEM_V0))
         return;
     else if (tp.item->size < sizeof(EXTENT_ITEM)) {
         ERR("(%llx,%x,%llx) was %x bytes, expected at least %x\n", tp.item->key.obj_id, tp.item->key.obj_type,
-                                                                   tp.item->key.offset, tp.item->size, sizeof(EXTENT_DATA));
+                                                                   tp.item->key.offset, tp.item->size, sizeof(EXTENT_ITEM));
         return;
     }
-    
+
     ei = (EXTENT_ITEM*)tp.item->data;
     ei->flags = flags;
 }
@@ -1758,23 +1915,23 @@ void update_extent_flags(device_extension* Vcb, UINT64 address, UINT64 flags, PI
 static changed_extent* get_changed_extent_item(chunk* c, UINT64 address, UINT64 size, BOOL no_csum) {
     LIST_ENTRY* le;
     changed_extent* ce;
-    
+
     le = c->changed_extents.Flink;
     while (le != &c->changed_extents) {
         ce = CONTAINING_RECORD(le, changed_extent, list_entry);
-        
+
         if (ce->address == address && ce->size == size)
             return ce;
-        
+
         le = le->Flink;
     }
-    
+
     ce = ExAllocatePoolWithTag(PagedPool, sizeof(changed_extent), ALLOC_TAG);
     if (!ce) {
         ERR("out of memory\n");
         return NULL;
     }
-    
+
     ce->address = address;
     ce->size = size;
     ce->old_size = size;
@@ -1784,13 +1941,13 @@ static changed_extent* get_changed_extent_item(chunk* c, UINT64 address, UINT64
     ce->superseded = FALSE;
     InitializeListHead(&ce->refs);
     InitializeListHead(&ce->old_refs);
-    
+
     InsertTailList(&c->changed_extents, &ce->list_entry);
-    
+
     return ce;
 }
 
-NTSTATUS update_changed_extent_ref(device_extension* Vcb, chunk* c, UINT64 address, UINT64 size, UINT64 root, UINT64 objid, UINT64 offset, signed long long count,
+NTSTATUS update_changed_extent_ref(device_extension* Vcb, chunk* c, UINT64 address, UINT64 size, UINT64 root, UINT64 objid, UINT64 offset, INT32 count,
                                    BOOL no_csum, BOOL superseded, PIRP Irp) {
     LIST_ENTRY* le;
     changed_extent* ce;
@@ -1798,48 +1955,48 @@ NTSTATUS update_changed_extent_ref(device_extension* Vcb, chunk* c, UINT64 addre
     NTSTATUS Status;
     KEY searchkey;
     traverse_ptr tp;
-    UINT64 old_count;
-    
+    UINT32 old_count;
+
     ExAcquireResourceExclusiveLite(&c->changed_extents_lock, TRUE);
-    
+
     ce = get_changed_extent_item(c, address, size, no_csum);
-    
+
     if (!ce) {
         ERR("get_changed_extent_item failed\n");
         Status = STATUS_INTERNAL_ERROR;
         goto end;
     }
-    
+
     if (IsListEmpty(&ce->refs) && IsListEmpty(&ce->old_refs)) { // new entry
         searchkey.obj_id = address;
         searchkey.obj_type = TYPE_EXTENT_ITEM;
         searchkey.offset = 0xffffffffffffffff;
-        
+
         Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE, Irp);
         if (!NT_SUCCESS(Status)) {
             ERR("error - find_item returned %08x\n", Status);
             goto end;
         }
-        
+
         if (tp.item->key.obj_id != searchkey.obj_id || tp.item->key.obj_type != searchkey.obj_type) {
             ERR("could not find address %llx in extent tree\n", address);
             Status = STATUS_INTERNAL_ERROR;
             goto end;
         }
-        
+
         if (tp.item->key.offset != size) {
             ERR("extent %llx had size %llx, not %llx as expected\n", address, tp.item->key.offset, size);
             Status = STATUS_INTERNAL_ERROR;
             goto end;
         }
-        
+
         if (tp.item->size == sizeof(EXTENT_ITEM_V0)) {
             EXTENT_ITEM_V0* eiv0 = (EXTENT_ITEM_V0*)tp.item->data;
-            
+
             ce->count = ce->old_count = eiv0->refcount;
         } else if (tp.item->size >= sizeof(EXTENT_ITEM)) {
             EXTENT_ITEM* ei = (EXTENT_ITEM*)tp.item->data;
-            
+
             ce->count = ce->old_count = ei->refcount;
         } else {
             ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(EXTENT_ITEM));
@@ -1847,71 +2004,71 @@ NTSTATUS update_changed_extent_ref(device_extension* Vcb, chunk* c, UINT64 addre
             goto end;
         }
     }
-    
+
     le = ce->refs.Flink;
     while (le != &ce->refs) {
         cer = CONTAINING_RECORD(le, changed_extent_ref, list_entry);
-        
+
         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;
-            
+
             if (superseded)
                 ce->superseded = TRUE;
-            
+
             goto end;
         }
-        
+
         le = le->Flink;
     }
-    
+
     old_count = find_extent_data_refcount(Vcb, address, size, root, objid, offset, Irp);
-    
+
     if (old_count > 0) {
         cer = ExAllocatePoolWithTag(PagedPool, sizeof(changed_extent_ref), ALLOC_TAG);
-    
+
         if (!cer) {
             ERR("out of memory\n");
             Status = STATUS_INSUFFICIENT_RESOURCES;
             goto end;
         }
-        
+
         cer->type = TYPE_EXTENT_DATA_REF;
         cer->edr.root = root;
         cer->edr.objid = objid;
         cer->edr.offset = offset;
         cer->edr.count = old_count;
-        
+
         InsertTailList(&ce->old_refs, &cer->list_entry);
     }
-    
+
     cer = ExAllocatePoolWithTag(PagedPool, sizeof(changed_extent_ref), ALLOC_TAG);
-    
+
     if (!cer) {
         ERR("out of memory\n");
         Status = STATUS_INSUFFICIENT_RESOURCES;
         goto end;
     }
-    
+
     cer->type = TYPE_EXTENT_DATA_REF;
     cer->edr.root = root;
     cer->edr.objid = objid;
     cer->edr.offset = offset;
     cer->edr.count = old_count + count;
-    
+
     InsertTailList(&ce->refs, &cer->list_entry);
-    
+
     ce->count += count;
-    
+
     if (superseded)
         ce->superseded = TRUE;
-    
+
     Status = STATUS_SUCCESS;
-    
+
 end:
     ExReleaseResourceLite(&c->changed_extents_lock);
-    
+
     return Status;
 }
 
@@ -1919,42 +2076,42 @@ void add_changed_extent_ref(chunk* c, UINT64 address, UINT64 size, UINT64 root,
     changed_extent* ce;
     changed_extent_ref* cer;
     LIST_ENTRY* le;
-    
+
     ce = get_changed_extent_item(c, address, size, no_csum);
-    
+
     if (!ce) {
         ERR("get_changed_extent_item failed\n");
         return;
     }
-    
+
     le = ce->refs.Flink;
     while (le != &ce->refs) {
         cer = CONTAINING_RECORD(le, changed_extent_ref, list_entry);
-        
+
         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;
         }
-        
+
         le = le->Flink;
     }
-    
+
     cer = ExAllocatePoolWithTag(PagedPool, sizeof(changed_extent_ref), ALLOC_TAG);
-    
+
     if (!cer) {
         ERR("out of memory\n");
         return;
     }
-    
+
     cer->type = TYPE_EXTENT_DATA_REF;
     cer->edr.root = root;
     cer->edr.objid = objid;
     cer->edr.offset = offset;
     cer->edr.count = count;
-    
+
     InsertTailList(&ce->refs, &cer->list_entry);
-    
+
     ce->count += count;
 }
 
@@ -1966,56 +2123,56 @@ UINT64 find_extent_shared_tree_refcount(device_extension* Vcb, UINT64 address, U
     EXTENT_ITEM* ei;
     UINT32 len;
     UINT8* ptr;
-    
+
     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;
-    
+
     Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE, Irp);
     if (!NT_SUCCESS(Status)) {
         ERR("error - find_item returned %08x\n", Status);
         return 0;
     }
-    
+
     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)) {
         TRACE("could not find address %llx in extent tree\n", address);
         return 0;
     }
-    
+
     if (tp.item->key.obj_type == TYPE_EXTENT_ITEM && tp.item->key.offset != Vcb->superblock.node_size) {
         ERR("extent %llx had size %llx, not %llx as expected\n", address, tp.item->key.offset, Vcb->superblock.node_size);
         return 0;
     }
-    
+
     if (tp.item->size < sizeof(EXTENT_ITEM)) {
         ERR("(%llx,%x,%llx): size was %u, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(EXTENT_ITEM));
         return 0;
     }
-    
+
     ei = (EXTENT_ITEM*)tp.item->data;
     inline_rc = 0;
-    
+
     len = tp.item->size - sizeof(EXTENT_ITEM);
     ptr = (UINT8*)&ei[1];
-    
+
     if (searchkey.obj_type == TYPE_EXTENT_ITEM && ei->flags & EXTENT_ITEM_TREE_BLOCK) {
         if (tp.item->size < sizeof(EXTENT_ITEM) + sizeof(EXTENT_ITEM2)) {
             ERR("(%llx,%x,%llx): size was %u, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset,
                                                                        tp.item->size, sizeof(EXTENT_ITEM) + sizeof(EXTENT_ITEM2));
             return 0;
         }
-        
+
         len -= sizeof(EXTENT_ITEM2);
         ptr += sizeof(EXTENT_ITEM2);
     }
-    
+
     while (len > 0) {
         UINT8 secttype = *ptr;
         ULONG sectlen = get_extent_data_len(secttype);
         UINT64 sectcount = get_extent_data_refcount(secttype, ptr + sizeof(UINT8));
-        
+
         len--;
-        
+
         if (sectlen > len) {
             ERR("(%llx,%x,%llx): %x bytes left, expecting at least %x\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, len, sectlen);
             return 0;
@@ -2025,45 +2182,41 @@ UINT64 find_extent_shared_tree_refcount(device_extension* Vcb, UINT64 address, U
             ERR("(%llx,%x,%llx): unrecognized extent type %x\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, secttype);
             return 0;
         }
-        
+
         if (secttype == TYPE_SHARED_BLOCK_REF) {
             SHARED_BLOCK_REF* sectsbr = (SHARED_BLOCK_REF*)(ptr + sizeof(UINT8));
-            
+
             if (sectsbr->offset == parent)
                 return 1;
         }
-        
+
         len -= sectlen;
         ptr += sizeof(UINT8) + sectlen;
         inline_rc += sectcount;
     }
-    
+
     // FIXME - what if old?
-    
+
     if (inline_rc == ei->refcount)
         return 0;
-    
+
     searchkey.obj_id = address;
     searchkey.obj_type = TYPE_SHARED_BLOCK_REF;
     searchkey.offset = parent;
-    
+
     Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE, Irp);
     if (!NT_SUCCESS(Status)) {
         ERR("error - find_item returned %08x\n", Status);
         return 0;
     }
-    
-    if (!keycmp(searchkey, tp.item->key)) {    
-        if (tp.item->size < sizeof(SHARED_BLOCK_REF))
-            ERR("(%llx,%x,%llx) has size %u, not %u as expected\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(SHARED_BLOCK_REF));
-        else
-            return 1;
-    }
-    
+
+    if (!keycmp(searchkey, tp.item->key))
+        return 1;
+
     return 0;
 }
 
-UINT64 find_extent_shared_data_refcount(device_extension* Vcb, UINT64 address, UINT64 parent, PIRP Irp) {
+UINT32 find_extent_shared_data_refcount(device_extension* Vcb, UINT64 address, UINT64 parent, PIRP Irp) {
     NTSTATUS Status;
     KEY searchkey;
     traverse_ptr tp;
@@ -2071,40 +2224,40 @@ UINT64 find_extent_shared_data_refcount(device_extension* Vcb, UINT64 address, U
     EXTENT_ITEM* ei;
     UINT32 len;
     UINT8* ptr;
-    
+
     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;
-    
+
     Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE, Irp);
     if (!NT_SUCCESS(Status)) {
         ERR("error - find_item returned %08x\n", Status);
         return 0;
     }
-    
+
     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)) {
         TRACE("could not find address %llx in extent tree\n", address);
         return 0;
     }
-    
+
     if (tp.item->size < sizeof(EXTENT_ITEM)) {
         ERR("(%llx,%x,%llx): size was %u, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(EXTENT_ITEM));
         return 0;
     }
-    
+
     ei = (EXTENT_ITEM*)tp.item->data;
     inline_rc = 0;
-    
+
     len = tp.item->size - sizeof(EXTENT_ITEM);
     ptr = (UINT8*)&ei[1];
-    
+
     while (len > 0) {
         UINT8 secttype = *ptr;
         ULONG sectlen = get_extent_data_len(secttype);
         UINT64 sectcount = get_extent_data_refcount(secttype, ptr + sizeof(UINT8));
-        
+
         len--;
-        
+
         if (sectlen > len) {
             ERR("(%llx,%x,%llx): %x bytes left, expecting at least %x\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, len, sectlen);
             return 0;
@@ -2114,42 +2267,42 @@ UINT64 find_extent_shared_data_refcount(device_extension* Vcb, UINT64 address, U
             ERR("(%llx,%x,%llx): unrecognized extent type %x\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, secttype);
             return 0;
         }
-        
+
         if (secttype == TYPE_SHARED_DATA_REF) {
             SHARED_DATA_REF* sectsdr = (SHARED_DATA_REF*)(ptr + sizeof(UINT8));
-            
+
             if (sectsdr->offset == parent)
                 return sectsdr->count;
         }
-        
+
         len -= sectlen;
         ptr += sizeof(UINT8) + sectlen;
         inline_rc += sectcount;
     }
-    
+
     // FIXME - what if old?
-    
+
     if (inline_rc == ei->refcount)
         return 0;
-    
+
     searchkey.obj_id = address;
     searchkey.obj_type = TYPE_SHARED_DATA_REF;
     searchkey.offset = parent;
-    
+
     Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE, Irp);
     if (!NT_SUCCESS(Status)) {
         ERR("error - find_item returned %08x\n", Status);
         return 0;
     }
-    
-    if (!keycmp(searchkey, tp.item->key)) {    
-        if (tp.item->size < sizeof(SHARED_DATA_REF))
-            ERR("(%llx,%x,%llx) has size %u, not %u as expected\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(SHARED_DATA_REF));
+
+    if (!keycmp(searchkey, tp.item->key)) {
+        if (tp.item->size < sizeof(UINT32))
+            ERR("(%llx,%x,%llx) has size %u, not %u as expected\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(UINT32));
         else {
-            SHARED_DATA_REF* sdr = (SHARED_DATA_REF*)tp.item->data;
-            return sdr->count;
+            UINT32* count = (UINT32*)tp.item->data;
+            return *count;
         }
     }
-    
+
     return 0;
 }