xref: /reactos/drivers/filesystems/btrfs/boot.c (revision c982533e)
1318da0c1SPierre Schweitzer /* Copyright (c) Mark Harmstone 2019
2318da0c1SPierre Schweitzer  *
3318da0c1SPierre Schweitzer  * This file is part of WinBtrfs.
4318da0c1SPierre Schweitzer  *
5318da0c1SPierre Schweitzer  * WinBtrfs is free software: you can redistribute it and/or modify
6318da0c1SPierre Schweitzer  * it under the terms of the GNU Lesser General Public Licence as published by
7318da0c1SPierre Schweitzer  * the Free Software Foundation, either version 3 of the Licence, or
8318da0c1SPierre Schweitzer  * (at your option) any later version.
9318da0c1SPierre Schweitzer  *
10318da0c1SPierre Schweitzer  * WinBtrfs is distributed in the hope that it will be useful,
11318da0c1SPierre Schweitzer  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12318da0c1SPierre Schweitzer  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13318da0c1SPierre Schweitzer  * GNU Lesser General Public Licence for more details.
14318da0c1SPierre Schweitzer  *
15318da0c1SPierre Schweitzer  * You should have received a copy of the GNU Lesser General Public Licence
16318da0c1SPierre Schweitzer  * along with WinBtrfs.  If not, see <http://www.gnu.org/licenses/>. */
17318da0c1SPierre Schweitzer 
18318da0c1SPierre Schweitzer #include "btrfs_drv.h"
19318da0c1SPierre Schweitzer 
20318da0c1SPierre Schweitzer #ifndef __REACTOS__
21318da0c1SPierre Schweitzer #ifdef _MSC_VER
22318da0c1SPierre Schweitzer #include <ntstrsafe.h>
23318da0c1SPierre Schweitzer #endif
24318da0c1SPierre Schweitzer #else
25318da0c1SPierre Schweitzer #include <ntstrsafe.h>
26318da0c1SPierre Schweitzer #endif
27318da0c1SPierre Schweitzer 
28318da0c1SPierre Schweitzer extern ERESOURCE pdo_list_lock;
29318da0c1SPierre Schweitzer extern LIST_ENTRY pdo_list;
3062e630deSPierre Schweitzer extern ERESOURCE boot_lock;
3162e630deSPierre Schweitzer extern PDRIVER_OBJECT drvobj;
32318da0c1SPierre Schweitzer 
33194ea909SVictor Perevertkin BTRFS_UUID boot_uuid; // initialized to 0
34194ea909SVictor Perevertkin uint64_t boot_subvol = 0;
35194ea909SVictor Perevertkin 
3662e630deSPierre Schweitzer // Not in any headers? Windbg knows about it though.
3762e630deSPierre Schweitzer #define DOE_START_PENDING 0x10
3862e630deSPierre Schweitzer 
3962e630deSPierre Schweitzer // Just as much as we need - the version in mingw is truncated still further
4062e630deSPierre Schweitzer typedef struct {
4162e630deSPierre Schweitzer     CSHORT Type;
4262e630deSPierre Schweitzer     USHORT Size;
4362e630deSPierre Schweitzer     PDEVICE_OBJECT DeviceObject;
4462e630deSPierre Schweitzer     ULONG PowerFlags;
4562e630deSPierre Schweitzer     void* Dope;
4662e630deSPierre Schweitzer     ULONG ExtensionFlags;
4762e630deSPierre Schweitzer } DEVOBJ_EXTENSION2;
4862e630deSPierre Schweitzer 
get_system_root()49*c982533eSVincent Franchomme static bool get_system_root() {
50318da0c1SPierre Schweitzer     NTSTATUS Status;
51318da0c1SPierre Schweitzer     HANDLE h;
52318da0c1SPierre Schweitzer     UNICODE_STRING us, target;
53318da0c1SPierre Schweitzer     OBJECT_ATTRIBUTES objatt;
54194ea909SVictor Perevertkin     ULONG retlen = 0;
55194ea909SVictor Perevertkin     bool second_time = false;
56318da0c1SPierre Schweitzer 
57318da0c1SPierre Schweitzer     static const WCHAR system_root[] = L"\\SystemRoot";
58194ea909SVictor Perevertkin     static const WCHAR boot_device[] = L"\\Device\\BootDevice";
59194ea909SVictor Perevertkin     static const WCHAR arc_btrfs_prefix[] = L"\\ArcName\\btrfs(";
60318da0c1SPierre Schweitzer 
61318da0c1SPierre Schweitzer     us.Buffer = (WCHAR*)system_root;
62318da0c1SPierre Schweitzer     us.Length = us.MaximumLength = sizeof(system_root) - sizeof(WCHAR);
63318da0c1SPierre Schweitzer 
64318da0c1SPierre Schweitzer     InitializeObjectAttributes(&objatt, &us, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
65318da0c1SPierre Schweitzer 
66194ea909SVictor Perevertkin     while (true) {
67318da0c1SPierre Schweitzer         Status = ZwOpenSymbolicLinkObject(&h, GENERIC_READ, &objatt);
68318da0c1SPierre Schweitzer         if (!NT_SUCCESS(Status)) {
69194ea909SVictor Perevertkin             ERR("ZwOpenSymbolicLinkObject returned %08lx\n", Status);
70*c982533eSVincent Franchomme             return false;
71318da0c1SPierre Schweitzer         }
72318da0c1SPierre Schweitzer 
73318da0c1SPierre Schweitzer         target.Length = target.MaximumLength = 0;
74318da0c1SPierre Schweitzer 
75318da0c1SPierre Schweitzer         Status = ZwQuerySymbolicLinkObject(h, &target, &retlen);
76318da0c1SPierre Schweitzer         if (Status != STATUS_BUFFER_TOO_SMALL) {
77194ea909SVictor Perevertkin             ERR("ZwQuerySymbolicLinkObject returned %08lx\n", Status);
78318da0c1SPierre Schweitzer             NtClose(h);
79*c982533eSVincent Franchomme             return false;
80318da0c1SPierre Schweitzer         }
81318da0c1SPierre Schweitzer 
82318da0c1SPierre Schweitzer         if (retlen == 0) {
83318da0c1SPierre Schweitzer             NtClose(h);
84*c982533eSVincent Franchomme             return false;
85318da0c1SPierre Schweitzer         }
86318da0c1SPierre Schweitzer 
87318da0c1SPierre Schweitzer         target.Buffer = ExAllocatePoolWithTag(NonPagedPool, retlen, ALLOC_TAG);
88318da0c1SPierre Schweitzer         if (!target.Buffer) {
89318da0c1SPierre Schweitzer             ERR("out of memory\n");
90318da0c1SPierre Schweitzer             NtClose(h);
91*c982533eSVincent Franchomme             return false;
92318da0c1SPierre Schweitzer         }
93318da0c1SPierre Schweitzer 
94318da0c1SPierre Schweitzer         target.Length = target.MaximumLength = (USHORT)retlen;
95318da0c1SPierre Schweitzer 
96318da0c1SPierre Schweitzer         Status = ZwQuerySymbolicLinkObject(h, &target, NULL);
97318da0c1SPierre Schweitzer         if (!NT_SUCCESS(Status)) {
98194ea909SVictor Perevertkin             ERR("ZwQuerySymbolicLinkObject returned %08lx\n", Status);
99318da0c1SPierre Schweitzer             NtClose(h);
100318da0c1SPierre Schweitzer             ExFreePool(target.Buffer);
101*c982533eSVincent Franchomme             return false;
102318da0c1SPierre Schweitzer         }
103318da0c1SPierre Schweitzer 
104318da0c1SPierre Schweitzer         NtClose(h);
105318da0c1SPierre Schweitzer 
106194ea909SVictor Perevertkin         if (second_time) {
107194ea909SVictor Perevertkin             TRACE("boot device is %.*S\n", (int)(target.Length / sizeof(WCHAR)), target.Buffer);
108194ea909SVictor Perevertkin         } else {
109194ea909SVictor Perevertkin             TRACE("system root is %.*S\n", (int)(target.Length / sizeof(WCHAR)), target.Buffer);
110318da0c1SPierre Schweitzer         }
111318da0c1SPierre Schweitzer 
112194ea909SVictor Perevertkin         if (!second_time && target.Length >= sizeof(boot_device) - sizeof(WCHAR) &&
113194ea909SVictor Perevertkin             RtlCompareMemory(target.Buffer, boot_device, sizeof(boot_device) - sizeof(WCHAR)) == sizeof(boot_device) - sizeof(WCHAR)) {
114194ea909SVictor Perevertkin             ExFreePool(target.Buffer);
115194ea909SVictor Perevertkin 
116194ea909SVictor Perevertkin             us.Buffer = (WCHAR*)boot_device;
117194ea909SVictor Perevertkin             us.Length = us.MaximumLength = sizeof(boot_device) - sizeof(WCHAR);
118194ea909SVictor Perevertkin 
119194ea909SVictor Perevertkin             second_time = true;
120194ea909SVictor Perevertkin         } else
121194ea909SVictor Perevertkin             break;
122194ea909SVictor Perevertkin     }
123194ea909SVictor Perevertkin 
124*c982533eSVincent Franchomme     if (target.Length >= sizeof(arc_btrfs_prefix) - sizeof(WCHAR) &&
125194ea909SVictor Perevertkin         RtlCompareMemory(target.Buffer, arc_btrfs_prefix, sizeof(arc_btrfs_prefix) - sizeof(WCHAR)) == sizeof(arc_btrfs_prefix) - sizeof(WCHAR)) {
126194ea909SVictor Perevertkin         WCHAR* s = &target.Buffer[(sizeof(arc_btrfs_prefix) / sizeof(WCHAR)) - 1];
127318da0c1SPierre Schweitzer 
128194ea909SVictor Perevertkin         for (unsigned int i = 0; i < 16; i++) {
129194ea909SVictor Perevertkin             if (*s >= '0' && *s <= '9')
130*c982533eSVincent Franchomme                 boot_uuid.uuid[i] = (*s - '0') << 4;
131194ea909SVictor Perevertkin             else if (*s >= 'a' && *s <= 'f')
132*c982533eSVincent Franchomme                 boot_uuid.uuid[i] = (*s - 'a' + 0xa) << 4;
133194ea909SVictor Perevertkin             else if (*s >= 'A' && *s <= 'F')
134*c982533eSVincent Franchomme                 boot_uuid.uuid[i] = (*s - 'A' + 0xa) << 4;
135194ea909SVictor Perevertkin             else {
136194ea909SVictor Perevertkin                 ExFreePool(target.Buffer);
137*c982533eSVincent Franchomme                 return false;
138194ea909SVictor Perevertkin             }
139194ea909SVictor Perevertkin 
140194ea909SVictor Perevertkin             s++;
141194ea909SVictor Perevertkin 
142194ea909SVictor Perevertkin             if (*s >= '0' && *s <= '9')
143*c982533eSVincent Franchomme                 boot_uuid.uuid[i] |= *s - '0';
144194ea909SVictor Perevertkin             else if (*s >= 'a' && *s <= 'f')
145*c982533eSVincent Franchomme                 boot_uuid.uuid[i] |= *s - 'a' + 0xa;
146194ea909SVictor Perevertkin             else if (*s >= 'A' && *s <= 'F')
147*c982533eSVincent Franchomme                 boot_uuid.uuid[i] |= *s - 'A' + 0xa;
148194ea909SVictor Perevertkin             else {
149194ea909SVictor Perevertkin                 ExFreePool(target.Buffer);
150*c982533eSVincent Franchomme                 return false;
151194ea909SVictor Perevertkin             }
152194ea909SVictor Perevertkin 
153194ea909SVictor Perevertkin             s++;
154194ea909SVictor Perevertkin 
155194ea909SVictor Perevertkin             if (i == 3 || i == 5 || i == 7 || i == 9) {
156194ea909SVictor Perevertkin                 if (*s != '-') {
157194ea909SVictor Perevertkin                     ExFreePool(target.Buffer);
158*c982533eSVincent Franchomme                     return false;
159194ea909SVictor Perevertkin                 }
160194ea909SVictor Perevertkin 
161194ea909SVictor Perevertkin                 s++;
162194ea909SVictor Perevertkin             }
163194ea909SVictor Perevertkin         }
164194ea909SVictor Perevertkin 
165194ea909SVictor Perevertkin         if (*s != ')') {
166194ea909SVictor Perevertkin             ExFreePool(target.Buffer);
167*c982533eSVincent Franchomme             return false;
168194ea909SVictor Perevertkin         }
169194ea909SVictor Perevertkin 
170194ea909SVictor Perevertkin         ExFreePool(target.Buffer);
171*c982533eSVincent Franchomme 
172*c982533eSVincent Franchomme         return true;
173318da0c1SPierre Schweitzer     }
174318da0c1SPierre Schweitzer 
175*c982533eSVincent Franchomme     ExFreePool(target.Buffer);
176174dfab6SVincent Franchomme 
177*c982533eSVincent Franchomme     return false;
178318da0c1SPierre Schweitzer }
179318da0c1SPierre Schweitzer 
mountmgr_notification(BTRFS_UUID * uuid)18062e630deSPierre Schweitzer static void mountmgr_notification(BTRFS_UUID* uuid) {
18162e630deSPierre Schweitzer     UNICODE_STRING mmdevpath;
18262e630deSPierre Schweitzer     NTSTATUS Status;
18362e630deSPierre Schweitzer     PFILE_OBJECT FileObject;
18462e630deSPierre Schweitzer     PDEVICE_OBJECT mountmgr;
18562e630deSPierre Schweitzer     ULONG mmtnlen;
18662e630deSPierre Schweitzer     MOUNTMGR_TARGET_NAME* mmtn;
18762e630deSPierre Schweitzer     WCHAR* w;
18862e630deSPierre Schweitzer 
18962e630deSPierre Schweitzer     RtlInitUnicodeString(&mmdevpath, MOUNTMGR_DEVICE_NAME);
19062e630deSPierre Schweitzer     Status = IoGetDeviceObjectPointer(&mmdevpath, FILE_READ_ATTRIBUTES, &FileObject, &mountmgr);
19162e630deSPierre Schweitzer     if (!NT_SUCCESS(Status)) {
192194ea909SVictor Perevertkin         ERR("IoGetDeviceObjectPointer returned %08lx\n", Status);
19362e630deSPierre Schweitzer         return;
19462e630deSPierre Schweitzer     }
19562e630deSPierre Schweitzer 
19662e630deSPierre Schweitzer     mmtnlen = offsetof(MOUNTMGR_TARGET_NAME, DeviceName[0]) + sizeof(BTRFS_VOLUME_PREFIX) + (36 * sizeof(WCHAR));
19762e630deSPierre Schweitzer 
19862e630deSPierre Schweitzer     mmtn = ExAllocatePoolWithTag(NonPagedPool, mmtnlen, ALLOC_TAG);
19962e630deSPierre Schweitzer     if (!mmtn) {
20062e630deSPierre Schweitzer         ERR("out of memory\n");
20162e630deSPierre Schweitzer         return;
20262e630deSPierre Schweitzer     }
20362e630deSPierre Schweitzer 
20462e630deSPierre Schweitzer     mmtn->DeviceNameLength = sizeof(BTRFS_VOLUME_PREFIX) + (36 * sizeof(WCHAR));
20562e630deSPierre Schweitzer 
20662e630deSPierre Schweitzer     RtlCopyMemory(mmtn->DeviceName, BTRFS_VOLUME_PREFIX, sizeof(BTRFS_VOLUME_PREFIX) - sizeof(WCHAR));
20762e630deSPierre Schweitzer 
20862e630deSPierre Schweitzer     w = &mmtn->DeviceName[(sizeof(BTRFS_VOLUME_PREFIX) / sizeof(WCHAR)) - 1];
20962e630deSPierre Schweitzer 
21062e630deSPierre Schweitzer     for (unsigned int i = 0; i < 16; i++) {
21162e630deSPierre Schweitzer         *w = hex_digit(uuid->uuid[i] >> 4); w++;
21262e630deSPierre Schweitzer         *w = hex_digit(uuid->uuid[i] & 0xf); w++;
21362e630deSPierre Schweitzer 
21462e630deSPierre Schweitzer         if (i == 3 || i == 5 || i == 7 || i == 9) {
21562e630deSPierre Schweitzer             *w = L'-';
21662e630deSPierre Schweitzer             w++;
21762e630deSPierre Schweitzer         }
21862e630deSPierre Schweitzer     }
21962e630deSPierre Schweitzer 
22062e630deSPierre Schweitzer     *w = L'}';
22162e630deSPierre Schweitzer 
22262e630deSPierre Schweitzer     Status = dev_ioctl(mountmgr, IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION, mmtn, mmtnlen, NULL, 0, false, NULL);
22362e630deSPierre Schweitzer     if (!NT_SUCCESS(Status)) {
224194ea909SVictor Perevertkin         ERR("IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION returned %08lx\n", Status);
22562e630deSPierre Schweitzer         ExFreePool(mmtn);
22662e630deSPierre Schweitzer         return;
22762e630deSPierre Schweitzer     }
22862e630deSPierre Schweitzer 
22962e630deSPierre Schweitzer     ExFreePool(mmtn);
23062e630deSPierre Schweitzer }
23162e630deSPierre Schweitzer 
check_boot_options()232194ea909SVictor Perevertkin static void check_boot_options() {
233194ea909SVictor Perevertkin     NTSTATUS Status;
234194ea909SVictor Perevertkin     WCHAR* s;
235194ea909SVictor Perevertkin 
236194ea909SVictor Perevertkin     static const WCHAR pathw[] = L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control";
237194ea909SVictor Perevertkin     static const WCHAR namew[] = L"SystemStartOptions";
238194ea909SVictor Perevertkin     static const WCHAR subvol[] = L"SUBVOL=";
239194ea909SVictor Perevertkin 
240194ea909SVictor Perevertkin     _SEH2_TRY {
241194ea909SVictor Perevertkin         HANDLE control;
242194ea909SVictor Perevertkin         OBJECT_ATTRIBUTES oa;
243194ea909SVictor Perevertkin         UNICODE_STRING path;
244194ea909SVictor Perevertkin         ULONG kvfilen = sizeof(KEY_VALUE_FULL_INFORMATION) - sizeof(WCHAR) + (255 * sizeof(WCHAR));
245194ea909SVictor Perevertkin         KEY_VALUE_FULL_INFORMATION* kvfi;
246194ea909SVictor Perevertkin         UNICODE_STRING name;
247194ea909SVictor Perevertkin         WCHAR* options;
248194ea909SVictor Perevertkin 
249194ea909SVictor Perevertkin         path.Buffer = (WCHAR*)pathw;
250194ea909SVictor Perevertkin         path.Length = path.MaximumLength = sizeof(pathw) - sizeof(WCHAR);
251194ea909SVictor Perevertkin 
252194ea909SVictor Perevertkin         InitializeObjectAttributes(&oa, &path, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
253194ea909SVictor Perevertkin 
254194ea909SVictor Perevertkin         Status = ZwOpenKey(&control, KEY_QUERY_VALUE, &oa);
255194ea909SVictor Perevertkin         if (!NT_SUCCESS(Status)) {
256194ea909SVictor Perevertkin             ERR("ZwOpenKey returned %08lx\n", Status);
257194ea909SVictor Perevertkin             return;
258194ea909SVictor Perevertkin         }
259194ea909SVictor Perevertkin 
260194ea909SVictor Perevertkin         // FIXME - don't fail if value too long (can we query for the length?)
261194ea909SVictor Perevertkin 
262194ea909SVictor Perevertkin         kvfi = ExAllocatePoolWithTag(PagedPool, kvfilen, ALLOC_TAG);
263194ea909SVictor Perevertkin         if (!kvfi) {
264194ea909SVictor Perevertkin             ERR("out of memory\n");
265194ea909SVictor Perevertkin             NtClose(control);
266194ea909SVictor Perevertkin             return;
267194ea909SVictor Perevertkin         }
268194ea909SVictor Perevertkin 
269194ea909SVictor Perevertkin         name.Buffer = (WCHAR*)namew;
270194ea909SVictor Perevertkin         name.Length = name.MaximumLength = sizeof(namew) - sizeof(WCHAR);
271194ea909SVictor Perevertkin 
272194ea909SVictor Perevertkin         Status = ZwQueryValueKey(control, &name, KeyValueFullInformation, kvfi,
273194ea909SVictor Perevertkin                                  kvfilen, &kvfilen);
274194ea909SVictor Perevertkin         if (!NT_SUCCESS(Status)) {
275194ea909SVictor Perevertkin             ERR("ZwQueryValueKey returned %08lx\n", Status);
276194ea909SVictor Perevertkin             NtClose(control);
277194ea909SVictor Perevertkin             return;
278194ea909SVictor Perevertkin         }
279194ea909SVictor Perevertkin 
280194ea909SVictor Perevertkin         NtClose(control);
281194ea909SVictor Perevertkin 
282194ea909SVictor Perevertkin         options = (WCHAR*)((uint8_t*)kvfi + kvfi->DataOffset);
283194ea909SVictor Perevertkin         options[kvfi->DataLength / sizeof(WCHAR)] = 0; // FIXME - make sure buffer long enough to allow this
284194ea909SVictor Perevertkin 
285194ea909SVictor Perevertkin         s = wcsstr(options, subvol);
286194ea909SVictor Perevertkin 
287194ea909SVictor Perevertkin         if (!s)
288194ea909SVictor Perevertkin             return;
289194ea909SVictor Perevertkin 
290194ea909SVictor Perevertkin         s += (sizeof(subvol) / sizeof(WCHAR)) - 1;
291194ea909SVictor Perevertkin 
292194ea909SVictor Perevertkin         boot_subvol = 0;
293194ea909SVictor Perevertkin 
294194ea909SVictor Perevertkin         while (true) {
295194ea909SVictor Perevertkin             if (*s >= '0' && *s <= '9') {
296194ea909SVictor Perevertkin                 boot_subvol <<= 4;
297194ea909SVictor Perevertkin                 boot_subvol |= *s - '0';
298194ea909SVictor Perevertkin             } else if (*s >= 'a' && *s <= 'f') {
299194ea909SVictor Perevertkin                 boot_subvol <<= 4;
300194ea909SVictor Perevertkin                 boot_subvol |= *s - 'a' + 0xa;
301194ea909SVictor Perevertkin             } else if (*s >= 'A' && *s <= 'F') {
302194ea909SVictor Perevertkin                 boot_subvol <<= 4;
303194ea909SVictor Perevertkin                 boot_subvol |= *s - 'A' + 0xa;
304194ea909SVictor Perevertkin             } else
305194ea909SVictor Perevertkin                 break;
306194ea909SVictor Perevertkin 
307194ea909SVictor Perevertkin             s++;
308194ea909SVictor Perevertkin         }
309194ea909SVictor Perevertkin     } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
310194ea909SVictor Perevertkin         return;
311194ea909SVictor Perevertkin     } _SEH2_END;
312194ea909SVictor Perevertkin 
313194ea909SVictor Perevertkin     if (boot_subvol != 0) {
314194ea909SVictor Perevertkin         TRACE("passed subvol %I64x in boot options\n", boot_subvol);
315194ea909SVictor Perevertkin     }
316194ea909SVictor Perevertkin }
317194ea909SVictor Perevertkin 
boot_add_device(DEVICE_OBJECT * pdo)318194ea909SVictor Perevertkin void boot_add_device(DEVICE_OBJECT* pdo) {
319194ea909SVictor Perevertkin     pdo_device_extension* pdode = pdo->DeviceExtension;
320194ea909SVictor Perevertkin 
321194ea909SVictor Perevertkin     AddDevice(drvobj, pdo);
322194ea909SVictor Perevertkin 
323194ea909SVictor Perevertkin     // To stop Windows sneakily setting DOE_START_PENDING
324194ea909SVictor Perevertkin     pdode->dont_report = true;
325194ea909SVictor Perevertkin 
326194ea909SVictor Perevertkin     if (pdo->DeviceObjectExtension) {
327194ea909SVictor Perevertkin         ((DEVOBJ_EXTENSION2*)pdo->DeviceObjectExtension)->ExtensionFlags &= ~DOE_START_PENDING;
328194ea909SVictor Perevertkin 
329194ea909SVictor Perevertkin         if (pdode && pdode->vde && pdode->vde->device)
330194ea909SVictor Perevertkin             ((DEVOBJ_EXTENSION2*)pdode->vde->device->DeviceObjectExtension)->ExtensionFlags &= ~DOE_START_PENDING;
331194ea909SVictor Perevertkin     }
332194ea909SVictor Perevertkin 
333194ea909SVictor Perevertkin     mountmgr_notification(&pdode->uuid);
334194ea909SVictor Perevertkin }
335194ea909SVictor Perevertkin 
check_system_root()336*c982533eSVincent Franchomme void check_system_root() {
337318da0c1SPierre Schweitzer     LIST_ENTRY* le;
33862e630deSPierre Schweitzer     PDEVICE_OBJECT pdo_to_add = NULL;
339318da0c1SPierre Schweitzer 
340*c982533eSVincent Franchomme     TRACE("()\n");
34106042735SVincent Franchomme 
34262e630deSPierre Schweitzer     // wait for any PNP notifications in progress to finish
34362e630deSPierre Schweitzer     ExAcquireResourceExclusiveLite(&boot_lock, TRUE);
34462e630deSPierre Schweitzer     ExReleaseResourceLite(&boot_lock);
34562e630deSPierre Schweitzer 
346*c982533eSVincent Franchomme     if (!get_system_root())
347*c982533eSVincent Franchomme         return;
348194ea909SVictor Perevertkin 
349194ea909SVictor Perevertkin     ExAcquireResourceSharedLite(&pdo_list_lock, true);
350194ea909SVictor Perevertkin 
351194ea909SVictor Perevertkin     le = pdo_list.Flink;
352194ea909SVictor Perevertkin     while (le != &pdo_list) {
353194ea909SVictor Perevertkin         pdo_device_extension* pdode = CONTAINING_RECORD(le, pdo_device_extension, list_entry);
354194ea909SVictor Perevertkin 
355*c982533eSVincent Franchomme         if (RtlCompareMemory(&pdode->uuid, &boot_uuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID)) {
356194ea909SVictor Perevertkin             if (!pdode->vde)
357194ea909SVictor Perevertkin                 pdo_to_add = pdode->pdo;
358*c982533eSVincent Franchomme             else if (pdode->vde->device && !(pdode->vde->device->Flags & DO_SYSTEM_BOOT_PARTITION)) { // AddDevice has beaten us to it
359194ea909SVictor Perevertkin                 NTSTATUS Status;
360194ea909SVictor Perevertkin 
361*c982533eSVincent Franchomme                 pdode->vde->device->Flags |= DO_SYSTEM_BOOT_PARTITION;
362*c982533eSVincent Franchomme                 pdode->pdo->Flags |= DO_SYSTEM_BOOT_PARTITION;
363194ea909SVictor Perevertkin 
364*c982533eSVincent Franchomme                 Status = IoSetDeviceInterfaceState(&pdode->vde->bus_name, false);
365194ea909SVictor Perevertkin                 if (!NT_SUCCESS(Status))
366194ea909SVictor Perevertkin                     ERR("IoSetDeviceInterfaceState returned %08lx\n", Status);
367194ea909SVictor Perevertkin 
368*c982533eSVincent Franchomme                 Status = IoSetDeviceInterfaceState(&pdode->vde->bus_name, true);
369194ea909SVictor Perevertkin                 if (!NT_SUCCESS(Status))
370194ea909SVictor Perevertkin                     ERR("IoSetDeviceInterfaceState returned %08lx\n", Status);
371194ea909SVictor Perevertkin             }
372194ea909SVictor Perevertkin 
373*c982533eSVincent Franchomme             break;
374*c982533eSVincent Franchomme         }
375*c982533eSVincent Franchomme 
376*c982533eSVincent Franchomme         le = le->Flink;
377*c982533eSVincent Franchomme     }
378*c982533eSVincent Franchomme 
379*c982533eSVincent Franchomme     ExReleaseResourceLite(&pdo_list_lock);
380*c982533eSVincent Franchomme 
381194ea909SVictor Perevertkin     check_boot_options();
38262e630deSPierre Schweitzer 
38362e630deSPierre Schweitzer     // If our FS depends on volumes that aren't there when we do our IoRegisterPlugPlayNotification calls
38462e630deSPierre Schweitzer     // in DriverEntry, bus_query_device_relations won't get called until it's too late. We need to do our
38562e630deSPierre Schweitzer     // own call to AddDevice here as a result. We need to clear the DOE_START_PENDING bits, or NtOpenFile
38662e630deSPierre Schweitzer     // will return STATUS_NO_SUCH_DEVICE.
387194ea909SVictor Perevertkin     if (pdo_to_add)
388194ea909SVictor Perevertkin         boot_add_device(pdo_to_add);
389318da0c1SPierre Schweitzer }
390