ReactOS 0.4.15-dev-8096-ga0eec98
balance.c File Reference
#include "btrfs_drv.h"
#include "btrfsioctl.h"
#include "crc32c.h"
#include <ntddstor.h>
Include dependency graph for balance.c:

Go to the source code of this file.

Classes

struct  metadata_reloc
 
struct  metadata_reloc_ref
 
struct  data_reloc
 
struct  data_reloc_ref
 

Macros

#define BALANCE_UNIT   0x100000
 

Functions

static NTSTATUS add_metadata_reloc (_Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension *Vcb, LIST_ENTRY *items, traverse_ptr *tp, bool skinny, metadata_reloc **mr2, chunk *c, LIST_ENTRY *rollback)
 
static NTSTATUS add_metadata_reloc_parent (_Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension *Vcb, LIST_ENTRY *items, uint64_t address, metadata_reloc **mr2, LIST_ENTRY *rollback)
 
static void sort_metadata_reloc_refs (metadata_reloc *mr)
 
static NTSTATUS add_metadata_reloc_extent_item (_Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension *Vcb, metadata_reloc *mr)
 
static NTSTATUS write_metadata_items (_Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension *Vcb, LIST_ENTRY *items, LIST_ENTRY *data_items, chunk *c, LIST_ENTRY *rollback)
 
static NTSTATUS balance_metadata_chunk (device_extension *Vcb, chunk *c, bool *changed)
 
static NTSTATUS data_reloc_add_tree_edr (_Requires_lock_held_(_Curr_->tree_lock) device_extension *Vcb, LIST_ENTRY *metadata_items, data_reloc *dr, EXTENT_DATA_REF *edr, LIST_ENTRY *rollback)
 
static NTSTATUS add_data_reloc (_Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension *Vcb, LIST_ENTRY *items, LIST_ENTRY *metadata_items, traverse_ptr *tp, chunk *c, LIST_ENTRY *rollback)
 
static void sort_data_reloc_refs (data_reloc *dr)
 
static NTSTATUS add_data_reloc_extent_item (_Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension *Vcb, data_reloc *dr)
 
static NTSTATUS balance_data_chunk (device_extension *Vcb, chunk *c, bool *changed)
 
static __inline uint64_t get_chunk_dup_type (chunk *c)
 
static bool should_balance_chunk (device_extension *Vcb, uint8_t sort, chunk *c)
 
static void copy_balance_args (btrfs_balance_opts *opts, BALANCE_ARGS *args)
 
static NTSTATUS add_balance_item (device_extension *Vcb)
 
static NTSTATUS remove_balance_item (device_extension *Vcb)
 
static void load_balance_args (btrfs_balance_opts *opts, BALANCE_ARGS *args)
 
static NTSTATUS remove_superblocks (device *dev)
 
static NTSTATUS finish_removing_device (_Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension *Vcb, device *dev)
 
static void trim_unalloc_space (_Requires_lock_held_(_Curr_->tree_lock) device_extension *Vcb, device *dev)
 
static NTSTATUS try_consolidation (device_extension *Vcb, uint64_t flags, chunk **newchunk)
 
static NTSTATUS regenerate_space_list (device_extension *Vcb, device *dev)
 
 _Function_class_ (KSTART_ROUTINE)
 
NTSTATUS start_balance (device_extension *Vcb, void *data, ULONG length, KPROCESSOR_MODE processor_mode)
 
NTSTATUS look_for_balance_item (_Requires_lock_held_(_Curr_->tree_lock) device_extension *Vcb)
 
NTSTATUS query_balance (device_extension *Vcb, void *data, ULONG length)
 
NTSTATUS pause_balance (device_extension *Vcb, KPROCESSOR_MODE processor_mode)
 
NTSTATUS resume_balance (device_extension *Vcb, KPROCESSOR_MODE processor_mode)
 
NTSTATUS stop_balance (device_extension *Vcb, KPROCESSOR_MODE processor_mode)
 
NTSTATUS remove_device (device_extension *Vcb, void *data, ULONG length, KPROCESSOR_MODE processor_mode)
 

Macro Definition Documentation

◆ BALANCE_UNIT

#define BALANCE_UNIT   0x100000

Definition at line 71 of file balance.c.

Function Documentation

◆ _Function_class_()

_Function_class_ ( KSTART_ROUTINE  )

Definition at line 3047 of file balance.c.

