2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: drivers/ksfilter/ks/allocators.c
5 * PURPOSE: KS Allocator functions
6 * PROGRAMMER: Johannes Anderwald
14 ALLOCATOR_NPAGED_LOOKASIDE
,
15 ALLOCATOR_PAGED_LOOKASIDE
,
21 ALLOCATOR_DEVICE_CONTROL
,
22 ALLOCATOR_DEVICE_CLOSE
,
28 typedef PVOID (*PFNKSPAGEDPOOLALLOCATE
)(IN PPAGED_LOOKASIDE_LIST Lookaside
);
29 typedef PVOID (*PFNKSNPAGEDPOOLALLOCATE
)(IN PNPAGED_LOOKASIDE_LIST Lookaside
);
31 typedef VOID (*PFNKSPAGEDPOOLFREE
)(IN PPAGED_LOOKASIDE_LIST Lookaside
, IN PVOID Entry
);
32 typedef VOID (*PFNKSNPAGEDPOOLFREE
)(IN PNPAGED_LOOKASIDE_LIST Lookaside
, IN PVOID Entry
);
34 typedef VOID (NTAPI
*PFNKSNPAGEDPOOLDELETE
)(IN PNPAGED_LOOKASIDE_LIST Lookaside
);
35 typedef VOID (NTAPI
*PFNKSPAGEDPOOLDELETE
)(IN PPAGED_LOOKASIDE_LIST Lookaside
);
39 IKsAllocatorVtbl
*lpVtbl
;
41 PKSIOBJECT_HEADER Header
;
44 KSSTREAMALLOCATOR_STATUS Status
;
48 NPAGED_LOOKASIDE_LIST NPagedList
;
49 PAGED_LOOKASIDE_LIST PagedList
;
55 PFNKSDEFAULTALLOCATE DefaultAllocate
;
56 PFNKSPAGEDPOOLALLOCATE PagedPool
;
57 PFNKSNPAGEDPOOLALLOCATE NPagedPool
;
62 PFNKSDEFAULTFREE DefaultFree
;
63 PFNKSPAGEDPOOLFREE PagedPool
;
64 PFNKSNPAGEDPOOLFREE NPagedPool
;
69 PFNKSDELETEALLOCATOR DefaultDelete
;
70 PFNKSNPAGEDPOOLDELETE NPagedPool
;
71 PFNKSPAGEDPOOLDELETE PagedPool
;
74 }ALLOCATOR
, *PALLOCATOR
;
76 /* use KSNAME_Allocator for IID_IKsAllocator */
77 const GUID IID_IKsAllocator
= {0x642F5D00L
, 0x4791, 0x11D0, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
78 const GUID KSPROPSETID_StreamAllocator
= {0x0cf6e4342, 0xec87, 0x11cf, {0xa1, 0x30, 0x00, 0x20, 0xaf, 0xd1, 0x56, 0xe4}};
83 IKsAllocator_Allocate(
84 IN PFILE_OBJECT FileObject
,
89 IKsAllocator_FreeFrame(
90 IN PFILE_OBJECT FileObject
,
96 IKsAllocator_fnQueryInterface(
101 PALLOCATOR This
= (PALLOCATOR
)CONTAINING_RECORD(iface
, ALLOCATOR
, lpVtbl
);
103 if (IsEqualGUIDAligned(refiid
, &IID_IUnknown
) ||
104 IsEqualGUIDAligned(refiid
, &IID_IKsAllocator
))
106 *Output
= &This
->lpVtbl
;
107 _InterlockedIncrement(&This
->ref
);
108 return STATUS_SUCCESS
;
110 return STATUS_UNSUCCESSFUL
;
115 IKsAllocator_fnAddRef(
116 IKsAllocator
* iface
)
118 PALLOCATOR This
= (PALLOCATOR
)CONTAINING_RECORD(iface
, ALLOCATOR
, lpVtbl
);
120 return InterlockedIncrement(&This
->ref
);
125 IKsAllocator_fnRelease(
126 IKsAllocator
* iface
)
128 PALLOCATOR This
= (PALLOCATOR
)CONTAINING_RECORD(iface
, ALLOCATOR
, lpVtbl
);
130 InterlockedDecrement(&This
->ref
);
137 /* Return new reference count */
143 IKsAllocator_fnDeviceIoControl(
145 IN PDEVICE_OBJECT DeviceObject
,
148 PALLOCATOR This
= (PALLOCATOR
)CONTAINING_RECORD(iface
, ALLOCATOR
, lpVtbl
);
149 PIO_STACK_LOCATION IoStack
;
150 PKSSTREAMALLOCATOR_FUNCTIONTABLE FunctionTable
;
151 PKSSTREAMALLOCATOR_STATUS State
;
152 PKSPROPERTY Property
;
156 /* get current irp stack */
157 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
159 if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
!= IOCTL_KS_PROPERTY
)
161 /* only KSPROPERTY requests are supported */
164 /* complete and forget irps */
165 Irp
->IoStatus
.Status
= STATUS_NOT_IMPLEMENTED
;
166 CompleteRequest(Irp
, IO_NO_INCREMENT
);
168 return STATUS_NOT_IMPLEMENTED
;
171 if (IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(KSPROPERTY
))
173 /* invalid request */
174 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
175 CompleteRequest(Irp
, IO_NO_INCREMENT
);
177 return STATUS_INVALID_DEVICE_REQUEST
;
180 /* check the request */
181 Property
= (PKSPROPERTY
)IoStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
183 if (IsEqualGUIDAligned(&Property
->Set
, &KSPROPSETID_StreamAllocator
))
185 if (Property
->Id
== KSPROPERTY_STREAMALLOCATOR_FUNCTIONTABLE
)
187 if (IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(KSSTREAMALLOCATOR_FUNCTIONTABLE
))
189 /* buffer too small */
190 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
191 Irp
->IoStatus
.Information
= sizeof(KSSTREAMALLOCATOR_FUNCTIONTABLE
);
192 /* complete and forget irp */
193 CompleteRequest(Irp
, IO_NO_INCREMENT
);
194 return STATUS_BUFFER_TOO_SMALL
;
196 if (!(Property
->Flags
& KSPROPERTY_TYPE_GET
))
198 /* only support retrieving the property */
199 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
200 /* complete and forget irp */
201 CompleteRequest(Irp
, IO_NO_INCREMENT
);
202 return STATUS_UNSUCCESSFUL
;
205 /* get output buffer */
206 FunctionTable
= (PKSSTREAMALLOCATOR_FUNCTIONTABLE
)Irp
->UserBuffer
;
208 FunctionTable
->AllocateFrame
= IKsAllocator_Allocate
;
209 FunctionTable
->FreeFrame
= IKsAllocator_FreeFrame
;
212 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
213 Irp
->IoStatus
.Information
= sizeof(KSSTREAMALLOCATOR_FUNCTIONTABLE
);
214 /* complete request */
215 CompleteRequest(Irp
, IO_NO_INCREMENT
);
216 return STATUS_SUCCESS
;
218 else if (Property
->Id
== KSPROPERTY_STREAMALLOCATOR_STATUS
)
220 if (IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(KSPROPERTY_STREAMALLOCATOR_STATUS
))
222 /* buffer too small */
223 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
224 Irp
->IoStatus
.Information
= sizeof(KSPROPERTY_STREAMALLOCATOR_STATUS
);
225 /* complete and forget irp */
226 CompleteRequest(Irp
, IO_NO_INCREMENT
);
227 return STATUS_BUFFER_TOO_SMALL
;
229 if (!(Property
->Flags
& KSPROPERTY_TYPE_GET
))
231 /* only support retrieving the property */
232 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
233 /* complete and forget irp */
234 CompleteRequest(Irp
, IO_NO_INCREMENT
);
235 return STATUS_UNSUCCESSFUL
;
238 /* get output buffer */
239 State
= (PKSSTREAMALLOCATOR_STATUS
)Irp
->UserBuffer
;
241 /* copy allocator status */
242 RtlMoveMemory(State
, &This
->Status
, sizeof(KSSTREAMALLOCATOR_STATUS
));
245 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
246 Irp
->IoStatus
.Information
= sizeof(KSSTREAMALLOCATOR_STATUS
);
248 /* complete request */
249 CompleteRequest(Irp
, IO_NO_INCREMENT
);
250 return STATUS_SUCCESS
;
254 /* unhandled request */
255 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
256 CompleteRequest(Irp
, IO_NO_INCREMENT
);
258 return STATUS_NOT_SUPPORTED
;
263 IKsAllocator_fnClose(
266 PALLOCATOR This
= (PALLOCATOR
)CONTAINING_RECORD(iface
, ALLOCATOR
, lpVtbl
);
270 /* now close allocator */
271 if (This
->Type
== ALLOCATOR_CUSTOM
)
273 This
->Delete
.DefaultDelete(This
->u
.CustomList
);
275 else if (This
->Type
== ALLOCATOR_NPAGED_LOOKASIDE
)
277 This
->Delete
.NPagedPool(&This
->u
.NPagedList
);
279 else if (This
->Type
== ALLOCATOR_PAGED_LOOKASIDE
)
281 This
->Delete
.PagedPool(&This
->u
.PagedList
);
284 /* free object header */
285 KsFreeObjectHeader(&This
->Header
);
287 return STATUS_SUCCESS
;
292 IKsAllocator_fnAllocateFrame(
297 PALLOCATOR This
= (PALLOCATOR
)CONTAINING_RECORD(iface
, ALLOCATOR
, lpVtbl
);
301 /* now allocate frame */
302 if (This
->Type
== ALLOCATOR_CUSTOM
)
304 Frame
= This
->Allocate
.DefaultAllocate(This
->u
.CustomList
);
306 else if (This
->Type
== ALLOCATOR_NPAGED_LOOKASIDE
)
308 Frame
= This
->Allocate
.NPagedPool(&This
->u
.NPagedList
);
310 else if (This
->Type
== ALLOCATOR_PAGED_LOOKASIDE
)
312 Frame
= This
->Allocate
.PagedPool(&This
->u
.PagedList
);
318 InterlockedIncrement((PLONG
)&This
->Status
.AllocatedFrames
);
319 return STATUS_SUCCESS
;
322 return STATUS_UNSUCCESSFUL
;
327 IKsAllocator_fnFreeFrame(
331 PALLOCATOR This
= (PALLOCATOR
)CONTAINING_RECORD(iface
, ALLOCATOR
, lpVtbl
);
333 /* now allocate frame */
334 if (This
->Type
== ALLOCATOR_CUSTOM
)
336 This
->Free
.DefaultFree(This
->u
.CustomList
, Frame
);
338 else if (This
->Type
== ALLOCATOR_NPAGED_LOOKASIDE
)
340 This
->Free
.NPagedPool(&This
->u
.NPagedList
, Frame
);
342 else if (This
->Type
== ALLOCATOR_PAGED_LOOKASIDE
)
344 This
->Free
.PagedPool(&This
->u
.PagedList
, Frame
);
349 static IKsAllocatorVtbl vt_IKsAllocator
=
351 IKsAllocator_fnQueryInterface
,
352 IKsAllocator_fnAddRef
,
353 IKsAllocator_fnRelease
,
354 IKsAllocator_fnDeviceIoControl
,
355 IKsAllocator_fnClose
,
356 IKsAllocator_fnAllocateFrame
,
357 IKsAllocator_fnFreeFrame
364 KSDDKAPI NTSTATUS NTAPI
366 IN HANDLE ConnectionHandle
,
367 IN PKSALLOCATOR_FRAMING AllocatorFraming
,
368 OUT PHANDLE AllocatorHandle
)
370 return KspCreateObjectType(ConnectionHandle
,
372 (PVOID
)AllocatorFraming
,
373 sizeof(KSALLOCATOR_FRAMING
),
381 KSDDKAPI NTSTATUS NTAPI
382 KsCreateDefaultAllocator(
385 return KsCreateDefaultAllocatorEx(Irp
, NULL
, NULL
, NULL
, NULL
, NULL
);
394 KsValidateAllocatorCreateRequest(
396 OUT PKSALLOCATOR_FRAMING
* OutAllocatorFraming
)
398 PKSALLOCATOR_FRAMING AllocatorFraming
;
401 ULONG SupportedFlags
;
403 /* set minimum request size */
404 Size
= sizeof(KSALLOCATOR_FRAMING
);
406 Status
= KspCopyCreateRequest(Irp
,
409 (PVOID
*)&AllocatorFraming
);
411 if (!NT_SUCCESS(Status
))
414 /* allowed supported flags */
415 SupportedFlags
= (KSALLOCATOR_OPTIONF_COMPATIBLE
| KSALLOCATOR_OPTIONF_SYSTEM_MEMORY
|
416 KSALLOCATOR_REQUIREMENTF_INPLACE_MODIFIER
| KSALLOCATOR_REQUIREMENTF_SYSTEM_MEMORY
| KSALLOCATOR_REQUIREMENTF_FRAME_INTEGRITY
|
417 KSALLOCATOR_REQUIREMENTF_MUST_ALLOCATE
);
420 if (!AllocatorFraming
->FrameSize
|| (AllocatorFraming
->OptionsFlags
& (~SupportedFlags
)))
422 FreeItem(AllocatorFraming
);
423 return STATUS_INVALID_PARAMETER
;
427 *OutAllocatorFraming
= AllocatorFraming
;
433 IKsAllocator_DispatchRequest(
434 IN PDEVICE_OBJECT DeviceObject
,
435 IN PFILE_OBJECT FileObject
,
438 IN ALLOC_REQUEST Request
)
440 PKSIOBJECT_HEADER Header
;
442 IKsAllocator
* Allocator
;
447 /* get object header */
448 Header
= (PKSIOBJECT_HEADER
)FileObject
->FsContext2
;
450 /* get real allocator */
451 Status
= Header
->Unknown
->lpVtbl
->QueryInterface(Header
->Unknown
, &IID_IKsAllocator
, (PVOID
*)&Allocator
);
453 if (!NT_SUCCESS(Status
))
455 /* misbehaving object */
456 return STATUS_UNSUCCESSFUL
;
459 if (Request
== ALLOCATOR_DEVICE_CONTROL
)
461 /* dispatch request allocator */
462 Status
= Allocator
->lpVtbl
->DispatchDeviceIoControl(Allocator
, DeviceObject
, Irp
);
464 else if (Request
== ALLOCATOR_DEVICE_CLOSE
)
466 /* delete allocator */
467 Status
= Allocator
->lpVtbl
->Close(Allocator
);
469 else if (Request
== ALLOCATOR_ALLOCATE
)
472 Status
= Allocator
->lpVtbl
->AllocateFrame(Allocator
, (PVOID
*)Frame
);
474 }else if (Request
== ALLOCATOR_FREE
)
477 Allocator
->lpVtbl
->FreeFrame(Allocator
, Frame
);
478 Status
= STATUS_SUCCESS
;
481 /* release interface */
482 Allocator
->lpVtbl
->Release(Allocator
);
489 IKsAllocator_DispatchDeviceIoControl(
490 IN PDEVICE_OBJECT DeviceObject
,
493 PIO_STACK_LOCATION IoStack
;
496 /* get current irp stack */
497 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
499 /* dispatch request */
500 Status
= IKsAllocator_DispatchRequest(DeviceObject
, IoStack
->FileObject
, Irp
, NULL
, ALLOCATOR_DEVICE_CONTROL
);
502 /* complete request */
503 Irp
->IoStatus
.Status
= Status
;
504 CompleteRequest(Irp
, IO_NO_INCREMENT
);
511 IKsAllocator_DispatchClose(
512 IN PDEVICE_OBJECT DeviceObject
,
515 PIO_STACK_LOCATION IoStack
;
518 /* get current irp stack */
519 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
521 /* dispatch request */
522 Status
= IKsAllocator_DispatchRequest(DeviceObject
, IoStack
->FileObject
, Irp
, NULL
, ALLOCATOR_DEVICE_CLOSE
);
524 /* complete request */
525 Irp
->IoStatus
.Status
= Status
;
526 CompleteRequest(Irp
, IO_NO_INCREMENT
);
533 IKsAllocator_Allocate(
534 IN PFILE_OBJECT FileObject
,
539 /* dispatch request */
540 Status
= IKsAllocator_DispatchRequest(NULL
, FileObject
, NULL
, (PVOID
)Frame
, ALLOCATOR_ALLOCATE
);
547 IKsAllocator_FreeFrame(
548 IN PFILE_OBJECT FileObject
,
551 /* dispatch request */
552 IKsAllocator_DispatchRequest(NULL
, FileObject
, NULL
, Frame
, ALLOCATOR_FREE
);
556 static KSDISPATCH_TABLE DispatchTable
=
558 IKsAllocator_DispatchDeviceIoControl
,
559 KsDispatchInvalidDeviceRequest
,
560 KsDispatchInvalidDeviceRequest
,
561 KsDispatchInvalidDeviceRequest
,
562 IKsAllocator_DispatchClose
,
563 KsDispatchQuerySecurity
,
564 KsDispatchSetSecurity
,
565 KsDispatchFastIoDeviceControlFailure
,
566 KsDispatchFastReadFailure
,
567 KsDispatchFastReadFailure
,
573 KSDDKAPI NTSTATUS NTAPI
574 KsCreateDefaultAllocatorEx(
576 IN PVOID InitializeContext OPTIONAL
,
577 IN PFNKSDEFAULTALLOCATE DefaultAllocate OPTIONAL
,
578 IN PFNKSDEFAULTFREE DefaultFree OPTIONAL
,
579 IN PFNKSINITIALIZEALLOCATOR InitializeAllocator OPTIONAL
,
580 IN PFNKSDELETEALLOCATOR DeleteAllocator OPTIONAL
)
583 PKSALLOCATOR_FRAMING AllocatorFraming
;
584 PALLOCATOR Allocator
;
587 /* first validate connect request */
588 Status
= KsValidateAllocatorCreateRequest(Irp
, &AllocatorFraming
);
589 if (!NT_SUCCESS(Status
))
590 return STATUS_INVALID_PARAMETER
;
592 /* check the valid file alignment */
593 if (AllocatorFraming
->FileAlignment
> (PAGE_SIZE
-1))
594 return STATUS_INVALID_PARAMETER
;
596 /* allocate allocator struct */
597 Allocator
= AllocateItem(NonPagedPool
, sizeof(ALLOCATOR
));
599 return STATUS_INSUFFICIENT_RESOURCES
;
601 /* allocate object header */
603 Status
= KsAllocateObjectHeader((KSOBJECT_HEADER
*)&Allocator
->Header
, 0, NULL
, Irp
, &DispatchTable
);
604 if (!NT_SUCCESS(Status
))
610 /* set allocator type in object header */
611 Allocator
->lpVtbl
= &vt_IKsAllocator
;
612 Allocator
->Header
->Unknown
= (PUNKNOWN
)&Allocator
->lpVtbl
;
617 /* use external allocator */
618 Allocator
->Type
= ALLOCATOR_CUSTOM
;
619 Allocator
->Allocate
.DefaultAllocate
= DefaultAllocate
;
620 Allocator
->Free
.DefaultFree
= DefaultFree
;
621 Allocator
->Delete
.DefaultDelete
= DeleteAllocator
;
622 Ctx
= InitializeAllocator(InitializeContext
, AllocatorFraming
, &Allocator
->u
.CustomList
);
623 /* check for success */
626 KsFreeObjectHeader(Allocator
->Header
);
631 else if (AllocatorFraming
->PoolType
== NonPagedPool
)
633 /* use non-paged pool allocator */
634 Allocator
->Type
= ALLOCATOR_NPAGED_LOOKASIDE
;
635 Allocator
->Allocate
.NPagedPool
= ExAllocateFromNPagedLookasideList
;
636 Allocator
->Free
.NPagedPool
= ExFreeToNPagedLookasideList
;
637 Allocator
->Delete
.NPagedPool
= ExDeleteNPagedLookasideList
;
638 ExInitializeNPagedLookasideList(&Allocator
->u
.NPagedList
, NULL
, NULL
, 0, AllocatorFraming
->FrameSize
, 0, 0);
640 else if (AllocatorFraming
->PoolType
== PagedPool
)
642 /* use paged pool allocator */
643 Allocator
->Allocate
.PagedPool
= ExAllocateFromPagedLookasideList
;
644 Allocator
->Free
.PagedPool
= ExFreeToPagedLookasideList
;
645 Allocator
->Delete
.PagedPool
= ExDeletePagedLookasideList
;
646 Allocator
->Type
= ALLOCATOR_PAGED_LOOKASIDE
;
647 ExInitializePagedLookasideList(&Allocator
->u
.PagedList
, NULL
, NULL
, 0, AllocatorFraming
->FrameSize
, 0, 0);
651 /* backup allocator framing */
652 RtlMoveMemory(&Allocator
->Status
.Framing
, AllocatorFraming
, sizeof(KSALLOCATOR_FRAMING
));
660 KSDDKAPI NTSTATUS NTAPI
661 KsValidateAllocatorFramingEx(
662 IN PKSALLOCATOR_FRAMING_EX Framing
,
664 IN
const KSALLOCATOR_FRAMING_EX
* PinFraming
)
666 if (BufferSize
< sizeof(KSALLOCATOR_FRAMING_EX
))
667 return STATUS_INVALID_DEVICE_REQUEST
;
670 if ((Framing
->FramingItem
[0].Flags
& KSALLOCATOR_FLAG_PARTIAL_READ_SUPPORT
) &&
671 Framing
->OutputCompression
.RatioNumerator
!= MAXULONG
&&
672 Framing
->OutputCompression
.RatioDenominator
!= 0 &&
673 Framing
->OutputCompression
.RatioDenominator
< Framing
->OutputCompression
.RatioNumerator
)
675 /* framing request is ok */
676 return STATUS_SUCCESS
;
679 return STATUS_INVALID_DEVICE_REQUEST
;