Remove unnecessary executable bits
[reactos.git] / drivers / filesystems / cdfs_new / pnp.c
1 /*++
2
3 Copyright (c) 1997-2000 Microsoft Corporation
4
5 Module Name:
6
7 Pnp.c
8
9 Abstract:
10
11 This module implements the Plug and Play routines for CDFS called by
12 the dispatch driver.
13
14
15 --*/
16
17 #include "cdprocs.h"
18
19 //
20 // The Bug check file id for this module
21 //
22
23 #define BugCheckFileId (CDFS_BUG_CHECK_PNP)
24
25 _Requires_lock_held_(_Global_critical_region_)
26 _Releases_nonreentrant_lock_(CdData.DataResource)
27 NTSTATUS
28 CdPnpQueryRemove (
29 _Inout_ PIRP_CONTEXT IrpContext,
30 _Inout_ PIRP Irp,
31 _Inout_ PVCB Vcb
32 );
33
34 _Requires_lock_held_(_Global_critical_region_)
35 _Releases_nonreentrant_lock_(CdData.DataResource)
36 NTSTATUS
37 CdPnpRemove (
38 _Inout_ PIRP_CONTEXT IrpContext,
39 _Inout_ PIRP Irp,
40 _Inout_ PVCB Vcb
41 );
42
43 _Requires_lock_held_(_Global_critical_region_)
44 _Releases_nonreentrant_lock_(CdData.DataResource)
45 NTSTATUS
46 CdPnpSurpriseRemove (
47 _Inout_ PIRP_CONTEXT IrpContext,
48 _Inout_ PIRP Irp,
49 _Inout_ PVCB Vcb
50 );
51
52 _Requires_lock_held_(_Global_critical_region_)
53 _Releases_nonreentrant_lock_(CdData.DataResource)
54 NTSTATUS
55 CdPnpCancelRemove (
56 _Inout_ PIRP_CONTEXT IrpContext,
57 _Inout_ PIRP Irp,
58 _Inout_ PVCB Vcb
59 );
60
61 // Tell prefast this is a completion routine.
62 IO_COMPLETION_ROUTINE CdPnpCompletionRoutine;
63
64 NTSTATUS
65 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
66 CdPnpCompletionRoutine (
67 _In_ PDEVICE_OBJECT DeviceObject,
68 _In_ PIRP Irp,
69 _In_reads_opt_(_Inexpressible_("varies")) PVOID Contxt
70 );
71
72 #ifdef ALLOC_PRAGMA
73 #pragma alloc_text(PAGE, CdCommonPnp)
74 #pragma alloc_text(PAGE, CdPnpCancelRemove)
75 #pragma alloc_text(PAGE, CdPnpQueryRemove)
76 #pragma alloc_text(PAGE, CdPnpRemove)
77 #pragma alloc_text(PAGE, CdPnpSurpriseRemove)
78 #endif
79
80 _Requires_lock_held_(_Global_critical_region_)
81 NTSTATUS
82 CdCommonPnp (
83 _Inout_ PIRP_CONTEXT IrpContext,
84 _Inout_ PIRP Irp
85 )
86
87 /*++
88
89 Routine Description:
90
91 This is the common routine for doing PnP operations called
92 by both the fsd and fsp threads
93
94 Arguments:
95
96 Irp - Supplies the Irp to process
97
98 Return Value:
99
100 NTSTATUS - The return status for the operation
101
102 --*/
103
104 {
105 NTSTATUS Status = STATUS_SUCCESS;
106 BOOLEAN PassThrough = FALSE;
107
108 PIO_STACK_LOCATION IrpSp;
109
110 PVOLUME_DEVICE_OBJECT OurDeviceObject;
111 PVCB Vcb;
112
113 PAGED_CODE();
114
115 // Global lock object is acquired based on internal book-keeping
116 _Analysis_suppress_lock_checking_(CdData.DataResource);
117
118 //
119 // Get the current Irp stack location.
120 //
121
122 IrpSp = IoGetCurrentIrpStackLocation( Irp );
123
124 //
125 // Find our Vcb. This is tricky since we have no file object in the Irp.
126 //
127
128 OurDeviceObject = (PVOLUME_DEVICE_OBJECT) IrpSp->DeviceObject;
129
130 //
131 // IO holds a handle reference on our VDO and holds the device lock, which
132 // syncs us against mounts/verifies. However we hold no reference on the
133 // volume, which may already have been torn down (and the Vpb freed), for
134 // example by a force dismount. Check for this condition. We must hold this
135 // lock until the pnp worker functions take additional locks/refs on the Vcb.
136 //
137
138 CdAcquireCdData( IrpContext);
139
140 //
141 // Make sure this device object really is big enough to be a volume device
142 // object. If it isn't, we need to get out before we try to reference some
143 // field that takes us past the end of an ordinary device object.
144 //
145
146 #ifdef _MSC_VER
147 #pragma prefast(suppress: 28175, "this is a filesystem driver, touching the size member is allowed")
148 #endif
149 if (OurDeviceObject->DeviceObject.Size != sizeof(VOLUME_DEVICE_OBJECT) ||
150 NodeType( &OurDeviceObject->Vcb ) != CDFS_NTC_VCB) {
151
152 //
153 // We were called with something we don't understand.
154 //
155
156 Status = STATUS_INVALID_PARAMETER;
157 CdReleaseCdData( IrpContext);
158 CdCompleteRequest( IrpContext, Irp, Status );
159 return Status;
160 }
161
162 //
163 // Force all PnP operations to be synchronous.
164 //
165
166 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
167
168 Vcb = &OurDeviceObject->Vcb;
169
170 //
171 // Check that the Vcb hasn't already been deleted. If so, just pass the
172 // request through to the driver below, we don't need to do anything.
173 //
174
175 if (NULL == Vcb->Vpb) {
176
177 PassThrough = TRUE;
178 }
179 else {
180
181 //
182 // Case on the minor code.
183 //
184
185 switch ( IrpSp->MinorFunction ) {
186
187 case IRP_MN_QUERY_REMOVE_DEVICE:
188
189 Status = CdPnpQueryRemove( IrpContext, Irp, Vcb );
190 break;
191
192 case IRP_MN_SURPRISE_REMOVAL:
193
194 Status = CdPnpSurpriseRemove( IrpContext, Irp, Vcb );
195 break;
196
197 case IRP_MN_REMOVE_DEVICE:
198
199 Status = CdPnpRemove( IrpContext, Irp, Vcb );
200 break;
201
202 case IRP_MN_CANCEL_REMOVE_DEVICE:
203
204 Status = CdPnpCancelRemove( IrpContext, Irp, Vcb );
205 break;
206
207 default:
208
209 PassThrough = TRUE;
210 break;
211 }
212 }
213
214 if (PassThrough) {
215
216 CdReleaseCdData( IrpContext);
217
218 //
219 // Just pass the IRP on. As we do not need to be in the
220 // way on return, ellide ourselves out of the stack.
221 //
222
223 IoSkipCurrentIrpStackLocation( Irp );
224
225 Status = IoCallDriver(Vcb->TargetDeviceObject, Irp);
226
227 //
228 // Cleanup our Irp Context. The driver has completed the Irp.
229 //
230
231 CdCompleteRequest( IrpContext, NULL, STATUS_SUCCESS );
232 }
233
234 return Status;
235 }
236
237 _Requires_lock_held_(_Global_critical_region_)
238 _Releases_nonreentrant_lock_(CdData.DataResource)
239 NTSTATUS
240 CdPnpQueryRemove (
241 _Inout_ PIRP_CONTEXT IrpContext,
242 _Inout_ PIRP Irp,
243 _Inout_ PVCB Vcb
244 )
245
246 /*++
247
248 Routine Description:
249
250 This routine handles the PnP query remove operation. The filesystem
251 is responsible for answering whether there are any reasons it sees
252 that the volume can not go away (and the device removed). Initiation
253 of the dismount begins when we answer yes to this question.
254
255 Query will be followed by a Cancel or Remove.
256
257 Arguments:
258
259 Irp - Supplies the Irp to process
260
261 Vcb - Supplies the volume being queried.
262
263 Return Value:
264
265 NTSTATUS - The return status for the operation
266
267 --*/
268
269 {
270 NTSTATUS Status;
271 KEVENT Event;
272 BOOLEAN VcbPresent = TRUE;
273
274 PAGED_CODE();
275
276 ASSERT_EXCLUSIVE_CDDATA;
277
278 //
279 // Having said yes to a QUERY, any communication with the
280 // underlying storage stack is undefined (and may block)
281 // until the bounding CANCEL or REMOVE is sent.
282 //
283 // Acquire the global resource so that we can try to vaporize the volume,
284 // and the vcb resource itself.
285 //
286
287 CdAcquireVcbExclusive( IrpContext, Vcb, FALSE );
288
289 //
290 // Drop a reference on the Vcb to keep it around after we drop the locks.
291 //
292
293 CdLockVcb( IrpContext, Vcb);
294 Vcb->VcbReference += 1;
295 CdUnlockVcb( IrpContext, Vcb);
296
297 CdReleaseCdData( IrpContext);
298
299 Status = CdLockVolumeInternal( IrpContext, Vcb, NULL );
300
301 //
302 // Reacquire the global lock, which means dropping the Vcb resource.
303 //
304
305 CdReleaseVcb( IrpContext, Vcb );
306
307 CdAcquireCdData( IrpContext );
308 CdAcquireVcbExclusive( IrpContext, Vcb, FALSE );
309
310 //
311 // Remove our extra reference.
312 //
313
314 CdLockVcb( IrpContext, Vcb);
315 Vcb->VcbReference -= 1;
316 CdUnlockVcb( IrpContext, Vcb);
317
318 if (NT_SUCCESS( Status )) {
319
320 //
321 // We need to pass this down before starting the dismount, which
322 // could disconnect us immediately from the stack.
323 //
324
325 //
326 // Get the next stack location, and copy over the stack location
327 //
328
329 IoCopyCurrentIrpStackLocationToNext( Irp );
330
331 //
332 // Set up the completion routine
333 //
334
335 KeInitializeEvent( &Event, NotificationEvent, FALSE );
336 IoSetCompletionRoutine( Irp,
337 CdPnpCompletionRoutine,
338 &Event,
339 TRUE,
340 TRUE,
341 TRUE );
342
343 //
344 // Send the request and wait.
345 //
346
347 Status = IoCallDriver(Vcb->TargetDeviceObject, Irp);
348
349 if (Status == STATUS_PENDING) {
350
351 (VOID)KeWaitForSingleObject( &Event,
352 Executive,
353 KernelMode,
354 FALSE,
355 NULL );
356
357 Status = Irp->IoStatus.Status;
358 }
359
360 //
361 // Now if no one below us failed already, initiate the dismount
362 // on this volume, make it go away. PnP needs to see our internal
363 // streams close and drop their references to the target device.
364 //
365 // Since we were able to lock the volume, we are guaranteed to
366 // move this volume into dismount state and disconnect it from
367 // the underlying storage stack. The force on our part is actually
368 // unnecesary, though complete.
369 //
370 // What is not strictly guaranteed, though, is that the closes
371 // for the metadata streams take effect synchronously underneath
372 // of this call. This would leave references on the target device
373 // even though we are disconnected!
374 //
375
376 if (NT_SUCCESS( Status )) {
377
378 VcbPresent = CdCheckForDismount( IrpContext, Vcb, TRUE );
379
380 NT_ASSERT( !VcbPresent || Vcb->VcbCondition == VcbDismountInProgress );
381 }
382
383 //
384 // Note: Normally everything will complete and the internal streams will
385 // vaporise. However there is some code in the system which drops additional
386 // references on fileobjects, including our internal stream file objects,
387 // for (WMI) tracing purposes. If that happens to run concurrently with our
388 // teardown, our internal streams will not vaporise until those references
389 // are removed. So it's possible that the volume still remains at this
390 // point. The pnp query remove will fail due to our references on the device.
391 // To be cleaner we will return an error here. We could pend the pnp
392 // IRP until the volume goes away, but since we don't know when that will
393 // be, and this is a very rare case, we'll just fail the query.
394 //
395 // The reason this is the case is that handles/fileobjects place a reference
396 // on the device objects they overly. In the filesystem case, these references
397 // are on our target devices. PnP correcly thinks that if references remain
398 // on the device objects in the stack that someone has a handle, and that this
399 // counts as a reason to not succeed the query - even though every interrogated
400 // driver thinks that it is OK.
401 //
402
403 if (NT_SUCCESS( Status) && VcbPresent && (Vcb->VcbReference != 0)) {
404
405 Status = STATUS_DEVICE_BUSY;
406 }
407 }
408
409 //
410 // Release the Vcb if it could still remain.
411 //
412
413 if (VcbPresent) {
414
415 CdReleaseVcb( IrpContext, Vcb );
416 }
417 else {
418 _Analysis_assume_lock_not_held_(Vcb->VcbResource);
419 }
420
421 CdReleaseCdData( IrpContext );
422
423 //
424 // Cleanup our IrpContext and complete the IRP if neccesary.
425 //
426
427 CdCompleteRequest( IrpContext, Irp, Status );
428
429 return Status;
430 }
431
432 _Requires_lock_held_(_Global_critical_region_)
433 _Releases_nonreentrant_lock_(CdData.DataResource)
434 NTSTATUS
435 CdPnpRemove (
436 _Inout_ PIRP_CONTEXT IrpContext,
437 _Inout_ PIRP Irp,
438 _Inout_ PVCB Vcb
439 )
440
441 /*++
442
443 Routine Description:
444
445 This routine handles the PnP remove operation. This is our notification
446 that the underlying storage device for the volume we have is gone, and
447 an excellent indication that the volume will never reappear. The filesystem
448 is responsible for initiation or completion the dismount.
449
450 Arguments:
451
452 Irp - Supplies the Irp to process
453
454 Vcb - Supplies the volume being removed.
455
456 Return Value:
457
458 NTSTATUS - The return status for the operation
459
460 --*/
461
462 {
463 NTSTATUS Status;
464 KEVENT Event;
465 BOOLEAN VcbPresent = TRUE;
466
467 PAGED_CODE();
468
469 ASSERT_EXCLUSIVE_CDDATA;
470
471 //
472 // REMOVE - a storage device is now gone. We either got
473 // QUERY'd and said yes OR got a SURPRISE OR a storage
474 // stack failed to spin back up from a sleep/stop state
475 // (the only case in which this will be the first warning).
476 //
477 // Note that it is entirely unlikely that we will be around
478 // for a REMOVE in the first two cases, as we try to intiate
479 // dismount.
480 //
481
482 //
483 // Acquire the global resource so that we can try to vaporize
484 // the volume, and the vcb resource itself.
485 //
486
487 CdAcquireVcbExclusive( IrpContext, Vcb, FALSE );
488
489 //
490 // The device will be going away. Remove our lock and find
491 // out if we ever had one in the first place.
492 //
493
494 Status = CdUnlockVolumeInternal( IrpContext, Vcb, NULL );
495
496 //
497 // If the volume had not been locked, we must invalidate the
498 // volume to ensure it goes away properly. The remove will
499 // succeed.
500 //
501
502 if (!NT_SUCCESS( Status )) {
503
504 CdLockVcb( IrpContext, Vcb );
505
506 if (Vcb->VcbCondition != VcbDismountInProgress) {
507
508 CdUpdateVcbCondition( Vcb, VcbInvalid);
509 }
510
511 CdUnlockVcb( IrpContext, Vcb );
512
513 Status = STATUS_SUCCESS;
514 }
515
516 //
517 // We need to pass this down before starting the dismount, which
518 // could disconnect us immediately from the stack.
519 //
520
521 //
522 // Get the next stack location, and copy over the stack location
523 //
524
525 IoCopyCurrentIrpStackLocationToNext( Irp );
526
527 //
528 // Set up the completion routine
529 //
530
531 KeInitializeEvent( &Event, NotificationEvent, FALSE );
532 IoSetCompletionRoutine( Irp,
533 CdPnpCompletionRoutine,
534 &Event,
535 TRUE,
536 TRUE,
537 TRUE );
538
539 //
540 // Send the request and wait.
541 //
542
543 Status = IoCallDriver(Vcb->TargetDeviceObject, Irp);
544
545 if (Status == STATUS_PENDING) {
546
547 (VOID)KeWaitForSingleObject( &Event,
548 Executive,
549 KernelMode,
550 FALSE,
551 NULL );
552
553 Status = Irp->IoStatus.Status;
554 }
555
556 //
557 // Now make our dismount happen. This may not vaporize the
558 // Vcb, of course, since there could be any number of handles
559 // outstanding if we were not preceeded by a QUERY.
560 //
561 // PnP will take care of disconnecting this stack if we
562 // couldn't get off of it immediately.
563 //
564
565
566 VcbPresent = CdCheckForDismount( IrpContext, Vcb, TRUE );
567
568 //
569 // Release the Vcb if it could still remain.
570 //
571
572 if (VcbPresent) {
573
574 CdReleaseVcb( IrpContext, Vcb );
575 }
576 else {
577 _Analysis_assume_lock_not_held_(Vcb->VcbResource);
578 }
579
580 CdReleaseCdData( IrpContext );
581
582 //
583 // Cleanup our IrpContext and complete the IRP.
584 //
585
586 CdCompleteRequest( IrpContext, Irp, Status );
587
588 return Status;
589 }
590
591 _Requires_lock_held_(_Global_critical_region_)
592 _Releases_nonreentrant_lock_(CdData.DataResource)
593 NTSTATUS
594 CdPnpSurpriseRemove (
595 _Inout_ PIRP_CONTEXT IrpContext,
596 _Inout_ PIRP Irp,
597 _Inout_ PVCB Vcb
598 )
599
600 /*++
601
602 Routine Description:
603
604 This routine handles the PnP surprise remove operation. This is another
605 type of notification that the underlying storage device for the volume we
606 have is gone, and is excellent indication that the volume will never reappear.
607 The filesystem is responsible for initiation or completion the dismount.
608
609 For the most part, only "real" drivers care about the distinction of a
610 surprise remove, which is a result of our noticing that a user (usually)
611 physically reached into the machine and pulled something out.
612
613 Surprise will be followed by a Remove when all references have been shut down.
614
615 Arguments:
616
617 Irp - Supplies the Irp to process
618
619 Vcb - Supplies the volume being removed.
620
621 Return Value:
622
623 NTSTATUS - The return status for the operation
624
625 --*/
626
627 {
628 NTSTATUS Status;
629 KEVENT Event;
630 BOOLEAN VcbPresent = TRUE;
631
632 PAGED_CODE();
633
634 ASSERT_EXCLUSIVE_CDDATA;
635
636 //
637 // SURPRISE - a device was physically yanked away without
638 // any warning. This means external forces.
639 //
640
641 CdAcquireVcbExclusive( IrpContext, Vcb, FALSE );
642
643 //
644 // Invalidate the volume right now.
645 //
646 // The intent here is to make every subsequent operation
647 // on the volume fail and grease the rails toward dismount.
648 // By definition there is no going back from a SURPRISE.
649 //
650
651 CdLockVcb( IrpContext, Vcb );
652
653 if (Vcb->VcbCondition != VcbDismountInProgress) {
654
655 CdUpdateVcbCondition( Vcb, VcbInvalid);
656 }
657
658 CdUnlockVcb( IrpContext, Vcb );
659
660 //
661 // We need to pass this down before starting the dismount, which
662 // could disconnect us immediately from the stack.
663 //
664
665 //
666 // Get the next stack location, and copy over the stack location
667 //
668
669 IoCopyCurrentIrpStackLocationToNext( Irp );
670
671 //
672 // Set up the completion routine
673 //
674
675 KeInitializeEvent( &Event, NotificationEvent, FALSE );
676 IoSetCompletionRoutine( Irp,
677 CdPnpCompletionRoutine,
678 &Event,
679 TRUE,
680 TRUE,
681 TRUE );
682
683 //
684 // Send the request and wait.
685 //
686
687 Status = IoCallDriver(Vcb->TargetDeviceObject, Irp);
688
689 if (Status == STATUS_PENDING) {
690
691 (VOID)KeWaitForSingleObject( &Event,
692 Executive,
693 KernelMode,
694 FALSE,
695 NULL );
696
697 Status = Irp->IoStatus.Status;
698 }
699
700 //
701 // Now make our dismount happen. This may not vaporize the
702 // Vcb, of course, since there could be any number of handles
703 // outstanding since this is an out of band notification.
704 //
705
706
707 VcbPresent = CdCheckForDismount( IrpContext, Vcb, TRUE );
708
709 //
710 // Release the Vcb if it could still remain.
711 //
712
713 if (VcbPresent) {
714
715 CdReleaseVcb( IrpContext, Vcb );
716 }
717 else {
718 _Analysis_assume_lock_not_held_(Vcb->VcbResource);
719 }
720
721 CdReleaseCdData( IrpContext );
722
723 //
724 // Cleanup our IrpContext and complete the IRP.
725 //
726
727 CdCompleteRequest( IrpContext, Irp, Status );
728
729 return Status;
730 }
731
732 _Requires_lock_held_(_Global_critical_region_)
733 _Releases_nonreentrant_lock_(CdData.DataResource)
734 NTSTATUS
735 CdPnpCancelRemove (
736 _Inout_ PIRP_CONTEXT IrpContext,
737 _Inout_ PIRP Irp,
738 _Inout_ PVCB Vcb
739 )
740
741 /*++
742
743 Routine Description:
744
745 This routine handles the PnP cancel remove operation. This is our
746 notification that a previously proposed remove (query) was eventually
747 vetoed by a component. The filesystem is responsible for cleaning up
748 and getting ready for more IO.
749
750 Arguments:
751
752 Irp - Supplies the Irp to process
753
754 Vcb - Supplies the volume being removed.
755
756 Return Value:
757
758 NTSTATUS - The return status for the operation
759
760 --*/
761
762 {
763 NTSTATUS Status;
764
765 PAGED_CODE();
766
767 ASSERT_EXCLUSIVE_CDDATA;
768
769 //
770 // CANCEL - a previous QUERY has been rescinded as a result
771 // of someone vetoing. Since PnP cannot figure out who may
772 // have gotten the QUERY (think about it: stacked drivers),
773 // we must expect to deal with getting a CANCEL without having
774 // seen the QUERY.
775 //
776 // For CDFS, this is quite easy. In fact, we can't get a
777 // CANCEL if the underlying drivers succeeded the QUERY since
778 // we disconnect the Vpb on our dismount initiation. This is
779 // actually pretty important because if PnP could get to us
780 // after the disconnect we'd be thoroughly unsynchronized
781 // with respect to the Vcb getting torn apart - merely referencing
782 // the volume device object is insufficient to keep us intact.
783 //
784
785 CdAcquireVcbExclusive( IrpContext, Vcb, FALSE );
786 CdReleaseCdData( IrpContext);
787
788 //
789 // Unlock the volume. This is benign if we never had seen
790 // a QUERY.
791 //
792
793 (VOID) CdUnlockVolumeInternal( IrpContext, Vcb, NULL );
794
795 CdReleaseVcb( IrpContext, Vcb );
796
797 //
798 // Send the request. The underlying driver will complete the
799 // IRP. Since we don't need to be in the way, simply ellide
800 // ourselves out of the IRP stack.
801 //
802
803 IoSkipCurrentIrpStackLocation( Irp );
804
805 Status = IoCallDriver(Vcb->TargetDeviceObject, Irp);
806
807 CdCompleteRequest( IrpContext, NULL, STATUS_SUCCESS );
808
809 return Status;
810 }
811
812
813 //
814 // Local support routine
815 //
816
817 NTSTATUS
818 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
819 CdPnpCompletionRoutine (
820 _In_ PDEVICE_OBJECT DeviceObject,
821 _In_ PIRP Irp,
822 _In_reads_opt_(_Inexpressible_("varies")) PVOID Contxt
823 )
824 {
825 PKEVENT Event = (PKEVENT) Contxt;
826 _Analysis_assume_(Contxt != NULL);
827
828 KeSetEvent( Event, 0, FALSE );
829
830 return STATUS_MORE_PROCESSING_REQUIRED;
831
832 UNREFERENCED_PARAMETER( DeviceObject );
833 UNREFERENCED_PARAMETER( Irp );
834 UNREFERENCED_PARAMETER( Contxt );
835 }
836
837