cswork / libraryOpen practice workspace

Articles

Linux Device Driver Interview Questions: Interrupts, DMA, and User-Kernel Interfaces

Practice Linux device driver questions with interrupt-context rules, DMA ownership, user-copy failures, device removal, and resource-lifetime scenarios.

Linux device driver interview questions test whether you can manage a device, its memory, and its users across concurrent execution and failure. The central questions are practical: which context is running, who owns this buffer, what can still access it, and how do you stop that access before cleanup?

Interrupt handling, DMA, and user-kernel interfaces are connected by those lifetimes. A correct transfer is not enough if device removal frees memory while work is still running, or if a user pointer is treated as an ordinary kernel address.

This guide uses a hypothetical data-acquisition device with an interrupt, a DMA buffer, and a read interface. The examples explain design decisions rather than provide a driver ready to load on hardware.

What should you ask before proposing a driver design?

Establish the device and bus model, kernel version, interrupt mechanism, DMA capabilities, and user-facing contract. A PCIe streaming device and a simple I2C sensor have different resource and execution requirements. Avoid beginning with a favorite lock or allocation flag before knowing the context.

For the acquisition example, ask whether the device can stop a transfer, how it reports completion, whether buffers are reused, and what happens during reset or removal. Define whether a read blocks, returns partial data, or reports a timeout.

Then draw the owners: the device has in-flight access to mapped memory; a worker may process completed samples; a user operation may be waiting for data; the driver has resources tied to probe and remove. Cleanup must account for every one of those users.

This is the thread connecting the rest of the interview. A local code fragment can look correct while its lifetime assumptions are wrong elsewhere.

What can a hard interrupt handler do?

A hard interrupt handler runs in a context with strict restrictions. Keep work bounded and avoid operations that may sleep. Typically it acknowledges or masks the device condition as required, records minimal state, and arranges appropriate deferred processing.

The exact acknowledge sequence comes from the hardware. Clearing a status bit too early can lose information; failing to clear or mask the right source can create an interrupt storm. A generic “read status and return” answer is incomplete without the device's interrupt contract.

For longer work, consider a threaded interrupt handler or another suitable deferred mechanism. The right choice depends on latency, ordering, and whether sleeping is allowed. Deferring work does not eliminate synchronization: the hard handler, thread, user operations, and removal path may still share state.

How do you choose between a spinlock and a mutex?

Begin with execution context. A mutex can sleep while waiting, so it is not appropriate in a hard IRQ context. A spinlock can protect short critical sections in contexts where sleeping is forbidden, but the exact variant and interrupt handling must match the shared users.

If process-context code takes a lock that an interrupt handler on the same CPU may take, account for that interruption scenario. Otherwise the interrupt can wait for a lock held by the code it interrupted. Explain the locking arrangement and relevant IRQ-safe pattern rather than naming spin_lock without context.

Keep slow operations outside short spinlocked sections. Do not hold a spinlock while copying to user memory, waiting for hardware, or calling code that can sleep. Protect a small state transition, retain whatever lifetime guarantee is needed, then perform the longer operation in the appropriate context.

Kernel configuration, including real-time configurations, can affect lock semantics. A strong interview answer states the assumed environment and checks the documented primitives used by that driver subsystem.

What is a DMA address?

A DMA address is the address the device uses for a transfer under the platform's DMA mapping rules. It is not automatically the same as a CPU virtual address or a physical address. An IOMMU and platform translation can change the relationship.

Use the kernel DMA API to allocate or map suitable memory, check mapping failures, and respect the device's supported DMA mask and direction. Handing a pointer from an arbitrary allocation directly to hardware is not a portable DMA strategy.

For streaming mappings, the driver must follow ownership and synchronization rules when the CPU and device access the buffer at different times. For coherent allocations, cache-maintenance needs differ, but ordering requirements do not disappear. Coherent does not mean every descriptor write is automatically observed in the sequence your device protocol requires.

In an interview, label the CPU address and device DMA address separately on the drawing. That one distinction prevents several common errors in explanations of buffers and descriptors.

Trace one DMA receive operation

Assume the driver has allocated a suitable buffer and established a mapping for device-to-memory transfer. It programs the device with the DMA address and length, following the hardware's descriptor and ordering requirements. The device fills the buffer and reports completion.

Before the CPU consumes the data, the driver performs the synchronization or unmapping required by the mapping type and platform. Only then should it interpret the received bytes under that contract. When reusing a streaming mapping, follow the corresponding transition back toward device ownership.

Prepare buffer and mapping
Program descriptor with DMA address and length
Device writes data
Observe completion using the device protocol
Synchronize/unmap as required
CPU reads completed data

