Sunday, April 19, 2009

device_create() and the linux shifting API

The kernel API for device_create() in 2.6.26 and previous versions was:

extern struct device *device_create(struct class *cls, struct device *parent,
dev_t devt, const char *fmt, ...)

and starting in 2.6.27 it changed to:

struct device *device_create(struct class *cls, struct device *parent,
dev_t devt, void *drvdata,
const char *fmt, ...)

Note the insertion of a fifth argument. In this case it is a void * at the fourth position in a function that takes a ... argument list.

This is more dangerous that the usual unstable evolutions in kernel APIs in that legacy code may continue to compile without warning on newer kernels, but it will of course crash as the first argument that was intended for the formatting string is now treated as the formatting string itself.

Some code is going to live out of the tree and trip over this. And some code is always going to live out of the tree - if for no other reason than the folks who control the commits have to (and should!) make judgments on what is appropriate, but of course other folks will disagree and carry on with their work. TCP Offload Engines are a good example of that kind of diversity.

Given that, I wonder what the reason for reusing the device_create() name was in between two incompatible versions of that function. There actually was an interim version of the new function called device_create_drvdata() that was used to migrate all of the in-tree uses over to the new style. At the end all the drvdata() versions were renamed back to device_create() where a safer path would seem to have been to simply remove device_create() all together to avoid confusion.

oh well, its not a big deal - but maybe this post will serve as google bait to help someone else resolve the issue more quickly than I could.