1 /* Copyright (c) Mark Harmstone 2016-17 2 * 3 * This file is part of WinBtrfs. 4 * 5 * WinBtrfs is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU Lesser General Public Licence as published by 7 * the Free Software Foundation, either version 3 of the Licence, or 8 * (at your option) any later version. 9 * 10 * WinBtrfs is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU Lesser General Public Licence for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public Licence 16 * along with WinBtrfs. If not, see <http://www.gnu.org/licenses/>. */ 17 18 #ifdef _DEBUG 19 #define DEBUG 20 #endif 21 22 #include "btrfs_drv.h" 23 #ifndef __REACTOS__ 24 #ifndef _MSC_VER 25 #include <cpuid.h> 26 #else 27 #include <intrin.h> 28 #endif 29 #endif 30 #include <ntddscsi.h> 31 #include "btrfs.h" 32 #include <ata.h> 33 34 #ifndef _MSC_VER 35 #include <initguid.h> 36 #include <ntddstor.h> 37 #undef INITGUID 38 #endif 39 40 #include <ntdddisk.h> 41 #include <ntddvol.h> 42 43 #ifdef _MSC_VER 44 #include <initguid.h> 45 #include <ntddstor.h> 46 #undef INITGUID 47 #endif 48 49 #define INCOMPAT_SUPPORTED (BTRFS_INCOMPAT_FLAGS_MIXED_BACKREF | BTRFS_INCOMPAT_FLAGS_DEFAULT_SUBVOL | BTRFS_INCOMPAT_FLAGS_MIXED_GROUPS | \ 50 BTRFS_INCOMPAT_FLAGS_COMPRESS_LZO | BTRFS_INCOMPAT_FLAGS_BIG_METADATA | BTRFS_INCOMPAT_FLAGS_RAID56 | \ 51 BTRFS_INCOMPAT_FLAGS_EXTENDED_IREF | BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA | BTRFS_INCOMPAT_FLAGS_NO_HOLES) 52 #define COMPAT_RO_SUPPORTED (BTRFS_COMPAT_RO_FLAGS_FREE_SPACE_CACHE | BTRFS_COMPAT_RO_FLAGS_FREE_SPACE_CACHE_VALID) 53 54 static WCHAR device_name[] = {'\\','B','t','r','f','s',0}; 55 static WCHAR dosdevice_name[] = {'\\','D','o','s','D','e','v','i','c','e','s','\\','B','t','r','f','s',0}; 56 57 DEFINE_GUID(BtrfsBusInterface, 0x4d414874, 0x6865, 0x6761, 0x6d, 0x65, 0x83, 0x69, 0x17, 0x9a, 0x7d, 0x1d); 58 59 PDRIVER_OBJECT drvobj; 60 PDEVICE_OBJECT master_devobj; 61 #ifndef __REACTOS__ 62 BOOL have_sse42 = FALSE, have_sse2 = FALSE; 63 #endif 64 UINT64 num_reads = 0; 65 LIST_ENTRY uid_map_list, gid_map_list; 66 LIST_ENTRY VcbList; 67 ERESOURCE global_loading_lock; 68 UINT32 debug_log_level = 0; 69 UINT32 mount_compress = 0; 70 UINT32 mount_compress_force = 0; 71 UINT32 mount_compress_type = 0; 72 UINT32 mount_zlib_level = 3; 73 UINT32 mount_flush_interval = 30; 74 UINT32 mount_max_inline = 2048; 75 UINT32 mount_skip_balance = 0; 76 UINT32 mount_no_barrier = 0; 77 UINT32 mount_no_trim = 0; 78 UINT32 mount_clear_cache = 0; 79 UINT32 mount_allow_degraded = 0; 80 UINT32 mount_readonly = 0; 81 UINT32 no_pnp = 0; 82 BOOL log_started = FALSE; 83 UNICODE_STRING log_device, log_file, registry_path; 84 tPsUpdateDiskCounters fPsUpdateDiskCounters; 85 tCcCopyReadEx fCcCopyReadEx; 86 tCcCopyWriteEx fCcCopyWriteEx; 87 tCcSetAdditionalCacheAttributesEx fCcSetAdditionalCacheAttributesEx; 88 tFsRtlUpdateDiskCounters fFsRtlUpdateDiskCounters; 89 BOOL diskacc = FALSE; 90 void *notification_entry = NULL, *notification_entry2 = NULL, *notification_entry3 = NULL; 91 ERESOURCE pdo_list_lock, mapping_lock; 92 LIST_ENTRY pdo_list; 93 BOOL finished_probing = FALSE; 94 HANDLE degraded_wait_handle = NULL, mountmgr_thread_handle = NULL; 95 BOOL degraded_wait = TRUE; 96 KEVENT mountmgr_thread_event; 97 BOOL shutting_down = FALSE; 98 99 #ifdef _DEBUG 100 PFILE_OBJECT comfo = NULL; 101 PDEVICE_OBJECT comdo = NULL; 102 HANDLE log_handle = NULL; 103 ERESOURCE log_lock; 104 HANDLE serial_thread_handle = NULL; 105 106 static void init_serial(BOOL first_time); 107 #endif 108 109 static NTSTATUS close_file(_In_ PFILE_OBJECT FileObject, _In_ PIRP Irp); 110 111 typedef struct { 112 KEVENT Event; 113 IO_STATUS_BLOCK iosb; 114 } read_context; 115 116 #ifdef _DEBUG 117 _Function_class_(IO_COMPLETION_ROUTINE) 118 static NTSTATUS dbg_completion(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp, _In_ PVOID conptr) { 119 read_context* context = conptr; 120 121 UNUSED(DeviceObject); 122 123 context->iosb = Irp->IoStatus; 124 KeSetEvent(&context->Event, 0, FALSE); 125 126 return STATUS_MORE_PROCESSING_REQUIRED; 127 } 128 129 #ifdef DEBUG_LONG_MESSAGES 130 void _debug_message(_In_ const char* func, _In_ const char* file, _In_ unsigned int line, _In_ char* s, ...) { 131 #else 132 void _debug_message(_In_ const char* func, _In_ char* s, ...) { 133 #endif 134 LARGE_INTEGER offset; 135 PIO_STACK_LOCATION IrpSp; 136 NTSTATUS Status; 137 PIRP Irp; 138 va_list ap; 139 char *buf2, *buf; 140 read_context context; 141 UINT32 length; 142 143 buf2 = ExAllocatePoolWithTag(NonPagedPool, 1024, ALLOC_TAG); 144 145 if (!buf2) { 146 DbgPrint("Couldn't allocate buffer in debug_message\n"); 147 return; 148 } 149 150 #ifdef DEBUG_LONG_MESSAGES 151 sprintf(buf2, "%p:%s:%s:%u:", PsGetCurrentThread(), func, file, line); 152 #else 153 sprintf(buf2, "%p:%s:", PsGetCurrentThread(), func); 154 #endif 155 buf = &buf2[strlen(buf2)]; 156 157 va_start(ap, s); 158 vsprintf(buf, s, ap); 159 160 ExAcquireResourceSharedLite(&log_lock, TRUE); 161 162 if (!log_started || (log_device.Length == 0 && log_file.Length == 0)) { 163 DbgPrint(buf2); 164 } else if (log_device.Length > 0) { 165 if (!comdo) { 166 DbgPrint("comdo is NULL :-(\n"); 167 DbgPrint(buf2); 168 goto exit2; 169 } 170 171 length = (UINT32)strlen(buf2); 172 173 offset.u.LowPart = 0; 174 offset.u.HighPart = 0; 175 176 RtlZeroMemory(&context, sizeof(read_context)); 177 178 KeInitializeEvent(&context.Event, NotificationEvent, FALSE); 179 180 Irp = IoAllocateIrp(comdo->StackSize, FALSE); 181 182 if (!Irp) { 183 DbgPrint("IoAllocateIrp failed\n"); 184 goto exit2; 185 } 186 187 IrpSp = IoGetNextIrpStackLocation(Irp); 188 IrpSp->MajorFunction = IRP_MJ_WRITE; 189 190 if (comdo->Flags & DO_BUFFERED_IO) { 191 Irp->AssociatedIrp.SystemBuffer = buf2; 192 193 Irp->Flags = IRP_BUFFERED_IO; 194 } else if (comdo->Flags & DO_DIRECT_IO) { 195 Irp->MdlAddress = IoAllocateMdl(buf2, length, FALSE, FALSE, NULL); 196 if (!Irp->MdlAddress) { 197 DbgPrint("IoAllocateMdl failed\n"); 198 goto exit; 199 } 200 201 MmBuildMdlForNonPagedPool(Irp->MdlAddress); 202 } else { 203 Irp->UserBuffer = buf2; 204 } 205 206 IrpSp->Parameters.Write.Length = length; 207 IrpSp->Parameters.Write.ByteOffset = offset; 208 209 Irp->UserIosb = &context.iosb; 210 211 Irp->UserEvent = &context.Event; 212 213 IoSetCompletionRoutine(Irp, dbg_completion, &context, TRUE, TRUE, TRUE); 214 215 Status = IoCallDriver(comdo, Irp); 216 217 if (Status == STATUS_PENDING) { 218 KeWaitForSingleObject(&context.Event, Executive, KernelMode, FALSE, NULL); 219 Status = context.iosb.Status; 220 } 221 222 if (comdo->Flags & DO_DIRECT_IO) 223 IoFreeMdl(Irp->MdlAddress); 224 225 if (!NT_SUCCESS(Status)) { 226 DbgPrint("failed to write to COM1 - error %08x\n", Status); 227 goto exit; 228 } 229 230 exit: 231 IoFreeIrp(Irp); 232 } else if (log_handle != NULL) { 233 IO_STATUS_BLOCK iosb; 234 235 length = (UINT32)strlen(buf2); 236 237 Status = ZwWriteFile(log_handle, NULL, NULL, NULL, &iosb, buf2, length, NULL, NULL); 238 239 if (!NT_SUCCESS(Status)) { 240 DbgPrint("failed to write to file - error %08x\n", Status); 241 } 242 } 243 244 exit2: 245 ExReleaseResourceLite(&log_lock); 246 247 va_end(ap); 248 249 if (buf2) 250 ExFreePool(buf2); 251 } 252 #endif 253 254 BOOL is_top_level(_In_ PIRP Irp) { 255 if (!IoGetTopLevelIrp()) { 256 IoSetTopLevelIrp(Irp); 257 return TRUE; 258 } 259 260 return FALSE; 261 } 262 263 _Function_class_(DRIVER_UNLOAD) 264 #ifdef __REACTOS__ 265 static void NTAPI DriverUnload(_In_ PDRIVER_OBJECT DriverObject) { 266 #else 267 static void DriverUnload(_In_ PDRIVER_OBJECT DriverObject) { 268 #endif 269 UNICODE_STRING dosdevice_nameW; 270 271 ERR("DriverUnload\n"); 272 273 free_cache(); 274 275 IoUnregisterFileSystem(DriverObject->DeviceObject); 276 277 if (notification_entry2) 278 #ifdef __REACTOS__ 279 IoUnregisterPlugPlayNotification(notification_entry2); 280 #else 281 IoUnregisterPlugPlayNotificationEx(notification_entry2); 282 #endif 283 284 if (notification_entry3) 285 #ifdef __REACTOS__ 286 IoUnregisterPlugPlayNotification(notification_entry3); 287 #else 288 IoUnregisterPlugPlayNotificationEx(notification_entry3); 289 #endif 290 291 if (notification_entry) 292 #ifdef __REACTOS__ 293 IoUnregisterPlugPlayNotification(notification_entry); 294 #else 295 IoUnregisterPlugPlayNotificationEx(notification_entry); 296 #endif 297 298 dosdevice_nameW.Buffer = dosdevice_name; 299 dosdevice_nameW.Length = dosdevice_nameW.MaximumLength = (USHORT)wcslen(dosdevice_name) * sizeof(WCHAR); 300 301 IoDeleteSymbolicLink(&dosdevice_nameW); 302 IoDeleteDevice(DriverObject->DeviceObject); 303 304 while (!IsListEmpty(&uid_map_list)) { 305 LIST_ENTRY* le = RemoveHeadList(&uid_map_list); 306 uid_map* um = CONTAINING_RECORD(le, uid_map, listentry); 307 308 ExFreePool(um->sid); 309 310 ExFreePool(um); 311 } 312 313 while (!IsListEmpty(&gid_map_list)) { 314 gid_map* gm = CONTAINING_RECORD(RemoveHeadList(&gid_map_list), gid_map, listentry); 315 316 ExFreePool(gm->sid); 317 ExFreePool(gm); 318 } 319 320 // FIXME - free volumes and their devpaths 321 322 #ifdef _DEBUG 323 if (comfo) 324 ObDereferenceObject(comfo); 325 326 if (log_handle) 327 ZwClose(log_handle); 328 #endif 329 330 ExDeleteResourceLite(&global_loading_lock); 331 ExDeleteResourceLite(&pdo_list_lock); 332 333 if (log_device.Buffer) 334 ExFreePool(log_device.Buffer); 335 336 if (log_file.Buffer) 337 ExFreePool(log_file.Buffer); 338 339 if (registry_path.Buffer) 340 ExFreePool(registry_path.Buffer); 341 342 #ifdef _DEBUG 343 ExDeleteResourceLite(&log_lock); 344 #endif 345 ExDeleteResourceLite(&mapping_lock); 346 } 347 348 static BOOL get_last_inode(_In_ _Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension* Vcb, _In_ root* r, _In_opt_ PIRP Irp) { 349 KEY searchkey; 350 traverse_ptr tp, prev_tp; 351 NTSTATUS Status; 352 353 // get last entry 354 searchkey.obj_id = 0xffffffffffffffff; 355 searchkey.obj_type = 0xff; 356 searchkey.offset = 0xffffffffffffffff; 357 358 Status = find_item(Vcb, r, &tp, &searchkey, FALSE, Irp); 359 if (!NT_SUCCESS(Status)) { 360 ERR("error - find_item returned %08x\n", Status); 361 return FALSE; 362 } 363 364 if (tp.item->key.obj_type == TYPE_INODE_ITEM || (tp.item->key.obj_type == TYPE_ROOT_ITEM && !(tp.item->key.obj_id & 0x8000000000000000))) { 365 r->lastinode = tp.item->key.obj_id; 366 TRACE("last inode for tree %llx is %llx\n", r->id, r->lastinode); 367 return TRUE; 368 } 369 370 while (find_prev_item(Vcb, &tp, &prev_tp, Irp)) { 371 tp = prev_tp; 372 373 TRACE("moving on to %llx,%x,%llx\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset); 374 375 if (tp.item->key.obj_type == TYPE_INODE_ITEM || (tp.item->key.obj_type == TYPE_ROOT_ITEM && !(tp.item->key.obj_id & 0x8000000000000000))) { 376 r->lastinode = tp.item->key.obj_id; 377 TRACE("last inode for tree %llx is %llx\n", r->id, r->lastinode); 378 return TRUE; 379 } 380 } 381 382 r->lastinode = SUBVOL_ROOT_INODE; 383 384 WARN("no INODE_ITEMs in tree %llx\n", r->id); 385 386 return TRUE; 387 } 388 389 _Success_(return) 390 static BOOL extract_xattr(_In_reads_bytes_(size) void* item, _In_ USHORT size, _In_z_ char* name, _Out_ UINT8** data, _Out_ UINT16* datalen) { 391 DIR_ITEM* xa = (DIR_ITEM*)item; 392 USHORT xasize; 393 394 while (TRUE) { 395 if (size < sizeof(DIR_ITEM) || size < (sizeof(DIR_ITEM) - 1 + xa->m + xa->n)) { 396 WARN("DIR_ITEM is truncated\n"); 397 return FALSE; 398 } 399 400 if (xa->n == strlen(name) && RtlCompareMemory(name, xa->name, xa->n) == xa->n) { 401 TRACE("found xattr %s\n", name); 402 403 *datalen = xa->m; 404 405 if (xa->m > 0) { 406 *data = ExAllocatePoolWithTag(PagedPool, xa->m, ALLOC_TAG); 407 if (!*data) { 408 ERR("out of memory\n"); 409 return FALSE; 410 } 411 412 RtlCopyMemory(*data, &xa->name[xa->n], xa->m); 413 } else 414 *data = NULL; 415 416 return TRUE; 417 } 418 419 xasize = sizeof(DIR_ITEM) - 1 + xa->m + xa->n; 420 421 if (size > xasize) { 422 size -= xasize; 423 xa = (DIR_ITEM*)&xa->name[xa->m + xa->n]; 424 } else 425 break; 426 } 427 428 TRACE("xattr %s not found\n", name); 429 430 return FALSE; 431 } 432 433 _Success_(return) 434 BOOL get_xattr(_In_ _Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, _In_ root* subvol, _In_ UINT64 inode, _In_z_ char* name, _In_ UINT32 crc32, 435 _Out_ UINT8** data, _Out_ UINT16* datalen, _In_opt_ PIRP Irp) { 436 KEY searchkey; 437 traverse_ptr tp; 438 NTSTATUS Status; 439 440 TRACE("(%p, %llx, %llx, %s, %08x, %p, %p)\n", Vcb, subvol->id, inode, name, crc32, data, datalen); 441 442 searchkey.obj_id = inode; 443 searchkey.obj_type = TYPE_XATTR_ITEM; 444 searchkey.offset = crc32; 445 446 Status = find_item(Vcb, subvol, &tp, &searchkey, FALSE, Irp); 447 if (!NT_SUCCESS(Status)) { 448 ERR("error - find_item returned %08x\n", Status); 449 return FALSE; 450 } 451 452 if (keycmp(tp.item->key, searchkey)) { 453 TRACE("could not find item (%llx,%x,%llx)\n", searchkey.obj_id, searchkey.obj_type, searchkey.offset); 454 return FALSE; 455 } 456 457 if (tp.item->size < sizeof(DIR_ITEM)) { 458 ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(DIR_ITEM)); 459 return FALSE; 460 } 461 462 return extract_xattr(tp.item->data, tp.item->size, name, data, datalen); 463 } 464 465 _Dispatch_type_(IRP_MJ_CLOSE) 466 _Function_class_(DRIVER_DISPATCH) 467 static NTSTATUS drv_close(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { 468 NTSTATUS Status; 469 PIO_STACK_LOCATION IrpSp; 470 device_extension* Vcb = DeviceObject->DeviceExtension; 471 BOOL top_level; 472 473 FsRtlEnterFileSystem(); 474 475 TRACE("close\n"); 476 477 top_level = is_top_level(Irp); 478 479 if (DeviceObject == master_devobj) { 480 TRACE("Closing file system\n"); 481 Status = STATUS_SUCCESS; 482 goto end; 483 } else if (Vcb && Vcb->type == VCB_TYPE_VOLUME) { 484 Status = vol_close(DeviceObject, Irp); 485 goto end; 486 } else if (!Vcb || Vcb->type != VCB_TYPE_FS) { 487 Status = STATUS_INVALID_PARAMETER; 488 goto end; 489 } 490 491 IrpSp = IoGetCurrentIrpStackLocation(Irp); 492 493 // FIXME - unmount if called for volume 494 // FIXME - call FsRtlNotifyUninitializeSync(&Vcb->NotifySync) if unmounting 495 496 Status = close_file(IrpSp->FileObject, Irp); 497 498 end: 499 Irp->IoStatus.Status = Status; 500 Irp->IoStatus.Information = 0; 501 502 IoCompleteRequest( Irp, IO_DISK_INCREMENT ); 503 504 if (top_level) 505 IoSetTopLevelIrp(NULL); 506 507 TRACE("returning %08x\n", Status); 508 509 FsRtlExitFileSystem(); 510 511 return Status; 512 } 513 514 _Dispatch_type_(IRP_MJ_FLUSH_BUFFERS) 515 _Function_class_(DRIVER_DISPATCH) 516 static NTSTATUS drv_flush_buffers(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { 517 NTSTATUS Status; 518 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); 519 PFILE_OBJECT FileObject = IrpSp->FileObject; 520 fcb* fcb = FileObject->FsContext; 521 device_extension* Vcb = DeviceObject->DeviceExtension; 522 BOOL top_level; 523 524 FsRtlEnterFileSystem(); 525 526 TRACE("flush buffers\n"); 527 528 top_level = is_top_level(Irp); 529 530 if (Vcb && Vcb->type == VCB_TYPE_VOLUME) { 531 Status = vol_flush_buffers(DeviceObject, Irp); 532 goto end; 533 } else if (!Vcb || Vcb->type != VCB_TYPE_FS) { 534 Status = STATUS_INVALID_PARAMETER; 535 goto end; 536 } 537 538 if (!fcb) { 539 ERR("fcb was NULL\n"); 540 Status = STATUS_INVALID_PARAMETER; 541 goto end; 542 } 543 544 if (fcb == Vcb->volume_fcb) { 545 Status = STATUS_INVALID_PARAMETER; 546 goto end; 547 } 548 549 Irp->IoStatus.Information = 0; 550 551 fcb->Header.IsFastIoPossible = fast_io_possible(fcb); 552 553 Status = STATUS_SUCCESS; 554 Irp->IoStatus.Status = Status; 555 556 if (fcb->type != BTRFS_TYPE_DIRECTORY) { 557 CcFlushCache(&fcb->nonpaged->segment_object, NULL, 0, &Irp->IoStatus); 558 559 if (fcb->Header.PagingIoResource) { 560 ExAcquireResourceExclusiveLite(fcb->Header.PagingIoResource, TRUE); 561 ExReleaseResourceLite(fcb->Header.PagingIoResource); 562 } 563 564 Status = Irp->IoStatus.Status; 565 } 566 567 end: 568 IoCompleteRequest(Irp, IO_NO_INCREMENT); 569 570 TRACE("returning %08x\n", Status); 571 572 if (top_level) 573 IoSetTopLevelIrp(NULL); 574 575 FsRtlExitFileSystem(); 576 577 return Status; 578 } 579 580 static void calculate_total_space(_In_ device_extension* Vcb, _Out_ UINT64* totalsize, _Out_ UINT64* freespace) { 581 UINT64 nfactor, dfactor, sectors_used; 582 583 if (Vcb->data_flags & BLOCK_FLAG_DUPLICATE || Vcb->data_flags & BLOCK_FLAG_RAID1 || Vcb->data_flags & BLOCK_FLAG_RAID10) { 584 nfactor = 1; 585 dfactor = 2; 586 } else if (Vcb->data_flags & BLOCK_FLAG_RAID5) { 587 nfactor = Vcb->superblock.num_devices - 1; 588 dfactor = Vcb->superblock.num_devices; 589 } else if (Vcb->data_flags & BLOCK_FLAG_RAID6) { 590 nfactor = Vcb->superblock.num_devices - 2; 591 dfactor = Vcb->superblock.num_devices; 592 } else { 593 nfactor = 1; 594 dfactor = 1; 595 } 596 597 sectors_used = Vcb->superblock.bytes_used / Vcb->superblock.sector_size; 598 599 *totalsize = (Vcb->superblock.total_bytes / Vcb->superblock.sector_size) * nfactor / dfactor; 600 *freespace = sectors_used > *totalsize ? 0 : (*totalsize - sectors_used); 601 } 602 603 #ifndef __REACTOS__ 604 // This function exists because we have to lie about our FS type in certain situations. 605 // MPR!MprGetConnection queries the FS type, and compares it to a whitelist. If it doesn't match, 606 // it will return ERROR_NO_NET_OR_BAD_PATH, which prevents UAC from working. 607 // The command mklink refuses to create hard links on anything other than NTFS, so we have to 608 // blacklist cmd.exe too. 609 610 static BOOL lie_about_fs_type() { 611 NTSTATUS Status; 612 PROCESS_BASIC_INFORMATION pbi; 613 PPEB peb; 614 LIST_ENTRY* le; 615 ULONG retlen; 616 617 static WCHAR mpr[] = L"MPR.DLL"; 618 static WCHAR cmd[] = L"CMD.EXE"; 619 static WCHAR fsutil[] = L"FSUTIL.EXE"; 620 UNICODE_STRING mprus, cmdus, fsutilus; 621 622 mprus.Buffer = mpr; 623 mprus.Length = mprus.MaximumLength = (USHORT)(wcslen(mpr) * sizeof(WCHAR)); 624 cmdus.Buffer = cmd; 625 cmdus.Length = cmdus.MaximumLength = (USHORT)(wcslen(cmd) * sizeof(WCHAR)); 626 fsutilus.Buffer = fsutil; 627 fsutilus.Length = fsutilus.MaximumLength = (USHORT)(wcslen(fsutil) * sizeof(WCHAR)); 628 629 if (!PsGetCurrentProcess()) 630 return FALSE; 631 632 Status = ZwQueryInformationProcess(NtCurrentProcess(), ProcessBasicInformation, &pbi, sizeof(pbi), &retlen); 633 634 if (!NT_SUCCESS(Status)) { 635 ERR("ZwQueryInformationProcess returned %08x\n", Status); 636 return FALSE; 637 } 638 639 if (!pbi.PebBaseAddress) 640 return FALSE; 641 642 peb = pbi.PebBaseAddress; 643 644 if (!peb->Ldr) 645 return FALSE; 646 647 le = peb->Ldr->InMemoryOrderModuleList.Flink; 648 while (le != &peb->Ldr->InMemoryOrderModuleList) { 649 LDR_DATA_TABLE_ENTRY* entry = CONTAINING_RECORD(le, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks); 650 BOOL blacklist = FALSE; 651 652 if (entry->FullDllName.Length >= mprus.Length) { 653 UNICODE_STRING name; 654 655 name.Buffer = &entry->FullDllName.Buffer[(entry->FullDllName.Length - mprus.Length) / sizeof(WCHAR)]; 656 name.Length = name.MaximumLength = mprus.Length; 657 658 blacklist = FsRtlAreNamesEqual(&name, &mprus, TRUE, NULL); 659 } 660 661 if (!blacklist && entry->FullDllName.Length >= cmdus.Length) { 662 UNICODE_STRING name; 663 664 name.Buffer = &entry->FullDllName.Buffer[(entry->FullDllName.Length - cmdus.Length) / sizeof(WCHAR)]; 665 name.Length = name.MaximumLength = cmdus.Length; 666 667 blacklist = FsRtlAreNamesEqual(&name, &cmdus, TRUE, NULL); 668 } 669 670 if (!blacklist && entry->FullDllName.Length >= fsutilus.Length) { 671 UNICODE_STRING name; 672 673 name.Buffer = &entry->FullDllName.Buffer[(entry->FullDllName.Length - fsutilus.Length) / sizeof(WCHAR)]; 674 name.Length = name.MaximumLength = fsutilus.Length; 675 676 blacklist = FsRtlAreNamesEqual(&name, &fsutilus, TRUE, NULL); 677 } 678 679 if (blacklist) { 680 void** frames; 681 ULONG i, num_frames; 682 683 frames = ExAllocatePoolWithTag(PagedPool, 256 * sizeof(void*), ALLOC_TAG); 684 if (!frames) { 685 ERR("out of memory\n"); 686 return FALSE; 687 } 688 689 num_frames = RtlWalkFrameChain(frames, 256, 1); 690 691 for (i = 0; i < num_frames; i++) { 692 // entry->Reserved3[1] appears to be the image size 693 if (frames[i] >= entry->DllBase && (ULONG_PTR)frames[i] <= (ULONG_PTR)entry->DllBase + (ULONG_PTR)entry->Reserved3[1]) { 694 ExFreePool(frames); 695 return TRUE; 696 } 697 } 698 699 ExFreePool(frames); 700 } 701 702 le = le->Flink; 703 } 704 705 return FALSE; 706 } 707 #endif 708 709 _Dispatch_type_(IRP_MJ_QUERY_VOLUME_INFORMATION) 710 _Function_class_(DRIVER_DISPATCH) 711 static NTSTATUS drv_query_volume_information(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { 712 PIO_STACK_LOCATION IrpSp; 713 NTSTATUS Status; 714 ULONG BytesCopied = 0; 715 device_extension* Vcb = DeviceObject->DeviceExtension; 716 BOOL top_level; 717 718 FsRtlEnterFileSystem(); 719 720 TRACE("query volume information\n"); 721 top_level = is_top_level(Irp); 722 723 if (Vcb && Vcb->type == VCB_TYPE_VOLUME) { 724 Status = vol_query_volume_information(DeviceObject, Irp); 725 goto end; 726 } else if (!Vcb || Vcb->type != VCB_TYPE_FS) { 727 Status = STATUS_INVALID_PARAMETER; 728 goto end; 729 } 730 731 IrpSp = IoGetCurrentIrpStackLocation(Irp); 732 733 Status = STATUS_NOT_IMPLEMENTED; 734 735 switch (IrpSp->Parameters.QueryVolume.FsInformationClass) { 736 case FileFsAttributeInformation: 737 { 738 FILE_FS_ATTRIBUTE_INFORMATION* data = Irp->AssociatedIrp.SystemBuffer; 739 BOOL overflow = FALSE; 740 #ifndef __REACTOS__ 741 WCHAR* fs_name = (Irp->RequestorMode == UserMode && lie_about_fs_type()) ? L"NTFS" : L"Btrfs"; 742 ULONG fs_name_len = (ULONG)wcslen(fs_name) * sizeof(WCHAR); 743 #else 744 WCHAR* fs_name = L"Btrfs"; 745 ULONG fs_name_len = 5 * sizeof(WCHAR); 746 #endif 747 ULONG orig_fs_name_len = fs_name_len; 748 749 TRACE("FileFsAttributeInformation\n"); 750 751 if (IrpSp->Parameters.QueryVolume.Length < sizeof(FILE_FS_ATTRIBUTE_INFORMATION) - sizeof(WCHAR) + fs_name_len) { 752 if (IrpSp->Parameters.QueryVolume.Length > sizeof(FILE_FS_ATTRIBUTE_INFORMATION) - sizeof(WCHAR)) 753 fs_name_len = IrpSp->Parameters.QueryVolume.Length - sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + sizeof(WCHAR); 754 else 755 fs_name_len = 0; 756 757 overflow = TRUE; 758 } 759 760 data->FileSystemAttributes = FILE_CASE_PRESERVED_NAMES | FILE_CASE_SENSITIVE_SEARCH | 761 FILE_UNICODE_ON_DISK | FILE_NAMED_STREAMS | FILE_SUPPORTS_HARD_LINKS | FILE_PERSISTENT_ACLS | 762 FILE_SUPPORTS_REPARSE_POINTS | FILE_SUPPORTS_SPARSE_FILES | FILE_SUPPORTS_OBJECT_IDS | 763 FILE_SUPPORTS_OPEN_BY_FILE_ID | FILE_SUPPORTS_EXTENDED_ATTRIBUTES | FILE_SUPPORTS_BLOCK_REFCOUNTING; 764 if (Vcb->readonly) 765 data->FileSystemAttributes |= FILE_READ_ONLY_VOLUME; 766 767 // should also be FILE_FILE_COMPRESSION when supported 768 data->MaximumComponentNameLength = 255; // FIXME - check 769 data->FileSystemNameLength = orig_fs_name_len; 770 RtlCopyMemory(data->FileSystemName, fs_name, fs_name_len); 771 772 BytesCopied = sizeof(FILE_FS_ATTRIBUTE_INFORMATION) - sizeof(WCHAR) + fs_name_len; 773 Status = overflow ? STATUS_BUFFER_OVERFLOW : STATUS_SUCCESS; 774 break; 775 } 776 777 case FileFsDeviceInformation: 778 { 779 FILE_FS_DEVICE_INFORMATION* ffdi = Irp->AssociatedIrp.SystemBuffer; 780 781 TRACE("FileFsDeviceInformation\n"); 782 783 ffdi->DeviceType = FILE_DEVICE_DISK; 784 785 ExAcquireResourceSharedLite(&Vcb->tree_lock, TRUE); 786 ffdi->Characteristics = Vcb->Vpb->RealDevice->Characteristics; 787 ExReleaseResourceLite(&Vcb->tree_lock); 788 789 if (Vcb->readonly) 790 ffdi->Characteristics |= FILE_READ_ONLY_DEVICE; 791 else 792 ffdi->Characteristics &= ~FILE_READ_ONLY_DEVICE; 793 794 BytesCopied = sizeof(FILE_FS_DEVICE_INFORMATION); 795 Status = STATUS_SUCCESS; 796 797 break; 798 } 799 800 case FileFsFullSizeInformation: 801 { 802 FILE_FS_FULL_SIZE_INFORMATION* ffsi = Irp->AssociatedIrp.SystemBuffer; 803 804 TRACE("FileFsFullSizeInformation\n"); 805 806 calculate_total_space(Vcb, (UINT64*)&ffsi->TotalAllocationUnits.QuadPart, (UINT64*)&ffsi->ActualAvailableAllocationUnits.QuadPart); 807 ffsi->CallerAvailableAllocationUnits.QuadPart = ffsi->ActualAvailableAllocationUnits.QuadPart; 808 ffsi->SectorsPerAllocationUnit = 1; 809 ffsi->BytesPerSector = Vcb->superblock.sector_size; 810 811 BytesCopied = sizeof(FILE_FS_FULL_SIZE_INFORMATION); 812 Status = STATUS_SUCCESS; 813 814 break; 815 } 816 817 case FileFsObjectIdInformation: 818 { 819 FILE_FS_OBJECTID_INFORMATION* ffoi = Irp->AssociatedIrp.SystemBuffer; 820 821 TRACE("FileFsObjectIdInformation\n"); 822 823 RtlCopyMemory(ffoi->ObjectId, &Vcb->superblock.uuid.uuid[0], sizeof(UCHAR) * 16); 824 RtlZeroMemory(ffoi->ExtendedInfo, sizeof(ffoi->ExtendedInfo)); 825 826 BytesCopied = sizeof(FILE_FS_OBJECTID_INFORMATION); 827 Status = STATUS_SUCCESS; 828 829 break; 830 } 831 832 case FileFsSizeInformation: 833 { 834 FILE_FS_SIZE_INFORMATION* ffsi = Irp->AssociatedIrp.SystemBuffer; 835 836 TRACE("FileFsSizeInformation\n"); 837 838 calculate_total_space(Vcb, (UINT64*)&ffsi->TotalAllocationUnits.QuadPart, (UINT64*)&ffsi->AvailableAllocationUnits.QuadPart); 839 ffsi->SectorsPerAllocationUnit = 1; 840 ffsi->BytesPerSector = Vcb->superblock.sector_size; 841 842 BytesCopied = sizeof(FILE_FS_SIZE_INFORMATION); 843 Status = STATUS_SUCCESS; 844 845 break; 846 } 847 848 case FileFsVolumeInformation: 849 { 850 FILE_FS_VOLUME_INFORMATION* data = Irp->AssociatedIrp.SystemBuffer; 851 FILE_FS_VOLUME_INFORMATION ffvi; 852 BOOL overflow = FALSE; 853 ULONG label_len, orig_label_len; 854 855 TRACE("FileFsVolumeInformation\n"); 856 TRACE("max length = %u\n", IrpSp->Parameters.QueryVolume.Length); 857 858 ExAcquireResourceSharedLite(&Vcb->tree_lock, TRUE); 859 860 Status = RtlUTF8ToUnicodeN(NULL, 0, &label_len, Vcb->superblock.label, (ULONG)strlen(Vcb->superblock.label)); 861 if (!NT_SUCCESS(Status)) { 862 ERR("RtlUTF8ToUnicodeN returned %08x\n", Status); 863 ExReleaseResourceLite(&Vcb->tree_lock); 864 break; 865 } 866 867 orig_label_len = label_len; 868 869 if (IrpSp->Parameters.QueryVolume.Length < sizeof(FILE_FS_VOLUME_INFORMATION) - sizeof(WCHAR) + label_len) { 870 if (IrpSp->Parameters.QueryVolume.Length > sizeof(FILE_FS_VOLUME_INFORMATION) - sizeof(WCHAR)) 871 label_len = IrpSp->Parameters.QueryVolume.Length - sizeof(FILE_FS_VOLUME_INFORMATION) + sizeof(WCHAR); 872 else 873 label_len = 0; 874 875 overflow = TRUE; 876 } 877 878 TRACE("label_len = %u\n", label_len); 879 880 ffvi.VolumeCreationTime.QuadPart = 0; // FIXME 881 ffvi.VolumeSerialNumber = Vcb->superblock.uuid.uuid[12] << 24 | Vcb->superblock.uuid.uuid[13] << 16 | Vcb->superblock.uuid.uuid[14] << 8 | Vcb->superblock.uuid.uuid[15]; 882 ffvi.VolumeLabelLength = orig_label_len; 883 ffvi.SupportsObjects = FALSE; 884 885 RtlCopyMemory(data, &ffvi, min(sizeof(FILE_FS_VOLUME_INFORMATION) - sizeof(WCHAR), IrpSp->Parameters.QueryVolume.Length)); 886 887 if (label_len > 0) { 888 ULONG bytecount; 889 890 Status = RtlUTF8ToUnicodeN(&data->VolumeLabel[0], label_len, &bytecount, Vcb->superblock.label, (ULONG)strlen(Vcb->superblock.label)); 891 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_TOO_SMALL) { 892 ERR("RtlUTF8ToUnicodeN returned %08x\n", Status); 893 ExReleaseResourceLite(&Vcb->tree_lock); 894 break; 895 } 896 897 TRACE("label = %.*S\n", label_len / sizeof(WCHAR), data->VolumeLabel); 898 } 899 900 ExReleaseResourceLite(&Vcb->tree_lock); 901 902 BytesCopied = sizeof(FILE_FS_VOLUME_INFORMATION) - sizeof(WCHAR) + label_len; 903 Status = overflow ? STATUS_BUFFER_OVERFLOW : STATUS_SUCCESS; 904 break; 905 } 906 907 #ifndef __REACTOS__ 908 #ifdef _MSC_VER // not in mingw yet 909 case FileFsSectorSizeInformation: 910 { 911 FILE_FS_SECTOR_SIZE_INFORMATION* data = Irp->AssociatedIrp.SystemBuffer; 912 913 data->LogicalBytesPerSector = Vcb->superblock.sector_size; 914 data->PhysicalBytesPerSectorForAtomicity = Vcb->superblock.sector_size; 915 data->PhysicalBytesPerSectorForPerformance = Vcb->superblock.sector_size; 916 data->FileSystemEffectivePhysicalBytesPerSectorForAtomicity = Vcb->superblock.sector_size; 917 data->ByteOffsetForSectorAlignment = 0; 918 data->ByteOffsetForPartitionAlignment = 0; 919 920 data->Flags = SSINFO_FLAGS_ALIGNED_DEVICE | SSINFO_FLAGS_PARTITION_ALIGNED_ON_DEVICE; 921 922 if (Vcb->trim && !Vcb->options.no_trim) 923 data->Flags |= SSINFO_FLAGS_TRIM_ENABLED; 924 925 BytesCopied = sizeof(FILE_FS_SECTOR_SIZE_INFORMATION); 926 927 break; 928 } 929 #endif 930 #endif /* __REACTOS__ */ 931 932 default: 933 Status = STATUS_INVALID_PARAMETER; 934 WARN("unknown FsInformationClass %u\n", IrpSp->Parameters.QueryVolume.FsInformationClass); 935 break; 936 } 937 938 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW) 939 Irp->IoStatus.Information = 0; 940 else 941 Irp->IoStatus.Information = BytesCopied; 942 943 end: 944 Irp->IoStatus.Status = Status; 945 946 IoCompleteRequest( Irp, IO_DISK_INCREMENT ); 947 948 if (top_level) 949 IoSetTopLevelIrp(NULL); 950 951 TRACE("query volume information returning %08x\n", Status); 952 953 FsRtlExitFileSystem(); 954 955 return Status; 956 } 957 958 _Function_class_(IO_COMPLETION_ROUTINE) 959 #ifdef __REACTOS__ 960 static NTSTATUS NTAPI read_completion(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp, _In_ PVOID conptr) { 961 #else 962 static NTSTATUS read_completion(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp, _In_ PVOID conptr) { 963 #endif 964 read_context* context = conptr; 965 966 UNUSED(DeviceObject); 967 968 context->iosb = Irp->IoStatus; 969 KeSetEvent(&context->Event, 0, FALSE); 970 971 return STATUS_MORE_PROCESSING_REQUIRED; 972 } 973 974 NTSTATUS create_root(_In_ _Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension* Vcb, _In_ UINT64 id, 975 _Out_ root** rootptr, _In_ BOOL no_tree, _In_ UINT64 offset, _In_opt_ PIRP Irp) { 976 NTSTATUS Status; 977 root* r; 978 tree* t = NULL; 979 ROOT_ITEM* ri; 980 traverse_ptr tp; 981 982 r = ExAllocatePoolWithTag(PagedPool, sizeof(root), ALLOC_TAG); 983 if (!r) { 984 ERR("out of memory\n"); 985 return STATUS_INSUFFICIENT_RESOURCES; 986 } 987 988 r->nonpaged = ExAllocatePoolWithTag(NonPagedPool, sizeof(root_nonpaged), ALLOC_TAG); 989 if (!r->nonpaged) { 990 ERR("out of memory\n"); 991 ExFreePool(r); 992 return STATUS_INSUFFICIENT_RESOURCES; 993 } 994 995 if (!no_tree) { 996 t = ExAllocatePoolWithTag(PagedPool, sizeof(tree), ALLOC_TAG); 997 if (!t) { 998 ERR("out of memory\n"); 999 ExFreePool(r->nonpaged); 1000 ExFreePool(r); 1001 return STATUS_INSUFFICIENT_RESOURCES; 1002 } 1003 1004 t->is_unique = TRUE; 1005 t->uniqueness_determined = TRUE; 1006 t->buf = NULL; 1007 } 1008 1009 ri = ExAllocatePoolWithTag(PagedPool, sizeof(ROOT_ITEM), ALLOC_TAG); 1010 if (!ri) { 1011 ERR("out of memory\n"); 1012 1013 if (t) 1014 ExFreePool(t); 1015 1016 ExFreePool(r->nonpaged); 1017 ExFreePool(r); 1018 return STATUS_INSUFFICIENT_RESOURCES; 1019 } 1020 1021 r->id = id; 1022 r->treeholder.address = 0; 1023 r->treeholder.generation = Vcb->superblock.generation; 1024 r->treeholder.tree = t; 1025 r->lastinode = 0; 1026 r->dirty = FALSE; 1027 r->received = FALSE; 1028 r->reserved = NULL; 1029 r->parent = 0; 1030 r->send_ops = 0; 1031 RtlZeroMemory(&r->root_item, sizeof(ROOT_ITEM)); 1032 r->root_item.num_references = 1; 1033 InitializeListHead(&r->fcbs); 1034 1035 RtlCopyMemory(ri, &r->root_item, sizeof(ROOT_ITEM)); 1036 1037 // We ask here for a traverse_ptr to the item we're inserting, so we can 1038 // copy some of the tree's variables 1039 1040 Status = insert_tree_item(Vcb, Vcb->root_root, id, TYPE_ROOT_ITEM, offset, ri, sizeof(ROOT_ITEM), &tp, Irp); 1041 if (!NT_SUCCESS(Status)) { 1042 ERR("insert_tree_item returned %08x\n", Status); 1043 ExFreePool(ri); 1044 1045 if (t) 1046 ExFreePool(t); 1047 1048 ExFreePool(r->nonpaged); 1049 ExFreePool(r); 1050 return Status; 1051 } 1052 1053 ExInitializeResourceLite(&r->nonpaged->load_tree_lock); 1054 1055 InsertTailList(&Vcb->roots, &r->list_entry); 1056 1057 if (!no_tree) { 1058 RtlZeroMemory(&t->header, sizeof(tree_header)); 1059 t->header.fs_uuid = tp.tree->header.fs_uuid; 1060 t->header.address = 0; 1061 t->header.flags = HEADER_FLAG_MIXED_BACKREF | 1; // 1 == "written"? Why does the Linux driver record this? 1062 t->header.chunk_tree_uuid = tp.tree->header.chunk_tree_uuid; 1063 t->header.generation = Vcb->superblock.generation; 1064 t->header.tree_id = id; 1065 t->header.num_items = 0; 1066 t->header.level = 0; 1067 1068 t->has_address = FALSE; 1069 t->size = 0; 1070 t->Vcb = Vcb; 1071 t->parent = NULL; 1072 t->paritem = NULL; 1073 t->root = r; 1074 1075 InitializeListHead(&t->itemlist); 1076 1077 t->new_address = 0; 1078 t->has_new_address = FALSE; 1079 t->updated_extents = FALSE; 1080 1081 InsertTailList(&Vcb->trees, &t->list_entry); 1082 t->list_entry_hash.Flink = NULL; 1083 1084 t->write = TRUE; 1085 Vcb->need_write = TRUE; 1086 } 1087 1088 *rootptr = r; 1089 1090 return STATUS_SUCCESS; 1091 } 1092 1093 static NTSTATUS set_label(_In_ device_extension* Vcb, _In_ FILE_FS_LABEL_INFORMATION* ffli) { 1094 ULONG utf8len; 1095 NTSTATUS Status; 1096 ULONG vollen, i; 1097 1098 TRACE("label = %.*S\n", ffli->VolumeLabelLength / sizeof(WCHAR), ffli->VolumeLabel); 1099 1100 vollen = ffli->VolumeLabelLength; 1101 1102 for (i = 0; i < ffli->VolumeLabelLength / sizeof(WCHAR); i++) { 1103 if (ffli->VolumeLabel[i] == 0) { 1104 vollen = i * sizeof(WCHAR); 1105 break; 1106 } else if (ffli->VolumeLabel[i] == '/' || ffli->VolumeLabel[i] == '\\') { 1107 Status = STATUS_INVALID_VOLUME_LABEL; 1108 goto end; 1109 } 1110 } 1111 1112 if (vollen == 0) { 1113 utf8len = 0; 1114 } else { 1115 Status = RtlUnicodeToUTF8N(NULL, 0, &utf8len, ffli->VolumeLabel, vollen); 1116 if (!NT_SUCCESS(Status)) 1117 goto end; 1118 1119 if (utf8len > MAX_LABEL_SIZE) { 1120 Status = STATUS_INVALID_VOLUME_LABEL; 1121 goto end; 1122 } 1123 } 1124 1125 ExAcquireResourceExclusiveLite(&Vcb->tree_lock, TRUE); 1126 1127 if (utf8len > 0) { 1128 Status = RtlUnicodeToUTF8N((PCHAR)&Vcb->superblock.label, MAX_LABEL_SIZE, &utf8len, ffli->VolumeLabel, vollen); 1129 if (!NT_SUCCESS(Status)) 1130 goto release; 1131 } else 1132 Status = STATUS_SUCCESS; 1133 1134 if (utf8len < MAX_LABEL_SIZE) 1135 RtlZeroMemory(Vcb->superblock.label + utf8len, MAX_LABEL_SIZE - utf8len); 1136 1137 Vcb->need_write = TRUE; 1138 1139 release: 1140 ExReleaseResourceLite(&Vcb->tree_lock); 1141 1142 end: 1143 TRACE("returning %08x\n", Status); 1144 1145 return Status; 1146 } 1147 1148 _Dispatch_type_(IRP_MJ_SET_VOLUME_INFORMATION) 1149 _Function_class_(DRIVER_DISPATCH) 1150 static NTSTATUS drv_set_volume_information(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { 1151 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); 1152 device_extension* Vcb = DeviceObject->DeviceExtension; 1153 NTSTATUS Status; 1154 BOOL top_level; 1155 1156 FsRtlEnterFileSystem(); 1157 1158 TRACE("set volume information\n"); 1159 1160 top_level = is_top_level(Irp); 1161 1162 if (Vcb && Vcb->type == VCB_TYPE_VOLUME) { 1163 Status = vol_set_volume_information(DeviceObject, Irp); 1164 goto end; 1165 } else if (!Vcb || Vcb->type != VCB_TYPE_FS) { 1166 Status = STATUS_INVALID_PARAMETER; 1167 goto end; 1168 } 1169 1170 Status = STATUS_NOT_IMPLEMENTED; 1171 1172 if (Vcb->readonly) { 1173 Status = STATUS_MEDIA_WRITE_PROTECTED; 1174 goto end; 1175 } 1176 1177 if (Vcb->removing || Vcb->locked) { 1178 Status = STATUS_ACCESS_DENIED; 1179 goto end; 1180 } 1181 1182 switch (IrpSp->Parameters.SetVolume.FsInformationClass) { 1183 case FileFsControlInformation: 1184 FIXME("STUB: FileFsControlInformation\n"); 1185 break; 1186 1187 case FileFsLabelInformation: 1188 TRACE("FileFsLabelInformation\n"); 1189 1190 Status = set_label(Vcb, Irp->AssociatedIrp.SystemBuffer); 1191 break; 1192 1193 case FileFsObjectIdInformation: 1194 FIXME("STUB: FileFsObjectIdInformation\n"); 1195 break; 1196 1197 default: 1198 WARN("Unrecognized FsInformationClass 0x%x\n", IrpSp->Parameters.SetVolume.FsInformationClass); 1199 break; 1200 } 1201 1202 end: 1203 Irp->IoStatus.Status = Status; 1204 Irp->IoStatus.Information = 0; 1205 1206 TRACE("returning %08x\n", Status); 1207 1208 IoCompleteRequest( Irp, IO_NO_INCREMENT ); 1209 1210 if (top_level) 1211 IoSetTopLevelIrp(NULL); 1212 1213 FsRtlExitFileSystem(); 1214 1215 return Status; 1216 } 1217 1218 static WCHAR* file_desc_fcb(_In_ fcb* fcb) { 1219 char s[60]; 1220 NTSTATUS Status; 1221 UNICODE_STRING us; 1222 ANSI_STRING as; 1223 1224 if (fcb->debug_desc) 1225 return fcb->debug_desc; 1226 1227 if (fcb == fcb->Vcb->volume_fcb) 1228 return L"volume FCB"; 1229 1230 fcb->debug_desc = ExAllocatePoolWithTag(PagedPool, 60 * sizeof(WCHAR), ALLOC_TAG); 1231 if (!fcb->debug_desc) 1232 return L"(memory error)"; 1233 1234 // I know this is pretty hackish... 1235 // GCC doesn't like %llx in sprintf, and MSVC won't let us use swprintf 1236 // without the CRT, which breaks drivers. 1237 1238 sprintf(s, "subvol %x, inode %x", (UINT32)fcb->subvol->id, (UINT32)fcb->inode); 1239 1240 as.Buffer = s; 1241 as.Length = as.MaximumLength = (USHORT)strlen(s); 1242 1243 us.Buffer = fcb->debug_desc; 1244 us.MaximumLength = 60 * sizeof(WCHAR); 1245 us.Length = 0; 1246 1247 Status = RtlAnsiStringToUnicodeString(&us, &as, FALSE); 1248 if (!NT_SUCCESS(Status)) 1249 return L"(RtlAnsiStringToUnicodeString error)"; 1250 1251 us.Buffer[us.Length / sizeof(WCHAR)] = 0; 1252 1253 return fcb->debug_desc; 1254 } 1255 1256 WCHAR* file_desc_fileref(_In_ file_ref* fileref) { 1257 NTSTATUS Status; 1258 UNICODE_STRING fn; 1259 ULONG reqlen; 1260 1261 if (fileref->debug_desc) 1262 return fileref->debug_desc; 1263 1264 fn.Length = fn.MaximumLength = 0; 1265 Status = fileref_get_filename(fileref, &fn, NULL, &reqlen); 1266 if (Status != STATUS_BUFFER_OVERFLOW) 1267 return L"ERROR"; 1268 1269 if (reqlen > 0xffff - sizeof(WCHAR)) 1270 return L"(too long)"; 1271 1272 fileref->debug_desc = ExAllocatePoolWithTag(PagedPool, reqlen + sizeof(WCHAR), ALLOC_TAG); 1273 if (!fileref->debug_desc) 1274 return L"(memory error)"; 1275 1276 fn.Buffer = fileref->debug_desc; 1277 fn.Length = 0; 1278 fn.MaximumLength = (USHORT)(reqlen + sizeof(WCHAR)); 1279 1280 Status = fileref_get_filename(fileref, &fn, NULL, &reqlen); 1281 if (!NT_SUCCESS(Status)) { 1282 ExFreePool(fileref->debug_desc); 1283 fileref->debug_desc = NULL; 1284 return L"ERROR"; 1285 } 1286 1287 fileref->debug_desc[fn.Length / sizeof(WCHAR)] = 0; 1288 1289 return fileref->debug_desc; 1290 } 1291 1292 _Ret_z_ 1293 WCHAR* file_desc(_In_ PFILE_OBJECT FileObject) { 1294 fcb* fcb = FileObject->FsContext; 1295 ccb* ccb = FileObject->FsContext2; 1296 file_ref* fileref = ccb ? ccb->fileref : NULL; 1297 1298 if (fileref) 1299 return file_desc_fileref(fileref); 1300 else 1301 return file_desc_fcb(fcb); 1302 } 1303 1304 void send_notification_fileref(_In_ file_ref* fileref, _In_ ULONG filter_match, _In_ ULONG action, _In_opt_ PUNICODE_STRING stream) { 1305 UNICODE_STRING fn; 1306 NTSTATUS Status; 1307 ULONG reqlen; 1308 USHORT name_offset; 1309 fcb* fcb = fileref->fcb; 1310 1311 fn.Length = fn.MaximumLength = 0; 1312 Status = fileref_get_filename(fileref, &fn, NULL, &reqlen); 1313 if (Status != STATUS_BUFFER_OVERFLOW) { 1314 ERR("fileref_get_filename returned %08x\n", Status); 1315 return; 1316 } 1317 1318 if (reqlen > 0xffff) { 1319 WARN("reqlen was too long for FsRtlNotifyFilterReportChange\n"); 1320 return; 1321 } 1322 1323 fn.Buffer = ExAllocatePoolWithTag(PagedPool, reqlen, ALLOC_TAG); 1324 if (!fn.Buffer) { 1325 ERR("out of memory\n"); 1326 return; 1327 } 1328 1329 fn.MaximumLength = (USHORT)reqlen; 1330 fn.Length = 0; 1331 1332 Status = fileref_get_filename(fileref, &fn, &name_offset, &reqlen); 1333 if (!NT_SUCCESS(Status)) { 1334 ERR("fileref_get_filename returned %08x\n", Status); 1335 ExFreePool(fn.Buffer); 1336 return; 1337 } 1338 1339 FsRtlNotifyFilterReportChange(fcb->Vcb->NotifySync, &fcb->Vcb->DirNotifyList, (PSTRING)&fn, name_offset, 1340 (PSTRING)stream, NULL, filter_match, action, NULL, NULL); 1341 ExFreePool(fn.Buffer); 1342 } 1343 1344 void send_notification_fcb(_In_ file_ref* fileref, _In_ ULONG filter_match, _In_ ULONG action, _In_opt_ PUNICODE_STRING stream) { 1345 fcb* fcb = fileref->fcb; 1346 LIST_ENTRY* le; 1347 NTSTATUS Status; 1348 1349 // no point looking for hardlinks if st_nlink == 1 1350 if (fileref->fcb->inode_item.st_nlink == 1) { 1351 send_notification_fileref(fileref, filter_match, action, stream); 1352 return; 1353 } 1354 1355 acquire_fcb_lock_exclusive(fcb->Vcb); 1356 1357 le = fcb->hardlinks.Flink; 1358 while (le != &fcb->hardlinks) { 1359 hardlink* hl = CONTAINING_RECORD(le, hardlink, list_entry); 1360 file_ref* parfr; 1361 1362 Status = open_fileref_by_inode(fcb->Vcb, fcb->subvol, hl->parent, &parfr, NULL); 1363 1364 if (!NT_SUCCESS(Status)) 1365 ERR("open_fileref_by_inode returned %08x\n", Status); 1366 else if (!parfr->deleted) { 1367 UNICODE_STRING fn; 1368 ULONG pathlen; 1369 1370 fn.Length = fn.MaximumLength = 0; 1371 Status = fileref_get_filename(parfr, &fn, NULL, &pathlen); 1372 if (Status != STATUS_BUFFER_OVERFLOW) { 1373 ERR("fileref_get_filename returned %08x\n", Status); 1374 free_fileref(fcb->Vcb, parfr); 1375 break; 1376 } 1377 1378 if (parfr != fcb->Vcb->root_fileref) 1379 pathlen += sizeof(WCHAR); 1380 1381 if (pathlen + hl->name.Length > 0xffff) { 1382 WARN("pathlen + hl->name.Length was too long for FsRtlNotifyFilterReportChange\n"); 1383 free_fileref(fcb->Vcb, parfr); 1384 break; 1385 } 1386 1387 fn.MaximumLength = (USHORT)(pathlen + hl->name.Length); 1388 fn.Buffer = ExAllocatePoolWithTag(PagedPool, fn.MaximumLength, ALLOC_TAG); 1389 if (!fn.Buffer) { 1390 ERR("out of memory\n"); 1391 free_fileref(fcb->Vcb, parfr); 1392 break; 1393 } 1394 1395 Status = fileref_get_filename(parfr, &fn, NULL, NULL); 1396 if (!NT_SUCCESS(Status)) { 1397 ERR("fileref_get_filename returned %08x\n", Status); 1398 free_fileref(fcb->Vcb, parfr); 1399 ExFreePool(fn.Buffer); 1400 break; 1401 } 1402 1403 if (parfr != fcb->Vcb->root_fileref) { 1404 fn.Buffer[(pathlen / sizeof(WCHAR)) - 1] = '\\'; 1405 fn.Length += sizeof(WCHAR); 1406 } 1407 1408 RtlCopyMemory(&fn.Buffer[pathlen / sizeof(WCHAR)], hl->name.Buffer, hl->name.Length); 1409 fn.Length += hl->name.Length; 1410 1411 FsRtlNotifyFilterReportChange(fcb->Vcb->NotifySync, &fcb->Vcb->DirNotifyList, (PSTRING)&fn, (USHORT)pathlen, 1412 (PSTRING)stream, NULL, filter_match, action, NULL, NULL); 1413 1414 ExFreePool(fn.Buffer); 1415 1416 free_fileref(fcb->Vcb, parfr); 1417 } 1418 1419 le = le->Flink; 1420 } 1421 1422 release_fcb_lock(fcb->Vcb); 1423 } 1424 1425 void mark_fcb_dirty(_In_ fcb* fcb) { 1426 if (!fcb->dirty) { 1427 #ifdef DEBUG_FCB_REFCOUNTS 1428 LONG rc; 1429 #endif 1430 fcb->dirty = TRUE; 1431 1432 #ifdef DEBUG_FCB_REFCOUNTS 1433 rc = InterlockedIncrement(&fcb->refcount); 1434 WARN("fcb %p: refcount now %i\n", fcb, rc); 1435 #else 1436 InterlockedIncrement(&fcb->refcount); 1437 #endif 1438 1439 ExAcquireResourceExclusiveLite(&fcb->Vcb->dirty_fcbs_lock, TRUE); 1440 InsertTailList(&fcb->Vcb->dirty_fcbs, &fcb->list_entry_dirty); 1441 ExReleaseResourceLite(&fcb->Vcb->dirty_fcbs_lock); 1442 } 1443 1444 fcb->Vcb->need_write = TRUE; 1445 } 1446 1447 void mark_fileref_dirty(_In_ file_ref* fileref) { 1448 if (!fileref->dirty) { 1449 fileref->dirty = TRUE; 1450 increase_fileref_refcount(fileref); 1451 1452 ExAcquireResourceExclusiveLite(&fileref->fcb->Vcb->dirty_filerefs_lock, TRUE); 1453 InsertTailList(&fileref->fcb->Vcb->dirty_filerefs, &fileref->list_entry_dirty); 1454 ExReleaseResourceLite(&fileref->fcb->Vcb->dirty_filerefs_lock); 1455 } 1456 1457 fileref->fcb->Vcb->need_write = TRUE; 1458 } 1459 1460 #ifdef DEBUG_FCB_REFCOUNTS 1461 void _free_fcb(_Requires_exclusive_lock_held_(_Curr_->fcb_lock) _In_ device_extension* Vcb, _Inout_ fcb* fcb, _In_ const char* func) { 1462 #else 1463 void free_fcb(_Requires_exclusive_lock_held_(_Curr_->fcb_lock) _In_ device_extension* Vcb, _Inout_ fcb* fcb) { 1464 #endif 1465 LONG rc; 1466 1467 rc = InterlockedDecrement(&fcb->refcount); 1468 1469 #ifdef DEBUG_FCB_REFCOUNTS 1470 #ifdef DEBUG_LONG_MESSAGES 1471 ERR("fcb %p: refcount now %i (subvol %llx, inode %llx)\n", fcb, rc, fcb->subvol ? fcb->subvol->id : 0, fcb->inode); 1472 #else 1473 ERR("fcb %p: refcount now %i (subvol %llx, inode %llx)\n", fcb, rc, fcb->subvol ? fcb->subvol->id : 0, fcb->inode); 1474 #endif 1475 #endif 1476 1477 if (rc > 0) 1478 return; 1479 1480 if (fcb->list_entry.Flink) 1481 RemoveEntryList(&fcb->list_entry); 1482 1483 if (fcb->list_entry_all.Flink) 1484 RemoveEntryList(&fcb->list_entry_all); 1485 1486 ExDeleteResourceLite(&fcb->nonpaged->resource); 1487 ExDeleteResourceLite(&fcb->nonpaged->paging_resource); 1488 ExDeleteResourceLite(&fcb->nonpaged->dir_children_lock); 1489 1490 ExFreeToNPagedLookasideList(&Vcb->fcb_np_lookaside, fcb->nonpaged); 1491 1492 if (fcb->sd) 1493 ExFreePool(fcb->sd); 1494 1495 if (fcb->adsxattr.Buffer) 1496 ExFreePool(fcb->adsxattr.Buffer); 1497 1498 if (fcb->reparse_xattr.Buffer) 1499 ExFreePool(fcb->reparse_xattr.Buffer); 1500 1501 if (fcb->ea_xattr.Buffer) 1502 ExFreePool(fcb->ea_xattr.Buffer); 1503 1504 if (fcb->adsdata.Buffer) 1505 ExFreePool(fcb->adsdata.Buffer); 1506 1507 if (fcb->debug_desc) 1508 ExFreePool(fcb->debug_desc); 1509 1510 while (!IsListEmpty(&fcb->extents)) { 1511 LIST_ENTRY* le = RemoveHeadList(&fcb->extents); 1512 extent* ext = CONTAINING_RECORD(le, extent, list_entry); 1513 1514 if (ext->csum) 1515 ExFreePool(ext->csum); 1516 1517 ExFreePool(ext); 1518 } 1519 1520 while (!IsListEmpty(&fcb->hardlinks)) { 1521 LIST_ENTRY* le = RemoveHeadList(&fcb->hardlinks); 1522 hardlink* hl = CONTAINING_RECORD(le, hardlink, list_entry); 1523 1524 if (hl->name.Buffer) 1525 ExFreePool(hl->name.Buffer); 1526 1527 if (hl->utf8.Buffer) 1528 ExFreePool(hl->utf8.Buffer); 1529 1530 ExFreePool(hl); 1531 } 1532 1533 while (!IsListEmpty(&fcb->xattrs)) { 1534 xattr* xa = CONTAINING_RECORD(RemoveHeadList(&fcb->xattrs), xattr, list_entry); 1535 1536 ExFreePool(xa); 1537 } 1538 1539 while (!IsListEmpty(&fcb->dir_children_index)) { 1540 LIST_ENTRY* le = RemoveHeadList(&fcb->dir_children_index); 1541 dir_child* dc = CONTAINING_RECORD(le, dir_child, list_entry_index); 1542 1543 ExFreePool(dc->utf8.Buffer); 1544 ExFreePool(dc->name.Buffer); 1545 ExFreePool(dc->name_uc.Buffer); 1546 ExFreePool(dc); 1547 } 1548 1549 if (fcb->hash_ptrs) 1550 ExFreePool(fcb->hash_ptrs); 1551 1552 if (fcb->hash_ptrs_uc) 1553 ExFreePool(fcb->hash_ptrs_uc); 1554 1555 FsRtlUninitializeFileLock(&fcb->lock); 1556 1557 if (fcb->pool_type == NonPagedPool) 1558 ExFreePool(fcb); 1559 else 1560 ExFreeToPagedLookasideList(&Vcb->fcb_lookaside, fcb); 1561 1562 #ifdef DEBUG_FCB_REFCOUNTS 1563 #ifdef DEBUG_LONG_MESSAGES 1564 _debug_message(func, file, line, "freeing fcb %p\n", fcb); 1565 #else 1566 _debug_message(func, "freeing fcb %p\n", fcb); 1567 #endif 1568 #endif 1569 } 1570 1571 void free_fileref(_Requires_exclusive_lock_held_(_Curr_->fcb_lock) _In_ device_extension* Vcb, _Inout_ file_ref* fr) { 1572 LONG rc; 1573 1574 rc = InterlockedDecrement(&fr->refcount); 1575 1576 #ifdef DEBUG_FCB_REFCOUNTS 1577 ERR("fileref %p: refcount now %i\n", fr, rc); 1578 #endif 1579 1580 #ifdef _DEBUG 1581 if (rc < 0) { 1582 ERR("fileref %p: refcount now %i\n", fr, rc); 1583 int3; 1584 } 1585 #endif 1586 1587 if (rc > 0) 1588 return; 1589 1590 if (fr->parent) 1591 ExAcquireResourceExclusiveLite(&fr->parent->nonpaged->children_lock, TRUE); 1592 1593 // FIXME - do we need a file_ref lock? 1594 1595 // FIXME - do delete if needed 1596 1597 if (fr->debug_desc) 1598 ExFreePool(fr->debug_desc); 1599 1600 ExDeleteResourceLite(&fr->nonpaged->children_lock); 1601 ExDeleteResourceLite(&fr->nonpaged->fileref_lock); 1602 1603 ExFreeToNPagedLookasideList(&Vcb->fileref_np_lookaside, fr->nonpaged); 1604 1605 // FIXME - throw error if children not empty 1606 1607 if (fr->fcb->fileref == fr) 1608 fr->fcb->fileref = NULL; 1609 1610 if (fr->dc) { 1611 if (fr->fcb->ads) 1612 fr->dc->size = fr->fcb->adsdata.Length; 1613 1614 fr->dc->fileref = NULL; 1615 } 1616 1617 if (fr->list_entry.Flink) 1618 RemoveEntryList(&fr->list_entry); 1619 1620 if (fr->parent) { 1621 ExReleaseResourceLite(&fr->parent->nonpaged->children_lock); 1622 free_fileref(Vcb, fr->parent); 1623 } 1624 1625 free_fcb(Vcb, fr->fcb); 1626 1627 ExFreeToPagedLookasideList(&Vcb->fileref_lookaside, fr); 1628 } 1629 1630 static NTSTATUS close_file(_In_ PFILE_OBJECT FileObject, _In_ PIRP Irp) { 1631 fcb* fcb; 1632 ccb* ccb; 1633 file_ref* fileref = NULL; 1634 LONG open_files; 1635 device_extension* Vcb; 1636 1637 UNUSED(Irp); 1638 1639 TRACE("FileObject = %p\n", FileObject); 1640 1641 fcb = FileObject->FsContext; 1642 if (!fcb) { 1643 TRACE("FCB was NULL, returning success\n"); 1644 return STATUS_SUCCESS; 1645 } 1646 1647 open_files = InterlockedDecrement(&fcb->Vcb->open_files); 1648 1649 ccb = FileObject->FsContext2; 1650 1651 TRACE("close called for %S (fcb == %p)\n", file_desc(FileObject), fcb); 1652 1653 // FIXME - make sure notification gets sent if file is being deleted 1654 1655 if (ccb) { 1656 if (ccb->query_string.Buffer) 1657 RtlFreeUnicodeString(&ccb->query_string); 1658 1659 if (ccb->filename.Buffer) 1660 ExFreePool(ccb->filename.Buffer); 1661 1662 // FIXME - use refcounts for fileref 1663 fileref = ccb->fileref; 1664 1665 if (fcb->Vcb->running_sends > 0) { 1666 BOOL send_cancelled = FALSE; 1667 1668 ExAcquireResourceExclusiveLite(&fcb->Vcb->send_load_lock, TRUE); 1669 1670 if (ccb->send) { 1671 ccb->send->cancelling = TRUE; 1672 send_cancelled = TRUE; 1673 KeSetEvent(&ccb->send->cleared_event, 0, FALSE); 1674 } 1675 1676 ExReleaseResourceLite(&fcb->Vcb->send_load_lock); 1677 1678 if (send_cancelled) { 1679 while (ccb->send) { 1680 ExAcquireResourceExclusiveLite(&fcb->Vcb->send_load_lock, TRUE); 1681 ExReleaseResourceLite(&fcb->Vcb->send_load_lock); 1682 } 1683 } 1684 } 1685 1686 ExFreePool(ccb); 1687 } 1688 1689 CcUninitializeCacheMap(FileObject, NULL, NULL); 1690 1691 if (open_files == 0 && fcb->Vcb->removing) { 1692 uninit(fcb->Vcb, FALSE); 1693 return STATUS_SUCCESS; 1694 } 1695 1696 if (!(fcb->Vcb->Vpb->Flags & VPB_MOUNTED)) 1697 return STATUS_SUCCESS; 1698 1699 Vcb = fcb->Vcb; 1700 1701 acquire_fcb_lock_exclusive(Vcb); 1702 1703 if (fileref) 1704 free_fileref(fcb->Vcb, fileref); 1705 else 1706 free_fcb(Vcb, fcb); 1707 1708 release_fcb_lock(Vcb); 1709 1710 return STATUS_SUCCESS; 1711 } 1712 1713 void uninit(_In_ device_extension* Vcb, _In_ BOOL flush) { 1714 UINT64 i; 1715 NTSTATUS Status; 1716 LIST_ENTRY* le; 1717 LARGE_INTEGER time; 1718 1719 if (!Vcb->removing) { 1720 ExAcquireResourceExclusiveLite(&Vcb->tree_lock, TRUE); 1721 Vcb->removing = TRUE; 1722 ExReleaseResourceLite(&Vcb->tree_lock); 1723 } 1724 1725 RemoveEntryList(&Vcb->list_entry); 1726 1727 if (Vcb->balance.thread) { 1728 Vcb->balance.paused = FALSE; 1729 Vcb->balance.stopping = TRUE; 1730 KeSetEvent(&Vcb->balance.event, 0, FALSE); 1731 KeWaitForSingleObject(&Vcb->balance.finished, Executive, KernelMode, FALSE, NULL); 1732 } 1733 1734 if (Vcb->scrub.thread) { 1735 Vcb->scrub.paused = FALSE; 1736 Vcb->scrub.stopping = TRUE; 1737 KeSetEvent(&Vcb->scrub.event, 0, FALSE); 1738 KeWaitForSingleObject(&Vcb->scrub.finished, Executive, KernelMode, FALSE, NULL); 1739 } 1740 1741 if (Vcb->running_sends != 0) { 1742 BOOL send_cancelled = FALSE; 1743 1744 ExAcquireResourceExclusiveLite(&Vcb->send_load_lock, TRUE); 1745 1746 le = Vcb->send_ops.Flink; 1747 while (le != &Vcb->send_ops) { 1748 send_info* send = CONTAINING_RECORD(le, send_info, list_entry); 1749 1750 if (!send->cancelling) { 1751 send->cancelling = TRUE; 1752 send_cancelled = TRUE; 1753 send->ccb = NULL; 1754 KeSetEvent(&send->cleared_event, 0, FALSE); 1755 } 1756 1757 le = le->Flink; 1758 } 1759 1760 ExReleaseResourceLite(&Vcb->send_load_lock); 1761 1762 if (send_cancelled) { 1763 while (Vcb->running_sends != 0) { 1764 ExAcquireResourceExclusiveLite(&Vcb->send_load_lock, TRUE); 1765 ExReleaseResourceLite(&Vcb->send_load_lock); 1766 } 1767 } 1768 } 1769 1770 Status = registry_mark_volume_unmounted(&Vcb->superblock.uuid); 1771 if (!NT_SUCCESS(Status) && Status != STATUS_TOO_LATE) 1772 WARN("registry_mark_volume_unmounted returned %08x\n", Status); 1773 1774 if (flush) { 1775 ExAcquireResourceExclusiveLite(&Vcb->tree_lock, TRUE); 1776 1777 if (Vcb->need_write && !Vcb->readonly) { 1778 Status = do_write(Vcb, NULL); 1779 if (!NT_SUCCESS(Status)) 1780 ERR("do_write returned %08x\n", Status); 1781 } 1782 1783 free_trees(Vcb); 1784 1785 ExReleaseResourceLite(&Vcb->tree_lock); 1786 } 1787 1788 for (i = 0; i < Vcb->calcthreads.num_threads; i++) { 1789 Vcb->calcthreads.threads[i].quit = TRUE; 1790 } 1791 1792 KeSetEvent(&Vcb->calcthreads.event, 0, FALSE); 1793 1794 for (i = 0; i < Vcb->calcthreads.num_threads; i++) { 1795 KeWaitForSingleObject(&Vcb->calcthreads.threads[i].finished, Executive, KernelMode, FALSE, NULL); 1796 1797 ZwClose(Vcb->calcthreads.threads[i].handle); 1798 } 1799 1800 ExDeleteResourceLite(&Vcb->calcthreads.lock); 1801 ExFreePool(Vcb->calcthreads.threads); 1802 1803 time.QuadPart = 0; 1804 KeSetTimer(&Vcb->flush_thread_timer, time, NULL); // trigger the timer early 1805 KeWaitForSingleObject(&Vcb->flush_thread_finished, Executive, KernelMode, FALSE, NULL); 1806 1807 acquire_fcb_lock_exclusive(Vcb); 1808 free_fcb(Vcb, Vcb->volume_fcb); 1809 free_fcb(Vcb, Vcb->dummy_fcb); 1810 release_fcb_lock(Vcb); 1811 1812 if (Vcb->root_file) 1813 ObDereferenceObject(Vcb->root_file); 1814 1815 le = Vcb->chunks.Flink; 1816 while (le != &Vcb->chunks) { 1817 chunk* c = CONTAINING_RECORD(le, chunk, list_entry); 1818 1819 if (c->cache) { 1820 acquire_fcb_lock_exclusive(Vcb); 1821 free_fcb(Vcb, c->cache); 1822 release_fcb_lock(Vcb); 1823 c->cache = NULL; 1824 } 1825 1826 le = le->Flink; 1827 } 1828 1829 while (!IsListEmpty(&Vcb->roots)) { 1830 root* r = CONTAINING_RECORD(RemoveHeadList(&Vcb->roots), root, list_entry); 1831 1832 ExDeleteResourceLite(&r->nonpaged->load_tree_lock); 1833 ExFreePool(r->nonpaged); 1834 ExFreePool(r); 1835 } 1836 1837 while (!IsListEmpty(&Vcb->chunks)) { 1838 chunk* c = CONTAINING_RECORD(RemoveHeadList(&Vcb->chunks), chunk, list_entry); 1839 1840 while (!IsListEmpty(&c->space)) { 1841 LIST_ENTRY* le2 = RemoveHeadList(&c->space); 1842 space* s = CONTAINING_RECORD(le2, space, list_entry); 1843 1844 ExFreePool(s); 1845 } 1846 1847 while (!IsListEmpty(&c->deleting)) { 1848 LIST_ENTRY* le2 = RemoveHeadList(&c->deleting); 1849 space* s = CONTAINING_RECORD(le2, space, list_entry); 1850 1851 ExFreePool(s); 1852 } 1853 1854 if (c->devices) 1855 ExFreePool(c->devices); 1856 1857 if (c->cache) { 1858 acquire_fcb_lock_exclusive(Vcb); 1859 free_fcb(Vcb, c->cache); 1860 release_fcb_lock(Vcb); 1861 } 1862 1863 ExDeleteResourceLite(&c->range_locks_lock); 1864 ExDeleteResourceLite(&c->partial_stripes_lock); 1865 ExDeleteResourceLite(&c->lock); 1866 ExDeleteResourceLite(&c->changed_extents_lock); 1867 1868 ExFreePool(c->chunk_item); 1869 ExFreePool(c); 1870 } 1871 1872 // FIXME - free any open fcbs? 1873 1874 while (!IsListEmpty(&Vcb->devices)) { 1875 device* dev = CONTAINING_RECORD(RemoveHeadList(&Vcb->devices), device, list_entry); 1876 1877 while (!IsListEmpty(&dev->space)) { 1878 LIST_ENTRY* le2 = RemoveHeadList(&dev->space); 1879 space* s = CONTAINING_RECORD(le2, space, list_entry); 1880 1881 ExFreePool(s); 1882 } 1883 1884 ExFreePool(dev); 1885 } 1886 1887 ExAcquireResourceExclusiveLite(&Vcb->scrub.stats_lock, TRUE); 1888 while (!IsListEmpty(&Vcb->scrub.errors)) { 1889 scrub_error* err = CONTAINING_RECORD(RemoveHeadList(&Vcb->scrub.errors), scrub_error, list_entry); 1890 1891 ExFreePool(err); 1892 } 1893 ExReleaseResourceLite(&Vcb->scrub.stats_lock); 1894 1895 ExDeleteResourceLite(&Vcb->fcb_lock); 1896 ExDeleteResourceLite(&Vcb->load_lock); 1897 ExDeleteResourceLite(&Vcb->tree_lock); 1898 ExDeleteResourceLite(&Vcb->chunk_lock); 1899 ExDeleteResourceLite(&Vcb->dirty_fcbs_lock); 1900 ExDeleteResourceLite(&Vcb->dirty_filerefs_lock); 1901 ExDeleteResourceLite(&Vcb->dirty_subvols_lock); 1902 ExDeleteResourceLite(&Vcb->scrub.stats_lock); 1903 ExDeleteResourceLite(&Vcb->send_load_lock); 1904 1905 ExDeletePagedLookasideList(&Vcb->tree_data_lookaside); 1906 ExDeletePagedLookasideList(&Vcb->traverse_ptr_lookaside); 1907 ExDeletePagedLookasideList(&Vcb->batch_item_lookaside); 1908 ExDeletePagedLookasideList(&Vcb->fileref_lookaside); 1909 ExDeletePagedLookasideList(&Vcb->fcb_lookaside); 1910 ExDeletePagedLookasideList(&Vcb->name_bit_lookaside); 1911 ExDeleteNPagedLookasideList(&Vcb->range_lock_lookaside); 1912 ExDeleteNPagedLookasideList(&Vcb->fileref_np_lookaside); 1913 ExDeleteNPagedLookasideList(&Vcb->fcb_np_lookaside); 1914 1915 ZwClose(Vcb->flush_thread_handle); 1916 } 1917 1918 NTSTATUS delete_fileref(_In_ file_ref* fileref, _In_opt_ PFILE_OBJECT FileObject, _In_opt_ PIRP Irp, _In_ LIST_ENTRY* rollback) { 1919 LARGE_INTEGER newlength, time; 1920 BTRFS_TIME now; 1921 NTSTATUS Status; 1922 ULONG utf8len = 0; 1923 1924 KeQuerySystemTime(&time); 1925 win_time_to_unix(time, &now); 1926 1927 ExAcquireResourceExclusiveLite(fileref->fcb->Header.Resource, TRUE); 1928 1929 if (fileref->deleted) { 1930 ExReleaseResourceLite(fileref->fcb->Header.Resource); 1931 return STATUS_SUCCESS; 1932 } 1933 1934 if (fileref->fcb->subvol->send_ops > 0) { 1935 ExReleaseResourceLite(fileref->fcb->Header.Resource); 1936 return STATUS_ACCESS_DENIED; 1937 } 1938 1939 fileref->deleted = TRUE; 1940 mark_fileref_dirty(fileref); 1941 1942 // delete INODE_ITEM (0x1) 1943 1944 TRACE("nlink = %u\n", fileref->fcb->inode_item.st_nlink); 1945 1946 if (!fileref->fcb->ads) { 1947 if (fileref->parent->fcb->subvol == fileref->fcb->subvol) { 1948 LIST_ENTRY* le; 1949 1950 mark_fcb_dirty(fileref->fcb); 1951 1952 fileref->fcb->inode_item_changed = TRUE; 1953 1954 if (fileref->fcb->inode_item.st_nlink > 1) { 1955 fileref->fcb->inode_item.st_nlink--; 1956 fileref->fcb->inode_item.transid = fileref->fcb->Vcb->superblock.generation; 1957 fileref->fcb->inode_item.sequence++; 1958 fileref->fcb->inode_item.st_ctime = now; 1959 } else { 1960 // excise extents 1961 1962 if (fileref->fcb->type != BTRFS_TYPE_DIRECTORY && fileref->fcb->inode_item.st_size > 0) { 1963 Status = excise_extents(fileref->fcb->Vcb, fileref->fcb, 0, sector_align(fileref->fcb->inode_item.st_size, fileref->fcb->Vcb->superblock.sector_size), Irp, rollback); 1964 if (!NT_SUCCESS(Status)) { 1965 ERR("excise_extents returned %08x\n", Status); 1966 ExReleaseResourceLite(fileref->fcb->Header.Resource); 1967 return Status; 1968 } 1969 } 1970 1971 fileref->fcb->Header.AllocationSize.QuadPart = 0; 1972 fileref->fcb->Header.FileSize.QuadPart = 0; 1973 fileref->fcb->Header.ValidDataLength.QuadPart = 0; 1974 1975 if (FileObject) { 1976 CC_FILE_SIZES ccfs; 1977 1978 ccfs.AllocationSize = fileref->fcb->Header.AllocationSize; 1979 ccfs.FileSize = fileref->fcb->Header.FileSize; 1980 ccfs.ValidDataLength = fileref->fcb->Header.ValidDataLength; 1981 1982 Status = STATUS_SUCCESS; 1983 1984 _SEH2_TRY { 1985 CcSetFileSizes(FileObject, &ccfs); 1986 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) { 1987 Status = _SEH2_GetExceptionCode(); 1988 } _SEH2_END; 1989 1990 if (!NT_SUCCESS(Status)) { 1991 ERR("CcSetFileSizes threw exception %08x\n", Status); 1992 ExReleaseResourceLite(fileref->fcb->Header.Resource); 1993 return Status; 1994 } 1995 } 1996 1997 fileref->fcb->deleted = TRUE; 1998 1999 le = fileref->children.Flink; 2000 while (le != &fileref->children) { 2001 file_ref* fr2 = CONTAINING_RECORD(le, file_ref, list_entry); 2002 2003 if (fr2->fcb->ads) { 2004 fr2->fcb->deleted = TRUE; 2005 mark_fcb_dirty(fr2->fcb); 2006 } 2007 2008 le = le->Flink; 2009 } 2010 } 2011 2012 if (fileref->dc) { 2013 le = fileref->fcb->hardlinks.Flink; 2014 while (le != &fileref->fcb->hardlinks) { 2015 hardlink* hl = CONTAINING_RECORD(le, hardlink, list_entry); 2016 2017 if (hl->parent == fileref->parent->fcb->inode && hl->index == fileref->dc->index) { 2018 RemoveEntryList(&hl->list_entry); 2019 2020 if (hl->name.Buffer) 2021 ExFreePool(hl->name.Buffer); 2022 2023 if (hl->utf8.Buffer) 2024 ExFreePool(hl->utf8.Buffer); 2025 2026 ExFreePool(hl); 2027 break; 2028 } 2029 2030 le = le->Flink; 2031 } 2032 } 2033 } else if (fileref->fcb->subvol->parent == fileref->parent->fcb->subvol->id) { // valid subvolume 2034 if (fileref->fcb->subvol->root_item.num_references > 1) { 2035 fileref->fcb->subvol->root_item.num_references--; 2036 2037 mark_fcb_dirty(fileref->fcb); // so ROOT_ITEM gets updated 2038 } else { 2039 LIST_ENTRY* le; 2040 2041 // FIXME - we need a lock here 2042 2043 RemoveEntryList(&fileref->fcb->subvol->list_entry); 2044 2045 InsertTailList(&fileref->fcb->Vcb->drop_roots, &fileref->fcb->subvol->list_entry); 2046 2047 le = fileref->children.Flink; 2048 while (le != &fileref->children) { 2049 file_ref* fr2 = CONTAINING_RECORD(le, file_ref, list_entry); 2050 2051 if (fr2->fcb->ads) { 2052 fr2->fcb->deleted = TRUE; 2053 mark_fcb_dirty(fr2->fcb); 2054 } 2055 2056 le = le->Flink; 2057 } 2058 } 2059 } 2060 } else { 2061 fileref->fcb->deleted = TRUE; 2062 mark_fcb_dirty(fileref->fcb); 2063 } 2064 2065 // remove dir_child from parent 2066 2067 if (fileref->dc) { 2068 TRACE("delete file %.*S\n", fileref->dc->name.Length / sizeof(WCHAR), fileref->dc->name.Buffer); 2069 2070 ExAcquireResourceExclusiveLite(&fileref->parent->fcb->nonpaged->dir_children_lock, TRUE); 2071 RemoveEntryList(&fileref->dc->list_entry_index); 2072 2073 if (!fileref->fcb->ads) 2074 remove_dir_child_from_hash_lists(fileref->parent->fcb, fileref->dc); 2075 2076 ExReleaseResourceLite(&fileref->parent->fcb->nonpaged->dir_children_lock); 2077 2078 if (!fileref->oldutf8.Buffer) 2079 fileref->oldutf8 = fileref->dc->utf8; 2080 else 2081 ExFreePool(fileref->dc->utf8.Buffer); 2082 2083 utf8len = fileref->dc->utf8.Length; 2084 2085 fileref->oldindex = fileref->dc->index; 2086 2087 ExFreePool(fileref->dc->name.Buffer); 2088 ExFreePool(fileref->dc->name_uc.Buffer); 2089 ExFreePool(fileref->dc); 2090 2091 fileref->dc = NULL; 2092 } 2093 2094 // update INODE_ITEM of parent 2095 2096 ExAcquireResourceExclusiveLite(fileref->parent->fcb->Header.Resource, TRUE); 2097 2098 fileref->parent->fcb->inode_item.transid = fileref->fcb->Vcb->superblock.generation; 2099 fileref->parent->fcb->inode_item.sequence++; 2100 fileref->parent->fcb->inode_item.st_ctime = now; 2101 2102 if (!fileref->fcb->ads) { 2103 TRACE("fileref->parent->fcb->inode_item.st_size (inode %llx) was %llx\n", fileref->parent->fcb->inode, fileref->parent->fcb->inode_item.st_size); 2104 fileref->parent->fcb->inode_item.st_size -= utf8len * 2; 2105 TRACE("fileref->parent->fcb->inode_item.st_size (inode %llx) now %llx\n", fileref->parent->fcb->inode, fileref->parent->fcb->inode_item.st_size); 2106 fileref->parent->fcb->inode_item.st_mtime = now; 2107 } 2108 2109 fileref->parent->fcb->inode_item_changed = TRUE; 2110 ExReleaseResourceLite(fileref->parent->fcb->Header.Resource); 2111 2112 if (!fileref->fcb->ads && fileref->parent->dc) 2113 send_notification_fcb(fileref->parent, FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_ACTION_MODIFIED, NULL); 2114 2115 mark_fcb_dirty(fileref->parent->fcb); 2116 2117 fileref->fcb->subvol->root_item.ctransid = fileref->fcb->Vcb->superblock.generation; 2118 fileref->fcb->subvol->root_item.ctime = now; 2119 2120 newlength.QuadPart = 0; 2121 2122 if (FileObject && !CcUninitializeCacheMap(FileObject, &newlength, NULL)) 2123 TRACE("CcUninitializeCacheMap failed\n"); 2124 2125 ExReleaseResourceLite(fileref->fcb->Header.Resource); 2126 2127 return STATUS_SUCCESS; 2128 } 2129 2130 _Dispatch_type_(IRP_MJ_CLEANUP) 2131 _Function_class_(DRIVER_DISPATCH) 2132 static NTSTATUS drv_cleanup(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { 2133 NTSTATUS Status; 2134 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); 2135 PFILE_OBJECT FileObject = IrpSp->FileObject; 2136 device_extension* Vcb = DeviceObject->DeviceExtension; 2137 fcb* fcb = FileObject->FsContext; 2138 BOOL top_level; 2139 2140 FsRtlEnterFileSystem(); 2141 2142 TRACE("cleanup\n"); 2143 2144 top_level = is_top_level(Irp); 2145 2146 if (Vcb && Vcb->type == VCB_TYPE_VOLUME) { 2147 Status = vol_cleanup(DeviceObject, Irp); 2148 goto exit; 2149 } else if (DeviceObject == master_devobj) { 2150 TRACE("closing file system\n"); 2151 Status = STATUS_SUCCESS; 2152 goto exit; 2153 } else if (!Vcb || Vcb->type != VCB_TYPE_FS) { 2154 Status = STATUS_INVALID_PARAMETER; 2155 goto exit; 2156 } 2157 2158 if (FileObject->Flags & FO_CLEANUP_COMPLETE) { 2159 TRACE("FileObject %p already cleaned up\n", FileObject); 2160 Status = STATUS_SUCCESS; 2161 goto exit; 2162 } 2163 2164 if (!fcb) { 2165 ERR("fcb was NULL\n"); 2166 Status = STATUS_INVALID_PARAMETER; 2167 goto exit; 2168 } 2169 2170 // We have to use the pointer to Vcb stored in the fcb, as we can receive cleanup 2171 // messages belonging to other devices. 2172 2173 if (FileObject && FileObject->FsContext) { 2174 LONG oc; 2175 ccb* ccb; 2176 file_ref* fileref; 2177 BOOL locked = TRUE; 2178 2179 ccb = FileObject->FsContext2; 2180 fileref = ccb ? ccb->fileref : NULL; 2181 2182 TRACE("cleanup called for FileObject %p\n", FileObject); 2183 TRACE("fileref %p (%S), refcount = %u, open_count = %u\n", fileref, file_desc(FileObject), fileref ? fileref->refcount : 0, fileref ? fileref->open_count : 0); 2184 2185 ExAcquireResourceSharedLite(&fcb->Vcb->tree_lock, TRUE); 2186 2187 ExAcquireResourceExclusiveLite(fcb->Header.Resource, TRUE); 2188 2189 IoRemoveShareAccess(FileObject, &fcb->share_access); 2190 2191 if (ccb) 2192 FsRtlNotifyCleanup(fcb->Vcb->NotifySync, &fcb->Vcb->DirNotifyList, ccb); 2193 2194 if (fileref) { 2195 oc = InterlockedDecrement(&fileref->open_count); 2196 #ifdef DEBUG_FCB_REFCOUNTS 2197 ERR("fileref %p: open_count now %i\n", fileref, oc); 2198 #endif 2199 } 2200 2201 if (ccb && ccb->options & FILE_DELETE_ON_CLOSE && fileref) 2202 fileref->delete_on_close = TRUE; 2203 2204 if (fileref && fileref->delete_on_close && fcb->type == BTRFS_TYPE_DIRECTORY && fcb->inode_item.st_size > 0 && fcb != fcb->Vcb->dummy_fcb) 2205 fileref->delete_on_close = FALSE; 2206 2207 if (fcb->Vcb->locked && fcb->Vcb->locked_fileobj == FileObject) { 2208 TRACE("unlocking volume\n"); 2209 do_unlock_volume(fcb->Vcb); 2210 FsRtlNotifyVolumeEvent(FileObject, FSRTL_VOLUME_UNLOCK); 2211 } 2212 2213 if (ccb && ccb->reserving) { 2214 fcb->subvol->reserved = NULL; 2215 ccb->reserving = FALSE; 2216 // FIXME - flush all of subvol's fcbs 2217 } 2218 2219 if (fileref && oc == 0) { 2220 if (!fcb->Vcb->removing) { 2221 if (fileref && fileref->delete_on_close && fileref != fcb->Vcb->root_fileref && fcb != fcb->Vcb->volume_fcb) { 2222 LIST_ENTRY rollback; 2223 2224 InitializeListHead(&rollback); 2225 2226 if (!fileref->fcb->ads || fileref->dc) { 2227 if (fileref->fcb->ads) { 2228 send_notification_fileref(fileref->parent, fcb->type == BTRFS_TYPE_DIRECTORY ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, 2229 FILE_ACTION_REMOVED, &fileref->dc->name); 2230 } else 2231 send_notification_fileref(fileref, fcb->type == BTRFS_TYPE_DIRECTORY ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_REMOVED, NULL); 2232 } 2233 2234 ExReleaseResourceLite(fcb->Header.Resource); 2235 locked = FALSE; 2236 2237 // fcb_lock needs to be acquired before fcb->Header.Resource 2238 acquire_fcb_lock_exclusive(fcb->Vcb); 2239 2240 Status = delete_fileref(fileref, FileObject, Irp, &rollback); 2241 if (!NT_SUCCESS(Status)) { 2242 ERR("delete_fileref returned %08x\n", Status); 2243 do_rollback(fcb->Vcb, &rollback); 2244 release_fcb_lock(fcb->Vcb); 2245 ExReleaseResourceLite(&fcb->Vcb->tree_lock); 2246 goto exit; 2247 } 2248 2249 release_fcb_lock(fcb->Vcb); 2250 2251 locked = FALSE; 2252 2253 clear_rollback(&rollback); 2254 } else if (FileObject->Flags & FO_CACHE_SUPPORTED && fcb->nonpaged->segment_object.DataSectionObject) { 2255 IO_STATUS_BLOCK iosb; 2256 CcFlushCache(FileObject->SectionObjectPointer, NULL, 0, &iosb); 2257 2258 if (!NT_SUCCESS(iosb.Status)) { 2259 ERR("CcFlushCache returned %08x\n", iosb.Status); 2260 } 2261 2262 if (!ExIsResourceAcquiredSharedLite(fcb->Header.PagingIoResource)) { 2263 ExAcquireResourceExclusiveLite(fcb->Header.PagingIoResource, TRUE); 2264 ExReleaseResourceLite(fcb->Header.PagingIoResource); 2265 } 2266 2267 CcPurgeCacheSection(&fcb->nonpaged->segment_object, NULL, 0, FALSE); 2268 2269 TRACE("flushed cache on close (FileObject = %p, fcb = %p, AllocationSize = %llx, FileSize = %llx, ValidDataLength = %llx)\n", 2270 FileObject, fcb, fcb->Header.AllocationSize.QuadPart, fcb->Header.FileSize.QuadPart, fcb->Header.ValidDataLength.QuadPart); 2271 } 2272 } 2273 2274 if (fcb->Vcb && fcb != fcb->Vcb->volume_fcb) 2275 CcUninitializeCacheMap(FileObject, NULL, NULL); 2276 } 2277 2278 if (locked) 2279 ExReleaseResourceLite(fcb->Header.Resource); 2280 2281 ExReleaseResourceLite(&fcb->Vcb->tree_lock); 2282 2283 FileObject->Flags |= FO_CLEANUP_COMPLETE; 2284 } 2285 2286 Status = STATUS_SUCCESS; 2287 2288 exit: 2289 TRACE("returning %08x\n", Status); 2290 2291 Irp->IoStatus.Status = Status; 2292 Irp->IoStatus.Information = 0; 2293 2294 IoCompleteRequest(Irp, IO_NO_INCREMENT); 2295 2296 if (top_level) 2297 IoSetTopLevelIrp(NULL); 2298 2299 FsRtlExitFileSystem(); 2300 2301 return Status; 2302 } 2303 2304 _Success_(return) 2305 BOOL get_file_attributes_from_xattr(_In_reads_bytes_(len) char* val, _In_ UINT16 len, _Out_ ULONG* atts) { 2306 if (len > 2 && val[0] == '0' && val[1] == 'x') { 2307 int i; 2308 ULONG dosnum = 0; 2309 2310 for (i = 2; i < len; i++) { 2311 dosnum *= 0x10; 2312 2313 if (val[i] >= '0' && val[i] <= '9') 2314 dosnum |= val[i] - '0'; 2315 else if (val[i] >= 'a' && val[i] <= 'f') 2316 dosnum |= val[i] + 10 - 'a'; 2317 else if (val[i] >= 'A' && val[i] <= 'F') 2318 dosnum |= val[i] + 10 - 'a'; 2319 } 2320 2321 TRACE("DOSATTRIB: %08x\n", dosnum); 2322 2323 *atts = dosnum; 2324 2325 return TRUE; 2326 } 2327 2328 return FALSE; 2329 } 2330 2331 ULONG get_file_attributes(_In_ _Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, _In_ root* r, _In_ UINT64 inode, 2332 _In_ UINT8 type, _In_ BOOL dotfile, _In_ BOOL ignore_xa, _In_opt_ PIRP Irp) { 2333 ULONG att; 2334 char* eaval; 2335 UINT16 ealen; 2336 2337 if (!ignore_xa && get_xattr(Vcb, r, inode, EA_DOSATTRIB, EA_DOSATTRIB_HASH, (UINT8**)&eaval, &ealen, Irp)) { 2338 ULONG dosnum = 0; 2339 2340 if (get_file_attributes_from_xattr(eaval, ealen, &dosnum)) { 2341 ExFreePool(eaval); 2342 2343 if (type == BTRFS_TYPE_DIRECTORY) 2344 dosnum |= FILE_ATTRIBUTE_DIRECTORY; 2345 else if (type == BTRFS_TYPE_SYMLINK) 2346 dosnum |= FILE_ATTRIBUTE_REPARSE_POINT; 2347 2348 if (type != BTRFS_TYPE_DIRECTORY) 2349 dosnum &= ~FILE_ATTRIBUTE_DIRECTORY; 2350 2351 if (inode == SUBVOL_ROOT_INODE) { 2352 if (r->root_item.flags & BTRFS_SUBVOL_READONLY) 2353 dosnum |= FILE_ATTRIBUTE_READONLY; 2354 else 2355 dosnum &= ~FILE_ATTRIBUTE_READONLY; 2356 } 2357 2358 return dosnum; 2359 } 2360 2361 ExFreePool(eaval); 2362 } 2363 2364 switch (type) { 2365 case BTRFS_TYPE_DIRECTORY: 2366 att = FILE_ATTRIBUTE_DIRECTORY; 2367 break; 2368 2369 case BTRFS_TYPE_SYMLINK: 2370 att = FILE_ATTRIBUTE_REPARSE_POINT; 2371 break; 2372 2373 default: 2374 att = 0; 2375 break; 2376 } 2377 2378 if (dotfile) { 2379 att |= FILE_ATTRIBUTE_HIDDEN; 2380 } 2381 2382 att |= FILE_ATTRIBUTE_ARCHIVE; 2383 2384 if (inode == SUBVOL_ROOT_INODE) { 2385 if (r->root_item.flags & BTRFS_SUBVOL_READONLY) 2386 att |= FILE_ATTRIBUTE_READONLY; 2387 else 2388 att &= ~FILE_ATTRIBUTE_READONLY; 2389 } 2390 2391 // FIXME - get READONLY from ii->st_mode 2392 // FIXME - return SYSTEM for block/char devices? 2393 2394 if (att == 0) 2395 att = FILE_ATTRIBUTE_NORMAL; 2396 2397 return att; 2398 } 2399 2400 NTSTATUS sync_read_phys(_In_ PDEVICE_OBJECT DeviceObject, _In_ UINT64 StartingOffset, _In_ ULONG Length, 2401 _Out_writes_bytes_(Length) PUCHAR Buffer, _In_ BOOL override) { 2402 IO_STATUS_BLOCK IoStatus; 2403 LARGE_INTEGER Offset; 2404 PIRP Irp; 2405 PIO_STACK_LOCATION IrpSp; 2406 NTSTATUS Status; 2407 read_context context; 2408 2409 num_reads++; 2410 2411 RtlZeroMemory(&context, sizeof(read_context)); 2412 KeInitializeEvent(&context.Event, NotificationEvent, FALSE); 2413 2414 Offset.QuadPart = (LONGLONG)StartingOffset; 2415 2416 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); 2417 2418 if (!Irp) { 2419 ERR("IoAllocateIrp failed\n"); 2420 return STATUS_INSUFFICIENT_RESOURCES; 2421 } 2422 2423 Irp->Flags |= IRP_NOCACHE; 2424 IrpSp = IoGetNextIrpStackLocation(Irp); 2425 IrpSp->MajorFunction = IRP_MJ_READ; 2426 2427 if (override) 2428 IrpSp->Flags |= SL_OVERRIDE_VERIFY_VOLUME; 2429 2430 if (DeviceObject->Flags & DO_BUFFERED_IO) { 2431 Irp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithTag(NonPagedPool, Length, ALLOC_TAG); 2432 if (!Irp->AssociatedIrp.SystemBuffer) { 2433 ERR("out of memory\n"); 2434 Status = STATUS_INSUFFICIENT_RESOURCES; 2435 goto exit; 2436 } 2437 2438 Irp->Flags |= IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER | IRP_INPUT_OPERATION; 2439 2440 Irp->UserBuffer = Buffer; 2441 } else if (DeviceObject->Flags & DO_DIRECT_IO) { 2442 Irp->MdlAddress = IoAllocateMdl(Buffer, Length, FALSE, FALSE, NULL); 2443 if (!Irp->MdlAddress) { 2444 ERR("IoAllocateMdl failed\n"); 2445 Status = STATUS_INSUFFICIENT_RESOURCES; 2446 goto exit; 2447 } 2448 2449 Status = STATUS_SUCCESS; 2450 2451 _SEH2_TRY { 2452 MmProbeAndLockPages(Irp->MdlAddress, KernelMode, IoWriteAccess); 2453 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) { 2454 Status = _SEH2_GetExceptionCode(); 2455 } _SEH2_END; 2456 2457 if (!NT_SUCCESS(Status)) { 2458 ERR("MmProbeAndLockPages threw exception %08x\n", Status); 2459 IoFreeMdl(Irp->MdlAddress); 2460 goto exit; 2461 } 2462 } else 2463 Irp->UserBuffer = Buffer; 2464 2465 IrpSp->Parameters.Read.Length = Length; 2466 IrpSp->Parameters.Read.ByteOffset = Offset; 2467 2468 Irp->UserIosb = &IoStatus; 2469 2470 Irp->UserEvent = &context.Event; 2471 2472 IoSetCompletionRoutine(Irp, read_completion, &context, TRUE, TRUE, TRUE); 2473 2474 Status = IoCallDriver(DeviceObject, Irp); 2475 2476 if (Status == STATUS_PENDING) { 2477 KeWaitForSingleObject(&context.Event, Executive, KernelMode, FALSE, NULL); 2478 Status = context.iosb.Status; 2479 } 2480 2481 if (DeviceObject->Flags & DO_DIRECT_IO) { 2482 MmUnlockPages(Irp->MdlAddress); 2483 IoFreeMdl(Irp->MdlAddress); 2484 } 2485 2486 exit: 2487 IoFreeIrp(Irp); 2488 2489 return Status; 2490 } 2491 2492 static NTSTATUS read_superblock(_In_ device_extension* Vcb, _In_ PDEVICE_OBJECT device, _In_ UINT64 length) { 2493 NTSTATUS Status; 2494 superblock* sb; 2495 ULONG i, to_read; 2496 UINT8 valid_superblocks; 2497 2498 to_read = device->SectorSize == 0 ? sizeof(superblock) : (ULONG)sector_align(sizeof(superblock), device->SectorSize); 2499 2500 sb = ExAllocatePoolWithTag(NonPagedPool, to_read, ALLOC_TAG); 2501 if (!sb) { 2502 ERR("out of memory\n"); 2503 return STATUS_INSUFFICIENT_RESOURCES; 2504 } 2505 2506 if (superblock_addrs[0] + to_read > length) { 2507 WARN("device was too short to have any superblock\n"); 2508 ExFreePool(sb); 2509 return STATUS_UNRECOGNIZED_VOLUME; 2510 } 2511 2512 i = 0; 2513 valid_superblocks = 0; 2514 2515 while (superblock_addrs[i] > 0) { 2516 UINT32 crc32; 2517 2518 if (i > 0 && superblock_addrs[i] + to_read > length) 2519 break; 2520 2521 Status = sync_read_phys(device, superblock_addrs[i], to_read, (PUCHAR)sb, FALSE); 2522 if (!NT_SUCCESS(Status)) { 2523 ERR("Failed to read superblock %u: %08x\n", i, Status); 2524 ExFreePool(sb); 2525 return Status; 2526 } 2527 2528 if (sb->magic != BTRFS_MAGIC) { 2529 if (i == 0) { 2530 TRACE("not a BTRFS volume\n"); 2531 ExFreePool(sb); 2532 return STATUS_UNRECOGNIZED_VOLUME; 2533 } 2534 } else { 2535 TRACE("got superblock %u!\n", i); 2536 2537 crc32 = ~calc_crc32c(0xffffffff, (UINT8*)&sb->uuid, (ULONG)sizeof(superblock) - sizeof(sb->checksum)); 2538 2539 if (crc32 != *((UINT32*)sb->checksum)) 2540 WARN("crc32 was %08x, expected %08x\n", crc32, *((UINT32*)sb->checksum)); 2541 else if (sb->sector_size == 0) 2542 WARN("superblock sector size was 0\n"); 2543 else if (sb->node_size < sizeof(tree_header) + sizeof(internal_node) || sb->node_size > 0x10000) 2544 WARN("invalid node size %x\n", sb->node_size); 2545 else if ((sb->node_size % sb->sector_size) != 0) 2546 WARN("node size %x was not a multiple of sector_size %x\n", sb->node_size, sb->sector_size); 2547 else if (valid_superblocks == 0 || sb->generation > Vcb->superblock.generation) { 2548 RtlCopyMemory(&Vcb->superblock, sb, sizeof(superblock)); 2549 valid_superblocks++; 2550 } 2551 } 2552 2553 i++; 2554 } 2555 2556 ExFreePool(sb); 2557 2558 if (valid_superblocks == 0) { 2559 ERR("could not find any valid superblocks\n"); 2560 return STATUS_INTERNAL_ERROR; 2561 } 2562 2563 TRACE("label is %s\n", Vcb->superblock.label); 2564 2565 return STATUS_SUCCESS; 2566 } 2567 2568 NTSTATUS dev_ioctl(_In_ PDEVICE_OBJECT DeviceObject, _In_ ULONG ControlCode, _In_reads_bytes_opt_(InputBufferSize) PVOID InputBuffer, _In_ ULONG InputBufferSize, 2569 _Out_writes_bytes_opt_(OutputBufferSize) PVOID OutputBuffer, _In_ ULONG OutputBufferSize, _In_ BOOLEAN Override, _Out_opt_ IO_STATUS_BLOCK* iosb) { 2570 PIRP Irp; 2571 KEVENT Event; 2572 NTSTATUS Status; 2573 PIO_STACK_LOCATION IrpSp; 2574 IO_STATUS_BLOCK IoStatus; 2575 2576 KeInitializeEvent(&Event, NotificationEvent, FALSE); 2577 2578 Irp = IoBuildDeviceIoControlRequest(ControlCode, 2579 DeviceObject, 2580 InputBuffer, 2581 InputBufferSize, 2582 OutputBuffer, 2583 OutputBufferSize, 2584 FALSE, 2585 &Event, 2586 &IoStatus); 2587 2588 if (!Irp) return STATUS_INSUFFICIENT_RESOURCES; 2589 2590 if (Override) { 2591 IrpSp = IoGetNextIrpStackLocation(Irp); 2592 IrpSp->Flags |= SL_OVERRIDE_VERIFY_VOLUME; 2593 } 2594 2595 Status = IoCallDriver(DeviceObject, Irp); 2596 2597 if (Status == STATUS_PENDING) { 2598 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 2599 Status = IoStatus.Status; 2600 } 2601 2602 if (iosb) 2603 *iosb = IoStatus; 2604 2605 return Status; 2606 } 2607 2608 _Requires_exclusive_lock_held_(Vcb->tree_lock) 2609 static NTSTATUS add_root(_Inout_ device_extension* Vcb, _In_ UINT64 id, _In_ UINT64 addr, 2610 _In_ UINT64 generation, _In_opt_ traverse_ptr* tp) { 2611 root* r = ExAllocatePoolWithTag(PagedPool, sizeof(root), ALLOC_TAG); 2612 if (!r) { 2613 ERR("out of memory\n"); 2614 return STATUS_INSUFFICIENT_RESOURCES; 2615 } 2616 2617 r->id = id; 2618 r->dirty = FALSE; 2619 r->received = FALSE; 2620 r->reserved = NULL; 2621 r->treeholder.address = addr; 2622 r->treeholder.tree = NULL; 2623 r->treeholder.generation = generation; 2624 r->parent = 0; 2625 r->send_ops = 0; 2626 InitializeListHead(&r->fcbs); 2627 2628 r->nonpaged = ExAllocatePoolWithTag(NonPagedPool, sizeof(root_nonpaged), ALLOC_TAG); 2629 if (!r->nonpaged) { 2630 ERR("out of memory\n"); 2631 ExFreePool(r); 2632 return STATUS_INSUFFICIENT_RESOURCES; 2633 } 2634 2635 ExInitializeResourceLite(&r->nonpaged->load_tree_lock); 2636 2637 r->lastinode = 0; 2638 2639 if (tp) { 2640 RtlCopyMemory(&r->root_item, tp->item->data, min(sizeof(ROOT_ITEM), tp->item->size)); 2641 if (tp->item->size < sizeof(ROOT_ITEM)) 2642 RtlZeroMemory(((UINT8*)&r->root_item) + tp->item->size, sizeof(ROOT_ITEM) - tp->item->size); 2643 } else 2644 RtlZeroMemory(&r->root_item, sizeof(ROOT_ITEM)); 2645 2646 if (!Vcb->readonly && (r->id == BTRFS_ROOT_ROOT || r->id == BTRFS_ROOT_FSTREE || (r->id >= 0x100 && !(r->id & 0xf000000000000000)))) { // FS tree root 2647 // FIXME - don't call this if subvol is readonly (though we will have to if we ever toggle this flag) 2648 get_last_inode(Vcb, r, NULL); 2649 2650 if (r->id == BTRFS_ROOT_ROOT && r->lastinode < 0x100) 2651 r->lastinode = 0x100; 2652 } 2653 2654 InsertTailList(&Vcb->roots, &r->list_entry); 2655 2656 switch (r->id) { 2657 case BTRFS_ROOT_ROOT: 2658 Vcb->root_root = r; 2659 break; 2660 2661 case BTRFS_ROOT_EXTENT: 2662 Vcb->extent_root = r; 2663 break; 2664 2665 case BTRFS_ROOT_CHUNK: 2666 Vcb->chunk_root = r; 2667 break; 2668 2669 case BTRFS_ROOT_DEVTREE: 2670 Vcb->dev_root = r; 2671 break; 2672 2673 case BTRFS_ROOT_CHECKSUM: 2674 Vcb->checksum_root = r; 2675 break; 2676 2677 case BTRFS_ROOT_UUID: 2678 Vcb->uuid_root = r; 2679 break; 2680 2681 case BTRFS_ROOT_FREE_SPACE: 2682 Vcb->space_root = r; 2683 break; 2684 2685 case BTRFS_ROOT_DATA_RELOC: 2686 Vcb->data_reloc_root = r; 2687 break; 2688 } 2689 2690 return STATUS_SUCCESS; 2691 } 2692 2693 static NTSTATUS look_for_roots(_Requires_exclusive_lock_held_(_Curr_->tree_lock) _In_ device_extension* Vcb, _In_opt_ PIRP Irp) { 2694 traverse_ptr tp, next_tp; 2695 KEY searchkey; 2696 BOOL b; 2697 NTSTATUS Status; 2698 2699 searchkey.obj_id = 0; 2700 searchkey.obj_type = 0; 2701 searchkey.offset = 0; 2702 2703 Status = find_item(Vcb, Vcb->root_root, &tp, &searchkey, FALSE, Irp); 2704 if (!NT_SUCCESS(Status)) { 2705 ERR("error - find_item returned %08x\n", Status); 2706 return Status; 2707 } 2708 2709 do { 2710 TRACE("(%llx,%x,%llx)\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset); 2711 2712 if (tp.item->key.obj_type == TYPE_ROOT_ITEM) { 2713 ROOT_ITEM* ri = (ROOT_ITEM*)tp.item->data; 2714 2715 if (tp.item->size < offsetof(ROOT_ITEM, byte_limit)) { 2716 ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, offsetof(ROOT_ITEM, byte_limit)); 2717 } else { 2718 TRACE("root %llx - address %llx\n", tp.item->key.obj_id, ri->block_number); 2719 2720 Status = add_root(Vcb, tp.item->key.obj_id, ri->block_number, ri->generation, &tp); 2721 if (!NT_SUCCESS(Status)) { 2722 ERR("add_root returned %08x\n", Status); 2723 return Status; 2724 } 2725 } 2726 } else if (tp.item->key.obj_type == TYPE_ROOT_BACKREF && !IsListEmpty(&Vcb->roots)) { 2727 root* lastroot = CONTAINING_RECORD(Vcb->roots.Blink, root, list_entry); 2728 2729 if (lastroot->id == tp.item->key.obj_id) 2730 lastroot->parent = tp.item->key.offset; 2731 } 2732 2733 b = find_next_item(Vcb, &tp, &next_tp, FALSE, Irp); 2734 2735 if (b) 2736 tp = next_tp; 2737 } while (b); 2738 2739 if (!Vcb->readonly && !Vcb->data_reloc_root) { 2740 root* reloc_root; 2741 INODE_ITEM* ii; 2742 UINT16 irlen; 2743 INODE_REF* ir; 2744 LARGE_INTEGER time; 2745 BTRFS_TIME now; 2746 2747 WARN("data reloc root doesn't exist, creating it\n"); 2748 2749 Status = create_root(Vcb, BTRFS_ROOT_DATA_RELOC, &reloc_root, FALSE, 0, Irp); 2750 2751 if (!NT_SUCCESS(Status)) { 2752 ERR("create_root returned %08x\n", Status); 2753 return Status; 2754 } 2755 2756 reloc_root->root_item.inode.generation = 1; 2757 reloc_root->root_item.inode.st_size = 3; 2758 reloc_root->root_item.inode.st_blocks = Vcb->superblock.node_size; 2759 reloc_root->root_item.inode.st_nlink = 1; 2760 reloc_root->root_item.inode.st_mode = 040755; 2761 reloc_root->root_item.inode.flags = 0xffffffff80000000; 2762 reloc_root->root_item.objid = SUBVOL_ROOT_INODE; 2763 reloc_root->root_item.bytes_used = Vcb->superblock.node_size; 2764 2765 ii = ExAllocatePoolWithTag(PagedPool, sizeof(INODE_ITEM), ALLOC_TAG); 2766 if (!ii) { 2767 ERR("out of memory\n"); 2768 return STATUS_INSUFFICIENT_RESOURCES; 2769 } 2770 2771 KeQuerySystemTime(&time); 2772 win_time_to_unix(time, &now); 2773 2774 RtlZeroMemory(ii, sizeof(INODE_ITEM)); 2775 ii->generation = Vcb->superblock.generation; 2776 ii->st_blocks = Vcb->superblock.node_size; 2777 ii->st_nlink = 1; 2778 ii->st_mode = 040755; 2779 ii->st_atime = now; 2780 ii->st_ctime = now; 2781 ii->st_mtime = now; 2782 2783 Status = insert_tree_item(Vcb, reloc_root, SUBVOL_ROOT_INODE, TYPE_INODE_ITEM, 0, ii, sizeof(INODE_ITEM), NULL, Irp); 2784 if (!NT_SUCCESS(Status)) { 2785 ERR("insert_tree_item returned %08x\n", Status); 2786 ExFreePool(ii); 2787 return Status; 2788 } 2789 2790 irlen = (UINT16)offsetof(INODE_REF, name[0]) + 2; 2791 ir = ExAllocatePoolWithTag(PagedPool, irlen, ALLOC_TAG); 2792 if (!ir) { 2793 ERR("out of memory\n"); 2794 return STATUS_INSUFFICIENT_RESOURCES; 2795 } 2796 2797 ir->index = 0; 2798 ir->n = 2; 2799 ir->name[0] = '.'; 2800 ir->name[1] = '.'; 2801 2802 Status = insert_tree_item(Vcb, reloc_root, SUBVOL_ROOT_INODE, TYPE_INODE_REF, SUBVOL_ROOT_INODE, ir, irlen, NULL, Irp); 2803 if (!NT_SUCCESS(Status)) { 2804 ERR("insert_tree_item returned %08x\n", Status); 2805 ExFreePool(ir); 2806 return Status; 2807 } 2808 2809 Vcb->data_reloc_root = reloc_root; 2810 Vcb->need_write = TRUE; 2811 } 2812 2813 return STATUS_SUCCESS; 2814 } 2815 2816 static NTSTATUS find_disk_holes(_In_ _Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, _In_ device* dev, _In_opt_ PIRP Irp) { 2817 KEY searchkey; 2818 traverse_ptr tp, next_tp; 2819 BOOL b; 2820 UINT64 lastaddr; 2821 NTSTATUS Status; 2822 2823 InitializeListHead(&dev->space); 2824 2825 searchkey.obj_id = 0; 2826 searchkey.obj_type = TYPE_DEV_STATS; 2827 searchkey.offset = dev->devitem.dev_id; 2828 2829 Status = find_item(Vcb, Vcb->dev_root, &tp, &searchkey, FALSE, Irp); 2830 if (NT_SUCCESS(Status) && !keycmp(tp.item->key, searchkey)) 2831 RtlCopyMemory(dev->stats, tp.item->data, min(sizeof(UINT64) * 5, tp.item->size)); 2832 2833 searchkey.obj_id = dev->devitem.dev_id; 2834 searchkey.obj_type = TYPE_DEV_EXTENT; 2835 searchkey.offset = 0; 2836 2837 Status = find_item(Vcb, Vcb->dev_root, &tp, &searchkey, FALSE, Irp); 2838 if (!NT_SUCCESS(Status)) { 2839 ERR("error - find_item returned %08x\n", Status); 2840 return Status; 2841 } 2842 2843 lastaddr = 0; 2844 2845 do { 2846 if (tp.item->key.obj_id == dev->devitem.dev_id && tp.item->key.obj_type == TYPE_DEV_EXTENT) { 2847 if (tp.item->size >= sizeof(DEV_EXTENT)) { 2848 DEV_EXTENT* de = (DEV_EXTENT*)tp.item->data; 2849 2850 if (tp.item->key.offset > lastaddr) { 2851 Status = add_space_entry(&dev->space, NULL, lastaddr, tp.item->key.offset - lastaddr); 2852 if (!NT_SUCCESS(Status)) { 2853 ERR("add_space_entry returned %08x\n", Status); 2854 return Status; 2855 } 2856 } 2857 2858 lastaddr = tp.item->key.offset + de->length; 2859 } else { 2860 ERR("(%llx,%x,%llx) was %u bytes, expected %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(DEV_EXTENT)); 2861 } 2862 } 2863 2864 b = find_next_item(Vcb, &tp, &next_tp, FALSE, Irp); 2865 2866 if (b) { 2867 tp = next_tp; 2868 if (tp.item->key.obj_id > searchkey.obj_id || tp.item->key.obj_type > searchkey.obj_type) 2869 break; 2870 } 2871 } while (b); 2872 2873 if (lastaddr < dev->devitem.num_bytes) { 2874 Status = add_space_entry(&dev->space, NULL, lastaddr, dev->devitem.num_bytes - lastaddr); 2875 if (!NT_SUCCESS(Status)) { 2876 ERR("add_space_entry returned %08x\n", Status); 2877 return Status; 2878 } 2879 } 2880 2881 // The Linux driver doesn't like to allocate chunks within the first megabyte of a device. 2882 2883 space_list_subtract2(&dev->space, NULL, 0, 0x100000, NULL, NULL); 2884 2885 return STATUS_SUCCESS; 2886 } 2887 2888 static void add_device_to_list(_In_ device_extension* Vcb, _In_ device* dev) { 2889 LIST_ENTRY* le; 2890 2891 le = Vcb->devices.Flink; 2892 2893 while (le != &Vcb->devices) { 2894 device* dev2 = CONTAINING_RECORD(le, device, list_entry); 2895 2896 if (dev2->devitem.dev_id > dev->devitem.dev_id) { 2897 InsertHeadList(le->Blink, &dev->list_entry); 2898 return; 2899 } 2900 2901 le = le->Flink; 2902 } 2903 2904 InsertTailList(&Vcb->devices, &dev->list_entry); 2905 } 2906 2907 _Ret_maybenull_ 2908 device* find_device_from_uuid(_In_ device_extension* Vcb, _In_ BTRFS_UUID* uuid) { 2909 volume_device_extension* vde; 2910 pdo_device_extension* pdode; 2911 LIST_ENTRY* le; 2912 2913 le = Vcb->devices.Flink; 2914 while (le != &Vcb->devices) { 2915 device* dev = CONTAINING_RECORD(le, device, list_entry); 2916 2917 TRACE("device %llx, uuid %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n", dev->devitem.dev_id, 2918 dev->devitem.device_uuid.uuid[0], dev->devitem.device_uuid.uuid[1], dev->devitem.device_uuid.uuid[2], dev->devitem.device_uuid.uuid[3], dev->devitem.device_uuid.uuid[4], dev->devitem.device_uuid.uuid[5], dev->devitem.device_uuid.uuid[6], dev->devitem.device_uuid.uuid[7], 2919 dev->devitem.device_uuid.uuid[8], dev->devitem.device_uuid.uuid[9], dev->devitem.device_uuid.uuid[10], dev->devitem.device_uuid.uuid[11], dev->devitem.device_uuid.uuid[12], dev->devitem.device_uuid.uuid[13], dev->devitem.device_uuid.uuid[14], dev->devitem.device_uuid.uuid[15]); 2920 2921 if (RtlCompareMemory(&dev->devitem.device_uuid, uuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID)) { 2922 TRACE("returning device %llx\n", dev->devitem.dev_id); 2923 return dev; 2924 } 2925 2926 le = le->Flink; 2927 } 2928 2929 vde = Vcb->vde; 2930 2931 if (!vde) 2932 goto end; 2933 2934 pdode = vde->pdode; 2935 2936 ExAcquireResourceSharedLite(&pdode->child_lock, TRUE); 2937 2938 if (Vcb->devices_loaded < Vcb->superblock.num_devices) { 2939 le = pdode->children.Flink; 2940 2941 while (le != &pdode->children) { 2942 volume_child* vc = CONTAINING_RECORD(le, volume_child, list_entry); 2943 2944 if (RtlCompareMemory(uuid, &vc->uuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID)) { 2945 device* dev; 2946 2947 dev = ExAllocatePoolWithTag(NonPagedPool, sizeof(device), ALLOC_TAG); 2948 if (!dev) { 2949 ExReleaseResourceLite(&pdode->child_lock); 2950 ERR("out of memory\n"); 2951 return NULL; 2952 } 2953 2954 RtlZeroMemory(dev, sizeof(device)); 2955 dev->devobj = vc->devobj; 2956 dev->devitem.device_uuid = *uuid; 2957 dev->devitem.dev_id = vc->devid; 2958 dev->devitem.num_bytes = vc->size; 2959 dev->seeding = vc->seeding; 2960 dev->readonly = dev->seeding; 2961 dev->reloc = FALSE; 2962 dev->removable = FALSE; 2963 dev->disk_num = vc->disk_num; 2964 dev->part_num = vc->part_num; 2965 dev->num_trim_entries = 0; 2966 InitializeListHead(&dev->trim_list); 2967 2968 add_device_to_list(Vcb, dev); 2969 Vcb->devices_loaded++; 2970 2971 ExReleaseResourceLite(&pdode->child_lock); 2972 2973 return dev; 2974 } 2975 2976 le = le->Flink; 2977 } 2978 } 2979 2980 ExReleaseResourceLite(&pdode->child_lock); 2981 2982 end: 2983 WARN("could not find device with uuid %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n", 2984 uuid->uuid[0], uuid->uuid[1], uuid->uuid[2], uuid->uuid[3], uuid->uuid[4], uuid->uuid[5], uuid->uuid[6], uuid->uuid[7], 2985 uuid->uuid[8], uuid->uuid[9], uuid->uuid[10], uuid->uuid[11], uuid->uuid[12], uuid->uuid[13], uuid->uuid[14], uuid->uuid[15]); 2986 2987 return NULL; 2988 } 2989 2990 static BOOL is_device_removable(_In_ PDEVICE_OBJECT devobj) { 2991 NTSTATUS Status; 2992 STORAGE_HOTPLUG_INFO shi; 2993 2994 Status = dev_ioctl(devobj, IOCTL_STORAGE_GET_HOTPLUG_INFO, NULL, 0, &shi, sizeof(STORAGE_HOTPLUG_INFO), TRUE, NULL); 2995 2996 if (!NT_SUCCESS(Status)) { 2997 ERR("dev_ioctl returned %08x\n", Status); 2998 return FALSE; 2999 } 3000 3001 return shi.MediaRemovable != 0 ? TRUE : FALSE; 3002 } 3003 3004 static ULONG get_device_change_count(_In_ PDEVICE_OBJECT devobj) { 3005 NTSTATUS Status; 3006 ULONG cc; 3007 IO_STATUS_BLOCK iosb; 3008 3009 Status = dev_ioctl(devobj, IOCTL_STORAGE_CHECK_VERIFY, NULL, 0, &cc, sizeof(ULONG), TRUE, &iosb); 3010 3011 if (!NT_SUCCESS(Status)) { 3012 ERR("dev_ioctl returned %08x\n", Status); 3013 return 0; 3014 } 3015 3016 if (iosb.Information < sizeof(ULONG)) { 3017 ERR("iosb.Information was too short\n"); 3018 return 0; 3019 } 3020 3021 return cc; 3022 } 3023 3024 void init_device(_In_ device_extension* Vcb, _Inout_ device* dev, _In_ BOOL get_nums) { 3025 NTSTATUS Status; 3026 ULONG aptelen; 3027 ATA_PASS_THROUGH_EX* apte; 3028 STORAGE_PROPERTY_QUERY spq; 3029 DEVICE_TRIM_DESCRIPTOR dtd; 3030 3031 dev->removable = is_device_removable(dev->devobj); 3032 dev->change_count = dev->removable ? get_device_change_count(dev->devobj) : 0; 3033 3034 if (get_nums) { 3035 STORAGE_DEVICE_NUMBER sdn; 3036 3037 Status = dev_ioctl(dev->devobj, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, 3038 &sdn, sizeof(STORAGE_DEVICE_NUMBER), TRUE, NULL); 3039 3040 if (!NT_SUCCESS(Status)) { 3041 WARN("IOCTL_STORAGE_GET_DEVICE_NUMBER returned %08x\n", Status); 3042 dev->disk_num = 0xffffffff; 3043 dev->part_num = 0xffffffff; 3044 } else { 3045 dev->disk_num = sdn.DeviceNumber; 3046 dev->part_num = sdn.PartitionNumber; 3047 } 3048 } 3049 3050 dev->trim = FALSE; 3051 dev->readonly = dev->seeding; 3052 dev->reloc = FALSE; 3053 dev->num_trim_entries = 0; 3054 dev->stats_changed = FALSE; 3055 InitializeListHead(&dev->trim_list); 3056 3057 if (!dev->readonly) { 3058 Status = dev_ioctl(dev->devobj, IOCTL_DISK_IS_WRITABLE, NULL, 0, 3059 NULL, 0, TRUE, NULL); 3060 if (Status == STATUS_MEDIA_WRITE_PROTECTED) 3061 dev->readonly = TRUE; 3062 } 3063 3064 aptelen = sizeof(ATA_PASS_THROUGH_EX) + 512; 3065 apte = ExAllocatePoolWithTag(NonPagedPool, aptelen, ALLOC_TAG); 3066 if (!apte) { 3067 ERR("out of memory\n"); 3068 return; 3069 } 3070 3071 RtlZeroMemory(apte, aptelen); 3072 3073 apte->Length = sizeof(ATA_PASS_THROUGH_EX); 3074 apte->AtaFlags = ATA_FLAGS_DATA_IN; 3075 apte->DataTransferLength = aptelen - sizeof(ATA_PASS_THROUGH_EX); 3076 apte->TimeOutValue = 3; 3077 apte->DataBufferOffset = apte->Length; 3078 apte->CurrentTaskFile[6] = IDE_COMMAND_IDENTIFY; 3079 3080 Status = dev_ioctl(dev->devobj, IOCTL_ATA_PASS_THROUGH, apte, aptelen, 3081 apte, aptelen, TRUE, NULL); 3082 3083 if (!NT_SUCCESS(Status)) 3084 TRACE("IOCTL_ATA_PASS_THROUGH returned %08x for IDENTIFY DEVICE\n", Status); 3085 else { 3086 IDENTIFY_DEVICE_DATA* idd = (IDENTIFY_DEVICE_DATA*)((UINT8*)apte + sizeof(ATA_PASS_THROUGH_EX)); 3087 3088 if (idd->CommandSetSupport.FlushCache) { 3089 dev->can_flush = TRUE; 3090 TRACE("FLUSH CACHE supported\n"); 3091 } else 3092 TRACE("FLUSH CACHE not supported\n"); 3093 } 3094 3095 ExFreePool(apte); 3096 3097 spq.PropertyId = StorageDeviceTrimProperty; 3098 spq.QueryType = PropertyStandardQuery; 3099 spq.AdditionalParameters[0] = 0; 3100 3101 Status = dev_ioctl(dev->devobj, IOCTL_STORAGE_QUERY_PROPERTY, &spq, sizeof(STORAGE_PROPERTY_QUERY), 3102 &dtd, sizeof(DEVICE_TRIM_DESCRIPTOR), TRUE, NULL); 3103 3104 if (NT_SUCCESS(Status)) { 3105 if (dtd.TrimEnabled) { 3106 dev->trim = TRUE; 3107 Vcb->trim = TRUE; 3108 TRACE("TRIM supported\n"); 3109 } else 3110 TRACE("TRIM not supported\n"); 3111 } 3112 3113 RtlZeroMemory(dev->stats, sizeof(UINT64) * 5); 3114 } 3115 3116 static NTSTATUS load_chunk_root(_In_ _Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, _In_opt_ PIRP Irp) { 3117 traverse_ptr tp, next_tp; 3118 KEY searchkey; 3119 BOOL b; 3120 chunk* c; 3121 NTSTATUS Status; 3122 3123 searchkey.obj_id = 0; 3124 searchkey.obj_type = 0; 3125 searchkey.offset = 0; 3126 3127 Vcb->data_flags = 0; 3128 Vcb->metadata_flags = 0; 3129 Vcb->system_flags = 0; 3130 3131 Status = find_item(Vcb, Vcb->chunk_root, &tp, &searchkey, FALSE, Irp); 3132 if (!NT_SUCCESS(Status)) { 3133 ERR("error - find_item returned %08x\n", Status); 3134 return Status; 3135 } 3136 3137 do { 3138 TRACE("(%llx,%x,%llx)\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset); 3139 3140 if (tp.item->key.obj_id == 1 && tp.item->key.obj_type == TYPE_DEV_ITEM) { 3141 if (tp.item->size < sizeof(DEV_ITEM)) { 3142 ERR("(%llx,%x,%llx) was %u bytes, expected %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(DEV_ITEM)); 3143 } else { 3144 DEV_ITEM* di = (DEV_ITEM*)tp.item->data; 3145 LIST_ENTRY* le; 3146 BOOL done = FALSE; 3147 3148 le = Vcb->devices.Flink; 3149 while (le != &Vcb->devices) { 3150 device* dev = CONTAINING_RECORD(le, device, list_entry); 3151 3152 if (dev->devobj && RtlCompareMemory(&dev->devitem.device_uuid, &di->device_uuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID)) { 3153 RtlCopyMemory(&dev->devitem, tp.item->data, min(tp.item->size, sizeof(DEV_ITEM))); 3154 3155 if (le != Vcb->devices.Flink) 3156 init_device(Vcb, dev, TRUE); 3157 3158 done = TRUE; 3159 break; 3160 } 3161 3162 le = le->Flink; 3163 } 3164 3165 if (!done && Vcb->vde) { 3166 volume_device_extension* vde = Vcb->vde; 3167 pdo_device_extension* pdode = vde->pdode; 3168 3169 ExAcquireResourceSharedLite(&pdode->child_lock, TRUE); 3170 3171 if (Vcb->devices_loaded < Vcb->superblock.num_devices) { 3172 le = pdode->children.Flink; 3173 3174 while (le != &pdode->children) { 3175 volume_child* vc = CONTAINING_RECORD(le, volume_child, list_entry); 3176 3177 if (RtlCompareMemory(&di->device_uuid, &vc->uuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID)) { 3178 device* dev; 3179 3180 dev = ExAllocatePoolWithTag(NonPagedPool, sizeof(device), ALLOC_TAG); 3181 if (!dev) { 3182 ExReleaseResourceLite(&pdode->child_lock); 3183 ERR("out of memory\n"); 3184 return STATUS_INSUFFICIENT_RESOURCES; 3185 } 3186 3187 RtlZeroMemory(dev, sizeof(device)); 3188 3189 dev->devobj = vc->devobj; 3190 RtlCopyMemory(&dev->devitem, di, min(tp.item->size, sizeof(DEV_ITEM))); 3191 dev->seeding = vc->seeding; 3192 init_device(Vcb, dev, FALSE); 3193 3194 if (dev->devitem.num_bytes > vc->size) { 3195 WARN("device %llx: DEV_ITEM says %llx bytes, but Windows only reports %llx\n", tp.item->key.offset, 3196 dev->devitem.num_bytes, vc->size); 3197 3198 dev->devitem.num_bytes = vc->size; 3199 } 3200 3201 dev->disk_num = vc->disk_num; 3202 dev->part_num = vc->part_num; 3203 add_device_to_list(Vcb, dev); 3204 Vcb->devices_loaded++; 3205 3206 done = TRUE; 3207 break; 3208 } 3209 3210 le = le->Flink; 3211 } 3212 3213 if (!done) { 3214 if (!Vcb->options.allow_degraded) { 3215 ERR("volume not found: device %llx, uuid %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n", tp.item->key.offset, 3216 di->device_uuid.uuid[0], di->device_uuid.uuid[1], di->device_uuid.uuid[2], di->device_uuid.uuid[3], di->device_uuid.uuid[4], di->device_uuid.uuid[5], di->device_uuid.uuid[6], di->device_uuid.uuid[7], 3217 di->device_uuid.uuid[8], di->device_uuid.uuid[9], di->device_uuid.uuid[10], di->device_uuid.uuid[11], di->device_uuid.uuid[12], di->device_uuid.uuid[13], di->device_uuid.uuid[14], di->device_uuid.uuid[15]); 3218 } else { 3219 device* dev; 3220 3221 dev = ExAllocatePoolWithTag(NonPagedPool, sizeof(device), ALLOC_TAG); 3222 if (!dev) { 3223 ExReleaseResourceLite(&pdode->child_lock); 3224 ERR("out of memory\n"); 3225 return STATUS_INSUFFICIENT_RESOURCES; 3226 } 3227 3228 RtlZeroMemory(dev, sizeof(device)); 3229 3230 // Missing device, so we keep dev->devobj as NULL 3231 RtlCopyMemory(&dev->devitem, di, min(tp.item->size, sizeof(DEV_ITEM))); 3232 InitializeListHead(&dev->trim_list); 3233 3234 add_device_to_list(Vcb, dev); 3235 Vcb->devices_loaded++; 3236 } 3237 } 3238 } else 3239 ERR("unexpected device %llx found\n", tp.item->key.offset); 3240 3241 ExReleaseResourceLite(&pdode->child_lock); 3242 } 3243 } 3244 } else if (tp.item->key.obj_type == TYPE_CHUNK_ITEM) { 3245 if (tp.item->size < sizeof(CHUNK_ITEM)) { 3246 ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(CHUNK_ITEM)); 3247 } else { 3248 c = ExAllocatePoolWithTag(NonPagedPool, sizeof(chunk), ALLOC_TAG); 3249 3250 if (!c) { 3251 ERR("out of memory\n"); 3252 return STATUS_INSUFFICIENT_RESOURCES; 3253 } 3254 3255 c->size = tp.item->size; 3256 c->offset = tp.item->key.offset; 3257 c->used = c->oldused = 0; 3258 c->cache = c->old_cache = NULL; 3259 c->created = FALSE; 3260 c->readonly = FALSE; 3261 c->reloc = FALSE; 3262 c->cache_loaded = FALSE; 3263 c->changed = FALSE; 3264 c->space_changed = FALSE; 3265 c->balance_num = 0; 3266 3267 c->chunk_item = ExAllocatePoolWithTag(NonPagedPool, tp.item->size, ALLOC_TAG); 3268 3269 if (!c->chunk_item) { 3270 ERR("out of memory\n"); 3271 ExFreePool(c); 3272 return STATUS_INSUFFICIENT_RESOURCES; 3273 } 3274 3275 RtlCopyMemory(c->chunk_item, tp.item->data, tp.item->size); 3276 3277 if (c->chunk_item->type & BLOCK_FLAG_DATA && c->chunk_item->type > Vcb->data_flags) 3278 Vcb->data_flags = c->chunk_item->type; 3279 3280 if (c->chunk_item->type & BLOCK_FLAG_METADATA && c->chunk_item->type > Vcb->metadata_flags) 3281 Vcb->metadata_flags = c->chunk_item->type; 3282 3283 if (c->chunk_item->type & BLOCK_FLAG_SYSTEM && c->chunk_item->type > Vcb->system_flags) 3284 Vcb->system_flags = c->chunk_item->type; 3285 3286 if (c->chunk_item->type & BLOCK_FLAG_RAID10) { 3287 if (c->chunk_item->sub_stripes == 0 || c->chunk_item->sub_stripes > c->chunk_item->num_stripes) { 3288 ERR("chunk %llx: invalid stripes (num_stripes %u, sub_stripes %u)\n", c->offset, c->chunk_item->num_stripes, c->chunk_item->sub_stripes); 3289 ExFreePool(c->chunk_item); 3290 ExFreePool(c); 3291 return STATUS_INTERNAL_ERROR; 3292 } 3293 } 3294 3295 if (c->chunk_item->num_stripes > 0) { 3296 CHUNK_ITEM_STRIPE* cis = (CHUNK_ITEM_STRIPE*)&c->chunk_item[1]; 3297 UINT16 i; 3298 3299 c->devices = ExAllocatePoolWithTag(NonPagedPool, sizeof(device*) * c->chunk_item->num_stripes, ALLOC_TAG); 3300 3301 if (!c->devices) { 3302 ERR("out of memory\n"); 3303 ExFreePool(c->chunk_item); 3304 ExFreePool(c); 3305 return STATUS_INSUFFICIENT_RESOURCES; 3306 } 3307 3308 for (i = 0; i < c->chunk_item->num_stripes; i++) { 3309 c->devices[i] = find_device_from_uuid(Vcb, &cis[i].dev_uuid); 3310 TRACE("device %llu = %p\n", i, c->devices[i]); 3311 3312 if (!c->devices[i]) { 3313 ERR("missing device\n"); 3314 ExFreePool(c->chunk_item); 3315 ExFreePool(c); 3316 return STATUS_INTERNAL_ERROR; 3317 } 3318 3319 if (c->devices[i]->readonly) 3320 c->readonly = TRUE; 3321 } 3322 } else { 3323 ERR("chunk %llx: number of stripes is 0\n", c->offset); 3324 ExFreePool(c->chunk_item); 3325 ExFreePool(c); 3326 return STATUS_INTERNAL_ERROR; 3327 } 3328 3329 ExInitializeResourceLite(&c->lock); 3330 ExInitializeResourceLite(&c->changed_extents_lock); 3331 3332 InitializeListHead(&c->space); 3333 InitializeListHead(&c->space_size); 3334 InitializeListHead(&c->deleting); 3335 InitializeListHead(&c->changed_extents); 3336 3337 InitializeListHead(&c->range_locks); 3338 ExInitializeResourceLite(&c->range_locks_lock); 3339 KeInitializeEvent(&c->range_locks_event, NotificationEvent, FALSE); 3340 3341 InitializeListHead(&c->partial_stripes); 3342 ExInitializeResourceLite(&c->partial_stripes_lock); 3343 3344 c->last_alloc_set = FALSE; 3345 3346 c->last_stripe = 0; 3347 3348 InsertTailList(&Vcb->chunks, &c->list_entry); 3349 3350 c->list_entry_balance.Flink = NULL; 3351 } 3352 } 3353 3354 b = find_next_item(Vcb, &tp, &next_tp, FALSE, Irp); 3355 3356 if (b) 3357 tp = next_tp; 3358 } while (b); 3359 3360 Vcb->log_to_phys_loaded = TRUE; 3361 3362 if (Vcb->data_flags == 0) 3363 Vcb->data_flags = BLOCK_FLAG_DATA | (Vcb->superblock.num_devices > 1 ? BLOCK_FLAG_RAID0 : 0); 3364 3365 if (Vcb->metadata_flags == 0) 3366 Vcb->metadata_flags = BLOCK_FLAG_METADATA | (Vcb->superblock.num_devices > 1 ? BLOCK_FLAG_RAID1 : BLOCK_FLAG_DUPLICATE); 3367 3368 if (Vcb->system_flags == 0) 3369 Vcb->system_flags = BLOCK_FLAG_SYSTEM | (Vcb->superblock.num_devices > 1 ? BLOCK_FLAG_RAID1 : BLOCK_FLAG_DUPLICATE); 3370 3371 if (Vcb->superblock.incompat_flags & BTRFS_INCOMPAT_FLAGS_MIXED_GROUPS) { 3372 Vcb->metadata_flags |= BLOCK_FLAG_DATA; 3373 Vcb->data_flags = Vcb->metadata_flags; 3374 } 3375 3376 return STATUS_SUCCESS; 3377 } 3378 3379 void protect_superblocks(_Inout_ chunk* c) { 3380 UINT16 i = 0, j; 3381 UINT64 off_start, off_end; 3382 3383 // The Linux driver also protects all the space before the first superblock. 3384 // I realize this confuses physical and logical addresses, but this is what btrfs-progs does - 3385 // evidently Linux assumes the chunk at 0 is always SINGLE. 3386 if (c->offset < superblock_addrs[0]) 3387 space_list_subtract(c, FALSE, c->offset, superblock_addrs[0] - c->offset, NULL); 3388 3389 while (superblock_addrs[i] != 0) { 3390 CHUNK_ITEM* ci = c->chunk_item; 3391 CHUNK_ITEM_STRIPE* cis = (CHUNK_ITEM_STRIPE*)&ci[1]; 3392 3393 if (ci->type & BLOCK_FLAG_RAID0 || ci->type & BLOCK_FLAG_RAID10) { 3394 for (j = 0; j < ci->num_stripes; j++) { 3395 UINT16 sub_stripes = max(ci->sub_stripes, 1); 3396 3397 if (cis[j].offset + (ci->size * ci->num_stripes / sub_stripes) > superblock_addrs[i] && cis[j].offset <= superblock_addrs[i] + sizeof(superblock)) { 3398 #ifdef _DEBUG 3399 UINT64 startoff; 3400 UINT16 startoffstripe; 3401 #endif 3402 3403 TRACE("cut out superblock in chunk %llx\n", c->offset); 3404 3405 off_start = superblock_addrs[i] - cis[j].offset; 3406 off_start -= off_start % ci->stripe_length; 3407 off_start *= ci->num_stripes / sub_stripes; 3408 off_start += (j / sub_stripes) * ci->stripe_length; 3409 3410 off_end = off_start + ci->stripe_length; 3411 3412 #ifdef _DEBUG 3413 get_raid0_offset(off_start, ci->stripe_length, ci->num_stripes / sub_stripes, &startoff, &startoffstripe); 3414 TRACE("j = %u, startoffstripe = %u\n", j, startoffstripe); 3415 TRACE("startoff = %llx, superblock = %llx\n", startoff + cis[j].offset, superblock_addrs[i]); 3416 #endif 3417 3418 space_list_subtract(c, FALSE, c->offset + off_start, off_end - off_start, NULL); 3419 } 3420 } 3421 } else if (ci->type & BLOCK_FLAG_RAID5) { 3422 UINT64 stripe_size = ci->size / (ci->num_stripes - 1); 3423 3424 for (j = 0; j < ci->num_stripes; j++) { 3425 if (cis[j].offset + stripe_size > superblock_addrs[i] && cis[j].offset <= superblock_addrs[i] + sizeof(superblock)) { 3426 TRACE("cut out superblock in chunk %llx\n", c->offset); 3427 3428 off_start = superblock_addrs[i] - cis[j].offset; 3429 off_start -= off_start % ci->stripe_length; 3430 off_start *= ci->num_stripes - 1; 3431 3432 off_end = sector_align(superblock_addrs[i] - cis[j].offset + sizeof(superblock), ci->stripe_length); 3433 off_end *= ci->num_stripes - 1; 3434 3435 TRACE("cutting out %llx, size %llx\n", c->offset + off_start, off_end - off_start); 3436 3437 space_list_subtract(c, FALSE, c->offset + off_start, off_end - off_start, NULL); 3438 } 3439 } 3440 } else if (ci->type & BLOCK_FLAG_RAID6) { 3441 UINT64 stripe_size = ci->size / (ci->num_stripes - 2); 3442 3443 for (j = 0; j < ci->num_stripes; j++) { 3444 if (cis[j].offset + stripe_size > superblock_addrs[i] && cis[j].offset <= superblock_addrs[i] + sizeof(superblock)) { 3445 TRACE("cut out superblock in chunk %llx\n", c->offset); 3446 3447 off_start = superblock_addrs[i] - cis[j].offset; 3448 off_start -= off_start % ci->stripe_length; 3449 off_start *= ci->num_stripes - 2; 3450 3451 off_end = sector_align(superblock_addrs[i] - cis[j].offset + sizeof(superblock), ci->stripe_length); 3452 off_end *= ci->num_stripes - 2; 3453 3454 TRACE("cutting out %llx, size %llx\n", c->offset + off_start, off_end - off_start); 3455 3456 space_list_subtract(c, FALSE, c->offset + off_start, off_end - off_start, NULL); 3457 } 3458 } 3459 } else { // SINGLE, DUPLICATE, RAID1 3460 for (j = 0; j < ci->num_stripes; j++) { 3461 if (cis[j].offset + ci->size > superblock_addrs[i] && cis[j].offset <= superblock_addrs[i] + sizeof(superblock)) { 3462 TRACE("cut out superblock in chunk %llx\n", c->offset); 3463 3464 // The Linux driver protects the whole stripe in which the superblock lives 3465 3466 off_start = ((superblock_addrs[i] - cis[j].offset) / c->chunk_item->stripe_length) * c->chunk_item->stripe_length; 3467 off_end = sector_align(superblock_addrs[i] - cis[j].offset + sizeof(superblock), c->chunk_item->stripe_length); 3468 3469 space_list_subtract(c, FALSE, c->offset + off_start, off_end - off_start, NULL); 3470 } 3471 } 3472 } 3473 3474 i++; 3475 } 3476 } 3477 3478 NTSTATUS find_chunk_usage(_In_ _Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, _In_opt_ PIRP Irp) { 3479 LIST_ENTRY* le = Vcb->chunks.Flink; 3480 chunk* c; 3481 KEY searchkey; 3482 traverse_ptr tp; 3483 BLOCK_GROUP_ITEM* bgi; 3484 NTSTATUS Status; 3485 3486 searchkey.obj_type = TYPE_BLOCK_GROUP_ITEM; 3487 3488 while (le != &Vcb->chunks) { 3489 c = CONTAINING_RECORD(le, chunk, list_entry); 3490 3491 searchkey.obj_id = c->offset; 3492 searchkey.offset = c->chunk_item->size; 3493 3494 Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE, Irp); 3495 if (!NT_SUCCESS(Status)) { 3496 ERR("error - find_item returned %08x\n", Status); 3497 return Status; 3498 } 3499 3500 if (!keycmp(searchkey, tp.item->key)) { 3501 if (tp.item->size >= sizeof(BLOCK_GROUP_ITEM)) { 3502 bgi = (BLOCK_GROUP_ITEM*)tp.item->data; 3503 3504 c->used = c->oldused = bgi->used; 3505 3506 TRACE("chunk %llx has %llx bytes used\n", c->offset, c->used); 3507 } else { 3508 ERR("(%llx;%llx,%x,%llx) is %u bytes, expected %u\n", 3509 Vcb->extent_root->id, tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(BLOCK_GROUP_ITEM)); 3510 } 3511 } 3512 3513 le = le->Flink; 3514 } 3515 3516 Vcb->chunk_usage_found = TRUE; 3517 3518 return STATUS_SUCCESS; 3519 } 3520 3521 static NTSTATUS load_sys_chunks(_In_ device_extension* Vcb) { 3522 KEY key; 3523 ULONG n = Vcb->superblock.n; 3524 3525 while (n > 0) { 3526 if (n > sizeof(KEY)) { 3527 RtlCopyMemory(&key, &Vcb->superblock.sys_chunk_array[Vcb->superblock.n - n], sizeof(KEY)); 3528 n -= sizeof(KEY); 3529 } else 3530 return STATUS_SUCCESS; 3531 3532 TRACE("bootstrap: %llx,%x,%llx\n", key.obj_id, key.obj_type, key.offset); 3533 3534 if (key.obj_type == TYPE_CHUNK_ITEM) { 3535 CHUNK_ITEM* ci; 3536 USHORT cisize; 3537 sys_chunk* sc; 3538 3539 if (n < sizeof(CHUNK_ITEM)) 3540 return STATUS_SUCCESS; 3541 3542 ci = (CHUNK_ITEM*)&Vcb->superblock.sys_chunk_array[Vcb->superblock.n - n]; 3543 cisize = sizeof(CHUNK_ITEM) + (ci->num_stripes * sizeof(CHUNK_ITEM_STRIPE)); 3544 3545 if (n < cisize) 3546 return STATUS_SUCCESS; 3547 3548 sc = ExAllocatePoolWithTag(PagedPool, sizeof(sys_chunk), ALLOC_TAG); 3549 3550 if (!sc) { 3551 ERR("out of memory\n"); 3552 return STATUS_INSUFFICIENT_RESOURCES; 3553 } 3554 3555 sc->key = key; 3556 sc->size = cisize; 3557 sc->data = ExAllocatePoolWithTag(PagedPool, sc->size, ALLOC_TAG); 3558 3559 if (!sc->data) { 3560 ERR("out of memory\n"); 3561 ExFreePool(sc); 3562 return STATUS_INSUFFICIENT_RESOURCES; 3563 } 3564 3565 RtlCopyMemory(sc->data, ci, sc->size); 3566 InsertTailList(&Vcb->sys_chunks, &sc->list_entry); 3567 3568 n -= cisize; 3569 } else { 3570 ERR("unexpected item %llx,%x,%llx in bootstrap\n", key.obj_id, key.obj_type, key.offset); 3571 return STATUS_INTERNAL_ERROR; 3572 } 3573 } 3574 3575 return STATUS_SUCCESS; 3576 } 3577 3578 _Ret_maybenull_ 3579 static root* find_default_subvol(_In_ _Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, _In_opt_ PIRP Irp) { 3580 LIST_ENTRY* le; 3581 3582 static char fn[] = "default"; 3583 static UINT32 crc32 = 0x8dbfc2d2; 3584 3585 if (Vcb->options.subvol_id != 0) { 3586 le = Vcb->roots.Flink; 3587 while (le != &Vcb->roots) { 3588 root* r = CONTAINING_RECORD(le, root, list_entry); 3589 3590 if (r->id == Vcb->options.subvol_id) 3591 return r; 3592 3593 le = le->Flink; 3594 } 3595 } 3596 3597 if (Vcb->superblock.incompat_flags & BTRFS_INCOMPAT_FLAGS_DEFAULT_SUBVOL) { 3598 NTSTATUS Status; 3599 KEY searchkey; 3600 traverse_ptr tp; 3601 DIR_ITEM* di; 3602 3603 searchkey.obj_id = Vcb->superblock.root_dir_objectid; 3604 searchkey.obj_type = TYPE_DIR_ITEM; 3605 searchkey.offset = crc32; 3606 3607 Status = find_item(Vcb, Vcb->root_root, &tp, &searchkey, FALSE, Irp); 3608 if (!NT_SUCCESS(Status)) { 3609 ERR("error - find_item returned %08x\n", Status); 3610 goto end; 3611 } 3612 3613 if (keycmp(tp.item->key, searchkey)) { 3614 ERR("could not find (%llx,%x,%llx) in root tree\n", searchkey.obj_id, searchkey.obj_type, searchkey.offset); 3615 goto end; 3616 } 3617 3618 if (tp.item->size < sizeof(DIR_ITEM)) { 3619 ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(DIR_ITEM)); 3620 goto end; 3621 } 3622 3623 di = (DIR_ITEM*)tp.item->data; 3624 3625 if (tp.item->size < sizeof(DIR_ITEM) - 1 + di->n) { 3626 ERR("(%llx,%x,%llx) was %u bytes, expected %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(DIR_ITEM) - 1 + di->n); 3627 goto end; 3628 } 3629 3630 if (di->n != strlen(fn) || RtlCompareMemory(di->name, fn, di->n) != di->n) { 3631 ERR("root DIR_ITEM had same CRC32, but was not \"default\"\n"); 3632 goto end; 3633 } 3634 3635 if (di->key.obj_type != TYPE_ROOT_ITEM) { 3636 ERR("default root has key (%llx,%x,%llx), expected subvolume\n", di->key.obj_id, di->key.obj_type, di->key.offset); 3637 goto end; 3638 } 3639 3640 le = Vcb->roots.Flink; 3641 while (le != &Vcb->roots) { 3642 root* r = CONTAINING_RECORD(le, root, list_entry); 3643 3644 if (r->id == di->key.obj_id) 3645 return r; 3646 3647 le = le->Flink; 3648 } 3649 3650 ERR("could not find root %llx, using default instead\n", di->key.obj_id); 3651 } 3652 3653 end: 3654 le = Vcb->roots.Flink; 3655 while (le != &Vcb->roots) { 3656 root* r = CONTAINING_RECORD(le, root, list_entry); 3657 3658 if (r->id == BTRFS_ROOT_FSTREE) 3659 return r; 3660 3661 le = le->Flink; 3662 } 3663 3664 return NULL; 3665 } 3666 3667 void init_file_cache(_In_ PFILE_OBJECT FileObject, _In_ CC_FILE_SIZES* ccfs) { 3668 TRACE("(%p, %p)\n", FileObject, ccfs); 3669 3670 CcInitializeCacheMap(FileObject, ccfs, FALSE, cache_callbacks, FileObject); 3671 3672 if (diskacc) 3673 fCcSetAdditionalCacheAttributesEx(FileObject, CC_ENABLE_DISK_IO_ACCOUNTING); 3674 3675 CcSetReadAheadGranularity(FileObject, READ_AHEAD_GRANULARITY); 3676 } 3677 3678 static NTSTATUS create_calc_threads(_In_ PDEVICE_OBJECT DeviceObject) { 3679 device_extension* Vcb = DeviceObject->DeviceExtension; 3680 ULONG i; 3681 3682 Vcb->calcthreads.num_threads = KeQueryActiveProcessorCount(NULL); 3683 3684 Vcb->calcthreads.threads = ExAllocatePoolWithTag(NonPagedPool, sizeof(drv_calc_thread) * Vcb->calcthreads.num_threads, ALLOC_TAG); 3685 if (!Vcb->calcthreads.threads) { 3686 ERR("out of memory\n"); 3687 return STATUS_INSUFFICIENT_RESOURCES; 3688 } 3689 3690 InitializeListHead(&Vcb->calcthreads.job_list); 3691 ExInitializeResourceLite(&Vcb->calcthreads.lock); 3692 KeInitializeEvent(&Vcb->calcthreads.event, NotificationEvent, FALSE); 3693 3694 RtlZeroMemory(Vcb->calcthreads.threads, sizeof(drv_calc_thread) * Vcb->calcthreads.num_threads); 3695 3696 for (i = 0; i < Vcb->calcthreads.num_threads; i++) { 3697 NTSTATUS Status; 3698 3699 Vcb->calcthreads.threads[i].DeviceObject = DeviceObject; 3700 KeInitializeEvent(&Vcb->calcthreads.threads[i].finished, NotificationEvent, FALSE); 3701 3702 Status = PsCreateSystemThread(&Vcb->calcthreads.threads[i].handle, 0, NULL, NULL, NULL, calc_thread, &Vcb->calcthreads.threads[i]); 3703 if (!NT_SUCCESS(Status)) { 3704 ULONG j; 3705 3706 ERR("PsCreateSystemThread returned %08x\n", Status); 3707 3708 for (j = 0; j < i; j++) { 3709 Vcb->calcthreads.threads[i].quit = TRUE; 3710 } 3711 3712 KeSetEvent(&Vcb->calcthreads.event, 0, FALSE); 3713 3714 return Status; 3715 } 3716 } 3717 3718 return STATUS_SUCCESS; 3719 } 3720 3721 static BOOL is_btrfs_volume(_In_ PDEVICE_OBJECT DeviceObject) { 3722 NTSTATUS Status; 3723 MOUNTDEV_NAME mdn, *mdn2; 3724 ULONG mdnsize; 3725 3726 Status = dev_ioctl(DeviceObject, IOCTL_MOUNTDEV_QUERY_DEVICE_NAME, NULL, 0, &mdn, sizeof(MOUNTDEV_NAME), TRUE, NULL); 3727 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW) { 3728 ERR("IOCTL_MOUNTDEV_QUERY_DEVICE_NAME returned %08x\n", Status); 3729 return FALSE; 3730 } 3731 3732 mdnsize = (ULONG)offsetof(MOUNTDEV_NAME, Name[0]) + mdn.NameLength; 3733 3734 mdn2 = ExAllocatePoolWithTag(PagedPool, mdnsize, ALLOC_TAG); 3735 if (!mdn2) { 3736 ERR("out of memory\n"); 3737 return FALSE; 3738 } 3739 3740 Status = dev_ioctl(DeviceObject, IOCTL_MOUNTDEV_QUERY_DEVICE_NAME, NULL, 0, mdn2, mdnsize, TRUE, NULL); 3741 if (!NT_SUCCESS(Status)) { 3742 ERR("IOCTL_MOUNTDEV_QUERY_DEVICE_NAME returned %08x\n", Status); 3743 ExFreePool(mdn2); 3744 return FALSE; 3745 } 3746 3747 if (mdn2->NameLength > wcslen(BTRFS_VOLUME_PREFIX) * sizeof(WCHAR) && 3748 RtlCompareMemory(mdn2->Name, BTRFS_VOLUME_PREFIX, wcslen(BTRFS_VOLUME_PREFIX) * sizeof(WCHAR)) == wcslen(BTRFS_VOLUME_PREFIX) * sizeof(WCHAR)) { 3749 ExFreePool(mdn2); 3750 return TRUE; 3751 } 3752 3753 ExFreePool(mdn2); 3754 3755 return FALSE; 3756 } 3757 3758 static NTSTATUS get_device_pnp_name_guid(_In_ PDEVICE_OBJECT DeviceObject, _Out_ PUNICODE_STRING pnp_name, _In_ const GUID* guid) { 3759 NTSTATUS Status; 3760 WCHAR *list = NULL, *s; 3761 3762 Status = IoGetDeviceInterfaces((PVOID)guid, NULL, 0, &list); 3763 if (!NT_SUCCESS(Status)) { 3764 ERR("IoGetDeviceInterfaces returned %08x\n", Status); 3765 return Status; 3766 } 3767 3768 s = list; 3769 while (s[0] != 0) { 3770 PFILE_OBJECT FileObject; 3771 PDEVICE_OBJECT devobj; 3772 UNICODE_STRING name; 3773 3774 name.Length = name.MaximumLength = (USHORT)wcslen(s) * sizeof(WCHAR); 3775 name.Buffer = s; 3776 3777 if (NT_SUCCESS(IoGetDeviceObjectPointer(&name, FILE_READ_ATTRIBUTES, &FileObject, &devobj))) { 3778 if (DeviceObject == devobj || DeviceObject == FileObject->DeviceObject) { 3779 ObDereferenceObject(FileObject); 3780 3781 pnp_name->Buffer = ExAllocatePoolWithTag(PagedPool, name.Length, ALLOC_TAG); 3782 if (!pnp_name->Buffer) { 3783 ERR("out of memory\n"); 3784 Status = STATUS_INSUFFICIENT_RESOURCES; 3785 goto end; 3786 } 3787 3788 RtlCopyMemory(pnp_name->Buffer, name.Buffer, name.Length); 3789 pnp_name->Length = pnp_name->MaximumLength = name.Length; 3790 3791 Status = STATUS_SUCCESS; 3792 goto end; 3793 } 3794 3795 ObDereferenceObject(FileObject); 3796 } 3797 3798 s = &s[wcslen(s) + 1]; 3799 } 3800 3801 pnp_name->Length = pnp_name->MaximumLength = 0; 3802 pnp_name->Buffer = 0; 3803 3804 Status = STATUS_NOT_FOUND; 3805 3806 end: 3807 if (list) 3808 ExFreePool(list); 3809 3810 return Status; 3811 } 3812 3813 NTSTATUS get_device_pnp_name(_In_ PDEVICE_OBJECT DeviceObject, _Out_ PUNICODE_STRING pnp_name, _Out_ const GUID** guid) { 3814 NTSTATUS Status; 3815 3816 Status = get_device_pnp_name_guid(DeviceObject, pnp_name, &GUID_DEVINTERFACE_VOLUME); 3817 if (NT_SUCCESS(Status)) { 3818 *guid = &GUID_DEVINTERFACE_VOLUME; 3819 return Status; 3820 } 3821 3822 Status = get_device_pnp_name_guid(DeviceObject, pnp_name, &GUID_DEVINTERFACE_HIDDEN_VOLUME); 3823 if (NT_SUCCESS(Status)) { 3824 *guid = &GUID_DEVINTERFACE_HIDDEN_VOLUME; 3825 return Status; 3826 } 3827 3828 Status = get_device_pnp_name_guid(DeviceObject, pnp_name, &GUID_DEVINTERFACE_DISK); 3829 if (NT_SUCCESS(Status)) { 3830 *guid = &GUID_DEVINTERFACE_DISK; 3831 return Status; 3832 } 3833 3834 return STATUS_NOT_FOUND; 3835 } 3836 3837 _Success_(return>=0) 3838 static NTSTATUS check_mount_device(_In_ PDEVICE_OBJECT DeviceObject, _Out_ BOOL* no_pnp) { 3839 NTSTATUS Status; 3840 ULONG to_read; 3841 superblock* sb; 3842 UINT32 crc32; 3843 UNICODE_STRING pnp_name; 3844 const GUID* guid; 3845 3846 to_read = DeviceObject->SectorSize == 0 ? sizeof(superblock) : (ULONG)sector_align(sizeof(superblock), DeviceObject->SectorSize); 3847 3848 sb = ExAllocatePoolWithTag(NonPagedPool, to_read, ALLOC_TAG); 3849 if (!sb) { 3850 ERR("out of memory\n"); 3851 return STATUS_INSUFFICIENT_RESOURCES; 3852 } 3853 3854 Status = sync_read_phys(DeviceObject, superblock_addrs[0], to_read, (PUCHAR)sb, TRUE); 3855 if (!NT_SUCCESS(Status)) { 3856 ERR("sync_read_phys returned %08x\n", Status); 3857 goto end; 3858 } 3859 3860 if (sb->magic != BTRFS_MAGIC) { 3861 Status = STATUS_SUCCESS; 3862 goto end; 3863 } 3864 3865 crc32 = ~calc_crc32c(0xffffffff, (UINT8*)&sb->uuid, (ULONG)sizeof(superblock) - sizeof(sb->checksum)); 3866 3867 if (crc32 != *((UINT32*)sb->checksum)) { 3868 WARN("crc32 was %08x, expected %08x\n", crc32, *((UINT32*)sb->checksum)); 3869 Status = STATUS_SUCCESS; 3870 goto end; 3871 } 3872 3873 DeviceObject->Flags &= ~DO_VERIFY_VOLUME; 3874 3875 pnp_name.Buffer = NULL; 3876 3877 Status = get_device_pnp_name(DeviceObject, &pnp_name, &guid); 3878 if (!NT_SUCCESS(Status)) { 3879 WARN("get_device_pnp_name returned %08x\n", Status); 3880 pnp_name.Length = 0; 3881 } 3882 3883 if (pnp_name.Length == 0) 3884 *no_pnp = TRUE; 3885 else { 3886 *no_pnp = FALSE; 3887 volume_arrival(drvobj, &pnp_name); 3888 } 3889 3890 if (pnp_name.Buffer) 3891 ExFreePool(pnp_name.Buffer); 3892 3893 Status = STATUS_SUCCESS; 3894 3895 end: 3896 ExFreePool(sb); 3897 3898 return Status; 3899 } 3900 3901 static BOOL still_has_superblock(_In_ PDEVICE_OBJECT device) { 3902 NTSTATUS Status; 3903 ULONG to_read; 3904 superblock* sb; 3905 PDEVICE_OBJECT device2; 3906 3907 if (!device) 3908 return FALSE; 3909 3910 to_read = device->SectorSize == 0 ? sizeof(superblock) : (ULONG)sector_align(sizeof(superblock), device->SectorSize); 3911 3912 sb = ExAllocatePoolWithTag(NonPagedPool, to_read, ALLOC_TAG); 3913 if (!sb) { 3914 ERR("out of memory\n"); 3915 return FALSE; 3916 } 3917 3918 Status = sync_read_phys(device, superblock_addrs[0], to_read, (PUCHAR)sb, TRUE); 3919 if (!NT_SUCCESS(Status)) { 3920 ERR("Failed to read superblock: %08x\n", Status); 3921 ExFreePool(sb); 3922 return FALSE; 3923 } 3924 3925 if (sb->magic != BTRFS_MAGIC) { 3926 TRACE("not a BTRFS volume\n"); 3927 ExFreePool(sb); 3928 return FALSE; 3929 } else { 3930 UINT32 crc32 = ~calc_crc32c(0xffffffff, (UINT8*)&sb->uuid, (ULONG)sizeof(superblock) - sizeof(sb->checksum)); 3931 3932 if (crc32 != *((UINT32*)sb->checksum)) { 3933 WARN("crc32 was %08x, expected %08x\n", crc32, *((UINT32*)sb->checksum)); 3934 ExFreePool(sb); 3935 return FALSE; 3936 } 3937 } 3938 3939 device2 = device; 3940 3941 do { 3942 device2->Flags &= ~DO_VERIFY_VOLUME; 3943 device2 = IoGetLowerDeviceObject(device2); 3944 } while (device2); 3945 3946 ExFreePool(sb); 3947 return TRUE; 3948 } 3949 3950 static NTSTATUS mount_vol(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { 3951 PIO_STACK_LOCATION IrpSp; 3952 PDEVICE_OBJECT NewDeviceObject = NULL; 3953 PDEVICE_OBJECT DeviceToMount, readobj; 3954 NTSTATUS Status; 3955 device_extension* Vcb = NULL; 3956 LIST_ENTRY *le, batchlist; 3957 KEY searchkey; 3958 traverse_ptr tp; 3959 fcb* root_fcb = NULL; 3960 ccb* root_ccb = NULL; 3961 BOOL init_lookaside = FALSE; 3962 device* dev; 3963 volume_device_extension* vde = NULL; 3964 pdo_device_extension* pdode = NULL; 3965 volume_child* vc; 3966 BOOL no_pnp = FALSE; 3967 UINT64 readobjsize; 3968 3969 TRACE("(%p, %p)\n", DeviceObject, Irp); 3970 3971 if (DeviceObject != master_devobj) { 3972 Status = STATUS_INVALID_DEVICE_REQUEST; 3973 goto exit; 3974 } 3975 3976 IrpSp = IoGetCurrentIrpStackLocation(Irp); 3977 DeviceToMount = IrpSp->Parameters.MountVolume.DeviceObject; 3978 3979 if (!is_btrfs_volume(DeviceToMount)) { 3980 Status = check_mount_device(DeviceToMount, &no_pnp); 3981 if (!NT_SUCCESS(Status)) 3982 WARN("check_mount_device returned %08x\n", Status); 3983 3984 if (!no_pnp) { 3985 Status = STATUS_UNRECOGNIZED_VOLUME; 3986 goto exit2; 3987 } 3988 } else { 3989 PDEVICE_OBJECT pdo; 3990 3991 pdo = DeviceToMount; 3992 3993 while (IoGetLowerDeviceObject(pdo)) { 3994 pdo = IoGetLowerDeviceObject(pdo); 3995 } 3996 3997 ExAcquireResourceSharedLite(&pdo_list_lock, TRUE); 3998 3999 le = pdo_list.Flink; 4000 while (le != &pdo_list) { 4001 pdo_device_extension* pdode = CONTAINING_RECORD(le, pdo_device_extension, list_entry); 4002 4003 if (pdode->pdo == pdo) { 4004 vde = pdode->vde; 4005 break; 4006 } 4007 4008 le = le->Flink; 4009 } 4010 4011 ExReleaseResourceLite(&pdo_list_lock); 4012 4013 if (!vde || vde->type != VCB_TYPE_VOLUME) { 4014 vde = NULL; 4015 Status = STATUS_UNRECOGNIZED_VOLUME; 4016 goto exit2; 4017 } 4018 } 4019 4020 if (vde) { 4021 pdode = vde->pdode; 4022 4023 ExAcquireResourceExclusiveLite(&pdode->child_lock, TRUE); 4024 4025 le = pdode->children.Flink; 4026 while (le != &pdode->children) { 4027 LIST_ENTRY* le2 = le->Flink; 4028 4029 vc = CONTAINING_RECORD(pdode->children.Flink, volume_child, list_entry); 4030 4031 if (!still_has_superblock(vc->devobj)) { 4032 remove_volume_child(vde, vc, FALSE); 4033 4034 if (pdode->num_children == 0) { 4035 ERR("error - number of devices is zero\n"); 4036 Status = STATUS_INTERNAL_ERROR; 4037 goto exit2; 4038 } 4039 4040 Status = STATUS_DEVICE_NOT_READY; 4041 goto exit2; 4042 } 4043 4044 le = le2; 4045 } 4046 4047 if (pdode->num_children == 0 || pdode->children_loaded == 0) { 4048 ERR("error - number of devices is zero\n"); 4049 Status = STATUS_INTERNAL_ERROR; 4050 goto exit; 4051 } 4052 4053 ExConvertExclusiveToSharedLite(&pdode->child_lock); 4054 4055 vc = CONTAINING_RECORD(pdode->children.Flink, volume_child, list_entry); 4056 4057 readobj = vc->devobj; 4058 readobjsize = vc->size; 4059 4060 vde->device->Characteristics &= ~FILE_DEVICE_SECURE_OPEN; 4061 } else { 4062 GET_LENGTH_INFORMATION gli; 4063 4064 vc = NULL; 4065 readobj = DeviceToMount; 4066 4067 Status = dev_ioctl(readobj, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, 4068 &gli, sizeof(gli), TRUE, NULL); 4069 4070 if (!NT_SUCCESS(Status)) { 4071 ERR("error reading length information: %08x\n", Status); 4072 goto exit; 4073 } 4074 4075 readobjsize = gli.Length.QuadPart; 4076 } 4077 4078 Status = IoCreateDevice(drvobj, sizeof(device_extension), NULL, FILE_DEVICE_DISK_FILE_SYSTEM, 0, FALSE, &NewDeviceObject); 4079 if (!NT_SUCCESS(Status)) { 4080 ERR("IoCreateDevice returned %08x\n", Status); 4081 Status = STATUS_UNRECOGNIZED_VOLUME; 4082 goto exit; 4083 } 4084 4085 NewDeviceObject->Flags |= DO_DIRECT_IO; 4086 4087 // Some programs seem to expect that the sector size will be 512, for 4088 // FILE_NO_INTERMEDIATE_BUFFERING and the like. 4089 NewDeviceObject->SectorSize = min(DeviceToMount->SectorSize, 512); 4090 4091 Vcb = (PVOID)NewDeviceObject->DeviceExtension; 4092 RtlZeroMemory(Vcb, sizeof(device_extension)); 4093 Vcb->type = VCB_TYPE_FS; 4094 Vcb->vde = vde; 4095 4096 ExInitializeResourceLite(&Vcb->tree_lock); 4097 Vcb->need_write = FALSE; 4098 4099 ExInitializeResourceLite(&Vcb->fcb_lock); 4100 ExInitializeResourceLite(&Vcb->chunk_lock); 4101 ExInitializeResourceLite(&Vcb->dirty_fcbs_lock); 4102 ExInitializeResourceLite(&Vcb->dirty_filerefs_lock); 4103 ExInitializeResourceLite(&Vcb->dirty_subvols_lock); 4104 ExInitializeResourceLite(&Vcb->scrub.stats_lock); 4105 4106 ExInitializeResourceLite(&Vcb->load_lock); 4107 ExAcquireResourceExclusiveLite(&Vcb->load_lock, TRUE); 4108 4109 ExAcquireResourceExclusiveLite(&Vcb->tree_lock, TRUE); 4110 4111 DeviceToMount->Flags |= DO_DIRECT_IO; 4112 4113 Status = read_superblock(Vcb, readobj, readobjsize); 4114 if (!NT_SUCCESS(Status)) { 4115 if (!IoIsErrorUserInduced(Status)) 4116 Status = STATUS_UNRECOGNIZED_VOLUME; 4117 else if (Irp->Tail.Overlay.Thread) 4118 IoSetHardErrorOrVerifyDevice(Irp, readobj); 4119 4120 goto exit; 4121 } 4122 4123 if (!vde && Vcb->superblock.num_devices > 1) { 4124 ERR("cannot mount multi-device FS with non-PNP device\n"); 4125 Status = STATUS_UNRECOGNIZED_VOLUME; 4126 goto exit; 4127 } 4128 4129 Status = registry_load_volume_options(Vcb); 4130 if (!NT_SUCCESS(Status)) { 4131 ERR("registry_load_volume_options returned %08x\n", Status); 4132 goto exit; 4133 } 4134 4135 if (pdode && pdode->children_loaded < pdode->num_children && (!Vcb->options.allow_degraded || !finished_probing || degraded_wait)) { 4136 ERR("could not mount as %u device(s) missing\n", pdode->num_children - pdode->children_loaded); 4137 Status = STATUS_DEVICE_NOT_READY; 4138 goto exit; 4139 } 4140 4141 if (Vcb->options.ignore) { 4142 TRACE("ignoring volume\n"); 4143 Status = STATUS_UNRECOGNIZED_VOLUME; 4144 goto exit; 4145 } 4146 4147 if (Vcb->superblock.incompat_flags & ~INCOMPAT_SUPPORTED) { 4148 WARN("cannot mount because of unsupported incompat flags (%llx)\n", Vcb->superblock.incompat_flags & ~INCOMPAT_SUPPORTED); 4149 Status = STATUS_UNRECOGNIZED_VOLUME; 4150 goto exit; 4151 } 4152 4153 Vcb->readonly = FALSE; 4154 if (Vcb->superblock.compat_ro_flags & ~COMPAT_RO_SUPPORTED) { 4155 WARN("mounting read-only because of unsupported flags (%llx)\n", Vcb->superblock.compat_ro_flags & ~COMPAT_RO_SUPPORTED); 4156 Vcb->readonly = TRUE; 4157 } 4158 4159 if (Vcb->options.readonly) 4160 Vcb->readonly = TRUE; 4161 4162 Vcb->superblock.generation++; 4163 Vcb->superblock.incompat_flags |= BTRFS_INCOMPAT_FLAGS_MIXED_BACKREF; 4164 4165 InitializeListHead(&Vcb->devices); 4166 dev = ExAllocatePoolWithTag(NonPagedPool, sizeof(device), ALLOC_TAG); 4167 if (!dev) { 4168 ERR("out of memory\n"); 4169 Status = STATUS_INSUFFICIENT_RESOURCES; 4170 goto exit; 4171 } 4172 4173 dev->devobj = readobj; 4174 RtlCopyMemory(&dev->devitem, &Vcb->superblock.dev_item, sizeof(DEV_ITEM)); 4175 4176 if (dev->devitem.num_bytes > readobjsize) { 4177 WARN("device %llx: DEV_ITEM says %llx bytes, but Windows only reports %llx\n", dev->devitem.dev_id, 4178 dev->devitem.num_bytes, readobjsize); 4179 4180 dev->devitem.num_bytes = readobjsize; 4181 } 4182 4183 dev->seeding = Vcb->superblock.flags & BTRFS_SUPERBLOCK_FLAGS_SEEDING ? TRUE : FALSE; 4184 4185 init_device(Vcb, dev, TRUE); 4186 4187 InsertTailList(&Vcb->devices, &dev->list_entry); 4188 Vcb->devices_loaded = 1; 4189 4190 if (DeviceToMount->Flags & DO_SYSTEM_BOOT_PARTITION) 4191 Vcb->disallow_dismount = TRUE; 4192 4193 TRACE("DeviceToMount = %p\n", DeviceToMount); 4194 TRACE("IrpSp->Parameters.MountVolume.Vpb = %p\n", IrpSp->Parameters.MountVolume.Vpb); 4195 4196 NewDeviceObject->StackSize = DeviceToMount->StackSize + 1; 4197 NewDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; 4198 4199 InitializeListHead(&Vcb->roots); 4200 InitializeListHead(&Vcb->drop_roots); 4201 4202 Vcb->log_to_phys_loaded = FALSE; 4203 4204 add_root(Vcb, BTRFS_ROOT_CHUNK, Vcb->superblock.chunk_tree_addr, Vcb->superblock.chunk_root_generation, NULL); 4205 4206 if (!Vcb->chunk_root) { 4207 ERR("Could not load chunk root.\n"); 4208 Status = STATUS_INTERNAL_ERROR; 4209 goto exit; 4210 } 4211 4212 InitializeListHead(&Vcb->sys_chunks); 4213 Status = load_sys_chunks(Vcb); 4214 if (!NT_SUCCESS(Status)) { 4215 ERR("load_sys_chunks returned %08x\n", Status); 4216 goto exit; 4217 } 4218 4219 InitializeListHead(&Vcb->chunks); 4220 InitializeListHead(&Vcb->trees); 4221 InitializeListHead(&Vcb->trees_hash); 4222 InitializeListHead(&Vcb->all_fcbs); 4223 InitializeListHead(&Vcb->dirty_fcbs); 4224 InitializeListHead(&Vcb->dirty_filerefs); 4225 InitializeListHead(&Vcb->dirty_subvols); 4226 InitializeListHead(&Vcb->send_ops); 4227 4228 InitializeListHead(&Vcb->DirNotifyList); 4229 InitializeListHead(&Vcb->scrub.errors); 4230 4231 FsRtlNotifyInitializeSync(&Vcb->NotifySync); 4232 4233 ExInitializePagedLookasideList(&Vcb->tree_data_lookaside, NULL, NULL, 0, sizeof(tree_data), ALLOC_TAG, 0); 4234 ExInitializePagedLookasideList(&Vcb->traverse_ptr_lookaside, NULL, NULL, 0, sizeof(traverse_ptr), ALLOC_TAG, 0); 4235 ExInitializePagedLookasideList(&Vcb->batch_item_lookaside, NULL, NULL, 0, sizeof(batch_item), ALLOC_TAG, 0); 4236 ExInitializePagedLookasideList(&Vcb->fileref_lookaside, NULL, NULL, 0, sizeof(file_ref), ALLOC_TAG, 0); 4237 ExInitializePagedLookasideList(&Vcb->fcb_lookaside, NULL, NULL, 0, sizeof(fcb), ALLOC_TAG, 0); 4238 ExInitializePagedLookasideList(&Vcb->name_bit_lookaside, NULL, NULL, 0, sizeof(name_bit), ALLOC_TAG, 0); 4239 ExInitializeNPagedLookasideList(&Vcb->range_lock_lookaside, NULL, NULL, 0, sizeof(range_lock), ALLOC_TAG, 0); 4240 ExInitializeNPagedLookasideList(&Vcb->fileref_np_lookaside, NULL, NULL, 0, sizeof(file_ref_nonpaged), ALLOC_TAG, 0); 4241 ExInitializeNPagedLookasideList(&Vcb->fcb_np_lookaside, NULL, NULL, 0, sizeof(fcb_nonpaged), ALLOC_TAG, 0); 4242 init_lookaside = TRUE; 4243 4244 Vcb->Vpb = IrpSp->Parameters.MountVolume.Vpb; 4245 4246 Status = load_chunk_root(Vcb, Irp); 4247 if (!NT_SUCCESS(Status)) { 4248 ERR("load_chunk_root returned %08x\n", Status); 4249 goto exit; 4250 } 4251 4252 if (Vcb->superblock.num_devices > 1) { 4253 if (Vcb->devices_loaded < Vcb->superblock.num_devices && (!Vcb->options.allow_degraded || !finished_probing)) { 4254 ERR("could not mount as %u device(s) missing\n", Vcb->superblock.num_devices - Vcb->devices_loaded); 4255 4256 IoRaiseInformationalHardError(IO_ERR_INTERNAL_ERROR, NULL, NULL); 4257 4258 Status = STATUS_INTERNAL_ERROR; 4259 goto exit; 4260 } 4261 4262 if (dev->readonly && !Vcb->readonly) { 4263 Vcb->readonly = TRUE; 4264 4265 le = Vcb->devices.Flink; 4266 while (le != &Vcb->devices) { 4267 device* dev2 = CONTAINING_RECORD(le, device, list_entry); 4268 4269 if (dev2->readonly && !dev2->seeding) 4270 break; 4271 4272 if (!dev2->readonly) { 4273 Vcb->readonly = FALSE; 4274 break; 4275 } 4276 4277 le = le->Flink; 4278 } 4279 4280 if (Vcb->readonly) 4281 WARN("setting volume to readonly\n"); 4282 } 4283 } else { 4284 if (dev->readonly) { 4285 WARN("setting volume to readonly as device is readonly\n"); 4286 Vcb->readonly = TRUE; 4287 } 4288 } 4289 4290 add_root(Vcb, BTRFS_ROOT_ROOT, Vcb->superblock.root_tree_addr, Vcb->superblock.generation - 1, NULL); 4291 4292 if (!Vcb->root_root) { 4293 ERR("Could not load root of roots.\n"); 4294 Status = STATUS_INTERNAL_ERROR; 4295 goto exit; 4296 } 4297 4298 Status = look_for_roots(Vcb, Irp); 4299 if (!NT_SUCCESS(Status)) { 4300 ERR("look_for_roots returned %08x\n", Status); 4301 goto exit; 4302 } 4303 4304 if (!Vcb->readonly) { 4305 Status = find_chunk_usage(Vcb, Irp); 4306 if (!NT_SUCCESS(Status)) { 4307 ERR("find_chunk_usage returned %08x\n", Status); 4308 goto exit; 4309 } 4310 } 4311 4312 InitializeListHead(&batchlist); 4313 4314 // We've already increased the generation by one 4315 if (!Vcb->readonly && ( 4316 Vcb->options.clear_cache || 4317 (!(Vcb->superblock.compat_ro_flags & BTRFS_COMPAT_RO_FLAGS_FREE_SPACE_CACHE) && Vcb->superblock.generation - 1 != Vcb->superblock.cache_generation) || 4318 (Vcb->superblock.compat_ro_flags & BTRFS_COMPAT_RO_FLAGS_FREE_SPACE_CACHE && !(Vcb->superblock.compat_ro_flags & BTRFS_COMPAT_RO_FLAGS_FREE_SPACE_CACHE_VALID)))) { 4319 if (Vcb->options.clear_cache) 4320 WARN("ClearCache option was set, clearing cache...\n"); 4321 else if (Vcb->superblock.compat_ro_flags & BTRFS_COMPAT_RO_FLAGS_FREE_SPACE_CACHE && !(Vcb->superblock.compat_ro_flags & BTRFS_COMPAT_RO_FLAGS_FREE_SPACE_CACHE_VALID)) 4322 WARN("clearing free-space tree created by buggy Linux driver\n"); 4323 else 4324 WARN("generation was %llx, free-space cache generation was %llx; clearing cache...\n", Vcb->superblock.generation - 1, Vcb->superblock.cache_generation); 4325 4326 Status = clear_free_space_cache(Vcb, &batchlist, Irp); 4327 if (!NT_SUCCESS(Status)) { 4328 ERR("clear_free_space_cache returned %08x\n", Status); 4329 clear_batch_list(Vcb, &batchlist); 4330 goto exit; 4331 } 4332 } 4333 4334 Status = commit_batch_list(Vcb, &batchlist, Irp); 4335 if (!NT_SUCCESS(Status)) { 4336 ERR("commit_batch_list returned %08x\n", Status); 4337 goto exit; 4338 } 4339 4340 Vcb->volume_fcb = create_fcb(Vcb, NonPagedPool); 4341 if (!Vcb->volume_fcb) { 4342 ERR("out of memory\n"); 4343 Status = STATUS_INSUFFICIENT_RESOURCES; 4344 goto exit; 4345 } 4346 4347 Vcb->volume_fcb->Vcb = Vcb; 4348 Vcb->volume_fcb->sd = NULL; 4349 4350 Vcb->dummy_fcb = create_fcb(Vcb, NonPagedPool); 4351 if (!Vcb->dummy_fcb) { 4352 ERR("out of memory\n"); 4353 Status = STATUS_INSUFFICIENT_RESOURCES; 4354 goto exit; 4355 } 4356 4357 Vcb->dummy_fcb->Vcb = Vcb; 4358 Vcb->dummy_fcb->type = BTRFS_TYPE_DIRECTORY; 4359 Vcb->dummy_fcb->inode = 2; 4360 Vcb->dummy_fcb->subvol = Vcb->root_root; 4361 Vcb->dummy_fcb->atts = FILE_ATTRIBUTE_DIRECTORY; 4362 Vcb->dummy_fcb->inode_item.st_nlink = 1; 4363 Vcb->dummy_fcb->inode_item.st_mode = __S_IFDIR; 4364 4365 Vcb->dummy_fcb->hash_ptrs = ExAllocatePoolWithTag(PagedPool, sizeof(LIST_ENTRY*) * 256, ALLOC_TAG); 4366 if (!Vcb->dummy_fcb->hash_ptrs) { 4367 ERR("out of memory\n"); 4368 Status = STATUS_INSUFFICIENT_RESOURCES; 4369 goto exit; 4370 } 4371 4372 RtlZeroMemory(Vcb->dummy_fcb->hash_ptrs, sizeof(LIST_ENTRY*) * 256); 4373 4374 Vcb->dummy_fcb->hash_ptrs_uc = ExAllocatePoolWithTag(PagedPool, sizeof(LIST_ENTRY*) * 256, ALLOC_TAG); 4375 if (!Vcb->dummy_fcb->hash_ptrs_uc) { 4376 ERR("out of memory\n"); 4377 Status = STATUS_INSUFFICIENT_RESOURCES; 4378 goto exit; 4379 } 4380 4381 RtlZeroMemory(Vcb->dummy_fcb->hash_ptrs_uc, sizeof(LIST_ENTRY*) * 256); 4382 4383 root_fcb = create_fcb(Vcb, NonPagedPool); 4384 if (!root_fcb) { 4385 ERR("out of memory\n"); 4386 Status = STATUS_INSUFFICIENT_RESOURCES; 4387 goto exit; 4388 } 4389 4390 root_fcb->Vcb = Vcb; 4391 root_fcb->inode = SUBVOL_ROOT_INODE; 4392 root_fcb->type = BTRFS_TYPE_DIRECTORY; 4393 4394 #ifdef DEBUG_FCB_REFCOUNTS 4395 WARN("volume FCB = %p\n", Vcb->volume_fcb); 4396 WARN("root FCB = %p\n", root_fcb); 4397 #endif 4398 4399 root_fcb->subvol = find_default_subvol(Vcb, Irp); 4400 4401 if (!root_fcb->subvol) { 4402 ERR("could not find top subvol\n"); 4403 Status = STATUS_INTERNAL_ERROR; 4404 goto exit; 4405 } 4406 4407 Status = load_dir_children(Vcb, root_fcb, TRUE, Irp); 4408 if (!NT_SUCCESS(Status)) { 4409 ERR("load_dir_children returned %08x\n", Status); 4410 goto exit; 4411 } 4412 4413 searchkey.obj_id = root_fcb->inode; 4414 searchkey.obj_type = TYPE_INODE_ITEM; 4415 searchkey.offset = 0xffffffffffffffff; 4416 4417 Status = find_item(Vcb, root_fcb->subvol, &tp, &searchkey, FALSE, Irp); 4418 if (!NT_SUCCESS(Status)) { 4419 ERR("error - find_item returned %08x\n", Status); 4420 goto exit; 4421 } 4422 4423 if (tp.item->key.obj_id != searchkey.obj_id || tp.item->key.obj_type != searchkey.obj_type) { 4424 ERR("couldn't find INODE_ITEM for root directory\n"); 4425 Status = STATUS_INTERNAL_ERROR; 4426 goto exit; 4427 } 4428 4429 if (tp.item->size > 0) 4430 RtlCopyMemory(&root_fcb->inode_item, tp.item->data, min(sizeof(INODE_ITEM), tp.item->size)); 4431 4432 fcb_get_sd(root_fcb, NULL, TRUE, Irp); 4433 4434 root_fcb->atts = get_file_attributes(Vcb, root_fcb->subvol, root_fcb->inode, root_fcb->type, FALSE, FALSE, Irp); 4435 4436 Vcb->root_fileref = create_fileref(Vcb); 4437 if (!Vcb->root_fileref) { 4438 ERR("out of memory\n"); 4439 Status = STATUS_INSUFFICIENT_RESOURCES; 4440 goto exit; 4441 } 4442 4443 Vcb->root_fileref->fcb = root_fcb; 4444 InsertTailList(&root_fcb->subvol->fcbs, &root_fcb->list_entry); 4445 InsertTailList(&Vcb->all_fcbs, &root_fcb->list_entry_all); 4446 4447 root_fcb->fileref = Vcb->root_fileref; 4448 4449 root_ccb = ExAllocatePoolWithTag(PagedPool, sizeof(ccb), ALLOC_TAG); 4450 if (!root_ccb) { 4451 ERR("out of memory\n"); 4452 Status = STATUS_INSUFFICIENT_RESOURCES; 4453 goto exit; 4454 } 4455 4456 Vcb->root_file = IoCreateStreamFileObject(NULL, DeviceToMount); 4457 Vcb->root_file->FsContext = root_fcb; 4458 Vcb->root_file->SectionObjectPointer = &root_fcb->nonpaged->segment_object; 4459 Vcb->root_file->Vpb = DeviceObject->Vpb; 4460 4461 RtlZeroMemory(root_ccb, sizeof(ccb)); 4462 root_ccb->NodeType = BTRFS_NODE_TYPE_CCB; 4463 root_ccb->NodeSize = sizeof(ccb); 4464 4465 Vcb->root_file->FsContext2 = root_ccb; 4466 4467 _SEH2_TRY { 4468 CcInitializeCacheMap(Vcb->root_file, (PCC_FILE_SIZES)(&root_fcb->Header.AllocationSize), FALSE, cache_callbacks, Vcb->root_file); 4469 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) { 4470 Status = _SEH2_GetExceptionCode(); 4471 goto exit; 4472 } _SEH2_END; 4473 4474 le = Vcb->devices.Flink; 4475 while (le != &Vcb->devices) { 4476 device* dev2 = CONTAINING_RECORD(le, device, list_entry); 4477 4478 Status = find_disk_holes(Vcb, dev2, Irp); 4479 if (!NT_SUCCESS(Status)) { 4480 ERR("find_disk_holes returned %08x\n", Status); 4481 goto exit; 4482 } 4483 4484 le = le->Flink; 4485 } 4486 4487 NewDeviceObject->Vpb = IrpSp->Parameters.MountVolume.Vpb; 4488 IrpSp->Parameters.MountVolume.Vpb->DeviceObject = NewDeviceObject; 4489 IrpSp->Parameters.MountVolume.Vpb->Flags |= VPB_MOUNTED; 4490 NewDeviceObject->Vpb->VolumeLabelLength = 4; // FIXME 4491 NewDeviceObject->Vpb->VolumeLabel[0] = '?'; 4492 NewDeviceObject->Vpb->VolumeLabel[1] = 0; 4493 NewDeviceObject->Vpb->ReferenceCount++; // FIXME - should we deref this at any point? 4494 4495 KeInitializeEvent(&Vcb->flush_thread_finished, NotificationEvent, FALSE); 4496 4497 Status = PsCreateSystemThread(&Vcb->flush_thread_handle, 0, NULL, NULL, NULL, flush_thread, NewDeviceObject); 4498 if (!NT_SUCCESS(Status)) { 4499 ERR("PsCreateSystemThread returned %08x\n", Status); 4500 goto exit; 4501 } 4502 4503 Status = create_calc_threads(NewDeviceObject); 4504 if (!NT_SUCCESS(Status)) { 4505 ERR("create_calc_threads returned %08x\n", Status); 4506 goto exit; 4507 } 4508 4509 Status = registry_mark_volume_mounted(&Vcb->superblock.uuid); 4510 if (!NT_SUCCESS(Status)) 4511 WARN("registry_mark_volume_mounted returned %08x\n", Status); 4512 4513 Status = look_for_balance_item(Vcb); 4514 if (!NT_SUCCESS(Status) && Status != STATUS_NOT_FOUND) 4515 WARN("look_for_balance_item returned %08x\n", Status); 4516 4517 Status = STATUS_SUCCESS; 4518 4519 if (vde) 4520 vde->mounted_device = NewDeviceObject; 4521 4522 ExInitializeResourceLite(&Vcb->send_load_lock); 4523 4524 exit: 4525 if (pdode) 4526 ExReleaseResourceLite(&pdode->child_lock); 4527 4528 exit2: 4529 if (Vcb) { 4530 ExReleaseResourceLite(&Vcb->tree_lock); 4531 ExReleaseResourceLite(&Vcb->load_lock); 4532 } 4533 4534 if (!NT_SUCCESS(Status)) { 4535 if (Vcb) { 4536 if (init_lookaside) { 4537 ExDeletePagedLookasideList(&Vcb->tree_data_lookaside); 4538 ExDeletePagedLookasideList(&Vcb->traverse_ptr_lookaside); 4539 ExDeletePagedLookasideList(&Vcb->batch_item_lookaside); 4540 ExDeletePagedLookasideList(&Vcb->fileref_lookaside); 4541 ExDeletePagedLookasideList(&Vcb->fcb_lookaside); 4542 ExDeletePagedLookasideList(&Vcb->name_bit_lookaside); 4543 ExDeleteNPagedLookasideList(&Vcb->range_lock_lookaside); 4544 ExDeleteNPagedLookasideList(&Vcb->fileref_np_lookaside); 4545 ExDeleteNPagedLookasideList(&Vcb->fcb_np_lookaside); 4546 } 4547 4548 if (Vcb->root_file) 4549 ObDereferenceObject(Vcb->root_file); 4550 else if (Vcb->root_fileref) { 4551 acquire_fcb_lock_exclusive(Vcb); 4552 free_fileref(Vcb, Vcb->root_fileref); 4553 release_fcb_lock(Vcb); 4554 } else if (root_fcb) { 4555 acquire_fcb_lock_exclusive(Vcb); 4556 free_fcb(Vcb, root_fcb); 4557 release_fcb_lock(Vcb); 4558 } 4559 4560 if (Vcb->volume_fcb) { 4561 acquire_fcb_lock_exclusive(Vcb); 4562 free_fcb(Vcb, Vcb->volume_fcb); 4563 release_fcb_lock(Vcb); 4564 } 4565 4566 ExDeleteResourceLite(&Vcb->tree_lock); 4567 ExDeleteResourceLite(&Vcb->load_lock); 4568 ExDeleteResourceLite(&Vcb->fcb_lock); 4569 ExDeleteResourceLite(&Vcb->chunk_lock); 4570 ExDeleteResourceLite(&Vcb->dirty_fcbs_lock); 4571 ExDeleteResourceLite(&Vcb->dirty_filerefs_lock); 4572 ExDeleteResourceLite(&Vcb->dirty_subvols_lock); 4573 ExDeleteResourceLite(&Vcb->scrub.stats_lock); 4574 4575 if (Vcb->devices.Flink) { 4576 while (!IsListEmpty(&Vcb->devices)) { 4577 device* dev2 = CONTAINING_RECORD(RemoveHeadList(&Vcb->devices), device, list_entry); 4578 4579 ExFreePool(dev2); 4580 } 4581 } 4582 } 4583 4584 if (NewDeviceObject) 4585 IoDeleteDevice(NewDeviceObject); 4586 } else { 4587 ExAcquireResourceExclusiveLite(&global_loading_lock, TRUE); 4588 InsertTailList(&VcbList, &Vcb->list_entry); 4589 ExReleaseResourceLite(&global_loading_lock); 4590 4591 FsRtlNotifyVolumeEvent(Vcb->root_file, FSRTL_VOLUME_MOUNT); 4592 } 4593 4594 TRACE("mount_vol done (status: %lx)\n", Status); 4595 4596 return Status; 4597 } 4598 4599 static NTSTATUS verify_device(_In_ device_extension* Vcb, _Inout_ device* dev) { 4600 NTSTATUS Status; 4601 superblock* sb; 4602 UINT32 crc32; 4603 ULONG to_read, cc; 4604 4605 if (!dev->devobj) 4606 return STATUS_WRONG_VOLUME; 4607 4608 if (dev->removable) { 4609 IO_STATUS_BLOCK iosb; 4610 4611 Status = dev_ioctl(dev->devobj, IOCTL_STORAGE_CHECK_VERIFY, NULL, 0, &cc, sizeof(ULONG), TRUE, &iosb); 4612 4613 if (IoIsErrorUserInduced(Status)) { 4614 ERR("IOCTL_STORAGE_CHECK_VERIFY returned %08x (user-induced)\n", Status); 4615 4616 if (Vcb->vde) { 4617 pdo_device_extension* pdode = Vcb->vde->pdode; 4618 LIST_ENTRY* le2; 4619 BOOL changed = FALSE; 4620 4621 ExAcquireResourceExclusiveLite(&pdode->child_lock, TRUE); 4622 4623 le2 = pdode->children.Flink; 4624 while (le2 != &pdode->children) { 4625 volume_child* vc = CONTAINING_RECORD(le2, volume_child, list_entry); 4626 4627 if (vc->devobj == dev->devobj) { 4628 TRACE("removing device\n"); 4629 4630 remove_volume_child(Vcb->vde, vc, TRUE); 4631 changed = TRUE; 4632 4633 break; 4634 } 4635 4636 le2 = le2->Flink; 4637 } 4638 4639 if (!changed) 4640 ExReleaseResourceLite(&pdode->child_lock); 4641 } 4642 } else if (!NT_SUCCESS(Status)) { 4643 ERR("IOCTL_STORAGE_CHECK_VERIFY returned %08x\n", Status); 4644 return Status; 4645 } else if (iosb.Information < sizeof(ULONG)) { 4646 ERR("iosb.Information was too short\n"); 4647 return STATUS_INTERNAL_ERROR; 4648 } 4649 4650 dev->change_count = cc; 4651 } 4652 4653 to_read = dev->devobj->SectorSize == 0 ? sizeof(superblock) : (ULONG)sector_align(sizeof(superblock), dev->devobj->SectorSize); 4654 4655 sb = ExAllocatePoolWithTag(NonPagedPool, to_read, ALLOC_TAG); 4656 if (!sb) { 4657 ERR("out of memory\n"); 4658 return STATUS_INSUFFICIENT_RESOURCES; 4659 } 4660 4661 Status = sync_read_phys(dev->devobj, superblock_addrs[0], to_read, (PUCHAR)sb, TRUE); 4662 if (!NT_SUCCESS(Status)) { 4663 ERR("Failed to read superblock: %08x\n", Status); 4664 ExFreePool(sb); 4665 return Status; 4666 } 4667 4668 if (sb->magic != BTRFS_MAGIC) { 4669 ERR("not a BTRFS volume\n"); 4670 ExFreePool(sb); 4671 return STATUS_WRONG_VOLUME; 4672 } 4673 4674 crc32 = ~calc_crc32c(0xffffffff, (UINT8*)&sb->uuid, (ULONG)sizeof(superblock) - sizeof(sb->checksum)); 4675 TRACE("crc32 was %08x, expected %08x\n", crc32, *((UINT32*)sb->checksum)); 4676 4677 if (crc32 != *((UINT32*)sb->checksum)) { 4678 ERR("checksum error\n"); 4679 ExFreePool(sb); 4680 return STATUS_WRONG_VOLUME; 4681 } 4682 4683 if (RtlCompareMemory(&sb->uuid, &Vcb->superblock.uuid, sizeof(BTRFS_UUID)) != sizeof(BTRFS_UUID)) { 4684 ERR("different UUIDs\n"); 4685 ExFreePool(sb); 4686 return STATUS_WRONG_VOLUME; 4687 } 4688 4689 ExFreePool(sb); 4690 4691 dev->devobj->Flags &= ~DO_VERIFY_VOLUME; 4692 4693 return STATUS_SUCCESS; 4694 } 4695 4696 static NTSTATUS verify_volume(_In_ PDEVICE_OBJECT devobj) { 4697 device_extension* Vcb = devobj->DeviceExtension; 4698 NTSTATUS Status; 4699 LIST_ENTRY* le; 4700 UINT64 failed_devices = 0; 4701 BOOL locked = FALSE, remove = FALSE; 4702 4703 if (!(Vcb->Vpb->Flags & VPB_MOUNTED)) 4704 return STATUS_WRONG_VOLUME; 4705 4706 if (!ExIsResourceAcquiredExclusive(&Vcb->tree_lock)) { 4707 ExAcquireResourceExclusiveLite(&Vcb->tree_lock, TRUE); 4708 locked = TRUE; 4709 } 4710 4711 if (Vcb->removing) { 4712 if (locked) ExReleaseResourceLite(&Vcb->tree_lock); 4713 return STATUS_WRONG_VOLUME; 4714 } 4715 4716 InterlockedIncrement(&Vcb->open_files); // so pnp_surprise_removal doesn't uninit the device while we're still using it 4717 4718 le = Vcb->devices.Flink; 4719 while (le != &Vcb->devices) { 4720 device* dev = CONTAINING_RECORD(le, device, list_entry); 4721 4722 Status = verify_device(Vcb, dev); 4723 if (!NT_SUCCESS(Status)) { 4724 failed_devices++; 4725 4726 if (dev->devobj && Vcb->options.allow_degraded) 4727 dev->devobj = NULL; 4728 } 4729 4730 le = le->Flink; 4731 } 4732 4733 InterlockedDecrement(&Vcb->open_files); 4734 4735 if (Vcb->removing && Vcb->open_files == 0) 4736 remove = TRUE; 4737 4738 if (locked) 4739 ExReleaseResourceLite(&Vcb->tree_lock); 4740 4741 if (remove) { 4742 uninit(Vcb, FALSE); 4743 return Status; 4744 } 4745 4746 if (failed_devices == 0 || (Vcb->options.allow_degraded && failed_devices < Vcb->superblock.num_devices)) { 4747 Vcb->Vpb->RealDevice->Flags &= ~DO_VERIFY_VOLUME; 4748 4749 return STATUS_SUCCESS; 4750 } 4751 4752 return Status; 4753 } 4754 4755 _Dispatch_type_(IRP_MJ_FILE_SYSTEM_CONTROL) 4756 _Function_class_(DRIVER_DISPATCH) 4757 static NTSTATUS drv_file_system_control(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { 4758 PIO_STACK_LOCATION IrpSp; 4759 NTSTATUS Status; 4760 device_extension* Vcb = DeviceObject->DeviceExtension; 4761 BOOL top_level; 4762 4763 FsRtlEnterFileSystem(); 4764 4765 TRACE("file system control\n"); 4766 4767 top_level = is_top_level(Irp); 4768 4769 if (Vcb && Vcb->type == VCB_TYPE_VOLUME) { 4770 Status = vol_file_system_control(DeviceObject, Irp); 4771 goto end; 4772 } else if (!Vcb || (Vcb->type != VCB_TYPE_FS && Vcb->type != VCB_TYPE_CONTROL)) { 4773 Status = STATUS_INVALID_PARAMETER; 4774 goto end; 4775 } 4776 4777 Status = STATUS_NOT_IMPLEMENTED; 4778 4779 IrpSp = IoGetCurrentIrpStackLocation( Irp ); 4780 4781 Irp->IoStatus.Information = 0; 4782 4783 switch (IrpSp->MinorFunction) { 4784 case IRP_MN_MOUNT_VOLUME: 4785 TRACE("IRP_MN_MOUNT_VOLUME\n"); 4786 4787 Status = mount_vol(DeviceObject, Irp); 4788 break; 4789 4790 case IRP_MN_KERNEL_CALL: 4791 TRACE("IRP_MN_KERNEL_CALL\n"); 4792 4793 Status = fsctl_request(DeviceObject, &Irp, IrpSp->Parameters.FileSystemControl.FsControlCode); 4794 break; 4795 4796 case IRP_MN_USER_FS_REQUEST: 4797 TRACE("IRP_MN_USER_FS_REQUEST\n"); 4798 4799 Status = fsctl_request(DeviceObject, &Irp, IrpSp->Parameters.FileSystemControl.FsControlCode); 4800 break; 4801 4802 case IRP_MN_VERIFY_VOLUME: 4803 TRACE("IRP_MN_VERIFY_VOLUME\n"); 4804 4805 Status = verify_volume(DeviceObject); 4806 4807 if (!NT_SUCCESS(Status) && Vcb->Vpb->Flags & VPB_MOUNTED) { 4808 ExAcquireResourceExclusiveLite(&Vcb->tree_lock, TRUE); 4809 Vcb->removing = TRUE; 4810 ExReleaseResourceLite(&Vcb->tree_lock); 4811 } 4812 4813 break; 4814 4815 default: 4816 break; 4817 } 4818 4819 end: 4820 TRACE("returning %08x\n", Status); 4821 4822 if (Irp) { 4823 Irp->IoStatus.Status = Status; 4824 4825 IoCompleteRequest(Irp, IO_NO_INCREMENT); 4826 } 4827 4828 if (top_level) 4829 IoSetTopLevelIrp(NULL); 4830 4831 FsRtlExitFileSystem(); 4832 4833 return Status; 4834 } 4835 4836 _Dispatch_type_(IRP_MJ_LOCK_CONTROL) 4837 _Function_class_(DRIVER_DISPATCH) 4838 static NTSTATUS drv_lock_control(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { 4839 NTSTATUS Status; 4840 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); 4841 fcb* fcb = IrpSp->FileObject->FsContext; 4842 device_extension* Vcb = DeviceObject->DeviceExtension; 4843 BOOL top_level; 4844 4845 FsRtlEnterFileSystem(); 4846 4847 top_level = is_top_level(Irp); 4848 4849 if (Vcb && Vcb->type == VCB_TYPE_VOLUME) { 4850 Status = vol_lock_control(DeviceObject, Irp); 4851 4852 Irp->IoStatus.Status = Status; 4853 IoCompleteRequest(Irp, IO_NO_INCREMENT); 4854 4855 goto exit; 4856 } 4857 4858 TRACE("lock control\n"); 4859 4860 Status = FsRtlProcessFileLock(&fcb->lock, Irp, NULL); 4861 4862 fcb->Header.IsFastIoPossible = fast_io_possible(fcb); 4863 4864 exit: 4865 TRACE("returning %08x\n", Status); 4866 4867 if (top_level) 4868 IoSetTopLevelIrp(NULL); 4869 4870 FsRtlExitFileSystem(); 4871 4872 return Status; 4873 } 4874 4875 _Dispatch_type_(IRP_MJ_SHUTDOWN) 4876 _Function_class_(DRIVER_DISPATCH) 4877 static NTSTATUS drv_shutdown(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { 4878 NTSTATUS Status; 4879 BOOL top_level; 4880 device_extension* Vcb = DeviceObject->DeviceExtension; 4881 4882 FsRtlEnterFileSystem(); 4883 4884 TRACE("shutdown\n"); 4885 4886 top_level = is_top_level(Irp); 4887 4888 if (Vcb && Vcb->type == VCB_TYPE_VOLUME) { 4889 Status = vol_shutdown(DeviceObject, Irp); 4890 goto end; 4891 } 4892 4893 Status = STATUS_SUCCESS; 4894 4895 shutting_down = TRUE; 4896 KeSetEvent(&mountmgr_thread_event, 0, FALSE); 4897 4898 while (!IsListEmpty(&VcbList)) { 4899 Vcb = CONTAINING_RECORD(VcbList.Flink, device_extension, list_entry); 4900 4901 TRACE("shutting down Vcb %p\n", Vcb); 4902 4903 uninit(Vcb, TRUE); 4904 } 4905 4906 #ifdef _DEBUG 4907 if (comfo) { 4908 ObDereferenceObject(comfo); 4909 comdo = NULL; 4910 comfo = NULL; 4911 } 4912 #endif 4913 4914 end: 4915 Irp->IoStatus.Status = Status; 4916 Irp->IoStatus.Information = 0; 4917 4918 IoCompleteRequest( Irp, IO_NO_INCREMENT ); 4919 4920 if (top_level) 4921 IoSetTopLevelIrp(NULL); 4922 4923 FsRtlExitFileSystem(); 4924 4925 return Status; 4926 } 4927 4928 _Dispatch_type_(IRP_MJ_POWER) 4929 _Function_class_(DRIVER_DISPATCH) 4930 static NTSTATUS drv_power(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { 4931 NTSTATUS Status; 4932 device_extension* Vcb = DeviceObject->DeviceExtension; 4933 BOOL top_level; 4934 4935 FsRtlEnterFileSystem(); 4936 4937 top_level = is_top_level(Irp); 4938 4939 Irp->IoStatus.Information = 0; 4940 4941 if (Vcb && Vcb->type == VCB_TYPE_VOLUME) { 4942 Status = vol_power(DeviceObject, Irp); 4943 4944 Irp->IoStatus.Status = Status; 4945 IoCompleteRequest(Irp, IO_NO_INCREMENT); 4946 4947 goto exit; 4948 } else if (Vcb && Vcb->type == VCB_TYPE_FS) { 4949 IoSkipCurrentIrpStackLocation(Irp); 4950 4951 Status = IoCallDriver(Vcb->Vpb->RealDevice, Irp); 4952 4953 goto exit; 4954 } 4955 4956 Status = STATUS_INVALID_DEVICE_REQUEST; 4957 Irp->IoStatus.Status = Status; 4958 IoCompleteRequest(Irp, IO_NO_INCREMENT); 4959 4960 exit: 4961 if (top_level) 4962 IoSetTopLevelIrp(NULL); 4963 4964 FsRtlExitFileSystem(); 4965 4966 return Status; 4967 } 4968 4969 _Dispatch_type_(IRP_MJ_SYSTEM_CONTROL) 4970 _Function_class_(DRIVER_DISPATCH) 4971 static NTSTATUS drv_system_control(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { 4972 NTSTATUS Status; 4973 device_extension* Vcb = DeviceObject->DeviceExtension; 4974 BOOL top_level; 4975 4976 FsRtlEnterFileSystem(); 4977 4978 top_level = is_top_level(Irp); 4979 4980 Irp->IoStatus.Information = 0; 4981 4982 if (Vcb && Vcb->type == VCB_TYPE_VOLUME) { 4983 volume_device_extension* vde = DeviceObject->DeviceExtension; 4984 4985 IoSkipCurrentIrpStackLocation(Irp); 4986 4987 Status = IoCallDriver(vde->pdo, Irp); 4988 4989 goto exit; 4990 } else if (Vcb && Vcb->type == VCB_TYPE_FS) { 4991 IoSkipCurrentIrpStackLocation(Irp); 4992 4993 Status = IoCallDriver(Vcb->Vpb->RealDevice, Irp); 4994 4995 goto exit; 4996 } 4997 4998 Status = Irp->IoStatus.Status; 4999 IoCompleteRequest(Irp, IO_NO_INCREMENT); 5000 5001 exit: 5002 if (top_level) 5003 IoSetTopLevelIrp(NULL); 5004 5005 FsRtlExitFileSystem(); 5006 5007 return Status; 5008 } 5009 5010 BOOL is_file_name_valid(_In_ PUNICODE_STRING us, _In_ BOOL posix) { 5011 ULONG i; 5012 5013 if (us->Length < sizeof(WCHAR)) 5014 return FALSE; 5015 5016 if (us->Length > 255 * sizeof(WCHAR)) 5017 return FALSE; 5018 5019 for (i = 0; i < us->Length / sizeof(WCHAR); i++) { 5020 if (us->Buffer[i] == '/' || us->Buffer[i] == 0 || 5021 (!posix && (us->Buffer[i] == '<' || us->Buffer[i] == '>' || us->Buffer[i] == ':' || us->Buffer[i] == '"' || 5022 us->Buffer[i] == '|' || us->Buffer[i] == '?' || us->Buffer[i] == '*' || (us->Buffer[i] >= 1 && us->Buffer[i] <= 31)))) 5023 return FALSE; 5024 } 5025 5026 if (us->Buffer[0] == '.' && (us->Length == sizeof(WCHAR) || (us->Length == 2 * sizeof(WCHAR) && us->Buffer[1] == '.'))) 5027 return FALSE; 5028 5029 return TRUE; 5030 } 5031 5032 void chunk_lock_range(_In_ device_extension* Vcb, _In_ chunk* c, _In_ UINT64 start, _In_ UINT64 length) { 5033 LIST_ENTRY* le; 5034 BOOL locked; 5035 range_lock* rl; 5036 5037 rl = ExAllocateFromNPagedLookasideList(&Vcb->range_lock_lookaside); 5038 if (!rl) { 5039 ERR("out of memory\n"); 5040 return; 5041 } 5042 5043 rl->start = start; 5044 rl->length = length; 5045 rl->thread = PsGetCurrentThread(); 5046 5047 while (TRUE) { 5048 locked = FALSE; 5049 5050 ExAcquireResourceExclusiveLite(&c->range_locks_lock, TRUE); 5051 5052 le = c->range_locks.Flink; 5053 while (le != &c->range_locks) { 5054 range_lock* rl2 = CONTAINING_RECORD(le, range_lock, list_entry); 5055 5056 if (rl2->start < start + length && rl2->start + rl2->length > start && rl2->thread != PsGetCurrentThread()) { 5057 locked = TRUE; 5058 break; 5059 } 5060 5061 le = le->Flink; 5062 } 5063 5064 if (!locked) { 5065 InsertTailList(&c->range_locks, &rl->list_entry); 5066 5067 ExReleaseResourceLite(&c->range_locks_lock); 5068 return; 5069 } 5070 5071 KeClearEvent(&c->range_locks_event); 5072 5073 ExReleaseResourceLite(&c->range_locks_lock); 5074 5075 KeWaitForSingleObject(&c->range_locks_event, UserRequest, KernelMode, FALSE, NULL); 5076 } 5077 } 5078 5079 void chunk_unlock_range(_In_ device_extension* Vcb, _In_ chunk* c, _In_ UINT64 start, _In_ UINT64 length) { 5080 LIST_ENTRY* le; 5081 5082 ExAcquireResourceExclusiveLite(&c->range_locks_lock, TRUE); 5083 5084 le = c->range_locks.Flink; 5085 while (le != &c->range_locks) { 5086 range_lock* rl = CONTAINING_RECORD(le, range_lock, list_entry); 5087 5088 if (rl->start == start && rl->length == length) { 5089 RemoveEntryList(&rl->list_entry); 5090 ExFreeToNPagedLookasideList(&Vcb->range_lock_lookaside, rl); 5091 break; 5092 } 5093 5094 le = le->Flink; 5095 } 5096 5097 KeSetEvent(&c->range_locks_event, 0, FALSE); 5098 5099 ExReleaseResourceLite(&c->range_locks_lock); 5100 } 5101 5102 void log_device_error(_In_ device_extension* Vcb, _Inout_ device* dev, _In_ int error) { 5103 dev->stats[error]++; 5104 dev->stats_changed = TRUE; 5105 Vcb->stats_changed = TRUE; 5106 } 5107 5108 #ifdef _DEBUG 5109 _Function_class_(KSTART_ROUTINE) 5110 static void serial_thread(void* context) { 5111 LARGE_INTEGER due_time; 5112 KTIMER timer; 5113 5114 UNUSED(context); 5115 5116 KeInitializeTimer(&timer); 5117 5118 due_time.QuadPart = (UINT64)-10000000; 5119 5120 KeSetTimer(&timer, due_time, NULL); 5121 5122 while (TRUE) { 5123 KeWaitForSingleObject(&timer, Executive, KernelMode, FALSE, NULL); 5124 5125 init_serial(FALSE); 5126 5127 if (comdo) 5128 break; 5129 5130 KeSetTimer(&timer, due_time, NULL); 5131 } 5132 5133 KeCancelTimer(&timer); 5134 5135 PsTerminateSystemThread(STATUS_SUCCESS); 5136 5137 serial_thread_handle = NULL; 5138 } 5139 5140 static void init_serial(BOOL first_time) { 5141 NTSTATUS Status; 5142 5143 Status = IoGetDeviceObjectPointer(&log_device, FILE_WRITE_DATA, &comfo, &comdo); 5144 if (!NT_SUCCESS(Status)) { 5145 ERR("IoGetDeviceObjectPointer returned %08x\n", Status); 5146 5147 if (first_time) { 5148 NTSTATUS Status; 5149 5150 Status = PsCreateSystemThread(&serial_thread_handle, 0, NULL, NULL, NULL, serial_thread, NULL); 5151 if (!NT_SUCCESS(Status)) { 5152 ERR("PsCreateSystemThread returned %08x\n", Status); 5153 return; 5154 } 5155 } 5156 } 5157 } 5158 #endif 5159 5160 #ifndef __REACTOS__ 5161 static void check_cpu() { 5162 unsigned int cpuInfo[4]; 5163 #ifndef _MSC_VER 5164 __get_cpuid(1, &cpuInfo[0], &cpuInfo[1], &cpuInfo[2], &cpuInfo[3]); 5165 have_sse42 = cpuInfo[2] & bit_SSE4_2; 5166 have_sse2 = cpuInfo[3] & bit_SSE2; 5167 #else 5168 __cpuid(cpuInfo, 1); 5169 have_sse42 = cpuInfo[2] & (1 << 20); 5170 have_sse2 = cpuInfo[3] & (1 << 26); 5171 #endif 5172 5173 if (have_sse42) 5174 TRACE("SSE4.2 is supported\n"); 5175 else 5176 TRACE("SSE4.2 not supported\n"); 5177 5178 if (have_sse2) 5179 TRACE("SSE2 is supported\n"); 5180 else 5181 TRACE("SSE2 is not supported\n"); 5182 } 5183 #endif 5184 5185 #ifdef _DEBUG 5186 static void init_logging() { 5187 ExAcquireResourceExclusiveLite(&log_lock, TRUE); 5188 5189 if (log_device.Length > 0) 5190 init_serial(TRUE); 5191 else if (log_file.Length > 0) { 5192 NTSTATUS Status; 5193 OBJECT_ATTRIBUTES oa; 5194 IO_STATUS_BLOCK iosb; 5195 char* dateline; 5196 LARGE_INTEGER time; 5197 TIME_FIELDS tf; 5198 5199 InitializeObjectAttributes(&oa, &log_file, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); 5200 5201 Status = ZwCreateFile(&log_handle, FILE_WRITE_DATA, &oa, &iosb, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, 5202 FILE_OPEN_IF, FILE_NON_DIRECTORY_FILE | FILE_WRITE_THROUGH | FILE_SYNCHRONOUS_IO_ALERT, NULL, 0); 5203 5204 if (!NT_SUCCESS(Status)) { 5205 ERR("ZwCreateFile returned %08x\n", Status); 5206 goto end; 5207 } 5208 5209 if (iosb.Information == FILE_OPENED) { // already exists 5210 FILE_STANDARD_INFORMATION fsi; 5211 FILE_POSITION_INFORMATION fpi; 5212 5213 static char delim[] = "\n---\n"; 5214 5215 // move to end of file 5216 5217 Status = ZwQueryInformationFile(log_handle, &iosb, &fsi, sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation); 5218 5219 if (!NT_SUCCESS(Status)) { 5220 ERR("ZwQueryInformationFile returned %08x\n", Status); 5221 goto end; 5222 } 5223 5224 fpi.CurrentByteOffset = fsi.EndOfFile; 5225 5226 Status = ZwSetInformationFile(log_handle, &iosb, &fpi, sizeof(FILE_POSITION_INFORMATION), FilePositionInformation); 5227 5228 if (!NT_SUCCESS(Status)) { 5229 ERR("ZwSetInformationFile returned %08x\n", Status); 5230 goto end; 5231 } 5232 5233 Status = ZwWriteFile(log_handle, NULL, NULL, NULL, &iosb, delim, (ULONG)strlen(delim), NULL, NULL); 5234 5235 if (!NT_SUCCESS(Status)) { 5236 ERR("ZwWriteFile returned %08x\n", Status); 5237 goto end; 5238 } 5239 } 5240 5241 dateline = ExAllocatePoolWithTag(PagedPool, 256, ALLOC_TAG); 5242 5243 if (!dateline) { 5244 ERR("out of memory\n"); 5245 goto end; 5246 } 5247 5248 KeQuerySystemTime(&time); 5249 5250 RtlTimeToTimeFields(&time, &tf); 5251 5252 sprintf(dateline, "Starting logging at %04i-%02i-%02i %02i:%02i:%02i\n", tf.Year, tf.Month, tf.Day, tf.Hour, tf.Minute, tf.Second); 5253 5254 Status = ZwWriteFile(log_handle, NULL, NULL, NULL, &iosb, dateline, (ULONG)strlen(dateline), NULL, NULL); 5255 5256 ExFreePool(dateline); 5257 5258 if (!NT_SUCCESS(Status)) { 5259 ERR("ZwWriteFile returned %08x\n", Status); 5260 goto end; 5261 } 5262 } 5263 5264 end: 5265 ExReleaseResourceLite(&log_lock); 5266 } 5267 #endif 5268 5269 _Function_class_(KSTART_ROUTINE) 5270 #ifdef __REACTOS__ 5271 static void NTAPI degraded_wait_thread(_In_ void* context) { 5272 #else 5273 static void degraded_wait_thread(_In_ void* context) { 5274 #endif 5275 KTIMER timer; 5276 LARGE_INTEGER delay; 5277 5278 UNUSED(context); 5279 5280 KeInitializeTimer(&timer); 5281 5282 delay.QuadPart = -30000000; // wait three seconds 5283 KeSetTimer(&timer, delay, NULL); 5284 KeWaitForSingleObject(&timer, Executive, KernelMode, FALSE, NULL); 5285 5286 TRACE("timer expired\n"); 5287 5288 degraded_wait = FALSE; 5289 5290 ZwClose(degraded_wait_handle); 5291 degraded_wait_handle = NULL; 5292 5293 PsTerminateSystemThread(STATUS_SUCCESS); 5294 } 5295 5296 #ifdef __REACTOS__ 5297 NTSTATUS NTAPI AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT PhysicalDeviceObject) { 5298 #else 5299 NTSTATUS AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT PhysicalDeviceObject) { 5300 #endif 5301 LIST_ENTRY* le; 5302 NTSTATUS Status; 5303 UNICODE_STRING volname; 5304 ULONG i, j; 5305 pdo_device_extension* pdode = NULL; 5306 PDEVICE_OBJECT voldev; 5307 volume_device_extension* vde; 5308 5309 TRACE("(%p, %p)\n", DriverObject, PhysicalDeviceObject); 5310 5311 ExAcquireResourceSharedLite(&pdo_list_lock, TRUE); 5312 5313 le = pdo_list.Flink; 5314 while (le != &pdo_list) { 5315 pdo_device_extension* pdode2 = CONTAINING_RECORD(le, pdo_device_extension, list_entry); 5316 5317 if (pdode2->pdo == PhysicalDeviceObject) { 5318 pdode = pdode2; 5319 break; 5320 } 5321 5322 le = le->Flink; 5323 } 5324 5325 if (!pdode) { 5326 WARN("unrecognized PDO %p\n", PhysicalDeviceObject); 5327 Status = STATUS_NOT_SUPPORTED; 5328 goto end; 5329 } 5330 5331 ExAcquireResourceSharedLite(&pdode->child_lock, TRUE); 5332 5333 volname.Length = volname.MaximumLength = (USHORT)((wcslen(BTRFS_VOLUME_PREFIX) + 36 + 1) * sizeof(WCHAR)); 5334 volname.Buffer = ExAllocatePoolWithTag(PagedPool, volname.MaximumLength, ALLOC_TAG); // FIXME - when do we free this? 5335 5336 if (!volname.Buffer) { 5337 ERR("out of memory\n"); 5338 Status = STATUS_INSUFFICIENT_RESOURCES; 5339 goto end2; 5340 } 5341 5342 RtlCopyMemory(volname.Buffer, BTRFS_VOLUME_PREFIX, wcslen(BTRFS_VOLUME_PREFIX) * sizeof(WCHAR)); 5343 5344 j = (ULONG)wcslen(BTRFS_VOLUME_PREFIX); 5345 for (i = 0; i < 16; i++) { 5346 volname.Buffer[j] = hex_digit(pdode->uuid.uuid[i] >> 4); j++; 5347 volname.Buffer[j] = hex_digit(pdode->uuid.uuid[i] & 0xf); j++; 5348 5349 if (i == 3 || i == 5 || i == 7 || i == 9) { 5350 volname.Buffer[j] = '-'; 5351 j++; 5352 } 5353 } 5354 5355 volname.Buffer[j] = '}'; 5356 5357 Status = IoCreateDevice(drvobj, sizeof(volume_device_extension), &volname, FILE_DEVICE_DISK, 5358 RtlIsNtDdiVersionAvailable(NTDDI_WIN8) ? FILE_DEVICE_ALLOW_APPCONTAINER_TRAVERSAL : 0, FALSE, &voldev); 5359 if (!NT_SUCCESS(Status)) { 5360 ERR("IoCreateDevice returned %08x\n", Status); 5361 goto end2; 5362 } 5363 5364 voldev->SectorSize = PhysicalDeviceObject->SectorSize; 5365 voldev->Flags |= DO_DIRECT_IO; 5366 5367 vde = voldev->DeviceExtension; 5368 vde->type = VCB_TYPE_VOLUME; 5369 vde->name = volname; 5370 vde->device = voldev; 5371 vde->mounted_device = NULL; 5372 vde->pdo = PhysicalDeviceObject; 5373 vde->pdode = pdode; 5374 vde->removing = FALSE; 5375 vde->open_count = 0; 5376 5377 Status = IoRegisterDeviceInterface(PhysicalDeviceObject, &GUID_DEVINTERFACE_VOLUME, NULL, &vde->bus_name); 5378 if (!NT_SUCCESS(Status)) 5379 WARN("IoRegisterDeviceInterface returned %08x\n", Status); 5380 5381 vde->attached_device = IoAttachDeviceToDeviceStack(voldev, PhysicalDeviceObject); 5382 5383 pdode->vde = vde; 5384 5385 if (pdode->removable) 5386 voldev->Characteristics |= FILE_REMOVABLE_MEDIA; 5387 5388 voldev->Flags &= ~DO_DEVICE_INITIALIZING; 5389 5390 Status = IoSetDeviceInterfaceState(&vde->bus_name, TRUE); 5391 if (!NT_SUCCESS(Status)) 5392 WARN("IoSetDeviceInterfaceState returned %08x\n", Status); 5393 5394 Status = STATUS_SUCCESS; 5395 5396 end2: 5397 ExReleaseResourceLite(&pdode->child_lock); 5398 5399 end: 5400 ExReleaseResourceLite(&pdo_list_lock); 5401 5402 return Status; 5403 } 5404 5405 _Function_class_(DRIVER_INITIALIZE) 5406 #ifdef __REACTOS__ 5407 NTSTATUS NTAPI DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath) { 5408 #else 5409 NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath) { 5410 #endif 5411 NTSTATUS Status; 5412 PDEVICE_OBJECT DeviceObject; 5413 UNICODE_STRING device_nameW; 5414 UNICODE_STRING dosdevice_nameW; 5415 control_device_extension* cde; 5416 HANDLE regh; 5417 OBJECT_ATTRIBUTES oa; 5418 ULONG dispos; 5419 5420 InitializeListHead(&uid_map_list); 5421 InitializeListHead(&gid_map_list); 5422 5423 #ifdef _DEBUG 5424 ExInitializeResourceLite(&log_lock); 5425 #endif 5426 ExInitializeResourceLite(&mapping_lock); 5427 5428 log_device.Buffer = NULL; 5429 log_device.Length = log_device.MaximumLength = 0; 5430 log_file.Buffer = NULL; 5431 log_file.Length = log_file.MaximumLength = 0; 5432 5433 registry_path.Length = registry_path.MaximumLength = RegistryPath->Length; 5434 registry_path.Buffer = ExAllocatePoolWithTag(PagedPool, registry_path.Length, ALLOC_TAG); 5435 5436 if (!registry_path.Buffer) { 5437 ERR("out of memory\n"); 5438 return STATUS_INSUFFICIENT_RESOURCES; 5439 } 5440 5441 RtlCopyMemory(registry_path.Buffer, RegistryPath->Buffer, registry_path.Length); 5442 5443 read_registry(®istry_path, FALSE); 5444 5445 #ifdef _DEBUG 5446 if (debug_log_level > 0) 5447 init_logging(); 5448 5449 log_started = TRUE; 5450 #endif 5451 5452 TRACE("DriverEntry\n"); 5453 5454 #ifndef __REACTOS__ 5455 check_cpu(); 5456 #endif 5457 5458 if (RtlIsNtDdiVersionAvailable(NTDDI_WIN8)) { 5459 UNICODE_STRING name; 5460 tPsIsDiskCountersEnabled fPsIsDiskCountersEnabled; 5461 5462 RtlInitUnicodeString(&name, L"PsIsDiskCountersEnabled"); 5463 fPsIsDiskCountersEnabled = (tPsIsDiskCountersEnabled)MmGetSystemRoutineAddress(&name); 5464 5465 if (fPsIsDiskCountersEnabled) { 5466 diskacc = fPsIsDiskCountersEnabled(); 5467 5468 RtlInitUnicodeString(&name, L"PsUpdateDiskCounters"); 5469 fPsUpdateDiskCounters = (tPsUpdateDiskCounters)MmGetSystemRoutineAddress(&name); 5470 5471 if (!fPsUpdateDiskCounters) 5472 diskacc = FALSE; 5473 5474 RtlInitUnicodeString(&name, L"FsRtlUpdateDiskCounters"); 5475 fFsRtlUpdateDiskCounters = (tFsRtlUpdateDiskCounters)MmGetSystemRoutineAddress(&name); 5476 } 5477 5478 RtlInitUnicodeString(&name, L"CcCopyReadEx"); 5479 fCcCopyReadEx = (tCcCopyReadEx)MmGetSystemRoutineAddress(&name); 5480 5481 RtlInitUnicodeString(&name, L"CcCopyWriteEx"); 5482 fCcCopyWriteEx = (tCcCopyWriteEx)MmGetSystemRoutineAddress(&name); 5483 5484 RtlInitUnicodeString(&name, L"CcSetAdditionalCacheAttributesEx"); 5485 fCcSetAdditionalCacheAttributesEx = (tCcSetAdditionalCacheAttributesEx)MmGetSystemRoutineAddress(&name); 5486 } else { 5487 fPsUpdateDiskCounters = NULL; 5488 fCcCopyReadEx = NULL; 5489 fCcCopyWriteEx = NULL; 5490 fCcSetAdditionalCacheAttributesEx = NULL; 5491 fFsRtlUpdateDiskCounters = NULL; 5492 } 5493 5494 drvobj = DriverObject; 5495 5496 DriverObject->DriverUnload = DriverUnload; 5497 5498 DriverObject->DriverExtension->AddDevice = AddDevice; 5499 5500 DriverObject->MajorFunction[IRP_MJ_CREATE] = (PDRIVER_DISPATCH)drv_create; 5501 DriverObject->MajorFunction[IRP_MJ_CLOSE] = (PDRIVER_DISPATCH)drv_close; 5502 DriverObject->MajorFunction[IRP_MJ_READ] = (PDRIVER_DISPATCH)drv_read; 5503 DriverObject->MajorFunction[IRP_MJ_WRITE] = (PDRIVER_DISPATCH)drv_write; 5504 DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] = (PDRIVER_DISPATCH)drv_query_information; 5505 DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] = (PDRIVER_DISPATCH)drv_set_information; 5506 DriverObject->MajorFunction[IRP_MJ_QUERY_EA] = (PDRIVER_DISPATCH)drv_query_ea; 5507 DriverObject->MajorFunction[IRP_MJ_SET_EA] = (PDRIVER_DISPATCH)drv_set_ea; 5508 DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = (PDRIVER_DISPATCH)drv_flush_buffers; 5509 DriverObject->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] = (PDRIVER_DISPATCH)drv_query_volume_information; 5510 DriverObject->MajorFunction[IRP_MJ_SET_VOLUME_INFORMATION] = (PDRIVER_DISPATCH)drv_set_volume_information; 5511 DriverObject->MajorFunction[IRP_MJ_DIRECTORY_CONTROL] = (PDRIVER_DISPATCH)drv_directory_control; 5512 DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = (PDRIVER_DISPATCH)drv_file_system_control; 5513 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = (PDRIVER_DISPATCH)drv_device_control; 5514 DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = (PDRIVER_DISPATCH)drv_shutdown; 5515 DriverObject->MajorFunction[IRP_MJ_LOCK_CONTROL] = (PDRIVER_DISPATCH)drv_lock_control; 5516 DriverObject->MajorFunction[IRP_MJ_CLEANUP] = (PDRIVER_DISPATCH)drv_cleanup; 5517 DriverObject->MajorFunction[IRP_MJ_QUERY_SECURITY] = (PDRIVER_DISPATCH)drv_query_security; 5518 DriverObject->MajorFunction[IRP_MJ_SET_SECURITY] = (PDRIVER_DISPATCH)drv_set_security; 5519 DriverObject->MajorFunction[IRP_MJ_POWER] = (PDRIVER_DISPATCH)drv_power; 5520 DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = (PDRIVER_DISPATCH)drv_system_control; 5521 DriverObject->MajorFunction[IRP_MJ_PNP] = (PDRIVER_DISPATCH)drv_pnp; 5522 5523 init_fast_io_dispatch(&DriverObject->FastIoDispatch); 5524 5525 device_nameW.Buffer = device_name; 5526 device_nameW.Length = device_nameW.MaximumLength = (USHORT)wcslen(device_name) * sizeof(WCHAR); 5527 dosdevice_nameW.Buffer = dosdevice_name; 5528 dosdevice_nameW.Length = dosdevice_nameW.MaximumLength = (USHORT)wcslen(dosdevice_name) * sizeof(WCHAR); 5529 5530 Status = IoCreateDevice(DriverObject, sizeof(control_device_extension), &device_nameW, FILE_DEVICE_DISK_FILE_SYSTEM, 5531 FILE_DEVICE_SECURE_OPEN, FALSE, &DeviceObject); 5532 if (!NT_SUCCESS(Status)) { 5533 ERR("IoCreateDevice returned %08x\n", Status); 5534 return Status; 5535 } 5536 5537 master_devobj = DeviceObject; 5538 cde = (control_device_extension*)master_devobj->DeviceExtension; 5539 5540 RtlZeroMemory(cde, sizeof(control_device_extension)); 5541 5542 cde->type = VCB_TYPE_CONTROL; 5543 5544 DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; 5545 5546 Status = IoCreateSymbolicLink(&dosdevice_nameW, &device_nameW); 5547 if (!NT_SUCCESS(Status)) { 5548 ERR("IoCreateSymbolicLink returned %08x\n", Status); 5549 return Status; 5550 } 5551 5552 Status = init_cache(); 5553 if (!NT_SUCCESS(Status)) { 5554 ERR("init_cache returned %08x\n", Status); 5555 return Status; 5556 } 5557 5558 InitializeListHead(&VcbList); 5559 ExInitializeResourceLite(&global_loading_lock); 5560 ExInitializeResourceLite(&pdo_list_lock); 5561 5562 InitializeListHead(&pdo_list); 5563 5564 InitializeObjectAttributes(&oa, RegistryPath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); 5565 Status = ZwCreateKey(®h, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY, &oa, 0, NULL, REG_OPTION_NON_VOLATILE, &dispos); 5566 if (!NT_SUCCESS(Status)) { 5567 ERR("ZwCreateKey returned %08x\n", Status); 5568 return Status; 5569 } 5570 5571 watch_registry(regh); 5572 5573 Status = IoReportDetectedDevice(drvobj, InterfaceTypeUndefined, 0xFFFFFFFF, 0xFFFFFFFF, 5574 NULL, NULL, 0, &cde->buspdo); 5575 if (!NT_SUCCESS(Status)) { 5576 ERR("IoReportDetectedDevice returned %08x\n", Status); 5577 return Status; 5578 } 5579 5580 Status = IoRegisterDeviceInterface(cde->buspdo, &BtrfsBusInterface, NULL, &cde->bus_name); 5581 if (!NT_SUCCESS(Status)) 5582 WARN("IoRegisterDeviceInterface returned %08x\n", Status); 5583 5584 cde->attached_device = IoAttachDeviceToDeviceStack(DeviceObject, cde->buspdo); 5585 5586 Status = IoSetDeviceInterfaceState(&cde->bus_name, TRUE); 5587 if (!NT_SUCCESS(Status)) 5588 WARN("IoSetDeviceInterfaceState returned %08x\n", Status); 5589 5590 DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; 5591 5592 IoInvalidateDeviceRelations(cde->buspdo, BusRelations); 5593 5594 Status = PsCreateSystemThread(°raded_wait_handle, 0, NULL, NULL, NULL, degraded_wait_thread, NULL); 5595 if (!NT_SUCCESS(Status)) 5596 WARN("PsCreateSystemThread returned %08x\n", Status); 5597 5598 Status = IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange, PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES, 5599 (PVOID)&GUID_DEVINTERFACE_VOLUME, DriverObject, volume_notification, DriverObject, ¬ification_entry2); 5600 if (!NT_SUCCESS(Status)) 5601 ERR("IoRegisterPlugPlayNotification returned %08x\n", Status); 5602 5603 Status = IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange, PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES, 5604 (PVOID)&GUID_DEVINTERFACE_HIDDEN_VOLUME, DriverObject, volume_notification, DriverObject, ¬ification_entry3); 5605 if (!NT_SUCCESS(Status)) 5606 ERR("IoRegisterPlugPlayNotification returned %08x\n", Status); 5607 5608 Status = IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange, PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES, 5609 (PVOID)&GUID_DEVINTERFACE_DISK, DriverObject, pnp_notification, DriverObject, ¬ification_entry); 5610 if (!NT_SUCCESS(Status)) 5611 ERR("IoRegisterPlugPlayNotification returned %08x\n", Status); 5612 5613 finished_probing = TRUE; 5614 5615 KeInitializeEvent(&mountmgr_thread_event, NotificationEvent, FALSE); 5616 5617 #ifndef __REACTOS__ 5618 Status = PsCreateSystemThread(&mountmgr_thread_handle, 0, NULL, NULL, NULL, mountmgr_thread, NULL); 5619 if (!NT_SUCCESS(Status)) 5620 WARN("PsCreateSystemThread returned %08x\n", Status); 5621 #endif 5622 5623 IoRegisterFileSystem(DeviceObject); 5624 5625 return STATUS_SUCCESS; 5626 } 5627