ReactOS 0.4.16-dev-321-g63bb46a
flushthread.c File Reference
#include "btrfs_drv.h"
#include "xxhash.h"
#include "crc32c.h"
#include <ata.h>
#include <ntddscsi.h>
#include <ntddstor.h>
Include dependency graph for flushthread.c:

Go to the source code of this file.

Classes

struct  write_context
 
struct  EXTENT_ITEM_TREE2
 
struct  EXTENT_ITEM_SKINNY_METADATA
 
struct  ioctl_context_stripe
 
struct  ioctl_context
 
struct  write_superblocks_stripe
 
struct  _write_superblocks_context
 
struct  extent_range
 

Macros

#define MAX_CSUM_SIZE   (4096 - sizeof(tree_header) - (2 * sizeof(leaf_node)))
 
#define BATCH_ITEM_LIMIT   1000
 

Typedefs

typedef struct _write_superblocks_context write_superblocks_context
 

Functions

static NTSTATUS create_chunk (device_extension *Vcb, chunk *c, PIRP Irp)
 
static NTSTATUS update_tree_extents (device_extension *Vcb, tree *t, PIRP Irp, LIST_ENTRY *rollback)
 
static NTSTATUS insert_tree_item_batch (LIST_ENTRY *batchlist, device_extension *Vcb, root *r, uint64_t objid, uint8_t objtype, uint64_t offset, _In_opt_ _When_(return >=0, __drv_aliasesMem) void *data, uint16_t datalen, enum batch_operation operation)
 
 _Function_class_ (IO_COMPLETION_ROUTINE)
 
NTSTATUS write_data_phys (_In_ PDEVICE_OBJECT device, _In_ PFILE_OBJECT fileobj, _In_ uint64_t address, _In_reads_bytes_(length) void *data, _In_ uint32_t length)
 
static void add_trim_entry (device *dev, uint64_t address, uint64_t size)
 
static void clean_space_cache_chunk (device_extension *Vcb, chunk *c)
 
static void clean_space_cache (device_extension *Vcb)
 
static bool trees_consistent (device_extension *Vcb)
 
static NTSTATUS add_parents (device_extension *Vcb, PIRP Irp)
 
static void add_parents_to_cache (tree *t)
 
static bool insert_tree_extent_skinny (device_extension *Vcb, uint8_t level, uint64_t root_id, chunk *c, uint64_t address, PIRP Irp, LIST_ENTRY *rollback)
 
bool find_metadata_address_in_chunk (device_extension *Vcb, chunk *c, uint64_t *address)
 
static bool insert_tree_extent (device_extension *Vcb, uint8_t level, uint64_t root_id, chunk *c, uint64_t *new_address, PIRP Irp, LIST_ENTRY *rollback)
 
NTSTATUS get_tree_new_address (device_extension *Vcb, tree *t, PIRP Irp, LIST_ENTRY *rollback)
 
static NTSTATUS reduce_tree_extent (device_extension *Vcb, uint64_t address, tree *t, uint64_t parent_root, uint8_t level, PIRP Irp, LIST_ENTRY *rollback)
 
static NTSTATUS add_changed_extent_ref_edr (changed_extent *ce, EXTENT_DATA_REF *edr, bool old)
 
static NTSTATUS add_changed_extent_ref_sdr (changed_extent *ce, SHARED_DATA_REF *sdr, bool old)
 
static bool shared_tree_is_unique (device_extension *Vcb, tree *t, PIRP Irp, LIST_ENTRY *rollback)
 
static NTSTATUS allocate_tree_extents (device_extension *Vcb, PIRP Irp, LIST_ENTRY *rollback)
 
static NTSTATUS update_root_root (device_extension *Vcb, bool no_cache, PIRP Irp, LIST_ENTRY *rollback)
 
NTSTATUS do_tree_writes (device_extension *Vcb, LIST_ENTRY *tree_writes, bool no_free)
 
void calc_tree_checksum (device_extension *Vcb, tree_header *th)
 
static NTSTATUS write_trees (device_extension *Vcb, PIRP Irp)
 
static void update_backup_superblock (device_extension *Vcb, superblock_backup *sb, PIRP Irp)
 
static void calc_superblock_checksum (superblock *sb)
 
static NTSTATUS write_superblock (device_extension *Vcb, device *device, write_superblocks_context *context)
 
static NTSTATUS write_superblocks (device_extension *Vcb, PIRP Irp)
 
static NTSTATUS flush_changed_extent (device_extension *Vcb, chunk *c, changed_extent *ce, PIRP Irp, LIST_ENTRY *rollback)
 
void add_checksum_entry (device_extension *Vcb, uint64_t address, ULONG length, void *csum, PIRP Irp)
 
static NTSTATUS update_chunk_usage (device_extension *Vcb, PIRP Irp, LIST_ENTRY *rollback)
 
static void get_first_item (tree *t, KEY *key)
 
static NTSTATUS split_tree_at (device_extension *Vcb, tree *t, tree_data *newfirstitem, uint32_t numitems, uint32_t size)
 
static NTSTATUS split_tree (device_extension *Vcb, tree *t)
 
bool is_tree_unique (device_extension *Vcb, tree *t, PIRP Irp)
 
static NTSTATUS try_tree_amalgamate (device_extension *Vcb, tree *t, bool *done, bool *done_deletions, PIRP Irp, LIST_ENTRY *rollback)
 
static NTSTATUS update_extent_level (device_extension *Vcb, uint64_t address, tree *t, uint8_t level, PIRP Irp)
 
static NTSTATUS update_tree_extents_recursive (device_extension *Vcb, tree *t, PIRP Irp, LIST_ENTRY *rollback)
 
static NTSTATUS do_splits (device_extension *Vcb, PIRP Irp, LIST_ENTRY *rollback)
 
static NTSTATUS remove_root_extents (device_extension *Vcb, root *r, tree_holder *th, uint8_t level, tree *parent, PIRP Irp, LIST_ENTRY *rollback)
 
static NTSTATUS drop_root (device_extension *Vcb, root *r, PIRP Irp, LIST_ENTRY *rollback)
 
static NTSTATUS drop_roots (device_extension *Vcb, PIRP Irp, LIST_ENTRY *rollback)
 
NTSTATUS update_dev_item (device_extension *Vcb, device *device, PIRP Irp)
 
static void regen_bootstrap (device_extension *Vcb)
 
static NTSTATUS add_to_bootstrap (device_extension *Vcb, uint64_t obj_id, uint8_t obj_type, uint64_t offset, void *data, uint16_t size)
 
static void remove_from_bootstrap (device_extension *Vcb, uint64_t obj_id, uint8_t obj_type, uint64_t offset)
 
static NTSTATUS set_xattr (device_extension *Vcb, LIST_ENTRY *batchlist, root *subvol, uint64_t inode, char *name, uint16_t namelen, uint32_t crc32, uint8_t *data, uint16_t datalen)
 
static NTSTATUS delete_xattr (device_extension *Vcb, LIST_ENTRY *batchlist, root *subvol, uint64_t inode, char *name, uint16_t namelen, uint32_t crc32)
 
static NTSTATUS insert_sparse_extent (fcb *fcb, LIST_ENTRY *batchlist, uint64_t start, uint64_t length)
 
static NTSTATUS split_batch_item_list (batch_item_ind *bii)
 
static void rationalize_extents (fcb *fcb, PIRP Irp)
 
NTSTATUS flush_fcb (fcb *fcb, bool cache, LIST_ENTRY *batchlist, PIRP Irp)
 
void add_trim_entry_avoid_sb (device_extension *Vcb, device *dev, uint64_t address, uint64_t size)
 
static NTSTATUS drop_chunk (device_extension *Vcb, chunk *c, LIST_ENTRY *batchlist, PIRP Irp, LIST_ENTRY *rollback)
 
static NTSTATUS partial_stripe_read (device_extension *Vcb, chunk *c, partial_stripe *ps, uint64_t startoff, uint16_t parity, ULONG offset, ULONG len)
 
NTSTATUS flush_partial_stripe (device_extension *Vcb, chunk *c, partial_stripe *ps)
 
static NTSTATUS update_chunks (device_extension *Vcb, LIST_ENTRY *batchlist, PIRP Irp, LIST_ENTRY *rollback)
 
static NTSTATUS delete_root_ref (device_extension *Vcb, uint64_t subvolid, uint64_t parsubvolid, uint64_t parinode, PANSI_STRING utf8, PIRP Irp)
 
static NTSTATUS add_root_ref (_In_ device_extension *Vcb, _In_ uint64_t subvolid, _In_ uint64_t parsubvolid, _In_ __drv_aliasesMem ROOT_REF *rr, _In_opt_ PIRP Irp)
 
static NTSTATUS update_root_backref (device_extension *Vcb, uint64_t subvolid, uint64_t parsubvolid, PIRP Irp)
 
static NTSTATUS add_root_item_to_cache (device_extension *Vcb, uint64_t root, PIRP Irp)
 
static NTSTATUS flush_fileref (file_ref *fileref, LIST_ENTRY *batchlist, PIRP Irp)
 
static void flush_disk_caches (device_extension *Vcb)
 
static NTSTATUS flush_changed_dev_stats (device_extension *Vcb, device *dev, PIRP Irp)
 
static NTSTATUS flush_subvol (device_extension *Vcb, root *r, PIRP Irp)
 
static NTSTATUS test_not_full (device_extension *Vcb)
 
static NTSTATUS check_for_orphans_root (device_extension *Vcb, root *r, PIRP Irp)
 
static NTSTATUS check_for_orphans (device_extension *Vcb, PIRP Irp)
 
static NTSTATUS do_write2 (device_extension *Vcb, PIRP Irp, LIST_ENTRY *rollback)
 
NTSTATUS do_write (device_extension *Vcb, PIRP Irp)
 
static void do_flush (device_extension *Vcb)
 
 _Function_class_ (KSTART_ROUTINE)
 

Macro Definition Documentation

◆ BATCH_ITEM_LIMIT

#define BATCH_ITEM_LIMIT   1000

Definition at line 32 of file flushthread.c.

◆ MAX_CSUM_SIZE

#define MAX_CSUM_SIZE   (4096 - sizeof(tree_header) - (2 * sizeof(leaf_node)))

Definition at line 28 of file flushthread.c.

Typedef Documentation

◆ write_superblocks_context

Function Documentation

◆ _Function_class_() [1/2]

_Function_class_ ( IO_COMPLETION_ROUTINE  )

Definition at line 58 of file flushthread.c.

59 {
60 write_context* context = conptr;
61
63
64 context->iosb = Irp->IoStatus;
65 KeSetEvent(&context->Event, 0, false);
66
68}
#define UNUSED(x)
Definition: btrfs_drv.h:82
_In_ PIRP Irp
Definition: csq.h:116
#define KeSetEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:476
#define STATUS_MORE_PROCESSING_REQUIRED
Definition: shellext.h:68
Definition: http.c:7252
_In_ PDEVICE_OBJECT DeviceObject
Definition: wdfdevice.h:2055

◆ _Function_class_() [2/2]

_Function_class_ ( KSTART_ROUTINE  )

Definition at line 7914 of file flushthread.c.

7915 {
7916 DEVICE_OBJECT* devobj = context;
7918 LARGE_INTEGER due_time;
7919
7920 ObReferenceObject(devobj);
7921
7922 KeInitializeTimer(&Vcb->flush_thread_timer);
7923
7924 due_time.QuadPart = (uint64_t)Vcb->options.flush_interval * -10000000;
7925
7926 KeSetTimer(&Vcb->flush_thread_timer, due_time, NULL);
7927
7928 while (true) {
7929 KeWaitForSingleObject(&Vcb->flush_thread_timer, Executive, KernelMode, false, NULL);
7930
7931 if (!(devobj->Vpb->Flags & VPB_MOUNTED) || Vcb->removing)
7932 break;
7933
7934 if (!Vcb->locked)
7935 do_flush(Vcb);
7936
7937 KeSetTimer(&Vcb->flush_thread_timer, due_time, NULL);
7938 }
7939
7940 ObDereferenceObject(devobj);
7941 KeCancelTimer(&Vcb->flush_thread_timer);
7942
7943 KeSetEvent(&Vcb->flush_thread_finished, 0, false);
7944
7946}
#define NULL
Definition: types.h:112
#define KeWaitForSingleObject(pEvt, foo, a, b, c)
Definition: env_spec_w32.h:478
static void do_flush(device_extension *Vcb)
Definition: flushthread.c:7896
#define KernelMode
Definition: asm.h:34
#define uint64_t
Definition: nsiface.idl:62
NTSTATUS NTAPI PsTerminateSystemThread(IN NTSTATUS ExitStatus)
Definition: kill.c:1145
#define Vcb
Definition: cdprocs.h:1415
#define STATUS_SUCCESS
Definition: shellext.h:65
PVOID DeviceExtension
Definition: env_spec_w32.h:418
BOOLEAN NTAPI KeSetTimer(IN OUT PKTIMER Timer, IN LARGE_INTEGER DueTime, IN PKDPC Dpc OPTIONAL)
Definition: timerobj.c:281
BOOLEAN NTAPI KeCancelTimer(IN OUT PKTIMER Timer)
Definition: timerobj.c:206
VOID NTAPI KeInitializeTimer(OUT PKTIMER Timer)
Definition: timerobj.c:233
LONGLONG QuadPart
Definition: typedefs.h:114
#define VPB_MOUNTED
Definition: iotypes.h:1807
@ Executive
Definition: ketypes.h:415
#define ObDereferenceObject
Definition: obfuncs.h:203
#define ObReferenceObject
Definition: obfuncs.h:204

◆ add_changed_extent_ref_edr()

static NTSTATUS add_changed_extent_ref_edr ( changed_extent ce,
EXTENT_DATA_REF edr,
bool  old 
)
static

Definition at line 1007 of file flushthread.c.

1007 {
1008 LIST_ENTRY *le2, *list;
1009 changed_extent_ref* cer;
1010
1011 list = old ? &ce->old_refs : &ce->refs;
1012
1013 le2 = list->Flink;
1014 while (le2 != list) {
1016
1017 if (cer->type == TYPE_EXTENT_DATA_REF && cer->edr.root == edr->root && cer->edr.objid == edr->objid && cer->edr.offset == edr->offset) {
1018 cer->edr.count += edr->count;
1019 goto end;
1020 }
1021
1022 le2 = le2->Flink;
1023 }
1024
1026 if (!cer) {
1027 ERR("out of memory\n");
1029 }
1030
1032 RtlCopyMemory(&cer->edr, edr, sizeof(EXTENT_DATA_REF));
1034
1035end:
1036 if (old)
1037 ce->old_count += edr->count;
1038 else
1039 ce->count += edr->count;
1040
1041 return STATUS_SUCCESS;
1042}
#define ERR(fmt,...)
Definition: precomp.h:57
#define ALLOC_TAG
Definition: btrfs_drv.h:87
Definition: list.h:37
#define TYPE_EXTENT_DATA_REF
Definition: btrfs.h:38
#define InsertTailList(ListHead, Entry)
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
#define PagedPool
Definition: env_spec_w32.h:308
GLuint GLuint end
Definition: gl.h:1545
#define list
Definition: rosglue.h:35
uint64_t offset
Definition: btrfs.h:419
uint64_t root
Definition: btrfs.h:417
uint64_t objid
Definition: btrfs.h:418
uint32_t count
Definition: btrfs.h:420
Definition: typedefs.h:120
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
LIST_ENTRY list_entry
Definition: btrfs_drv.h:617
EXTENT_DATA_REF edr
Definition: btrfs_drv.h:613
uint64_t old_count
Definition: btrfs_drv.h:601
LIST_ENTRY old_refs
Definition: btrfs_drv.h:605
uint64_t count
Definition: btrfs_drv.h:600
LIST_ENTRY refs
Definition: btrfs_drv.h:604
Definition: list.h:27
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158

Referenced by update_tree_extents().

◆ add_changed_extent_ref_sdr()

static NTSTATUS add_changed_extent_ref_sdr ( changed_extent ce,
SHARED_DATA_REF sdr,
bool  old 
)
static

Definition at line 1044 of file flushthread.c.

1044 {
1045 LIST_ENTRY *le2, *list;
1046 changed_extent_ref* cer;
1047
1048 list = old ? &ce->old_refs : &ce->refs;
1049
1050 le2 = list->Flink;
1051 while (le2 != list) {
1053
1054 if (cer->type == TYPE_SHARED_DATA_REF && cer->sdr.offset == sdr->offset) {
1055 cer->sdr.count += sdr->count;
1056 goto end;
1057 }
1058
1059 le2 = le2->Flink;
1060 }
1061
1063 if (!cer) {
1064 ERR("out of memory\n");
1066 }
1067
1069 RtlCopyMemory(&cer->sdr, sdr, sizeof(SHARED_DATA_REF));
1071
1072end:
1073 if (old)
1074 ce->old_count += sdr->count;
1075 else
1076 ce->count += sdr->count;
1077
1078 return STATUS_SUCCESS;
1079}
#define TYPE_SHARED_DATA_REF
Definition: btrfs.h:41
uint32_t count
Definition: btrfs.h:442
uint64_t offset
Definition: btrfs.h:441
SHARED_DATA_REF sdr
Definition: btrfs_drv.h:614

Referenced by update_tree_extents().

◆ add_checksum_entry()

void add_checksum_entry ( device_extension Vcb,
uint64_t  address,
ULONG  length,
void csum,
PIRP  Irp 
)

Definition at line 2602 of file flushthread.c.

