1 /* Copyright (c) Mark Harmstone 2016-17
3 * This file is part of WinBtrfs.
5 * WinBtrfs is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public Licence as published by
7 * the Free Software Foundation, either version 3 of the Licence, or
8 * (at your option) any later version.
10 * WinBtrfs is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public Licence for more details.
15 * You should have received a copy of the GNU Lesser General Public Licence
16 * along with WinBtrfs. If not, see <http://www.gnu.org/licenses/>. */
18 #include "btrfs_drv.h"
25 #define IOCTL_VOLUME_IS_DYNAMIC CTL_CODE(IOCTL_VOLUME_BASE, 18, METHOD_BUFFERED, FILE_ANY_ACCESS)
26 #define IOCTL_VOLUME_POST_ONLINE CTL_CODE(IOCTL_VOLUME_BASE, 25, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
28 extern PDRIVER_OBJECT drvobj
;
29 extern PDEVICE_OBJECT master_devobj
;
30 extern ERESOURCE pdo_list_lock
;
31 extern LIST_ENTRY pdo_list
;
32 extern UNICODE_STRING registry_path
;
34 NTSTATUS
vol_create(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
) {
35 volume_device_extension
* vde
= DeviceObject
->DeviceExtension
;
37 TRACE("(%p, %p)\n", DeviceObject
, Irp
);
40 return STATUS_DEVICE_NOT_READY
;
42 Irp
->IoStatus
.Information
= FILE_OPENED
;
43 InterlockedIncrement(&vde
->open_count
);
45 return STATUS_SUCCESS
;
48 NTSTATUS
vol_close(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
) {
49 volume_device_extension
* vde
= DeviceObject
->DeviceExtension
;
50 pdo_device_extension
* pdode
= vde
->pdode
;
52 TRACE("(%p, %p)\n", DeviceObject
, Irp
);
54 Irp
->IoStatus
.Information
= 0;
56 ExAcquireResourceSharedLite(&pdode
->child_lock
, TRUE
);
58 if (InterlockedDecrement(&vde
->open_count
) == 0 && vde
->removing
) {
60 UNICODE_STRING mmdevpath
;
61 PDEVICE_OBJECT mountmgr
;
62 PFILE_OBJECT mountmgrfo
;
65 RtlInitUnicodeString(&mmdevpath
, MOUNTMGR_DEVICE_NAME
);
66 Status
= IoGetDeviceObjectPointer(&mmdevpath
, FILE_READ_ATTRIBUTES
, &mountmgrfo
, &mountmgr
);
67 if (!NT_SUCCESS(Status
))
68 ERR("IoGetDeviceObjectPointer returned %08x\n", Status
);
70 remove_drive_letter(mountmgr
, &vde
->name
);
72 ObDereferenceObject(mountmgrfo
);
75 if (vde
->mounted_device
) {
76 device_extension
* Vcb
= vde
->mounted_device
->DeviceExtension
;
82 ExFreePool(vde
->name
.Buffer
);
84 ExReleaseResourceLite(&pdode
->child_lock
);
85 ExDeleteResourceLite(&pdode
->child_lock
);
86 IoDetachDevice(vde
->pdo
);
89 IoDeleteDevice(vde
->device
);
94 ExReleaseResourceLite(&pdode
->child_lock
);
96 return STATUS_SUCCESS
;
100 IO_STATUS_BLOCK iosb
;
104 _Function_class_(IO_COMPLETION_ROUTINE
)
106 static NTSTATUS NTAPI
vol_read_completion(PDEVICE_OBJECT DeviceObject
, PIRP Irp
, PVOID conptr
) {
108 static NTSTATUS
vol_read_completion(PDEVICE_OBJECT DeviceObject
, PIRP Irp
, PVOID conptr
) {
110 vol_read_context
* context
= conptr
;
112 UNUSED(DeviceObject
);
114 context
->iosb
= Irp
->IoStatus
;
115 KeSetEvent(&context
->Event
, 0, FALSE
);
117 return STATUS_MORE_PROCESSING_REQUIRED
;
120 NTSTATUS
vol_read(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
) {
121 volume_device_extension
* vde
= DeviceObject
->DeviceExtension
;
122 pdo_device_extension
* pdode
= vde
->pdode
;
126 vol_read_context context
;
127 PIO_STACK_LOCATION IrpSp
, IrpSp2
;
129 TRACE("(%p, %p)\n", DeviceObject
, Irp
);
131 ExAcquireResourceSharedLite(&pdode
->child_lock
, TRUE
);
133 if (IsListEmpty(&pdode
->children
)) {
134 ExReleaseResourceLite(&pdode
->child_lock
);
135 Status
= STATUS_INVALID_DEVICE_REQUEST
;
139 vc
= CONTAINING_RECORD(pdode
->children
.Flink
, volume_child
, list_entry
);
141 // We can't use IoSkipCurrentIrpStackLocation as the device isn't in our stack
143 Irp2
= IoAllocateIrp(vc
->devobj
->StackSize
, FALSE
);
146 ERR("IoAllocateIrp failed\n");
147 ExReleaseResourceLite(&pdode
->child_lock
);
148 Status
= STATUS_INSUFFICIENT_RESOURCES
;
152 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
153 IrpSp2
= IoGetNextIrpStackLocation(Irp2
);
155 IrpSp2
->MajorFunction
= IRP_MJ_READ
;
157 if (vc
->devobj
->Flags
& DO_BUFFERED_IO
) {
158 Irp2
->AssociatedIrp
.SystemBuffer
= ExAllocatePoolWithTag(NonPagedPool
, IrpSp
->Parameters
.Read
.Length
, ALLOC_TAG
);
159 if (!Irp2
->AssociatedIrp
.SystemBuffer
) {
160 ERR("out of memory\n");
161 ExReleaseResourceLite(&pdode
->child_lock
);
162 Status
= STATUS_INSUFFICIENT_RESOURCES
;
166 Irp2
->Flags
|= IRP_BUFFERED_IO
| IRP_DEALLOCATE_BUFFER
| IRP_INPUT_OPERATION
;
168 Irp2
->UserBuffer
= MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, NormalPagePriority
);
169 } else if (vc
->devobj
->Flags
& DO_DIRECT_IO
)
170 Irp2
->MdlAddress
= Irp
->MdlAddress
;
172 Irp2
->UserBuffer
= MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, NormalPagePriority
);
174 IrpSp2
->Parameters
.Read
.Length
= IrpSp
->Parameters
.Read
.Length
;
175 IrpSp2
->Parameters
.Read
.ByteOffset
.QuadPart
= IrpSp
->Parameters
.Read
.ByteOffset
.QuadPart
;
177 KeInitializeEvent(&context
.Event
, NotificationEvent
, FALSE
);
178 Irp2
->UserIosb
= &context
.iosb
;
180 IoSetCompletionRoutine(Irp2
, vol_read_completion
, &context
, TRUE
, TRUE
, TRUE
);
182 Status
= IoCallDriver(vc
->devobj
, Irp2
);
184 if (Status
== STATUS_PENDING
) {
185 KeWaitForSingleObject(&context
.Event
, Executive
, KernelMode
, FALSE
, NULL
);
186 Status
= context
.iosb
.Status
;
189 ExReleaseResourceLite(&pdode
->child_lock
);
191 Irp
->IoStatus
.Information
= context
.iosb
.Information
;
194 Irp
->IoStatus
.Status
= Status
;
195 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
200 NTSTATUS
vol_write(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
) {
201 volume_device_extension
* vde
= DeviceObject
->DeviceExtension
;
202 pdo_device_extension
* pdode
= vde
->pdode
;
206 vol_read_context context
;
207 PIO_STACK_LOCATION IrpSp
, IrpSp2
;
209 TRACE("(%p, %p)\n", DeviceObject
, Irp
);
211 ExAcquireResourceSharedLite(&pdode
->child_lock
, TRUE
);
213 if (IsListEmpty(&pdode
->children
)) {
214 ExReleaseResourceLite(&pdode
->child_lock
);
215 Status
= STATUS_INVALID_DEVICE_REQUEST
;
219 vc
= CONTAINING_RECORD(pdode
->children
.Flink
, volume_child
, list_entry
);
221 if (vc
->list_entry
.Flink
!= &pdode
->children
) { // more than once device
222 ExReleaseResourceLite(&pdode
->child_lock
);
223 Status
= STATUS_ACCESS_DENIED
;
227 // We can't use IoSkipCurrentIrpStackLocation as the device isn't in our stack
229 Irp2
= IoAllocateIrp(vc
->devobj
->StackSize
, FALSE
);
232 ERR("IoAllocateIrp failed\n");
233 ExReleaseResourceLite(&pdode
->child_lock
);
234 Status
= STATUS_INSUFFICIENT_RESOURCES
;
238 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
239 IrpSp2
= IoGetNextIrpStackLocation(Irp2
);
241 IrpSp2
->MajorFunction
= IRP_MJ_WRITE
;
243 if (vc
->devobj
->Flags
& DO_BUFFERED_IO
) {
244 Irp2
->AssociatedIrp
.SystemBuffer
= MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, NormalPagePriority
);
246 Irp2
->Flags
|= IRP_BUFFERED_IO
;
248 Irp2
->UserBuffer
= MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, NormalPagePriority
);
249 } else if (vc
->devobj
->Flags
& DO_DIRECT_IO
)
250 Irp2
->MdlAddress
= Irp
->MdlAddress
;
252 Irp2
->UserBuffer
= MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, NormalPagePriority
);
254 IrpSp2
->Parameters
.Write
.Length
= IrpSp
->Parameters
.Write
.Length
;
255 IrpSp2
->Parameters
.Write
.ByteOffset
.QuadPart
= IrpSp
->Parameters
.Write
.ByteOffset
.QuadPart
;
257 KeInitializeEvent(&context
.Event
, NotificationEvent
, FALSE
);
258 Irp2
->UserIosb
= &context
.iosb
;
260 IoSetCompletionRoutine(Irp2
, vol_read_completion
, &context
, TRUE
, TRUE
, TRUE
);
262 Status
= IoCallDriver(vc
->devobj
, Irp2
);
264 if (Status
== STATUS_PENDING
) {
265 KeWaitForSingleObject(&context
.Event
, Executive
, KernelMode
, FALSE
, NULL
);
266 Status
= context
.iosb
.Status
;
269 ExReleaseResourceLite(&pdode
->child_lock
);
271 Irp
->IoStatus
.Information
= context
.iosb
.Information
;
274 Irp
->IoStatus
.Status
= Status
;
275 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
280 NTSTATUS
vol_query_information(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
) {
281 TRACE("(%p, %p)\n", DeviceObject
, Irp
);
283 return STATUS_INVALID_DEVICE_REQUEST
;
286 NTSTATUS
vol_set_information(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
) {
287 TRACE("(%p, %p)\n", DeviceObject
, Irp
);
289 return STATUS_INVALID_DEVICE_REQUEST
;
292 NTSTATUS
vol_query_ea(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
) {
293 TRACE("(%p, %p)\n", DeviceObject
, Irp
);
295 return STATUS_INVALID_DEVICE_REQUEST
;
298 NTSTATUS
vol_set_ea(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
) {
299 TRACE("(%p, %p)\n", DeviceObject
, Irp
);
301 return STATUS_INVALID_DEVICE_REQUEST
;
304 NTSTATUS
vol_flush_buffers(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
) {
305 TRACE("(%p, %p)\n", DeviceObject
, Irp
);
307 return STATUS_INVALID_DEVICE_REQUEST
;
310 NTSTATUS
vol_query_volume_information(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
) {
311 TRACE("(%p, %p)\n", DeviceObject
, Irp
);
313 return STATUS_INVALID_DEVICE_REQUEST
;
316 NTSTATUS
vol_set_volume_information(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
) {
317 TRACE("(%p, %p)\n", DeviceObject
, Irp
);
319 return STATUS_INVALID_DEVICE_REQUEST
;
322 NTSTATUS
vol_cleanup(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
) {
323 TRACE("(%p, %p)\n", DeviceObject
, Irp
);
325 Irp
->IoStatus
.Information
= 0;
327 return STATUS_SUCCESS
;
330 NTSTATUS
vol_directory_control(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
) {
331 TRACE("(%p, %p)\n", DeviceObject
, Irp
);
333 return STATUS_INVALID_DEVICE_REQUEST
;
336 NTSTATUS
vol_file_system_control(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
) {
337 TRACE("(%p, %p)\n", DeviceObject
, Irp
);
339 return STATUS_INVALID_DEVICE_REQUEST
;
342 NTSTATUS
vol_lock_control(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
) {
343 TRACE("(%p, %p)\n", DeviceObject
, Irp
);
345 return STATUS_INVALID_DEVICE_REQUEST
;
348 static NTSTATUS
vol_query_device_name(volume_device_extension
* vde
, PIRP Irp
) {
349 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
352 if (IrpSp
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(MOUNTDEV_NAME
)) {
353 Irp
->IoStatus
.Information
= sizeof(MOUNTDEV_NAME
);
354 return STATUS_BUFFER_TOO_SMALL
;
357 name
= Irp
->AssociatedIrp
.SystemBuffer
;
358 name
->NameLength
= vde
->name
.Length
;
360 if (IrpSp
->Parameters
.DeviceIoControl
.OutputBufferLength
< offsetof(MOUNTDEV_NAME
, Name
[0]) + name
->NameLength
) {
361 Irp
->IoStatus
.Information
= sizeof(MOUNTDEV_NAME
);
362 return STATUS_BUFFER_OVERFLOW
;
365 RtlCopyMemory(name
->Name
, vde
->name
.Buffer
, vde
->name
.Length
);
367 Irp
->IoStatus
.Information
= offsetof(MOUNTDEV_NAME
, Name
[0]) + name
->NameLength
;
369 return STATUS_SUCCESS
;
372 static NTSTATUS
vol_query_unique_id(volume_device_extension
* vde
, PIRP Irp
) {
373 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
374 MOUNTDEV_UNIQUE_ID
* mduid
;
375 pdo_device_extension
* pdode
;
377 if (IrpSp
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(MOUNTDEV_UNIQUE_ID
)) {
378 Irp
->IoStatus
.Information
= sizeof(MOUNTDEV_UNIQUE_ID
);
379 return STATUS_BUFFER_TOO_SMALL
;
382 mduid
= Irp
->AssociatedIrp
.SystemBuffer
;
383 mduid
->UniqueIdLength
= sizeof(BTRFS_UUID
);
385 if (IrpSp
->Parameters
.DeviceIoControl
.OutputBufferLength
< offsetof(MOUNTDEV_UNIQUE_ID
, UniqueId
[0]) + mduid
->UniqueIdLength
) {
386 Irp
->IoStatus
.Information
= sizeof(MOUNTDEV_UNIQUE_ID
);
387 return STATUS_BUFFER_OVERFLOW
;
391 return STATUS_INVALID_PARAMETER
;
395 RtlCopyMemory(mduid
->UniqueId
, &pdode
->uuid
, sizeof(BTRFS_UUID
));
397 Irp
->IoStatus
.Information
= offsetof(MOUNTDEV_UNIQUE_ID
, UniqueId
[0]) + mduid
->UniqueIdLength
;
399 return STATUS_SUCCESS
;
402 static NTSTATUS
vol_is_dynamic(PIRP Irp
) {
403 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
406 if (IrpSp
->Parameters
.DeviceIoControl
.OutputBufferLength
== 0 || !Irp
->AssociatedIrp
.SystemBuffer
)
407 return STATUS_INVALID_PARAMETER
;
409 buf
= (UINT8
*)Irp
->AssociatedIrp
.SystemBuffer
;
413 Irp
->IoStatus
.Information
= 1;
415 return STATUS_SUCCESS
;
418 static NTSTATUS
vol_check_verify(volume_device_extension
* vde
) {
419 pdo_device_extension
* pdode
= vde
->pdode
;
423 ExAcquireResourceSharedLite(&pdode
->child_lock
, TRUE
);
425 le
= pdode
->children
.Flink
;
426 while (le
!= &pdode
->children
) {
427 volume_child
* vc
= CONTAINING_RECORD(le
, volume_child
, list_entry
);
429 Status
= dev_ioctl(vc
->devobj
, IOCTL_STORAGE_CHECK_VERIFY
, NULL
, 0, NULL
, 0, FALSE
, NULL
);
430 if (!NT_SUCCESS(Status
))
436 Status
= STATUS_SUCCESS
;
439 ExReleaseResourceLite(&pdode
->child_lock
);
444 static NTSTATUS
vol_get_disk_extents(volume_device_extension
* vde
, PIRP Irp
) {
445 pdo_device_extension
* pdode
= vde
->pdode
;
446 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
448 ULONG num_extents
= 0, i
, max_extents
= 1;
450 VOLUME_DISK_EXTENTS
*ext
, *ext3
;
452 if (IrpSp
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(VOLUME_DISK_EXTENTS
))
453 return STATUS_BUFFER_TOO_SMALL
;
455 ExAcquireResourceSharedLite(&pdode
->child_lock
, TRUE
);
457 le
= pdode
->children
.Flink
;
458 while (le
!= &pdode
->children
) {
459 volume_child
* vc
= CONTAINING_RECORD(le
, volume_child
, list_entry
);
460 VOLUME_DISK_EXTENTS ext2
;
462 Status
= dev_ioctl(vc
->devobj
, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS
, NULL
, 0, &ext2
, sizeof(VOLUME_DISK_EXTENTS
), FALSE
, NULL
);
463 if (!NT_SUCCESS(Status
) && Status
!= STATUS_BUFFER_OVERFLOW
) {
464 ERR("IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS returned %08x\n", Status
);
468 num_extents
+= ext2
.NumberOfDiskExtents
;
470 if (ext2
.NumberOfDiskExtents
> max_extents
)
471 max_extents
= ext2
.NumberOfDiskExtents
;
476 ext
= Irp
->AssociatedIrp
.SystemBuffer
;
478 if (IrpSp
->Parameters
.DeviceIoControl
.OutputBufferLength
< offsetof(VOLUME_DISK_EXTENTS
, Extents
[0]) + (num_extents
* sizeof(DISK_EXTENT
))) {
479 Irp
->IoStatus
.Information
= offsetof(VOLUME_DISK_EXTENTS
, Extents
[0]);
480 ext
->NumberOfDiskExtents
= num_extents
;
481 Status
= STATUS_BUFFER_OVERFLOW
;
485 ext3
= ExAllocatePoolWithTag(PagedPool
, offsetof(VOLUME_DISK_EXTENTS
, Extents
[0]) + (max_extents
* sizeof(DISK_EXTENT
)), ALLOC_TAG
);
487 ERR("out of memory\n");
488 Status
= STATUS_INSUFFICIENT_RESOURCES
;
493 ext
->NumberOfDiskExtents
= 0;
495 le
= pdode
->children
.Flink
;
496 while (le
!= &pdode
->children
) {
497 volume_child
* vc
= CONTAINING_RECORD(le
, volume_child
, list_entry
);
499 Status
= dev_ioctl(vc
->devobj
, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS
, NULL
, 0, ext3
,
500 (ULONG
)offsetof(VOLUME_DISK_EXTENTS
, Extents
[0]) + (max_extents
* sizeof(DISK_EXTENT
)), FALSE
, NULL
);
501 if (!NT_SUCCESS(Status
)) {
502 ERR("IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS returned %08x\n", Status
);
507 if (i
+ ext3
->NumberOfDiskExtents
> num_extents
) {
508 Irp
->IoStatus
.Information
= offsetof(VOLUME_DISK_EXTENTS
, Extents
[0]);
509 ext
->NumberOfDiskExtents
= i
+ ext3
->NumberOfDiskExtents
;
510 Status
= STATUS_BUFFER_OVERFLOW
;
515 RtlCopyMemory(&ext
->Extents
[i
], ext3
->Extents
, sizeof(DISK_EXTENT
) * ext3
->NumberOfDiskExtents
);
516 i
+= ext3
->NumberOfDiskExtents
;
523 Status
= STATUS_SUCCESS
;
525 ext
->NumberOfDiskExtents
= i
;
526 Irp
->IoStatus
.Information
= offsetof(VOLUME_DISK_EXTENTS
, Extents
[0]) + (i
* sizeof(DISK_EXTENT
));
529 ExReleaseResourceLite(&pdode
->child_lock
);
534 static NTSTATUS
vol_is_writable(volume_device_extension
* vde
) {
535 pdo_device_extension
* pdode
= vde
->pdode
;
538 BOOL writable
= FALSE
;
540 ExAcquireResourceSharedLite(&pdode
->child_lock
, TRUE
);
542 le
= pdode
->children
.Flink
;
543 while (le
!= &pdode
->children
) {
544 volume_child
* vc
= CONTAINING_RECORD(le
, volume_child
, list_entry
);
546 Status
= dev_ioctl(vc
->devobj
, IOCTL_DISK_IS_WRITABLE
, NULL
, 0, NULL
, 0, TRUE
, NULL
);
548 if (NT_SUCCESS(Status
)) {
551 } else if (Status
!= STATUS_MEDIA_WRITE_PROTECTED
)
557 Status
= writable
? STATUS_SUCCESS
: STATUS_MEDIA_WRITE_PROTECTED
;
560 ExReleaseResourceLite(&pdode
->child_lock
);
562 return STATUS_SUCCESS
;
565 static NTSTATUS
vol_get_length(volume_device_extension
* vde
, PIRP Irp
) {
566 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
567 pdo_device_extension
* pdode
= vde
->pdode
;
568 GET_LENGTH_INFORMATION
* gli
;
571 if (IrpSp
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(GET_LENGTH_INFORMATION
))
572 return STATUS_BUFFER_TOO_SMALL
;
574 gli
= (GET_LENGTH_INFORMATION
*)Irp
->AssociatedIrp
.SystemBuffer
;
576 gli
->Length
.QuadPart
= 0;
578 ExAcquireResourceSharedLite(&pdode
->child_lock
, TRUE
);
580 le
= pdode
->children
.Flink
;
581 while (le
!= &pdode
->children
) {
582 volume_child
* vc
= CONTAINING_RECORD(le
, volume_child
, list_entry
);
584 gli
->Length
.QuadPart
+= vc
->size
;
589 ExReleaseResourceLite(&pdode
->child_lock
);
591 Irp
->IoStatus
.Information
= sizeof(GET_LENGTH_INFORMATION
);
593 return STATUS_SUCCESS
;
596 static NTSTATUS
vol_get_drive_geometry(PDEVICE_OBJECT DeviceObject
, PIRP Irp
) {
597 volume_device_extension
* vde
= DeviceObject
->DeviceExtension
;
598 pdo_device_extension
* pdode
= vde
->pdode
;
599 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
604 if (IrpSp
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(DISK_GEOMETRY
))
605 return STATUS_BUFFER_TOO_SMALL
;
609 ExAcquireResourceSharedLite(&pdode
->child_lock
, TRUE
);
611 le
= pdode
->children
.Flink
;
612 while (le
!= &pdode
->children
) {
613 volume_child
* vc
= CONTAINING_RECORD(le
, volume_child
, list_entry
);
620 ExReleaseResourceLite(&pdode
->child_lock
);
622 geom
= (DISK_GEOMETRY
*)Irp
->AssociatedIrp
.SystemBuffer
;
623 geom
->BytesPerSector
= DeviceObject
->SectorSize
== 0 ? 0x200 : DeviceObject
->SectorSize
;
624 geom
->SectorsPerTrack
= 0x3f;
625 geom
->TracksPerCylinder
= 0xff;
626 geom
->Cylinders
.QuadPart
= length
/ (UInt32x32To64(geom
->TracksPerCylinder
, geom
->SectorsPerTrack
) * geom
->BytesPerSector
);
627 geom
->MediaType
= DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
? RemovableMedia
: FixedMedia
;
629 Irp
->IoStatus
.Information
= sizeof(DISK_GEOMETRY
);
631 return STATUS_SUCCESS
;
634 static NTSTATUS
vol_get_gpt_attributes(PIRP Irp
) {
635 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
636 VOLUME_GET_GPT_ATTRIBUTES_INFORMATION
* vggai
;
638 if (IrpSp
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(VOLUME_GET_GPT_ATTRIBUTES_INFORMATION
))
639 return STATUS_BUFFER_TOO_SMALL
;
641 vggai
= (VOLUME_GET_GPT_ATTRIBUTES_INFORMATION
*)Irp
->AssociatedIrp
.SystemBuffer
;
643 vggai
->GptAttributes
= 0;
645 Irp
->IoStatus
.Information
= sizeof(VOLUME_GET_GPT_ATTRIBUTES_INFORMATION
);
647 return STATUS_SUCCESS
;
650 static NTSTATUS
vol_get_device_number(volume_device_extension
* vde
, PIRP Irp
) {
651 pdo_device_extension
* pdode
= vde
->pdode
;
652 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
654 STORAGE_DEVICE_NUMBER
* sdn
;
656 // If only one device, return its disk number. This is needed for ejection to work.
658 if (IrpSp
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(STORAGE_DEVICE_NUMBER
))
659 return STATUS_BUFFER_TOO_SMALL
;
661 ExAcquireResourceSharedLite(&pdode
->child_lock
, TRUE
);
663 if (IsListEmpty(&pdode
->children
) || pdode
->num_children
> 1) {
664 ExReleaseResourceLite(&pdode
->child_lock
);
665 return STATUS_INVALID_DEVICE_REQUEST
;
668 vc
= CONTAINING_RECORD(pdode
->children
.Flink
, volume_child
, list_entry
);
670 if (vc
->disk_num
== 0xffffffff) {
671 ExReleaseResourceLite(&pdode
->child_lock
);
672 return STATUS_INVALID_DEVICE_REQUEST
;
675 sdn
= (STORAGE_DEVICE_NUMBER
*)Irp
->AssociatedIrp
.SystemBuffer
;
677 sdn
->DeviceType
= FILE_DEVICE_DISK
;
678 sdn
->DeviceNumber
= vc
->disk_num
;
679 sdn
->PartitionNumber
= vc
->part_num
;
681 ExReleaseResourceLite(&pdode
->child_lock
);
683 Irp
->IoStatus
.Information
= sizeof(STORAGE_DEVICE_NUMBER
);
685 return STATUS_SUCCESS
;
688 _Function_class_(IO_COMPLETION_ROUTINE
)
690 static NTSTATUS NTAPI
vol_ioctl_completion(PDEVICE_OBJECT DeviceObject
, PIRP Irp
, PVOID conptr
) {
692 static NTSTATUS
vol_ioctl_completion(PDEVICE_OBJECT DeviceObject
, PIRP Irp
, PVOID conptr
) {
694 KEVENT
* event
= conptr
;
696 UNUSED(DeviceObject
);
699 KeSetEvent(event
, 0, FALSE
);
701 return STATUS_MORE_PROCESSING_REQUIRED
;
704 static NTSTATUS
vol_ioctl_passthrough(volume_device_extension
* vde
, PIRP Irp
) {
708 PIO_STACK_LOCATION IrpSp
, IrpSp2
;
710 pdo_device_extension
* pdode
= vde
->pdode
;
712 TRACE("(%p, %p)\n", vde
, Irp
);
714 ExAcquireResourceSharedLite(&pdode
->child_lock
, TRUE
);
716 if (IsListEmpty(&pdode
->children
)) {
717 ExReleaseResourceLite(&pdode
->child_lock
);
718 return STATUS_INVALID_DEVICE_REQUEST
;
721 vc
= CONTAINING_RECORD(pdode
->children
.Flink
, volume_child
, list_entry
);
723 if (vc
->list_entry
.Flink
!= &pdode
->children
) { // more than one device
724 ExReleaseResourceLite(&pdode
->child_lock
);
725 return STATUS_INVALID_DEVICE_REQUEST
;
728 Irp2
= IoAllocateIrp(vc
->devobj
->StackSize
, FALSE
);
731 ERR("IoAllocateIrp failed\n");
732 ExReleaseResourceLite(&pdode
->child_lock
);
733 return STATUS_INSUFFICIENT_RESOURCES
;
736 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
737 IrpSp2
= IoGetNextIrpStackLocation(Irp2
);
739 IrpSp2
->MajorFunction
= IrpSp
->MajorFunction
;
740 IrpSp2
->MinorFunction
= IrpSp
->MinorFunction
;
742 IrpSp2
->Parameters
.DeviceIoControl
.OutputBufferLength
= IrpSp
->Parameters
.DeviceIoControl
.OutputBufferLength
;
743 IrpSp2
->Parameters
.DeviceIoControl
.InputBufferLength
= IrpSp
->Parameters
.DeviceIoControl
.InputBufferLength
;
744 IrpSp2
->Parameters
.DeviceIoControl
.IoControlCode
= IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
;
745 IrpSp2
->Parameters
.DeviceIoControl
.Type3InputBuffer
= IrpSp
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
747 Irp2
->AssociatedIrp
.SystemBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
748 Irp2
->MdlAddress
= Irp
->MdlAddress
;
749 Irp2
->UserBuffer
= Irp
->UserBuffer
;
750 Irp2
->Flags
= Irp
->Flags
;
752 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
754 IoSetCompletionRoutine(Irp2
, vol_ioctl_completion
, &Event
, TRUE
, TRUE
, TRUE
);
756 Status
= IoCallDriver(vc
->devobj
, Irp2
);
758 if (Status
== STATUS_PENDING
) {
759 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
760 Status
= Irp2
->IoStatus
.Status
;
763 Irp
->IoStatus
.Status
= Irp2
->IoStatus
.Status
;
764 Irp
->IoStatus
.Information
= Irp2
->IoStatus
.Information
;
766 ExReleaseResourceLite(&pdode
->child_lock
);
771 NTSTATUS
vol_device_control(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
) {
772 volume_device_extension
* vde
= DeviceObject
->DeviceExtension
;
773 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
775 TRACE("(%p, %p)\n", DeviceObject
, Irp
);
777 Irp
->IoStatus
.Information
= 0;
779 switch (IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
) {
780 case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
:
781 return vol_query_device_name(vde
, Irp
);
783 case IOCTL_MOUNTDEV_QUERY_UNIQUE_ID
:
784 return vol_query_unique_id(vde
, Irp
);
786 case IOCTL_STORAGE_GET_DEVICE_NUMBER
:
787 return vol_get_device_number(vde
, Irp
);
789 case IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME
:
790 TRACE("unhandled control code IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME\n");
793 case IOCTL_MOUNTDEV_QUERY_STABLE_GUID
:
794 TRACE("unhandled control code IOCTL_MOUNTDEV_QUERY_STABLE_GUID\n");
797 case IOCTL_MOUNTDEV_LINK_CREATED
:
798 TRACE("unhandled control code IOCTL_MOUNTDEV_LINK_CREATED\n");
801 case IOCTL_VOLUME_GET_GPT_ATTRIBUTES
:
802 return vol_get_gpt_attributes(Irp
);
804 case IOCTL_VOLUME_IS_DYNAMIC
:
805 return vol_is_dynamic(Irp
);
807 case IOCTL_VOLUME_ONLINE
:
808 TRACE("unhandled control code IOCTL_VOLUME_ONLINE\n");
811 case IOCTL_VOLUME_POST_ONLINE
:
812 TRACE("unhandled control code IOCTL_VOLUME_POST_ONLINE\n");
815 case IOCTL_DISK_GET_DRIVE_GEOMETRY
:
816 return vol_get_drive_geometry(DeviceObject
, Irp
);
818 case IOCTL_DISK_IS_WRITABLE
:
819 return vol_is_writable(vde
);
821 case IOCTL_DISK_GET_LENGTH_INFO
:
822 return vol_get_length(vde
, Irp
);
824 case IOCTL_STORAGE_CHECK_VERIFY
:
825 case IOCTL_DISK_CHECK_VERIFY
:
826 return vol_check_verify(vde
);
828 case IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS
:
829 return vol_get_disk_extents(vde
, Irp
);
831 default: // pass ioctl through if only one child device
832 return vol_ioctl_passthrough(vde
, Irp
);
835 return STATUS_INVALID_DEVICE_REQUEST
;
838 NTSTATUS
vol_shutdown(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
) {
839 TRACE("(%p, %p)\n", DeviceObject
, Irp
);
841 return STATUS_INVALID_DEVICE_REQUEST
;
844 NTSTATUS
vol_query_security(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
) {
845 TRACE("(%p, %p)\n", DeviceObject
, Irp
);
847 return STATUS_INVALID_DEVICE_REQUEST
;
850 NTSTATUS
vol_set_security(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
) {
851 TRACE("(%p, %p)\n", DeviceObject
, Irp
);
853 return STATUS_INVALID_DEVICE_REQUEST
;
856 NTSTATUS
vol_power(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
) {
857 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
860 TRACE("(%p, %p)\n", DeviceObject
, Irp
);
862 if (IrpSp
->MinorFunction
== IRP_MN_SET_POWER
|| IrpSp
->MinorFunction
== IRP_MN_QUERY_POWER
)
863 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
865 Status
= Irp
->IoStatus
.Status
;
866 PoStartNextPowerIrp(Irp
);
871 NTSTATUS
mountmgr_add_drive_letter(PDEVICE_OBJECT mountmgr
, PUNICODE_STRING devpath
) {
874 MOUNTMGR_DRIVE_LETTER_TARGET
* mmdlt
;
875 MOUNTMGR_DRIVE_LETTER_INFORMATION mmdli
;
877 mmdltsize
= (ULONG
)offsetof(MOUNTMGR_DRIVE_LETTER_TARGET
, DeviceName
[0]) + devpath
->Length
;
879 mmdlt
= ExAllocatePoolWithTag(NonPagedPool
, mmdltsize
, ALLOC_TAG
);
881 ERR("out of memory\n");
882 return STATUS_INSUFFICIENT_RESOURCES
;
885 mmdlt
->DeviceNameLength
= devpath
->Length
;
886 RtlCopyMemory(&mmdlt
->DeviceName
, devpath
->Buffer
, devpath
->Length
);
887 TRACE("mmdlt = %.*S\n", mmdlt
->DeviceNameLength
/ sizeof(WCHAR
), mmdlt
->DeviceName
);
889 Status
= dev_ioctl(mountmgr
, IOCTL_MOUNTMGR_NEXT_DRIVE_LETTER
, mmdlt
, mmdltsize
, &mmdli
, sizeof(MOUNTMGR_DRIVE_LETTER_INFORMATION
), FALSE
, NULL
);
891 if (!NT_SUCCESS(Status
))
892 ERR("IOCTL_MOUNTMGR_NEXT_DRIVE_LETTER returned %08x\n", Status
);
894 TRACE("DriveLetterWasAssigned = %u, CurrentDriveLetter = %c\n", mmdli
.DriveLetterWasAssigned
, mmdli
.CurrentDriveLetter
);
901 _Function_class_(DRIVER_NOTIFICATION_CALLBACK_ROUTINE
)
903 NTSTATUS NTAPI
pnp_removal(PVOID NotificationStructure
, PVOID Context
) {
905 NTSTATUS
pnp_removal(PVOID NotificationStructure
, PVOID Context
) {
907 TARGET_DEVICE_REMOVAL_NOTIFICATION
* tdrn
= (TARGET_DEVICE_REMOVAL_NOTIFICATION
*)NotificationStructure
;
908 pdo_device_extension
* pdode
= (pdo_device_extension
*)Context
;
910 if (RtlCompareMemory(&tdrn
->Event
, &GUID_TARGET_DEVICE_QUERY_REMOVE
, sizeof(GUID
)) == sizeof(GUID
)) {
911 TRACE("GUID_TARGET_DEVICE_QUERY_REMOVE\n");
913 if (pdode
->vde
&& pdode
->vde
->mounted_device
)
914 return pnp_query_remove_device(pdode
->vde
->mounted_device
, NULL
);
917 return STATUS_SUCCESS
;
920 static BOOL
allow_degraded_mount(BTRFS_UUID
* uuid
) {
923 OBJECT_ATTRIBUTES oa
;
924 UNICODE_STRING path
, adus
;
925 UINT32 degraded
= mount_allow_degraded
;
926 ULONG i
, j
, kvfilen
, retlen
;
927 KEY_VALUE_FULL_INFORMATION
* kvfi
;
929 path
.Length
= path
.MaximumLength
= registry_path
.Length
+ (37 * sizeof(WCHAR
));
930 path
.Buffer
= ExAllocatePoolWithTag(PagedPool
, path
.Length
, ALLOC_TAG
);
933 ERR("out of memory\n");
937 RtlCopyMemory(path
.Buffer
, registry_path
.Buffer
, registry_path
.Length
);
938 i
= registry_path
.Length
/ sizeof(WCHAR
);
940 path
.Buffer
[i
] = '\\';
943 for (j
= 0; j
< 16; j
++) {
944 path
.Buffer
[i
] = hex_digit((uuid
->uuid
[j
] & 0xF0) >> 4);
945 path
.Buffer
[i
+1] = hex_digit(uuid
->uuid
[j
] & 0xF);
949 if (j
== 3 || j
== 5 || j
== 7 || j
== 9) {
950 path
.Buffer
[i
] = '-';
955 InitializeObjectAttributes(&oa
, &path
, OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
, NULL
, NULL
);
957 kvfilen
= (ULONG
)offsetof(KEY_VALUE_FULL_INFORMATION
, Name
[0]) + (255 * sizeof(WCHAR
));
958 kvfi
= ExAllocatePoolWithTag(PagedPool
, kvfilen
, ALLOC_TAG
);
960 ERR("out of memory\n");
961 ExFreePool(path
.Buffer
);
965 Status
= ZwOpenKey(&h
, KEY_QUERY_VALUE
, &oa
);
966 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
968 else if (!NT_SUCCESS(Status
)) {
969 ERR("ZwOpenKey returned %08x\n", Status
);
973 adus
.Buffer
= L
"AllowDegraded";
974 adus
.Length
= adus
.MaximumLength
= (USHORT
)(wcslen(adus
.Buffer
) * sizeof(WCHAR
));
976 if (NT_SUCCESS(ZwQueryValueKey(h
, &adus
, KeyValueFullInformation
, kvfi
, kvfilen
, &retlen
))) {
977 if (kvfi
->Type
== REG_DWORD
&& kvfi
->DataLength
>= sizeof(UINT32
)) {
978 UINT32
* val
= (UINT32
*)((UINT8
*)kvfi
+ kvfi
->DataOffset
);
989 ExFreePool(path
.Buffer
);
994 void add_volume_device(superblock
* sb
, PDEVICE_OBJECT mountmgr
, PUNICODE_STRING devpath
, UINT64 length
, ULONG disk_num
, ULONG part_num
) {
997 PDEVICE_OBJECT DeviceObject
;
999 PFILE_OBJECT FileObject
;
1000 UNICODE_STRING devpath2
;
1001 BOOL inserted
= FALSE
, new_pdo
= FALSE
;
1002 pdo_device_extension
* pdode
= NULL
;
1003 PDEVICE_OBJECT pdo
= NULL
;
1005 if (devpath
->Length
== 0)
1008 ExAcquireResourceExclusiveLite(&pdo_list_lock
, TRUE
);
1010 le
= pdo_list
.Flink
;
1011 while (le
!= &pdo_list
) {
1012 pdo_device_extension
* pdode2
= CONTAINING_RECORD(le
, pdo_device_extension
, list_entry
);
1014 if (RtlCompareMemory(&pdode2
->uuid
, &sb
->uuid
, sizeof(BTRFS_UUID
)) == sizeof(BTRFS_UUID
)) {
1022 Status
= IoGetDeviceObjectPointer(devpath
, FILE_READ_ATTRIBUTES
, &FileObject
, &DeviceObject
);
1023 if (!NT_SUCCESS(Status
)) {
1024 ERR("IoGetDeviceObjectPointer returned %08x\n", Status
);
1025 ExReleaseResourceLite(&pdo_list_lock
);
1031 Status
= IoReportDetectedDevice(drvobj
, InterfaceTypeUndefined
, 0xFFFFFFFF, 0xFFFFFFFF, NULL
, NULL
, 0, &pdo
);
1033 if (!NT_SUCCESS(Status
)) {
1034 ERR("IoReportDetectedDevice returned %08x\n", Status
);
1035 ExReleaseResourceLite(&pdo_list_lock
);
1039 pdode
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(pdo_device_extension
), ALLOC_TAG
);
1042 ERR("out of memory\n");
1043 ExReleaseResourceLite(&pdo_list_lock
);
1047 Status
= IoCreateDevice(drvobj
, sizeof(pdo_device_extension
), NULL
, FILE_DEVICE_DISK
,
1048 FILE_AUTOGENERATED_DEVICE_NAME
| FILE_DEVICE_SECURE_OPEN
, FALSE
, &pdo
);
1049 if (!NT_SUCCESS(Status
)) {
1050 ERR("IoCreateDevice returned %08x\n", Status
);
1051 ExReleaseResourceLite(&pdo_list_lock
);
1055 pdo
->Flags
|= DO_BUS_ENUMERATED_DEVICE
;
1057 pdode
= pdo
->DeviceExtension
;
1060 RtlZeroMemory(pdode
, sizeof(pdo_device_extension
));
1062 pdode
->type
= VCB_TYPE_PDO
;
1064 pdode
->uuid
= sb
->uuid
;
1066 ExInitializeResourceLite(&pdode
->child_lock
);
1067 InitializeListHead(&pdode
->children
);
1068 pdode
->num_children
= sb
->num_devices
;
1069 pdode
->children_loaded
= 0;
1071 pdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
1072 pdo
->SectorSize
= (USHORT
)sb
->sector_size
;
1074 ExAcquireResourceExclusiveLite(&pdode
->child_lock
, TRUE
);
1078 ExAcquireResourceExclusiveLite(&pdode
->child_lock
, TRUE
);
1079 ExConvertExclusiveToSharedLite(&pdo_list_lock
);
1081 le
= pdode
->children
.Flink
;
1082 while (le
!= &pdode
->children
) {
1083 volume_child
* vc2
= CONTAINING_RECORD(le
, volume_child
, list_entry
);
1085 if (RtlCompareMemory(&vc2
->uuid
, &sb
->dev_item
.device_uuid
, sizeof(BTRFS_UUID
)) == sizeof(BTRFS_UUID
)) {
1086 // duplicate, ignore
1087 ExReleaseResourceLite(&pdode
->child_lock
);
1088 ExReleaseResourceLite(&pdo_list_lock
);
1096 vc
= ExAllocatePoolWithTag(PagedPool
, sizeof(volume_child
), ALLOC_TAG
);
1098 ERR("out of memory\n");
1100 ExReleaseResourceLite(&pdode
->child_lock
);
1101 ExReleaseResourceLite(&pdo_list_lock
);
1106 vc
->uuid
= sb
->dev_item
.device_uuid
;
1107 vc
->devid
= sb
->dev_item
.dev_id
;
1108 vc
->generation
= sb
->generation
;
1109 vc
->notification_entry
= NULL
;
1111 Status
= IoRegisterPlugPlayNotification(EventCategoryTargetDeviceChange
, 0, FileObject
,
1112 drvobj
, pnp_removal
, pdode
, &vc
->notification_entry
);
1113 if (!NT_SUCCESS(Status
))
1114 WARN("IoRegisterPlugPlayNotification returned %08x\n", Status
);
1116 vc
->devobj
= DeviceObject
;
1117 vc
->fileobj
= FileObject
;
1119 devpath2
= *devpath
;
1121 // The PNP path sometimes begins \\?\ and sometimes \??\. We need to remove this prefix
1122 // so we can compare properly if the device is removed.
1123 if (devpath
->Length
> 4 * sizeof(WCHAR
) && devpath
->Buffer
[0] == '\\' && (devpath
->Buffer
[1] == '\\' || devpath
->Buffer
[1] == '?') &&
1124 devpath
->Buffer
[2] == '?' && devpath
->Buffer
[3] == '\\') {
1125 devpath2
.Buffer
= &devpath2
.Buffer
[3];
1126 devpath2
.Length
-= 3 * sizeof(WCHAR
);
1127 devpath2
.MaximumLength
-= 3 * sizeof(WCHAR
);
1130 vc
->pnp_name
.Length
= vc
->pnp_name
.MaximumLength
= devpath2
.Length
;
1131 vc
->pnp_name
.Buffer
= ExAllocatePoolWithTag(PagedPool
, devpath2
.Length
, ALLOC_TAG
);
1133 if (vc
->pnp_name
.Buffer
)
1134 RtlCopyMemory(vc
->pnp_name
.Buffer
, devpath2
.Buffer
, devpath2
.Length
);
1136 ERR("out of memory\n");
1137 vc
->pnp_name
.Length
= vc
->pnp_name
.MaximumLength
= 0;
1141 vc
->seeding
= sb
->flags
& BTRFS_SUPERBLOCK_FLAGS_SEEDING
? TRUE
: FALSE
;
1142 vc
->disk_num
= disk_num
;
1143 vc
->part_num
= part_num
;
1144 vc
->had_drive_letter
= FALSE
;
1146 le
= pdode
->children
.Flink
;
1147 while (le
!= &pdode
->children
) {
1148 volume_child
* vc2
= CONTAINING_RECORD(le
, volume_child
, list_entry
);
1150 if (vc2
->generation
< vc
->generation
) {
1151 if (le
== pdode
->children
.Flink
)
1152 pdode
->num_children
= sb
->num_devices
;
1154 InsertHeadList(vc2
->list_entry
.Blink
, &vc
->list_entry
);
1163 InsertTailList(&pdode
->children
, &vc
->list_entry
);
1165 pdode
->children_loaded
++;
1167 if (pdode
->vde
&& pdode
->vde
->mounted_device
) {
1168 device_extension
* Vcb
= pdode
->vde
->mounted_device
->DeviceExtension
;
1170 ExAcquireResourceExclusiveLite(&Vcb
->tree_lock
, TRUE
);
1172 le
= Vcb
->devices
.Flink
;
1173 while (le
!= &Vcb
->devices
) {
1174 device
* dev
= CONTAINING_RECORD(le
, device
, list_entry
);
1176 if (!dev
->devobj
&& RtlCompareMemory(&dev
->devitem
.device_uuid
, &sb
->dev_item
.device_uuid
, sizeof(BTRFS_UUID
)) == sizeof(BTRFS_UUID
)) {
1177 dev
->devobj
= DeviceObject
;
1178 dev
->disk_num
= disk_num
;
1179 dev
->part_num
= part_num
;
1180 init_device(Vcb
, dev
, FALSE
);
1187 ExReleaseResourceLite(&Vcb
->tree_lock
);
1190 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
1191 pdode
->removable
= TRUE
;
1193 if (pdode
->vde
&& pdode
->vde
->device
)
1194 pdode
->vde
->device
->Characteristics
|= FILE_REMOVABLE_MEDIA
;
1197 if (pdode
->num_children
== pdode
->children_loaded
|| (pdode
->children_loaded
== 1 && allow_degraded_mount(&sb
->uuid
))) {
1198 if (pdode
->num_children
== 1) {
1199 Status
= remove_drive_letter(mountmgr
, devpath
);
1200 if (!NT_SUCCESS(Status
) && Status
!= STATUS_NOT_FOUND
)
1201 WARN("remove_drive_letter returned %08x\n", Status
);
1203 vc
->had_drive_letter
= NT_SUCCESS(Status
);
1205 le
= pdode
->children
.Flink
;
1207 while (le
!= &pdode
->children
) {
1208 UNICODE_STRING name
;
1210 vc
= CONTAINING_RECORD(le
, volume_child
, list_entry
);
1212 name
.Length
= name
.MaximumLength
= vc
->pnp_name
.Length
+ (3 * sizeof(WCHAR
));
1213 name
.Buffer
= ExAllocatePoolWithTag(PagedPool
, name
.Length
, ALLOC_TAG
);
1216 ERR("out of memory\n");
1218 ExReleaseResourceLite(&pdode
->child_lock
);
1219 ExReleaseResourceLite(&pdo_list_lock
);
1224 RtlCopyMemory(name
.Buffer
, L
"\\??", 3 * sizeof(WCHAR
));
1225 RtlCopyMemory(&name
.Buffer
[3], vc
->pnp_name
.Buffer
, vc
->pnp_name
.Length
);
1227 Status
= remove_drive_letter(mountmgr
, &name
);
1229 if (!NT_SUCCESS(Status
) && Status
!= STATUS_NOT_FOUND
)
1230 WARN("remove_drive_letter returned %08x\n", Status
);
1232 ExFreePool(name
.Buffer
);
1234 vc
->had_drive_letter
= NT_SUCCESS(Status
);
1240 if ((!new_pdo
|| !no_pnp
) && pdode
->vde
) {
1241 Status
= IoSetDeviceInterfaceState(&pdode
->vde
->bus_name
, TRUE
);
1242 if (!NT_SUCCESS(Status
))
1243 WARN("IoSetDeviceInterfaceState returned %08x\n", Status
);
1247 ExReleaseResourceLite(&pdode
->child_lock
);
1250 control_device_extension
* cde
= master_devobj
->DeviceExtension
;
1252 InsertTailList(&pdo_list
, &pdode
->list_entry
);
1255 IoInvalidateDeviceRelations(cde
->buspdo
, BusRelations
);
1258 ExReleaseResourceLite(&pdo_list_lock
);
1260 if (new_pdo
&& no_pnp
)
1261 AddDevice(drvobj
, pdo
);
1266 ObDereferenceObject(FileObject
);