Check the transfer length before reading. A device reporting completion does not justify indexing past the allocated capacity. Also decide whether the buffer can be reused while a user read still depends on its contents; that is an ownership question beyond cache coherence.

Why are memory barriers still relevant?

CPU memory ordering, device register access, and DMA visibility are related but distinct. The device may require descriptor fields to be visible before an ownership flag or doorbell announces that the descriptor is ready.

Use the kernel and subsystem APIs appropriate for that memory and device, rather than substituting a userspace atomic or volatile and assuming the problem is solved. A barrier can enforce a required ordering relationship, but it does not fix an invalid mapping or a freed buffer.

For a descriptor ring, explain which side owns each descriptor, how ownership changes, and what must be visible at the handoff. Then identify the API or barrier that supports that relationship on the target platform.

If a bug appears only on another architecture, review assumptions about ordering and coherency before dismissing it as timing. Code that accidentally works on one machine may still violate the DMA API contract.

How should a driver handle user pointers?

Treat a user pointer as an address in user space that requires the supported access routines and validation of lengths. It is not an ordinary trusted kernel pointer. Operations such as copy_to_user and copy_from_user can fault and may sleep in contexts where that is permitted.

Pay attention to return conventions. These routines report bytes that could not be copied, not simply a universal negative error code. The file-operation implementation must translate partial or failed copies into the behavior its interface promises.

Validate size arithmetic before allocating or copying. If a user supplies an element count and element size, multiplication can overflow. Bound requests by the actual buffer and device capabilities. Do not trust a successful earlier check forever if the relevant state can change concurrently.

For an ioctl interface, define stable layouts and compatibility expectations. Kernel and userspace may differ in word size, so exposing raw internal pointers or compiler-dependent structures makes the interface fragile.

How do blocking reads interact with interrupts?

A blocking read can wait until data is available or the device becomes unavailable. The interrupt or deferred processing path updates the readiness condition and wakes the appropriate waiters. The waiting code must recheck the condition under the intended synchronization model.

Handle interruption by signals and device removal explicitly. A wait should not sleep forever after the hardware is gone. A nonblocking read has a different contract: if no data is currently available, it should report the appropriate no-data condition rather than wait.

Be careful about lost wakeups and stale condition checks. Describe the state variable that represents readiness, how it is protected, and the waiting primitive's contract. “The interrupt wakes the process” is too vague to prove correctness.

Also define whether several readers compete for one stream or each receive a copy. That choice affects buffering, locking, and what it means for a read to consume data.

Why is device removal a difficult lifetime problem?

Removal can overlap with interrupts, workers, DMA, and open file operations. Freeing the driver's data structure immediately can leave those paths holding invalid references. A correct remove path prevents new work, stops or quiesces the device, synchronizes outstanding activity, and releases resources only when users are finished.

The exact order depends on the hardware and subsystem. For example, disabling a software callback is not enough if the device can still DMA into memory you are about to free. Similarly, stopping DMA does not automatically finish a worker that already queued a reference to that memory.

Managed resource helpers can simplify release on probe failure and detach, but they do not magically establish every asynchronous lifetime relationship. You must still ensure that no active path uses a resource after its release point.

Test removal while a transfer is active, while a reader is blocked, and while deferred work is queued. These cases reveal different owners and often require different cleanup actions.

What should a probe failure path clean up?

Probe typically acquires resources in stages. A later failure must release what was successfully acquired earlier, without releasing resources that were never obtained. Managed APIs help with supported resource types, while other resources need explicit cleanup.

Write a resource ledger for the acquisition example: registers mapped, interrupt registered, DMA buffers allocated, worker initialized, user interface registered, device enabled. Then consider failure after each stage. The cleanup must leave no exposed interface referring to a half-initialized device.

Do not enable hardware activity before the structures needed by its callbacks are ready. An interrupt can arrive sooner than the happy-path code assumes. Initialization ordering is a correctness issue, not merely a stylistic preference.

A practical interview rehearsal

Trace one transfer and one removal concurrently on paper. Mark every point where the device, interrupt handler, worker, or reader can access a buffer. Then propose the state transition that prevents a new access and the synchronization that waits for existing accesses to finish.

FailureFirst boundary to inspect
Sleeping-in-atomic warningExecution context and calls inside critical sections
Corrupt DMA dataMapping, ownership, length, and ordering
Crash after unplugOutstanding references and cleanup order
Read never returns after removalWait condition and wakeup policy
Probe intermittently crashesHardware enabled before callback state is ready

Your strongest answer connects an API choice to the lifetime it protects. That makes the reasoning portable across drivers while keeping the implementation grounded in the actual device and kernel.

Sources and Further Reading

Research checked September 24, 2026. This is an interview guide, not hardware-specific driver code. Use the target kernel, subsystem, and device documentation for implementation details.