3048 {
3050 LIST_ENTRY chunks;
3051 LIST_ENTRY* le;
3052 uint64_t num_chunks[3], okay_metadata_chunks = 0, okay_data_chunks = 0, okay_system_chunks = 0;
3053 uint64_t old_data_flags = 0, old_metadata_flags = 0, old_system_flags = 0;
3055
3056 Vcb->balance.balance_num++;
3057
3058 Vcb->balance.stopping = false;
3059 KeInitializeEvent(&Vcb->balance.finished, NotificationEvent, false);
3060
3061 if (Vcb->balance.opts[BALANCE_OPTS_DATA].flags & BTRFS_BALANCE_OPTS_ENABLED && Vcb->balance.opts[BALANCE_OPTS_DATA].flags & BTRFS_BALANCE_OPTS_CONVERT) {
3062 old_data_flags = Vcb->data_flags;
3063 Vcb->data_flags = BLOCK_FLAG_DATA | (Vcb->balance.opts[BALANCE_OPTS_DATA].convert == BLOCK_FLAG_SINGLE ? 0 : Vcb->balance.opts[BALANCE_OPTS_DATA].convert);
3064
3066 }
3067
3068 if (Vcb->balance.opts[BALANCE_OPTS_METADATA].flags & BTRFS_BALANCE_OPTS_ENABLED && Vcb->balance.opts[BALANCE_OPTS_METADATA].flags & BTRFS_BALANCE_OPTS_CONVERT) {
3069 old_metadata_flags = Vcb->metadata_flags;
3070 Vcb->metadata_flags = BLOCK_FLAG_METADATA | (Vcb->balance.opts[BALANCE_OPTS_METADATA].convert == BLOCK_FLAG_SINGLE ? 0 : Vcb->balance.opts[BALANCE_OPTS_METADATA].convert);
3071 }
3072
3073 if (Vcb->balance.opts[BALANCE_OPTS_SYSTEM].flags & BTRFS_BALANCE_OPTS_ENABLED && Vcb->balance.opts[BALANCE_OPTS_SYSTEM].flags & BTRFS_BALANCE_OPTS_CONVERT) {
3074 old_system_flags = Vcb->system_flags;
3075 Vcb->system_flags = BLOCK_FLAG_SYSTEM | (Vcb->balance.opts[BALANCE_OPTS_SYSTEM].convert == BLOCK_FLAG_SINGLE ? 0 : Vcb->balance.opts[BALANCE_OPTS_SYSTEM].convert);
3076 }
3077
3078 if (Vcb->superblock.incompat_flags & BTRFS_INCOMPAT_FLAGS_MIXED_GROUPS) {
3079 if (Vcb->balance.opts[BALANCE_OPTS_DATA].flags & BTRFS_BALANCE_OPTS_ENABLED)
3080 RtlCopyMemory(&Vcb->balance.opts[BALANCE_OPTS_METADATA], &Vcb->balance.opts[BALANCE_OPTS_DATA], sizeof(btrfs_balance_opts));
3081 else if (Vcb->balance.opts[BALANCE_OPTS_METADATA].flags & BTRFS_BALANCE_OPTS_ENABLED)
3082 RtlCopyMemory(&Vcb->balance.opts[BALANCE_OPTS_DATA], &Vcb->balance.opts[BALANCE_OPTS_METADATA], sizeof(btrfs_balance_opts));
3083 }
3084
3085 num_chunks[0] = num_chunks[1] = num_chunks[2] = 0;
3086 Vcb->balance.total_chunks = Vcb->balance.chunks_left = 0;
3087
3088 InitializeListHead(&chunks);
3089
3090 // FIXME - what are we supposed to do with limit_start?
3091
3092 if (!Vcb->readonly) {
3093 if (!Vcb->balance.removing && !Vcb->balance.shrinking) {
3095 if (!NT_SUCCESS(Status)) {
3096 ERR("add_balance_item returned %08lx\n", Status);
3097 Vcb->balance.status = Status;
3098 goto end;
3099 }
3100 } else {
3101 if (Vcb->need_write) {
3102 Status = do_write(Vcb, NULL);
3103
3104 free_trees(Vcb);
3105
3106 if (!NT_SUCCESS(Status)) {
3107 ERR("do_write returned %08lx\n", Status);
3108 Vcb->balance.status = Status;
3109 goto end;
3110 }
3111 }
3112 }
3113 }
3114
3115 KeWaitForSingleObject(&Vcb->balance.event, Executive, KernelMode, false, NULL);
3116
3117 if (Vcb->balance.stopping)
3118 goto end;
3119
3120 ExAcquireResourceSharedLite(&Vcb->chunk_lock, true);
3121
3122 le = Vcb->chunks.Flink;
3123 while (le != &Vcb->chunks) {
3125 uint8_t sort;
3126
3128
3129 if (c->chunk_item->type & BLOCK_FLAG_DATA)
3131 else if (c->chunk_item->type & BLOCK_FLAG_METADATA)
3133 else if (c->chunk_item->type & BLOCK_FLAG_SYSTEM)
3135 else {
3136 ERR("unexpected chunk type %I64x\n", c->chunk_item->type);
3138 break;
3139 }
3140
3141 if ((!(Vcb->balance.opts[sort].flags & BTRFS_BALANCE_OPTS_LIMIT) || num_chunks[sort] < Vcb->balance.opts[sort].limit_end) &&
3143 InsertTailList(&chunks, &c->list_entry_balance);
3144
3145 num_chunks[sort]++;
3146 Vcb->balance.total_chunks++;
3147 Vcb->balance.chunks_left++;
3148 } else if (sort == BALANCE_OPTS_METADATA)
3149 okay_metadata_chunks++;
3150 else if (sort == BALANCE_OPTS_DATA)
3151 okay_data_chunks++;
3152 else if (sort == BALANCE_OPTS_SYSTEM)
3153 okay_system_chunks++;
3154
3155 if (!c->cache_loaded) {
3157
3158 if (!NT_SUCCESS(Status)) {
3159 ERR("load_cache_chunk returned %08lx\n", Status);
3160 Vcb->balance.status = Status;
3162 ExReleaseResourceLite(&Vcb->chunk_lock);
3163 goto end;
3164 }
3165 }
3166
3168
3169 le = le->Flink;
3170 }
3171
3172 ExReleaseResourceLite(&Vcb->chunk_lock);
3173
3174 // If we're doing a full balance, try and allocate a new chunk now, before we mess things up
3175 if (okay_metadata_chunks == 0 || okay_data_chunks == 0 || okay_system_chunks == 0) {
3176 bool consolidated = false;
3177 chunk* c;
3178
3179 if (okay_metadata_chunks == 0) {
3180 ExAcquireResourceExclusiveLite(&Vcb->chunk_lock, true);
3181
3182 Status = alloc_chunk(Vcb, Vcb->metadata_flags, &c, true);
3183 if (NT_SUCCESS(Status))
3184 c->balance_num = Vcb->balance.balance_num;
3185 else if (Status != STATUS_DISK_FULL || consolidated) {
3186 ERR("alloc_chunk returned %08lx\n", Status);
3187 ExReleaseResourceLite(&Vcb->chunk_lock);
3188 Vcb->balance.status = Status;
3189 goto end;
3190 }
3191
3192 ExReleaseResourceLite(&Vcb->chunk_lock);
3193
3194 if (Status == STATUS_DISK_FULL) {
3195 Status = try_consolidation(Vcb, Vcb->metadata_flags, &c);
3196 if (!NT_SUCCESS(Status)) {
3197 ERR("try_consolidation returned %08lx\n", Status);
3198 Vcb->balance.status = Status;
3199 goto end;
3200 } else
3201 c->balance_num = Vcb->balance.balance_num;
3202
3203 consolidated = true;
3204
3205 if (Vcb->balance.stopping)
3206 goto end;
3207 }
3208 }
3209
3210 if (okay_data_chunks == 0) {
3211 ExAcquireResourceExclusiveLite(&Vcb->chunk_lock, true);
3212
3213 Status = alloc_chunk(Vcb, Vcb->data_flags, &c, true);
3214 if (NT_SUCCESS(Status))
3215 c->balance_num = Vcb->balance.balance_num;
3216 else if (Status != STATUS_DISK_FULL || consolidated) {
3217 ERR("alloc_chunk returned %08lx\n", Status);
3218 ExReleaseResourceLite(&Vcb->chunk_lock);
3219 Vcb->balance.status = Status;
3220 goto end;
3221 }
3222
3223 ExReleaseResourceLite(&Vcb->chunk_lock);
3224
3225 if (Status == STATUS_DISK_FULL) {
3226 Status = try_consolidation(Vcb, Vcb->data_flags, &c);
3227 if (!NT_SUCCESS(Status)) {
3228 ERR("try_consolidation returned %08lx\n", Status);
3229 Vcb->balance.status = Status;
3230 goto end;
3231 } else
3232 c->balance_num = Vcb->balance.balance_num;
3233
3234 consolidated = true;
3235
3236 if (Vcb->balance.stopping)
3237 goto end;
3238 }
3239 }
3240
3241 if (okay_system_chunks == 0) {
3242 ExAcquireResourceExclusiveLite(&Vcb->chunk_lock, true);
3243
3244 Status = alloc_chunk(Vcb, Vcb->system_flags, &c, true);
3245 if (NT_SUCCESS(Status))
3246 c->balance_num = Vcb->balance.balance_num;
3247 else if (Status != STATUS_DISK_FULL || consolidated) {
3248 ERR("alloc_chunk returned %08lx\n", Status);
3249 ExReleaseResourceLite(&Vcb->chunk_lock);
3250 Vcb->balance.status = Status;
3251 goto end;
3252 }
3253
3254 ExReleaseResourceLite(&Vcb->chunk_lock);
3255
3256 if (Status == STATUS_DISK_FULL) {
3257 Status = try_consolidation(Vcb, Vcb->system_flags, &c);
3258 if (!NT_SUCCESS(Status)) {
3259 ERR("try_consolidation returned %08lx\n", Status);
3260 Vcb->balance.status = Status;
3261 goto end;
3262 } else
3263 c->balance_num = Vcb->balance.balance_num;
3264
3265 consolidated = true;
3266
3267 if (Vcb->balance.stopping)
3268 goto end;
3269 }
3270 }
3271 }
3272
3273 ExAcquireResourceSharedLite(&Vcb->chunk_lock, true);
3274
3275 le = chunks.Flink;
3276 while (le != &chunks) {
3277 chunk* c = CONTAINING_RECORD(le, chunk, list_entry_balance);
3278
3279 c->reloc = true;
3280
3281 le = le->Flink;
3282 }
3283
3284 ExReleaseResourceLite(&Vcb->chunk_lock);
3285
3286 // do data chunks before metadata
3287 le = chunks.Flink;
3288 while (le != &chunks) {
3289 chunk* c = CONTAINING_RECORD(le, chunk, list_entry_balance);
3290 LIST_ENTRY* le2 = le->Flink;
3291
3292 if (c->chunk_item->type & BLOCK_FLAG_DATA) {
3293 bool changed;
3294
3295 do {
3296 changed = false;
3297
3298 Status = balance_data_chunk(Vcb, c, &changed);
3299 if (!NT_SUCCESS(Status)) {
3300 ERR("balance_data_chunk returned %08lx\n", Status);
3301 Vcb->balance.status = Status;
3302 goto end;
3303 }
3304
3305 KeWaitForSingleObject(&Vcb->balance.event, Executive, KernelMode, false, NULL);
3306
3307 if (Vcb->readonly)
3308 Vcb->balance.stopping = true;
3309
3310 if (Vcb->balance.stopping)
3311 break;
3312 } while (changed);
3313
3314 c->changed = true;
3315 c->space_changed = true;
3316 }
3317
3318 if (Vcb->balance.stopping)
3319 goto end;
3320
3321 if (c->chunk_item->type & BLOCK_FLAG_DATA &&
3322 (!(Vcb->balance.opts[BALANCE_OPTS_METADATA].flags & BTRFS_BALANCE_OPTS_ENABLED) || !(c->chunk_item->type & BLOCK_FLAG_METADATA))) {
3323 RemoveEntryList(&c->list_entry_balance);
3324 c->list_entry_balance.Flink = NULL;
3325
3326 Vcb->balance.chunks_left--;
3327 }
3328
3329 le = le2;
3330 }
3331
3332 // do metadata chunks
3333 while (!IsListEmpty(&chunks)) {
3334 chunk* c;
3335 bool changed;
3336
3337 le = RemoveHeadList(&chunks);
3338 c = CONTAINING_RECORD(le, chunk, list_entry_balance);
3339
3340 if (c->chunk_item->type & BLOCK_FLAG_METADATA || c->chunk_item->type & BLOCK_FLAG_SYSTEM) {
3341 do {
3342 Status = balance_metadata_chunk(Vcb, c, &changed);
3343 if (!NT_SUCCESS(Status)) {
3344 ERR("balance_metadata_chunk returned %08lx\n", Status);
3345 Vcb->balance.status = Status;
3346 goto end;
3347 }
3348
3349 KeWaitForSingleObject(&Vcb->balance.event, Executive, KernelMode, false, NULL);
3350
3351 if (Vcb->readonly)
3352 Vcb->balance.stopping = true;
3353
3354 if (Vcb->balance.stopping)
3355 break;
3356 } while (changed);
3357
3358 c->changed = true;
3359 c->space_changed = true;
3360 }
3361
3362 if (Vcb->balance.stopping)
3363 break;
3364
3365 c->list_entry_balance.Flink = NULL;
3366
3367 Vcb->balance.chunks_left--;
3368 }
3369
3370end:
3371 if (!Vcb->readonly) {
3372 if (Vcb->balance.stopping || !NT_SUCCESS(Vcb->balance.status)) {
3373 le = chunks.Flink;
3374 while (le != &chunks) {
3375 chunk* c = CONTAINING_RECORD(le, chunk, list_entry_balance);
3376 c->reloc = false;
3377
3378 le = le->Flink;
3379 c->list_entry_balance.Flink = NULL;
3380 }
3381
3382 if (old_data_flags != 0)
3383 Vcb->data_flags = old_data_flags;
3384
3385 if (old_metadata_flags != 0)
3386 Vcb->metadata_flags = old_metadata_flags;
3387
3388 if (old_system_flags != 0)
3389 Vcb->system_flags = old_system_flags;
3390 }
3391
3392 if (Vcb->balance.removing) {
3393 device* dev = NULL;
3394
3395 ExAcquireResourceExclusiveLite(&Vcb->tree_lock, true);
3396
3397 le = Vcb->devices.Flink;
3398 while (le != &Vcb->devices) {
3400
3401 if (dev2->devitem.dev_id == Vcb->balance.opts[0].devid) {
3402 dev = dev2;
3403 break;
3404 }
3405
3406 le = le->Flink;
3407 }
3408
3409 if (dev) {
3410 if (Vcb->balance.chunks_left == 0) {
3412
3413 if (!NT_SUCCESS(Status)) {
3414 ERR("finish_removing_device returned %08lx\n", Status);
3415 dev->reloc = false;
3416 }
3417 } else
3418 dev->reloc = false;
3419 }
3420
3421 ExReleaseResourceLite(&Vcb->tree_lock);
3422 } else if (Vcb->balance.shrinking) {
3423 device* dev = NULL;
3424
3425 ExAcquireResourceExclusiveLite(&Vcb->tree_lock, true);
3426
3427 le = Vcb->devices.Flink;
3428 while (le != &Vcb->devices) {
3430
3431 if (dev2->devitem.dev_id == Vcb->balance.opts[0].devid) {
3432 dev = dev2;
3433 break;
3434 }
3435
3436 le = le->Flink;
3437 }
3438
3439 if (!dev) {
3440 ERR("could not find device %I64x\n", Vcb->balance.opts[0].devid);
3441 Vcb->balance.status = STATUS_INTERNAL_ERROR;
3442 }
3443
3444 if (Vcb->balance.stopping || !NT_SUCCESS(Vcb->balance.status)) {
3445 if (dev) {
3447 if (!NT_SUCCESS(Status))
3448 WARN("regenerate_space_list returned %08lx\n", Status);
3449 }
3450 } else {
3451 uint64_t old_size;
3452
3453 old_size = dev->devitem.num_bytes;
3454 dev->devitem.num_bytes = Vcb->balance.opts[0].drange_start;
3455
3457 if (!NT_SUCCESS(Status)) {
3458 ERR("update_dev_item returned %08lx\n", Status);
3459 dev->devitem.num_bytes = old_size;
3460 Vcb->balance.status = Status;
3461
3463 if (!NT_SUCCESS(Status))
3464 WARN("regenerate_space_list returned %08lx\n", Status);
3465 } else {
3466 Vcb->superblock.total_bytes -= old_size - dev->devitem.num_bytes;
3467
3468 Status = do_write(Vcb, NULL);
3469 if (!NT_SUCCESS(Status))
3470 ERR("do_write returned %08lx\n", Status);
3471
3472 free_trees(Vcb);
3473 }
3474 }
3475
3476 ExReleaseResourceLite(&Vcb->tree_lock);
3477
3478 if (!Vcb->balance.stopping && NT_SUCCESS(Vcb->balance.status))
3480 } else {
3482 if (!NT_SUCCESS(Status)) {
3483 ERR("remove_balance_item returned %08lx\n", Status);
3484 goto end;
3485 }
3486 }
3487
3488 if (Vcb->trim && !Vcb->options.no_trim) {
3489 ExAcquireResourceExclusiveLite(&Vcb->tree_lock, true);
3490
3491 le = Vcb->devices.Flink;
3492 while (le != &Vcb->devices) {
3494
3495 if (dev2->devobj && !dev2->readonly && dev2->trim)
3496 trim_unalloc_space(Vcb, dev2);
3497
3498 le = le->Flink;
3499 }
3500
3501 ExReleaseResourceLite(&Vcb->tree_lock);
3502 }
3503 }
3504
3505 ZwClose(Vcb->balance.thread);
3506 Vcb->balance.thread = NULL;
3507
3508 KeSetEvent(&Vcb->balance.finished, 0, false);
3509}
_STLP_MOVE_TO_STD_NAMESPACE void sort(_RandomAccessIter __first, _RandomAccessIter __last)
Definition: _algo.c:993
LONG NTSTATUS
Definition: precomp.h:26
#define WARN(fmt,...)
Definition: debug.h:115
#define ERR(fmt,...)
Definition: debug.h:113
#define acquire_chunk_lock(c, Vcb)
Definition: btrfs_drv.h:1139
NTSTATUS load_cache_chunk(device_extension *Vcb, chunk *c, PIRP Irp)
Definition: free-space.c:980
NTSTATUS alloc_chunk(device_extension *Vcb, uint64_t flags, chunk **pc, bool full_size) __attribute__((nonnull(1
NTSTATUS update_dev_item(device_extension *Vcb, device *device, PIRP Irp)
Definition: flushthread.c:4093
#define BALANCE_OPTS_METADATA
Definition: btrfs_drv.h:694
NTSTATUS do_write(device_extension *Vcb, PIRP Irp)
Definition: flushthread.c:7877
#define BALANCE_OPTS_DATA
Definition: btrfs_drv.h:693
NTSTATUS NTSTATUS bool bool void free_trees(device_extension *Vcb) __attribute__((nonnull(1)))
#define BALANCE_OPTS_SYSTEM
Definition: btrfs_drv.h:695
#define release_chunk_lock(c, Vcb)
Definition: btrfs_drv.h:1140
#define BTRFS_BALANCE_OPTS_ENABLED
Definition: btrfsioctl.h:130
#define BTRFS_BALANCE_OPTS_CONVERT
Definition: btrfsioctl.h:138
#define BLOCK_FLAG_SINGLE
Definition: btrfsioctl.h:141
#define BTRFS_BALANCE_OPTS_LIMIT
Definition: btrfsioctl.h:135
#define NULL
Definition: types.h:112
UINT64 uint64_t
Definition: types.h:77
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
static NTSTATUS remove_balance_item(device_extension *Vcb)
Definition: balance.c:2451
static NTSTATUS finish_removing_device(_Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension *Vcb, device *dev)
Definition: balance.c:2586
static void trim_unalloc_space(_Requires_lock_held_(_Curr_->tree_lock) device_extension *Vcb, device *dev)
Definition: balance.c:2802
static bool should_balance_chunk(device_extension *Vcb, uint8_t sort, chunk *c)
Definition: balance.c:2225
static NTSTATUS try_consolidation(device_extension *Vcb, uint64_t flags, chunk **newchunk)
Definition: balance.c:2902
static NTSTATUS balance_data_chunk(device_extension *Vcb, chunk *c, bool *changed)
Definition: balance.c:1671
static NTSTATUS balance_metadata_chunk(device_extension *Vcb, chunk *c, bool *changed)
Definition: balance.c:1100
static NTSTATUS add_balance_item(device_extension *Vcb)
Definition: balance.c:2378
static NTSTATUS regenerate_space_list(device_extension *Vcb, device *dev)
Definition: balance.c:2997
#define BTRFS_INCOMPAT_FLAGS_MIXED_GROUPS
Definition: btrfs.h:117
#define RemoveEntryList(Entry)
Definition: env_spec_w32.h:986
#define InsertTailList(ListHead, Entry)
#define IsListEmpty(ListHead)
Definition: env_spec_w32.h:954
#define KeWaitForSingleObject(pEvt, foo, a, b, c)
Definition: env_spec_w32.h:478
#define KeInitializeEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:477
#define KeSetEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:476
#define ExAcquireResourceExclusiveLite(res, wait)
Definition: env_spec_w32.h:615
#define RemoveHeadList(ListHead)
Definition: env_spec_w32.h:964
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
#define ExAcquireResourceSharedLite(res, wait)
Definition: env_spec_w32.h:621
#define FSRTL_VOLUME_CHANGE_SIZE
Definition: fsrtltypes.h:101
Status
Definition: gdiplustypes.h:25
GLuint GLuint end
Definition: gl.h:1545
const GLubyte * c
Definition: glext.h:8905
#define c
Definition: ke_i.h:80
BYTE uint8_t
Definition: msvideo1.c:66
#define KernelMode
Definition: asm.h:34
NTSYSAPI NTSTATUS NTAPI ZwClose(_In_ HANDLE Handle)
@ NotificationEvent
VOID FASTCALL ExReleaseResourceLite(IN PERESOURCE Resource)
Definition: resource.c:1822
NTSTATUS NTAPI FsRtlNotifyVolumeEvent(IN PFILE_OBJECT FileObject, IN ULONG EventCode)
Definition: pnp.c:38
#define STATUS_INTERNAL_ERROR
Definition: ntstatus.h:465
#define Vcb
Definition: cdprocs.h:1415
#define BLOCK_FLAG_DATA
Definition: shellext.h:75
#define BLOCK_FLAG_SYSTEM
Definition: shellext.h:76
#define BLOCK_FLAG_METADATA
Definition: shellext.h:77
uint64_t dev_id
Definition: btrfs.h:178
Definition: typedefs.h:120
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
Definition: http.c:7252
Definition: devices.h:37
DEV_ITEM devitem
Definition: btrfs_drv.h:527
bool readonly
Definition: btrfs_drv.h:530
bool trim
Definition: btrfs_drv.h:532
PDEVICE_OBJECT devobj
Definition: btrfs_drv.h:525
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_DISK_FULL
Definition: udferr_usr.h:155
@ Executive
Definition: ketypes.h:415

◆ add_balance_item()

static NTSTATUS add_balance_item ( device_extension Vcb)
static

Definition at line 2378 of file balance.c.

2378 {
2379 KEY searchkey;
2382 BALANCE_ITEM* bi;
2383
2384 searchkey.obj_id = BALANCE_ITEM_ID;
2385 searchkey.obj_type = TYPE_TEMP_ITEM;
2386 searchkey.offset = 0;
2387
2388 ExAcquireResourceExclusiveLite(&Vcb->tree_lock, true);
2389
2390 Status = find_item(Vcb, Vcb->root_root, &tp, &searchkey, false, NULL);
2391 if (!NT_SUCCESS(Status)) {
2392 ERR("find_item returned %08lx\n", Status);
2393 goto end;
2394 }
2395
2396 if (!keycmp(tp.item->key, searchkey)) {
2398 if (!NT_SUCCESS(Status)) {
2399 ERR("delete_tree_item returned %08lx\n", Status);
2400 goto end;
2401 }
2402 }
2403
2405 if (!bi) {
2406 ERR("out of memory\n");
2408 goto end;
2409 }
2410
2411 RtlZeroMemory(bi, sizeof(BALANCE_ITEM));
2412
2413 if (Vcb->balance.opts[BALANCE_OPTS_DATA].flags & BTRFS_BALANCE_OPTS_ENABLED) {
2415 copy_balance_args(&Vcb->balance.opts[BALANCE_OPTS_DATA], &bi->data);
2416 }
2417
2418 if (Vcb->balance.opts[BALANCE_OPTS_METADATA].flags & BTRFS_BALANCE_OPTS_ENABLED) {
2420 copy_balance_args(&Vcb->balance.opts[BALANCE_OPTS_METADATA], &bi->metadata);
2421 }
2422
2423 if (Vcb->balance.opts[BALANCE_OPTS_SYSTEM].flags & BTRFS_BALANCE_OPTS_ENABLED) {
2425 copy_balance_args(&Vcb->balance.opts[BALANCE_OPTS_SYSTEM], &bi->system);
2426 }
2427
2429 if (!NT_SUCCESS(Status)) {
2430 ERR("insert_tree_item returned %08lx\n", Status);
2431 ExFreePool(bi);
2432 goto end;
2433 }
2434
2436
2437end:
2438 if (NT_SUCCESS(Status)) {
2439 Status = do_write(Vcb, NULL);
2440 if (!NT_SUCCESS(Status))
2441 ERR("do_write returned %08lx\n", Status);
2442 }
2443
2444 free_trees(Vcb);
2445
2446 ExReleaseResourceLite(&Vcb->tree_lock);
2447
2448 return Status;
2449}
#define keycmp(key1, key2)
Definition: btrfs_drv.h:1016
#define ALLOC_TAG
Definition: btrfs_drv.h:87
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 delete_tree_item(_In_ _Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension *Vcb, _Inout_ traverse_ptr *tp) __attribute__((nonnull(1
static LONG find_item(PropertyBag *This, LPCOLESTR name)
Definition: propertybag.c:110
static void copy_balance_args(btrfs_balance_opts *opts, BALANCE_ARGS *args)
Definition: balance.c:2318
_In_ uint64_t _In_ uint64_t _In_ uint64_t _In_opt_ traverse_ptr * tp
Definition: btrfs.c:2996
#define TYPE_TEMP_ITEM
Definition: btrfs.h:49
#define BALANCE_FLAGS_METADATA
Definition: btrfs.h:478
#define BALANCE_FLAGS_SYSTEM
Definition: btrfs.h:477
#define BALANCE_ITEM_ID
Definition: btrfs.h:92
#define BALANCE_FLAGS_DATA
Definition: btrfs.h:476
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
#define ExFreePool(addr)
Definition: env_spec_w32.h:352
#define PagedPool
Definition: env_spec_w32.h:308
#define STATUS_SUCCESS
Definition: shellext.h:65
BALANCE_ARGS metadata
Definition: btrfs.h:527
BALANCE_ARGS system
Definition: btrfs.h:528
uint64_t flags
Definition: btrfs.h:525
BALANCE_ARGS data
Definition: btrfs.h:526
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
tree_data * item
Definition: btrfs_drv.h:509
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158

Referenced by _Function_class_().

◆ add_data_reloc()

static NTSTATUS add_data_reloc ( _Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension Vcb,
LIST_ENTRY items,
LIST_ENTRY metadata_items,
traverse_ptr tp,
chunk c,
LIST_ENTRY rollback 
)
static

Definition at line 1316 of file balance.c.

1317 {
1319 data_reloc* dr;
1320 EXTENT_ITEM* ei;
1321 uint16_t len;
1322 uint64_t inline_rc;
1323 uint8_t* ptr;
1324
1326 if (!dr) {
1327 ERR("out of memory\n");
1329 }
1330
1331 dr->address = tp->item->key.obj_id;
1332 dr->size = tp->item->key.offset;
1333 dr->ei = (EXTENT_ITEM*)tp->item->data;
1335
1337 if (!NT_SUCCESS(Status)) {
1338 ERR("delete_tree_item returned %08lx\n", Status);
1339 return Status;
1340 }
1341
1342 if (!c)
1344
1345 if (c) {
1347
1348 c->used -= tp->item->key.offset;
1349
1351
1353 }
1354
1355 ei = (EXTENT_ITEM*)tp->item->data;
1356 inline_rc = 0;
1357
1358 len = tp->item->size - sizeof(EXTENT_ITEM);
1359 ptr = (uint8_t*)tp->item->data + sizeof(EXTENT_ITEM);
1360
1361 while (len > 0) {
1362 uint8_t secttype = *ptr;
1363 uint16_t sectlen = secttype == TYPE_EXTENT_DATA_REF ? sizeof(EXTENT_DATA_REF) : (secttype == TYPE_SHARED_DATA_REF ? sizeof(SHARED_DATA_REF) : 0);
1364
1365 len--;
1366
1367 if (sectlen > len) {
1368 ERR("(%I64x,%x,%I64x): %x bytes left, expecting at least %x\n", tp->item->key.obj_id, tp->item->key.obj_type, tp->item->key.offset, len, sectlen);
1369 return STATUS_INTERNAL_ERROR;
1370 }
1371
1372 if (sectlen == 0) {
1373 ERR("(%I64x,%x,%I64x): unrecognized extent type %x\n", tp->item->key.obj_id, tp->item->key.obj_type, tp->item->key.offset, secttype);
1374 return STATUS_INTERNAL_ERROR;
1375 }
1376
1377 if (secttype == TYPE_EXTENT_DATA_REF) {
1378 EXTENT_DATA_REF* edr = (EXTENT_DATA_REF*)(ptr + sizeof(uint8_t));
1379
1380 inline_rc += edr->count;
1381
1382 Status = data_reloc_add_tree_edr(Vcb, metadata_items, dr, edr, rollback);
1383 if (!NT_SUCCESS(Status)) {
1384 ERR("data_reloc_add_tree_edr returned %08lx\n", Status);
1385 return Status;
1386 }
1387 } else if (secttype == TYPE_SHARED_DATA_REF) {
1388 metadata_reloc* mr;
1390
1392 if (!ref) {
1393 ERR("out of memory\n");
1395 }
1396
1397 ref->type = TYPE_SHARED_DATA_REF;
1398 RtlCopyMemory(&ref->sdr, ptr + sizeof(uint8_t), sizeof(SHARED_DATA_REF));
1399 inline_rc += ref->sdr.count;
1400
1401 Status = add_metadata_reloc_parent(Vcb, metadata_items, ref->sdr.offset, &mr, rollback);
1402 if (!NT_SUCCESS(Status)) {
1403 ERR("add_metadata_reloc_parent returned %08lx\n", Status);
1404 ExFreePool(ref);
1405 return Status;
1406 }
1407
1408 ref->parent = mr;
1409
1411 } else {
1412 ERR("unexpected tree type %x\n", secttype);
1413 return STATUS_INTERNAL_ERROR;
1414 }
1415
1416
1417 len -= sectlen;
1418 ptr += sizeof(uint8_t) + sectlen;
1419 }
1420
1421 if (inline_rc < ei->refcount) { // look for non-inline entries
1422 traverse_ptr tp2 = *tp, next_tp;
1423
1424 while (find_next_item(Vcb, &tp2, &next_tp, false, NULL)) {
1425 tp2 = next_tp;
1426
1427 if (tp2.item->key.obj_id == tp->item->key.obj_id) {
1428 if (tp2.item->key.obj_type == TYPE_EXTENT_DATA_REF && tp2.item->size >= sizeof(EXTENT_DATA_REF)) {
1429 Status = data_reloc_add_tree_edr(Vcb, metadata_items, dr, (EXTENT_DATA_REF*)tp2.item->data, rollback);
1430 if (!NT_SUCCESS(Status)) {
1431 ERR("data_reloc_add_tree_edr returned %08lx\n", Status);
1432 return Status;
1433 }
1434
1435 Status = delete_tree_item(Vcb, &tp2);
1436 if (!NT_SUCCESS(Status)) {
1437 ERR("delete_tree_item returned %08lx\n", Status);
1438 return Status;
1439 }
1440 } else if (tp2.item->key.obj_type == TYPE_SHARED_DATA_REF && tp2.item->size >= sizeof(uint32_t)) {
1441 metadata_reloc* mr;
1443
1445 if (!ref) {
1446 ERR("out of memory\n");
1448 }
1449
1450 ref->type = TYPE_SHARED_DATA_REF;
1451 ref->sdr.offset = tp2.item->key.offset;
1452 ref->sdr.count = *((uint32_t*)tp2.item->data);
1453
1454 Status = add_metadata_reloc_parent(Vcb, metadata_items, ref->sdr.offset, &mr, rollback);
1455 if (!NT_SUCCESS(Status)) {
1456 ERR("add_metadata_reloc_parent returned %08lx\n", Status);
1457 ExFreePool(ref);
1458 return Status;
1459 }
1460
1461 ref->parent = mr;
1463
1464 Status = delete_tree_item(Vcb, &tp2);
1465 if (!NT_SUCCESS(Status)) {
1466 ERR("delete_tree_item returned %08lx\n", Status);
1467 return Status;
1468 }
1469 }
1470 } else
1471 break;
1472 }
1473 }
1474
1476
1477 return STATUS_SUCCESS;
1478}
unsigned short int uint16_t
Definition: acefiex.h:54
_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 NTSTATUS NTSTATUS NTSTATUS NTSTATUS chunk * get_chunk_from_address(device_extension *Vcb, uint64_t address) __attribute__((nonnull(1)))
void space_list_add(chunk *c, uint64_t address, uint64_t length, LIST_ENTRY *rollback)
Definition: free-space.c:2146
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
UINT32 uint32_t
Definition: types.h:75
static NTSTATUS add_metadata_reloc_parent(_Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension *Vcb, LIST_ENTRY *items, uint64_t address, metadata_reloc **mr2, LIST_ENTRY *rollback)
Definition: balance.c:226
static NTSTATUS data_reloc_add_tree_edr(_Requires_lock_held_(_Curr_->tree_lock) device_extension *Vcb, LIST_ENTRY *metadata_items, data_reloc *dr, EXTENT_DATA_REF *edr, LIST_ENTRY *rollback)
Definition: balance.c:1217
#define TYPE_EXTENT_DATA_REF
Definition: btrfs.h:38
#define TYPE_SHARED_DATA_REF
Definition: btrfs.h:41
GLenum GLsizei len
Definition: glext.h:6722
static PVOID ptr
Definition: dispmode.c:27
#define uint8_t
Definition: nsiface.idl:59
static TCHAR * items[]
Definition: page1.c:45
uint32_t count
Definition: btrfs.h:420
uint8_t * data
Definition: btrfs_drv.h:415
uint16_t size
Definition: btrfs_drv.h:414
uint64_t address
Definition: balance.c:49
LIST_ENTRY refs
Definition: balance.c:54
LIST_ENTRY list_entry
Definition: balance.c:55
EXTENT_ITEM * ei
Definition: balance.c:53
uint64_t size
Definition: balance.c:50
Definition: send.c:48
LIST_ENTRY list_entry
Definition: send.c:49

Referenced by balance_data_chunk().

◆ add_data_reloc_extent_item()

static NTSTATUS add_data_reloc_extent_item ( _Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension Vcb,
data_reloc dr 
)
static

Definition at line 1541 of file balance.c.

1541 {
1543 LIST_ENTRY* le;
1544 uint64_t rc = 0;
1545 uint16_t inline_len;
1546 bool all_inline = true;
1547 data_reloc_ref* first_noninline = NULL;
1548 EXTENT_ITEM* ei;
1549 uint8_t* ptr;
1550
1551 inline_len = sizeof(EXTENT_ITEM);
1552
1554
1555 le = dr->refs.Flink;
1556 while (le != &dr->refs) {
1558 uint16_t extlen = 0;
1559
1560 if (ref->type == TYPE_EXTENT_DATA_REF) {
1561 extlen += sizeof(EXTENT_DATA_REF);
1562 rc += ref->edr.count;
1563 } else if (ref->type == TYPE_SHARED_DATA_REF) {
1564 extlen += sizeof(SHARED_DATA_REF);
1565 rc++;
1566 }
1567
1568 if (all_inline) {
1569 if ((ULONG)(inline_len + 1 + extlen) > (Vcb->superblock.node_size >> 2)) {
1570 all_inline = false;
1571 first_noninline = ref;
1572 } else
1573 inline_len += extlen + 1;
1574 }
1575
1576 le = le->Flink;
1577 }
1578
1579 ei = ExAllocatePoolWithTag(PagedPool, inline_len, ALLOC_TAG);
1580 if (!ei) {
1581 ERR("out of memory\n");
1583 }
1584
1585 ei->refcount = rc;
1586 ei->generation = dr->ei->generation;
1587 ei->flags = dr->ei->flags;
1588 ptr = (uint8_t*)&ei[1];
1589
1590 le = dr->refs.Flink;
1591 while (le != &dr->refs) {
1593
1594 if (ref == first_noninline)
1595 break;
1596
1597 *ptr = ref->type;
1598 ptr++;
1599
1600 if (ref->type == TYPE_EXTENT_DATA_REF) {
1602
1603 RtlCopyMemory(edr, &ref->edr, sizeof(EXTENT_DATA_REF));
1604
1605 ptr += sizeof(EXTENT_DATA_REF);
1606 } else if (ref->type == TYPE_SHARED_DATA_REF) {
1608
1609 sdr->offset = ref->parent->new_address;
1610 sdr->count = ref->sdr.count;
1611
1612 ptr += sizeof(SHARED_DATA_REF);
1613 }
1614
1615 le = le->Flink;
1616 }
1617
1618 Status = insert_tree_item(Vcb, Vcb->extent_root, dr->new_address, TYPE_EXTENT_ITEM, dr->size, ei, inline_len, NULL, NULL);
1619 if (!NT_SUCCESS(Status)) {
1620 ERR("insert_tree_item returned %08lx\n", Status);
1621 return Status;
1622 }
1623
1624 if (!all_inline) {
1625 le = &first_noninline->list_entry;
1626
1627 while (le != &dr->refs) {
1629
1630 if (ref->type == TYPE_EXTENT_DATA_REF) {
1631 EXTENT_DATA_REF* edr;
1632
1634 if (!edr) {
1635 ERR("out of memory\n");
1637 }
1638
1639 RtlCopyMemory(edr, &ref->edr, sizeof(EXTENT_DATA_REF));
1640
1641 Status = insert_tree_item(Vcb, Vcb->extent_root, dr->new_address, TYPE_EXTENT_DATA_REF, ref->hash, edr, sizeof(EXTENT_DATA_REF), NULL, NULL);
1642 if (!NT_SUCCESS(Status)) {
1643 ERR("insert_tree_item returned %08lx\n", Status);
1644 return Status;
1645 }
1646 } else if (ref->type == TYPE_SHARED_DATA_REF) {
1647 uint32_t* sdr;
1648
1650 if (!sdr) {
1651 ERR("out of memory\n");
1653 }
1654
1655 *sdr = ref->sdr.count;
1656
1657 Status = insert_tree_item(Vcb, Vcb->extent_root, dr->new_address, TYPE_SHARED_DATA_REF, ref->parent->new_address, sdr, sizeof(uint32_t), NULL, NULL);
1658 if (!NT_SUCCESS(Status)) {
1659 ERR("insert_tree_item returned %08lx\n", Status);
1660 return Status;
1661 }
1662 }
1663
1664 le = le->Flink;
1665 }
1666 }
1667
1668 return STATUS_SUCCESS;
1669}
static void sort_data_reloc_refs(data_reloc *dr)
Definition: balance.c:1480
#define TYPE_EXTENT_ITEM
Definition: btrfs.h:35
uint64_t generation
Definition: btrfs.h:393
uint64_t flags
Definition: btrfs.h:394
uint64_t refcount
Definition: btrfs.h:392
uint32_t count
Definition: btrfs.h:442
uint64_t offset
Definition: btrfs.h:441
LIST_ENTRY list_entry
Definition: balance.c:68
uint64_t new_address
Definition: balance.c:51
uint32_t ULONG
Definition: typedefs.h:59

Referenced by balance_data_chunk().

◆ add_metadata_reloc()

static NTSTATUS add_metadata_reloc ( _Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension Vcb,
LIST_ENTRY items,
traverse_ptr tp,
bool  skinny,
metadata_reloc **  mr2,
chunk c,
LIST_ENTRY rollback 
)
static

Definition at line 73 of file balance.c.

74 {
77 EXTENT_ITEM* ei;
79 uint64_t inline_rc;
80 uint8_t* ptr;
81
83 if (!mr) {
84 ERR("out of memory\n");
86 }
87
88 mr->address = tp->item->key.obj_id;
89 mr->data = NULL;
90 mr->ei = (EXTENT_ITEM*)tp->item->data;
91 mr->system = false;
93
95 if (!NT_SUCCESS(Status)) {
96 ERR("delete_tree_item returned %08lx\n", Status);
97 ExFreePool(mr);
98 return Status;
99 }
100
101 if (!c)
103
104 if (c) {
106
107 c->used -= Vcb->superblock.node_size;
108
109 space_list_add(c, tp->item->key.obj_id, Vcb->superblock.node_size, rollback);
110
112 }
113
114 ei = (EXTENT_ITEM*)tp->item->data;
115 inline_rc = 0;
116
117 len = tp->item->size - sizeof(EXTENT_ITEM);
118 ptr = (uint8_t*)tp->item->data + sizeof(EXTENT_ITEM);
119 if (!skinny) {
120 len -= sizeof(EXTENT_ITEM2);
121 ptr += sizeof(EXTENT_ITEM2);
122 }
123
124 while (len > 0) {
125 uint8_t secttype = *ptr;
126 uint16_t sectlen = secttype == TYPE_TREE_BLOCK_REF ? sizeof(TREE_BLOCK_REF) : (secttype == TYPE_SHARED_BLOCK_REF ? sizeof(SHARED_BLOCK_REF) : 0);
128
129 len--;
130
131 if (sectlen > len) {
132 ERR("(%I64x,%x,%I64x): %x bytes left, expecting at least %x\n", tp->item->key.obj_id, tp->item->key.obj_type, tp->item->key.offset, len, sectlen);
134 }
135
136 if (sectlen == 0) {
137 ERR("(%I64x,%x,%I64x): unrecognized extent type %x\n", tp->item->key.obj_id, tp->item->key.obj_type, tp->item->key.offset, secttype);
139 }
140
142 if (!ref) {
143 ERR("out of memory\n");
145 }
146
147 if (secttype == TYPE_TREE_BLOCK_REF) {
148 ref->type = TYPE_TREE_BLOCK_REF;
149 RtlCopyMemory(&ref->tbr, ptr + sizeof(uint8_t), sizeof(TREE_BLOCK_REF));
150 inline_rc++;
151 } else if (secttype == TYPE_SHARED_BLOCK_REF) {
153 RtlCopyMemory(&ref->sbr, ptr + sizeof(uint8_t), sizeof(SHARED_BLOCK_REF));
154 inline_rc++;
155 } else {
156 ERR("unexpected tree type %x\n", secttype);
159 }
160
161 ref->parent = NULL;
162 ref->top = false;
164
165 len -= sectlen;
166 ptr += sizeof(uint8_t) + sectlen;
167 }
168
169 if (inline_rc < ei->refcount) { // look for non-inline entries
170 traverse_ptr tp2 = *tp, next_tp;
171
172 while (find_next_item(Vcb, &tp2, &next_tp, false, NULL)) {
173 tp2 = next_tp;
174
175 if (tp2.item->key.obj_id == tp->item->key.obj_id) {
176 if (tp2.item->key.obj_type == TYPE_TREE_BLOCK_REF) {
178 if (!ref) {
179 ERR("out of memory\n");
181 }
182
183 ref->type = TYPE_TREE_BLOCK_REF;
184 ref->tbr.offset = tp2.item->key.offset;
185 ref->parent = NULL;
186 ref->top = false;
188
189 Status = delete_tree_item(Vcb, &tp2);
190 if (!NT_SUCCESS(Status)) {
191 ERR("delete_tree_item returned %08lx\n", Status);
192 return Status;
193 }
194 } else if (tp2.item->key.obj_type == TYPE_SHARED_BLOCK_REF) {
196 if (!ref) {
197 ERR("out of memory\n");
199 }
200
202 ref->sbr.offset = tp2.item->key.offset;
203 ref->parent = NULL;
204 ref->top = false;
206
207 Status = delete_tree_item(Vcb, &tp2);
208 if (!NT_SUCCESS(Status)) {
209 ERR("delete_tree_item returned %08lx\n", Status);
210 return Status;
211 }
212 }
213 } else
214 break;
215 }
216 }
217
219
220 if (mr2)
221 *mr2 = mr;
222
223 return STATUS_SUCCESS;
224}
#define TYPE_SHARED_BLOCK_REF
Definition: btrfs.h:40
#define TYPE_TREE_BLOCK_REF
Definition: btrfs.h:37
LIST_ENTRY refs
Definition: balance.c:30
uint64_t address
Definition: balance.c:24
EXTENT_ITEM * ei
Definition: balance.c:27
bool system
Definition: balance.c:29
LIST_ENTRY list_entry
Definition: balance.c:31
tree_header * data
Definition: balance.c:26

Referenced by add_metadata_reloc_parent(), and balance_metadata_chunk().

◆ add_metadata_reloc_extent_item()

static NTSTATUS add_metadata_reloc_extent_item ( _Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension Vcb,
metadata_reloc mr 
)
static

Definition at line 322 of file balance.c.

322 {
324 LIST_ENTRY* le;
325 uint64_t rc = 0;
326 uint16_t inline_len;
327 bool all_inline = true;
328 metadata_reloc_ref* first_noninline = NULL;
329 EXTENT_ITEM* ei;
330 uint8_t* ptr;
331
332 inline_len = sizeof(EXTENT_ITEM);
333 if (!(Vcb->superblock.incompat_flags & BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA))
334 inline_len += sizeof(EXTENT_ITEM2);
335
337
338 le = mr->refs.Flink;
339 while (le != &mr->refs) {
341 uint16_t extlen = 0;
342
343 rc++;
344
345 if (ref->type == TYPE_TREE_BLOCK_REF)
346 extlen += sizeof(TREE_BLOCK_REF);
347 else if (ref->type == TYPE_SHARED_BLOCK_REF)
348 extlen += sizeof(SHARED_BLOCK_REF);
349
350 if (all_inline) {
351 if ((ULONG)(inline_len + 1 + extlen) > (Vcb->superblock.node_size >> 2)) {
352 all_inline = false;
353 first_noninline = ref;
354 } else
355 inline_len += extlen + 1;
356 }
357
358 le = le->Flink;
359 }
360
361 ei = ExAllocatePoolWithTag(PagedPool, inline_len, ALLOC_TAG);
362 if (!ei) {
363 ERR("out of memory\n");
365 }
366
367 ei->refcount = rc;
368 ei->generation = mr->ei->generation;
369 ei->flags = mr->ei->flags;
370 ptr = (uint8_t*)&ei[1];
371
372 if (!(Vcb->superblock.incompat_flags & BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA)) {
374
375 ei2->firstitem = *(KEY*)&mr->data[1];
376 ei2->level = mr->data->level;
377
378 ptr += sizeof(EXTENT_ITEM2);
379 }
380
381 le = mr->refs.Flink;
382 while (le != &mr->refs) {
384
385 if (ref == first_noninline)
386 break;
387
388 *ptr = ref->type;
389 ptr++;
390
391 if (ref->type == TYPE_TREE_BLOCK_REF) {
393
394 tbr->offset = ref->tbr.offset;
395
396 ptr += sizeof(TREE_BLOCK_REF);
397 } else if (ref->type == TYPE_SHARED_BLOCK_REF) {
399
400 sbr->offset = ref->parent->new_address;
401
402 ptr += sizeof(SHARED_BLOCK_REF);
403 }
404
405 le = le->Flink;
406 }
407
408 if (Vcb->superblock.incompat_flags & BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA)
409 Status = insert_tree_item(Vcb, Vcb->extent_root, mr->new_address, TYPE_METADATA_ITEM, mr->data->level, ei, inline_len, NULL, NULL);
410 else
411 Status = insert_tree_item(Vcb, Vcb->extent_root, mr->new_address, TYPE_EXTENT_ITEM, Vcb->superblock.node_size, ei, inline_len, NULL, NULL);
412
413 if (!NT_SUCCESS(Status)) {
414 ERR("insert_tree_item returned %08lx\n", Status);
415 ExFreePool(ei);
416 return Status;
417 }
418
419 if (!all_inline) {
420 le = &first_noninline->list_entry;
421
422 while (le != &mr->refs) {
424
425 if (ref->type == TYPE_TREE_BLOCK_REF) {
426 Status = insert_tree_item(Vcb, Vcb->extent_root, mr->new_address, TYPE_TREE_BLOCK_REF, ref->tbr.offset, NULL, 0, NULL, NULL);
427 if (!NT_SUCCESS(Status)) {
428 ERR("insert_tree_item returned %08lx\n", Status);
429 return Status;
430 }
431 } else if (ref->type == TYPE_SHARED_BLOCK_REF) {
432 Status = insert_tree_item(Vcb, Vcb->extent_root, mr->new_address, TYPE_SHARED_BLOCK_REF, ref->parent->new_address, NULL, 0, NULL, NULL);
433 if (!NT_SUCCESS(Status)) {
434 ERR("insert_tree_item returned %08lx\n", Status);
435 return Status;
436 }
437 }
438
439 le = le->Flink;
440 }
441 }
442
444 if (mr->data->level > 0) {
445 uint16_t i;
446 internal_node* in = (internal_node*)&mr->data[1];
447
448 for (i = 0; i < mr->data->num_items; i++) {
450
451 if (sbrrc > 0) {
453
454 sbr.offset = mr->new_address;
455
456 Status = increase_extent_refcount(Vcb, in[i].address, Vcb->superblock.node_size, TYPE_SHARED_BLOCK_REF, &sbr, NULL, 0, NULL);
457 if (!NT_SUCCESS(Status)) {
458 ERR("increase_extent_refcount returned %08lx\n", Status);
459 return Status;
460 }
461
462 sbr.offset = mr->address;
463
464 Status = decrease_extent_refcount(Vcb, in[i].address, Vcb->superblock.node_size, TYPE_SHARED_BLOCK_REF, &sbr, NULL, 0,
465 sbr.offset, false, NULL);
466 if (!NT_SUCCESS(Status)) {
467 ERR("decrease_extent_refcount returned %08lx\n", Status);
468 return Status;
469 }
470 }
471 }
472 } else {
473 uint16_t i;
474 leaf_node* ln = (leaf_node*)&mr->data[1];
475
476 for (i = 0; i < mr->data->num_items; i++) {
477 if (ln[i].key.obj_type == TYPE_EXTENT_DATA && ln[i].size >= sizeof(EXTENT_DATA) - 1 + sizeof(EXTENT_DATA2)) {
478 EXTENT_DATA* ed = (EXTENT_DATA*)((uint8_t*)mr->data + sizeof(tree_header) + ln[i].offset);
479
480 if (ed->type == EXTENT_TYPE_REGULAR || ed->type == EXTENT_TYPE_PREALLOC) {
481 EXTENT_DATA2* ed2 = (EXTENT_DATA2*)ed->data;
482
483 if (ed2->size > 0) { // not sparse
485
486 if (sdrrc > 0) {
487 SHARED_DATA_REF sdr;
488 chunk* c;
489
490 sdr.offset = mr->new_address;
491 sdr.count = sdrrc;
492
494 if (!NT_SUCCESS(Status)) {
495 ERR("increase_extent_refcount returned %08lx\n", Status);
496 return Status;
497 }
498
499 sdr.offset = mr->address;
500
502 sdr.offset, false, NULL);
503 if (!NT_SUCCESS(Status)) {
504 ERR("decrease_extent_refcount returned %08lx\n", Status);
505 return Status;
506 }
507
509
510 if (c) {
511 // check changed_extents
512
513 ExAcquireResourceExclusiveLite(&c->changed_extents_lock, true);
514
515 le = c->changed_extents.Flink;
516
517 while (le != &c->changed_extents) {
519
520 if (ce->address == ed2->address) {
521 LIST_ENTRY* le2;
522
523 le2 = ce->refs.Flink;
524 while (le2 != &ce->refs) {
526
527 if (cer->type == TYPE_SHARED_DATA_REF && cer->sdr.offset == mr->address) {
528 cer->sdr.offset = mr->new_address;
529 break;
530 }
531
532 le2 = le2->Flink;
533 }
534
535 le2 = ce->old_refs.Flink;
536 while (le2 != &ce->old_refs) {
538
539 if (cer->type == TYPE_SHARED_DATA_REF && cer->sdr.offset == mr->address) {
540 cer->sdr.offset = mr->new_address;
541 break;
542 }
543
544 le2 = le2->Flink;
545 }
546
547 break;
548 }
549
550 le = le->Flink;
551 }
552
553 ExReleaseResourceLite(&c->changed_extents_lock);
554 }
555 }
556 }
557 }
558 }
559 }
560 }
561 }
562
563 return STATUS_SUCCESS;
564}
uint64_t find_extent_shared_tree_refcount(device_extension *Vcb, uint64_t address, uint64_t parent, PIRP Irp)
Definition: extent-tree.c:2119
uint32_t find_extent_shared_data_refcount(device_extension *Vcb, uint64_t address, uint64_t parent, PIRP Irp)
Definition: extent-tree.c:2220
NTSTATUS increase_extent_refcount(device_extension *Vcb, uint64_t address, uint64_t size, uint8_t type, void *data, KEY *firstitem, uint8_t level, PIRP Irp)
Definition: extent-tree.c:454
NTSTATUS decrease_extent_refcount(device_extension *Vcb, uint64_t address, uint64_t size, uint8_t type, void *data, KEY *firstitem, uint8_t level, uint64_t parent, bool superseded, PIRP Irp)
Definition: extent-tree.c:903
static void sort_metadata_reloc_refs(metadata_reloc *mr)
Definition: balance.c:280
#define TYPE_EXTENT_DATA
Definition: btrfs.h:30
#define BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA
Definition: btrfs.h:123
#define EXTENT_TYPE_PREALLOC
Definition: btrfs.h:76
#define HEADER_FLAG_SHARED_BACKREF
Definition: btrfs.h:150
#define HEADER_FLAG_MIXED_BACKREF
Definition: btrfs.h:151
#define EXTENT_TYPE_REGULAR
Definition: btrfs.h:75
#define EXTENT_ITEM_SHARED_BACKREFS
Definition: btrfs.h:389
#define TYPE_METADATA_ITEM
Definition: btrfs.h:36
GLuint address
Definition: glext.h:9393
GLuint in
Definition: glext.h:9616
GLintptr offset
Definition: glext.h:5920
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
if(dx< 0)
Definition: linetemp.h:194
#define for
Definition: utility.h:88
uint64_t address
Definition: btrfs.h:368
uint64_t size
Definition: btrfs.h:369
uint8_t data[1]
Definition: btrfs.h:364
uint8_t type
Definition: btrfs.h:363
KEY firstitem
Definition: btrfs.h:398
uint8_t level
Definition: btrfs.h:399
uint64_t offset
Definition: btrfs.h:437
uint64_t offset
Definition: btrfs.h:413
SHARED_DATA_REF sdr
Definition: btrfs_drv.h:614
uint64_t address
Definition: btrfs_drv.h:597
LIST_ENTRY old_refs
Definition: btrfs_drv.h:605
LIST_ENTRY refs
Definition: btrfs_drv.h:604
Definition: copy.c:22
LIST_ENTRY list_entry
Definition: balance.c:45
uint64_t new_address
Definition: balance.c:25
uint32_t num_items
Definition: btrfs.h:161
uint64_t flags
Definition: btrfs.h:157
uint8_t level
Definition: btrfs.h:162

Referenced by write_metadata_items().

◆ add_metadata_reloc_parent()

static NTSTATUS add_metadata_reloc_parent ( _Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension Vcb,
LIST_ENTRY items,
uint64_t  address,
metadata_reloc **  mr2,
LIST_ENTRY rollback 
)
static

Definition at line 226 of file balance.c.

227 {
228 LIST_ENTRY* le;
229 KEY searchkey;
231 bool skinny = false;
233
234 le = items->Flink;
235 while (le != items) {
237
238 if (mr->address == address) {
239 *mr2 = mr;
240 return STATUS_SUCCESS;
241 }
242
243 le = le->Flink;
244 }
245
246 searchkey.obj_id = address;
247 searchkey.obj_type = TYPE_METADATA_ITEM;
248 searchkey.offset = 0xffffffffffffffff;
249
250 Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, false, NULL);
251 if (!NT_SUCCESS(Status)) {
252 ERR("find_item returned %08lx\n", Status);
253 return Status;
254 }
255
257 skinny = true;
258 else if (tp.item->key.obj_id == address && tp.item->key.obj_type == TYPE_EXTENT_ITEM && tp.item->key.offset == Vcb->superblock.node_size &&
259 tp.item->size >= sizeof(EXTENT_ITEM)) {
261
262 if (!(ei->flags & EXTENT_ITEM_TREE_BLOCK)) {
263 ERR("EXTENT_ITEM for %I64x found, but tree flag not set\n", address);
265 }
266 } else {
267 ERR("could not find valid EXTENT_ITEM for address %I64x\n", address);
269 }
270
271 Status = add_metadata_reloc(Vcb, items, &tp, skinny, mr2, NULL, rollback);
272 if (!NT_SUCCESS(Status)) {
273 ERR("add_metadata_reloc returned %08lx\n", Status);
274 return Status;
275 }
276
277 return STATUS_SUCCESS;
278}
static NTSTATUS add_metadata_reloc(_Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension *Vcb, LIST_ENTRY *items, traverse_ptr *tp, bool skinny, metadata_reloc **mr2, chunk *c, LIST_ENTRY *rollback)
Definition: balance.c:73
#define EXTENT_ITEM_TREE_BLOCK
Definition: btrfs.h:388

Referenced by add_data_reloc(), data_reloc_add_tree_edr(), and write_metadata_items().

◆ balance_data_chunk()

static NTSTATUS balance_data_chunk ( device_extension Vcb,
chunk c,
bool changed 
)
static

Definition at line 1671 of file balance.c.

1671 {
1672 KEY searchkey;
1675 bool b;
1676 LIST_ENTRY items, metadata_items, rollback, *le;
1677 uint64_t loaded = 0, num_loaded = 0;
1678 chunk* newchunk = NULL;
1679 uint8_t* data = NULL;
1680
1681 TRACE("chunk %I64x\n", c->offset);
1682
1685 InitializeListHead(&metadata_items);
1686
1687 ExAcquireResourceExclusiveLite(&Vcb->tree_lock, true);
1688
1689 searchkey.obj_id = c->offset;
1690 searchkey.obj_type = TYPE_EXTENT_ITEM;
1691 searchkey.offset = 0xffffffffffffffff;
1692
1693 Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, false, NULL);
1694 if (!NT_SUCCESS(Status)) {
1695 ERR("find_item returned %08lx\n", Status);
1696 goto end;
1697 }
1698
1699 do {
1700 traverse_ptr next_tp;
1701
1702 if (tp.item->key.obj_id >= c->offset + c->chunk_item->size)
1703 break;
1704
1705 if (tp.item->key.obj_id >= c->offset && tp.item->key.obj_type == TYPE_EXTENT_ITEM) {
1706 bool tree = false;
1707
1708 if (tp.item->key.obj_type == TYPE_EXTENT_ITEM && tp.item->size >= sizeof(EXTENT_ITEM)) {
1710
1712 tree = true;
1713 }
1714
1715 if (!tree) {
1716 Status = add_data_reloc(Vcb, &items, &metadata_items, &tp, c, &rollback);
1717
1718 if (!NT_SUCCESS(Status)) {
1719 ERR("add_data_reloc returned %08lx\n", Status);
1720 goto end;
1721 }
1722
1723 loaded += tp.item->key.offset;
1724 num_loaded++;
1725
1726 if (loaded >= 0x1000000 || num_loaded >= 100) // only do so much at a time, so we don't block too obnoxiously
1727 break;
1728 }
1729 }
1730
1731 b = find_next_item(Vcb, &tp, &next_tp, false, NULL);
1732
1733 if (b)
1734 tp = next_tp;
1735 } while (b);
1736
1737 if (IsListEmpty(&items)) {
1738 *changed = false;
1740 goto end;
1741 } else
1742 *changed = true;
1743
1745 if (!data) {
1746 ERR("out of memory\n");
1748 goto end;
1749 }
1750
1751 le = items.Flink;
1752 while (le != &items) {
1754 bool done = false;
1755 LIST_ENTRY* le2;
1756 void* csum;
1758 ULONG* bmparr;
1759 ULONG bmplen, runlength, index, lastoff;
1760
1761 if (newchunk) {
1762 acquire_chunk_lock(newchunk, Vcb);
1763
1764 if (find_data_address_in_chunk(Vcb, newchunk, dr->size, &dr->new_address)) {
1765 newchunk->used += dr->size;
1766 space_list_subtract(newchunk, dr->new_address, dr->size, &rollback);
1767 done = true;
1768 }
1769
1770 release_chunk_lock(newchunk, Vcb);
1771 }
1772
1773 if (!done) {
1774 ExAcquireResourceExclusiveLite(&Vcb->chunk_lock, true);
1775
1776 le2 = Vcb->chunks.Flink;
1777 while (le2 != &Vcb->chunks) {
1779
1780 if (!c2->readonly && !c2->reloc && c2 != newchunk && c2->chunk_item->type == Vcb->data_flags) {
1782
1783 if ((c2->chunk_item->size - c2->used) >= dr->size) {
1784 if (find_data_address_in_chunk(Vcb, c2, dr->size, &dr->new_address)) {
1785 c2->used += dr->size;
1788 newchunk = c2;
1789 done = true;
1790 break;
1791 }
1792 }
1793
1795 }
1796
1797 le2 = le2->Flink;
1798 }
1799
1800 // allocate new chunk if necessary
1801 if (!done) {
1802 Status = alloc_chunk(Vcb, Vcb->data_flags, &newchunk, false);
1803
1804 if (!NT_SUCCESS(Status)) {
1805 ERR("alloc_chunk returned %08lx\n", Status);
1806 ExReleaseResourceLite(&Vcb->chunk_lock);
1807 goto end;
1808 }
1809
1810 acquire_chunk_lock(newchunk, Vcb);
1811
1812 newchunk->balance_num = Vcb->balance.balance_num;
1813
1814 if (!find_data_address_in_chunk(Vcb, newchunk, dr->size, &dr->new_address)) {
1815 release_chunk_lock(newchunk, Vcb);
1816 ExReleaseResourceLite(&Vcb->chunk_lock);
1817 ERR("could not find address in new chunk\n");
1819 goto end;
1820 } else {
1821 newchunk->used += dr->size;
1822 space_list_subtract(newchunk, dr->new_address, dr->size, &rollback);
1823 }
1824
1825 release_chunk_lock(newchunk, Vcb);
1826 }
1827
1828 ExReleaseResourceLite(&Vcb->chunk_lock);
1829 }
1830
1831 dr->newchunk = newchunk;
1832
1833 bmplen = (ULONG)(dr->size >> Vcb->sector_shift);
1834
1835 bmparr = ExAllocatePoolWithTag(PagedPool, (ULONG)sector_align(bmplen + 1, sizeof(ULONG)), ALLOC_TAG);
1836 if (!bmparr) {
1837 ERR("out of memory\n");
1839 goto end;
1840 }
1841
1842 csum = ExAllocatePoolWithTag(PagedPool, (ULONG)((dr->size * Vcb->csum_size) >> Vcb->sector_shift), ALLOC_TAG);
1843 if (!csum) {
1844 ERR("out of memory\n");
1845 ExFreePool(bmparr);
1847 goto end;
1848 }
1849
1850 RtlInitializeBitMap(&bmp, bmparr, bmplen);
1851 RtlSetAllBits(&bmp); // 1 = no csum, 0 = csum
1852
1853 searchkey.obj_id = EXTENT_CSUM_ID;
1854 searchkey.obj_type = TYPE_EXTENT_CSUM;
1855 searchkey.offset = dr->address;
1856
1857 Status = find_item(Vcb, Vcb->checksum_root, &tp, &searchkey, false, NULL);
1859 ERR("find_item returned %08lx\n", Status);
1861 ExFreePool(bmparr);
1862 goto end;
1863 }
1864
1865 if (Status != STATUS_NOT_FOUND) {
1866 do {
1867 traverse_ptr next_tp;
1868
1870 if (tp.item->key.offset >= dr->address + dr->size)
1871 break;
1872 else if (tp.item->size >= Vcb->csum_size && tp.item->key.offset + (((unsigned int)tp.item->size << Vcb->sector_shift) / Vcb->csum_size) >= dr->address) {
1874 uint64_t ce = min(dr->address + dr->size, tp.item->key.offset + (((unsigned int)tp.item->size << Vcb->sector_shift) / Vcb->csum_size));
1875
1876 RtlCopyMemory((uint8_t*)csum + (((cs - dr->address) * Vcb->csum_size) >> Vcb->sector_shift),
1877 tp.item->data + (((cs - tp.item->key.offset) * Vcb->csum_size) >> Vcb->sector_shift),
1878 (ULONG)(((ce - cs) * Vcb->csum_size) >> Vcb->sector_shift));
1879
1880 RtlClearBits(&bmp, (ULONG)((cs - dr->address) >> Vcb->sector_shift), (ULONG)((ce - cs) >> Vcb->sector_shift));
1881
1882 if (ce == dr->address + dr->size)
1883 break;
1884 }
1885 }
1886
1887 if (find_next_item(Vcb, &tp, &next_tp, false, NULL))
1888 tp = next_tp;
1889 else
1890 break;
1891 } while (true);
1892 }
1893
1894 lastoff = 0;
1895 runlength = RtlFindFirstRunClear(&bmp, &index);
1896
1897 while (runlength != 0) {
1898 if (index >= bmplen)
1899 break;
1900
1901 if (index + runlength >= bmplen) {
1902 runlength = bmplen - index;
1903
1904 if (runlength == 0)
1905 break;
1906 }
1907
1908 if (index > lastoff) {
1909 ULONG off = lastoff;
1910 ULONG size = index - lastoff;
1911
1912 // handle no csum run
1913 do {
1914 ULONG rl;
1915
1916 if (size << Vcb->sector_shift > BALANCE_UNIT)
1917 rl = BALANCE_UNIT >> Vcb->sector_shift;
1918 else
1919 rl = size;
1920
1921 Status = read_data(Vcb, dr->address + (off << Vcb->sector_shift), rl << Vcb->sector_shift, NULL, false, data,
1922 c, NULL, NULL, 0, false, NormalPagePriority);
1923 if (!NT_SUCCESS(Status)) {
1924 ERR("read_data returned %08lx\n", Status);
1926 ExFreePool(bmparr);
1927 goto end;
1928 }
1929
1930 Status = write_data_complete(Vcb, dr->new_address + (off << Vcb->sector_shift), data, rl << Vcb->sector_shift,
1931 NULL, newchunk, false, 0, NormalPagePriority);
1932 if (!NT_SUCCESS(Status)) {
1933 ERR("write_data_complete returned %08lx\n", Status);
1935 ExFreePool(bmparr);
1936 goto end;
1937 }
1938
1939 size -= rl;
1940 off += rl;
1941 } while (size > 0);
1942 }
1943
1944 add_checksum_entry(Vcb, dr->new_address + (index << Vcb->sector_shift), runlength, (uint8_t*)csum + (index * Vcb->csum_size), NULL);
1945 add_checksum_entry(Vcb, dr->address + (index << Vcb->sector_shift), runlength, NULL, NULL);
1946
1947 // handle csum run
1948 do {
1949 ULONG rl;
1950
1951 if (runlength << Vcb->sector_shift > BALANCE_UNIT)
1952 rl = BALANCE_UNIT >> Vcb->sector_shift;
1953 else
1954 rl = runlength;
1955
1956 Status = read_data(Vcb, dr->address + (index << Vcb->sector_shift), rl << Vcb->sector_shift,
1957 (uint8_t*)csum + (index * Vcb->csum_size), false, data, c, NULL, NULL, 0, false, NormalPagePriority);
1958 if (!NT_SUCCESS(Status)) {
1959 ERR("read_data returned %08lx\n", Status);
1961 ExFreePool(bmparr);
1962 goto end;
1963 }
1964
1965 Status = write_data_complete(Vcb, dr->new_address + (index << Vcb->sector_shift), data, rl << Vcb->sector_shift,
1966 NULL, newchunk, false, 0, NormalPagePriority);
1967 if (!NT_SUCCESS(Status)) {
1968 ERR("write_data_complete returned %08lx\n", Status);
1970 ExFreePool(bmparr);
1971 goto end;
1972 }
1973
1974 runlength -= rl;
1975 index += rl;
1976 } while (runlength > 0);
1977
1978 lastoff = index;
1979 runlength = RtlFindNextForwardRunClear(&bmp, index, &index);
1980 }
1981
1983 ExFreePool(bmparr);
1984
1985 // handle final nocsum run
1986 if (lastoff < dr->size >> Vcb->sector_shift) {
1987 ULONG off = lastoff;
1988 ULONG size = (ULONG)((dr->size >> Vcb->sector_shift) - lastoff);
1989
1990 do {
1991 ULONG rl;
1992
1993 if (size << Vcb->sector_shift > BALANCE_UNIT)
1994 rl = BALANCE_UNIT >> Vcb->sector_shift;
1995 else
1996 rl = size;
1997
1998 Status = read_data(Vcb, dr->address + (off << Vcb->sector_shift), rl << Vcb->sector_shift, NULL, false, data,
1999 c, NULL, NULL, 0, false, NormalPagePriority);
2000 if (!NT_SUCCESS(Status)) {
2001 ERR("read_data returned %08lx\n", Status);
2002 goto end;
2003 }
2004
2005 Status = write_data_complete(Vcb, dr->new_address + (off << Vcb->sector_shift), data, rl << Vcb->sector_shift,
2006 NULL, newchunk, false, 0, NormalPagePriority);
2007 if (!NT_SUCCESS(Status)) {
2008 ERR("write_data_complete returned %08lx\n", Status);
2009 goto end;
2010 }
2011
2012 size -= rl;
2013 off += rl;
2014 } while (size > 0);
2015 }
2016
2017 le = le->Flink;
2018 }
2019
2021 data = NULL;
2022
2023 Status = write_metadata_items(Vcb, &metadata_items, &items, NULL, &rollback);
2024 if (!NT_SUCCESS(Status)) {
2025 ERR("write_metadata_items returned %08lx\n", Status);
2026 goto end;
2027 }
2028
2029 le = items.Flink;
2030 while (le != &items) {
2032
2034 if (!NT_SUCCESS(Status)) {
2035 ERR("add_data_reloc_extent_item returned %08lx\n", Status);
2036 goto end;
2037 }
2038
2039 le = le->Flink;
2040 }
2041
2042 le = c->changed_extents.Flink;
2043 while (le != &c->changed_extents) {
2044 LIST_ENTRY *le2, *le3;
2046
2047 le3 = le->Flink;
2048
2049 le2 = items.Flink;
2050 while (le2 != &items) {
2052
2053 if (ce->address == dr->address) {
2054 ce->address = dr->new_address;
2057 break;
2058 }
2059
2060 le2 = le2->Flink;
2061 }
2062
2063 le = le3;
2064 }
2065
2067
2068 Vcb->need_write = true;
2069
2070end:
2071 if (NT_SUCCESS(Status)) {
2072 // update extents in cache inodes before we flush
2073 le = Vcb->chunks.Flink;
2074 while (le != &Vcb->chunks) {
2076
2077 if (c2->cache) {
2078 LIST_ENTRY* le2;
2079
2080 ExAcquireResourceExclusiveLite(c2->cache->Header.Resource, true);
2081
2082 le2 = c2->cache->extents.Flink;
2083 while (le2 != &c2->cache->extents) {
2085
2086 if (!ext->ignore) {
2087 if (ext->extent_data.type == EXTENT_TYPE_REGULAR || ext->extent_data.type == EXTENT_TYPE_PREALLOC) {
2088 EXTENT_DATA2* ed2 = (EXTENT_DATA2*)ext->extent_data.data;
2089
2090 if (ed2->size > 0 && ed2->address >= c->offset && ed2->address < c->offset + c->chunk_item->size) {
2091 LIST_ENTRY* le3 = items.Flink;
2092 while (le3 != &items) {
2094
2095 if (ed2->address == dr->address) {
2096 ed2->address = dr->new_address;
2097 break;
2098 }
2099
2100 le3 = le3->Flink;
2101 }
2102 }
2103 }
2104 }
2105
2106 le2 = le2->Flink;
2107 }
2108
2109 ExReleaseResourceLite(c2->cache->Header.Resource);
2110 }
2111
2112 le = le->Flink;
2113 }
2114
2115 Status = do_write(Vcb, NULL);
2116 if (!NT_SUCCESS(Status))
2117 ERR("do_write returned %08lx\n", Status);
2118 }
2119
2120 if (NT_SUCCESS(Status)) {
2122
2123 // update open FCBs
2124 // FIXME - speed this up(?)
2125
2126 le = Vcb->all_fcbs.Flink;
2127 while (le != &Vcb->all_fcbs) {
2128 struct _fcb* fcb = CONTAINING_RECORD(le, struct _fcb, list_entry_all);
2129 LIST_ENTRY* le2;
2130
2131 ExAcquireResourceExclusiveLite(fcb->Header.Resource, true);
2132
2133 le2 = fcb->extents.Flink;
2134 while (le2 != &fcb->extents) {
2136
2137 if (!ext->ignore) {
2138 if (ext->extent_data.type == EXTENT_TYPE_REGULAR || ext->extent_data.type == EXTENT_TYPE_PREALLOC) {
2139 EXTENT_DATA2* ed2 = (EXTENT_DATA2*)ext->extent_data.data;
2140
2141 if (ed2->size > 0 && ed2->address >= c->offset && ed2->address < c->offset + c->chunk_item->size) {
2142 LIST_ENTRY* le3 = items.Flink;
2143 while (le3 != &items) {
2145
2146 if (ed2->address == dr->address) {
2147 ed2->address = dr->new_address;
2148 break;
2149 }
2150
2151 le3 = le3->Flink;
2152 }
2153 }
2154 }
2155 }
2156
2157 le2 = le2->Flink;
2158 }
2159
2160 ExReleaseResourceLite(fcb->Header.Resource);
2161
2162 le = le->Flink;
2163 }
2164 } else
2166
2167 free_trees(Vcb);
2168
2169 ExReleaseResourceLite(&Vcb->tree_lock);
2170
2171 if (data)
2173
2174 while (!IsListEmpty(&items)) {
2176
2177 while (!IsListEmpty(&dr->refs)) {
2179
2180 ExFreePool(ref);
2181 }
2182
2183 ExFreePool(dr);
2184 }
2185
2186 while (!IsListEmpty(&metadata_items)) {
2188
2189 while (!IsListEmpty(&mr->refs)) {
2191
2192 ExFreePool(ref);
2193 }
2194
2195 if (mr->data)
2196 ExFreePool(mr->data);
2197
2198 ExFreePool(mr);
2199 }
2200
2201 return Status;
2202}
#define index(s, c)
Definition: various.h:29
NTSTATUS bool find_data_address_in_chunk(device_extension *Vcb, chunk *c, uint64_t length, uint64_t *address) __attribute__((nonnull(1
void do_rollback(device_extension *Vcb, LIST_ENTRY *rollback) __attribute__((nonnull(1
NTSTATUS NTSTATUS NTSTATUS write_data_complete(device_extension *Vcb, uint64_t address, void *data, uint32_t length, PIRP Irp, chunk *c, bool file_write, uint64_t irp_offset, ULONG priority) __attribute__((nonnull(1
NTSTATUS NTSTATUS void clear_rollback(LIST_ENTRY *rollback) __attribute__((nonnull(1)))
void space_list_subtract(chunk *c, uint64_t address, uint64_t length, LIST_ENTRY *rollback)
Definition: free-space.c:2234
void add_checksum_entry(device_extension *Vcb, uint64_t address, ULONG length, void *csum, PIRP Irp)
Definition: flushthread.c:2602
static uint64_t __inline sector_align(uint64_t n, uint64_t a)
static const WCHAR *const ext[]
Definition: module.c:53
static NTSTATUS write_metadata_items(_Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension *Vcb, LIST_ENTRY *items, LIST_ENTRY *data_items, chunk *c, LIST_ENTRY *rollback)
Definition: balance.c:566
#define BALANCE_UNIT
Definition: balance.c:71
static NTSTATUS add_data_reloc(_Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension *Vcb, LIST_ENTRY *items, LIST_ENTRY *metadata_items, traverse_ptr *tp, chunk *c, LIST_ENTRY *rollback)
Definition: balance.c:1316
static NTSTATUS add_data_reloc_extent_item(_Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension *Vcb, data_reloc *dr)
Definition: balance.c:1541
#define EXTENT_CSUM_ID
Definition: btrfs.h:91
#define TYPE_EXTENT_CSUM
Definition: btrfs.h:31
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
GLsizeiptr size
Definition: glext.h:5919
GLuint index
Definition: glext.h:6031
GLboolean GLboolean GLboolean b
Definition: glext.h:6204
#define cs
Definition: i386-dis.c:442
NTSYSAPI void WINAPI RtlInitializeBitMap(PRTL_BITMAP, PULONG, ULONG)
NTSYSAPI void WINAPI RtlSetAllBits(PRTL_BITMAP)
NTSYSAPI void WINAPI RtlClearBits(PRTL_BITMAP, ULONG, ULONG)
NTSYSAPI ULONG WINAPI RtlFindNextForwardRunClear(PCRTL_BITMAP, ULONG, PULONG)
#define b
Definition: ke_i.h:79
@ NormalPagePriority
Definition: imports.h:56
BITMAP bmp
Definition: alphablend.c:62
BOOL loaded
Definition: xmlview.c:54
#define min(a, b)
Definition: monoChain.cc:55
#define STATUS_NOT_FOUND
Definition: shellext.h:72
#define TRACE(s)
Definition: solgame.cpp:4
uint64_t size
Definition: btrfs.h:340
uint64_t type
Definition: btrfs.h:343
LIST_ENTRY list_entry_all
Definition: btrfs_drv.h:337
LIST_ENTRY extents
Definition: btrfs_drv.h:300
FSRTL_ADVANCED_FCB_HEADER Header
Definition: btrfs_drv.h:283
LIST_ENTRY list_entry
Definition: btrfs_drv.h:606
bool readonly
Definition: btrfs_drv.h:580
bool reloc
Definition: btrfs_drv.h:581
uint64_t used
Definition: btrfs_drv.h:565
fcb * cache
Definition: btrfs_drv.h:568
ULONG balance_num
Definition: btrfs_drv.h:590
LIST_ENTRY changed_extents
Definition: btrfs_drv.h:573
CHUNK_ITEM * chunk_item
Definition: btrfs_drv.h:562
Definition: ffs.h:52
chunk * newchunk
Definition: balance.c:52
#define max(a, b)
Definition: svc.c:63
NTSYSAPI ULONG NTAPI RtlFindFirstRunClear(_In_ PRTL_BITMAP BitMapHeader, _Out_ PULONG StartingIndex)

Referenced by _Function_class_(), and try_consolidation().

◆ balance_metadata_chunk()

static NTSTATUS balance_metadata_chunk ( device_extension Vcb,
chunk c,
bool changed 
)
static

Definition at line 1100 of file balance.c.

1100 {
1101 KEY searchkey;
1104 bool b;
1106 uint32_t loaded = 0;
1107
1108 TRACE("chunk %I64x\n", c->offset);
1109
1112
1113 ExAcquireResourceExclusiveLite(&Vcb->tree_lock, true);
1114
1115 searchkey.obj_id = c->offset;
1116 searchkey.obj_type = TYPE_METADATA_ITEM;
1117 searchkey.offset = 0xffffffffffffffff;
1118
1119 Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, false, NULL);
1120 if (!NT_SUCCESS(Status)) {
1121 ERR("find_item returned %08lx\n", Status);
1122 goto end;
1123 }
1124
1125 do {
1126 traverse_ptr next_tp;
1127
1128 if (tp.item->key.obj_id >= c->offset + c->chunk_item->size)
1129 break;
1130
1132 bool tree = false, skinny = false;
1133
1134 if (tp.item->key.obj_type == TYPE_METADATA_ITEM && tp.item->size >= sizeof(EXTENT_ITEM)) {
1135 tree = true;
1136 skinny = true;
1137 } else if (tp.item->key.obj_type == TYPE_EXTENT_ITEM && tp.item->key.offset == Vcb->superblock.node_size &&
1138 tp.item->size >= sizeof(EXTENT_ITEM)) {
1140
1142 tree = true;
1143 }
1144
1145 if (tree) {
1146 Status = add_metadata_reloc(Vcb, &items, &tp, skinny, NULL, c, &rollback);
1147
1148 if (!NT_SUCCESS(Status)) {
1149 ERR("add_metadata_reloc returned %08lx\n", Status);
1150 goto end;
1151 }
1152
1153 loaded++;
1154
1155 if (loaded >= 64) // only do 64 at a time
1156 break;
1157 }
1158 }
1159
1160 b = find_next_item(Vcb, &tp, &next_tp, false, NULL);
1161
1162 if (b)
1163 tp = next_tp;
1164 } while (b);
1165
1166 if (IsListEmpty(&items)) {
1167 *changed = false;
1169 goto end;
1170 } else
1171 *changed = true;
1172
1174 if (!NT_SUCCESS(Status)) {
1175 ERR("write_metadata_items returned %08lx\n", Status);
1176 goto end;
1177 }
1178
1180
1181 Vcb->need_write = true;
1182
1183end:
1184 if (NT_SUCCESS(Status)) {
1185 Status = do_write(Vcb, NULL);
1186 if (!NT_SUCCESS(Status))
1187 ERR("do_write returned %08lx\n", Status);
1188 }
1189
1190 if (NT_SUCCESS(Status))
1192 else
1194
1195 free_trees(Vcb);
1196
1197 ExReleaseResourceLite(&Vcb->tree_lock);
1198
1199 while (!IsListEmpty(&items)) {
1201
1202 while (!IsListEmpty(&mr->refs)) {
1204
1205 ExFreePool(ref);
1206 }
1207
1208 if (mr->data)
1209 ExFreePool(mr->data);
1210
1211 ExFreePool(mr);
1212 }
1213
1214 return Status;
1215}

Referenced by _Function_class_().

◆ copy_balance_args()

static void copy_balance_args ( btrfs_balance_opts opts,
BALANCE_ARGS args 
)
static

Definition at line 2318 of file balance.c.

2318 {
2319 if (opts->flags & BTRFS_BALANCE_OPTS_PROFILES) {
2320 args->profiles = opts->profiles;
2322 }
2323
2324 if (opts->flags & BTRFS_BALANCE_OPTS_USAGE) {
2325 if (args->usage_start == 0) {
2327 args->usage_start = opts->usage_start;
2328 args->usage_end = opts->usage_end;
2329 } else {
2331 args->usage = opts->usage_end;
2332 }
2333 }
2334
2335 if (opts->flags & BTRFS_BALANCE_OPTS_DEVID) {
2336 args->devid = opts->devid;
2338 }
2339
2340 if (opts->flags & BTRFS_BALANCE_OPTS_DRANGE) {
2341 args->drange_start = opts->drange_start;
2342 args->drange_end = opts->drange_end;
2344 }
2345
2346 if (opts->flags & BTRFS_BALANCE_OPTS_VRANGE) {
2347 args->vrange_start = opts->vrange_start;
2348 args->vrange_end = opts->vrange_end;
2350 }
2351
2352 if (opts->flags & BTRFS_BALANCE_OPTS_CONVERT) {
2353 args->convert = opts->convert;
2355
2356 if (opts->flags & BTRFS_BALANCE_OPTS_SOFT)
2357 args->flags |= BALANCE_ARGS_FLAGS_SOFT;
2358 }
2359
2360 if (opts->flags & BTRFS_BALANCE_OPTS_LIMIT) {
2361 if (args->limit_start == 0) {
2363 args->limit_start = (uint32_t)opts->limit_start;
2364 args->limit_end = (uint32_t)opts->limit_end;
2365 } else {
2367 args->limit = opts->limit_end;
2368 }
2369 }
2370
2371 if (opts->flags & BTRFS_BALANCE_OPTS_STRIPES) {
2372 args->stripes_start = opts->stripes_start;
2373 args->stripes_end = opts->stripes_end;
2375 }
2376}
#define BTRFS_BALANCE_OPTS_DRANGE
Definition: btrfsioctl.h:133
#define BTRFS_BALANCE_OPTS_SOFT
Definition: btrfsioctl.h:139
#define BTRFS_BALANCE_OPTS_PROFILES
Definition: btrfsioctl.h:131
#define BTRFS_BALANCE_OPTS_VRANGE
Definition: btrfsioctl.h:134
#define BTRFS_BALANCE_OPTS_DEVID
Definition: btrfsioctl.h:132
#define BTRFS_BALANCE_OPTS_USAGE
Definition: btrfsioctl.h:137
#define BTRFS_BALANCE_OPTS_STRIPES
Definition: btrfsioctl.h:136
#define BALANCE_ARGS_FLAGS_LIMIT
Definition: btrfs.h:485
#define BALANCE_ARGS_FLAGS_CONVERT
Definition: btrfs.h:488
#define BALANCE_ARGS_FLAGS_LIMIT_RANGE
Definition: btrfs.h:486
#define BALANCE_ARGS_FLAGS_PROFILES
Definition: btrfs.h:480
#define BALANCE_ARGS_FLAGS_STRIPES_RANGE
Definition: btrfs.h:487
#define BALANCE_ARGS_FLAGS_SOFT
Definition: btrfs.h:489
#define BALANCE_ARGS_FLAGS_DRANGE
Definition: btrfs.h:483
#define BALANCE_ARGS_FLAGS_USAGE_RANGE
Definition: btrfs.h:490
#define BALANCE_ARGS_FLAGS_VRANGE
Definition: btrfs.h:484
#define BALANCE_ARGS_FLAGS_DEVID
Definition: btrfs.h:482
#define BALANCE_ARGS_FLAGS_USAGE
Definition: btrfs.h:481
#define uint32_t
Definition: nsiface.idl:61
Definition: match.c:390
uint16_t stripes_start
Definition: btrfsioctl.h:153
uint64_t drange_start
Definition: btrfsioctl.h:147
uint64_t drange_end
Definition: btrfsioctl.h:148
uint64_t limit_start
Definition: btrfsioctl.h:151
uint64_t vrange_start
Definition: btrfsioctl.h:149
uint64_t limit_end
Definition: btrfsioctl.h:152
uint16_t stripes_end
Definition: btrfsioctl.h:154
uint64_t vrange_end
Definition: btrfsioctl.h:150

Referenced by add_balance_item().

◆ data_reloc_add_tree_edr()

static NTSTATUS data_reloc_add_tree_edr ( _Requires_lock_held_(_Curr_->tree_lock) device_extension Vcb,
LIST_ENTRY metadata_items,
data_reloc dr,
EXTENT_DATA_REF edr,
LIST_ENTRY rollback 
)
static

Definition at line 1217 of file balance.c.

1218 {
1220 LIST_ENTRY* le;
1221 KEY searchkey;
1223 root* r = NULL;
1224 metadata_reloc* mr;
1225 uint64_t last_tree = 0;
1227
1228 le = Vcb->roots.Flink;
1229 while (le != &Vcb->roots) {
1231
1232 if (r2->id == edr->root) {
1233 r = r2;
1234 break;
1235 }
1236
1237 le = le->Flink;
1238 }
1239
1240 if (!r) {
1241 ERR("could not find subvol %I64x\n", edr->root);
1242 return STATUS_INTERNAL_ERROR;
1243 }
1244
1245 searchkey.obj_id = edr->objid;
1246 searchkey.obj_type = TYPE_EXTENT_DATA;
1247 searchkey.offset = 0;
1248
1249 Status = find_item(Vcb, r, &tp, &searchkey, false, NULL);
1250 if (!NT_SUCCESS(Status)) {
1251 ERR("find_item returned %08lx\n", Status);
1252 return Status;
1253 }
1254
1255 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)) {
1256 traverse_ptr tp2;
1257
1258 if (find_next_item(Vcb, &tp, &tp2, false, NULL))
1259 tp = tp2;
1260 else {
1261 ERR("could not find EXTENT_DATA for inode %I64x in root %I64x\n", searchkey.obj_id, r->id);
1262 return STATUS_INTERNAL_ERROR;
1263 }
1264 }
1265
1266 ref = NULL;
1267
1268 while (tp.item->key.obj_id == searchkey.obj_id && tp.item->key.obj_type == searchkey.obj_type) {
1269 traverse_ptr tp2;
1270
1271 if (tp.item->size >= sizeof(EXTENT_DATA)) {
1273
1275 EXTENT_DATA2* ed2 = (EXTENT_DATA2*)ed->data;
1276
1277 if (ed2->address == dr->address && ed2->size == dr->size && tp.item->key.offset - ed2->offset == edr->offset) {
1278 if (ref && last_tree == tp.tree->header.address)
1279 ref->edr.count++;
1280 else {
1282 if (!ref) {
1283 ERR("out of memory\n");
1285 }
1286
1287 ref->type = TYPE_EXTENT_DATA_REF;
1288 RtlCopyMemory(&ref->edr, edr, sizeof(EXTENT_DATA_REF));
1289 ref->edr.count = 1;
1290
1291 Status = add_metadata_reloc_parent(Vcb, metadata_items, tp.tree->header.address, &mr, rollback);
1292 if (!NT_SUCCESS(Status)) {
1293 ERR("add_metadata_reloc_parent returned %08lx\n", Status);
1294 ExFreePool(ref);
1295 return Status;
1296 }
1297
1298 last_tree = tp.tree->header.address;
1299 ref->parent = mr;
1300
1302 }
1303 }
1304 }
1305 }
1306
1307 if (find_next_item(Vcb, &tp, &tp2, false, NULL))
1308 tp = tp2;
1309 else
1310 break;
1311 }
1312
1313 return STATUS_SUCCESS;
1314}
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
static DNS_RECORDW r2
Definition: record.c:38
#define offsetof(TYPE, MEMBER)
uint64_t offset
Definition: btrfs.h:370
uint64_t offset
Definition: btrfs.h:419
uint64_t root
Definition: btrfs.h:417
uint64_t objid
Definition: btrfs.h:418
tree_header header
Definition: btrfs_drv.h:426
tree * tree
Definition: btrfs_drv.h:508
uint64_t address
Definition: btrfs.h:156

Referenced by add_data_reloc().

◆ finish_removing_device()

static NTSTATUS finish_removing_device ( _Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension Vcb,
device dev 
)
static

Definition at line 2586 of file balance.c.

2586 {
2587 KEY searchkey;
2590 LIST_ENTRY* le;
2592
2593 if (Vcb->need_write) {
2594 Status = do_write(Vcb, NULL);
2595
2596 if (!NT_SUCCESS(Status))
2597 ERR("do_write returned %08lx\n", Status);
2598 } else
2600
2601 free_trees(Vcb);
2602
2603 if (!NT_SUCCESS(Status))
2604 return Status;
2605
2606 // remove entry in chunk tree
2607
2608 searchkey.obj_id = 1;
2609 searchkey.obj_type = TYPE_DEV_ITEM;
2610 searchkey.offset = dev->devitem.dev_id;
2611
2612 Status = find_item(Vcb, Vcb->chunk_root, &tp, &searchkey, false, NULL);
2613 if (!NT_SUCCESS(Status)) {
2614 ERR("find_item returned %08lx\n", Status);
2615 return Status;
2616 }
2617
2618 if (!keycmp(searchkey, tp.item->key)) {
2620
2621 if (!NT_SUCCESS(Status)) {
2622 ERR("delete_tree_item returned %08lx\n", Status);
2623 return Status;
2624 }
2625 }
2626
2627 // remove stats entry in device tree
2628
2629 searchkey.obj_id = 0;
2630 searchkey.obj_type = TYPE_DEV_STATS;
2631 searchkey.offset = dev->devitem.dev_id;
2632
2633 Status = find_item(Vcb, Vcb->dev_root, &tp, &searchkey, false, NULL);
2634 if (!NT_SUCCESS(Status)) {
2635 ERR("find_item returned %08lx\n", Status);
2636 return Status;
2637 }
2638
2639 if (!keycmp(searchkey, tp.item->key)) {
2641
2642 if (!NT_SUCCESS(Status)) {
2643 ERR("delete_tree_item returned %08lx\n", Status);
2644 return Status;
2645 }
2646 }
2647
2648 // update superblock
2649
2650 Vcb->superblock.num_devices--;
2651 Vcb->superblock.total_bytes -= dev->devitem.num_bytes;
2652 Vcb->devices_loaded--;
2653
2654 RemoveEntryList(&dev->list_entry);
2655
2656 // flush
2657
2658 Status = do_write(Vcb, NULL);
2659 if (!NT_SUCCESS(Status))
2660 ERR("do_write returned %08lx\n", Status);
2661
2662 free_trees(Vcb);
2663
2664 if (!NT_SUCCESS(Status))
2665 return Status;
2666
2667 if (!dev->readonly && dev->devobj) {
2669 if (!NT_SUCCESS(Status))
2670 WARN("remove_superblocks returned %08lx\n", Status);
2671 }
2672
2673 // remove entry in volume list
2674
2675 vde = Vcb->vde;
2676
2677 if (dev->devobj) {
2678 pdo_device_extension* pdode = vde->pdode;
2679
2681
2682 le = pdode->children.Flink;
2683 while (le != &pdode->children) {
2685
2686 if (RtlCompareMemory(&dev->devitem.device_uuid, &vc->uuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID)) {
2689 UNICODE_STRING mmdevpath;
2690
2691 pdode->children_loaded--;
2692
2693 if (vc->had_drive_letter) { // re-add entry to mountmgr
2696 if (!NT_SUCCESS(Status))
2697 ERR("IoGetDeviceObjectPointer returned %08lx\n", Status);
2698 else {
2699 MOUNTDEV_NAME mdn;
2700
2701 Status = dev_ioctl(dev->devobj, IOCTL_MOUNTDEV_QUERY_DEVICE_NAME, NULL, 0, &mdn, sizeof(MOUNTDEV_NAME), true, NULL);
2703 ERR("IOCTL_MOUNTDEV_QUERY_DEVICE_NAME returned %08lx\n", Status);
2704 else {
2705 MOUNTDEV_NAME* mdn2;
2706 ULONG mdnsize = (ULONG)offsetof(MOUNTDEV_NAME, Name[0]) + mdn.NameLength;
2707
2708 mdn2 = ExAllocatePoolWithTag(PagedPool, mdnsize, ALLOC_TAG);
2709 if (!mdn2)
2710 ERR("out of memory\n");
2711 else {
2712 Status = dev_ioctl(dev->devobj, IOCTL_MOUNTDEV_QUERY_DEVICE_NAME, NULL, 0, mdn2, mdnsize, true, NULL);
2713 if (!NT_SUCCESS(Status))
2714 ERR("IOCTL_MOUNTDEV_QUERY_DEVICE_NAME returned %08lx\n", Status);
2715 else {
2717
2718 name.Buffer = mdn2->Name;
2719 name.Length = name.MaximumLength = mdn2->NameLength;
2720
2722 if (!NT_SUCCESS(Status))
2723 WARN("mountmgr_add_drive_letter returned %08lx\n", Status);
2724 }
2725
2726 ExFreePool(mdn2);
2727 }
2728 }
2729
2731 }
2732 }
2733
2736 ExFreePool(vc);
2737
2739
2740 break;
2741 }
2742
2743 le = le->Flink;
2744 }
2745
2746 if (pdode->children_loaded > 0 && vde->device->Characteristics & FILE_REMOVABLE_MEDIA) {
2747 vde->device->Characteristics &= ~FILE_REMOVABLE_MEDIA;
2748
2749 le = pdode->children.Flink;
2750 while (le != &pdode->children) {
2752
2753 if (vc->devobj->Characteristics & FILE_REMOVABLE_MEDIA) {
2754 vde->device->Characteristics |= FILE_REMOVABLE_MEDIA;
2755 break;
2756 }
2757
2758 le = le->Flink;
2759 }
2760 }
2761
2762 pdode->num_children = Vcb->superblock.num_devices;
2763
2765
2766 // free dev
2767
2768 if (dev->trim && !dev->readonly && !Vcb->options.no_trim)
2770 }
2771
2772 while (!IsListEmpty(&dev->space)) {
2773 LIST_ENTRY* le2 = RemoveHeadList(&dev->space);
2775
2776 ExFreePool(s);
2777 }
2778
2779 ExFreePool(dev);
2780
2781 if (Vcb->trim) {
2782 Vcb->trim = false;
2783
2784 le = Vcb->devices.Flink;
2785 while (le != &Vcb->devices) {
2787
2788 if (dev2->trim) {
2789 Vcb->trim = true;
2790 break;
2791 }
2792
2793 le = le->Flink;
2794 }
2795 }
2796
2798
2799 return STATUS_SUCCESS;
2800}
NTSTATUS mountmgr_add_drive_letter(PDEVICE_OBJECT mountmgr, PUNICODE_STRING devpath)
Definition: volume.c:832
void trim_whole_device(device *dev)
Definition: fsctl.c:2716
static NTSTATUS remove_superblocks(device *dev)
Definition: balance.c:2557
NTSTATUS dev_ioctl(_In_ PDEVICE_OBJECT DeviceObject, _In_ ULONG ControlCode, _In_reads_bytes_opt_(InputBufferSize) PVOID InputBuffer, _In_ ULONG InputBufferSize, _Out_writes_bytes_opt_(OutputBufferSize) PVOID OutputBuffer, _In_ ULONG OutputBufferSize, _In_ bool Override, _Out_opt_ IO_STATUS_BLOCK *iosb)
Definition: btrfs.c:2954
#define TYPE_DEV_ITEM
Definition: btrfs.h:47
#define TYPE_DEV_STATS
Definition: btrfs.h:50
#define RtlCompareMemory(s1, s2, l)
Definition: env_spec_w32.h:465
GLdouble s
Definition: gl.h:2039
#define IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
Definition: imports.h:93
#define MOUNTMGR_DEVICE_NAME
Definition: imports.h:76
#define FILE_READ_ATTRIBUTES
Definition: nt_native.h:647
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
#define FILE_REMOVABLE_MEDIA
Definition: nt_native.h:807
NTSTATUS NTAPI IoGetDeviceObjectPointer(IN PUNICODE_STRING ObjectName, IN ACCESS_MASK DesiredAccess, OUT PFILE_OBJECT *FileObject, OUT PDEVICE_OBJECT *DeviceObject)
Definition: device.c:1435
#define STATUS_BUFFER_OVERFLOW
Definition: shellext.h:66
USHORT NameLength
Definition: imports.h:143
WCHAR Name[1]
Definition: imports.h:144
struct pdo_device_extension * pdode
Definition: btrfs_drv.h:878
PDEVICE_OBJECT device
Definition: btrfs_drv.h:875
uint64_t dev_id
Definition: name.c:39
ERESOURCE child_lock
Definition: btrfs_drv.h:896
uint64_t children_loaded
Definition: btrfs_drv.h:895
LIST_ENTRY children
Definition: btrfs_drv.h:897
uint64_t num_children
Definition: btrfs_drv.h:894
LIST_ENTRY list_entry
Definition: btrfs_drv.h:867
PFILE_OBJECT fileobj
Definition: btrfs_drv.h:858
UNICODE_STRING pnp_name
Definition: btrfs_drv.h:859
PDEVICE_OBJECT devobj
Definition: btrfs_drv.h:857
bool had_drive_letter
Definition: btrfs_drv.h:862
BTRFS_UUID uuid
Definition: btrfs_drv.h:854
_In_ WDFREQUEST _In_ WDFFILEOBJECT FileObject
Definition: wdfdevice.h:550
* PFILE_OBJECT
Definition: iotypes.h:1998
#define ObDereferenceObject
Definition: obfuncs.h:203

Referenced by _Function_class_().

◆ get_chunk_dup_type()

static __inline uint64_t get_chunk_dup_type ( chunk c)
static

Definition at line 2204 of file balance.c.

2204 {
2205 if (c->chunk_item->type & BLOCK_FLAG_RAID0)
2206 return BLOCK_FLAG_RAID0;
2207 else if (c->chunk_item->type & BLOCK_FLAG_RAID1)
2208 return BLOCK_FLAG_RAID1;
2209 else if (c->chunk_item->type & BLOCK_FLAG_DUPLICATE)
2210 return BLOCK_FLAG_DUPLICATE;
2211 else if (c->chunk_item->type & BLOCK_FLAG_RAID10)
2212 return BLOCK_FLAG_RAID10;
2213 else if (c->chunk_item->type & BLOCK_FLAG_RAID5)
2214 return BLOCK_FLAG_RAID5;
2215 else if (c->chunk_item->type & BLOCK_FLAG_RAID6)
2216 return BLOCK_FLAG_RAID6;
2217 else if (c->chunk_item->type & BLOCK_FLAG_RAID1C3)
2218 return BLOCK_FLAG_RAID1C3;
2219 else if (c->chunk_item->type & BLOCK_FLAG_RAID1C4)
2220 return BLOCK_FLAG_RAID1C4;
2221 else
2222 return BLOCK_FLAG_SINGLE;
2223}
#define BLOCK_FLAG_RAID1C4
Definition: btrfs.h:88
#define BLOCK_FLAG_RAID1C3
Definition: btrfs.h:87
#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_RAID1
Definition: shellext.h:79

Referenced by should_balance_chunk().

◆ load_balance_args()

static void load_balance_args ( btrfs_balance_opts opts,
BALANCE_ARGS args 
)
static

Definition at line 2492 of file balance.c.

2492 {
2494
2495 if (args->flags & BALANCE_ARGS_FLAGS_PROFILES) {
2497 opts->profiles = args->profiles;
2498 }
2499
2500 if (args->flags & BALANCE_ARGS_FLAGS_USAGE) {
2502
2503 opts->usage_start = 0;
2504 opts->usage_end = (uint8_t)args->usage;
2505 } else if (args->flags & BALANCE_ARGS_FLAGS_USAGE_RANGE) {
2507
2508 opts->usage_start = (uint8_t)args->usage_start;
2509 opts->usage_end = (uint8_t)args->usage_end;
2510 }
2511
2512 if (args->flags & BALANCE_ARGS_FLAGS_DEVID) {
2514 opts->devid = args->devid;
2515 }
2516
2517 if (args->flags & BALANCE_ARGS_FLAGS_DRANGE) {
2519 opts->drange_start = args->drange_start;
2520 opts->drange_end = args->drange_end;
2521 }
2522
2523 if (args->flags & BALANCE_ARGS_FLAGS_VRANGE) {
2525 opts->vrange_start = args->vrange_start;
2526 opts->vrange_end = args->vrange_end;
2527 }
2528
2529 if (args->flags & BALANCE_ARGS_FLAGS_LIMIT) {
2531
2532 opts->limit_start = 0;
2533 opts->limit_end = args->limit;
2534 } else if (args->flags & BALANCE_ARGS_FLAGS_LIMIT_RANGE) {
2536
2537 opts->limit_start = args->limit_start;
2538 opts->limit_end = args->limit_end;
2539 }
2540
2543
2544 opts->stripes_start = (uint16_t)args->stripes_start;
2545 opts->stripes_end = (uint16_t)args->stripes_end;
2546 }
2547
2548 if (args->flags & BALANCE_ARGS_FLAGS_CONVERT) {
2550 opts->convert = args->convert;
2551
2552 if (args->flags & BALANCE_ARGS_FLAGS_SOFT)
2554 }
2555}
#define uint16_t
Definition: nsiface.idl:60

Referenced by look_for_balance_item().

◆ look_for_balance_item()

NTSTATUS look_for_balance_item ( _Requires_lock_held_(_Curr_->tree_lock) device_extension Vcb)

Definition at line 3628 of file balance.c.

3628 {
3629 KEY searchkey;
3632 BALANCE_ITEM* bi;
3634 int i;
3635
3636 searchkey.obj_id = BALANCE_ITEM_ID;
3637 searchkey.obj_type = TYPE_TEMP_ITEM;
3638 searchkey.offset = 0;
3639
3640 Status = find_item(Vcb, Vcb->root_root, &tp, &searchkey, false, NULL);
3641 if (!NT_SUCCESS(Status)) {
3642 ERR("find_item returned %08lx\n", Status);
3643 return Status;
3644 }
3645
3646 if (keycmp(tp.item->key, searchkey)) {
3647 TRACE("no balance item found\n");
3648 return STATUS_NOT_FOUND;
3649 }
3650
3651 if (tp.item->size < sizeof(BALANCE_ITEM)) {
3652 WARN("(%I64x,%x,%I64x) was %u bytes, expected %Iu\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset,
3653 tp.item->size, sizeof(BALANCE_ITEM));
3654 return STATUS_INTERNAL_ERROR;
3655 }
3656
3657 bi = (BALANCE_ITEM*)tp.item->data;
3658
3660 load_balance_args(&Vcb->balance.opts[BALANCE_OPTS_DATA], &bi->data);
3661
3662 if (bi->flags & BALANCE_FLAGS_METADATA)
3663 load_balance_args(&Vcb->balance.opts[BALANCE_OPTS_METADATA], &bi->metadata);
3664
3665 if (bi->flags & BALANCE_FLAGS_SYSTEM)
3666 load_balance_args(&Vcb->balance.opts[BALANCE_OPTS_SYSTEM], &bi->system);
3667
3668 // do the heuristics that Linux driver does
3669
3670 for (i = 0; i < 3; i++) {
3671 if (Vcb->balance.opts[i].flags & BTRFS_BALANCE_OPTS_ENABLED) {
3672 // if converting, don't redo chunks already done
3673
3674 if (Vcb->balance.opts[i].flags & BTRFS_BALANCE_OPTS_CONVERT)
3675 Vcb->balance.opts[i].flags |= BTRFS_BALANCE_OPTS_SOFT;
3676
3677 // don't balance chunks more than 90% filled - presumably these
3678 // have already been done
3679
3680 if (!(Vcb->balance.opts[i].flags & BTRFS_BALANCE_OPTS_USAGE) &&
3681 !(Vcb->balance.opts[i].flags & BTRFS_BALANCE_OPTS_CONVERT)
3682 ) {
3683 Vcb->balance.opts[i].flags |= BTRFS_BALANCE_OPTS_USAGE;
3684 Vcb->balance.opts[i].usage_start = 0;
3685 Vcb->balance.opts[i].usage_end = 90;
3686 }
3687 }
3688 }
3689
3690 if (Vcb->readonly || Vcb->options.skip_balance)
3691 Vcb->balance.paused = true;
3692 else
3693 Vcb->balance.paused = false;
3694
3695 Vcb->balance.removing = false;
3696 Vcb->balance.shrinking = false;
3697 Vcb->balance.status = STATUS_SUCCESS;
3698 KeInitializeEvent(&Vcb->balance.event, NotificationEvent, !Vcb->balance.paused);
3699
3701
3702 Status = PsCreateSystemThread(&Vcb->balance.thread, 0, &oa, NULL, NULL, balance_thread, Vcb);
3703 if (!NT_SUCCESS(Status)) {
3704 ERR("PsCreateSystemThread returned %08lx\n", Status);
3705 return Status;
3706 }
3707
3708 return STATUS_SUCCESS;
3709}
static void load_balance_args(btrfs_balance_opts *opts, BALANCE_ARGS *args)
Definition: balance.c:2492
#define OBJ_KERNEL_HANDLE
Definition: winternl.h:231
#define InitializeObjectAttributes(p, n, a, r, s)
Definition: reg.c:106
NTSTATUS NTAPI PsCreateSystemThread(OUT PHANDLE ThreadHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, IN HANDLE ProcessHandle, IN PCLIENT_ID ClientId, IN PKSTART_ROUTINE StartRoutine, IN PVOID StartContext)
Definition: thread.c:602

Referenced by mount_vol().

◆ pause_balance()

NTSTATUS pause_balance ( device_extension Vcb,
KPROCESSOR_MODE  processor_mode 
)

Definition at line 3749 of file balance.c.

3749 {
3750 if (!SeSinglePrivilegeCheck(RtlConvertLongToLuid(SE_MANAGE_VOLUME_PRIVILEGE), processor_mode))
3752
3753 if (!Vcb->balance.thread)
3755
3756 if (Vcb->balance.paused)
3758
3759 Vcb->balance.paused = true;
3760 KeClearEvent(&Vcb->balance.event);
3761
3762 return STATUS_SUCCESS;
3763}
#define STATUS_PRIVILEGE_NOT_HELD
Definition: DriverTester.h:9
VOID NTAPI KeClearEvent(IN PKEVENT Event)
Definition: eventobj.c:22
#define SE_MANAGE_VOLUME_PRIVILEGE
Definition: security.c:682
BOOLEAN NTAPI SeSinglePrivilegeCheck(_In_ LUID PrivilegeValue, _In_ KPROCESSOR_MODE PreviousMode)
Checks if a single privilege is present in the context of the calling thread.
Definition: priv.c:744
#define STATUS_DEVICE_NOT_READY
Definition: shellext.h:70

Referenced by fsctl_request().

◆ query_balance()

NTSTATUS query_balance ( device_extension Vcb,
void data,
ULONG  length 
)

Definition at line 3711 of file balance.c.

3711 {
3713
3714 if (length < sizeof(btrfs_query_balance) || !data)
3716
3717 if (!Vcb->balance.thread) {
3719
3720 if (!NT_SUCCESS(Vcb->balance.status)) {
3722 bqb->error = Vcb->balance.status;
3723 }
3724
3725 return STATUS_SUCCESS;
3726 }
3727
3728 bqb->status = Vcb->balance.paused ? BTRFS_BALANCE_PAUSED : BTRFS_BALANCE_RUNNING;
3729
3730 if (Vcb->balance.removing)
3732
3733 if (Vcb->balance.shrinking)
3735
3736 if (!NT_SUCCESS(Vcb->balance.status))
3738
3739 bqb->chunks_left = Vcb->balance.chunks_left;
3740 bqb->total_chunks = Vcb->balance.total_chunks;
3741 bqb->error = Vcb->balance.status;
3742 RtlCopyMemory(&bqb->data_opts, &Vcb->balance.opts[BALANCE_OPTS_DATA], sizeof(btrfs_balance_opts));
3744 RtlCopyMemory(&bqb->system_opts, &Vcb->balance.opts[BALANCE_OPTS_SYSTEM], sizeof(btrfs_balance_opts));
3745
3746 return STATUS_SUCCESS;
3747}
#define BTRFS_BALANCE_STOPPED
Definition: btrfsioctl.h:160
#define BTRFS_BALANCE_ERROR
Definition: btrfsioctl.h:164
#define BTRFS_BALANCE_SHRINKING
Definition: btrfsioctl.h:165
#define BTRFS_BALANCE_RUNNING
Definition: btrfsioctl.h:161
#define BTRFS_BALANCE_PAUSED
Definition: btrfsioctl.h:162
#define BTRFS_BALANCE_REMOVAL
Definition: btrfsioctl.h:163
GLuint GLsizei GLsizei * length
Definition: glext.h:6040
btrfs_balance_opts data_opts
Definition: btrfsioctl.h:172
uint64_t total_chunks
Definition: btrfsioctl.h:170
btrfs_balance_opts metadata_opts
Definition: btrfsioctl.h:173
uint64_t chunks_left
Definition: btrfsioctl.h:169
btrfs_balance_opts system_opts
Definition: btrfsioctl.h:174
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135

Referenced by fsctl_request().

◆ regenerate_space_list()

static NTSTATUS regenerate_space_list ( device_extension Vcb,
device dev 
)
static

Definition at line 2997 of file balance.c.

2997 {
2998 LIST_ENTRY* le;
2999
3000 while (!IsListEmpty(&dev->space)) {
3002
3003 ExFreePool(s);
3004 }
3005
3006 // The Linux driver doesn't like to allocate chunks within the first megabyte of a device.
3007
3008 space_list_add2(&dev->space, NULL, 0x100000, dev->devitem.num_bytes - 0x100000, NULL, NULL);
3009
3010 le = Vcb->chunks.Flink;
3011 while (le != &Vcb->chunks) {
3012 uint16_t n;
3014 CHUNK_ITEM_STRIPE* cis = (CHUNK_ITEM_STRIPE*)&c->chunk_item[1];
3015
3016 for (n = 0; n < c->chunk_item->num_stripes; n++) {
3017 uint64_t stripe_size = 0;
3018
3019 if (cis[n].dev_id == dev->devitem.dev_id) {
3020 if (stripe_size == 0) {
3022
3023 if (c->chunk_item->type & BLOCK_FLAG_RAID0)
3024 factor = c->chunk_item->num_stripes;
3025 else if (c->chunk_item->type & BLOCK_FLAG_RAID10)
3026 factor = c->chunk_item->num_stripes / c->chunk_item->sub_stripes;
3027 else if (c->chunk_item->type & BLOCK_FLAG_RAID5)
3028 factor = c->chunk_item->num_stripes - 1;
3029 else if (c->chunk_item->type & BLOCK_FLAG_RAID6)
3030 factor = c->chunk_item->num_stripes - 2;
3031 else // SINGLE, DUP, RAID1, RAID1C3, RAID1C4
3032 factor = 1;
3033
3034 stripe_size = c->chunk_item->size / factor;
3035 }
3036
3037 space_list_subtract2(&dev->space, NULL, cis[n].offset, stripe_size, NULL, NULL);
3038 }
3039 }
3040
3041 le = le->Flink;
3042 }
3043
3044 return STATUS_SUCCESS;
3045}
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 space_list_subtract2(LIST_ENTRY *list, LIST_ENTRY *list_size, uint64_t address, uint64_t length, chunk *c, LIST_ENTRY *rollback)
Definition: free-space.c:2155
GLdouble n
Definition: glext.h:7729
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

Referenced by _Function_class_().

◆ remove_balance_item()

static NTSTATUS remove_balance_item ( device_extension Vcb)
static

Definition at line 2451 of file balance.c.

2451 {
2452 KEY searchkey;
2455
2456 searchkey.obj_id = BALANCE_ITEM_ID;
2457 searchkey.obj_type = TYPE_TEMP_ITEM;
2458 searchkey.offset = 0;
2459
2460 ExAcquireResourceExclusiveLite(&Vcb->tree_lock, true);
2461
2462 Status = find_item(Vcb, Vcb->root_root, &tp, &searchkey, false, NULL);
2463 if (!NT_SUCCESS(Status)) {
2464 ERR("find_item returned %08lx\n", Status);
2465 goto end;
2466 }
2467
2468 if (!keycmp(tp.item->key, searchkey)) {
2470 if (!NT_SUCCESS(Status)) {
2471 ERR("delete_tree_item returned %08lx\n", Status);
2472 goto end;
2473 }
2474
2475 Status = do_write(Vcb, NULL);
2476 if (!NT_SUCCESS(Status)) {
2477 ERR("do_write returned %08lx\n", Status);
2478 goto end;
2479 }
2480
2481 free_trees(Vcb);
2482 }
2483
2485
2486end:
2487 ExReleaseResourceLite(&Vcb->tree_lock);
2488
2489 return Status;
2490}

Referenced by _Function_class_().

◆ remove_device()

NTSTATUS remove_device ( device_extension Vcb,
void data,
ULONG  length,
KPROCESSOR_MODE  processor_mode 
)

Definition at line 3799 of file balance.c.

3799 {
3800 uint64_t devid;
3801 LIST_ENTRY* le;
3802 device* dev = NULL;
3804 int i;
3805 uint64_t num_rw_devices;
3807
3808 TRACE("(%p, %p, %lx)\n", Vcb, data, length);
3809
3810 if (!SeSinglePrivilegeCheck(RtlConvertLongToLuid(SE_MANAGE_VOLUME_PRIVILEGE), processor_mode))
3812
3813 if (length < sizeof(uint64_t))
3815
3816 devid = *(uint64_t*)data;
3817
3818 ExAcquireResourceSharedLite(&Vcb->tree_lock, true);
3819
3820 if (Vcb->readonly) {
3821 ExReleaseResourceLite(&Vcb->tree_lock);
3823 }
3824
3825 num_rw_devices = 0;
3826
3827 le = Vcb->devices.Flink;
3828 while (le != &Vcb->devices) {
3830
3831 if (dev2->devitem.dev_id == devid)
3832 dev = dev2;
3833
3834 if (!dev2->readonly)
3835 num_rw_devices++;
3836
3837 le = le->Flink;
3838 }
3839
3840 if (!dev) {
3841 ExReleaseResourceLite(&Vcb->tree_lock);
3842 WARN("device %I64x not found\n", devid);
3843 return STATUS_NOT_FOUND;
3844 }
3845
3846 if (!dev->readonly) {
3847 if (num_rw_devices == 1) {
3848 ExReleaseResourceLite(&Vcb->tree_lock);
3849 WARN("not removing last non-readonly device\n");
3851 }
3852
3853 if (num_rw_devices == 4 &&
3854 ((Vcb->data_flags & BLOCK_FLAG_RAID10 || Vcb->metadata_flags & BLOCK_FLAG_RAID10 || Vcb->system_flags & BLOCK_FLAG_RAID10) ||
3855 (Vcb->data_flags & BLOCK_FLAG_RAID6 || Vcb->metadata_flags & BLOCK_FLAG_RAID6 || Vcb->system_flags & BLOCK_FLAG_RAID6) ||
3856 (Vcb->data_flags & BLOCK_FLAG_RAID1C4 || Vcb->metadata_flags & BLOCK_FLAG_RAID1C4 || Vcb->system_flags & BLOCK_FLAG_RAID1C4)
3857 )
3858 ) {
3859 ExReleaseResourceLite(&Vcb->tree_lock);
3860 ERR("would not be enough devices to satisfy RAID requirement (RAID6/10/1C4)\n");
3861 return STATUS_CANNOT_DELETE;
3862 }
3863
3864 if (num_rw_devices == 3 &&
3865 ((Vcb->data_flags & BLOCK_FLAG_RAID5 || Vcb->metadata_flags & BLOCK_FLAG_RAID5 || Vcb->system_flags & BLOCK_FLAG_RAID5) ||
3866 (Vcb->data_flags & BLOCK_FLAG_RAID1C3 || Vcb->metadata_flags & BLOCK_FLAG_RAID1C3 || Vcb->system_flags & BLOCK_FLAG_RAID1C3))
3867 ) {
3868 ExReleaseResourceLite(&Vcb->tree_lock);
3869 ERR("would not be enough devices to satisfy RAID requirement (RAID5/1C3)\n");
3870 return STATUS_CANNOT_DELETE;
3871 }
3872
3873 if (num_rw_devices == 2 &&
3874 ((Vcb->data_flags & BLOCK_FLAG_RAID0 || Vcb->metadata_flags & BLOCK_FLAG_RAID0 || Vcb->system_flags & BLOCK_FLAG_RAID0) ||
3875 (Vcb->data_flags & BLOCK_FLAG_RAID1 || Vcb->metadata_flags & BLOCK_FLAG_RAID1 || Vcb->system_flags & BLOCK_FLAG_RAID1))
3876 ) {
3877 ExReleaseResourceLite(&Vcb->tree_lock);
3878 ERR("would not be enough devices to satisfy RAID requirement (RAID0/1)\n");
3879 return STATUS_CANNOT_DELETE;
3880 }
3881 }
3882
3883 ExReleaseResourceLite(&Vcb->tree_lock);
3884
3885 if (Vcb->balance.thread) {
3886 WARN("balance already running\n");
3888 }
3889
3890 dev->reloc = true;
3891
3892 RtlZeroMemory(Vcb->balance.opts, sizeof(btrfs_balance_opts) * 3);
3893
3894 for (i = 0; i < 3; i++) {
3896 Vcb->balance.opts[i].devid = devid;
3897 }
3898
3899 Vcb->balance.paused = false;
3900 Vcb->balance.removing = true;
3901 Vcb->balance.shrinking = false;
3902 Vcb->balance.status = STATUS_SUCCESS;
3903 KeInitializeEvent(&Vcb->balance.event, NotificationEvent, !Vcb->balance.paused);
3904
3906
3907 Status = PsCreateSystemThread(&Vcb->balance.thread, 0, &oa, NULL, NULL, balance_thread, Vcb);
3908 if (!NT_SUCCESS(Status)) {
3909 ERR("PsCreateSystemThread returned %08lx\n", Status);
3910 dev->reloc = false;
3911 return Status;
3912 }
3913
3914 return STATUS_SUCCESS;
3915}
#define STATUS_CANNOT_DELETE
Definition: shellext.h:71
#define STATUS_MEDIA_WRITE_PROTECTED
Definition: udferr_usr.h:161

Referenced by fsctl_request().

◆ remove_superblocks()

static NTSTATUS remove_superblocks ( device dev)
static

Definition at line 2557 of file balance.c.

2557 {
2559 superblock* sb;
2560 int i = 0;
2561
2563 if (!sb) {
2564 ERR("out of memory\n");
2566 }
2567
2568 RtlZeroMemory(sb, sizeof(superblock));
2569
2570 while (superblock_addrs[i] > 0 && dev->devitem.num_bytes >= superblock_addrs[i] + sizeof(superblock)) {
2571 Status = write_data_phys(dev->devobj, dev->fileobj, superblock_addrs[i], sb, sizeof(superblock));
2572
2573 if (!NT_SUCCESS(Status)) {
2574 ExFreePool(sb);
2575 return Status;
2576 }
2577
2578 i++;
2579 }
2580
2581 ExFreePool(sb);
2582
2583 return STATUS_SUCCESS;
2584}
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)
Definition: flushthread.c:70
superblock * sb
Definition: btrfs.c:4261
static const uint64_t superblock_addrs[]
Definition: btrfs.h:16

Referenced by finish_removing_device().

◆ resume_balance()

NTSTATUS resume_balance ( device_extension Vcb,
KPROCESSOR_MODE  processor_mode 
)

Definition at line 3765 of file balance.c.

3765 {
3766 if (!SeSinglePrivilegeCheck(RtlConvertLongToLuid(SE_MANAGE_VOLUME_PRIVILEGE), processor_mode))
3768
3769 if (!Vcb->balance.thread)
3771
3772 if (!Vcb->balance.paused)
3774
3775 if (Vcb->readonly)
3777
3778 Vcb->balance.paused = false;
3779 KeSetEvent(&Vcb->balance.event, 0, false);
3780
3781 return STATUS_SUCCESS;
3782}

Referenced by fsctl_request().

◆ should_balance_chunk()

static bool should_balance_chunk ( device_extension Vcb,
uint8_t  sort,
chunk c 
)
static

Definition at line 2225 of file balance.c.

2225 {
2226 btrfs_balance_opts* opts;
2227
2228 opts = &Vcb->balance.opts[sort];
2229
2230 if (!(opts->flags & BTRFS_BALANCE_OPTS_ENABLED))
2231 return false;
2232
2233 if (opts->flags & BTRFS_BALANCE_OPTS_PROFILES) {
2235
2236 if (!(type & opts->profiles))
2237 return false;
2238 }
2239
2240 if (opts->flags & BTRFS_BALANCE_OPTS_DEVID) {
2241 uint16_t i;
2242 CHUNK_ITEM_STRIPE* cis = (CHUNK_ITEM_STRIPE*)&c->chunk_item[1];
2243 bool b = false;
2244
2245 for (i = 0; i < c->chunk_item->num_stripes; i++) {
2246 if (cis[i].dev_id == opts->devid) {
2247 b = true;
2248 break;
2249 }
2250 }
2251
2252 if (!b)
2253 return false;
2254 }
2255
2256 if (opts->flags & BTRFS_BALANCE_OPTS_DRANGE) {
2257 uint16_t i, factor;
2258 uint64_t physsize;
2259 CHUNK_ITEM_STRIPE* cis = (CHUNK_ITEM_STRIPE*)&c->chunk_item[1];
2260 bool b = false;
2261
2262 if (c->chunk_item->type & BLOCK_FLAG_RAID0)
2263 factor = c->chunk_item->num_stripes;
2264 else if (c->chunk_item->type & BLOCK_FLAG_RAID10)
2265 factor = c->chunk_item->num_stripes / c->chunk_item->sub_stripes;
2266 else if (c->chunk_item->type & BLOCK_FLAG_RAID5)
2267 factor = c->chunk_item->num_stripes - 1;
2268 else if (c->chunk_item->type & BLOCK_FLAG_RAID6)
2269 factor = c->chunk_item->num_stripes - 2;
2270 else // SINGLE, DUPLICATE, RAID1, RAID1C3, RAID1C4
2271 factor = 1;
2272
2273 physsize = c->chunk_item->size / factor;
2274
2275 for (i = 0; i < c->chunk_item->num_stripes; i++) {
2276 if (cis[i].offset < opts->drange_end && cis[i].offset + physsize >= opts->drange_start &&
2277 (!(opts->flags & BTRFS_BALANCE_OPTS_DEVID) || cis[i].dev_id == opts->devid)) {
2278 b = true;
2279 break;
2280 }
2281 }
2282
2283 if (!b)
2284 return false;
2285 }
2286
2287 if (opts->flags & BTRFS_BALANCE_OPTS_VRANGE) {
2288 if (c->offset + c->chunk_item->size <= opts->vrange_start || c->offset > opts->vrange_end)
2289 return false;
2290 }
2291
2292 if (opts->flags & BTRFS_BALANCE_OPTS_STRIPES) {
2293 if (c->chunk_item->num_stripes < opts->stripes_start || c->chunk_item->num_stripes < opts->stripes_end)
2294 return false;
2295 }
2296
2297 if (opts->flags & BTRFS_BALANCE_OPTS_USAGE) {
2298 uint64_t usage = c->used * 100 / c->chunk_item->size;
2299
2300 // usage == 0 should mean completely empty, not just that usage rounds to 0%
2301 if (c->used > 0 && usage == 0)
2302 usage = 1;
2303
2304 if (usage < opts->usage_start || usage > opts->usage_end)
2305 return false;
2306 }
2307
2310
2311 if (type == opts->convert)
2312 return false;
2313 }
2314
2315 return true;
2316}
static __inline uint64_t get_chunk_dup_type(chunk *c)
Definition: balance.c:2204
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
GLsizeiptr const GLvoid GLenum usage
Definition: glext.h:5919
uint64_t dev_id
Definition: btrfs.h:352

Referenced by _Function_class_().

◆ sort_data_reloc_refs()

static void sort_data_reloc_refs ( data_reloc dr)
static

Definition at line 1480 of file balance.c.

1480 {
1481 LIST_ENTRY newlist, *le;
1482
1483 if (IsListEmpty(&dr->refs))
1484 return;
1485
1486 // insertion sort
1487
1488 InitializeListHead(&newlist);
1489
1490 while (!IsListEmpty(&dr->refs)) {
1492 bool inserted = false;
1493
1494 if (ref->type == TYPE_EXTENT_DATA_REF)
1495 ref->hash = get_extent_data_ref_hash2(ref->edr.root, ref->edr.objid, ref->edr.offset);
1496 else if (ref->type == TYPE_SHARED_DATA_REF)
1497 ref->hash = ref->parent->new_address;
1498
1499 le = newlist.Flink;
1500 while (le != &newlist) {
1502
1503 if (ref->type < ref2->type || (ref->type == ref2->type && ref->hash > ref2->hash)) {
1505 inserted = true;
1506 break;
1507 }
1508
1509 le = le->Flink;
1510 }
1511
1512 if (!inserted)
1513 InsertTailList(&newlist, &ref->list_entry);
1514 }
1515
1516 le = newlist.Flink;
1517 while (le != &newlist) {
1519
1520 if (le->Flink != &newlist) {
1522
1523 if (ref->type == TYPE_EXTENT_DATA_REF && ref2->type == TYPE_EXTENT_DATA_REF && ref->edr.root == ref2->edr.root &&
1524 ref->edr.objid == ref2->edr.objid && ref->edr.offset == ref2->edr.offset) {
1526 ref->edr.count += ref2->edr.count;
1527 ExFreePool(ref2);
1528 continue;
1529 }
1530 }
1531
1532 le = le->Flink;
1533 }
1534
1535 newlist.Flink->Blink = &dr->refs;
1536 newlist.Blink->Flink = &dr->refs;
1537 dr->refs.Flink = newlist.Flink;
1538 dr->refs.Blink = newlist.Blink;
1539}
uint64_t get_extent_data_ref_hash2(uint64_t root, uint64_t objid, uint64_t offset)
Definition: extent-tree.c:35
#define InsertHeadList(ListHead, Entry)
struct _LIST_ENTRY * Blink
Definition: typedefs.h:122
uint64_t hash
Definition: balance.c:60
EXTENT_DATA_REF edr
Definition: balance.c:63
uint8_t type
Definition: balance.c:59

Referenced by add_data_reloc_extent_item().

◆ sort_metadata_reloc_refs()

static void sort_metadata_reloc_refs ( metadata_reloc mr)
static

Definition at line 280 of file balance.c.

280 {
281 LIST_ENTRY newlist, *le;
282
283 if (mr->refs.Flink == mr->refs.Blink) // 0 or 1 items
284 return;
285
286 // insertion sort
287
288 InitializeListHead(&newlist);
289
290 while (!IsListEmpty(&mr->refs)) {
292 bool inserted = false;
293
294 if (ref->type == TYPE_TREE_BLOCK_REF)
295 ref->hash = ref->tbr.offset;
296 else if (ref->type == TYPE_SHARED_BLOCK_REF)
297 ref->hash = ref->parent->new_address;
298
299 le = newlist.Flink;
300 while (le != &newlist) {
302
303 if (ref->type < ref2->type || (ref->type == ref2->type && ref->hash > ref2->hash)) {
305 inserted = true;
306 break;
307 }
308
309 le = le->Flink;
310 }
311
312 if (!inserted)
313 InsertTailList(&newlist, &ref->list_entry);
314 }
315
316 newlist.Flink->Blink = &mr->refs;
317 newlist.Blink->Flink = &mr->refs;
318 mr->refs.Flink = newlist.Flink;
319 mr->refs.Blink = newlist.Blink;
320}
uint8_t type
Definition: balance.c:35
uint64_t hash
Definition: balance.c:36

Referenced by add_metadata_reloc_extent_item().

◆ start_balance()

NTSTATUS start_balance ( device_extension Vcb,
void data,
ULONG  length,
KPROCESSOR_MODE  processor_mode 
)

Definition at line 3511 of file balance.c.

3511 {
3515 uint8_t i;
3516
3517 if (length < sizeof(btrfs_start_balance) || !data)
3519
3520 if (!SeSinglePrivilegeCheck(RtlConvertLongToLuid(SE_MANAGE_VOLUME_PRIVILEGE), processor_mode))
3522
3523 if (Vcb->locked) {
3524 WARN("cannot start balance while locked\n");
3526 }
3527
3528 if (Vcb->scrub.thread) {
3529 WARN("cannot start balance while scrub running\n");
3531 }
3532
3533 if (Vcb->balance.thread) {
3534 WARN("balance already running\n");
3536 }
3537
3538 if (Vcb->readonly)
3540
3544 return STATUS_SUCCESS;
3545
3546 for (i = 0; i < 3; i++) {
3547 if (bsb->opts[i].flags & BTRFS_BALANCE_OPTS_ENABLED) {
3552
3553 if (bsb->opts[i].profiles == 0)
3555 }
3556
3557 if (bsb->opts[i].flags & BTRFS_BALANCE_OPTS_DEVID) {
3558 if (bsb->opts[i].devid == 0)
3560 }
3561
3562 if (bsb->opts[i].flags & BTRFS_BALANCE_OPTS_DRANGE) {
3563 if (bsb->opts[i].drange_start > bsb->opts[i].drange_end)
3565 }
3566
3567 if (bsb->opts[i].flags & BTRFS_BALANCE_OPTS_VRANGE) {
3568 if (bsb->opts[i].vrange_start > bsb->opts[i].vrange_end)
3570 }
3571
3572 if (bsb->opts[i].flags & BTRFS_BALANCE_OPTS_LIMIT) {
3573 bsb->opts[i].limit_start = max(1, bsb->opts[i].limit_start);
3574 bsb->opts[i].limit_end = max(1, bsb->opts[i].limit_end);
3575
3576 if (bsb->opts[i].limit_start > bsb->opts[i].limit_end)
3578 }
3579
3580 if (bsb->opts[i].flags & BTRFS_BALANCE_OPTS_STRIPES) {
3581 bsb->opts[i].stripes_start = max(1, bsb->opts[i].stripes_start);
3582 bsb->opts[i].stripes_end = max(1, bsb->opts[i].stripes_end);
3583
3584 if (bsb->opts[i].stripes_start > bsb->opts[i].stripes_end)
3586 }
3587
3588 if (bsb->opts[i].flags & BTRFS_BALANCE_OPTS_USAGE) {
3589 bsb->opts[i].usage_start = min(100, bsb->opts[i].stripes_start);
3590 bsb->opts[i].usage_end = min(100, bsb->opts[i].stripes_end);
3591
3592 if (bsb->opts[i].stripes_start > bsb->opts[i].stripes_end)
3594 }
3595
3596 if (bsb->opts[i].flags & BTRFS_BALANCE_OPTS_CONVERT) {
3597 if (bsb->opts[i].convert != BLOCK_FLAG_RAID0 && bsb->opts[i].convert != BLOCK_FLAG_RAID1 &&
3603 }
3604 }
3605 }
3606
3610
3611 Vcb->balance.paused = false;
3612 Vcb->balance.removing = false;
3613 Vcb->balance.shrinking = false;
3614 Vcb->balance.status = STATUS_SUCCESS;
3615 KeInitializeEvent(&Vcb->balance.event, NotificationEvent, !Vcb->balance.paused);
3616
3618
3619 Status = PsCreateSystemThread(&Vcb->balance.thread, 0, &oa, NULL, NULL, balance_thread, Vcb);
3620 if (!NT_SUCCESS(Status)) {
3621 ERR("PsCreateSystemThread returned %08lx\n", Status);
3622 return Status;
3623 }
3624
3625 return STATUS_SUCCESS;
3626}
btrfs_balance_opts opts[3]
Definition: btrfsioctl.h:178

Referenced by fsctl_request().

◆ stop_balance()

NTSTATUS stop_balance ( device_extension Vcb,
KPROCESSOR_MODE  processor_mode 
)

Definition at line 3784 of file balance.c.

3784 {
3785 if (!SeSinglePrivilegeCheck(RtlConvertLongToLuid(SE_MANAGE_VOLUME_PRIVILEGE), processor_mode))
3787
3788 if (!Vcb->balance.thread)
3790
3791 Vcb->balance.paused = false;
3792 Vcb->balance.stopping = true;
3793 Vcb->balance.status = STATUS_SUCCESS;
3794 KeSetEvent(&Vcb->balance.event, 0, false);
3795
3796 return STATUS_SUCCESS;
3797}

Referenced by fsctl_request().

◆ trim_unalloc_space()

static void trim_unalloc_space ( _Requires_lock_held_(_Curr_->tree_lock)