LWN.net Logo

Device resource management

Writing device drivers can be a tricky task. Simply getting a piece of hardware to operate as desired - perhaps working from erroneous or nonexistent documentation - can be a frustrating process. Beyond that, however, the driver must allocate several different types of resources for the device; these resources can include I/O memory mappings, interrupt lines, blocks of memory, DMA buffers, registrations with multiple subsystems, etc. All of these allocations must be returned to the system when the device (or its driver) goes away. It is not uncommon for driver writers to forget to deallocate something, leading to resource leaks.

The problem can get worse, however, in the face of initialization errors. If the driver is unable to properly set up its device, it must undo any registrations which had been done up to the point of failure. Attempts to handle initialization failures usually take the form of several goto labels within the initialization function or some sort of global "initialization state" variable describing where cleanup should begin. Either way, these paths tend not to be well tested, so the chances of an initialization failure leading to some sort of resource leak are quite good.

Tejun Heo, who has done much to improve the Linux serial ATA subsystem over the last year, has had enough of these sorts of initialization problems. So he has put together a device resource management patch which, if accepted, has the potential to make driver code simpler and more robust. The core idea is simple: every time a driver allocates a resource, the management code remembers the allocation and any information needed to free that allocation. When the driver disconnects from the device, all of the remembered allocations are returned to the system.

This sort of allocation tracking cannot be added to the current API in any sort of coherent way. Tejun's patch, instead, creates new "managed" versions of various allocation functions. The new functions look like the old ones with (1) the addition of "m" (or "devm") to the name, and (2) a struct device argument if the function did not already have one. So, for example, the managed versions of the interrupt allocation functions are:

    int devm_request_irq(struct device *dev, unsigned int irq,
		         irq_handler_t handler, unsigned long irqflags,
		    	 const char *devname, void *dev_id);
    void devm_free_irq(struct device *dev, unsigned int irq, 
                       void *dev_id);

The patch also includes managed functions for dealing with DMA buffers, I/O memory regions, plain memory allocations, and PCI device setup. They allow the driver author to replace a whole set of deallocation calls with a simple call to devres_release_all(), simplifying the code significantly. In fact, even that call is unnecessary; the driver core will call it when the driver detaches from the device.

For more complicated situations, there is also a "group" concept. Groups can be thought of as markers in the stream of allocations associated with a given device. The allocations performed within a specific group can be rolled back without affecting any others. In brief, the group API is:

    void *devres_open_group(struct device *dev, void *id, gfp_t gfp);
    void devres_close_group(struct device *dev, void *id);
    void devres_remove_group(struct device *dev, void *id);
    int devres_release_group(struct device *dev, void *id);

A call to devres_open_group() will create a new group for the given device, identified by the id value. Any allocations performed thereafter will be considered to be a part of that group until devres_close_group() is called. If initialization works as desired, however, devres_remove_group() can be used to get rid of the group overhead while leaving the allocations (and their tracking information) untouched. In the failure path, devres_release_group() will return all allocations belonging to the given group.

There has been very little discussion of this patch set, as of this writing. Driver writers, perhaps, are still recovering from the holiday festivities. It is not too hard to imagine that there could be some discomfort about the extra overhead involved in tracking all of those allocations - especially since things do function normally almost all of the time. In the end, however, the promise of correct operation in a wider range of situations may be enough to motivate the inclusion of the new interface.


(Log in to post comments)

Device resource management

Posted Jan 4, 2007 15:43 UTC (Thu) by NAR (subscriber, #1313) [Link]

It's a kind of garbage collection, isn't it?

Bye,NAR

Device resource management

Posted Jan 5, 2007 17:22 UTC (Fri) by nix (subscriber, #2304) [Link]

More like a sort of obstacky thing, really. It's only garbage collection if you consider `chuck it all away' to be GC.

The true meaning of GC

Posted Jan 7, 2007 1:45 UTC (Sun) by Max.Hyre (subscriber, #1054) [Link]

It's only garbage collection if you consider `chuck it all away' to be GC.
Isn't that what GC is all about? This one just doesn't have to be so picky about what it chucks. :-)

The true meaning of GC

Posted Jan 9, 2007 16:50 UTC (Tue) by nix (subscriber, #2304) [Link]

Well, yeah, but it's at best very *simple-minded* GC. :)

Device resource management

Posted Jan 12, 2007 11:51 UTC (Fri) by josh (subscriber, #17465) [Link]

Looks reminiscent of talloc, sans hierarchy.

talloc()

Posted Jan 12, 2007 13:48 UTC (Fri) by corbet (editor, #1) [Link]

Yes, kind of like talloc(), but with the hierarchy - that's what the groups are - and with the ability to track allocation of resources other than memory.

Copyright © 2007, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds