[BTRFS]
[reactos.git] / reactos / drivers / filesystems / btrfs / pnp.c
1 #include "btrfs_drv.h"
2
3 struct pnp_context;
4
5 typedef struct {
6 struct pnp_context* context;
7 PIRP Irp;
8 IO_STATUS_BLOCK iosb;
9 NTSTATUS Status;
10 } pnp_stripe;
11
12 typedef struct {
13 KEVENT Event;
14 NTSTATUS Status;
15 LONG left;
16 pnp_stripe* stripes;
17 } pnp_context;
18
19 static NTSTATUS STDCALL pnp_completion(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID conptr) {
20 pnp_stripe* stripe = conptr;
21 pnp_context* context = (pnp_context*)stripe->context;
22
23 stripe->Status = Irp->IoStatus.Status;
24
25 InterlockedDecrement(&context->left);
26
27 if (context->left == 0)
28 KeSetEvent(&context->Event, 0, FALSE);
29
30 return STATUS_MORE_PROCESSING_REQUIRED;
31 }
32
33 static NTSTATUS send_disks_pnp_message(device_extension* Vcb, UCHAR minor) {
34 pnp_context* context;
35 UINT64 num_devices, i;
36 NTSTATUS Status;
37
38 context = ExAllocatePoolWithTag(NonPagedPool, sizeof(pnp_context), ALLOC_TAG);
39 if (!context) {
40 ERR("out of memory\n");
41 return STATUS_INSUFFICIENT_RESOURCES;
42 }
43
44 RtlZeroMemory(context, sizeof(pnp_context));
45 KeInitializeEvent(&context->Event, NotificationEvent, FALSE);
46
47 num_devices = Vcb->superblock.num_devices;
48
49 context->stripes = ExAllocatePoolWithTag(NonPagedPool, sizeof(pnp_stripe) * num_devices, ALLOC_TAG);
50 if (!context->stripes) {
51 ERR("out of memory\n");
52 ExFreePool(context);
53 return STATUS_INSUFFICIENT_RESOURCES;
54 }
55
56 RtlZeroMemory(context->stripes, sizeof(pnp_stripe) * num_devices);
57
58 for (i = 0; i < num_devices; i++) {
59 PIO_STACK_LOCATION IrpSp;
60
61 if (Vcb->devices[i].devobj) {
62 context->stripes[i].context = (struct pnp_context*)context;
63
64 context->stripes[i].Irp = IoAllocateIrp(Vcb->devices[i].devobj->StackSize, FALSE);
65
66 if (!context->stripes[i].Irp) {
67 UINT64 j;
68
69 ERR("IoAllocateIrp failed\n");
70
71 for (j = 0; j < i; j++) {
72 if (Vcb->devices[j].devobj) {
73 IoFreeIrp(context->stripes[j].Irp);
74 }
75 }
76 ExFreePool(context->stripes);
77 ExFreePool(context);
78
79 return STATUS_INSUFFICIENT_RESOURCES;
80 }
81
82 IrpSp = IoGetNextIrpStackLocation(context->stripes[i].Irp);
83 IrpSp->MajorFunction = IRP_MJ_PNP;
84 IrpSp->MinorFunction = minor;
85
86 context->stripes[i].Irp->UserIosb = &context->stripes[i].iosb;
87
88 IoSetCompletionRoutine(context->stripes[i].Irp, pnp_completion, &context->stripes[i], TRUE, TRUE, TRUE);
89
90 context->stripes[i].Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
91
92 context->left++;
93 }
94 }
95
96 if (context->left == 0) {
97 Status = STATUS_SUCCESS;
98 goto end;
99 }
100
101 for (i = 0; i < num_devices; i++) {
102 if (context->stripes[i].Irp) {
103 IoCallDriver(Vcb->devices[i].devobj, context->stripes[i].Irp);
104 }
105 }
106
107 KeWaitForSingleObject(&context->Event, Executive, KernelMode, FALSE, NULL);
108
109 Status = STATUS_SUCCESS;
110
111 for (i = 0; i < num_devices; i++) {
112 if (context->stripes[i].Irp) {
113 if (context->stripes[i].Status != STATUS_SUCCESS)
114 Status = context->stripes[i].Status;
115 }
116 }
117
118 end:
119 for (i = 0; i < num_devices; i++) {
120 if (context->stripes[i].Irp) {
121 IoFreeIrp(context->stripes[i].Irp);
122 }
123 }
124
125 ExFreePool(context->stripes);
126 ExFreePool(context);
127
128 return Status;
129 }
130
131 static NTSTATUS pnp_cancel_remove_device(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
132 device_extension* Vcb = DeviceObject->DeviceExtension;
133 NTSTATUS Status;
134
135 ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
136
137 if (Vcb->root_fileref && Vcb->root_fileref->fcb && (Vcb->root_fileref->fcb->open_count > 0 || has_open_children(Vcb->root_fileref))) {
138 Status = STATUS_ACCESS_DENIED;
139 goto end;
140 }
141
142 Status = send_disks_pnp_message(Vcb, IRP_MN_CANCEL_REMOVE_DEVICE);
143 if (!NT_SUCCESS(Status)) {
144 WARN("send_disks_pnp_message returned %08x\n", Status);
145 goto end;
146 }
147
148 Vcb->removing = FALSE;
149 end:
150 ExReleaseResourceLite(&Vcb->fcb_lock);
151
152 return STATUS_SUCCESS;
153 }
154
155 static NTSTATUS pnp_query_remove_device(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
156 device_extension* Vcb = DeviceObject->DeviceExtension;
157 NTSTATUS Status;
158 LIST_ENTRY rollback;
159
160 ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
161
162 if (Vcb->root_fileref && Vcb->root_fileref->fcb && (Vcb->root_fileref->fcb->open_count > 0 || has_open_children(Vcb->root_fileref))) {
163 Status = STATUS_ACCESS_DENIED;
164 goto end;
165 }
166
167 Status = send_disks_pnp_message(Vcb, IRP_MN_QUERY_REMOVE_DEVICE);
168 if (!NT_SUCCESS(Status)) {
169 WARN("send_disks_pnp_message returned %08x\n", Status);
170 goto end;
171 }
172
173 Vcb->removing = TRUE;
174
175 InitializeListHead(&rollback);
176
177 ExAcquireResourceExclusiveLite(&Vcb->tree_lock, TRUE);
178
179 if (Vcb->need_write)
180 do_write(Vcb, &rollback);
181
182 clear_rollback(&rollback);
183
184 ExReleaseResourceLite(&Vcb->tree_lock);
185
186 Status = STATUS_SUCCESS;
187 end:
188 ExReleaseResourceLite(&Vcb->fcb_lock);
189
190 return Status;
191 }
192
193 static NTSTATUS pnp_remove_device(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
194 device_extension* Vcb = DeviceObject->DeviceExtension;
195 NTSTATUS Status;
196
197 Status = send_disks_pnp_message(Vcb, IRP_MN_REMOVE_DEVICE);
198 if (!NT_SUCCESS(Status)) {
199 WARN("send_disks_pnp_message returned %08x\n", Status);
200 }
201
202 if (DeviceObject->Vpb->Flags & VPB_MOUNTED) {
203 Status = FsRtlNotifyVolumeEvent(Vcb->root_file, FSRTL_VOLUME_DISMOUNT);
204 if (!NT_SUCCESS(Status)) {
205 WARN("FsRtlNotifyVolumeEvent returned %08x\n", Status);
206 }
207
208 uninit(Vcb, FALSE);
209 Vcb->Vpb->Flags &= ~VPB_MOUNTED;
210 }
211
212 return STATUS_SUCCESS;
213 }
214
215 static NTSTATUS pnp_start_device(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
216 FIXME("STUB\n");
217
218 return STATUS_NOT_IMPLEMENTED;
219 }
220
221 static NTSTATUS pnp_surprise_removal(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
222 FIXME("STUB\n");
223
224 return STATUS_SUCCESS;
225 }
226
227 NTSTATUS STDCALL drv_pnp(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
228 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
229 device_extension* Vcb = DeviceObject->DeviceExtension;
230 NTSTATUS Status;
231 BOOL top_level;
232
233 FsRtlEnterFileSystem();
234
235 top_level = is_top_level(Irp);
236
237 if (Vcb && Vcb->type == VCB_TYPE_PARTITION0) {
238 Status = part0_passthrough(DeviceObject, Irp);
239 goto end;
240 }
241
242 Status = STATUS_NOT_IMPLEMENTED;
243
244 switch (IrpSp->MinorFunction) {
245 case IRP_MN_CANCEL_REMOVE_DEVICE:
246 Status = pnp_cancel_remove_device(DeviceObject, Irp);
247 break;
248
249 case IRP_MN_QUERY_REMOVE_DEVICE:
250 Status = pnp_query_remove_device(DeviceObject, Irp);
251 break;
252
253 case IRP_MN_REMOVE_DEVICE:
254 Status = pnp_remove_device(DeviceObject, Irp);
255 break;
256
257 case IRP_MN_START_DEVICE:
258 Status = pnp_start_device(DeviceObject, Irp);
259 break;
260
261 case IRP_MN_SURPRISE_REMOVAL:
262 Status = pnp_surprise_removal(DeviceObject, Irp);
263 break;
264
265 default:
266 TRACE("passing minor function 0x%x on\n", IrpSp->MinorFunction);
267
268 IoSkipCurrentIrpStackLocation(Irp);
269 Status = IoCallDriver(Vcb->devices[0].devobj, Irp);
270 goto end;
271 }
272
273 // // Irp->IoStatus.Status = Status;
274 // // Irp->IoStatus.Information = 0;
275 //
276 // IoSkipCurrentIrpStackLocation(Irp);
277 //
278 // Status = IoCallDriver(Vcb->devices[0].devobj, Irp);
279 //
280 // // IoCompleteRequest(Irp, IO_NO_INCREMENT);
281
282 Irp->IoStatus.Status = Status;
283
284 IoCompleteRequest(Irp, IO_NO_INCREMENT);
285
286 end:
287 if (top_level)
288 IoSetTopLevelIrp(NULL);
289
290 FsRtlExitFileSystem();
291
292 return Status;
293 }