Unwinding a failed character-device registration releases resources acquired before an initialization failure while preserving the lifetime of anything that concurrent users can still access. In Linux, reserving device numbers, publishing the character-device object and creating userspace-visible names are distinct steps. The cleanup path must know which steps actually succeeded.
Consider an original abstract initialization sequence: reserve a number range, initialize a character-device object, publish it, then finish a later setup step. The following table tracks successful acquisitions; it is not a complete driver implementation.
| State reached | Range reserved? | Character device live? | Required response to a later failure |
|---|---|---|---|
| Before reservation succeeds | No | No | Do not release a range that was not acquired. |
| Reservation succeeded, publication not reached | Yes | No | Release that reserved range and other private resources already acquired. |
| Publication succeeded | Yes | Yes | Stop new access, unwind the reservation, and preserve storage needed by existing users. |
alloc_chrdev_region reserves a range and reports failure through its return value. cdev_init initializes the object with its operations; cdev_add publishes it and makes it live immediately. unregister_chrdev_region releases a successful number reservation. Pair each release with the acquisition that actually succeeded, using the same first number and count.[ref]Character-device number registration in the Linux kernel documentation. Char devices, alloc_chrdev_region, cdev_init, cdev_add and unregister_chrdev_region
For a concrete bookkeeping example, suppose a successful reservation contains four interfaces starting at returned pair . Failure before publication requires releasing that four-number range. Releasing only three leaves part of the reservation behind; releasing a guessed starting major or an unacquired range is a different error. The returned major from dynamic character-device number allocation must be retained rather than reconstructed from a pathname.
Publication changes the lifetime problem.
cdev_del prevents new opens, but existing open file descriptors can still invoke their file operations. Therefore removing the device from lookup is not a proof that its backing state can immediately be freed. Character-device lifetime after deletion must account for the references and callbacks already in progress.[ref]Character-device number registration in the Linux kernel documentation. Char devices, cdev_del lifetime note
The combined
cdev_device_add helper has an especially important failure contract: callers must assume userspace could open the device and call operations even if the helper returns failure. A blanket error handler that immediately frees all backing state would violate that contract.[ref]Character-device number registration in the Linux kernel documentation. Char devices, cdev_device_add note
Design ownership and reference handling around the documented publication boundary, then release each owned resource once. The general lesson is that reverse acquisition order must be combined with concurrency-aware lifetime management.Character-device lifetime after deletion is the interval during which a removed character device still needs valid backing state because existing users can invoke its operations. Linux
cdev_del removes the device from new-open lookup; it does not invalidate already-open file descriptors. The kernel explicitly permits their file-operation callbacks after deletion returns.[ref]Character-device number registration in the Linux kernel documentation. Char devices, cdev_del lifetime note
Consider an original event sequence. Process A opens an interface and retains a pointer to driver state. Removal calls
cdev_del; process B can no longer obtain a new open through that registration. Process A then calls read. Freeing the state immediately after deletion would make that callback access dead storage: a use-after-free. The lookup lifetime and the backing allocation lifetime are different.A useful ownership model gives the allocation one registration reference and one reference for each successful open. In a simplified reference counting design with opens, the reference count is . Removal drops the registration reference; each final close drops its open reference. With two opens, the sequence is , and storage is reclaimed only at zero. This is a model of ownership, not a complete driver implementation: taking references must itself be synchronized with removal, and asynchronous work can require additional references.
The character device may be disconnected from its hardware before its storage is reclaimed. Existing operations can observe a synchronized disconnected state and return an appropriate error while the allocation remains valid. Reference protection alone does not make removed hardware usable or serialize simultaneous operations.
For combined device objects,
cdev_device_add and cdev_device_del have their own documented pairing and parent-reference rules. The add helper can expose callbacks even when it reports failure; the delete helper distinguishes stopped sysfs callbacks from still-callable operations on existing opens.[ref]Character-device number registration in the Linux kernel documentation. cdev_device_add description and failure warning; cdev_device_del note
Therefore unwinding a failed character-device registration must follow the actual publication and ownership state. Releasing the device number reservation is separate from proving that every user of private storage has finished. Articles by others on the same topic
There are currently no matching articles.