Sync to trunk revision 61757.
[reactos.git] / drivers / storage / classpnp / create.c
1 /*++
2
3 Copyright (C) Microsoft Corporation, 1991 - 1999
4
5 Module Name:
6
7 class.c
8
9 Abstract:
10
11 SCSI class driver routines
12
13 Environment:
14
15 kernel mode only
16
17 Notes:
18
19
20 Revision History:
21
22 --*/
23
24 #define CLASS_INIT_GUID 0
25 #include "classp.h"
26 #include "debug.h"
27
28 ULONG BreakOnClose = 0;
29
30 PCSTR LockTypeStrings[] = {
31 "Simple",
32 "Secure",
33 "Internal"
34 };
35
36
37 PFILE_OBJECT_EXTENSION
38 NTAPI
39 ClasspGetFsContext(
40 IN PCOMMON_DEVICE_EXTENSION CommonExtension,
41 IN PFILE_OBJECT FileObject
42 );
43
44 VOID
45 NTAPI
46 ClasspCleanupDisableMcn(
47 IN PFILE_OBJECT_EXTENSION FsContext
48 );
49
50 #ifdef ALLOC_PRAGMA
51 #pragma alloc_text(PAGE, ClassCreateClose)
52 #pragma alloc_text(PAGE, ClasspCreateClose)
53 #pragma alloc_text(PAGE, ClasspCleanupProtectedLocks)
54 #pragma alloc_text(PAGE, ClasspEjectionControl)
55 #pragma alloc_text(PAGE, ClasspCleanupDisableMcn)
56 #pragma alloc_text(PAGE, ClasspGetFsContext)
57 #endif
58
59 NTSTATUS
60 NTAPI
61 ClassCreateClose(
62 IN PDEVICE_OBJECT DeviceObject,
63 IN PIRP Irp
64 )
65
66 /*++
67
68 Routine Description:
69
70 SCSI class driver create and close routine. This is called by the I/O system
71 when the device is opened or closed.
72
73 Arguments:
74
75 DriverObject - Pointer to driver object created by system.
76
77 Irp - IRP involved.
78
79 Return Value:
80
81 Device-specific drivers return value or STATUS_SUCCESS.
82
83 --*/
84
85 {
86 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
87 ULONG removeState;
88 NTSTATUS status;
89
90 PAGED_CODE();
91
92 //
93 // If we're getting a close request then we know the device object hasn't
94 // been completely destroyed. Let the driver cleanup if necessary.
95 //
96
97 removeState = ClassAcquireRemoveLock(DeviceObject, Irp);
98
99 //
100 // Invoke the device-specific routine, if one exists. Otherwise complete
101 // with SUCCESS
102 //
103
104 if((removeState == NO_REMOVE) ||
105 IS_CLEANUP_REQUEST(IoGetCurrentIrpStackLocation(Irp)->MajorFunction)) {
106
107 status = ClasspCreateClose(DeviceObject, Irp);
108
109 if((NT_SUCCESS(status)) &&
110 (commonExtension->DevInfo->ClassCreateClose)) {
111
112 return commonExtension->DevInfo->ClassCreateClose(DeviceObject, Irp);
113 }
114
115 } else {
116 status = STATUS_DEVICE_DOES_NOT_EXIST;
117 }
118
119 Irp->IoStatus.Status = status;
120 ClassReleaseRemoveLock(DeviceObject, Irp);
121 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
122 return status;
123 }
124
125 NTSTATUS
126 NTAPI
127 ClasspCreateClose(
128 IN PDEVICE_OBJECT DeviceObject,
129 IN PIRP Irp
130 )
131 /*++
132
133 Routine Description:
134
135 This routine will handle create/close operations for a given classpnp
136 device if the class driver doesn't supply it's own handler. If there
137 is a file object supplied for our driver (if it's a FO_DIRECT_DEVICE_OPEN
138 file object) then it will initialize a file extension on create or destroy
139 the extension on a close.
140
141 Arguments:
142
143 DeviceObject - the device object being opened or closed.
144
145 Irp - the create/close irp
146
147 Return Value:
148
149 status
150
151 --*/
152 {
153 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
154 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
155
156 PFILE_OBJECT fileObject = irpStack->FileObject;
157
158 NTSTATUS status = STATUS_SUCCESS;
159
160 PAGED_CODE();
161
162
163 //
164 // ISSUE-2000/3/28-henrygab - if lower stack fails create/close, we end up
165 // in an inconsistent state. re-write to verify all args and allocate all
166 // required resources, then pass the irp down, then complete the
167 // transaction. this is because we also cannot forward the irp, then fail
168 // it after it has succeeded a lower-level driver.
169 //
170
171 if(irpStack->MajorFunction == IRP_MJ_CREATE) {
172
173 PIO_SECURITY_CONTEXT securityContext =
174 irpStack->Parameters.Create.SecurityContext;
175 DebugPrint((2,
176 "ClasspCREATEClose: create received for device %p\n",
177 DeviceObject));
178 DebugPrint((2,
179 "ClasspCREATEClose: desired access %lx\n",
180 securityContext->DesiredAccess));
181 DebugPrint((2,
182 "ClasspCREATEClose: file object %lx\n",
183 irpStack->FileObject));
184
185 ASSERT(BreakOnClose == FALSE);
186
187 if(irpStack->FileObject != NULL) {
188
189 PFILE_OBJECT_EXTENSION fsContext;
190
191 //
192 // Allocate our own file object extension for this device object.
193 //
194
195 status = AllocateDictionaryEntry(
196 &commonExtension->FileObjectDictionary,
197 (ULONG_PTR)irpStack->FileObject,
198 sizeof(FILE_OBJECT_EXTENSION),
199 CLASS_TAG_FILE_OBJECT_EXTENSION,
200 (PVOID *)&fsContext);
201
202 if(NT_SUCCESS(status)) {
203
204 RtlZeroMemory(fsContext,
205 sizeof(FILE_OBJECT_EXTENSION));
206
207 fsContext->FileObject = irpStack->FileObject;
208 fsContext->DeviceObject = DeviceObject;
209 } else if (status == STATUS_OBJECT_NAME_COLLISION) {
210 status = STATUS_SUCCESS;
211 }
212 }
213
214 } else {
215
216 DebugPrint((2,
217 "ClasspCreateCLOSE: close received for device %p\n",
218 DeviceObject));
219 DebugPrint((2,
220 "ClasspCreateCLOSE: file object %p\n",
221 fileObject));
222
223 if(irpStack->FileObject != NULL) {
224
225 PFILE_OBJECT_EXTENSION fsContext =
226 ClasspGetFsContext(commonExtension, irpStack->FileObject);
227
228 DebugPrint((2,
229 "ClasspCreateCLOSE: file extension %p\n",
230 fsContext));
231
232 if(fsContext != NULL) {
233
234 DebugPrint((2,
235 "ClasspCreateCLOSE: extension is ours - "
236 "freeing\n"));
237 ASSERT(BreakOnClose == FALSE);
238
239 ClasspCleanupProtectedLocks(fsContext);
240
241 ClasspCleanupDisableMcn(fsContext);
242
243 FreeDictionaryEntry(&(commonExtension->FileObjectDictionary),
244 fsContext);
245 }
246 }
247 }
248
249 //
250 // Notify the lower levels about the create or close operation - give them
251 // a chance to cleanup too.
252 //
253
254 DebugPrint((2,
255 "ClasspCreateClose: %s for devobj %p\n",
256 (NT_SUCCESS(status) ? "Success" : "FAILED"),
257 DeviceObject));
258
259
260 if(NT_SUCCESS(status)) {
261
262 KEVENT event;
263
264 //
265 // Set up the event to wait on
266 //
267
268 KeInitializeEvent(&event, SynchronizationEvent, FALSE);
269
270 IoCopyCurrentIrpStackLocationToNext(Irp);
271 IoSetCompletionRoutine( Irp, ClassSignalCompletion, &event,
272 TRUE, TRUE, TRUE);
273
274 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
275
276 if(status == STATUS_PENDING) {
277 KeWaitForSingleObject(&event,
278 Executive,
279 KernelMode,
280 FALSE,
281 NULL);
282 status = Irp->IoStatus.Status;
283 }
284
285 if (!NT_SUCCESS(status)) {
286 DebugPrint((ClassDebugError,
287 "ClasspCreateClose: Lower driver failed, but we "
288 "succeeded. This is a problem, lock counts will be "
289 "out of sync between levels.\n"));
290 }
291
292 }
293
294
295 return status;
296 }
297
298 VOID
299 NTAPI
300 ClasspCleanupProtectedLocks(
301 IN PFILE_OBJECT_EXTENSION FsContext
302 )
303 {
304 PCOMMON_DEVICE_EXTENSION commonExtension =
305 FsContext->DeviceObject->DeviceExtension;
306
307 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension =
308 commonExtension->PartitionZeroExtension;
309
310 ULONG newDeviceLockCount = 1;
311
312 PAGED_CODE();
313
314 DebugPrint((2,
315 "ClasspCleanupProtectedLocks called for %p\n",
316 FsContext->DeviceObject));
317 DebugPrint((2,
318 "ClasspCleanupProtectedLocks - FsContext %p is locked "
319 "%d times\n", FsContext, FsContext->LockCount));
320
321 ASSERT(BreakOnClose == FALSE);
322
323 //
324 // Synchronize with ejection and ejection control requests.
325 //
326
327 KeEnterCriticalRegion();
328 KeWaitForSingleObject(&(fdoExtension->EjectSynchronizationEvent),
329 UserRequest,
330 UserMode,
331 FALSE,
332 NULL);
333
334 //
335 // For each secure lock on this handle decrement the secured lock count
336 // for the FDO. Keep track of the new value.
337 //
338
339 if(FsContext->LockCount != 0) {
340
341 do {
342
343 InterlockedDecrement((PLONG)&FsContext->LockCount);
344
345 newDeviceLockCount =
346 InterlockedDecrement(&fdoExtension->ProtectedLockCount);
347
348 } while(FsContext->LockCount != 0);
349
350 //
351 // If the new lock count has been dropped to zero then issue a lock
352 // command to the device.
353 //
354
355 DebugPrint((2,
356 "ClasspCleanupProtectedLocks: FDO secured lock count = %d "
357 "lock count = %d\n",
358 fdoExtension->ProtectedLockCount,
359 fdoExtension->LockCount));
360
361 if((newDeviceLockCount == 0) && (fdoExtension->LockCount == 0)) {
362
363 SCSI_REQUEST_BLOCK srb;
364 PCDB cdb;
365 NTSTATUS status;
366
367 DebugPrint((2,
368 "ClasspCleanupProtectedLocks: FDO lock count dropped "
369 "to zero\n"));
370
371 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
372 cdb = (PCDB) &(srb.Cdb);
373
374 srb.CdbLength = 6;
375
376 cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL;
377
378 //
379 // TRUE - prevent media removal.
380 // FALSE - allow media removal.
381 //
382
383 cdb->MEDIA_REMOVAL.Prevent = FALSE;
384
385 //
386 // Set timeout value.
387 //
388
389 srb.TimeOutValue = fdoExtension->TimeOutValue;
390 status = ClassSendSrbSynchronous(fdoExtension->DeviceObject,
391 &srb,
392 NULL,
393 0,
394 FALSE);
395
396 DebugPrint((2,
397 "ClasspCleanupProtectedLocks: unlock request to drive "
398 "returned status %lx\n", status));
399 }
400 }
401
402 KeSetEvent(&fdoExtension->EjectSynchronizationEvent,
403 IO_NO_INCREMENT,
404 FALSE);
405 KeLeaveCriticalRegion();
406 return;
407 }
408
409 VOID
410 NTAPI
411 ClasspCleanupDisableMcn(
412 IN PFILE_OBJECT_EXTENSION FsContext
413 )
414 {
415 PCOMMON_DEVICE_EXTENSION commonExtension =
416 FsContext->DeviceObject->DeviceExtension;
417
418 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension =
419 commonExtension->PartitionZeroExtension;
420
421 PAGED_CODE();
422
423 DebugPrint((ClassDebugTrace,
424 "ClasspCleanupDisableMcn called for %p\n",
425 FsContext->DeviceObject));
426 DebugPrint((ClassDebugTrace,
427 "ClasspCleanupDisableMcn - FsContext %p is disabled "
428 "%d times\n", FsContext, FsContext->McnDisableCount));
429
430 //
431 // For each secure lock on this handle decrement the secured lock count
432 // for the FDO. Keep track of the new value.
433 //
434
435 while(FsContext->McnDisableCount != 0) {
436 FsContext->McnDisableCount--;
437 ClassEnableMediaChangeDetection(fdoExtension);
438 }
439
440 return;
441 }
442
443 #if 1
444 /*
445 * BUGBUG REMOVE this old function implementation as soon as the
446 * boottime pagefile problems with the new one (below)
447 * are resolved.
448 */
449 NTSTATUS
450 NTAPI
451 ClasspEjectionControl(
452 IN PDEVICE_OBJECT Fdo,
453 IN PIRP Irp,
454 IN MEDIA_LOCK_TYPE LockType,
455 IN BOOLEAN Lock
456 )
457 {
458 PFUNCTIONAL_DEVICE_EXTENSION FdoExtension = Fdo->DeviceExtension;
459 PCOMMON_DEVICE_EXTENSION commonExtension =
460 (PCOMMON_DEVICE_EXTENSION) FdoExtension;
461
462 PFILE_OBJECT_EXTENSION fsContext = NULL;
463 NTSTATUS status;
464 volatile PSCSI_REQUEST_BLOCK srb = NULL;
465 BOOLEAN countChanged = FALSE;
466
467 PAGED_CODE();
468
469 //
470 // Interlock with ejection and secure lock cleanup code. This is a
471 // user request so we can allow the stack to get swapped out while we
472 // wait for synchronization.
473 //
474
475 status = KeWaitForSingleObject(
476 &(FdoExtension->EjectSynchronizationEvent),
477 UserRequest,
478 UserMode,
479 FALSE,
480 NULL);
481
482 ASSERT(status == STATUS_SUCCESS);
483
484 DebugPrint((2,
485 "ClasspEjectionControl: "
486 "Received request for %s lock type\n",
487 LockTypeStrings[LockType]
488 ));
489
490 _SEH2_TRY {
491 PCDB cdb;
492
493 srb = ClasspAllocateSrb(FdoExtension);
494
495 if(srb == NULL) {
496 status = STATUS_INSUFFICIENT_RESOURCES;
497 _SEH2_LEAVE;
498 }
499
500 RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
501
502 cdb = (PCDB) srb->Cdb;
503
504 //
505 // Determine if this is a "secured" request.
506 //
507
508 if(LockType == SecureMediaLock) {
509
510 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
511 PFILE_OBJECT fileObject = irpStack->FileObject;
512
513 //
514 // Make sure that the file object we are supplied has a
515 // proper FsContext before we try doing a secured lock.
516 //
517
518 if(fileObject != NULL) {
519 fsContext = ClasspGetFsContext(commonExtension, fileObject);
520 }
521
522 if (fsContext == NULL) {
523
524 //
525 // This handle isn't setup correctly. We can't let the
526 // operation go.
527 //
528
529 status = STATUS_INVALID_PARAMETER;
530 _SEH2_LEAVE;
531 }
532 }
533
534 if(Lock) {
535
536 //
537 // This is a lock command. Reissue the command in case bus or
538 // device was reset and the lock was cleared.
539 // note: may need to decrement count if actual lock operation
540 // failed....
541 //
542
543 switch(LockType) {
544
545 case SimpleMediaLock: {
546 FdoExtension->LockCount++;
547 countChanged = TRUE;
548 break;
549 }
550
551 case SecureMediaLock: {
552 fsContext->LockCount++;
553 FdoExtension->ProtectedLockCount++;
554 countChanged = TRUE;
555 break;
556 }
557
558 case InternalMediaLock: {
559 FdoExtension->InternalLockCount++;
560 countChanged = TRUE;
561 break;
562 }
563 }
564
565 } else {
566
567 //
568 // This is an unlock command. If it's a secured one then make sure
569 // the caller has a lock outstanding or return an error.
570 // note: may need to re-increment the count if actual unlock
571 // operation fails....
572 //
573
574 switch(LockType) {
575
576 case SimpleMediaLock: {
577 if(FdoExtension->LockCount != 0) {
578 FdoExtension->LockCount--;
579 countChanged = TRUE;
580 }
581 break;
582 }
583
584 case SecureMediaLock: {
585 if(fsContext->LockCount == 0) {
586 status = STATUS_INVALID_DEVICE_STATE;
587 _SEH2_LEAVE;
588 }
589 fsContext->LockCount--;
590 FdoExtension->ProtectedLockCount--;
591 countChanged = TRUE;
592 break;
593 }
594
595 case InternalMediaLock: {
596 ASSERT(FdoExtension->InternalLockCount != 0);
597 FdoExtension->InternalLockCount--;
598 countChanged = TRUE;
599 break;
600 }
601 }
602
603 //
604 // We only send an unlock command to the drive if both the
605 // secured and unsecured lock counts have dropped to zero.
606 //
607
608 if((FdoExtension->ProtectedLockCount != 0) ||
609 (FdoExtension->InternalLockCount != 0) ||
610 (FdoExtension->LockCount != 0)) {
611
612 status = STATUS_SUCCESS;
613 _SEH2_LEAVE;
614 }
615 }
616
617 status = STATUS_SUCCESS;
618 if (TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) {
619
620 srb->CdbLength = 6;
621 cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL;
622
623 //
624 // TRUE - prevent media removal.
625 // FALSE - allow media removal.
626 //
627
628 cdb->MEDIA_REMOVAL.Prevent = Lock;
629
630 //
631 // Set timeout value.
632 //
633
634 srb->TimeOutValue = FdoExtension->TimeOutValue;
635
636 //
637 // The actual lock operation on the device isn't so important
638 // as the internal lock counts. Ignore failures.
639 //
640
641 status = ClassSendSrbSynchronous(FdoExtension->DeviceObject,
642 srb,
643 NULL,
644 0,
645 FALSE);
646 }
647
648 } _SEH2_FINALLY {
649
650 if (!NT_SUCCESS(status)) {
651 DebugPrint((2,
652 "ClasspEjectionControl: FAILED status %x -- "
653 "reverting lock counts\n", status));
654
655 if (countChanged) {
656
657 //
658 // have to revert to previous counts if the
659 // lock/unlock operation actually failed.
660 //
661
662 if(Lock) {
663
664 switch(LockType) {
665
666 case SimpleMediaLock: {
667 FdoExtension->LockCount--;
668 break;
669 }
670
671 case SecureMediaLock: {
672 fsContext->LockCount--;
673 FdoExtension->ProtectedLockCount--;
674 break;
675 }
676
677 case InternalMediaLock: {
678 FdoExtension->InternalLockCount--;
679 break;
680 }
681 }
682
683 } else {
684
685 switch(LockType) {
686
687 case SimpleMediaLock: {
688 FdoExtension->LockCount++;
689 break;
690 }
691
692 case SecureMediaLock: {
693 fsContext->LockCount++;
694 FdoExtension->ProtectedLockCount++;
695 break;
696 }
697
698 case InternalMediaLock: {
699 FdoExtension->InternalLockCount++;
700 break;
701 }
702 }
703 }
704
705 }
706
707 } else {
708
709 DebugPrint((2,
710 "ClasspEjectionControl: Succeeded\n"));
711
712 }
713
714 DebugPrint((2,
715 "ClasspEjectionControl: "
716 "Current Counts: Internal: %x Secure: %x Simple: %x\n",
717 FdoExtension->InternalLockCount,
718 FdoExtension->ProtectedLockCount,
719 FdoExtension->LockCount
720 ));
721
722 KeSetEvent(&(FdoExtension->EjectSynchronizationEvent),
723 IO_NO_INCREMENT,
724 FALSE);
725 if (srb) {
726 ClassFreeOrReuseSrb(FdoExtension, srb);
727 }
728
729 } _SEH2_END;
730 return status;
731 }
732
733 #else
734
735 /*
736 * BUGBUG RESTORE
737 * This is a new implementation of the function that doesn't thrash memory
738 * or depend on the srbLookasideList.
739 * HOWEVER, it seems to cause pagefile initialization to fail during boot
740 * for some reason. Need to resolve this before switching to this function.
741 */
742 NTSTATUS
743 NTAPI
744 ClasspEjectionControl(
745 IN PDEVICE_OBJECT Fdo,
746 IN PIRP Irp,
747 IN MEDIA_LOCK_TYPE LockType,
748 IN BOOLEAN Lock
749 )
750 {
751 PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension;
752 PFILE_OBJECT_EXTENSION fsContext;
753 BOOLEAN fileHandleOk = TRUE;
754 BOOLEAN countChanged = FALSE;
755 NTSTATUS status;
756
757 PAGED_CODE();
758
759 status = KeWaitForSingleObject(
760 &fdoExt->EjectSynchronizationEvent,
761 UserRequest,
762 UserMode,
763 FALSE,
764 NULL);
765 ASSERT(status == STATUS_SUCCESS);
766
767 /*
768 * If this is a "secured" request, we have to make sure
769 * that the file handle is valid.
770 */
771 if (LockType == SecureMediaLock){
772 PIO_STACK_LOCATION thisSp = IoGetCurrentIrpStackLocation(Irp);
773
774 /*
775 * Make sure that the file object we are supplied has a
776 * proper FsContext before we try doing a secured lock.
777 */
778 if (thisSp->FileObject){
779 PCOMMON_DEVICE_EXTENSION commonExt = (PCOMMON_DEVICE_EXTENSION)fdoExt;
780 fsContext = ClasspGetFsContext(commonExt, thisSp->FileObject);
781 }
782 else {
783 fsContext = NULL;
784 }
785
786 if (!fsContext){
787 ASSERT(fsContext);
788 fileHandleOk = FALSE;
789 }
790 }
791
792 if (fileHandleOk){
793
794 /*
795 * Adjust the lock counts and make sure they make sense.
796 */
797 status = STATUS_SUCCESS;
798 if (Lock){
799 switch(LockType) {
800 case SimpleMediaLock:
801 fdoExt->LockCount++;
802 countChanged = TRUE;
803 break;
804 case SecureMediaLock:
805 fsContext->LockCount++;
806 fdoExt->ProtectedLockCount++;
807 countChanged = TRUE;
808 break;
809 case InternalMediaLock:
810 fdoExt->InternalLockCount++;
811 countChanged = TRUE;
812 break;
813 }
814 }
815 else {
816 /*
817 * This is an unlock command. If it's a secured one then make sure
818 * the caller has a lock outstanding or return an error.
819 */
820 switch (LockType){
821 case SimpleMediaLock:
822 if (fdoExt->LockCount > 0){
823 fdoExt->LockCount--;
824 countChanged = TRUE;
825 }
826 else {
827 ASSERT(fdoExt->LockCount > 0);
828 status = STATUS_INTERNAL_ERROR;
829 }
830 break;
831 case SecureMediaLock:
832 if (fsContext->LockCount > 0){
833 ASSERT(fdoExt->ProtectedLockCount > 0);
834 fsContext->LockCount--;
835 fdoExt->ProtectedLockCount--;
836 countChanged = TRUE;
837 }
838 else {
839 ASSERT(fsContext->LockCount > 0);
840 status = STATUS_INVALID_DEVICE_STATE;
841 }
842 break;
843 case InternalMediaLock:
844 ASSERT(fdoExt->InternalLockCount > 0);
845 fdoExt->InternalLockCount--;
846 countChanged = TRUE;
847 break;
848 }
849 }
850
851 if (NT_SUCCESS(status)){
852 /*
853 * We only send an unlock command to the drive if
854 * all the lock counts have dropped to zero.
855 */
856 if (!Lock &&
857 (fdoExt->ProtectedLockCount ||
858 fdoExt->InternalLockCount ||
859 fdoExt->LockCount)){
860
861 /*
862 * The lock count is still positive, so don't unlock yet.
863 */
864 status = STATUS_SUCCESS;
865 }
866 else if (!TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) {
867 /*
868 * The device isn't removable media. don't send a cmd.
869 */
870 status = STATUS_SUCCESS;
871 }
872 else {
873 TRANSFER_PACKET *pkt;
874
875 pkt = DequeueFreeTransferPacket(Fdo, TRUE);
876 if (pkt){
877 KEVENT event;
878
879 /*
880 * Store the number of packets servicing the irp (one)
881 * inside the original IRP. It will be used to counted down
882 * to zero when the packet completes.
883 * Initialize the original IRP's status to success.
884 * If the packet fails, we will set it to the error status.
885 */
886 Irp->Tail.Overlay.DriverContext[0] = LongToPtr(1);
887 Irp->IoStatus.Status = STATUS_SUCCESS;
888
889 /*
890 * Set this up as a SYNCHRONOUS transfer, submit it,
891 * and wait for the packet to complete. The result
892 * status will be written to the original irp.
893 */
894 KeInitializeEvent(&event, SynchronizationEvent, FALSE);
895 SetupEjectionTransferPacket(pkt, Lock, &event, Irp);
896 SubmitTransferPacket(pkt);
897 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
898 status = Irp->IoStatus.Status;
899 }
900 else {
901 status = STATUS_INSUFFICIENT_RESOURCES;
902 }
903 }
904 }
905 }
906 else {
907 status = STATUS_INVALID_PARAMETER;
908 }
909
910 if (!NT_SUCCESS(status) && countChanged) {
911
912 //
913 // have to revert to previous counts if the
914 // lock/unlock operation actually failed.
915 //
916
917 if(Lock) {
918
919 switch(LockType) {
920
921 case SimpleMediaLock: {
922 FdoExtension->LockCount--;
923 break;
924 }
925
926 case SecureMediaLock: {
927 fsContext->LockCount--;
928 FdoExtension->ProtectedLockCount--;
929 break;
930 }
931
932 case InternalMediaLock: {
933 FdoExtension->InternalLockCount--;
934 break;
935 }
936 }
937
938 } else {
939
940 switch(LockType) {
941
942 case SimpleMediaLock: {
943 FdoExtension->LockCount++;
944 break;
945 }
946
947 case SecureMediaLock: {
948 fsContext->LockCount++;
949 FdoExtension->ProtectedLockCount++;
950 break;
951 }
952
953 case InternalMediaLock: {
954 FdoExtension->InternalLockCount++;
955 break;
956 }
957 }
958 }
959 }
960
961
962
963 KeSetEvent(&fdoExt->EjectSynchronizationEvent, IO_NO_INCREMENT, FALSE);
964
965 return status;
966 }
967 #endif
968
969 PFILE_OBJECT_EXTENSION
970 NTAPI
971 ClasspGetFsContext(
972 IN PCOMMON_DEVICE_EXTENSION CommonExtension,
973 IN PFILE_OBJECT FileObject
974 )
975 {
976 PAGED_CODE();
977 return GetDictionaryEntry(&(CommonExtension->FileObjectDictionary),
978 (ULONG_PTR)FileObject);
979 }