ERROR_NOT_ENOUGH_QUOTA

Occasionally my DeviceIOControl( ) returns and if an error is returned a subsequent call to GetLastError will give me “ERROR_NOT_ENOUGH_QUOTA”.

The calls that I’ve seen fail so far as pretty simple read and write calls via IOControl to my PCI board. I’ve seen this behavior when running my application to loop a procedure to test it’s durability. The procedure does many DeviceIOcontrol calls and at some point it can return this error before completing.

I can’t seem to find too much information as to possible causes behind this error. The one that seems to make sense refers to Async IO. In my init I believe I’m correctly using Sync IO.

WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&ioQConfig,WdfIoQueueDispatchSequential)

Any suggestions or ideas? I don’t know what exactly can cause this error. I imagine it is running out of some resource but i don’t know which and I don’t know why. I don’t run any calls in parallel. All calls are completed before the next is made. Not sure how I could run out of a resource randomly when the procedure is identical each time but only fails sometimes.

xxxxx@yahoo.com wrote:

Occasionally my DeviceIOControl( ) returns and if an error is returned a subsequent call to GetLastError will give me “ERROR_NOT_ENOUGH_QUOTA”.

FYI, that is the user-mode mapping of the kernel error
STATUS_QUOTA_EXCEEDED. Does your driver ever return that?


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

I will have to look back at my notes to remember how to enable tracing. Been a while. I was hoping it was something obviously wrong I might be doing. I’m working on tracing now.

What might that error suggest? If that is the user mapped error is there any way my driver wouldn’t return STATUS_QUOTA_EXCEEDED?

That kernel error did help me find new paths to research. I was unaware that the kernel and user level errors used different labels.

I found this but still don’t know how I might be doing one of these.
* Object handles are leaking because of an object (or handle) leak in a program.
* A driver is leaking pool memory from kernel mode.

Any examples?

xxxxx@yahoo.com wrote:

That kernel error did help me find new paths to research. I was unaware that the kernel and user level errors used different labels.

I found this but still don’t know how I might be doing one of these.
* Object handles are leaking because of an object (or handle) leak in a program.
* A driver is leaking pool memory from kernel mode.

Any examples?

Really, you’re going to have to trace through your driver (either in
Windbg or with KdPrints) to narrow down where in the path you are
getting this error. It doesn’t come from thin air – somewhere,
something in your driver is getting that error and setting it into the IRP.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

This could mean you’re leaking IRPs. You either issue too many async requests and the driver loses them, or return incorrect status from your dispatch routine, or fail to match STATUS_PENDING with IoMarkIrpPending.

I’m not sure what to even trace. These calls are extremely simple. They retrieve input/output buffer and do a Read/Write_Register and CompleteWithInfo. The only calls that can return an error are the WdfRequestRetrieveInput(Output)Buffer calls. These calls are extremely simple. The same read and write calls are made thousands of times before one finally returns an error.

I only use synchronous calls and if my app sees pending it blocks until completed. If my application has a memory leak could this affect the driver such that it gets the quota error?

In TaskManager, how many handles you see for your app?

Just the one. Siill trying to get tracing working again. Been a very long time. For some reason it gave me the BSOD when I started the session. I hadn’t even run my application which never causes an OS crash, just app crashes.This is why I’m trying to figure this out with the driver debuggers. They are always a hassle to use.

After running a trace I see none of my possible error conditions print a message. The retrieve/in/out buffers are the only functions that can return errors but do not do so. I simply see an ERROR_NOT_ENOUGH_QUOTA on the app side but no call in the driver reports this error directly.

This is an example of the driver code that returns an error:

IOCTL:
status = SheldonPassthroughRead(Request, InputBufferLength, OutputBufferLength);
WdfRequestCompleteWithInformation(Request, status, OutputBufferLength);

SheldonPassthroughRead:
NTSTATUS
SheldonPassthroughRead
(
WDFREQUEST Request,
size_t InputBufferLength,
size_t OutputBufferLength
)
{
WDFDEVICE device;
PDEVICE_CONTEXT devCtx;
NTSTATUS status = STATUS_SUCCESS;
CHAR *bytePointer;
ULONG count, width;
PULONG inputBuffer;
PULONG outputBuffer;

device = WdfIoQueueGetDevice(WdfRequestGetIoQueue(Request));
devCtx = GetDeviceContext(device);

status = WdfRequestRetrieveInputBuffer(Request, InputBufferLength, (PVOID*) &inputBuffer, NULL);
if(!NT_SUCCESS(status))
{
TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS, __DRIVER_NAME “SheldonPassthroughRead: WdfRequestRetrieveInputBuffer failed with status 0x%08x”, status);
return status;
}

