14.3. Hotplug Event Generation
A hotplug event is a
notification
to
user space from the kernel
that something has changed in the system's
configuration. They are generated whenever a kobject is created or
destroyed. Such events are generated, for example, when a digital
camera is plugged in with a USB cable, when a user switches console
modes, or when a disk is repartitioned. Hotplug events turn into an
invocation of /sbin/hotplug, which can respond
to each event by loading drivers, creating device nodes, mounting
partitions, or taking any other action that is appropriate.
The last major kobject function we look at is the generation of these
events. The actual event generation takes place when a kobject is
passed to kobject_add or
kobject_del. Before the event is handed to user
space, code associated with the kobject (or, more specifically, the
kset to which it belongs) has the opportunity to add information for
user space or to disable event generation entirely.
14.3.1. Hotplug Operations
Actual control of hotplug events
is
exercised by way of a set of methods stored in the
kset_hotplug_ops
structure:
struct kset_hotplug_ops {
int (*filter)(struct kset *kset, struct kobject *kobj);
char *(*name)(struct kset *kset, struct kobject *kobj);
int (*hotplug)(struct kset *kset, struct kobject *kobj,
char **envp, int num_envp, char *buffer,
int buffer_size);
};
A pointer to this structure is found in the
hotplug_ops field of the kset structure. If a
given kobject is not contained within a kset, the kernel searchs up
through the hierarchy (via the parent pointer)
until it finds a kobject that does have a kset;
that kset's hotplug operations are then used.
The filter
hotplug operation is called whenever
the kernel is considering generating an event for a given kobject. If
filter returns 0, the event
is not created. This method, therefore, gives the kset code an
opportunity to decide which events should be passed on to user space
and which should not.
As an example of how this method might be used, consider the block
subsystem. There are at least three types of kobjects used there,
representing disks, partitions, and request queues. User space may
want to react to the addition of a disk or a partition, but it does
not normally care about request queues. So the
filter method allows event generation only for
kobjects representing disks and partitions. It looks like this:
static int block_hotplug_filter(struct kset *kset, struct kobject *kobj)
{
struct kobj_type *ktype = get_ktype(kobj);
return ((ktype = = &ktype_block) || (ktype = = &ktype_part));
}
Here, a quick test on the type of kobject is sufficient to decide
whether the event should be generated or not.
When the user-space hotplug program is invoked, it is passed to the
name of the relevant subsystem as its one and only parameter. The
name hotplug method is charged with providing
that name. It should return a simple string suitable for passing to
user space.
Everything else that the hotplug script might want to know is passed
in the environment. The final hotplug method
(hotplug) gives an opportunity to add useful
environment variables prior to the invocation of that script. Again,
this method's prototype is:
int (*hotplug)(struct kset *kset, struct kobject *kobj,
char **envp, int num_envp, char *buffer,
int buffer_size);
As usual, kset and kobject
describe the object for which the event is being generated. The
envp array is a place to store additional
environment variable definitions (in the usual
NAME=value format); it has
num_envp entries available. The variables
themselves should be encoded into buffer, which is
buffer_size bytes long. If you add any variables
to envp, be sure to add a NULL
entry after your last addition so that the kernel knows where the end
is. The return value should normally be 0; any
nonzero return aborts the generation of the hotplug event.
The generation of hotplug events (like much of the work in the device
model) is usually handled by logic at the bus driver level.
|