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
16 ALLOCATOR_NPAGED_LOOKASIDE
,
17 ALLOCATOR_PAGED_LOOKASIDE
,
23 ALLOCATOR_DEVICE_CONTROL
,
24 ALLOCATOR_DEVICE_CLOSE
,
30 typedef PVOID (*PFNKSPAGEDPOOLALLOCATE
)(IN PPAGED_LOOKASIDE_LIST Lookaside
);
31 typedef PVOID (*PFNKSNPAGEDPOOLALLOCATE
)(IN PNPAGED_LOOKASIDE_LIST Lookaside
);
33 typedef VOID (*PFNKSPAGEDPOOLFREE
)(IN PPAGED_LOOKASIDE_LIST Lookaside
, IN PVOID Entry
);
34 typedef VOID (*PFNKSNPAGEDPOOLFREE
)(IN PNPAGED_LOOKASIDE_LIST Lookaside
, IN PVOID Entry
);
36 typedef VOID (NTAPI
*PFNKSNPAGEDPOOLDELETE
)(IN PNPAGED_LOOKASIDE_LIST Lookaside
);
37 typedef VOID (NTAPI
*PFNKSPAGEDPOOLDELETE
)(IN PPAGED_LOOKASIDE_LIST Lookaside
);
41 IKsAllocatorVtbl
*lpVtbl
;
43 PKSIOBJECT_HEADER Header
;
46 KSSTREAMALLOCATOR_STATUS Status
;
50 NPAGED_LOOKASIDE_LIST NPagedList
;
51 PAGED_LOOKASIDE_LIST PagedList
;
57 PFNKSDEFAULTALLOCATE DefaultAllocate
;
58 PFNKSPAGEDPOOLALLOCATE PagedPool
;
59 PFNKSNPAGEDPOOLALLOCATE NPagedPool
;
64 PFNKSDEFAULTFREE DefaultFree
;
65 PFNKSPAGEDPOOLFREE PagedPool
;
66 PFNKSNPAGEDPOOLFREE NPagedPool
;
71 PFNKSDELETEALLOCATOR DefaultDelete
;
72 PFNKSNPAGEDPOOLDELETE NPagedPool
;
73 PFNKSPAGEDPOOLDELETE PagedPool
;
76 }ALLOCATOR
, *PALLOCATOR
;
78 /* use KSNAME_Allocator for IID_IKsAllocator */
79 const GUID IID_IKsAllocator
= {0x642F5D00L
, 0x4791, 0x11D0, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
80 const GUID KSPROPSETID_StreamAllocator
= {0x0cf6e4342, 0xec87, 0x11cf, {0xa1, 0x30, 0x00, 0x20, 0xaf, 0xd1, 0x56, 0xe4}};
85 IKsAllocator_Allocate(
86 IN PFILE_OBJECT FileObject
,
91 IKsAllocator_FreeFrame(
92 IN PFILE_OBJECT FileObject
,
98 IKsAllocator_fnQueryInterface(
103 PALLOCATOR This
= (PALLOCATOR
)CONTAINING_RECORD(iface
, ALLOCATOR
, lpVtbl
);
105 if (IsEqualGUIDAligned(refiid
, &IID_IUnknown
) ||
106 IsEqualGUIDAligned(refiid
, &IID_IKsAllocator
))
108 *Output
= &This
->lpVtbl
;
109 _InterlockedIncrement(&This
->ref
);
110 return STATUS_SUCCESS
;
112 return STATUS_UNSUCCESSFUL
;
117 IKsAllocator_fnAddRef(
118 IKsAllocator
* iface
)
120 PALLOCATOR This
= (PALLOCATOR
)CONTAINING_RECORD(iface
, ALLOCATOR
, lpVtbl
);
122 return InterlockedIncrement(&This
->ref
);
127 IKsAllocator_fnRelease(
128 IKsAllocator
* iface
)
130 PALLOCATOR This
= (PALLOCATOR
)CONTAINING_RECORD(iface
, ALLOCATOR
, lpVtbl
);
132 InterlockedDecrement(&This
->ref
);
139 /* Return new reference count */
145 IKsAllocator_fnDeviceIoControl(
147 IN PDEVICE_OBJECT DeviceObject
,
150 PALLOCATOR This
= (PALLOCATOR
)CONTAINING_RECORD(iface
, ALLOCATOR
, lpVtbl
);
151 PIO_STACK_LOCATION IoStack
;
152 PKSSTREAMALLOCATOR_FUNCTIONTABLE FunctionTable
;
153 PKSSTREAMALLOCATOR_STATUS State
;
154 PKSPROPERTY Property
;
158 /* get current irp stack */
159 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
161 if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
!= IOCTL_KS_PROPERTY
)
163 /* only KSPROPERTY requests are supported */
166 /* complete and forget irps */
167 Irp
->IoStatus
.Status
= STATUS_NOT_IMPLEMENTED
;
168 CompleteRequest(Irp
, IO_NO_INCREMENT
);
170 return STATUS_NOT_IMPLEMENTED
;
173 if (IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(KSPROPERTY
))
175 /* invalid request */
176 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
177 CompleteRequest(Irp
, IO_NO_INCREMENT
);
179 return STATUS_INVALID_DEVICE_REQUEST
;
182 /* check the request */
183 Property
= (PKSPROPERTY
)IoStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
185 if (IsEqualGUIDAligned(&Property
->Set
, &KSPROPSETID_StreamAllocator
))
187 if (Property
->Id
== KSPROPERTY_STREAMALLOCATOR_FUNCTIONTABLE
)
189 if (IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(KSSTREAMALLOCATOR_FUNCTIONTABLE
))
191 /* buffer too small */
192 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
193 Irp
->IoStatus
.Information
= sizeof(KSSTREAMALLOCATOR_FUNCTIONTABLE
);
194 /* complete and forget irp */
195 CompleteRequest(Irp
, IO_NO_INCREMENT
);
196 return STATUS_BUFFER_TOO_SMALL
;
198 if (!(Property
->Flags
& KSPROPERTY_TYPE_GET
))
200 /* only support retrieving the property */
201 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
202 /* complete and forget irp */
203 CompleteRequest(Irp
, IO_NO_INCREMENT
);
204 return STATUS_UNSUCCESSFUL
;
207 /* get output buffer */
208 FunctionTable
= (PKSSTREAMALLOCATOR_FUNCTIONTABLE
)Irp
->UserBuffer
;
210 FunctionTable
->AllocateFrame
= IKsAllocator_Allocate
;
211 FunctionTable
->FreeFrame
= IKsAllocator_FreeFrame
;
214 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
215 Irp
->IoStatus
.Information
= sizeof(KSSTREAMALLOCATOR_FUNCTIONTABLE
);
216 /* complete request */
217 CompleteRequest(Irp
, IO_NO_INCREMENT
);
218 return STATUS_SUCCESS
;
220 else if (Property
->Id
== KSPROPERTY_STREAMALLOCATOR_STATUS
)
222 if (IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(KSPROPERTY_STREAMALLOCATOR_STATUS
))
224 /* buffer too small */
225 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
226 Irp
->IoStatus
.Information
= sizeof(KSPROPERTY_STREAMALLOCATOR_STATUS
);
227 /* complete and forget irp */
228 CompleteRequest(Irp
, IO_NO_INCREMENT
);
229 return STATUS_BUFFER_TOO_SMALL
;
231 if (!(Property
->Flags
& KSPROPERTY_TYPE_GET
))
233 /* only support retrieving the property */
234 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
235 /* complete and forget irp */
236 CompleteRequest(Irp
, IO_NO_INCREMENT
);
237 return STATUS_UNSUCCESSFUL
;
240 /* get output buffer */
241 State
= (PKSSTREAMALLOCATOR_STATUS
)Irp
->UserBuffer
;
243 /* copy allocator status */
244 RtlMoveMemory(State
, &This
->Status
, sizeof(KSSTREAMALLOCATOR_STATUS
));
247 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
248 Irp
->IoStatus
.Information
= sizeof(KSSTREAMALLOCATOR_STATUS
);
250 /* complete request */
251 CompleteRequest(Irp
, IO_NO_INCREMENT
);
252 return STATUS_SUCCESS
;
256 /* unhandled request */
257 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
258 CompleteRequest(Irp
, IO_NO_INCREMENT
);
260 return STATUS_NOT_SUPPORTED
;
265 IKsAllocator_fnClose(
268 PALLOCATOR This
= (PALLOCATOR
)CONTAINING_RECORD(iface
, ALLOCATOR
, lpVtbl
);
272 /* now close allocator */
273 if (This
->Type
== ALLOCATOR_CUSTOM
)
275 This
->Delete
.DefaultDelete(This
->u
.CustomList
);
277 else if (This
->Type
== ALLOCATOR_NPAGED_LOOKASIDE
)
279 This
->Delete
.NPagedPool(&This
->u
.NPagedList
);
281 else if (This
->Type
== ALLOCATOR_PAGED_LOOKASIDE
)
283 This
->Delete
.PagedPool(&This
->u
.PagedList
);
286 /* free object header */
287 KsFreeObjectHeader(&This
->Header
);
289 return STATUS_SUCCESS
;
294 IKsAllocator_fnAllocateFrame(
299 PALLOCATOR This
= (PALLOCATOR
)CONTAINING_RECORD(iface
, ALLOCATOR
, lpVtbl
);
303 /* now allocate frame */
304 if (This
->Type
== ALLOCATOR_CUSTOM
)
306 Frame
= This
->Allocate
.DefaultAllocate(This
->u
.CustomList
);
308 else if (This
->Type
== ALLOCATOR_NPAGED_LOOKASIDE
)
310 Frame
= This
->Allocate
.NPagedPool(&This
->u
.NPagedList
);
312 else if (This
->Type
== ALLOCATOR_PAGED_LOOKASIDE
)
314 Frame
= This
->Allocate
.PagedPool(&This
->u
.PagedList
);
320 InterlockedIncrement((PLONG
)&This
->Status
.AllocatedFrames
);
321 return STATUS_SUCCESS
;
324 return STATUS_UNSUCCESSFUL
;
329 IKsAllocator_fnFreeFrame(
333 PALLOCATOR This
= (PALLOCATOR
)CONTAINING_RECORD(iface
, ALLOCATOR
, lpVtbl
);
335 /* now allocate frame */
336 if (This
->Type
== ALLOCATOR_CUSTOM
)
338 This
->Free
.DefaultFree(This
->u
.CustomList
, Frame
);
340 else if (This
->Type
== ALLOCATOR_NPAGED_LOOKASIDE
)
342 This
->Free
.NPagedPool(&This
->u
.NPagedList
, Frame
);
344 else if (This
->Type
== ALLOCATOR_PAGED_LOOKASIDE
)
346 This
->Free
.PagedPool(&This
->u
.PagedList
, Frame
);
351 static IKsAllocatorVtbl vt_IKsAllocator
=
353 IKsAllocator_fnQueryInterface
,
354 IKsAllocator_fnAddRef
,
355 IKsAllocator_fnRelease
,
356 IKsAllocator_fnDeviceIoControl
,
357 IKsAllocator_fnClose
,
358 IKsAllocator_fnAllocateFrame
,
359 IKsAllocator_fnFreeFrame
366 KSDDKAPI NTSTATUS NTAPI
368 IN HANDLE ConnectionHandle
,
369 IN PKSALLOCATOR_FRAMING AllocatorFraming
,
370 OUT PHANDLE AllocatorHandle
)
372 return KspCreateObjectType(ConnectionHandle
,
374 (PVOID
)AllocatorFraming
,
375 sizeof(KSALLOCATOR_FRAMING
),
383 KSDDKAPI NTSTATUS NTAPI
384 KsCreateDefaultAllocator(
387 return KsCreateDefaultAllocatorEx(Irp
, NULL
, NULL
, NULL
, NULL
, NULL
);
396 KsValidateAllocatorCreateRequest(
398 OUT PKSALLOCATOR_FRAMING
* OutAllocatorFraming
)
400 PKSALLOCATOR_FRAMING AllocatorFraming
;
403 ULONG SupportedFlags
;
405 /* set minimum request size */
406 Size
= sizeof(KSALLOCATOR_FRAMING
);
408 Status
= KspCopyCreateRequest(Irp
,
411 (PVOID
*)&AllocatorFraming
);
413 if (!NT_SUCCESS(Status
))
416 /* allowed supported flags */
417 SupportedFlags
= (KSALLOCATOR_OPTIONF_COMPATIBLE
| KSALLOCATOR_OPTIONF_SYSTEM_MEMORY
|
418 KSALLOCATOR_REQUIREMENTF_INPLACE_MODIFIER
| KSALLOCATOR_REQUIREMENTF_SYSTEM_MEMORY
| KSALLOCATOR_REQUIREMENTF_FRAME_INTEGRITY
|
419 KSALLOCATOR_REQUIREMENTF_MUST_ALLOCATE
);
422 if (!AllocatorFraming
->FrameSize
|| (AllocatorFraming
->OptionsFlags
& (~SupportedFlags
)))
424 FreeItem(AllocatorFraming
);
425 return STATUS_INVALID_PARAMETER
;
429 *OutAllocatorFraming
= AllocatorFraming
;
435 IKsAllocator_DispatchRequest(
436 IN PDEVICE_OBJECT DeviceObject
,
437 IN PFILE_OBJECT FileObject
,
440 IN ALLOC_REQUEST Request
)
442 PKSIOBJECT_HEADER Header
;
444 IKsAllocator
* Allocator
;
449 /* get object header */
450 Header
= (PKSIOBJECT_HEADER
)FileObject
->FsContext2
;
452 /* get real allocator */
453 Status
= Header
->Unknown
->lpVtbl
->QueryInterface(Header
->Unknown
, &IID_IKsAllocator
, (PVOID
*)&Allocator
);
455 if (!NT_SUCCESS(Status
))
457 /* misbehaving object */
458 return STATUS_UNSUCCESSFUL
;
461 if (Request
== ALLOCATOR_DEVICE_CONTROL
)
463 /* dispatch request allocator */
464 Status
= Allocator
->lpVtbl
->DispatchDeviceIoControl(Allocator
, DeviceObject
, Irp
);
466 else if (Request
== ALLOCATOR_DEVICE_CLOSE
)
468 /* delete allocator */
469 Status
= Allocator
->lpVtbl
->Close(Allocator
);
471 else if (Request
== ALLOCATOR_ALLOCATE
)
474 Status
= Allocator
->lpVtbl
->AllocateFrame(Allocator
, (PVOID
*)Frame
);
476 }else if (Request
== ALLOCATOR_FREE
)
479 Allocator
->lpVtbl
->FreeFrame(Allocator
, Frame
);
480 Status
= STATUS_SUCCESS
;
483 /* release interface */
484 Allocator
->lpVtbl
->Release(Allocator
);
491 IKsAllocator_DispatchDeviceIoControl(
492 IN PDEVICE_OBJECT DeviceObject
,
495 PIO_STACK_LOCATION IoStack
;
498 /* get current irp stack */
499 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
501 /* dispatch request */
502 Status
= IKsAllocator_DispatchRequest(DeviceObject
, IoStack
->FileObject
, Irp
, NULL
, ALLOCATOR_DEVICE_CONTROL
);
504 /* complete request */
505 Irp
->IoStatus
.Status
= Status
;
506 CompleteRequest(Irp
, IO_NO_INCREMENT
);
513 IKsAllocator_DispatchClose(
514 IN PDEVICE_OBJECT DeviceObject
,
517 PIO_STACK_LOCATION IoStack
;
520 /* get current irp stack */
521 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
523 /* dispatch request */
524 Status
= IKsAllocator_DispatchRequest(DeviceObject
, IoStack
->FileObject
, Irp
, NULL
, ALLOCATOR_DEVICE_CLOSE
);
526 /* complete request */
527 Irp
->IoStatus
.Status
= Status
;
528 CompleteRequest(Irp
, IO_NO_INCREMENT
);
535 IKsAllocator_Allocate(
536 IN PFILE_OBJECT FileObject
,
541 /* dispatch request */
542 Status
= IKsAllocator_DispatchRequest(NULL
, FileObject
, NULL
, (PVOID
)Frame
, ALLOCATOR_ALLOCATE
);
549 IKsAllocator_FreeFrame(
550 IN PFILE_OBJECT FileObject
,
553 /* dispatch request */
554 IKsAllocator_DispatchRequest(NULL
, FileObject
, NULL
, Frame
, ALLOCATOR_FREE
);
558 static KSDISPATCH_TABLE DispatchTable
=
560 IKsAllocator_DispatchDeviceIoControl
,
561 KsDispatchInvalidDeviceRequest
,
562 KsDispatchInvalidDeviceRequest
,
563 KsDispatchInvalidDeviceRequest
,
564 IKsAllocator_DispatchClose
,
565 KsDispatchQuerySecurity
,
566 KsDispatchSetSecurity
,
567 KsDispatchFastIoDeviceControlFailure
,
568 KsDispatchFastReadFailure
,
569 KsDispatchFastReadFailure
,
575 KSDDKAPI NTSTATUS NTAPI
576 KsCreateDefaultAllocatorEx(
578 IN PVOID InitializeContext OPTIONAL
,
579 IN PFNKSDEFAULTALLOCATE DefaultAllocate OPTIONAL
,
580 IN PFNKSDEFAULTFREE DefaultFree OPTIONAL
,
581 IN PFNKSINITIALIZEALLOCATOR InitializeAllocator OPTIONAL
,
582 IN PFNKSDELETEALLOCATOR DeleteAllocator OPTIONAL
)
585 PKSALLOCATOR_FRAMING AllocatorFraming
;
586 PALLOCATOR Allocator
;
589 /* first validate connect request */
590 Status
= KsValidateAllocatorCreateRequest(Irp
, &AllocatorFraming
);
591 if (!NT_SUCCESS(Status
))
592 return STATUS_INVALID_PARAMETER
;
594 /* check the valid file alignment */
595 if (AllocatorFraming
->FileAlignment
> (PAGE_SIZE
-1))
596 return STATUS_INVALID_PARAMETER
;
598 /* allocate allocator struct */
599 Allocator
= AllocateItem(NonPagedPool
, sizeof(ALLOCATOR
));
601 return STATUS_INSUFFICIENT_RESOURCES
;
603 /* allocate object header */
605 Status
= KsAllocateObjectHeader((KSOBJECT_HEADER
*)&Allocator
->Header
, 0, NULL
, Irp
, &DispatchTable
);
606 if (!NT_SUCCESS(Status
))
612 /* set allocator type in object header */
613 Allocator
->lpVtbl
= &vt_IKsAllocator
;
614 Allocator
->Header
->Unknown
= (PUNKNOWN
)&Allocator
->lpVtbl
;
619 /* use external allocator */
620 Allocator
->Type
= ALLOCATOR_CUSTOM
;
621 Allocator
->Allocate
.DefaultAllocate
= DefaultAllocate
;
622 Allocator
->Free
.DefaultFree
= DefaultFree
;
623 Allocator
->Delete
.DefaultDelete
= DeleteAllocator
;
624 Ctx
= InitializeAllocator(InitializeContext
, AllocatorFraming
, &Allocator
->u
.CustomList
);
625 /* check for success */
628 KsFreeObjectHeader(Allocator
->Header
);
633 else if (AllocatorFraming
->PoolType
== NonPagedPool
)
635 /* use non-paged pool allocator */
636 Allocator
->Type
= ALLOCATOR_NPAGED_LOOKASIDE
;
637 Allocator
->Allocate
.NPagedPool
= ExAllocateFromNPagedLookasideList
;
638 Allocator
->Free
.NPagedPool
= ExFreeToNPagedLookasideList
;
639 Allocator
->Delete
.NPagedPool
= ExDeleteNPagedLookasideList
;
640 ExInitializeNPagedLookasideList(&Allocator
->u
.NPagedList
, NULL
, NULL
, 0, AllocatorFraming
->FrameSize
, 0, 0);
642 else if (AllocatorFraming
->PoolType
== PagedPool
)
644 /* use paged pool allocator */
645 Allocator
->Allocate
.PagedPool
= ExAllocateFromPagedLookasideList
;
646 Allocator
->Free
.PagedPool
= ExFreeToPagedLookasideList
;
647 Allocator
->Delete
.PagedPool
= ExDeletePagedLookasideList
;
648 Allocator
->Type
= ALLOCATOR_PAGED_LOOKASIDE
;
649 ExInitializePagedLookasideList(&Allocator
->u
.PagedList
, NULL
, NULL
, 0, AllocatorFraming
->FrameSize
, 0, 0);
653 /* backup allocator framing */
654 RtlMoveMemory(&Allocator
->Status
.Framing
, AllocatorFraming
, sizeof(KSALLOCATOR_FRAMING
));
662 KSDDKAPI NTSTATUS NTAPI
663 KsValidateAllocatorFramingEx(
664 IN PKSALLOCATOR_FRAMING_EX Framing
,
666 IN
const KSALLOCATOR_FRAMING_EX
* PinFraming
)
668 if (BufferSize
< sizeof(KSALLOCATOR_FRAMING_EX
))
669 return STATUS_INVALID_DEVICE_REQUEST
;
672 if ((Framing
->FramingItem
[0].Flags
& KSALLOCATOR_FLAG_PARTIAL_READ_SUPPORT
) &&
673 Framing
->OutputCompression
.RatioNumerator
!= MAXULONG
&&
674 Framing
->OutputCompression
.RatioDenominator
!= 0 &&
675 Framing
->OutputCompression
.RatioDenominator
< Framing
->OutputCompression
.RatioNumerator
)
677 /* framing request is ok */
678 return STATUS_SUCCESS
;
681 return STATUS_INVALID_DEVICE_REQUEST
;