1 /* Copyright (c) Mark Harmstone 2016
3 * This file is part of WinBtrfs.
5 * WinBtrfs is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public Licence as published by
7 * the Free Software Foundation, either version 3 of the Licence, or
8 * (at your option) any later version.
10 * WinBtrfs is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public Licence for more details.
15 * You should have received a copy of the GNU Lesser General Public Licence
16 * along with WinBtrfs. If not, see <http://www.gnu.org/licenses/>. */
18 #include "btrfs_drv.h"
20 // #define DEBUG_TREE_LOCKS
22 enum read_tree_status
{
23 ReadTreeStatus_Pending
,
24 ReadTreeStatus_Success
,
25 ReadTreeStatus_Cancelling
,
26 ReadTreeStatus_Cancelled
,
28 ReadTreeStatus_CRCError
,
29 ReadTreeStatus_MissingDevice
32 struct read_tree_context
;
35 struct read_tree_context
* context
;
39 enum read_tree_status status
;
51 read_tree_stripe
* stripes
;
60 enum rollback_type type
;
62 LIST_ENTRY list_entry
;
65 static NTSTATUS STDCALL
read_tree_completion(PDEVICE_OBJECT DeviceObject
, PIRP Irp
, PVOID conptr
) {
66 read_tree_stripe
* stripe
= conptr
;
67 read_tree_context
* context
= (read_tree_context
*)stripe
->context
;
70 if (stripe
->status
== ReadTreeStatus_Cancelling
) {
71 stripe
->status
= ReadTreeStatus_Cancelled
;
75 stripe
->iosb
= Irp
->IoStatus
;
77 if (NT_SUCCESS(Irp
->IoStatus
.Status
)) {
78 tree_header
* th
= (tree_header
*)stripe
->buf
;
81 crc32
= ~calc_crc32c(0xffffffff, (UINT8
*)&th
->fs_uuid
, context
->buflen
- sizeof(th
->csum
));
83 if (crc32
== *((UINT32
*)th
->csum
)) {
84 stripe
->status
= ReadTreeStatus_Success
;
86 for (i
= 0; i
< context
->num_stripes
; i
++) {
87 if (context
->stripes
[i
].status
== ReadTreeStatus_Pending
) {
88 context
->stripes
[i
].status
= ReadTreeStatus_Cancelling
;
89 IoCancelIrp(context
->stripes
[i
].Irp
);
95 stripe
->status
= ReadTreeStatus_CRCError
;
97 stripe
->status
= ReadTreeStatus_Error
;
101 if (InterlockedDecrement(&context
->stripes_left
) == 0)
102 KeSetEvent(&context
->Event
, 0, FALSE
);
104 // return STATUS_SUCCESS;
105 return STATUS_MORE_PROCESSING_REQUIRED
;
108 NTSTATUS STDCALL
read_tree(device_extension
* Vcb
, UINT64 addr
, UINT8
* buf
) {
110 CHUNK_ITEM_STRIPE
* cis
;
111 read_tree_context
* context
;
112 UINT64 i
/*, type*/, offset
;
116 // FIXME - make this work with RAID
118 if (Vcb
->log_to_phys_loaded
) {
119 chunk
* c
= get_chunk_from_address(Vcb
, addr
);
122 ERR("get_chunk_from_address failed\n");
123 return STATUS_INTERNAL_ERROR
;
128 devices
= c
->devices
;
130 LIST_ENTRY
* le
= Vcb
->sys_chunks
.Flink
;
134 while (le
!= &Vcb
->sys_chunks
) {
135 sys_chunk
* sc
= CONTAINING_RECORD(le
, sys_chunk
, list_entry
);
137 if (sc
->key
.obj_id
== 0x100 && sc
->key
.obj_type
== TYPE_CHUNK_ITEM
&& sc
->key
.offset
<= addr
) {
138 CHUNK_ITEM
* chunk_item
= sc
->data
;
140 if ((addr
- sc
->key
.offset
) < chunk_item
->size
&& chunk_item
->num_stripes
> 0) {
142 offset
= sc
->key
.offset
;
143 cis
= (CHUNK_ITEM_STRIPE
*)&chunk_item
[1];
145 devices
= ExAllocatePoolWithTag(PagedPool
, sizeof(device
*) * ci
->num_stripes
, ALLOC_TAG
);
147 ERR("out of memory\n");
148 return STATUS_INSUFFICIENT_RESOURCES
;
151 for (i
= 0; i
< ci
->num_stripes
; i
++) {
152 devices
[i
] = find_device_from_uuid(Vcb
, &cis
[i
].dev_uuid
);
163 ERR("could not find chunk for %llx in bootstrap\n", addr
);
164 return STATUS_INTERNAL_ERROR
;
168 // if (ci->type & BLOCK_FLAG_DUPLICATE) {
169 // type = BLOCK_FLAG_DUPLICATE;
170 // } else if (ci->type & BLOCK_FLAG_RAID0) {
171 // FIXME("RAID0 not yet supported\n");
172 // return STATUS_NOT_IMPLEMENTED;
173 // } else if (ci->type & BLOCK_FLAG_RAID1) {
174 // FIXME("RAID1 not yet supported\n");
175 // return STATUS_NOT_IMPLEMENTED;
176 // } else if (ci->type & BLOCK_FLAG_RAID10) {
177 // FIXME("RAID10 not yet supported\n");
178 // return STATUS_NOT_IMPLEMENTED;
179 // } else if (ci->type & BLOCK_FLAG_RAID5) {
180 // FIXME("RAID5 not yet supported\n");
181 // return STATUS_NOT_IMPLEMENTED;
182 // } else if (ci->type & BLOCK_FLAG_RAID6) {
183 // FIXME("RAID6 not yet supported\n");
184 // return STATUS_NOT_IMPLEMENTED;
185 // } else { // SINGLE
189 cis
= (CHUNK_ITEM_STRIPE
*)&ci
[1];
191 context
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(read_tree_context
), ALLOC_TAG
);
193 ERR("out of memory\n");
194 return STATUS_INSUFFICIENT_RESOURCES
;
197 RtlZeroMemory(context
, sizeof(read_tree_context
));
198 KeInitializeEvent(&context
->Event
, NotificationEvent
, FALSE
);
200 context
->stripes
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(read_tree_stripe
) * ci
->num_stripes
, ALLOC_TAG
);
201 if (!context
->stripes
) {
202 ERR("out of memory\n");
204 return STATUS_INSUFFICIENT_RESOURCES
;
207 RtlZeroMemory(context
->stripes
, sizeof(read_tree_stripe
) * ci
->num_stripes
);
209 context
->buflen
= Vcb
->superblock
.node_size
;
210 context
->num_stripes
= ci
->num_stripes
;
211 context
->stripes_left
= context
->num_stripes
;
212 // context->type = type;
214 // FIXME - for RAID, check beforehand whether there's enough devices to satisfy request
216 for (i
= 0; i
< ci
->num_stripes
; i
++) {
217 PIO_STACK_LOCATION IrpSp
;
220 context
->stripes
[i
].status
= ReadTreeStatus_MissingDevice
;
221 context
->stripes
[i
].buf
= NULL
;
222 context
->stripes_left
--;
224 context
->stripes
[i
].context
= (struct read_tree_context
*)context
;
225 context
->stripes
[i
].buf
= ExAllocatePoolWithTag(NonPagedPool
, Vcb
->superblock
.node_size
, ALLOC_TAG
);
227 if (!context
->stripes
[i
].buf
) {
228 ERR("out of memory\n");
229 Status
= STATUS_INSUFFICIENT_RESOURCES
;
233 context
->stripes
[i
].Irp
= IoAllocateIrp(devices
[i
]->devobj
->StackSize
, FALSE
);
235 if (!context
->stripes
[i
].Irp
) {
236 ERR("IoAllocateIrp failed\n");
237 Status
= STATUS_INSUFFICIENT_RESOURCES
;
241 IrpSp
= IoGetNextIrpStackLocation(context
->stripes
[i
].Irp
);
242 IrpSp
->MajorFunction
= IRP_MJ_READ
;
244 if (devices
[i
]->devobj
->Flags
& DO_BUFFERED_IO
) {
245 FIXME("FIXME - buffered IO\n");
246 } else if (devices
[i
]->devobj
->Flags
& DO_DIRECT_IO
) {
247 context
->stripes
[i
].Irp
->MdlAddress
= IoAllocateMdl(context
->stripes
[i
].buf
, Vcb
->superblock
.node_size
, FALSE
, FALSE
, NULL
);
248 if (!context
->stripes
[i
].Irp
->MdlAddress
) {
249 ERR("IoAllocateMdl failed\n");
250 Status
= STATUS_INSUFFICIENT_RESOURCES
;
254 MmProbeAndLockPages(context
->stripes
[i
].Irp
->MdlAddress
, KernelMode
, IoWriteAccess
);
256 context
->stripes
[i
].Irp
->UserBuffer
= context
->stripes
[i
].buf
;
259 IrpSp
->Parameters
.Read
.Length
= Vcb
->superblock
.node_size
;
260 IrpSp
->Parameters
.Read
.ByteOffset
.QuadPart
= addr
- offset
+ cis
[i
].offset
;
262 context
->stripes
[i
].Irp
->UserIosb
= &context
->stripes
[i
].iosb
;
264 IoSetCompletionRoutine(context
->stripes
[i
].Irp
, read_tree_completion
, &context
->stripes
[i
], TRUE
, TRUE
, TRUE
);
266 context
->stripes
[i
].status
= ReadTreeStatus_Pending
;
270 for (i
= 0; i
< ci
->num_stripes
; i
++) {
271 if (context
->stripes
[i
].status
!= ReadTreeStatus_MissingDevice
) {
272 IoCallDriver(devices
[i
]->devobj
, context
->stripes
[i
].Irp
);
276 KeWaitForSingleObject(&context
->Event
, Executive
, KernelMode
, FALSE
, NULL
);
278 // FIXME - if checksum error, write good data over bad
280 // check if any of the devices return a "user-induced" error
282 for (i
= 0; i
< ci
->num_stripes
; i
++) {
283 if (context
->stripes
[i
].status
== ReadTreeStatus_Error
&& IoIsErrorUserInduced(context
->stripes
[i
].iosb
.Status
)) {
284 IoSetHardErrorOrVerifyDevice(context
->stripes
[i
].Irp
, devices
[i
]->devobj
);
286 Status
= context
->stripes
[i
].iosb
.Status
;
291 // check if any of the stripes succeeded
293 for (i
= 0; i
< ci
->num_stripes
; i
++) {
294 if (context
->stripes
[i
].status
== ReadTreeStatus_Success
) {
295 RtlCopyMemory(buf
, context
->stripes
[i
].buf
, Vcb
->superblock
.node_size
);
296 Status
= STATUS_SUCCESS
;
301 // if not, see if we got a checksum error
303 for (i
= 0; i
< ci
->num_stripes
; i
++) {
304 if (context
->stripes
[i
].status
== ReadTreeStatus_CRCError
) {
306 tree_header
* th
= (tree_header
*)context
->stripes
[i
].buf
;
307 UINT32 crc32
= ~calc_crc32c(0xffffffff, (UINT8
*)&th
->fs_uuid
, context
->buflen
- sizeof(th
->csum
));
310 WARN("stripe %llu had a checksum error\n", i
);
311 WARN("crc32 was %08x, expected %08x\n", crc32
, *((UINT32
*)th
->csum
));
314 // for (j = 0; j < ci->num_stripes; j++) {
315 // WARN("stripe %llu: device = %p, status = %u\n", j, c->devices[j], context->stripes[j].status);
319 Status
= STATUS_IMAGE_CHECKSUM_MISMATCH
;
324 // failing that, return the first error we encountered
326 for (i
= 0; i
< ci
->num_stripes
; i
++) {
327 if (context
->stripes
[i
].status
== ReadTreeStatus_Error
) {
328 Status
= context
->stripes
[i
].iosb
.Status
;
333 // if we somehow get here, return STATUS_INTERNAL_ERROR
335 Status
= STATUS_INTERNAL_ERROR
;
337 // for (i = 0; i < ci->num_stripes; i++) {
338 // ERR("%llx: status = %u, NTSTATUS = %08x\n", i, context->stripes[i].status, context->stripes[i].iosb.Status);
342 for (i
= 0; i
< ci
->num_stripes
; i
++) {
343 if (context
->stripes
[i
].Irp
) {
344 if (devices
[i
]->devobj
->Flags
& DO_DIRECT_IO
) {
345 MmUnlockPages(context
->stripes
[i
].Irp
->MdlAddress
);
346 IoFreeMdl(context
->stripes
[i
].Irp
->MdlAddress
);
348 IoFreeIrp(context
->stripes
[i
].Irp
);
351 if (context
->stripes
[i
].buf
)
352 ExFreePool(context
->stripes
[i
].buf
);
355 ExFreePool(context
->stripes
);
358 if (!Vcb
->log_to_phys_loaded
)
364 NTSTATUS STDCALL
_load_tree(device_extension
* Vcb
, UINT64 addr
, root
* r
, tree
** pt
, const char* func
, const char* file
, unsigned int line
) {
372 TRACE("(%p, %llx)\n", Vcb
, addr
);
374 buf
= ExAllocatePoolWithTag(PagedPool
, Vcb
->superblock
.node_size
, ALLOC_TAG
);
376 ERR("out of memory\n");
377 return STATUS_INSUFFICIENT_RESOURCES
;
380 Status
= read_tree(Vcb
, addr
, buf
);
381 if (!NT_SUCCESS(Status
)) {
382 ERR("read_tree returned 0x%08x\n", Status
);
387 th
= (tree_header
*)buf
;
389 t
= ExAllocatePoolWithTag(PagedPool
, sizeof(tree
), ALLOC_TAG
);
391 ERR("out of memory\n");
393 return STATUS_INSUFFICIENT_RESOURCES
;
396 RtlCopyMemory(&t
->header
, th
, sizeof(tree_header
));
397 // t->address = addr;
398 // t->level = th->level;
399 t
->has_address
= TRUE
;
403 // t->nonpaged = ExAllocatePoolWithTag(NonPagedPool, sizeof(tree_nonpaged), ALLOC_TAG);
407 t
->has_new_address
= FALSE
;
410 c
= get_chunk_from_address(Vcb
, addr
);
413 t
->flags
= c
->chunk_item
->type
;
417 // ExInitializeResourceLite(&t->nonpaged->load_tree_lock);
419 // t->items = ExAllocatePoolWithTag(PagedPool, num_items * sizeof(tree_data), ALLOC_TAG);
420 InitializeListHead(&t
->itemlist
);
422 if (t
->header
.level
== 0) { // leaf node
423 leaf_node
* ln
= (leaf_node
*)(buf
+ sizeof(tree_header
));
426 for (i
= 0; i
< t
->header
.num_items
; i
++) {
427 td
= ExAllocatePoolWithTag(PagedPool
, sizeof(tree_data
), ALLOC_TAG
);
429 ERR("out of memory\n");
431 return STATUS_INSUFFICIENT_RESOURCES
;
435 // TRACE("load_tree: leaf item %u (%x,%x,%x)\n", i, (UINT32)ln[i].key.obj_id, ln[i].key.obj_type, (UINT32)ln[i].key.offset);
437 if (ln
[i
].size
> 0) {
438 td
->data
= ExAllocatePoolWithTag(PagedPool
, ln
[i
].size
, ALLOC_TAG
);
440 ERR("out of memory\n");
442 return STATUS_INSUFFICIENT_RESOURCES
;
445 RtlCopyMemory(td
->data
, buf
+ sizeof(tree_header
) + ln
[i
].offset
, ln
[i
].size
);
449 td
->size
= ln
[i
].size
;
451 td
->inserted
= FALSE
;
453 InsertTailList(&t
->itemlist
, &td
->list_entry
);
455 t
->size
+= ln
[i
].size
;
458 t
->size
+= t
->header
.num_items
* sizeof(leaf_node
);
460 internal_node
* in
= (internal_node
*)(buf
+ sizeof(tree_header
));
463 for (i
= 0; i
< t
->header
.num_items
; i
++) {
464 td
= ExAllocatePoolWithTag(PagedPool
, sizeof(tree_data
), ALLOC_TAG
);
466 ERR("out of memory\n");
468 return STATUS_INSUFFICIENT_RESOURCES
;
472 // TRACE("load_tree: internal item %u (%x,%x,%x)\n", i, (UINT32)in[i].key.obj_id, in[i].key.obj_type, (UINT32)in[i].key.offset);
474 td
->treeholder
.address
= in
[i
].address
;
475 td
->treeholder
.generation
= in
[i
].generation
;
476 td
->treeholder
.tree
= NULL
;
477 init_tree_holder(&td
->treeholder
);
478 // td->treeholder.nonpaged->status = tree_holder_unloaded;
480 td
->inserted
= FALSE
;
482 InsertTailList(&t
->itemlist
, &td
->list_entry
);
485 t
->size
= t
->header
.num_items
* sizeof(internal_node
);
490 InterlockedIncrement(&Vcb
->open_trees
);
491 InsertTailList(&Vcb
->trees
, &t
->list_entry
);
493 TRACE("returning %p\n", t
);
497 return STATUS_SUCCESS
;
500 static tree
* free_tree2(tree
* t
, const char* func
, const char* file
, unsigned int line
) {
508 // if (par) ExAcquireResourceExclusiveLite(&par->nonpaged->load_tree_lock, TRUE);
510 if (r
&& r
->treeholder
.tree
!= t
)
514 // FsRtlEnterFileSystem();
515 // ExAcquireResourceExclusiveLite(&r->nonpaged->load_tree_lock, TRUE);
520 t
->paritem
->treeholder
.tree
= NULL
;
522 // ExReleaseResourceLite(&par->nonpaged->load_tree_lock);
525 // ExDeleteResourceLite(&t->nonpaged->load_tree_lock);
527 // ExFreePool(t->nonpaged);
529 while (!IsListEmpty(&t
->itemlist
)) {
530 le
= RemoveHeadList(&t
->itemlist
);
531 td
= CONTAINING_RECORD(le
, tree_data
, list_entry
);
533 if (t
->header
.level
== 0 && td
->data
)
534 ExFreePool(td
->data
);
539 InterlockedDecrement(&t
->Vcb
->open_trees
);
540 RemoveEntryList(&t
->list_entry
);
543 r
->treeholder
.tree
= NULL
;
544 // ExReleaseResourceLite(&r->nonpaged->load_tree_lock);
545 // FsRtlExitFileSystem();
553 NTSTATUS STDCALL
_do_load_tree(device_extension
* Vcb
, tree_holder
* th
, root
* r
, tree
* t
, tree_data
* td
, BOOL
* loaded
, const char* func
, const char* file
, unsigned int line
) {
555 // tree_holder_nonpaged* thnp = th->nonpaged;
558 // ExAcquireResourceExclusiveLite(&thnp->lock, TRUE);
559 ExAcquireResourceExclusiveLite(&r
->nonpaged
->load_tree_lock
, TRUE
);
561 // KeAcquireSpinLock(&thnp->spin_lock, &irql);
563 // if (thnp->status == tree_header_loading) {
564 // KeReleaseSpinLock(&thnp->spin_lock, irql);
566 // // FIXME - wait for Event
567 // } else if (thnp->status == tree_header_unloaded || thnp->status == tree_header_unloading) {
568 // if (thnp->status == tree_header_unloading) {
569 // KeReleaseSpinLock(&thnp->spin_lock, irql);
570 // // FIXME - wait for Event
573 // // FIXME - change status
574 // thnp->status = tree_header_loading;
575 // KeReleaseSpinLock(&thnp->spin_lock, irql);
578 // // FIXME - change status
579 // // FIXME - trigger event
580 // } else if (thnp->status == tree_header_loaded) {
581 // _increase_tree_rc(th->tree, func, file, line);
582 // KeReleaseSpinLock(&thnp->spin_lock, irql);
590 Status
= _load_tree(Vcb
, th
->address
, r
, &th
->tree
, func
, file
, line
);
591 if (!NT_SUCCESS(Status
)) {
592 ERR("load_tree returned %08x\n", Status
);
593 ExReleaseResourceLite(&r
->nonpaged
->load_tree_lock
);
597 th
->tree
->parent
= t
;
598 th
->tree
->paritem
= td
;
604 // KeReleaseSpinLock(&thnp->spin_lock, irql);
606 // ExReleaseResourceLite(&thnp->lock);
607 ExReleaseResourceLite(&r
->nonpaged
->load_tree_lock
);
611 return STATUS_SUCCESS
;
614 tree
* STDCALL
_free_tree(tree
* t
, const char* func
, const char* file
, unsigned int line
) {
618 ExAcquireResourceExclusiveLite(&r
->nonpaged
->load_tree_lock
, TRUE
);
620 ret
= free_tree2(t
, func
, file
, line
);
622 ExReleaseResourceLite(&r
->nonpaged
->load_tree_lock
);
627 static __inline tree_data
* first_item(tree
* t
) {
628 LIST_ENTRY
* le
= t
->itemlist
.Flink
;
630 if (le
== &t
->itemlist
)
633 return CONTAINING_RECORD(le
, tree_data
, list_entry
);
636 static __inline tree_data
* prev_item(tree
* t
, tree_data
* td
) {
637 LIST_ENTRY
* le
= td
->list_entry
.Blink
;
639 if (le
== &t
->itemlist
)
642 return CONTAINING_RECORD(le
, tree_data
, list_entry
);
645 static __inline tree_data
* next_item(tree
* t
, tree_data
* td
) {
646 LIST_ENTRY
* le
= td
->list_entry
.Flink
;
648 if (le
== &t
->itemlist
)
651 return CONTAINING_RECORD(le
, tree_data
, list_entry
);
654 static NTSTATUS STDCALL
find_item_in_tree(device_extension
* Vcb
, tree
* t
, traverse_ptr
* tp
, const KEY
* searchkey
, BOOL ignore
, const char* func
, const char* file
, unsigned int line
) {
656 tree_data
*td
, *lasttd
;
658 TRACE("(%p, %p, %p, %p, %u)\n", Vcb
, t
, tp
, searchkey
, ignore
);
664 if (!td
) return STATUS_INTERNAL_ERROR
;
667 cmp
= keycmp(searchkey
, &td
->key
);
668 // TRACE("(%u) comparing (%x,%x,%x) to (%x,%x,%x) - %i (ignore = %s)\n", t->header.level, (UINT32)searchkey->obj_id, searchkey->obj_type, (UINT32)searchkey->offset, (UINT32)td->key.obj_id, td->key.obj_type, (UINT32)td->key.offset, cmp, td->ignore ? "TRUE" : "FALSE");
671 td
= next_item(t
, td
);
674 if (t
->header
.level
== 0 && cmp
== 0 && !ignore
&& td
&& td
->ignore
) {
675 tree_data
* origtd
= td
;
677 while (td
&& td
->ignore
)
678 td
= next_item(t
, td
);
681 cmp
= keycmp(searchkey
, &td
->key
);
690 } while (td
&& cmp
== 1);
692 if ((cmp
== -1 || !td
) && lasttd
)
695 if (t
->header
.level
== 0) {
696 if (td
->ignore
&& !ignore
) {
702 while (_find_prev_item(Vcb
, &oldtp
, tp
, TRUE
, func
, file
, line
)) {
703 if (!tp
->item
->ignore
)
704 return STATUS_SUCCESS
;
709 // if no valid entries before where item should be, look afterwards instead
714 while (_find_next_item(Vcb
, &oldtp
, tp
, TRUE
, func
, file
, line
)) {
715 if (!tp
->item
->ignore
)
716 return STATUS_SUCCESS
;
721 return STATUS_INTERNAL_ERROR
;
727 return STATUS_SUCCESS
;
732 while (td
&& td
->treeholder
.tree
&& IsListEmpty(&td
->treeholder
.tree
->itemlist
)) {
733 td
= prev_item(t
, td
);
737 return STATUS_INTERNAL_ERROR
;
740 // TRACE("entering tree from (%x,%x,%x) to (%x,%x,%x) (%p)\n", (UINT32)t->items[i].key.obj_id, t->items[i].key.obj_type, (UINT32)t->items[i].key.offset, (UINT32)t->items[i+1].key.obj_id, t->items[i+1].key.obj_type, (UINT32)t->items[i+1].key.offset, t->items[i].tree);
742 Status
= _do_load_tree(Vcb
, &td
->treeholder
, t
->root
, t
, td
, &loaded
, func
, file
, line
);
743 if (!NT_SUCCESS(Status
)) {
744 ERR("do_load_tree returned %08x\n", Status
);
748 Status
= find_item_in_tree(Vcb
, td
->treeholder
.tree
, tp
, searchkey
, ignore
, func
, file
, line
);
754 NTSTATUS STDCALL
_find_item(device_extension
* Vcb
, root
* r
, traverse_ptr
* tp
, const KEY
* searchkey
, BOOL ignore
, const char* func
, const char* file
, unsigned int line
) {
759 TRACE("(%p, %p, %p, %p)\n", Vcb
, r
, tp
, searchkey
);
761 if (!r
->treeholder
.tree
) {
762 Status
= _do_load_tree(Vcb
, &r
->treeholder
, r
, NULL
, NULL
, &loaded
, func
, file
, line
);
763 if (!NT_SUCCESS(Status
)) {
764 ERR("do_load_tree returned %08x\n", Status
);
769 Status
= find_item_in_tree(Vcb
, r
->treeholder
.tree
, tp
, searchkey
, ignore
, func
, file
, line
);
770 if (!NT_SUCCESS(Status
)) {
771 ERR("find_item_in_tree returned %08x\n", Status
);
774 // #ifdef DEBUG_PARANOID
775 // if (b && !ignore && tp->item->ignore) {
776 // ERR("error - returning ignored item\n");
784 BOOL STDCALL
_find_next_item(device_extension
* Vcb
, const traverse_ptr
* tp
, traverse_ptr
* next_tp
, BOOL ignore
, const char* func
, const char* file
, unsigned int line
) {
786 tree_data
*td
, *next
;
790 next
= next_item(tp
->tree
, tp
->item
);
793 while (next
&& next
->ignore
)
794 next
= next_item(tp
->tree
, next
);
798 next_tp
->tree
= tp
->tree
;
799 next_tp
->item
= next
;
801 #ifdef DEBUG_PARANOID
802 if (!ignore
&& next_tp
->item
->ignore
) {
803 ERR("error - returning ignored item\n");
811 if (!tp
->tree
->parent
)
817 td
= next_item(t
->parent
, t
->paritem
);
828 Status
= _do_load_tree(Vcb
, &td
->treeholder
, t
->parent
->root
, t
->parent
, td
, &loaded
, func
, file
, line
);
829 if (!NT_SUCCESS(Status
)) {
830 ERR("do_load_tree returned %08x\n", Status
);
834 t
= td
->treeholder
.tree
;
836 while (t
->header
.level
!= 0) {
841 Status
= _do_load_tree(Vcb
, &fi
->treeholder
, t
->parent
->root
, t
, fi
, &loaded
, func
, file
, line
);
842 if (!NT_SUCCESS(Status
)) {
843 ERR("do_load_tree returned %08x\n", Status
);
847 t
= fi
->treeholder
.tree
;
851 next_tp
->item
= first_item(t
);
853 if (!ignore
&& next_tp
->item
->ignore
) {
857 while ((b
= _find_next_item(Vcb
, next_tp
, &ntp2
, TRUE
, func
, file
, line
))) {
860 if (!next_tp
->item
->ignore
)
868 #ifdef DEBUG_PARANOID
869 if (!ignore
&& next_tp
->item
->ignore
) {
870 ERR("error - returning ignored item\n");
878 static __inline tree_data
* last_item(tree
* t
) {
879 LIST_ENTRY
* le
= t
->itemlist
.Blink
;
881 if (le
== &t
->itemlist
)
884 return CONTAINING_RECORD(le
, tree_data
, list_entry
);
887 BOOL STDCALL
_find_prev_item(device_extension
* Vcb
, const traverse_ptr
* tp
, traverse_ptr
* prev_tp
, BOOL ignore
, const char* func
, const char* file
, unsigned int line
) {
893 // FIXME - support ignore flag
894 if (prev_item(tp
->tree
, tp
->item
)) {
895 prev_tp
->tree
= tp
->tree
;
896 prev_tp
->item
= prev_item(tp
->tree
, tp
->item
);
901 if (!tp
->tree
->parent
)
905 while (t
&& (!t
->parent
|| !prev_item(t
->parent
, t
->paritem
))) {
912 td
= prev_item(t
->parent
, t
->paritem
);
914 Status
= _do_load_tree(Vcb
, &td
->treeholder
, t
->parent
->root
, t
, td
, &loaded
, func
, file
, line
);
915 if (!NT_SUCCESS(Status
)) {
916 ERR("do_load_tree returned %08x\n", Status
);
920 t
= td
->treeholder
.tree
;
922 while (t
->header
.level
!= 0) {
927 Status
= _do_load_tree(Vcb
, &li
->treeholder
, t
->parent
->root
, t
, li
, &loaded
, func
, file
, line
);
928 if (!NT_SUCCESS(Status
)) {
929 ERR("do_load_tree returned %08x\n", Status
);
933 t
= li
->treeholder
.tree
;
937 prev_tp
->item
= last_item(t
);
942 // static void free_tree_holder(tree_holder* th) {
943 // root* r = th->tree->root;
945 // // ExAcquireResourceExclusiveLite(&th->nonpaged->lock, TRUE);
946 // ExAcquireResourceExclusiveLite(&r->nonpaged->load_tree_lock, TRUE);
948 // free_tree2(th->tree, funcname, __FILE__, __LINE__);
950 // // ExReleaseResourceLite(&th->nonpaged->lock);
951 // ExReleaseResourceLite(&r->nonpaged->load_tree_lock);
954 void free_trees_root(device_extension
* Vcb
, root
* r
) {
958 for (level
= 0; level
<= 255; level
++) {
961 le
= Vcb
->trees
.Flink
;
963 while (le
!= &Vcb
->trees
) {
964 LIST_ENTRY
* nextle
= le
->Flink
;
965 tree
* t
= CONTAINING_RECORD(le
, tree
, list_entry
);
967 if (t
->root
== r
&& t
->header
.level
== level
) {
968 BOOL top
= !t
->paritem
;
972 free_tree2(t
, funcname
, __FILE__
, __LINE__
);
973 if (top
&& r
->treeholder
.tree
== t
)
974 r
->treeholder
.tree
= NULL
;
976 if (IsListEmpty(&Vcb
->trees
))
988 void STDCALL
free_trees(device_extension
* Vcb
) {
992 while (!IsListEmpty(&Vcb
->trees
)) {
993 t
= CONTAINING_RECORD(Vcb
->trees
.Flink
, tree
, list_entry
);
996 ExAcquireResourceExclusiveLite(&r
->nonpaged
->load_tree_lock
, TRUE
);
998 free_trees_root(Vcb
, r
);
1000 ExReleaseResourceLite(&r
->nonpaged
->load_tree_lock
);
1004 static void add_rollback(LIST_ENTRY
* rollback
, enum rollback_type type
, void* ptr
) {
1007 ri
= ExAllocatePoolWithTag(PagedPool
, sizeof(rollback_item
), ALLOC_TAG
);
1009 ERR("out of memory\n");
1015 InsertTailList(rollback
, &ri
->list_entry
);
1018 BOOL STDCALL
insert_tree_item(device_extension
* Vcb
, root
* r
, UINT64 obj_id
, UINT8 obj_type
, UINT64 offset
, void* data
, UINT32 size
, traverse_ptr
* ptp
, LIST_ENTRY
* rollback
) {
1022 tree_data
*td
, *paritem
;
1026 KEY firstitem
= {0xcccccccccccccccc,0xcc,0xcccccccccccccccc};
1029 BOOL success
= FALSE
;
1032 TRACE("(%p, %p, %llx, %x, %llx, %p, %x, %p, %p)\n", Vcb
, r
, obj_id
, obj_type
, offset
, data
, size
, ptp
, rollback
);
1034 searchkey
.obj_id
= obj_id
;
1035 searchkey
.obj_type
= obj_type
;
1036 searchkey
.offset
= offset
;
1038 Status
= find_item(Vcb
, r
, &tp
, &searchkey
, TRUE
);
1039 if (!NT_SUCCESS(Status
)) {
1041 if (!r
->treeholder
.tree
) {
1044 Status
= do_load_tree(Vcb
, &r
->treeholder
, r
, NULL
, NULL
, &loaded
);
1046 if (!NT_SUCCESS(Status
)) {
1047 ERR("do_load_tree returned %08x\n", Status
);
1052 if (r
->treeholder
.tree
&& r
->treeholder
.tree
->header
.num_items
== 0) {
1053 tp
.tree
= r
->treeholder
.tree
;
1056 ERR("error: unable to load tree for root %llx\n", r
->id
);
1060 ERR("error: find_item returned %08x\n", Status
);
1065 TRACE("tp.item = %p\n", tp
.item
);
1068 TRACE("tp.item->key = %p\n", &tp
.item
->key
);
1069 cmp
= keycmp(&searchkey
, &tp
.item
->key
);
1071 if (cmp
== 0 && !tp
.item
->ignore
) { // FIXME - look for all items of the same key to make sure none are non-ignored
1072 ERR("error: key (%llx,%x,%llx) already present\n", obj_id
, obj_type
, offset
);
1078 td
= ExAllocatePoolWithTag(PagedPool
, sizeof(tree_data
), ALLOC_TAG
);
1080 ERR("out of memory\n");
1084 td
->key
= searchkey
;
1088 td
->inserted
= TRUE
;
1091 le
= tp
.tree
->itemlist
.Flink
;
1092 while (le
!= &tp
.tree
->itemlist
) {
1093 tree_data
* td2
= CONTAINING_RECORD(le
, tree_data
, list_entry
);
1094 firstitem
= td2
->key
;
1098 TRACE("inserting %llx,%x,%llx into tree beginning %llx,%x,%llx (num_items %x)\n", obj_id
, obj_type
, offset
, firstitem
.obj_id
, firstitem
.obj_type
, firstitem
.offset
, tp
.tree
->header
.num_items
);
1101 if (cmp
== -1) { // very first key in root
1102 InsertHeadList(&tp
.tree
->itemlist
, &td
->list_entry
);
1104 paritem
= tp
.tree
->paritem
;
1106 // ERR("paritem = %llx,%x,%llx, tp.item->key = %llx,%x,%llx\n", paritem->key.obj_id, paritem->key.obj_type, paritem->key.offset, tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
1107 if (!keycmp(&paritem
->key
, &tp
.item
->key
)) {
1108 paritem
->key
= searchkey
;
1112 paritem
= paritem
->treeholder
.tree
->paritem
;
1116 InsertAfter(&tp
.tree
->itemlist
, &td
->list_entry
, &tp
.item
->list_entry
); // FIXME - we don't need this
1119 tp
.tree
->header
.num_items
++;
1120 tp
.tree
->size
+= size
+ sizeof(leaf_node
);
1121 // ERR("tree %p, num_items now %x\n", tp.tree, tp.tree->header.num_items);
1122 // ERR("size now %x\n", tp.tree->size);
1124 if (!tp
.tree
->write
) {
1125 tp
.tree
->write
= TRUE
;
1134 if (t
->paritem
&& t
->paritem
->ignore
) {
1135 t
->paritem
->ignore
= FALSE
;
1136 t
->parent
->header
.num_items
++;
1137 t
->parent
->size
+= sizeof(internal_node
);
1139 // FIXME - do we need to add a rollback entry here?
1142 t
->header
.generation
= Vcb
->superblock
.generation
;
1146 // FIXME - free this correctly
1148 tp2
= ExAllocatePoolWithTag(PagedPool
, sizeof(traverse_ptr
), ALLOC_TAG
);
1150 ERR("out of memory\n");
1154 tp2
->tree
= tp
.tree
;
1157 add_rollback(rollback
, ROLLBACK_INSERT_ITEM
, tp2
);
1165 static __inline tree_data
* first_valid_item(tree
* t
) {
1166 LIST_ENTRY
* le
= t
->itemlist
.Flink
;
1168 while (le
!= &t
->itemlist
) {
1169 tree_data
* td
= CONTAINING_RECORD(le
, tree_data
, list_entry
);
1180 void STDCALL
delete_tree_item(device_extension
* Vcb
, traverse_ptr
* tp
, LIST_ENTRY
* rollback
) {
1185 TRACE("deleting item %llx,%x,%llx (ignore = %s)\n", tp
->item
->key
.obj_id
, tp
->item
->key
.obj_type
, tp
->item
->key
.offset
, tp
->item
->ignore
? "TRUE" : "FALSE");
1187 #ifdef DEBUG_PARANOID
1188 if (tp
->item
->ignore
) {
1189 ERR("trying to delete already-deleted item %llx,%x,%llx\n", tp
->item
->key
.obj_id
, tp
->item
->key
.obj_type
, tp
->item
->key
.offset
);
1194 tp
->item
->ignore
= TRUE
;
1196 if (!tp
->tree
->write
) {
1197 tp
->tree
->write
= TRUE
;
1201 tp
->tree
->header
.num_items
--;
1203 if (tp
->tree
->header
.level
== 0)
1204 tp
->tree
->size
-= sizeof(leaf_node
) + tp
->item
->size
;
1206 tp
->tree
->size
-= sizeof(internal_node
);
1208 gen
= tp
->tree
->Vcb
->superblock
.generation
;
1212 t
->header
.generation
= gen
;
1216 tp2
= ExAllocatePoolWithTag(PagedPool
, sizeof(traverse_ptr
), ALLOC_TAG
);
1218 ERR("out of memory\n");
1222 tp2
->tree
= tp
->tree
;
1223 tp2
->item
= tp
->item
;
1225 add_rollback(rollback
, ROLLBACK_DELETE_ITEM
, tp2
);
1228 void clear_rollback(LIST_ENTRY
* rollback
) {
1231 while (!IsListEmpty(rollback
)) {
1232 LIST_ENTRY
* le
= RemoveHeadList(rollback
);
1233 ri
= CONTAINING_RECORD(le
, rollback_item
, list_entry
);
1236 case ROLLBACK_INSERT_ITEM
:
1237 case ROLLBACK_DELETE_ITEM
:
1238 ExFreePool(ri
->ptr
);
1246 void do_rollback(device_extension
* Vcb
, LIST_ENTRY
* rollback
) {
1249 while (!IsListEmpty(rollback
)) {
1250 LIST_ENTRY
* le
= RemoveHeadList(rollback
);
1251 ri
= CONTAINING_RECORD(le
, rollback_item
, list_entry
);
1254 case ROLLBACK_INSERT_ITEM
:
1256 traverse_ptr
* tp
= ri
->ptr
;
1258 if (!tp
->item
->ignore
) {
1259 tp
->item
->ignore
= TRUE
;
1260 tp
->tree
->header
.num_items
--;
1262 if (tp
->tree
->header
.level
== 0)
1263 tp
->tree
->size
-= sizeof(leaf_node
) + tp
->item
->size
;
1265 tp
->tree
->size
-= sizeof(internal_node
);
1272 case ROLLBACK_DELETE_ITEM
:
1274 traverse_ptr
* tp
= ri
->ptr
;
1276 if (tp
->item
->ignore
) {
1277 tp
->item
->ignore
= FALSE
;
1278 tp
->tree
->header
.num_items
++;
1280 if (tp
->tree
->header
.level
== 0)
1281 tp
->tree
->size
+= sizeof(leaf_node
) + tp
->item
->size
;
1283 tp
->tree
->size
+= sizeof(internal_node
);