2602 {
2603 KEY searchkey;
2604 traverse_ptr tp, next_tp;
2606 uint64_t startaddr, endaddr;
2607 ULONG len;
2609 ULONG* bmparr;
2610 ULONG runlength, index;
2611
2612 TRACE("(%p, %I64x, %lx, %p, %p)\n", Vcb, address, length, csum, Irp);
2613
2614 searchkey.obj_id = EXTENT_CSUM_ID;
2615 searchkey.obj_type = TYPE_EXTENT_CSUM;
2616 searchkey.offset = address;
2617
2618 // FIXME - create checksum_root if it doesn't exist at all
2619
2620 Status = find_item(Vcb, Vcb->checksum_root, &tp, &searchkey, false, Irp);
2621 if (Status == STATUS_NOT_FOUND) { // tree is completely empty
2622 if (csum) { // not deleted
2623 ULONG length2 = length;
2624 uint64_t off = address;
2625 void* data = csum;
2626
2627 do {
2628 uint16_t il = (uint16_t)min(length2, MAX_CSUM_SIZE / Vcb->csum_size);
2629
2630 void* checksums = ExAllocatePoolWithTag(PagedPool, il * Vcb->csum_size, ALLOC_TAG);
2631 if (!checksums) {
2632 ERR("out of memory\n");
2633 return;
2634 }
2635
2636 RtlCopyMemory(checksums, data, il * Vcb->csum_size);
2637
2638 Status = insert_tree_item(Vcb, Vcb->checksum_root, EXTENT_CSUM_ID, TYPE_EXTENT_CSUM, off, checksums,
2639 il * Vcb->csum_size, NULL, Irp);
2640 if (!NT_SUCCESS(Status)) {
2641 ERR("insert_tree_item returned %08lx\n", Status);
2642 ExFreePool(checksums);
2643 return;
2644 }
2645
2646 length2 -= il;
2647
2648 if (length2 > 0) {
2649 off += (uint64_t)il << Vcb->sector_shift;
2650 data = (uint8_t*)data + (il * Vcb->csum_size);
2651 }
2652 } while (length2 > 0);
2653 }
2654 } else if (!NT_SUCCESS(Status)) {
2655 ERR("find_item returned %08lx\n", Status);
2656 return;
2657 } else {
2658 uint32_t tplen;
2659 void* checksums;
2660
2661 // FIXME - check entry is TYPE_EXTENT_CSUM?
2662
2663 if (tp.item->key.offset < address && tp.item->key.offset + (((uint64_t)tp.item->size << Vcb->sector_shift) / Vcb->csum_size) >= address)
2665 else
2667
2668 searchkey.obj_id = EXTENT_CSUM_ID;
2669 searchkey.obj_type = TYPE_EXTENT_CSUM;
2670 searchkey.offset = address + (length << Vcb->sector_shift);
2671
2672 Status = find_item(Vcb, Vcb->checksum_root, &tp, &searchkey, false, Irp);
2673 if (!NT_SUCCESS(Status)) {
2674 ERR("find_item returned %08lx\n", Status);
2675 return;
2676 }
2677
2678 tplen = tp.item->size / Vcb->csum_size;
2679
2680 if (tp.item->key.offset + (tplen << Vcb->sector_shift) >= address + (length << Vcb->sector_shift))
2681 endaddr = tp.item->key.offset + (tplen << Vcb->sector_shift);
2682 else
2683 endaddr = address + (length << Vcb->sector_shift);
2684
2685 TRACE("cs starts at %I64x (%lx sectors)\n", address, length);
2686 TRACE("startaddr = %I64x\n", startaddr);
2687 TRACE("endaddr = %I64x\n", endaddr);
2688
2689 len = (ULONG)((endaddr - startaddr) >> Vcb->sector_shift);
2690
2691 checksums = ExAllocatePoolWithTag(PagedPool, Vcb->csum_size * len, ALLOC_TAG);
2692 if (!checksums) {
2693 ERR("out of memory\n");
2694 return;
2695 }
2696
2697 bmparr = ExAllocatePoolWithTag(PagedPool, sizeof(ULONG) * ((len/8)+1), ALLOC_TAG);
2698 if (!bmparr) {
2699 ERR("out of memory\n");
2700 ExFreePool(checksums);
2701 return;
2702 }
2703
2704 RtlInitializeBitMap(&bmp, bmparr, len);
2706
2707 searchkey.obj_id = EXTENT_CSUM_ID;
2708 searchkey.obj_type = TYPE_EXTENT_CSUM;
2709 searchkey.offset = address;
2710
2711 Status = find_item(Vcb, Vcb->checksum_root, &tp, &searchkey, false, Irp);
2712 if (!NT_SUCCESS(Status)) {
2713 ERR("find_item returned %08lx\n", Status);
2714 ExFreePool(checksums);
2715 ExFreePool(bmparr);
2716 return;
2717 }
2718
2719 // set bit = free space, cleared bit = allocated sector
2720
2721 while (tp.item->key.offset < endaddr) {
2722 if (tp.item->key.offset >= startaddr) {
2723 if (tp.item->size > 0) {
2724 ULONG itemlen = (ULONG)min((len - ((tp.item->key.offset - startaddr) >> Vcb->sector_shift)) * Vcb->csum_size, tp.item->size);
2725
2726 RtlCopyMemory((uint8_t*)checksums + (((tp.item->key.offset - startaddr) * Vcb->csum_size) >> Vcb->sector_shift),
2727 tp.item->data, itemlen);
2728 RtlClearBits(&bmp, (ULONG)((tp.item->key.offset - startaddr) >> Vcb->sector_shift), itemlen / Vcb->csum_size);
2729 }
2730
2732 if (!NT_SUCCESS(Status)) {
2733 ERR("delete_tree_item returned %08lx\n", Status);
2734 ExFreePool(checksums);
2735 ExFreePool(bmparr);
2736 return;
2737 }
2738 }
2739
2740 if (find_next_item(Vcb, &tp, &next_tp, false, Irp)) {
2741 tp = next_tp;
2742 } else
2743 break;
2744 }
2745
2746 if (!csum) { // deleted
2747 RtlSetBits(&bmp, (ULONG)((address - startaddr) >> Vcb->sector_shift), length);
2748 } else {
2749 RtlCopyMemory((uint8_t*)checksums + (((address - startaddr) * Vcb->csum_size) >> Vcb->sector_shift),
2750 csum, length * Vcb->csum_size);
2751 RtlClearBits(&bmp, (ULONG)((address - startaddr) >> Vcb->sector_shift), length);
2752 }
2753
2754 runlength = RtlFindFirstRunClear(&bmp, &index);
2755
2756 while (runlength != 0) {
2757 if (index >= len)
2758 break;
2759
2760 if (index + runlength >= len) {
2761 runlength = len - index;
2762
2763 if (runlength == 0)
2764 break;
2765 }
2766
2767 do {
2768 uint16_t rl;
2769 uint64_t off;
2770 void* data;
2771
2772 if (runlength * Vcb->csum_size > MAX_CSUM_SIZE)
2773 rl = (uint16_t)(MAX_CSUM_SIZE / Vcb->csum_size);
2774 else
2775 rl = (uint16_t)runlength;
2776
2777 data = ExAllocatePoolWithTag(PagedPool, Vcb->csum_size * rl, ALLOC_TAG);
2778 if (!data) {
2779 ERR("out of memory\n");
2780 ExFreePool(bmparr);
2781 ExFreePool(checksums);
2782 return;
2783 }
2784
2785 RtlCopyMemory(data, (uint8_t*)checksums + (Vcb->csum_size * index), Vcb->csum_size * rl);
2786
2787 off = startaddr + ((uint64_t)index << Vcb->sector_shift);
2788
2789 Status = insert_tree_item(Vcb, Vcb->checksum_root, EXTENT_CSUM_ID, TYPE_EXTENT_CSUM, off, data, Vcb->csum_size * rl, NULL, Irp);
2790 if (!NT_SUCCESS(Status)) {
2791 ERR("insert_tree_item returned %08lx\n", Status);
2793 ExFreePool(bmparr);
2794 ExFreePool(checksums);
2795 return;
2796 }
2797
2798 runlength -= rl;
2799 index += rl;
2800 } while (runlength > 0);
2801
2802 runlength = RtlFindNextForwardRunClear(&bmp, index, &index);
2803 }
2804
2805 ExFreePool(bmparr);
2806 ExFreePool(checksums);
2807 }
2808}
unsigned short int uint16_t
Definition: acefiex.h:54
static void startaddr(void)
LONG NTSTATUS
Definition: precomp.h:26
#define index(s, c)
Definition: various.h:29
NTSTATUS insert_tree_item(_In_ _Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension *Vcb, _In_ root *r, _In_ uint64_t obj_id, _In_ uint8_t obj_type, _In_ uint64_t offset, _In_reads_bytes_opt_(size) _When_(return >=0, __drv_aliasesMem) void *data, _In_ uint16_t size, _Out_opt_ traverse_ptr *ptp, _In_opt_ PIRP Irp) __attribute__((nonnull(1
NTSTATUS NTSTATUS bool find_next_item(_Requires_lock_held_(_Curr_->tree_lock) device_extension *Vcb, const traverse_ptr *tp, traverse_ptr *next_tp, bool ignore, PIRP Irp) __attribute__((nonnull(1
NTSTATUS NTSTATUS delete_tree_item(_In_ _Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension *Vcb, _Inout_ traverse_ptr *tp) __attribute__((nonnull(1
#define RtlClearBits
Definition: dbgbitmap.h:331
#define RtlInitializeBitMap
Definition: dbgbitmap.h:326
#define RtlFindNextForwardRunClear
Definition: dbgbitmap.h:338
#define RtlSetAllBits
Definition: dbgbitmap.h:346
#define RtlFindFirstRunClear
Definition: dbgbitmap.h:334
#define RtlSetBits
Definition: dbgbitmap.h:345
UINT32 uint32_t
Definition: types.h:75
UINT64 uint64_t
Definition: types.h:77
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
static LONG find_item(PropertyBag *This, LPCOLESTR name)
Definition: propertybag.c:110
_In_ uint64_t _In_ uint64_t _In_ uint64_t _In_opt_ traverse_ptr * tp
Definition: btrfs.c:2996
#define EXTENT_CSUM_ID
Definition: btrfs.h:91
#define TYPE_EXTENT_CSUM
Definition: btrfs.h:31
#define ExFreePool(addr)
Definition: env_spec_w32.h:352
#define MAX_CSUM_SIZE
Definition: flushthread.c:28
Status
Definition: gdiplustypes.h:25
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
GLuint address
Definition: glext.h:9393
GLuint index
Definition: glext.h:6031
GLuint GLsizei GLsizei * length
Definition: glext.h:6040
GLenum GLsizei len
Definition: glext.h:6722
BITMAP bmp
Definition: alphablend.c:62
#define min(a, b)
Definition: monoChain.cc:55
BYTE uint8_t
Definition: msvideo1.c:66
#define uint16_t
Definition: nsiface.idl:60
#define STATUS_NOT_FOUND
Definition: shellext.h:72
#define TRACE(s)
Definition: solgame.cpp:4
Definition: btrfs.h:143
uint8_t obj_type
Definition: btrfs.h:145
uint64_t obj_id
Definition: btrfs.h:144
uint64_t offset
Definition: btrfs.h:146
uint8_t * data
Definition: btrfs_drv.h:415
uint16_t size
Definition: btrfs_drv.h:414
Definition: ffs.h:52
tree_data * item
Definition: btrfs_drv.h:509
uint32_t ULONG
Definition: typedefs.h:59

Referenced by balance_data_chunk(), decrease_extent_refcount(), flush_fcb(), and rationalize_extents().

◆ add_parents()

static NTSTATUS add_parents ( device_extension Vcb,
PIRP  Irp 
)
static

Definition at line 615 of file flushthread.c.

615 {
616 ULONG level;
617 LIST_ENTRY* le;
618
619 for (level = 0; level <= 255; level++) {
620 bool nothing_found = true;
621
622 TRACE("level = %lu\n", level);
623
624 le = Vcb->trees.Flink;
625 while (le != &Vcb->trees) {
627
628 if (t->write && t->header.level == level) {
629 TRACE("tree %p: root = %I64x, level = %x, parent = %p\n", t, t->header.tree_id, t->header.level, t->parent);
630
631 nothing_found = false;
632
633 if (t->parent) {
634 if (!t->parent->write)
635 TRACE("adding tree %p (level %x)\n", t->parent, t->header.level);
636
637 t->parent->write = true;
638 } else if (t->root != Vcb->root_root && t->root != Vcb->chunk_root) {
639 KEY searchkey;
642
643 searchkey.obj_id = t->root->id;
644 searchkey.obj_type = TYPE_ROOT_ITEM;
645 searchkey.offset = 0xffffffffffffffff;
646
647 Status = find_item(Vcb, Vcb->root_root, &tp, &searchkey, false, Irp);
648 if (!NT_SUCCESS(Status)) {
649 ERR("error - find_item returned %08lx\n", Status);
650 return Status;
651 }
652
653 if (tp.item->key.obj_id != searchkey.obj_id || tp.item->key.obj_type != searchkey.obj_type) {
654 ERR("could not find ROOT_ITEM for tree %I64x\n", searchkey.obj_id);
656 }
657
658 if (tp.item->size < sizeof(ROOT_ITEM)) { // if not full length, delete and create new entry
660
661 if (!ri) {
662 ERR("out of memory\n");
664 }
665
666 RtlCopyMemory(ri, &t->root->root_item, sizeof(ROOT_ITEM));
667
669 if (!NT_SUCCESS(Status)) {
670 ERR("delete_tree_item returned %08lx\n", Status);
671 ExFreePool(ri);
672 return Status;
673 }
674
676 if (!NT_SUCCESS(Status)) {
677 ERR("insert_tree_item returned %08lx\n", Status);
678 ExFreePool(ri);
679 return Status;
680 }
681 }
682
683 tree* t2 = tp.tree;
684 while (t2) {
685 t2->write = true;
686
687 t2 = t2->parent;
688 }
689 }
690 }
691
692 le = le->Flink;
693 }
694
695 if (nothing_found)
696 break;
697 }
698
699 return STATUS_SUCCESS;
700}
#define TYPE_ROOT_ITEM
Definition: btrfs.h:32
GLint level
Definition: gl.h:1546
GLdouble GLdouble t
Definition: gl.h:2047
#define STATUS_INTERNAL_ERROR
Definition: ntstatus.h:465
bool write
Definition: btrfs_drv.h:440
struct _tree * parent
Definition: btrfs_drv.h:431
tree * tree
Definition: btrfs_drv.h:508

Referenced by do_write2().

◆ add_parents_to_cache()

static void add_parents_to_cache ( tree t)
static

Definition at line 702 of file flushthread.c.

702 {
703 while (t->parent) {
704 t = t->parent;
705 t->write = true;
706 }
707}

Referenced by insert_tree_extent(), and insert_tree_extent_skinny().

◆ add_root_item_to_cache()

static NTSTATUS add_root_item_to_cache ( device_extension Vcb,
uint64_t  root,
PIRP  Irp 
)
static

Definition at line 6472 of file flushthread.c.

6472 {
6473 KEY searchkey;
6476
6477 searchkey.obj_id = root;
6478 searchkey.obj_type = TYPE_ROOT_ITEM;
6479 searchkey.offset = 0xffffffffffffffff;
6480
6481 Status = find_item(Vcb, Vcb->root_root, &tp, &searchkey, false, Irp);
6482 if (!NT_SUCCESS(Status)) {
6483 ERR("error - find_item returned %08lx\n", Status);
6484 return Status;
6485 }
6486
6487 if (tp.item->key.obj_id != searchkey.obj_id || tp.item->key.obj_type != searchkey.obj_type) {
6488 ERR("could not find ROOT_ITEM for tree %I64x\n", searchkey.obj_id);
6489 return STATUS_INTERNAL_ERROR;
6490 }
6491
6492 if (tp.item->size < sizeof(ROOT_ITEM)) { // if not full length, create new entry with new bits zeroed
6494 if (!ri) {
6495 ERR("out of memory\n");
6497 }
6498
6499 if (tp.item->size > 0)
6501
6502 RtlZeroMemory(((uint8_t*)ri) + tp.item->size, sizeof(ROOT_ITEM) - tp.item->size);
6503
6505 if (!NT_SUCCESS(Status)) {
6506 ERR("delete_tree_item returned %08lx\n", Status);
6507 ExFreePool(ri);
6508 return Status;
6509 }
6510
6511 Status = insert_tree_item(Vcb, Vcb->root_root, searchkey.obj_id, searchkey.obj_type, tp.item->key.offset, ri, sizeof(ROOT_ITEM), NULL, Irp);
6512 if (!NT_SUCCESS(Status)) {
6513 ERR("insert_tree_item returned %08lx\n", Status);
6514 ExFreePool(ri);
6515 return Status;
6516 }
6517 } else {
6518 tp.tree->write = true;
6519 }
6520
6521 return STATUS_SUCCESS;
6522}
struct _root root
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262

Referenced by do_write2().

◆ add_root_ref()

static NTSTATUS add_root_ref ( _In_ device_extension Vcb,
_In_ uint64_t  subvolid,
_In_ uint64_t  parsubvolid,
_In_ __drv_aliasesMem ROOT_REF rr,
_In_opt_ PIRP  Irp 
)
static

Definition at line 6343 of file flushthread.c.

6343 {
6344 KEY searchkey;
6347
6348 searchkey.obj_id = parsubvolid;
6349 searchkey.obj_type = TYPE_ROOT_REF;
6350 searchkey.offset = subvolid;
6351
6352 Status = find_item(Vcb, Vcb->root_root, &tp, &searchkey, false, Irp);
6353 if (!NT_SUCCESS(Status)) {
6354 ERR("error - find_item returned %08lx\n", Status);
6355 return Status;
6356 }
6357
6358 if (!keycmp(searchkey, tp.item->key)) {
6359 uint16_t rrsize = tp.item->size + (uint16_t)offsetof(ROOT_REF, name[0]) + rr->n;
6360 uint8_t* rr2;
6361
6363 if (!rr2) {
6364 ERR("out of memory\n");
6366 }
6367
6368 if (tp.item->size > 0)
6369 RtlCopyMemory(rr2, tp.item->data, tp.item->size);
6370
6371 RtlCopyMemory(rr2 + tp.item->size, rr, offsetof(ROOT_REF, name[0]) + rr->n);
6372 ExFreePool(rr);
6373
6375 if (!NT_SUCCESS(Status)) {
6376 ERR("delete_tree_item returned %08lx\n", Status);
6377 ExFreePool(rr2);
6378 return Status;
6379 }
6380
6381 Status = insert_tree_item(Vcb, Vcb->root_root, searchkey.obj_id, searchkey.obj_type, searchkey.offset, rr2, rrsize, NULL, Irp);
6382 if (!NT_SUCCESS(Status)) {
6383 ERR("insert_tree_item returned %08lx\n", Status);
6384 ExFreePool(rr2);
6385 return Status;
6386 }
6387 } else {
6388 Status = insert_tree_item(Vcb, Vcb->root_root, searchkey.obj_id, searchkey.obj_type, searchkey.offset, rr, (uint16_t)offsetof(ROOT_REF, name[0]) + rr->n, NULL, Irp);
6389 if (!NT_SUCCESS(Status)) {
6390 ERR("insert_tree_item returned %08lx\n", Status);
6391 ExFreePool(rr);
6392 return Status;
6393 }
6394 }
6395
6396 return STATUS_SUCCESS;
6397}
#define keycmp(key1, key2)
Definition: btrfs_drv.h:1016
#define TYPE_ROOT_REF
Definition: btrfs.h:34
#define offsetof(TYPE, MEMBER)
Definition: name.c:39

Referenced by flush_fileref().

◆ add_to_bootstrap()

static NTSTATUS add_to_bootstrap ( device_extension Vcb,
uint64_t  obj_id,
uint8_t  obj_type,
uint64_t  offset,
void data,
uint16_t  size 
)
static

Definition at line 4160 of file flushthread.c.

4160 {
4161 sys_chunk* sc;
4162 LIST_ENTRY* le;
4163
4164 if (Vcb->superblock.n + sizeof(KEY) + size > SYS_CHUNK_ARRAY_SIZE) {
4165 ERR("error - bootstrap is full\n");
4166 return STATUS_INTERNAL_ERROR;
4167 }
4168
4170 if (!sc) {
4171 ERR("out of memory\n");
4173 }
4174
4175 sc->key.obj_id = obj_id;
4176 sc->key.obj_type = obj_type;
4177 sc->key.offset = offset;
4178 sc->size = size;
4180 if (!sc->data) {
4181 ERR("out of memory\n");
4182 ExFreePool(sc);
4184 }
4185
4186 RtlCopyMemory(sc->data, data, sc->size);
4187
4188 le = Vcb->sys_chunks.Flink;
4189 while (le != &Vcb->sys_chunks) {
4191
4192 if (keycmp(sc2->key, sc->key) == 1)
4193 break;
4194
4195 le = le->Flink;
4196 }
4197 InsertTailList(le, &sc->list_entry);
4198
4199 Vcb->superblock.n += sizeof(KEY) + size;
4200
4202
4203 return STATUS_SUCCESS;
4204}
#define SYS_CHUNK_ARRAY_SIZE
Definition: btrfs.h:194
static void regen_bootstrap(device_extension *Vcb)
Definition: flushthread.c:4138
GLsizeiptr size
Definition: glext.h:5919
GLintptr offset
Definition: glext.h:5920
#define KEY
Definition: profile.c:30
LIST_ENTRY list_entry
Definition: btrfs_drv.h:624
USHORT size
Definition: btrfs_drv.h:623
void * data
Definition: btrfs_drv.h:622

Referenced by create_chunk().

◆ add_trim_entry()

static void add_trim_entry ( device dev,
uint64_t  address,
uint64_t  size 
)
static

Definition at line 157 of file flushthread.c.

157 {
159 if (!s) {
160 ERR("out of memory\n");
161 return;
162 }
163
164 s->address = address;
165 s->size = size;
166 dev->num_trim_entries++;
167
168 InsertTailList(&dev->trim_list, &s->list_entry);
169}
GLdouble s
Definition: gl.h:2039

Referenced by add_trim_entry_avoid_sb(), and clean_space_cache_chunk().

◆ add_trim_entry_avoid_sb()

void add_trim_entry_avoid_sb ( device_extension Vcb,
device dev,
uint64_t  address,
uint64_t  size 
)

Definition at line 5507 of file flushthread.c.

5507 {
5508 int i;
5509 ULONG sblen = (ULONG)sector_align(sizeof(superblock), Vcb->superblock.sector_size);
5510
5511 i = 0;
5512 while (superblock_addrs[i] != 0) {
5513 if (superblock_addrs[i] + sblen >= address && superblock_addrs[i] < address + size) {
5514 if (superblock_addrs[i] > address)
5516
5517 if (size <= superblock_addrs[i] + sblen - address)
5518 return;
5519
5520 size -= superblock_addrs[i] + sblen - address;
5521 address = superblock_addrs[i] + sblen;
5522 } else if (superblock_addrs[i] > address + size)
5523 break;
5524
5525 i++;
5526 }
5527
5529}
static uint64_t __inline sector_align(uint64_t n, uint64_t a)
static const uint64_t superblock_addrs[]
Definition: btrfs.h:16
static void add_trim_entry(device *dev, uint64_t address, uint64_t size)
Definition: flushthread.c:157
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248

Referenced by drop_chunk(), and trim_unalloc_space().

◆ allocate_tree_extents()

static NTSTATUS allocate_tree_extents ( device_extension Vcb,
PIRP  Irp,
LIST_ENTRY rollback 
)
static

Definition at line 1465 of file flushthread.c.

1465 {
1466 LIST_ENTRY* le;
1468 bool changed = false;
1469 uint8_t max_level = 0, level;
1470
1471 TRACE("(%p)\n", Vcb);
1472
1473 le = Vcb->trees.Flink;
1474 while (le != &Vcb->trees) {
1476
1477 if (t->write && !t->has_new_address) {
1478 chunk* c;
1479
1480 if (t->has_address) {
1481 c = get_chunk_from_address(Vcb, t->header.address);
1482
1483 if (c) {
1484 if (!c->cache_loaded) {
1486
1487 if (!c->cache_loaded) {
1489
1490 if (!NT_SUCCESS(Status)) {
1491 ERR("load_cache_chunk returned %08lx\n", Status);
1493 return Status;
1494 }
1495 }
1496
1498 }
1499 }
1500 }
1501
1503 if (!NT_SUCCESS(Status)) {
1504 ERR("get_tree_new_address returned %08lx\n", Status);
1505 return Status;
1506 }
1507
1508 TRACE("allocated extent %I64x\n", t->new_address);
1509
1510 c = get_chunk_from_address(Vcb, t->new_address);
1511
1512 if (c)
1513 c->used += Vcb->superblock.node_size;
1514 else {
1515 ERR("could not find chunk for address %I64x\n", t->new_address);
1516 return STATUS_INTERNAL_ERROR;
1517 }
1518
1519 changed = true;
1520
1521 if (t->header.level > max_level)
1522 max_level = t->header.level;
1523 }
1524
1525 le = le->Flink;
1526 }
1527
1528 if (!changed)
1529 return STATUS_SUCCESS;
1530
1531 level = max_level;
1532 do {
1533 le = Vcb->trees.Flink;
1534 while (le != &Vcb->trees) {
1536
1537 if (t->write && !t->updated_extents && t->has_address && t->header.level == level) {
1539 if (!NT_SUCCESS(Status)) {
1540 ERR("update_tree_extents returned %08lx\n", Status);
1541 return Status;
1542 }
1543 }
1544
1545 le = le->Flink;
1546 }
1547
1548 if (level == 0)
1549 break;
1550
1551 level--;
1552 } while (true);
1553
1554 return STATUS_SUCCESS;
1555}
#define acquire_chunk_lock(c, Vcb)
Definition: btrfs_drv.h:1139
_In_ fcb _In_ chunk _In_ uint64_t _In_ uint64_t _In_ bool _In_opt_ void _In_opt_ PIRP _In_ LIST_ENTRY * rollback
Definition: btrfs_drv.h:1365
NTSTATUS load_cache_chunk(device_extension *Vcb, chunk *c, PIRP Irp)
Definition: free-space.c:980
NTSTATUS NTSTATUS NTSTATUS NTSTATUS NTSTATUS chunk * get_chunk_from_address(device_extension *Vcb, uint64_t address) __attribute__((nonnull(1)))
#define release_chunk_lock(c, Vcb)
Definition: btrfs_drv.h:1140
static NTSTATUS update_tree_extents(device_extension *Vcb, tree *t, PIRP Irp, LIST_ENTRY *rollback)
Definition: flushthread.c:1110
NTSTATUS get_tree_new_address(device_extension *Vcb, tree *t, PIRP Irp, LIST_ENTRY *rollback)
Definition: flushthread.c:878
const GLubyte * c
Definition: glext.h:8905
#define c
Definition: ke_i.h:80

Referenced by do_write2().

◆ calc_superblock_checksum()

static void calc_superblock_checksum ( superblock sb)
static

Definition at line 2211 of file flushthread.c.

2211 {
2212 switch (sb->csum_type) {
2213 case CSUM_TYPE_CRC32C:
2214 *(uint32_t*)sb = ~calc_crc32c(0xffffffff, (uint8_t*)&sb->uuid, (ULONG)sizeof(superblock) - sizeof(sb->checksum));
2215 break;
2216
2217 case CSUM_TYPE_XXHASH:
2218 *(uint64_t*)sb = XXH64(&sb->uuid, sizeof(superblock) - sizeof(sb->checksum), 0);
2219 break;
2220
2221 case CSUM_TYPE_SHA256:
2222 calc_sha256((uint8_t*)sb, &sb->uuid, sizeof(superblock) - sizeof(sb->checksum));
2223 break;
2224
2225 case CSUM_TYPE_BLAKE2:
2226 blake2b((uint8_t*)sb, BLAKE2_HASH_SIZE, &sb->uuid, sizeof(superblock) - sizeof(sb->checksum));
2227 break;
2228 }
2229}
void blake2b(void *out, size_t outlen, const void *in, size_t inlen)
Definition: blake2b-ref.c:237
#define BLAKE2_HASH_SIZE
Definition: btrfs_drv.h:1252
void calc_sha256(uint8_t *hash, const void *input, size_t len)
Definition: sha256.c:126
crc_func calc_crc32c
Definition: crc32c.c:23
superblock * sb
Definition: btrfs.c:4261
#define CSUM_TYPE_SHA256
Definition: btrfs.h:134
#define CSUM_TYPE_XXHASH
Definition: btrfs.h:133
#define CSUM_TYPE_BLAKE2
Definition: btrfs.h:135
#define CSUM_TYPE_CRC32C
Definition: btrfs.h:132
uint16_t csum_type
Definition: btrfs.h:247
BTRFS_UUID uuid
Definition: btrfs.h:225
uint8_t checksum[32]
Definition: btrfs.h:224
XXH_PUBLIC_API unsigned long long XXH64(const void *input, size_t len, unsigned long long seed)
Definition: xxhash.c:555

Referenced by write_superblock().

◆ calc_tree_checksum()

void calc_tree_checksum ( device_extension Vcb,
tree_header th 
)

Definition at line 1806 of file flushthread.c.

1806 {
1807 switch (Vcb->superblock.csum_type) {
1808 case CSUM_TYPE_CRC32C:
1809 *((uint32_t*)th) = ~calc_crc32c(0xffffffff, (uint8_t*)&th->fs_uuid, Vcb->superblock.node_size - sizeof(th->csum));
1810 break;
1811
1812 case CSUM_TYPE_XXHASH:
1813 *((uint64_t*)th) = XXH64((uint8_t*)&th->fs_uuid, Vcb->superblock.node_size - sizeof(th->csum), 0);
1814 break;
1815
1816 case CSUM_TYPE_SHA256:
1817 calc_sha256((uint8_t*)th, &th->fs_uuid, Vcb->superblock.node_size - sizeof(th->csum));
1818 break;
1819
1820 case CSUM_TYPE_BLAKE2:
1821 blake2b((uint8_t*)th, BLAKE2_HASH_SIZE, &th->fs_uuid, Vcb->superblock.node_size - sizeof(th->csum));
1822 break;
1823 }
1824}
uint8_t csum[32]
Definition: btrfs.h:154
BTRFS_UUID fs_uuid
Definition: btrfs.h:155

Referenced by snapshot_tree_copy(), write_metadata_items(), and write_trees().

◆ check_for_orphans()

static NTSTATUS check_for_orphans ( device_extension Vcb,
PIRP  Irp 
)
static

Definition at line 7450 of file flushthread.c.

7450 {
7452 LIST_ENTRY* le;
7453
7454 if (IsListEmpty(&Vcb->dirty_filerefs))
7455 return STATUS_SUCCESS;
7456
7457 le = Vcb->dirty_filerefs.Flink;
7458 while (le != &Vcb->dirty_filerefs) {
7459 file_ref* fr = CONTAINING_RECORD(le, file_ref, list_entry_dirty);
7460
7461 if (!fr->fcb->subvol->checked_for_orphans) {
7463 if (!NT_SUCCESS(Status)) {
7464 ERR("check_for_orphans_root returned %08lx\n", Status);
7465 return Status;
7466 }
7467
7468 fr->fcb->subvol->checked_for_orphans = true;
7469 }
7470
7471 le = le->Flink;
7472 }
7473
7474 return STATUS_SUCCESS;
7475}
#define IsListEmpty(ListHead)
Definition: env_spec_w32.h:954
static NTSTATUS check_for_orphans_root(device_extension *Vcb, root *r, PIRP Irp)
Definition: flushthread.c:7375
struct _root * subvol
Definition: btrfs_drv.h:288
fcb * fcb
Definition: btrfs_drv.h:342

Referenced by do_write2().

◆ check_for_orphans_root()

static NTSTATUS check_for_orphans_root ( device_extension Vcb,
root r,
PIRP  Irp 
)
static

Definition at line 7375 of file flushthread.c.

7375 {
7377 KEY searchkey;
7380
7381 TRACE("(%p, %p)\n", Vcb, r);
7382
7384
7385 searchkey.obj_id = BTRFS_ORPHAN_INODE_OBJID;
7386 searchkey.obj_type = TYPE_ORPHAN_INODE;
7387 searchkey.offset = 0;
7388
7389 Status = find_item(Vcb, r, &tp, &searchkey, false, Irp);
7390 if (!NT_SUCCESS(Status)) {
7391 ERR("find_item returned %08lx\n", Status);
7392 return Status;
7393 }
7394
7395 do {
7396 traverse_ptr next_tp;
7397
7398 if (tp.item->key.obj_id > searchkey.obj_id || (tp.item->key.obj_id == searchkey.obj_id && tp.item->key.obj_type > searchkey.obj_type))
7399 break;
7400
7401 if (tp.item->key.obj_id == searchkey.obj_id && tp.item->key.obj_type == searchkey.obj_type) {
7402 fcb* fcb;
7403
7404 TRACE("removing orphaned inode %I64x\n", tp.item->key.offset);
7405
7406 Status = open_fcb(Vcb, r, tp.item->key.offset, 0, NULL, false, NULL, &fcb, PagedPool, Irp);
7407 if (!NT_SUCCESS(Status))
7408 ERR("open_fcb returned %08lx\n", Status);
7409 else {
7410 if (fcb->inode_item.st_nlink == 0) {
7412 Status = excise_extents(Vcb, fcb, 0, sector_align(fcb->inode_item.st_size, Vcb->superblock.sector_size), Irp, &rollback);
7413 if (!NT_SUCCESS(Status)) {
7414 ERR("excise_extents returned %08lx\n", Status);
7415 goto end;
7416 }
7417 }
7418
7419 fcb->deleted = true;
7420
7422 }
7423
7424 free_fcb(fcb);
7425
7427 if (!NT_SUCCESS(Status)) {
7428 ERR("delete_tree_item returned %08lx\n", Status);
7429 goto end;
7430 }
7431 }
7432 }
7433
7434 if (find_next_item(Vcb, &tp, &next_tp, false, Irp))
7435 tp = next_tp;
7436 else
7437 break;
7438 } while (true);
7439
7441
7443
7444end:
7446
7447 return Status;
7448}
NTSTATUS NTSTATUS NTSTATUS NTSTATUS NTSTATUS excise_extents(device_extension *Vcb, fcb *fcb, uint64_t start_data, uint64_t end_data, PIRP Irp, LIST_ENTRY *rollback) __attribute__((nonnull(1
struct _fcb fcb
Definition: btrfs_drv.h:1364
void do_rollback(device_extension *Vcb, LIST_ENTRY *rollback) __attribute__((nonnull(1
NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lock_held_(_Curr_->fcb_lock) device_extension *Vcb, root *subvol, uint64_t inode, uint8_t type, PANSI_STRING utf8, bool always_add_hl, fcb *parent, fcb **pfcb, POOL_TYPE pooltype, PIRP Irp)
Definition: create.c:706
NTSTATUS NTSTATUS void clear_rollback(LIST_ENTRY *rollback) __attribute__((nonnull(1)))
void mark_fcb_dirty(_In_ fcb *fcb)
Definition: btrfs.c:1695
void free_fcb(_Inout_ fcb *fcb)
Definition: btrfs.c:1734
#define TYPE_ORPHAN_INODE
Definition: btrfs.h:27
#define BTRFS_ORPHAN_INODE_OBJID
Definition: btrfs.h:130
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
#define BTRFS_TYPE_DIRECTORY
Definition: shellext.h:86
uint32_t st_nlink
Definition: btrfs.h:292
uint64_t st_size
Definition: btrfs.h:289
bool deleted
Definition: btrfs_drv.h:295
INODE_ITEM inode_item
Definition: btrfs_drv.h:292
uint8_t type
Definition: btrfs_drv.h:291

Referenced by check_for_orphans().

◆ clean_space_cache()

static void clean_space_cache ( device_extension Vcb)
static

Definition at line 403 of file flushthread.c.

403 {
404 LIST_ENTRY* le;
405 chunk* c;
406#ifndef DEBUG_TRIM_EMULATION
407 ULONG num;
408#endif
409
410 TRACE("(%p)\n", Vcb);
411
412 ExAcquireResourceSharedLite(&Vcb->chunk_lock, true);
413
414 le = Vcb->chunks.Flink;
415 while (le != &Vcb->chunks) {
417
418 if (c->space_changed) {
420
421 if (c->space_changed) {
422 if (Vcb->trim && !Vcb->options.no_trim)
424
425 space_list_merge(&c->space, &c->space_size, &c->deleting);
426
427 while (!IsListEmpty(&c->deleting)) {
429
430 ExFreePool(s);
431 }
432 }
433
434 c->space_changed = false;
435
437 }
438
439 le = le->Flink;
440 }
441
442 ExReleaseResourceLite(&Vcb->chunk_lock);
443
444 if (Vcb->trim && !Vcb->options.no_trim) {
445#ifndef DEBUG_TRIM_EMULATION
447 ULONG total_num;
448
449 context.left = 0;
450
451 le = Vcb->devices.Flink;
452 while (le != &Vcb->devices) {
454
455 if (dev->devobj && !dev->readonly && dev->trim && dev->num_trim_entries > 0)
456 context.left++;
457
458 le = le->Flink;
459 }
460
461 if (context.left == 0)
462 return;
463
464 total_num = context.left;
465 num = 0;
466
468
470 if (!context.stripes) {
471 ERR("out of memory\n");
472 return;
473 }
474
475 RtlZeroMemory(context.stripes, sizeof(ioctl_context_stripe) * context.left);
476#endif
477
478 le = Vcb->devices.Flink;
479 while (le != &Vcb->devices) {
481
482 if (dev->devobj && !dev->readonly && dev->trim && dev->num_trim_entries > 0) {
483#ifdef DEBUG_TRIM_EMULATION
484 trim_emulation(dev);
485#else
486 LIST_ENTRY* le2;
488 DEVICE_DATA_SET_RANGE* ranges;
489 ULONG datalen = (ULONG)sector_align(sizeof(DEVICE_MANAGE_DATA_SET_ATTRIBUTES), sizeof(uint64_t)) + (dev->num_trim_entries * sizeof(DEVICE_DATA_SET_RANGE)), i;
491
493 if (!stripe->dmdsa) {
494 ERR("out of memory\n");
495 goto nextdev;
496 }
497
498 stripe->dmdsa->Size = sizeof(DEVICE_MANAGE_DATA_SET_ATTRIBUTES);
499 stripe->dmdsa->Action = DeviceDsmAction_Trim;
501 stripe->dmdsa->ParameterBlockOffset = 0;
502 stripe->dmdsa->ParameterBlockLength = 0;
503 stripe->dmdsa->DataSetRangesOffset = (ULONG)sector_align(sizeof(DEVICE_MANAGE_DATA_SET_ATTRIBUTES), sizeof(uint64_t));
504 stripe->dmdsa->DataSetRangesLength = dev->num_trim_entries * sizeof(DEVICE_DATA_SET_RANGE);
505
506 ranges = (DEVICE_DATA_SET_RANGE*)((uint8_t*)stripe->dmdsa + stripe->dmdsa->DataSetRangesOffset);
507
508 i = 0;
509
510 le2 = dev->trim_list.Flink;
511 while (le2 != &dev->trim_list) {
513
514 ranges[i].StartingOffset = s->address;
515 ranges[i].LengthInBytes = s->size;
516 i++;
517
518 le2 = le2->Flink;
519 }
520
521 stripe->Irp = IoAllocateIrp(dev->devobj->StackSize, false);
522
523 if (!stripe->Irp) {
524 ERR("IoAllocateIrp failed\n");
525 goto nextdev;
526 }
527
530 IrpSp->FileObject = dev->fileobj;
531
533 IrpSp->Parameters.DeviceIoControl.InputBufferLength = datalen;
534 IrpSp->Parameters.DeviceIoControl.OutputBufferLength = 0;
535
536 stripe->Irp->AssociatedIrp.SystemBuffer = stripe->dmdsa;
537 stripe->Irp->Flags |= IRP_BUFFERED_IO;
538 stripe->Irp->UserBuffer = NULL;
539 stripe->Irp->UserIosb = &stripe->iosb;
540
541 IoSetCompletionRoutine(stripe->Irp, ioctl_completion, &context, true, true, true);
542
543 IoCallDriver(dev->devobj, stripe->Irp);
544
545nextdev:
546#endif
547 while (!IsListEmpty(&dev->trim_list)) {
549 ExFreePool(s);
550 }
551
552 dev->num_trim_entries = 0;
553
554#ifndef DEBUG_TRIM_EMULATION
555 num++;
556#endif
557 }
558
559 le = le->Flink;
560 }
561
562#ifndef DEBUG_TRIM_EMULATION
564
565 for (num = 0; num < total_num; num++) {
566 if (context.stripes[num].dmdsa)
567 ExFreePool(context.stripes[num].dmdsa);
568
569 if (context.stripes[num].Irp)
570 IoFreeIrp(context.stripes[num].Irp);
571 }
572
573 ExFreePool(context.stripes);
574#endif
575 }
576}
void space_list_merge(LIST_ENTRY *spacelist, LIST_ENTRY *spacelist_size, LIST_ENTRY *deleting)
Definition: free-space.c:1657
_In_ PIO_STACK_LOCATION IrpSp
Definition: create.c:4137
#define KeInitializeEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:477
#define RemoveHeadList(ListHead)
Definition: env_spec_w32.h:964
#define NonPagedPool
Definition: env_spec_w32.h:307
#define ExAcquireResourceSharedLite(res, wait)
Definition: env_spec_w32.h:621
static void clean_space_cache_chunk(device_extension *Vcb, chunk *c)
Definition: flushthread.c:171
GLuint GLuint num
Definition: glext.h:9618
#define IoSetCompletionRoutine(_Irp, _CompletionRoutine, _Context, _InvokeOnSuccess, _InvokeOnError, _InvokeOnCancel)
Definition: irp.cpp:490
int const JOCTET unsigned int datalen
Definition: jpeglib.h:1031
struct _DEVICE_MANAGE_DATA_SET_ATTRIBUTES DEVICE_MANAGE_DATA_SET_ATTRIBUTES
#define DEVICE_DSM_FLAG_TRIM_NOT_FS_ALLOCATED
Definition: ntddstor.h:764
#define IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES
Definition: ntddstor.h:181
#define DeviceDsmAction_Trim
Definition: ntddstor.h:276
struct _DEVICE_DATA_SET_RANGE DEVICE_DATA_SET_RANGE
@ NotificationEvent
VOID FASTCALL ExReleaseResourceLite(IN PERESOURCE Resource)
Definition: resource.c:1822
PIRP NTAPI IoAllocateIrp(IN CCHAR StackSize, IN BOOLEAN ChargeQuota)
Definition: irp.c:615
#define IoCallDriver
Definition: irp.c:1225
VOID NTAPI IoFreeIrp(IN PIRP Irp)
Definition: irp.c:1666
#define IRP_MJ_DEVICE_CONTROL
Definition: rdpdr.c:52
ULONGLONG LengthInBytes
Definition: ntddstor.h:768
LONGLONG StartingOffset
Definition: ntddstor.h:767
union _IO_STACK_LOCATION::@1581 Parameters
struct _IO_STACK_LOCATION::@1581::@1582 DeviceIoControl
PFILE_OBJECT FileObject
Definition: iotypes.h:3169
Definition: devices.h:37
Definition: write.c:113
__drv_aliasesMem FORCEINLINE PIO_STACK_LOCATION IoGetNextIrpStackLocation(_In_ PIRP Irp)
Definition: iofuncs.h:2695
#define IRP_BUFFERED_IO

Referenced by do_write2().

◆ clean_space_cache_chunk()

static void clean_space_cache_chunk ( device_extension Vcb,
chunk c 
)
static

Definition at line 171 of file flushthread.c.

171 {
172 LIST_ENTRY* le;
173 ULONG type;
174
175 if (c->chunk_item->type & BLOCK_FLAG_DUPLICATE)
177 else if (c->chunk_item->type & BLOCK_FLAG_RAID0)
179 else if (c->chunk_item->type & BLOCK_FLAG_RAID1)
181 else if (c->chunk_item->type & BLOCK_FLAG_RAID10)
183 else if (c->chunk_item->type & BLOCK_FLAG_RAID5)
185 else if (c->chunk_item->type & BLOCK_FLAG_RAID6)
187 else if (c->chunk_item->type & BLOCK_FLAG_RAID1C3)
189 else if (c->chunk_item->type & BLOCK_FLAG_RAID1C4)
191 else // SINGLE
193
194 le = c->deleting.Flink;
195 while (le != &c->deleting) {
197
198 if (!Vcb->options.no_barrier || !(c->chunk_item->type & BLOCK_FLAG_METADATA)) {
199 CHUNK_ITEM_STRIPE* cis = (CHUNK_ITEM_STRIPE*)&c->chunk_item[1];
200
202 uint16_t i;
203
204 for (i = 0; i < c->chunk_item->num_stripes; i++) {
205 if (c->devices[i] && c->devices[i]->devobj && !c->devices[i]->readonly && c->devices[i]->trim)
206 add_trim_entry(c->devices[i], s->address - c->offset + cis[i].offset, s->size);
207 }
208 } else if (type == BLOCK_FLAG_RAID0) {
209 uint64_t startoff, endoff;
210 uint16_t startoffstripe, endoffstripe, i;
211
212 get_raid0_offset(s->address - c->offset, c->chunk_item->stripe_length, c->chunk_item->num_stripes, &startoff, &startoffstripe);
213 get_raid0_offset(s->address - c->offset + s->size - 1, c->chunk_item->stripe_length, c->chunk_item->num_stripes, &endoff, &endoffstripe);
214
215 for (i = 0; i < c->chunk_item->num_stripes; i++) {
216 if (c->devices[i] && c->devices[i]->devobj && !c->devices[i]->readonly && c->devices[i]->trim) {
217 uint64_t stripestart, stripeend;
218
219 if (startoffstripe > i)
220 stripestart = startoff - (startoff % c->chunk_item->stripe_length) + c->chunk_item->stripe_length;
221 else if (startoffstripe == i)
222 stripestart = startoff;
223 else
224 stripestart = startoff - (startoff % c->chunk_item->stripe_length);
225
226 if (endoffstripe > i)
227 stripeend = endoff - (endoff % c->chunk_item->stripe_length) + c->chunk_item->stripe_length;
228 else if (endoffstripe == i)
229 stripeend = endoff + 1;
230 else
231 stripeend = endoff - (endoff % c->chunk_item->stripe_length);
232
233 if (stripestart != stripeend)
234 add_trim_entry(c->devices[i], stripestart + cis[i].offset, stripeend - stripestart);
235 }
236 }
237 } else if (type == BLOCK_FLAG_RAID10) {
238 uint64_t startoff, endoff;
239 uint16_t sub_stripes, startoffstripe, endoffstripe, i;
240
241 sub_stripes = max(1, c->chunk_item->sub_stripes);
242
243 get_raid0_offset(s->address - c->offset, c->chunk_item->stripe_length, c->chunk_item->num_stripes / sub_stripes, &startoff, &startoffstripe);
244 get_raid0_offset(s->address - c->offset + s->size - 1, c->chunk_item->stripe_length, c->chunk_item->num_stripes / sub_stripes, &endoff, &endoffstripe);
245
246 startoffstripe *= sub_stripes;
247 endoffstripe *= sub_stripes;
248
249 for (i = 0; i < c->chunk_item->num_stripes; i += sub_stripes) {
250 ULONG j;
251 uint64_t stripestart, stripeend;
252
253 if (startoffstripe > i)
254 stripestart = startoff - (startoff % c->chunk_item->stripe_length) + c->chunk_item->stripe_length;
255 else if (startoffstripe == i)
256 stripestart = startoff;
257 else
258 stripestart = startoff - (startoff % c->chunk_item->stripe_length);
259
260 if (endoffstripe > i)
261 stripeend = endoff - (endoff % c->chunk_item->stripe_length) + c->chunk_item->stripe_length;
262 else if (endoffstripe == i)
263 stripeend = endoff + 1;
264 else
265 stripeend = endoff - (endoff % c->chunk_item->stripe_length);
266
267 if (stripestart != stripeend) {
268 for (j = 0; j < sub_stripes; j++) {
269 if (c->devices[i+j] && c->devices[i+j]->devobj && !c->devices[i+j]->readonly && c->devices[i+j]->trim)
270 add_trim_entry(c->devices[i+j], stripestart + cis[i+j].offset, stripeend - stripestart);
271 }
272 }
273 }
274 }
275 // FIXME - RAID5(?), RAID6(?)
276 }
277
278 le = le->Flink;
279 }
280}
_Post_satisfies_ static stripe __inline void get_raid0_offset(_In_ uint64_t off, _In_ uint64_t stripe_length, _In_ uint16_t num_stripes, _Out_ uint64_t *stripeoff, _Out_ uint16_t *stripe)
Definition: btrfs_drv.h:997
#define BLOCK_FLAG_RAID1C4
Definition: btrfs.h:88
#define BLOCK_FLAG_RAID1C3
Definition: btrfs.h:87
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint GLint GLint j
Definition: glfuncs.h:250
if(dx< 0)
Definition: linetemp.h:194
#define BLOCK_FLAG_RAID5
Definition: shellext.h:82
#define BLOCK_FLAG_DUPLICATE
Definition: shellext.h:80
#define BLOCK_FLAG_RAID10
Definition: shellext.h:81
#define BLOCK_FLAG_RAID0
Definition: shellext.h:78
#define BLOCK_FLAG_RAID6
Definition: shellext.h:83
#define BLOCK_FLAG_METADATA
Definition: shellext.h:77
#define BLOCK_FLAG_RAID1
Definition: shellext.h:79
#define max(a, b)
Definition: svc.c:63

Referenced by clean_space_cache().

◆ create_chunk()

static NTSTATUS create_chunk ( device_extension Vcb,
chunk c,
PIRP  Irp 
)
static

Definition at line 4206 of file flushthread.c.

4206 {
4207 CHUNK_ITEM* ci;
4208 CHUNK_ITEM_STRIPE* cis;
4209 BLOCK_GROUP_ITEM* bgi;
4210 uint16_t i, factor;
4212
4214 if (!ci) {
4215 ERR("out of memory\n");
4217 }
4218
4219 RtlCopyMemory(ci, c->chunk_item, c->size);
4220
4221 Status = insert_tree_item(Vcb, Vcb->chunk_root, 0x100, TYPE_CHUNK_ITEM, c->offset, ci, c->size, NULL, Irp);
4222 if (!NT_SUCCESS(Status)) {
4223 ERR("insert_tree_item failed\n");
4224 ExFreePool(ci);
4225 return Status;
4226 }
4227
4228 if (c->chunk_item->type & BLOCK_FLAG_SYSTEM) {
4229 Status = add_to_bootstrap(Vcb, 0x100, TYPE_CHUNK_ITEM, c->offset, ci, c->size);
4230 if (!NT_SUCCESS(Status)) {
4231 ERR("add_to_bootstrap returned %08lx\n", Status);
4232 return Status;
4233 }
4234 }
4235
4236 // add BLOCK_GROUP_ITEM to tree 2
4237
4239 if (!bgi) {
4240 ERR("out of memory\n");
4242 }
4243
4244 bgi->used = c->used;
4245 bgi->chunk_tree = 0x100;
4246 bgi->flags = c->chunk_item->type;
4247
4248 Status = insert_tree_item(Vcb, Vcb->extent_root, c->offset, TYPE_BLOCK_GROUP_ITEM, c->chunk_item->size, bgi, sizeof(BLOCK_GROUP_ITEM), NULL, Irp);
4249 if (!NT_SUCCESS(Status)) {
4250 ERR("insert_tree_item failed\n");
4251 ExFreePool(bgi);
4252 return Status;
4253 }
4254
4255 if (c->chunk_item->type & BLOCK_FLAG_RAID0)
4256 factor = c->chunk_item->num_stripes;
4257 else if (c->chunk_item->type & BLOCK_FLAG_RAID10)
4258 factor = c->chunk_item->num_stripes / c->chunk_item->sub_stripes;
4259 else if (c->chunk_item->type & BLOCK_FLAG_RAID5)
4260 factor = c->chunk_item->num_stripes - 1;
4261 else if (c->chunk_item->type & BLOCK_FLAG_RAID6)
4262 factor = c->chunk_item->num_stripes - 2;
4263 else // SINGLE, DUPLICATE, RAID1, RAID1C3, RAID1C4
4264 factor = 1;
4265
4266 // add DEV_EXTENTs to tree 4
4267
4268 cis = (CHUNK_ITEM_STRIPE*)&c->chunk_item[1];
4269
4270 for (i = 0; i < c->chunk_item->num_stripes; i++) {
4271 DEV_EXTENT* de;
4272
4274 if (!de) {
4275 ERR("out of memory\n");
4277 }
4278
4279 de->chunktree = Vcb->chunk_root->id;
4280 de->objid = 0x100;
4281 de->address = c->offset;
4282 de->length = c->chunk_item->size / factor;
4283 de->chunktree_uuid = Vcb->chunk_root->treeholder.tree->header.chunk_tree_uuid;
4284
4285 Status = insert_tree_item(Vcb, Vcb->dev_root, c->devices[i]->devitem.dev_id, TYPE_DEV_EXTENT, cis[i].offset, de, sizeof(DEV_EXTENT), NULL, Irp);
4286 if (!NT_SUCCESS(Status)) {
4287 ERR("insert_tree_item returned %08lx\n", Status);
4288 ExFreePool(de);
4289 return Status;
4290 }
4291
4292 // FIXME - no point in calling this twice for the same device
4293 Status = update_dev_item(Vcb, c->devices[i], Irp);
4294 if (!NT_SUCCESS(Status)) {
4295 ERR("update_dev_item returned %08lx\n", Status);
4296 return Status;
4297 }
4298 }
4299
4300 c->created = false;
4301 c->oldused = c->used;
4302
4303 Vcb->superblock.bytes_used += c->used;
4304
4305 return STATUS_SUCCESS;
4306}
#define TYPE_DEV_EXTENT
Definition: btrfs.h:46
#define TYPE_BLOCK_GROUP_ITEM
Definition: btrfs.h:42
#define TYPE_CHUNK_ITEM
Definition: btrfs.h:48
NTSTATUS update_dev_item(device_extension *Vcb, device *device, PIRP Irp)
Definition: flushthread.c:4093
static NTSTATUS add_to_bootstrap(device_extension *Vcb, uint64_t obj_id, uint8_t obj_type, uint64_t offset, void *data, uint16_t size)
Definition: flushthread.c:4160
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint factor
Definition: glfuncs.h:178
#define for
Definition: utility.h:88
#define BLOCK_FLAG_SYSTEM
Definition: shellext.h:76
uint64_t chunk_tree
Definition: btrfs.h:425
uint64_t flags
Definition: btrfs.h:426
uint64_t used
Definition: btrfs.h:424
uint64_t address
Definition: btrfs.h:471
BTRFS_UUID chunktree_uuid
Definition: btrfs.h:473
uint64_t chunktree
Definition: btrfs.h:469
uint64_t objid
Definition: btrfs.h:470
uint64_t length
Definition: btrfs.h:472

Referenced by update_chunk_usage(), and update_chunks().

◆ delete_root_ref()

static NTSTATUS delete_root_ref ( device_extension Vcb,
uint64_t  subvolid,
uint64_t  parsubvolid,
uint64_t  parinode,
PANSI_STRING  utf8,
PIRP  Irp 
)
static

Definition at line 6246 of file flushthread.c.

6246 {
6247 KEY searchkey;
6250
6251 searchkey.obj_id = parsubvolid;
6252 searchkey.obj_type = TYPE_ROOT_REF;
6253 searchkey.offset = subvolid;
6254
6255 Status = find_item(Vcb, Vcb->root_root, &tp, &searchkey, false, Irp);
6256 if (!NT_SUCCESS(Status)) {
6257 ERR("error - find_item returned %08lx\n", Status);
6258 return Status;
6259 }
6260
6261 if (!keycmp(searchkey, tp.item->key)) {
6262 if (tp.item->size < sizeof(ROOT_REF)) {
6263 ERR("(%I64x,%x,%I64x) was %u bytes, expected at least %Iu\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(ROOT_REF));
6264 return STATUS_INTERNAL_ERROR;
6265 } else {
6266 ROOT_REF* rr;
6267 ULONG len;
6268
6269 rr = (ROOT_REF*)tp.item->data;
6270 len = tp.item->size;
6271
6272 do {
6273 uint16_t itemlen;
6274
6275 if (len < sizeof(ROOT_REF) || len < offsetof(ROOT_REF, name[0]) + rr->n) {
6276 ERR("(%I64x,%x,%I64x) was truncated\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
6277 break;
6278 }
6279
6280 itemlen = (uint16_t)offsetof(ROOT_REF, name[0]) + rr->n;
6281
6282 if (rr->dir == parinode && rr->n == utf8->Length && RtlCompareMemory(rr->name, utf8->Buffer, rr->n) == rr->n) {
6283 uint16_t newlen = tp.item->size - itemlen;
6284
6286 if (!NT_SUCCESS(Status)) {
6287 ERR("delete_tree_item returned %08lx\n", Status);
6288 return Status;
6289 }
6290
6291 if (newlen == 0) {
6292 TRACE("deleting (%I64x,%x,%I64x)\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
6293 } else {
6294 uint8_t *newrr = ExAllocatePoolWithTag(PagedPool, newlen, ALLOC_TAG), *rroff;
6295
6296 if (!newrr) {
6297 ERR("out of memory\n");
6299 }
6300
6301 TRACE("modifying (%I64x,%x,%I64x)\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
6302
6303 if ((uint8_t*)rr > tp.item->data) {
6304 RtlCopyMemory(newrr, tp.item->data, (uint8_t*)rr - tp.item->data);
6305 rroff = newrr + ((uint8_t*)rr - tp.item->data);
6306 } else {
6307 rroff = newrr;
6308 }
6309
6310 if ((uint8_t*)&rr->name[rr->n] < tp.item->data + tp.item->size)
6311 RtlCopyMemory(rroff, &rr->name[rr->n], tp.item->size - ((uint8_t*)&rr->name[rr->n] - tp.item->data));
6312
6313 Status = insert_tree_item(Vcb, Vcb->root_root, tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, newrr, newlen, NULL, Irp);
6314 if (!NT_SUCCESS(Status)) {
6315 ERR("insert_tree_item returned %08lx\n", Status);
6316 ExFreePool(newrr);
6317 return Status;
6318 }
6319 }
6320
6321 break;
6322 }
6323
6324 if (len > itemlen) {
6325 len -= itemlen;
6326 rr = (ROOT_REF*)&rr->name[rr->n];
6327 } else
6328 break;
6329 } while (len > 0);
6330 }
6331 } else {
6332 WARN("could not find ROOT_REF entry for subvol %I64x in %I64x\n", searchkey.offset, searchkey.obj_id);
6333 return STATUS_NOT_FOUND;
6334 }
6335
6336 return STATUS_SUCCESS;
6337}
#define WARN(fmt,...)
Definition: precomp.h:61
#define RtlCompareMemory(s1, s2, l)
Definition: env_spec_w32.h:465
uint64_t dir
Definition: btrfs.h:462
char name[1]
Definition: btrfs.h:465
uint16_t n
Definition: btrfs.h:464

Referenced by flush_fileref().

◆ delete_xattr()

static NTSTATUS delete_xattr ( device_extension Vcb,
LIST_ENTRY batchlist,
root subvol,
uint64_t  inode,
char name,
uint16_t  namelen,
uint32_t  crc32 
)
static

Definition at line 4367 of file flushthread.c.

4368 {
4370 uint16_t xasize;
4371 DIR_ITEM* xa;
4372
4373 TRACE("(%p, %I64x, %I64x, %.*s, %08x)\n", Vcb, subvol->id, inode, namelen, name, crc32);
4374
4375 xasize = (uint16_t)offsetof(DIR_ITEM, name[0]) + namelen;
4376
4378 if (!xa) {
4379 ERR("out of memory\n");
4381 }
4382
4383 xa->key.obj_id = 0;
4384 xa->key.obj_type = 0;
4385 xa->key.offset = 0;
4386 xa->transid = Vcb->superblock.generation;
4387 xa->m = 0;
4388 xa->n = namelen;
4389 xa->type = BTRFS_TYPE_EA;
4391
4392 Status = insert_tree_item_batch(batchlist, Vcb, subvol, inode, TYPE_XATTR_ITEM, crc32, xa, xasize, Batch_DeleteXattr);
4393 if (!NT_SUCCESS(Status)) {
4394 ERR("insert_tree_item_batch returned %08lx\n", Status);
4395 ExFreePool(xa);
4396 return Status;
4397 }
4398
4399 return STATUS_SUCCESS;
4400}
@ Batch_DeleteXattr
Definition: btrfs_drv.h:476
#define crc32(crc, buf, len)
Definition: inflate.c:1081
#define TYPE_XATTR_ITEM
Definition: btrfs.h:26
#define BTRFS_TYPE_EA
Definition: btrfs.h:270
static NTSTATUS insert_tree_item_batch(LIST_ENTRY *batchlist, device_extension *Vcb, root *r, uint64_t objid, uint8_t objtype, uint64_t offset, _In_opt_ _When_(return >=0, __drv_aliasesMem) void *data, uint16_t datalen, enum batch_operation operation)
Definition: flushthread.c:4517
GLint namelen
Definition: glext.h:7232
uint16_t m
Definition: btrfs.h:275
uint8_t type
Definition: btrfs.h:277
char name[1]
Definition: btrfs.h:278
uint64_t transid
Definition: btrfs.h:274
uint16_t n
Definition: btrfs.h:276
KEY key
Definition: btrfs.h:273
uint64_t id
Definition: btrfs_drv.h:451
Definition: fs.h:78

Referenced by flush_fcb().

◆ do_flush()

static void do_flush ( device_extension Vcb)
static

Definition at line 7896 of file flushthread.c.

7896 {
7898
7899 ExAcquireResourceExclusiveLite(&Vcb->tree_lock, true);
7900
7901 if (Vcb->need_write && !Vcb->readonly)
7902 Status = do_write(Vcb, NULL);
7903 else
7905
7906 free_trees(Vcb);
7907
7908 if (!NT_SUCCESS(Status))
7909 ERR("do_write returned %08lx\n", Status);
7910
7911 ExReleaseResourceLite(&Vcb->tree_lock);
7912}
NTSTATUS NTSTATUS bool bool void free_trees(device_extension *Vcb) __attribute__((nonnull(1)))
#define ExAcquireResourceExclusiveLite(res, wait)
Definition: env_spec_w32.h:615
NTSTATUS do_write(device_extension *Vcb, PIRP Irp)
Definition: flushthread.c:7877

Referenced by _Function_class_().

◆ do_splits()

static NTSTATUS do_splits ( device_extension Vcb,
PIRP  Irp,
LIST_ENTRY rollback 
)
static

Definition at line 3654 of file flushthread.c.

3654 {
3655 ULONG level, max_level;
3656 uint32_t min_size, min_size_fst;
3657 bool empty, done_deletions = false;
3659 tree* t;
3660
3661 TRACE("(%p)\n", Vcb);
3662
3663 max_level = 0;
3664
3665 for (level = 0; level <= 255; level++) {
3666 LIST_ENTRY *le, *nextle;
3667
3668 empty = true;
3669
3670 TRACE("doing level %lu\n", level);
3671
3672 le = Vcb->trees.Flink;
3673
3674 while (le != &Vcb->trees) {
3676
3677 nextle = le->Flink;
3678
3679 if (t->write && t->header.level == level) {
3680 empty = false;
3681
3682 if (t->header.num_items == 0) {
3683 if (t->parent) {
3684 done_deletions = true;
3685
3686 TRACE("deleting tree in root %I64x\n", t->root->id);
3687
3688 t->root->root_item.bytes_used -= Vcb->superblock.node_size;
3689
3690 if (t->has_new_address) { // delete associated EXTENT_ITEM
3691 Status = reduce_tree_extent(Vcb, t->new_address, t, t->parent->header.tree_id, t->header.level, Irp, rollback);
3692
3693 if (!NT_SUCCESS(Status)) {
3694 ERR("reduce_tree_extent returned %08lx\n", Status);
3695 return Status;
3696 }
3697
3698 t->has_new_address = false;
3699 } else if (t->has_address) {
3700 Status = reduce_tree_extent(Vcb,t->header.address, t, t->parent->header.tree_id, t->header.level, Irp, rollback);
3701
3702 if (!NT_SUCCESS(Status)) {
3703 ERR("reduce_tree_extent returned %08lx\n", Status);
3704 return Status;
3705 }
3706
3707 t->has_address = false;
3708 }
3709
3710 if (!t->paritem->ignore) {
3711 t->paritem->ignore = true;
3712 t->parent->header.num_items--;
3713 t->parent->size -= sizeof(internal_node);
3714 }
3715
3716 RemoveEntryList(&t->paritem->list_entry);
3717 ExFreePool(t->paritem);
3718 t->paritem = NULL;
3719
3720 free_tree(t);
3721 } else if (t->header.level != 0) {
3722 if (t->has_new_address) {
3723 Status = update_extent_level(Vcb, t->new_address, t, 0, Irp);
3724
3725 if (!NT_SUCCESS(Status)) {
3726 ERR("update_extent_level returned %08lx\n", Status);
3727 return Status;
3728 }
3729 }
3730
3731 t->header.level = 0;
3732 }
3733 } else if (t->size > Vcb->superblock.node_size - sizeof(tree_header)) {
3734 TRACE("splitting overlarge tree (%x > %Ix)\n", t->size, Vcb->superblock.node_size - sizeof(tree_header));
3735
3736 if (!t->updated_extents && t->has_address) {
3738 if (!NT_SUCCESS(Status)) {
3739 ERR("update_tree_extents_recursive returned %08lx\n", Status);
3740 return Status;
3741 }
3742 }
3743
3744 Status = split_tree(Vcb, t);
3745
3746 if (!NT_SUCCESS(Status)) {
3747 ERR("split_tree returned %08lx\n", Status);
3748 return Status;
3749 }
3750 }
3751 }
3752
3753 le = nextle;
3754 }
3755
3756 if (!empty) {
3757 max_level = level;
3758 } else {
3759 TRACE("nothing found for level %lu\n", level);
3760 break;
3761 }
3762 }
3763
3764 min_size = (Vcb->superblock.node_size - sizeof(tree_header)) / 2;
3765 min_size_fst = (Vcb->superblock.node_size - sizeof(tree_header)) / 4;
3766
3767 for (level = 0; level <= max_level; level++) {
3768 LIST_ENTRY* le;
3769
3770 le = Vcb->trees.Flink;
3771
3772 while (le != &Vcb->trees) {
3774
3775 if (t->write && t->header.level == level && t->header.num_items > 0 && t->parent &&
3776 ((t->size < min_size && t->root->id != BTRFS_ROOT_FREE_SPACE) || (t->size < min_size_fst && t->root->id == BTRFS_ROOT_FREE_SPACE)) &&
3777 is_tree_unique(Vcb, t, Irp)) {
3778 bool done;
3779
3780 do {
3781 Status = try_tree_amalgamate(Vcb, t, &done, &done_deletions, Irp, rollback);
3782 if (!NT_SUCCESS(Status)) {
3783 ERR("try_tree_amalgamate returned %08lx\n", Status);
3784 return Status;
3785 }
3786 } while (done && t->size < min_size);
3787 }
3788
3789 le = le->Flink;
3790 }
3791 }
3792
3793 // simplify trees if top tree only has one entry
3794
3795 if (done_deletions) {
3796 for (level = max_level; level > 0; level--) {
3797 LIST_ENTRY *le, *nextle;
3798
3799 le = Vcb->trees.Flink;
3800 while (le != &Vcb->trees) {
3801 nextle = le->Flink;
3803
3804 if (t->write && t->header.level == level) {
3805 if (!t->parent && t->header.num_items == 1) {
3806 LIST_ENTRY* le2 = t->itemlist.Flink;
3807 tree_data* td = NULL;
3808 tree* child_tree = NULL;
3809
3810 while (le2 != &t->itemlist) {
3812 if (!td->ignore)
3813 break;
3814 le2 = le2->Flink;
3815 }
3816
3817 TRACE("deleting top-level tree in root %I64x with one item\n", t->root->id);
3818
3819 if (t->has_new_address) { // delete associated EXTENT_ITEM
3820 Status = reduce_tree_extent(Vcb, t->new_address, t, t->header.tree_id, t->header.level, Irp, rollback);
3821
3822 if (!NT_SUCCESS(Status)) {
3823 ERR("reduce_tree_extent returned %08lx\n", Status);
3824 return Status;
3825 }
3826
3827 t->has_new_address = false;
3828 } else if (t->has_address) {
3829 Status = reduce_tree_extent(Vcb,t->header.address, t, t->header.tree_id, t->header.level, Irp, rollback);
3830
3831 if (!NT_SUCCESS(Status)) {
3832 ERR("reduce_tree_extent returned %08lx\n", Status);
3833 return Status;
3834 }
3835
3836 t->has_address = false;
3837 }
3838
3839 if (!td->treeholder.tree) { // load first item if not already loaded
3840 KEY searchkey = {0,0,0};
3842
3843 Status = find_item(Vcb, t->root, &tp, &searchkey, false, Irp);
3844 if (!NT_SUCCESS(Status)) {
3845 ERR("error - find_item returned %08lx\n", Status);
3846 return Status;
3847 }
3848 }
3849
3850 child_tree = td->treeholder.tree;
3851
3852 if (child_tree) {
3853 child_tree->parent = NULL;
3854 child_tree->paritem = NULL;
3855 }
3856
3857 t->root->root_item.bytes_used -= Vcb->superblock.node_size;
3858
3859 free_tree(t);
3860
3861 if (child_tree)
3862 child_tree->root->treeholder.tree = child_tree;
3863 }
3864 }
3865
3866 le = nextle;
3867 }
3868 }
3869 }
3870
3871 return STATUS_SUCCESS;
3872}
NTSTATUS NTSTATUS void free_tree(tree *t) __attribute__((nonnull(1)))
static const WCHAR empty[]
Definition: main.c:47
#define BTRFS_ROOT_FREE_SPACE
Definition: btrfs.h:62
#define RemoveEntryList(Entry)
Definition: env_spec_w32.h:986
static NTSTATUS update_tree_extents_recursive(device_extension *Vcb, tree *t, PIRP Irp, LIST_ENTRY *rollback)
Definition: flushthread.c:3636
static NTSTATUS reduce_tree_extent(device_extension *Vcb, uint64_t address, tree *t, uint64_t parent_root, uint8_t level, PIRP Irp, LIST_ENTRY *rollback)
Definition: flushthread.c:956
static NTSTATUS update_extent_level(device_extension *Vcb, uint64_t address, tree *t, uint8_t level, PIRP Irp)
Definition: flushthread.c:3536
static NTSTATUS split_tree(device_extension *Vcb, tree *t)
Definition: flushthread.c:3203
static NTSTATUS try_tree_amalgamate(device_extension *Vcb, tree *t, bool *done, bool *done_deletions, PIRP Irp, LIST_ENTRY *rollback)
Definition: flushthread.c:3306
bool is_tree_unique(device_extension *Vcb, tree *t, PIRP Irp)
Definition: flushthread.c:3243
tree_holder treeholder
Definition: btrfs_drv.h:411
bool ignore
Definition: btrfs_drv.h:407
struct _root * root
Definition: btrfs_drv.h:433
tree_data * paritem
Definition: btrfs_drv.h:432
struct _tree * tree
Definition: btrfs_drv.h:401

Referenced by do_write2().

◆ do_tree_writes()

NTSTATUS do_tree_writes ( device_extension Vcb,
LIST_ENTRY tree_writes,
bool  no_free 
)

Definition at line 1620 of file flushthread.c.

1620 {
1621 chunk* c;
1622 LIST_ENTRY* le;
1623 tree_write* tw;
1625 ULONG i, num_bits;
1626 write_data_context* wtc;
1627 ULONG bit_num = 0;
1628 bool raid56 = false;
1629
1630 // merge together runs
1631 c = NULL;
1632 le = tree_writes->Flink;
1633 while (le != tree_writes) {
1635
1636 if (!c || tw->address < c->offset || tw->address >= c->offset + c->chunk_item->size)
1638 else {
1640
1641 if (tw->address == tw2->address + tw2->length) {
1643
1644 if (!data) {
1645 ERR("out of memory\n");
1647 }
1648
1649 RtlCopyMemory(data, tw2->data, tw2->length);
1650 RtlCopyMemory(&data[tw2->length], tw->data, tw->length);
1651
1652 if (!no_free || tw2->allocated)
1653 ExFreePool(tw2->data);
1654
1655 tw2->data = data;
1656 tw2->length += tw->length;
1657 tw2->allocated = true;
1658
1659 if (!no_free || tw->allocated)
1660 ExFreePool(tw->data);
1661
1663 ExFreePool(tw);
1664
1665 le = tw2->list_entry.Flink;
1666 continue;
1667 }
1668 }
1669
1670 tw->c = c;
1671
1672 if (c->chunk_item->type & (BLOCK_FLAG_RAID5 | BLOCK_FLAG_RAID6))
1673 raid56 = true;
1674
1675 le = le->Flink;
1676 }
1677
1678 num_bits = 0;
1679
1680 le = tree_writes->Flink;
1681 while (le != tree_writes) {
1683
1684 num_bits++;
1685
1686 le = le->Flink;
1687 }
1688
1690 if (!wtc) {
1691 ERR("out of memory\n");
1693 }
1694
1695 le = tree_writes->Flink;
1696
1697 while (le != tree_writes) {
1699
1700 TRACE("address: %I64x, size: %x\n", tw->address, tw->length);
1701
1702 KeInitializeEvent(&wtc[bit_num].Event, NotificationEvent, false);
1703 InitializeListHead(&wtc[bit_num].stripes);
1704 wtc[bit_num].need_wait = false;
1705 wtc[bit_num].stripes_left = 0;
1706 wtc[bit_num].parity1 = wtc[bit_num].parity2 = wtc[bit_num].scratch = NULL;
1707 wtc[bit_num].mdl = wtc[bit_num].parity1_mdl = wtc[bit_num].parity2_mdl = NULL;
1708
1709 Status = write_data(Vcb, tw->address, tw->data, tw->length, &wtc[bit_num], NULL, NULL, false, 0, HighPagePriority);
1710 if (!NT_SUCCESS(Status)) {
1711 ERR("write_data returned %08lx\n", Status);
1712
1713 for (i = 0; i < num_bits; i++) {
1715 }
1716 ExFreePool(wtc);
1717
1718 return Status;
1719 }
1720
1721 bit_num++;
1722
1723 le = le->Flink;
1724 }
1725
1726 for (i = 0; i < num_bits; i++) {
1727 if (wtc[i].stripes.Flink != &wtc[i].stripes) {
1728 // launch writes and wait
1729 le = wtc[i].stripes.Flink;
1730 while (le != &wtc[i].stripes) {
1732
1733 if (stripe->status != WriteDataStatus_Ignore) {
1734 wtc[i].need_wait = true;
1736 }
1737
1738 le = le->Flink;
1739 }
1740 }
1741 }
1742
1743 for (i = 0; i < num_bits; i++) {
1744 if (wtc[i].need_wait)
1746 }
1747
1748 for (i = 0; i < num_bits; i++) {
1749 le = wtc[i].stripes.Flink;
1750 while (le != &wtc[i].stripes) {
1752
1753 if (stripe->status != WriteDataStatus_Ignore && !NT_SUCCESS(stripe->iosb.Status)) {
1754 Status = stripe->iosb.Status;
1756 break;
1757 }
1758
1759 le = le->Flink;
1760 }
1761
1763 }
1764
1765 ExFreePool(wtc);
1766
1767 if (raid56) {
1768 c = NULL;
1769
1770 le = tree_writes->Flink;
1771 while (le != tree_writes) {
1773
1774 if (tw->c != c) {
1775 c = tw->c;
1776
1777 ExAcquireResourceExclusiveLite(&c->partial_stripes_lock, true);
1778
1779 while (!IsListEmpty(&c->partial_stripes)) {
1781
1783
1784 if (ps->bmparr)
1785 ExFreePool(ps->bmparr);
1786
1787 ExFreePool(ps);
1788
1789 if (!NT_SUCCESS(Status)) {
1790 ERR("flush_partial_stripe returned %08lx\n", Status);
1791 ExReleaseResourceLite(&c->partial_stripes_lock);
1792 return Status;
1793 }
1794 }
1795
1796 ExReleaseResourceLite(&c->partial_stripes_lock);
1797 }
1798
1799 le = le->Flink;
1800 }
1801 }
1802
1803 return STATUS_SUCCESS;
1804}
NTSTATUS NTSTATUS NTSTATUS void free_write_data_stripes(write_data_context *wtc) __attribute__((nonnull(1)))
@ WriteDataStatus_Ignore
Definition: btrfs_drv.h:920
void log_device_error(_In_ device_extension *Vcb, _Inout_ device *dev, _In_ int error)
Definition: btrfs.c:5914
#define BTRFS_DEV_STAT_WRITE_ERRORS
Definition: btrfs.h:539
NTSTATUS flush_partial_stripe(device_extension *Vcb, chunk *c, partial_stripe *ps)
Definition: flushthread.c:5958
@ HighPagePriority
Definition: imports.h:55
struct _LIST_ENTRY * Blink
Definition: typedefs.h:122
LIST_ENTRY stripes
Definition: btrfs_drv.h:938
uint8_t * parity1
Definition: btrfs_drv.h:941
uint8_t * parity2
Definition: btrfs_drv.h:941
uint8_t * scratch
Definition: btrfs_drv.h:941
PDEVICE_OBJECT devobj
Definition: btrfs_drv.h:525
ULONG * bmparr
Definition: btrfs_drv.h:554
device * device
Definition: write.c:115
uint32_t length
Definition: btrfs_drv.h:947
uint64_t address
Definition: btrfs_drv.h:946
uint8_t * data
Definition: btrfs_drv.h:948
LIST_ENTRY list_entry
Definition: btrfs_drv.h:951
bool allocated
Definition: btrfs_drv.h:950
chunk * c
Definition: btrfs_drv.h:949

Referenced by write_metadata_items(), and write_trees().

◆ do_write()

NTSTATUS do_write ( device_extension Vcb,
PIRP  Irp 
)

Definition at line 7877 of file flushthread.c.

7877 {
7880
7882
7884
7885 if (!NT_SUCCESS(Status)) {
7886 ERR("do_write2 returned %08lx, dropping into readonly mode\n", Status);
7887 Vcb->readonly = true;
7890 } else
7892
7893 return Status;
7894}
static NTSTATUS do_write2(device_extension *Vcb, PIRP Irp, LIST_ENTRY *rollback)
Definition: flushthread.c:7477
#define FSRTL_VOLUME_FORCED_CLOSED
Definition: fsrtltypes.h:98
NTSTATUS NTAPI FsRtlNotifyVolumeEvent(IN PFILE_OBJECT FileObject, IN ULONG EventCode)
Definition: pnp.c:38

Referenced by _Dispatch_type_(), _Function_class_(), add_balance_item(), add_device(), balance_data_chunk(), balance_metadata_chunk(), dismount_volume(), do_create_snapshot(), do_flush(), finish_removing_device(), invalidate_volumes(), lock_volume(), pnp_query_remove_device(), remove_balance_item(), and try_consolidation().

◆ do_write2()

static NTSTATUS do_write2 ( device_extension Vcb,
PIRP  Irp,
LIST_ENTRY rollback 
)
static

Definition at line 7477 of file flushthread.c.

7477 {
7479 LIST_ENTRY *le, batchlist;
7480 bool cache_changed = false;
7482 bool no_cache = false;
7483#ifdef DEBUG_FLUSH_TIMES
7484 uint64_t filerefs = 0, fcbs = 0;
7485 LARGE_INTEGER freq, time1, time2;
7486#endif
7487#ifdef DEBUG_WRITE_LOOPS
7488 UINT loops = 0;
7489#endif
7490
7491 TRACE("(%p)\n", Vcb);
7492
7493 InitializeListHead(&batchlist);
7494
7495#ifdef DEBUG_FLUSH_TIMES
7496 time1 = KeQueryPerformanceCounter(&freq);
7497#endif
7498
7500 if (!NT_SUCCESS(Status)) {
7501 ERR("check_for_orphans returned %08lx\n", Status);
7502 return Status;
7503 }
7504
7505 ExAcquireResourceExclusiveLite(&Vcb->dirty_filerefs_lock, true);
7506
7507 while (!IsListEmpty(&Vcb->dirty_filerefs)) {
7508 file_ref* fr = CONTAINING_RECORD(RemoveHeadList(&Vcb->dirty_filerefs), file_ref, list_entry_dirty);
7509
7510 flush_fileref(fr, &batchlist, Irp);
7511 free_fileref(fr);
7512
7513#ifdef DEBUG_FLUSH_TIMES
7514 filerefs++;
7515#endif
7516 }
7517
7518 ExReleaseResourceLite(&Vcb->dirty_filerefs_lock);
7519
7520 Status = commit_batch_list(Vcb, &batchlist, Irp);
7521 if (!NT_SUCCESS(Status)) {
7522 ERR("commit_batch_list returned %08lx\n", Status);
7523 return Status;
7524 }
7525
7526#ifdef DEBUG_FLUSH_TIMES
7528
7529 ERR("flushed %I64u filerefs in %I64u (freq = %I64u)\n", filerefs, time2.QuadPart - time1.QuadPart, freq.QuadPart);
7530
7531 time1 = KeQueryPerformanceCounter(&freq);
7532#endif
7533
7534 // We process deleted streams first, so we don't run over our xattr
7535 // limit unless we absolutely have to.
7536 // We also process deleted normal files, to avoid any problems
7537 // caused by inode collisions.
7538
7539 ExAcquireResourceExclusiveLite(&Vcb->dirty_fcbs_lock, true);
7540
7541 le = Vcb->dirty_fcbs.Flink;
7542 while (le != &Vcb->dirty_fcbs) {
7543 fcb* fcb = CONTAINING_RECORD(le, struct _fcb, list_entry_dirty);
7544 LIST_ENTRY* le2 = le->Flink;
7545
7546 if (fcb->deleted) {
7547 ExAcquireResourceExclusiveLite(fcb->Header.Resource, true);
7548 Status = flush_fcb(fcb, false, &batchlist, Irp);
7549 ExReleaseResourceLite(fcb->Header.Resource);
7550
7551 free_fcb(fcb);
7552
7553 if (!NT_SUCCESS(Status)) {
7554 ERR("flush_fcb returned %08lx\n", Status);
7555 clear_batch_list(Vcb, &batchlist);
7556 ExReleaseResourceLite(&Vcb->dirty_fcbs_lock);
7557 return Status;
7558 }
7559
7560#ifdef DEBUG_FLUSH_TIMES
7561 fcbs++;
7562#endif
7563 }
7564
7565 le = le2;
7566 }
7567
7568 Status = commit_batch_list(Vcb, &batchlist, Irp);
7569 if (!NT_SUCCESS(Status)) {
7570 ERR("commit_batch_list returned %08lx\n", Status);
7571 ExReleaseResourceLite(&Vcb->dirty_fcbs_lock);
7572 return Status;
7573 }
7574
7575 le = Vcb->dirty_fcbs.Flink;
7576 while (le != &Vcb->dirty_fcbs) {
7577 fcb* fcb = CONTAINING_RECORD(le, struct _fcb, list_entry_dirty);
7578 LIST_ENTRY* le2 = le->Flink;
7579
7580 if (fcb->subvol != Vcb->root_root) {
7581 ExAcquireResourceExclusiveLite(fcb->Header.Resource, true);
7582 Status = flush_fcb(fcb, false, &batchlist, Irp);
7583 ExReleaseResourceLite(fcb->Header.Resource);
7584 free_fcb(fcb);
7585
7586 if (!NT_SUCCESS(Status)) {
7587 ERR("flush_fcb returned %08lx\n", Status);
7588 ExReleaseResourceLite(&Vcb->dirty_fcbs_lock);
7589 return Status;
7590 }
7591
7592#ifdef DEBUG_FLUSH_TIMES
7593 fcbs++;
7594#endif
7595 }
7596
7597 le = le2;
7598 }
7599
7600 ExReleaseResourceLite(&Vcb->dirty_fcbs_lock);
7601
7602 Status = commit_batch_list(Vcb, &batchlist, Irp);
7603 if (!NT_SUCCESS(Status)) {
7604 ERR("commit_batch_list returned %08lx\n", Status);
7605 return Status;
7606 }
7607
7608#ifdef DEBUG_FLUSH_TIMES
7610
7611 ERR("flushed %I64u fcbs in %I64u (freq = %I64u)\n", filerefs, time2.QuadPart - time1.QuadPart, freq.QuadPart);
7612#endif
7613
7614 // no need to get dirty_subvols_lock here, as we have tree_lock exclusively
7615 while (!IsListEmpty(&Vcb->dirty_subvols)) {
7616 root* r = CONTAINING_RECORD(RemoveHeadList(&Vcb->dirty_subvols), root, list_entry_dirty);
7617
7619 if (!NT_SUCCESS(Status)) {
7620 ERR("flush_subvol returned %08lx\n", Status);
7621 return Status;
7622 }
7623 }
7624
7625 if (!IsListEmpty(&Vcb->drop_roots)) {
7627
7628 if (!NT_SUCCESS(Status)) {
7629 ERR("drop_roots returned %08lx\n", Status);
7630 return Status;
7631 }
7632 }
7633
7634 Status = update_chunks(Vcb, &batchlist, Irp, rollback);
7635
7636 if (!NT_SUCCESS(Status)) {
7637 ERR("update_chunks returned %08lx\n", Status);
7638 return Status;
7639 }
7640
7641 Status = commit_batch_list(Vcb, &batchlist, Irp);
7642
7643 // If only changing superblock, e.g. changing label, we still need to rewrite
7644 // the root tree so the generations match, otherwise you won't be able to mount on Linux.
7645 if (!Vcb->root_root->treeholder.tree || !Vcb->root_root->treeholder.tree->write) {
7646 KEY searchkey;
7647
7649
7650 searchkey.obj_id = 0;
7651 searchkey.obj_type = 0;
7652 searchkey.offset = 0;
7653
7654 Status = find_item(Vcb, Vcb->root_root, &tp, &searchkey, false, Irp);
7655 if (!NT_SUCCESS(Status)) {
7656 ERR("error - find_item returned %08lx\n", Status);
7657 return Status;
7658 }
7659
7660 Vcb->root_root->treeholder.tree->write = true;
7661 }
7662
7663 // make sure we always update the extent tree
7665 if (!NT_SUCCESS(Status)) {
7666 ERR("add_root_item_to_cache returned %08lx\n", Status);
7667 return Status;
7668 }
7669
7670 if (Vcb->stats_changed) {
7671 le = Vcb->devices.Flink;
7672 while (le != &Vcb->devices) {
7674
7675 if (dev->stats_changed) {
7677 if (!NT_SUCCESS(Status)) {
7678 ERR("flush_changed_dev_stats returned %08lx\n", Status);
7679 return Status;
7680 }
7681 dev->stats_changed = false;
7682 }
7683
7684 le = le->Flink;
7685 }
7686
7687 Vcb->stats_changed = false;
7688 }
7689
7690 do {
7692 if (!NT_SUCCESS(Status)) {
7693 ERR("add_parents returned %08lx\n", Status);
7694 goto end;
7695 }
7696
7698 if (!NT_SUCCESS(Status)) {
7699 ERR("allocate_tree_extents returned %08lx\n", Status);
7700 goto end;
7701 }
7702
7704 if (!NT_SUCCESS(Status)) {
7705 ERR("do_splits returned %08lx\n", Status);
7706 goto end;
7707 }
7708
7710 if (!NT_SUCCESS(Status)) {
7711 ERR("update_chunk_usage returned %08lx\n", Status);
7712 goto end;
7713 }
7714
7715 if (!(Vcb->superblock.compat_ro_flags & BTRFS_COMPAT_RO_FLAGS_FREE_SPACE_CACHE)) {
7716 if (!no_cache) {
7717 Status = allocate_cache(Vcb, &cache_changed, Irp, rollback);
7718 if (!NT_SUCCESS(Status)) {
7719 WARN("allocate_cache returned %08lx\n", Status);
7720 no_cache = true;
7721 cache_changed = false;
7722 }
7723 }
7724 } else {
7726 if (!NT_SUCCESS(Status)) {
7727 ERR("update_chunk_caches_tree returned %08lx\n", Status);
7728 goto end;
7729 }
7730 }
7731
7732#ifdef DEBUG_WRITE_LOOPS
7733 loops++;
7734
7735 if (cache_changed)
7736 ERR("cache has changed, looping again\n");
7737#endif
7738 } while (cache_changed || !trees_consistent(Vcb));
7739
7740#ifdef DEBUG_WRITE_LOOPS
7741 ERR("%u loops\n", loops);
7742#endif
7743
7744 TRACE("trees consistent\n");
7745
7746 Status = update_root_root(Vcb, no_cache, Irp, rollback);
7747 if (!NT_SUCCESS(Status)) {
7748 ERR("update_root_root returned %08lx\n", Status);
7749 goto end;
7750 }
7751
7753 if (!NT_SUCCESS(Status)) {
7754 ERR("write_trees returned %08lx\n", Status);
7755 goto end;
7756 }
7757
7759 if (!NT_SUCCESS(Status)) {
7760 ERR("test_not_full returned %08lx\n", Status);
7761 goto end;
7762 }
7763
7764#ifdef DEBUG_PARANOID
7765 le = Vcb->trees.Flink;
7766 while (le != &Vcb->trees) {
7768 KEY searchkey;
7770
7771 searchkey.obj_id = t->header.address;
7772 searchkey.obj_type = TYPE_METADATA_ITEM;
7773 searchkey.offset = 0xffffffffffffffff;
7774
7775 Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, false, Irp);
7776 if (!NT_SUCCESS(Status)) {
7777 ERR("error - find_item returned %08lx\n", Status);
7778 goto end;
7779 }
7780
7781 if (tp.item->key.obj_id != searchkey.obj_id || tp.item->key.obj_type != searchkey.obj_type) {
7782 searchkey.obj_id = t->header.address;
7783 searchkey.obj_type = TYPE_EXTENT_ITEM;
7784 searchkey.offset = 0xffffffffffffffff;
7785
7786 Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, false, Irp);
7787 if (!NT_SUCCESS(Status)) {
7788 ERR("error - find_item returned %08lx\n", Status);
7789 goto end;
7790 }
7791
7792 if (tp.item->key.obj_id != searchkey.obj_id || tp.item->key.obj_type != searchkey.obj_type) {
7793 ERR("error - could not find entry in extent tree for tree at %I64x\n", t->header.address);
7795 goto end;
7796 }
7797 }
7798
7799 le = le->Flink;
7800 }
7801#endif
7802
7803 Vcb->superblock.cache_generation = Vcb->superblock.generation;
7804
7805 if (!Vcb->options.no_barrier)
7807
7809 if (!NT_SUCCESS(Status)) {
7810 ERR("write_superblocks returned %08lx\n", Status);
7811 goto end;
7812 }
7813
7814 vde = Vcb->vde;
7815
7816 if (vde) {
7817 pdo_device_extension* pdode = vde->pdode;
7818
7820
7821 le = pdode->children.Flink;
7822
7823 while (le != &pdode->children) {
7825
7826 vc->generation = Vcb->superblock.generation;
7827 le = le->Flink;
7828 }
7829
7831 }
7832
7834
7835 le = Vcb->chunks.Flink;
7836 while (le != &Vcb->chunks) {
7838
7839 c->changed = false;
7840 c->space_changed = false;
7841
7842 le = le->Flink;
7843 }
7844
7845 Vcb->superblock.generation++;
7846
7848
7849 le = Vcb->trees.Flink;
7850 while (le != &Vcb->trees) {
7852
7853 t->write = false;
7854
7855 le = le->Flink;
7856 }
7857
7858 Vcb->need_write = false;
7859
7860 while (!IsListEmpty(&Vcb->drop_roots)) {
7862
7863 if (IsListEmpty(&r->fcbs)) {
7864 ExDeleteResourceLite(&r->nonpaged->load_tree_lock);
7865 ExFreePool(r->nonpaged);
7866 ExFreePool(r);
7867 } else
7868 r->dropped = true;
7869 }
7870
7871end:
7872 TRACE("do_write returning %08lx\n", Status);
7873
7874 return Status;
7875}
void void void NTSTATUS commit_batch_list(_Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension *Vcb, LIST_ENTRY *batchlist, PIRP Irp) __attribute__((nonnull(1
void void void NTSTATUS void clear_batch_list(device_extension *Vcb, LIST_ENTRY *batchlist) __attribute__((nonnull(1
NTSTATUS update_chunk_caches_tree(device_extension *Vcb, PIRP Irp)
Definition: free-space.c:2113
NTSTATUS allocate_cache(device_extension *Vcb, bool *changed, PIRP Irp, LIST_ENTRY *rollback)
Definition: free-space.c:1382
void free_fileref(_Inout_ file_ref *fr)
Definition: btrfs.c:1856
#define BTRFS_COMPAT_RO_FLAGS_FREE_SPACE_CACHE
Definition: btrfs.h:111
#define TYPE_EXTENT_ITEM
Definition: btrfs.h:35
#define BTRFS_ROOT_EXTENT
Definition: btrfs.h:55
#define TYPE_METADATA_ITEM
Definition: btrfs.h:36
#define ExDeleteResourceLite(res)
Definition: env_spec_w32.h:647
static NTSTATUS flush_changed_dev_stats(device_extension *Vcb, device *dev, PIRP Irp)
Definition: flushthread.c:7000
NTSTATUS flush_fcb(fcb *fcb, bool cache, LIST_ENTRY *batchlist, PIRP Irp)
Definition: flushthread.c:4924
static NTSTATUS flush_fileref(file_ref *fileref, LIST_ENTRY *batchlist, PIRP Irp)
Definition: flushthread.c:6524
static NTSTATUS write_trees(device_extension *Vcb, PIRP Irp)
Definition: flushthread.c:1826
static NTSTATUS flush_subvol(device_extension *Vcb, root *r, PIRP Irp)
Definition: flushthread.c:7044
static bool trees_consistent(device_extension *Vcb)
Definition: flushthread.c:578
static NTSTATUS update_chunks(device_extension *Vcb, LIST_ENTRY *batchlist, PIRP Irp, LIST_ENTRY *rollback)
Definition: flushthread.c:6133
static NTSTATUS write_superblocks(device_extension *Vcb, PIRP Irp)
Definition: flushthread.c:2326
static NTSTATUS drop_roots(device_extension *Vcb, PIRP Irp, LIST_ENTRY *rollback)
Definition: flushthread.c:4072
static NTSTATUS test_not_full(device_extension *Vcb)
Definition: flushthread.c:7171
static NTSTATUS allocate_tree_extents(device_extension *Vcb, PIRP Irp, LIST_ENTRY *rollback)
Definition: flushthread.c:1465
static NTSTATUS check_for_orphans(device_extension *Vcb, PIRP Irp)
Definition: flushthread.c:7450
static NTSTATUS update_chunk_usage(device_extension *Vcb, PIRP Irp, LIST_ENTRY *rollback)
Definition: flushthread.c:2810
static NTSTATUS add_root_item_to_cache(device_extension *Vcb, uint64_t root, PIRP Irp)
Definition: flushthread.c:6472
static NTSTATUS do_splits(device_extension *Vcb, PIRP Irp, LIST_ENTRY *rollback)
Definition: flushthread.c:3654
static void flush_disk_caches(device_extension *Vcb)
Definition: flushthread.c:6911
static NTSTATUS update_root_root(device_extension *Vcb, bool no_cache, PIRP Irp, LIST_ENTRY *rollback)
Definition: flushthread.c:1557
static void clean_space_cache(device_extension *Vcb)
Definition: flushthread.c:403
static NTSTATUS add_parents(device_extension *Vcb, PIRP Irp)
Definition: flushthread.c:615
LARGE_INTEGER NTAPI KeQueryPerformanceCounter(IN PLARGE_INTEGER PerformanceFreq)
Definition: timer.c:138
unsigned int UINT
Definition: ndis.h:50
FSRTL_ADVANCED_FCB_HEADER Header
Definition: btrfs_drv.h:283
struct pdo_device_extension * pdode
Definition: btrfs_drv.h:878
ERESOURCE child_lock
Definition: btrfs_drv.h:896
LIST_ENTRY children
Definition: btrfs_drv.h:897
uint64_t generation
Definition: btrfs_drv.h:856

Referenced by do_write().

◆ drop_chunk()

static NTSTATUS drop_chunk ( device_extension Vcb,
chunk c,
LIST_ENTRY batchlist,
PIRP  Irp,
LIST_ENTRY rollback 
)
static

Definition at line 5531 of file flushthread.c.

5531 {
5533 KEY searchkey;
5535 uint64_t i, factor;
5536 CHUNK_ITEM_STRIPE* cis = (CHUNK_ITEM_STRIPE*)&c->chunk_item[1];;
5537
5538 TRACE("dropping chunk %I64x\n", c->offset);
5539
5540 if (c->chunk_item->type & BLOCK_FLAG_RAID0)
5541 factor = c->chunk_item->num_stripes;
5542 else if (c->chunk_item->type & BLOCK_FLAG_RAID10)
5543 factor = c->chunk_item->num_stripes / c->chunk_item->sub_stripes;
5544 else if (c->chunk_item->type & BLOCK_FLAG_RAID5)
5545 factor = c->chunk_item->num_stripes - 1;
5546 else if (c->chunk_item->type & BLOCK_FLAG_RAID6)
5547 factor = c->chunk_item->num_stripes - 2;
5548 else // SINGLE, DUPLICATE, RAID1, RAID1C3, RAID1C4
5549 factor = 1;
5550
5551 // do TRIM
5552 if (Vcb->trim && !Vcb->options.no_trim) {
5553 uint64_t len = c->chunk_item->size / factor;
5554
5555 for (i = 0; i < c->chunk_item->num_stripes; i++) {
5556 if (c->devices[i] && c->devices[i]->devobj && !c->devices[i]->readonly && c->devices[i]->trim)
5557 add_trim_entry_avoid_sb(Vcb, c->devices[i], cis[i].offset, len);
5558 }
5559 }
5560
5561 if (!c->cache) {
5563
5565 WARN("load_stored_free_space_cache returned %08lx\n", Status);
5566 }
5567
5568 // remove free space cache
5569 if (c->cache) {
5570 c->cache->deleted = true;
5571
5572 Status = excise_extents(Vcb, c->cache, 0, c->cache->inode_item.st_size, Irp, rollback);
5573 if (!NT_SUCCESS(Status)) {
5574 ERR("excise_extents returned %08lx\n", Status);
5575 return Status;
5576 }
5577
5578 Status = flush_fcb(c->cache, true, batchlist, Irp);
5579
5580 free_fcb(c->cache);
5581
5582 if (c->cache->refcount == 0)
5583 reap_fcb(c->cache);
5584
5585 if (!NT_SUCCESS(Status)) {
5586 ERR("flush_fcb returned %08lx\n", Status);
5587 return Status;
5588 }
5589
5590 searchkey.obj_id = FREE_SPACE_CACHE_ID;
5591 searchkey.obj_type = 0;
5592 searchkey.offset = c->offset;
5593
5594 Status = find_item(Vcb, Vcb->root_root, &tp, &searchkey, false, Irp);
5595 if (!NT_SUCCESS(Status)) {
5596 ERR("error - find_item returned %08lx\n", Status);
5597 return Status;
5598 }
5599
5600 if (!keycmp(tp.item->key, searchkey)) {
5602 if (!NT_SUCCESS(Status)) {
5603 ERR("delete_tree_item returned %08lx\n", Status);
5604 return Status;
5605 }
5606 }
5607 }
5608
5609 if (Vcb->space_root) {
5610 Status = insert_tree_item_batch(batchlist, Vcb, Vcb->space_root, c->offset, TYPE_FREE_SPACE_INFO, c->chunk_item->size,
5612 if (!NT_SUCCESS(Status)) {
5613 ERR("insert_tree_item_batch returned %08lx\n", Status);
5614 return Status;
5615 }
5616 }
5617
5618 for (i = 0; i < c->chunk_item->num_stripes; i++) {
5619 if (!c->created) {
5620 // remove DEV_EXTENTs from tree 4
5621 searchkey.obj_id = cis[i].dev_id;
5622 searchkey.obj_type = TYPE_DEV_EXTENT;
5623 searchkey.offset = cis[i].offset;
5624
5625 Status = find_item(Vcb, Vcb->dev_root, &tp, &searchkey, false, Irp);
5626 if (!NT_SUCCESS(Status)) {
5627 ERR("error - find_item returned %08lx\n", Status);
5628 return Status;
5629 }
5630
5631 if (!keycmp(tp.item->key, searchkey)) {
5633 if (!NT_SUCCESS(Status)) {
5634 ERR("delete_tree_item returned %08lx\n", Status);
5635 return Status;
5636 }
5637
5638 if (tp.item->size >= sizeof(DEV_EXTENT)) {
5639 DEV_EXTENT* de = (DEV_EXTENT*)tp.item->data;
5640
5641 c->devices[i]->devitem.bytes_used -= de->length;
5642
5643 if (Vcb->balance.thread && Vcb->balance.shrinking && Vcb->balance.opts[0].devid == c->devices[i]->devitem.dev_id) {
5644 if (cis[i].offset < Vcb->balance.opts[0].drange_start && cis[i].offset + de->length > Vcb->balance.opts[0].drange_start)
5645 space_list_add2(&c->devices[i]->space, NULL, cis[i].offset, Vcb->balance.opts[0].drange_start - cis[i].offset, NULL, rollback);
5646 } else
5647 space_list_add2(&c->devices[i]->space, NULL, cis[i].offset, de->length, NULL, rollback);
5648 }
5649 } else
5650 WARN("could not find (%I64x,%x,%I64x) in dev tree\n", searchkey.obj_id, searchkey.obj_type, searchkey.offset);
5651 } else {
5652 uint64_t len = c->chunk_item->size / factor;
5653
5654 c->devices[i]->devitem.bytes_used -= len;
5655
5656 if (Vcb->balance.thread && Vcb->balance.shrinking && Vcb->balance.opts[0].devid == c->devices[i]->devitem.dev_id) {
5657 if (cis[i].offset < Vcb->balance.opts[0].drange_start && cis[i].offset + len > Vcb->balance.opts[0].drange_start)
5658 space_list_add2(&c->devices[i]->space, NULL, cis[i].offset, Vcb->balance.opts[0].drange_start - cis[i].offset, NULL, rollback);
5659 } else
5660 space_list_add2(&c->devices[i]->space, NULL, cis[i].offset, len, NULL, rollback);
5661 }
5662 }
5663
5664 // modify DEV_ITEMs in chunk tree
5665 for (i = 0; i < c->chunk_item->num_stripes; i++) {
5666 if (c->devices[i]) {
5667 uint64_t j;
5668 DEV_ITEM* di;
5669
5670 searchkey.obj_id = 1;
5671 searchkey.obj_type = TYPE_DEV_ITEM;
5672 searchkey.offset = c->devices[i]->devitem.dev_id;
5673
5674 Status = find_item(Vcb, Vcb->chunk_root, &tp, &searchkey, false, Irp);
5675 if (!NT_SUCCESS(Status)) {
5676 ERR("error - find_item returned %08lx\n", Status);
5677 return Status;
5678 }
5679
5680 if (!keycmp(tp.item->key, searchkey)) {
5682 if (!NT_SUCCESS(Status)) {
5683 ERR("delete_tree_item returned %08lx\n", Status);
5684 return Status;
5685 }
5686
5688 if (!di) {
5689 ERR("out of memory\n");
5691 }
5692
5693 RtlCopyMemory(di, &c->devices[i]->devitem, sizeof(DEV_ITEM));
5694
5695 Status = insert_tree_item(Vcb, Vcb->chunk_root, 1, TYPE_DEV_ITEM, c->devices[i]->devitem.dev_id, di, sizeof(DEV_ITEM), NULL, Irp);
5696 if (!NT_SUCCESS(Status)) {
5697 ERR("insert_tree_item returned %08lx\n", Status);
5698 return Status;
5699 }
5700 }
5701
5702 for (j = i + 1; j < c->chunk_item->num_stripes; j++) {
5703 if (c->devices[j] == c->devices[i])
5704 c->devices[j] = NULL;
5705 }
5706 }
5707 }
5708
5709 if (!c->created) {
5710 // remove CHUNK_ITEM from chunk tree
5711 searchkey.obj_id = 0x100;
5712 searchkey.obj_type = TYPE_CHUNK_ITEM;
5713 searchkey.offset = c->offset;
5714
5715 Status = find_item(Vcb, Vcb->chunk_root, &tp, &searchkey, false, Irp);
5716 if (!NT_SUCCESS(Status)) {
5717 ERR("error - find_item returned %08lx\n", Status);
5718 return Status;
5719 }
5720
5721 if (!keycmp(tp.item->key, searchkey)) {
5723
5724 if (!NT_SUCCESS(Status)) {
5725 ERR("delete_tree_item returned %08lx\n", Status);
5726 return Status;
5727 }
5728 } else
5729 WARN("could not find CHUNK_ITEM for chunk %I64x\n", c->offset);
5730
5731 // remove BLOCK_GROUP_ITEM from extent tree
5732 searchkey.obj_id = c->offset;
5733 searchkey.obj_type = TYPE_BLOCK_GROUP_ITEM;
5734 searchkey.offset = 0xffffffffffffffff;
5735
5736 Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, false, Irp);
5737 if (!NT_SUCCESS(Status)) {
5738 ERR("error - find_item returned %08lx\n", Status);
5739 return Status;
5740 }
5741
5742 if (tp.item->key.obj_id == searchkey.obj_id && tp.item->key.obj_type == searchkey.obj_type) {
5744
5745 if (!NT_SUCCESS(Status)) {
5746 ERR("delete_tree_item returned %08lx\n", Status);
5747 return Status;
5748 }
5749 } else
5750 WARN("could not find BLOCK_GROUP_ITEM for chunk %I64x\n", c->offset);
5751 }
5752
5753 if (c->chunk_item->type & BLOCK_FLAG_SYSTEM)
5754 remove_from_bootstrap(Vcb, 0x100, TYPE_CHUNK_ITEM, c->offset);
5755
5756 RemoveEntryList(&c->list_entry);
5757
5758 // clear raid56 incompat flag if dropping last RAID5/6 chunk
5759
5760 if (c->chunk_item->type & BLOCK_FLAG_RAID5 || c->chunk_item->type & BLOCK_FLAG_RAID6) {
5761 LIST_ENTRY* le;
5762 bool clear_flag = true;
5763
5764 le = Vcb->chunks.Flink;
5765 while (le != &Vcb->chunks) {
5767
5769 clear_flag = false;
5770 break;
5771 }
5772
5773 le = le->Flink;
5774 }
5775
5776 if (clear_flag)
5777 Vcb->superblock.incompat_flags &= ~BTRFS_INCOMPAT_FLAGS_RAID56;
5778 }
5779
5780 // clear raid1c34 incompat flag if dropping last RAID5/6 chunk
5781
5782 if (c->chunk_item->type & BLOCK_FLAG_RAID1C3 || c->chunk_item->type & BLOCK_FLAG_RAID1C4) {
5783 LIST_ENTRY* le;
5784 bool clear_flag = true;
5785
5786 le = Vcb->chunks.Flink;
5787 while (le != &Vcb->chunks) {
5789
5791 clear_flag = false;
5792 break;
5793 }
5794
5795 le = le->Flink;
5796 }
5797
5798 if (clear_flag)
5799 Vcb->superblock.incompat_flags &= ~BTRFS_INCOMPAT_FLAGS_RAID1C34;
5800 }
5801
5802 Vcb->superblock.bytes_used -= c->oldused;
5803
5804 ExFreePool(c->chunk_item);
5805 ExFreePool(c->devices);
5806
5807 while (!IsListEmpty(&c->space)) {
5808 space* s = CONTAINING_RECORD(c->space.Flink, space, list_entry);
5809
5810 RemoveEntryList(&s->list_entry);
5811 ExFreePool(s);
5812 }
5813
5814 while (!IsListEmpty(&c->deleting)) {
5815 space* s = CONTAINING_RECORD(c->deleting.Flink, space, list_entry);
5816
5817 RemoveEntryList(&s->list_entry);
5818 ExFreePool(s);
5819 }
5820
5822
5823 ExDeleteResourceLite(&c->partial_stripes_lock);
5824 ExDeleteResourceLite(&c->range_locks_lock);
5825 ExDeleteResourceLite(&c->lock);
5826 ExDeleteResourceLite(&c->changed_extents_lock);
5827
5828 ExFreePool(c);
5829
5830 return STATUS_SUCCESS;
5831}
NTSTATUS load_stored_free_space_cache(device_extension *Vcb, chunk *c, bool load_only, PIRP Irp)
Definition: free-space.c:466
@ Batch_DeleteFreeSpace
Definition: btrfs_drv.h:478
void space_list_add2(LIST_ENTRY *list, LIST_ENTRY *list_size, uint64_t address, uint64_t length, chunk *c, LIST_ENTRY *rollback)
Definition: free-space.c:1446
void reap_fcb(fcb *fcb)
Definition: btrfs.c:1743
#define FREE_SPACE_CACHE_ID
Definition: btrfs.h:90
#define TYPE_DEV_ITEM
Definition: btrfs.h:47
#define TYPE_FREE_SPACE_INFO
Definition: btrfs.h:43
static void remove_from_bootstrap(device_extension *Vcb, uint64_t obj_id, uint8_t obj_type, uint64_t offset)
Definition: flushthread.c:4308
void add_trim_entry_avoid_sb(device_extension *Vcb, device *dev, uint64_t address, uint64_t size)
Definition: flushthread.c:5507
uint64_t offset
Definition: btrfs.h:353
uint64_t dev_id
Definition: btrfs.h:352
uint64_t type
Definition: btrfs.h:343
CHUNK_ITEM * chunk_item
Definition: btrfs_drv.h:562

Referenced by update_chunks().

◆ drop_root()

static NTSTATUS drop_root ( device_extension Vcb,
root r,
PIRP  Irp,
LIST_ENTRY rollback 
)
static

Definition at line 3945 of file flushthread.c.

3945 {
3947 KEY searchkey;
3949
3950 Status = remove_root_extents(Vcb, r, &r->treeholder, r->root_item.root_level, NULL, Irp, rollback);
3951 if (!NT_SUCCESS(Status)) {
3952 ERR("remove_root_extents returned %08lx\n", Status);
3953 return Status;
3954 }
3955
3956 // remove entries in uuid root (tree 9)
3957 if (Vcb->uuid_root) {
3958 RtlCopyMemory(&searchkey.obj_id, &r->root_item.uuid.uuid[0], sizeof(uint64_t));
3959 searchkey.obj_type = TYPE_SUBVOL_UUID;
3960 RtlCopyMemory(&searchkey.offset, &r->root_item.uuid.uuid[sizeof(uint64_t)], sizeof(uint64_t));
3961
3962 if (searchkey.obj_id != 0 || searchkey.offset != 0) {
3963 Status = find_item(Vcb, Vcb->uuid_root, &tp, &searchkey, false, Irp);
3964 if (!NT_SUCCESS(Status)) {
3965 WARN("find_item returned %08lx\n", Status);
3966 } else {
3967 if (!keycmp(tp.item->key, searchkey)) {
3969 if (!NT_SUCCESS(Status)) {
3970 ERR("delete_tree_item returned %08lx\n", Status);
3971 return Status;
3972 }
3973 } else
3974 WARN("could not find (%I64x,%x,%I64x) in uuid tree\n", searchkey.obj_id, searchkey.obj_type, searchkey.offset);
3975 }
3976 }
3977
3978 if (r->root_item.rtransid > 0) {
3979 RtlCopyMemory(&searchkey.obj_id, &r->root_item.received_uuid.uuid[0], sizeof(uint64_t));
3980 searchkey.obj_type = TYPE_SUBVOL_REC_UUID;
3981 RtlCopyMemory(&searchkey.offset, &r->root_item.received_uuid.uuid[sizeof(uint64_t)], sizeof(uint64_t));
3982
3983 Status = find_item(Vcb, Vcb->uuid_root, &tp, &searchkey, false, Irp);
3984 if (!NT_SUCCESS(Status))
3985 WARN("find_item returned %08lx\n", Status);
3986 else {
3987 if (!keycmp(tp.item->key, searchkey)) {
3988 if (tp.item->size == sizeof(uint64_t)) {
3989 uint64_t* id = (uint64_t*)tp.item->data;
3990
3991 if (*id == r->id) {
3993 if (!NT_SUCCESS(Status)) {
3994 ERR("delete_tree_item returned %08lx\n", Status);
3995 return Status;
3996 }
3997 }
3998 } else if (tp.item->size > sizeof(uint64_t)) {
3999 ULONG i;
4001
4002 for (i = 0; i < tp.item->size / sizeof(uint64_t); i++) {
4003 if (ids[i] == r->id) {
4004 uint64_t* ne;
4005
4007 if (!ne) {
4008 ERR("out of memory\n");
4010 }
4011
4012 if (i > 0)
4013 RtlCopyMemory(ne, ids, sizeof(uint64_t) * i);
4014
4015 if ((i + 1) * sizeof(uint64_t) < tp.item->size)
4016 RtlCopyMemory(&ne[i], &ids[i + 1], tp.item->size - ((i + 1) * sizeof(uint64_t)));
4017
4019 if (!NT_SUCCESS(Status)) {
4020 ERR("delete_tree_item returned %08lx\n", Status);
4021 ExFreePool(ne);
4022 return Status;
4023 }
4024
4026 ne, tp.item->size - sizeof(uint64_t), NULL, Irp);
4027 if (!NT_SUCCESS(Status)) {
4028 ERR("insert_tree_item returned %08lx\n", Status);
4029 ExFreePool(ne);
4030 return Status;
4031 }
4032
4033 break;
4034 }
4035 }
4036 }
4037 } else
4038 WARN("could not find (%I64x,%x,%I64x) in uuid tree\n", searchkey.obj_id, searchkey.obj_type, searchkey.offset);
4039 }
4040 }
4041 }
4042
4043 // delete ROOT_ITEM
4044
4045 searchkey.obj_id = r->id;
4046 searchkey.obj_type = TYPE_ROOT_ITEM;
4047 searchkey.offset = 0xffffffffffffffff;
4048
4049 Status = find_item(Vcb, Vcb->root_root, &tp, &searchkey, false, Irp);
4050 if (!NT_SUCCESS(Status)) {
4051 ERR("find_item returned %08lx\n", Status);
4052 return Status;
4053 }
4054
4055 if (tp.item->key.obj_id == searchkey.obj_id && tp.item->key.obj_type == searchkey.obj_type) {
4057
4058 if (!NT_SUCCESS(Status)) {
4059 ERR("delete_tree_item returned %08lx\n", Status);
4060 return Status;
4061 }
4062 } else
4063 WARN("could not find (%I64x,%x,%I64x) in root_root\n", searchkey.obj_id, searchkey.obj_type, searchkey.offset);
4064
4065 // delete items in tree cache
4066
4068
4069 return STATUS_SUCCESS;
4070}
void void free_trees_root(device_extension *Vcb, root *r) __attribute__((nonnull(1
#define TYPE_SUBVOL_REC_UUID
Definition: btrfs.h:52
#define TYPE_SUBVOL_UUID
Definition: btrfs.h:51
static NTSTATUS remove_root_extents(device_extension *Vcb, root *r, tree_holder *th, uint8_t level, tree *parent, PIRP Irp, LIST_ENTRY *rollback)
Definition: flushthread.c:3874
GLuint * ids
Definition: glext.h:5907

Referenced by drop_roots().

◆ drop_roots()

static NTSTATUS drop_roots ( device_extension Vcb,
PIRP  Irp,
LIST_ENTRY rollback 
)
static

Definition at line 4072 of file flushthread.c.

4072 {
4073 LIST_ENTRY *le = Vcb->drop_roots.Flink, *le2;
4075
4076 while (le != &Vcb->drop_roots) {
4078
4079 le2 = le->Flink;
4080
4082 if (!NT_SUCCESS(Status)) {
4083 ERR("drop_root(%I64x) returned %08lx\n", r->id, Status);
4084 return Status;
4085 }
4086
4087 le = le2;
4088 }
4089
4090 return STATUS_SUCCESS;
4091}
static NTSTATUS drop_root(device_extension *Vcb, root *r, PIRP Irp, LIST_ENTRY *rollback)
Definition: flushthread.c:3945

Referenced by do_write2().

◆ find_metadata_address_in_chunk()

bool find_metadata_address_in_chunk ( device_extension Vcb,
chunk c,
uint64_t address 
)

Definition at line 744 of file flushthread.c.

744 {
745 LIST_ENTRY* le;
746 space* s;
747
748 TRACE("(%p, %I64x, %p)\n", Vcb, c->offset, address);
749
750 if (Vcb->superblock.node_size > c->chunk_item->size - c->used)
751 return false;
752
753 if (!c->cache_loaded) {
755
756 if (!NT_SUCCESS(Status)) {
757 ERR("load_cache_chunk returned %08lx\n", Status);
758 return false;
759 }
760 }
761
762 if (IsListEmpty(&c->space_size))
763 return false;
764
765 if (!c->last_alloc_set) {
766 s = CONTAINING_RECORD(c->space.Blink, space, list_entry);
767
768 c->last_alloc = s->address;
769 c->last_alloc_set = true;
770
771 if (s->size >= Vcb->superblock.node_size) {
772 *address = s->address;
773 c->last_alloc += Vcb->superblock.node_size;
774 return true;
775 }
776 }
777
778 le = c->space.Flink;
779 while (le != &c->space) {
781
782 if (s->address <= c->last_alloc && s->address + s->size >= c->last_alloc + Vcb->superblock.node_size) {
783 *address = c->last_alloc;
784 c->last_alloc += Vcb->superblock.node_size;
785 return true;
786 }
787
788 le = le->Flink;
789 }
790
791 le = c->space_size.Flink;
792 while (le != &c->space_size) {
793 s = CONTAINING_RECORD(le, space, list_entry_size);
794
795 if (s->size == Vcb->superblock.node_size) {
796 *address = s->address;
797 c->last_alloc = s->address + Vcb->superblock.node_size;
798 return true;
799 } else if (s->size < Vcb->superblock.node_size) {
800 if (le == c->space_size.Flink)
801 return false;
802
803 s = CONTAINING_RECORD(le->Blink, space, list_entry_size);
804
805 *address = s->address;
806 c->last_alloc = s->address + Vcb->superblock.node_size;
807
808 return true;
809 }
810
811 le = le->Flink;
812 }
813
814 s = CONTAINING_RECORD(c->space_size.Blink, space, list_entry_size);
815
816 if (s->size > Vcb->superblock.node_size) {
817 *address = s->address;
818 c->last_alloc = s->address + Vcb->superblock.node_size;
819 return true;
820 }
821
822 return false;
823}

Referenced by insert_tree_extent(), and write_metadata_items().

◆ flush_changed_dev_stats()

static NTSTATUS flush_changed_dev_stats ( device_extension Vcb,
device dev,
PIRP  Irp 
)
static

Definition at line 7000 of file flushthread.c.

7000 {
7002 KEY searchkey;
7004 uint16_t statslen;
7005 uint64_t* stats;
7006
7007 searchkey.obj_id = 0;
7008 searchkey.obj_type = TYPE_DEV_STATS;
7009 searchkey.offset = dev->devitem.dev_id;
7010
7011 Status = find_item(Vcb, Vcb->dev_root, &tp, &searchkey, false, Irp);
7012 if (!NT_SUCCESS(Status)) {
7013 ERR("find_item returned %08lx\n", Status);
7014 return Status;
7015 }
7016
7017 if (!keycmp(tp.item->key, searchkey)) {
7019 if (!NT_SUCCESS(Status)) {
7020 ERR("delete_tree_item returned %08lx\n", Status);
7021 return Status;
7022 }
7023 }
7024
7025 statslen = sizeof(uint64_t) * 5;
7026 stats = ExAllocatePoolWithTag(PagedPool, statslen, ALLOC_TAG);
7027 if (!stats) {
7028 ERR("out of memory\n");
7030 }
7031
7032 RtlCopyMemory(stats, dev->stats, statslen);
7033
7034 Status = insert_tree_item(Vcb, Vcb->dev_root, 0, TYPE_DEV_STATS, dev->devitem.dev_id, stats, statslen, NULL, Irp);
7035 if (!NT_SUCCESS(Status)) {
7036 ERR("insert_tree_item returned %08lx\n", Status);
7037 ExFreePool(stats);
7038 return Status;
7039 }
7040
7041 return STATUS_SUCCESS;
7042}
#define TYPE_DEV_STATS
Definition: btrfs.h:50
uint64_t dev_id

Referenced by do_write2().

◆ flush_changed_extent()

static NTSTATUS flush_changed_extent ( device_extension Vcb,
chunk c,
changed_extent ce,
PIRP  Irp,
LIST_ENTRY rollback 
)
static

Definition at line 2433 of file flushthread.c.

2433 {
2434 LIST_ENTRY *le, *le2;
2436 uint64_t old_size;
2437
2438 if (ce->count == 0 && ce->old_count == 0) {
2439 while (!IsListEmpty(&ce->refs)) {
2441 ExFreePool(cer);
2442 }
2443
2444 while (!IsListEmpty(&ce->old_refs)) {
2446 ExFreePool(cer);
2447 }
2448
2449 goto end;
2450 }
2451
2452 le = ce->refs.Flink;
2453 while (le != &ce->refs) {
2455 uint32_t old_count = 0;
2456
2457 if (cer->type == TYPE_EXTENT_DATA_REF) {
2458 le2 = ce->old_refs.Flink;
2459 while (le2 != &ce->old_refs) {
2461
2462 if (cer2->type == TYPE_EXTENT_DATA_REF && cer2->edr.root == cer->edr.root && cer2->edr.objid == cer->edr.objid && cer2->edr.offset == cer->edr.offset) {
2463 old_count = cer2->edr.count;
2464 break;
2465 }
2466
2467 le2 = le2->Flink;
2468 }
2469
2470 old_size = ce->old_count > 0 ? ce->old_size : ce->size;
2471
2472 if (cer->edr.count > old_count) {
2473 Status = increase_extent_refcount_data(Vcb, ce->address, old_size, cer->edr.root, cer->edr.objid, cer->edr.offset, cer->edr.count - old_count, Irp);
2474
2475 if (!NT_SUCCESS(Status)) {
2476 ERR("increase_extent_refcount_data returned %08lx\n", Status);
2477 return Status;
2478 }
2479 }
2480 } else if (cer->type == TYPE_SHARED_DATA_REF) {
2481 le2 = ce->old_refs.Flink;
2482 while (le2 != &ce->old_refs) {
2484
2485 if (cer2->type == TYPE_SHARED_DATA_REF && cer2->sdr.offset == cer->sdr.offset) {
2487 ExFreePool(cer2);
2488 break;