status = WdfRequestRetrieveOutputBuffer(Request, OutputBufferLength, (PVOID*) &outputBuffer, NULL);
if(!NT_SUCCESS(status))
{
TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS, __DRIVER_NAME “SheldonPassthroughRead: WdfRequestRetrieveOutputBuffer failed with status 0x%08x”, status);
return status;
}

bytePointer = (CHAR *) devCtx->base[inputBuffer[0]];
bytePointer += inputBuffer[1];
count = inputBuffer[2];
width = inputBuffer[3];

// all looks OK, so do the read
switch (width)
{
case 0: //32bit
READ_REGISTER_BUFFER_ULONG((PULONG)bytePointer, (PULONG) outputBuffer, count);
break;
case 1: //16bit
READ_REGISTER_BUFFER_USHORT((PUSHORT)bytePointer, (PUSHORT) outputBuffer, count);
break;
case 2: //8bit
READ_REGISTER_BUFFER_UCHAR((PUCHAR)bytePointer, (PUCHAR) outputBuffer, count);
break;
default:
READ_REGISTER_BUFFER_ULONG((PULONG)bytePointer, (PULONG) outputBuffer, count);
break;
}

return STATUS_SUCCESS;
}

What else can I do to find the source of my error?

Though it’s not related to your problem, but you REALLY need to validate your input parameters. That inputBuffer[0] doesn’t exceed highest BAR index, and buffer[1] doesn’t exceed that BAR size, and number of read bytes doesn’t exceed BAR boundary. Make sure you don’t get integer overflow when you validate the parameters, too.

I used to have such checks but removed them because I feared it would slow things down. I will put them back.

I found: http://support.microsoft.com/kb/264223
Using PoolMon I found a Tag I assume is mine. When running my app in an loop it always creeps it’s way to the top of the list. I’m not quite sure how to interpret the data but it seems there is a growing disparity between Allocs and Frees. I imagine this is the problem. Does this necessarily mean it is my driver or can it still be the app? After running this all day the errors have moved to instances of malloc in my application. It appears I have a memory leak but can this error explain the ERROR_NOT_ENOUGH_QUOTA error seen earlier and the numbers I see through Poolmon? I’m not sure if or how the three are related. I want to be sure the error is in the app, driver, or both. Is there a way to determine who is the problem?

The Difference value between Allocs and Frees only seems to grow when I run in a loop. If I keep the application open and run the same function as single accesses the number is unchanged. Running in a loop always increases the value. I can’t imagine why this is the case. I simple loop around the same call. I don’t add any other calls. Just repeat the same one more rapidly.

xxxxx@yahoo.com wrote:

After running a trace I see none of my possible error conditions print a message. The retrieve/in/out buffers are the only functions that can return errors but do not do so. I simply see an ERROR_NOT_ENOUGH_QUOTA on the app side but no call in the driver reports this error directly.

bytePointer = (CHAR *) devCtx->base[inputBuffer[0]];
bytePointer += inputBuffer[1];
count = inputBuffer[2];
width = inputBuffer[3];

I’m with Grigora – I would at least want to check that the transfer
wasn’t going to blow the output buffer. Users can’t be trusted, you know.
ASSERT(width <= 2);
int Bytes = count << (2-width);
ASSERT( Bytes <= OutputBufferLength );

Your outer code assumes that you are always returning OutputBufferLength
bytes (even in case of error). That’s not really correct. You compute
the amount of data to return from the input parameters. If I ask for 3
dwords, and give you a 500-byte buffer, you should return 12, not 500.

That’s not related to your quota problem, however.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

Thanks for the knowledge. I will look to implement the changes you mentioned to prevent future errors.

I have also tracked down my problem. While walking through the calls in my app I noticed I had a mismatched CreateEvent call when doing my reads. I neglected to call closehandle and allocated a new handle for each read call and I was doing thousands of calls. I can now make it through my loop of 100 calls successfully and see my tag in Poolmon doesn’t keep allocating more than it frees as it runs the loop.

Thanks for the input.