Unwinding a failed character-device registration (source code)

= Unwinding a failed character-device registration

\b[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.<Character-device number registration in the Linux kernel documentation>[Char devices, alloc_chrdev_region, cdev_init, cdev_add and unregister_chrdev_region]{ref}

For a concrete bookkeeping example, suppose a successful reservation contains four interfaces starting at returned pair $(M,20)$. 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.<Character-device number registration in the Linux kernel documentation>[Char devices, cdev_del lifetime note]{ref}

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.<Character-device number registration in the Linux kernel documentation>[Char devices, cdev_device_add note]{ref} 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.