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 #include "btrfs_drv.h" 19 20 struct pnp_context; 21 22 typedef struct { 23 struct pnp_context* context; 24 PIRP Irp; 25 IO_STATUS_BLOCK iosb; 26 NTSTATUS Status; 27 device* dev; 28 } pnp_stripe; 29 30 typedef struct { 31 KEVENT Event; 32 NTSTATUS Status; 33 LONG left; 34 pnp_stripe* stripes; 35 } pnp_context; 36 37 extern ERESOURCE pdo_list_lock; 38 extern LIST_ENTRY pdo_list; 39 40 _Function_class_(IO_COMPLETION_ROUTINE) 41 static NTSTATUS __stdcall pnp_completion(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID conptr) { 42 pnp_stripe* stripe = conptr; 43 pnp_context* context = (pnp_context*)stripe->context; 44 45 UNUSED(DeviceObject); 46 47 stripe->Status = Irp->IoStatus.Status; 48 49 InterlockedDecrement(&context->left); 50 51 if (context->left == 0) 52 KeSetEvent(&context->Event, 0, false); 53 54 return STATUS_MORE_PROCESSING_REQUIRED; 55 } 56 57 static NTSTATUS send_disks_pnp_message(device_extension* Vcb, UCHAR minor) { 58 pnp_context context; 59 ULONG num_devices, i; 60 NTSTATUS Status; 61 LIST_ENTRY* le; 62 63 RtlZeroMemory(&context, sizeof(pnp_context)); 64 KeInitializeEvent(&context.Event, NotificationEvent, false); 65 66 num_devices = (ULONG)min(0xffffffff, Vcb->superblock.num_devices); 67 68 context.stripes = ExAllocatePoolWithTag(NonPagedPool, sizeof(pnp_stripe) * num_devices, ALLOC_TAG); 69 if (!context.stripes) { 70 ERR("out of memory\n"); 71 return STATUS_INSUFFICIENT_RESOURCES; 72 } 73 74 RtlZeroMemory(context.stripes, sizeof(pnp_stripe) * num_devices); 75 76 i = 0; 77 le = Vcb->devices.Flink; 78 79 while (le != &Vcb->devices) { 80 PIO_STACK_LOCATION IrpSp; 81 device* dev = CONTAINING_RECORD(le, device, list_entry); 82 83 if (dev->devobj) { 84 context.stripes[i].context = (struct pnp_context*)&context; 85 86 context.stripes[i].Irp = IoAllocateIrp(dev->devobj->StackSize, false); 87 88 if (!context.stripes[i].Irp) { 89 uint64_t j; 90 91 ERR("IoAllocateIrp failed\n"); 92 93 for (j = 0; j < i; j++) { 94 if (context.stripes[j].dev->devobj) { 95 IoFreeIrp(context.stripes[j].Irp); 96 } 97 } 98 ExFreePool(context.stripes); 99 100 return STATUS_INSUFFICIENT_RESOURCES; 101 } 102 103 IrpSp = IoGetNextIrpStackLocation(context.stripes[i].Irp); 104 IrpSp->MajorFunction = IRP_MJ_PNP; 105 IrpSp->MinorFunction = minor; 106 IrpSp->FileObject = dev->fileobj; 107 108 context.stripes[i].Irp->UserIosb = &context.stripes[i].iosb; 109 110 IoSetCompletionRoutine(context.stripes[i].Irp, pnp_completion, &context.stripes[i], true, true, true); 111 112 context.stripes[i].Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; 113 context.stripes[i].dev = dev; 114 115 context.left++; 116 } 117 118 le = le->Flink; 119 } 120 121 if (context.left == 0) { 122 Status = STATUS_SUCCESS; 123 goto end; 124 } 125 126 for (i = 0; i < num_devices; i++) { 127 if (context.stripes[i].Irp) { 128 IoCallDriver(context.stripes[i].dev->devobj, context.stripes[i].Irp); 129 } 130 } 131 132 KeWaitForSingleObject(&context.Event, Executive, KernelMode, false, NULL); 133 134 Status = STATUS_SUCCESS; 135 136 for (i = 0; i < num_devices; i++) { 137 if (context.stripes[i].Irp) { 138 if (context.stripes[i].Status != STATUS_SUCCESS) 139 Status = context.stripes[i].Status; 140 } 141 } 142 143 end: 144 for (i = 0; i < num_devices; i++) { 145 if (context.stripes[i].Irp) { 146 IoFreeIrp(context.stripes[i].Irp); 147 } 148 } 149 150 ExFreePool(context.stripes); 151 152 return Status; 153 } 154 155 static NTSTATUS pnp_cancel_remove_device(PDEVICE_OBJECT DeviceObject) { 156 device_extension* Vcb = DeviceObject->DeviceExtension; 157 NTSTATUS Status; 158 159 ExAcquireResourceSharedLite(&Vcb->tree_lock, true); 160 161 ExAcquireResourceExclusiveLite(&Vcb->fileref_lock, true); 162 163 if (Vcb->root_fileref && Vcb->root_fileref->fcb && (Vcb->root_fileref->open_count > 0 || has_open_children(Vcb->root_fileref))) { 164 Status = STATUS_ACCESS_DENIED; 165 goto end; 166 } 167 168 Status = send_disks_pnp_message(Vcb, IRP_MN_CANCEL_REMOVE_DEVICE); 169 if (!NT_SUCCESS(Status)) { 170 WARN("send_disks_pnp_message returned %08x\n", Status); 171 goto end; 172 } 173 174 end: 175 ExReleaseResourceLite(&Vcb->fileref_lock); 176 ExReleaseResourceLite(&Vcb->tree_lock); 177 178 return STATUS_SUCCESS; 179 } 180 181 NTSTATUS pnp_query_remove_device(PDEVICE_OBJECT DeviceObject, PIRP Irp) { 182 device_extension* Vcb = DeviceObject->DeviceExtension; 183 NTSTATUS Status; 184 185 ExAcquireResourceExclusiveLite(&Vcb->tree_lock, true); 186 187 if (Vcb->root_fileref && Vcb->root_fileref->fcb && (Vcb->root_fileref->open_count > 0 || has_open_children(Vcb->root_fileref))) { 188 ExReleaseResourceLite(&Vcb->tree_lock); 189 return STATUS_ACCESS_DENIED; 190 } 191 192 Status = send_disks_pnp_message(Vcb, IRP_MN_QUERY_REMOVE_DEVICE); 193 if (!NT_SUCCESS(Status)) { 194 WARN("send_disks_pnp_message returned %08x\n", Status); 195 ExReleaseResourceLite(&Vcb->tree_lock); 196 return Status; 197 } 198 199 Vcb->removing = true; 200 201 if (Vcb->need_write && !Vcb->readonly) { 202 Status = do_write(Vcb, Irp); 203 204 free_trees(Vcb); 205 206 if (!NT_SUCCESS(Status)) { 207 ERR("do_write returned %08x\n", Status); 208 ExReleaseResourceLite(&Vcb->tree_lock); 209 return Status; 210 } 211 } 212 213 ExReleaseResourceLite(&Vcb->tree_lock); 214 215 if (Vcb->open_files == 0) 216 uninit(Vcb); 217 218 return STATUS_SUCCESS; 219 } 220 221 static NTSTATUS pnp_remove_device(PDEVICE_OBJECT DeviceObject) { 222 device_extension* Vcb = DeviceObject->DeviceExtension; 223 NTSTATUS Status; 224 225 ExAcquireResourceSharedLite(&Vcb->tree_lock, true); 226 227 Status = send_disks_pnp_message(Vcb, IRP_MN_REMOVE_DEVICE); 228 229 if (!NT_SUCCESS(Status)) 230 WARN("send_disks_pnp_message returned %08x\n", Status); 231 232 ExReleaseResourceLite(&Vcb->tree_lock); 233 234 if (DeviceObject->Vpb->Flags & VPB_MOUNTED) { 235 Status = FsRtlNotifyVolumeEvent(Vcb->root_file, FSRTL_VOLUME_DISMOUNT); 236 if (!NT_SUCCESS(Status)) { 237 WARN("FsRtlNotifyVolumeEvent returned %08x\n", Status); 238 } 239 240 if (Vcb->vde) 241 Vcb->vde->mounted_device = NULL; 242 243 ExAcquireResourceExclusiveLite(&Vcb->tree_lock, true); 244 Vcb->removing = true; 245 ExReleaseResourceLite(&Vcb->tree_lock); 246 247 if (Vcb->open_files == 0) 248 uninit(Vcb); 249 } 250 251 return STATUS_SUCCESS; 252 } 253 254 NTSTATUS pnp_surprise_removal(PDEVICE_OBJECT DeviceObject, PIRP Irp) { 255 device_extension* Vcb = DeviceObject->DeviceExtension; 256 257 TRACE("(%p, %p)\n", DeviceObject, Irp); 258 259 if (DeviceObject->Vpb->Flags & VPB_MOUNTED) { 260 ExAcquireResourceExclusiveLite(&Vcb->tree_lock, true); 261 262 if (Vcb->vde) 263 Vcb->vde->mounted_device = NULL; 264 265 Vcb->removing = true; 266 267 ExReleaseResourceLite(&Vcb->tree_lock); 268 269 if (Vcb->open_files == 0) 270 uninit(Vcb); 271 } 272 273 return STATUS_SUCCESS; 274 } 275 276 static NTSTATUS bus_query_capabilities(PIRP Irp) { 277 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); 278 PDEVICE_CAPABILITIES dc = IrpSp->Parameters.DeviceCapabilities.Capabilities; 279 280 dc->UniqueID = true; 281 dc->SilentInstall = true; 282 283 return STATUS_SUCCESS; 284 } 285 286 static NTSTATUS bus_query_device_relations(PIRP Irp) { 287 NTSTATUS Status; 288 ULONG num_children; 289 LIST_ENTRY* le; 290 ULONG drsize, i; 291 DEVICE_RELATIONS* dr; 292 293 ExAcquireResourceSharedLite(&pdo_list_lock, true); 294 295 num_children = 0; 296 297 le = pdo_list.Flink; 298 while (le != &pdo_list) { 299 pdo_device_extension* pdode = CONTAINING_RECORD(le, pdo_device_extension, list_entry); 300 301 if (!pdode->dont_report) 302 num_children++; 303 304 le = le->Flink; 305 } 306 307 drsize = offsetof(DEVICE_RELATIONS, Objects[0]) + (num_children * sizeof(PDEVICE_OBJECT)); 308 dr = ExAllocatePoolWithTag(PagedPool, drsize, ALLOC_TAG); 309 310 if (!dr) { 311 ERR("out of memory\n"); 312 Status = STATUS_INSUFFICIENT_RESOURCES; 313 goto end; 314 } 315 316 dr->Count = num_children; 317 318 i = 0; 319 le = pdo_list.Flink; 320 while (le != &pdo_list) { 321 pdo_device_extension* pdode = CONTAINING_RECORD(le, pdo_device_extension, list_entry); 322 323 if (!pdode->dont_report) { 324 ObReferenceObject(pdode->pdo); 325 dr->Objects[i] = pdode->pdo; 326 i++; 327 } 328 329 le = le->Flink; 330 } 331 332 Irp->IoStatus.Information = (ULONG_PTR)dr; 333 334 Status = STATUS_SUCCESS; 335 336 end: 337 ExReleaseResourceLite(&pdo_list_lock); 338 339 return Status; 340 } 341 342 static NTSTATUS bus_query_hardware_ids(PIRP Irp) { 343 WCHAR* out; 344 345 static const WCHAR ids[] = L"ROOT\\btrfs\0"; 346 347 out = ExAllocatePoolWithTag(PagedPool, sizeof(ids), ALLOC_TAG); 348 if (!out) { 349 ERR("out of memory\n"); 350 return STATUS_INSUFFICIENT_RESOURCES; 351 } 352 353 RtlCopyMemory(out, ids, sizeof(ids)); 354 355 Irp->IoStatus.Information = (ULONG_PTR)out; 356 357 return STATUS_SUCCESS; 358 } 359 360 static NTSTATUS bus_pnp(bus_device_extension* bde, PIRP Irp) { 361 NTSTATUS Status = Irp->IoStatus.Status; 362 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); 363 bool handled = false; 364 365 switch (IrpSp->MinorFunction) { 366 case IRP_MN_QUERY_CAPABILITIES: 367 Status = bus_query_capabilities(Irp); 368 handled = true; 369 break; 370 371 case IRP_MN_QUERY_DEVICE_RELATIONS: 372 if (IrpSp->Parameters.QueryDeviceRelations.Type != BusRelations || no_pnp) 373 break; 374 375 Status = bus_query_device_relations(Irp); 376 handled = true; 377 break; 378 379 case IRP_MN_QUERY_ID: 380 if (IrpSp->Parameters.QueryId.IdType != BusQueryHardwareIDs) 381 break; 382 383 Status = bus_query_hardware_ids(Irp); 384 handled = true; 385 break; 386 } 387 388 if (!NT_SUCCESS(Status) && handled) { 389 Irp->IoStatus.Status = Status; 390 IoCompleteRequest(Irp, IO_NO_INCREMENT); 391 392 return Status; 393 } 394 395 Irp->IoStatus.Status = Status; 396 397 IoSkipCurrentIrpStackLocation(Irp); 398 return IoCallDriver(bde->attached_device, Irp); 399 } 400 401 static NTSTATUS pdo_query_device_id(pdo_device_extension* pdode, PIRP Irp) { 402 WCHAR name[100], *noff, *out; 403 int i; 404 405 static const WCHAR pref[] = L"Btrfs\\"; 406 407 RtlCopyMemory(name, pref, sizeof(pref) - sizeof(WCHAR)); 408 409 noff = &name[(sizeof(pref) / sizeof(WCHAR)) - 1]; 410 for (i = 0; i < 16; i++) { 411 *noff = hex_digit(pdode->uuid.uuid[i] >> 4); noff++; 412 *noff = hex_digit(pdode->uuid.uuid[i] & 0xf); noff++; 413 414 if (i == 3 || i == 5 || i == 7 || i == 9) { 415 *noff = '-'; 416 noff++; 417 } 418 } 419 *noff = 0; 420 421 out = ExAllocatePoolWithTag(PagedPool, (wcslen(name) + 1) * sizeof(WCHAR), ALLOC_TAG); 422 if (!out) { 423 ERR("out of memory\n"); 424 return STATUS_INSUFFICIENT_RESOURCES; 425 } 426 427 RtlCopyMemory(out, name, (wcslen(name) + 1) * sizeof(WCHAR)); 428 429 Irp->IoStatus.Information = (ULONG_PTR)out; 430 431 return STATUS_SUCCESS; 432 } 433 434 static NTSTATUS pdo_query_hardware_ids(PIRP Irp) { 435 WCHAR* out; 436 437 static const WCHAR ids[] = L"BtrfsVolume\0"; 438 439 out = ExAllocatePoolWithTag(PagedPool, sizeof(ids), ALLOC_TAG); 440 if (!out) { 441 ERR("out of memory\n"); 442 return STATUS_INSUFFICIENT_RESOURCES; 443 } 444 445 RtlCopyMemory(out, ids, sizeof(ids)); 446 447 Irp->IoStatus.Information = (ULONG_PTR)out; 448 449 return STATUS_SUCCESS; 450 } 451 452 static NTSTATUS pdo_query_id(pdo_device_extension* pdode, PIRP Irp) { 453 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); 454 455 switch (IrpSp->Parameters.QueryId.IdType) { 456 case BusQueryDeviceID: 457 TRACE("BusQueryDeviceID\n"); 458 return pdo_query_device_id(pdode, Irp); 459 460 case BusQueryHardwareIDs: 461 TRACE("BusQueryHardwareIDs\n"); 462 return pdo_query_hardware_ids(Irp); 463 464 default: 465 break; 466 } 467 468 return Irp->IoStatus.Status; 469 } 470 471 typedef struct { 472 IO_STATUS_BLOCK iosb; 473 KEVENT Event; 474 NTSTATUS Status; 475 } device_usage_context; 476 477 _Function_class_(IO_COMPLETION_ROUTINE) 478 static NTSTATUS __stdcall device_usage_completion(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID conptr) { 479 device_usage_context* context = conptr; 480 481 UNUSED(DeviceObject); 482 483 context->Status = Irp->IoStatus.Status; 484 485 KeSetEvent(&context->Event, 0, false); 486 487 return STATUS_MORE_PROCESSING_REQUIRED; 488 } 489 490 static NTSTATUS pdo_device_usage_notification(pdo_device_extension* pdode, PIRP Irp) { 491 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); 492 LIST_ENTRY* le; 493 494 TRACE("(%p, %p)\n", pdode, Irp); 495 496 ExAcquireResourceSharedLite(&pdode->child_lock, true); 497 498 le = pdode->children.Flink; 499 500 while (le != &pdode->children) { 501 volume_child* vc = CONTAINING_RECORD(le, volume_child, list_entry); 502 503 if (vc->devobj) { 504 PIRP Irp2; 505 PIO_STACK_LOCATION IrpSp2; 506 device_usage_context context; 507 508 Irp2 = IoAllocateIrp(vc->devobj->StackSize, false); 509 if (!Irp2) { 510 ERR("out of memory\n"); 511 ExReleaseResourceLite(&pdode->child_lock); 512 return STATUS_INSUFFICIENT_RESOURCES; 513 } 514 515 IrpSp2 = IoGetNextIrpStackLocation(Irp2); 516 IrpSp2->MajorFunction = IRP_MJ_PNP; 517 IrpSp2->MinorFunction = IRP_MN_DEVICE_USAGE_NOTIFICATION; 518 IrpSp2->Parameters.UsageNotification = IrpSp->Parameters.UsageNotification; 519 IrpSp2->FileObject = vc->fileobj; 520 521 context.iosb.Status = STATUS_SUCCESS; 522 Irp2->UserIosb = &context.iosb; 523 524 KeInitializeEvent(&context.Event, NotificationEvent, false); 525 Irp2->UserEvent = &context.Event; 526 527 IoSetCompletionRoutine(Irp2, device_usage_completion, &context, true, true, true); 528 529 context.Status = IoCallDriver(vc->devobj, Irp2); 530 531 if (context.Status == STATUS_PENDING) 532 KeWaitForSingleObject(&context.Event, Executive, KernelMode, false, NULL); 533 534 if (!NT_SUCCESS(context.Status)) { 535 ERR("IoCallDriver returned %08x\n", context.Status); 536 ExReleaseResourceLite(&pdode->child_lock); 537 return context.Status; 538 } 539 } 540 541 le = le->Flink; 542 } 543 544 ExReleaseResourceLite(&pdode->child_lock); 545 546 return STATUS_SUCCESS; 547 } 548 549 static NTSTATUS pdo_query_device_relations(PDEVICE_OBJECT pdo, PIRP Irp) { 550 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); 551 PDEVICE_RELATIONS device_relations; 552 553 if (IrpSp->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation) 554 return Irp->IoStatus.Status; 555 556 device_relations = ExAllocatePoolWithTag(PagedPool, sizeof(DEVICE_RELATIONS), ALLOC_TAG); 557 if (!device_relations) { 558 ERR("out of memory\n"); 559 return STATUS_INSUFFICIENT_RESOURCES; 560 } 561 562 device_relations->Count = 1; 563 device_relations->Objects[0] = pdo; 564 565 ObReferenceObject(pdo); 566 567 Irp->IoStatus.Information = (ULONG_PTR)device_relations; 568 569 return STATUS_SUCCESS; 570 } 571 572 static NTSTATUS pdo_pnp(PDEVICE_OBJECT pdo, PIRP Irp) { 573 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); 574 pdo_device_extension* pdode = pdo->DeviceExtension; 575 576 switch (IrpSp->MinorFunction) { 577 case IRP_MN_QUERY_ID: 578 return pdo_query_id(pdode, Irp); 579 580 case IRP_MN_START_DEVICE: 581 case IRP_MN_CANCEL_REMOVE_DEVICE: 582 case IRP_MN_SURPRISE_REMOVAL: 583 case IRP_MN_REMOVE_DEVICE: 584 return STATUS_SUCCESS; 585 586 case IRP_MN_QUERY_REMOVE_DEVICE: 587 return STATUS_UNSUCCESSFUL; 588 589 case IRP_MN_DEVICE_USAGE_NOTIFICATION: 590 return pdo_device_usage_notification(pdode, Irp); 591 592 case IRP_MN_QUERY_DEVICE_RELATIONS: 593 return pdo_query_device_relations(pdo, Irp); 594 } 595 596 return Irp->IoStatus.Status; 597 } 598 599 static NTSTATUS pnp_device_usage_notification(PDEVICE_OBJECT DeviceObject, PIRP Irp) { 600 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); 601 device_extension* Vcb = DeviceObject->DeviceExtension; 602 603 if (IrpSp->Parameters.UsageNotification.InPath) { 604 switch (IrpSp->Parameters.UsageNotification.Type) { 605 case DeviceUsageTypePaging: 606 case DeviceUsageTypeHibernation: 607 case DeviceUsageTypeDumpFile: 608 IoAdjustPagingPathCount(&Vcb->page_file_count, IrpSp->Parameters.UsageNotification.InPath); 609 break; 610 611 default: 612 break; 613 } 614 } 615 616 IoSkipCurrentIrpStackLocation(Irp); 617 return IoCallDriver(Vcb->Vpb->RealDevice, Irp); 618 } 619 620 _Dispatch_type_(IRP_MJ_PNP) 621 _Function_class_(DRIVER_DISPATCH) 622 NTSTATUS __stdcall drv_pnp(PDEVICE_OBJECT DeviceObject, PIRP Irp) { 623 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); 624 device_extension* Vcb = DeviceObject->DeviceExtension; 625 NTSTATUS Status; 626 bool top_level; 627 628 FsRtlEnterFileSystem(); 629 630 top_level = is_top_level(Irp); 631 632 if (Vcb && Vcb->type == VCB_TYPE_BUS) { 633 Status = bus_pnp(DeviceObject->DeviceExtension, Irp); 634 goto exit; 635 } else if (Vcb && Vcb->type == VCB_TYPE_VOLUME) { 636 volume_device_extension* vde = DeviceObject->DeviceExtension; 637 IoSkipCurrentIrpStackLocation(Irp); 638 Status = IoCallDriver(vde->attached_device, Irp); 639 goto exit; 640 } else if (Vcb && Vcb->type == VCB_TYPE_PDO) { 641 Status = pdo_pnp(DeviceObject, Irp); 642 goto end; 643 } else if (!Vcb || Vcb->type != VCB_TYPE_FS) { 644 Status = STATUS_INVALID_PARAMETER; 645 goto end; 646 } 647 648 Status = STATUS_NOT_IMPLEMENTED; 649 650 switch (IrpSp->MinorFunction) { 651 case IRP_MN_CANCEL_REMOVE_DEVICE: 652 Status = pnp_cancel_remove_device(DeviceObject); 653 break; 654 655 case IRP_MN_QUERY_REMOVE_DEVICE: 656 Status = pnp_query_remove_device(DeviceObject, Irp); 657 break; 658 659 case IRP_MN_REMOVE_DEVICE: 660 Status = pnp_remove_device(DeviceObject); 661 break; 662 663 case IRP_MN_SURPRISE_REMOVAL: 664 Status = pnp_surprise_removal(DeviceObject, Irp); 665 break; 666 667 case IRP_MN_DEVICE_USAGE_NOTIFICATION: 668 Status = pnp_device_usage_notification(DeviceObject, Irp); 669 goto exit; 670 671 default: 672 TRACE("passing minor function 0x%x on\n", IrpSp->MinorFunction); 673 674 IoSkipCurrentIrpStackLocation(Irp); 675 Status = IoCallDriver(Vcb->Vpb->RealDevice, Irp); 676 goto exit; 677 } 678 679 end: 680 Irp->IoStatus.Status = Status; 681 682 IoCompleteRequest(Irp, IO_NO_INCREMENT); 683 684 exit: 685 TRACE("returning %08x\n", Status); 686 687 if (top_level) 688 IoSetTopLevelIrp(NULL); 689 690 FsRtlExitFileSystem(); 691 692 return Status; 693 } 694