blob: a1333295d310bc7317088030b74a576a29c0058c [file] [log] [blame] [edit]
.\"
.\" Copyright (C) 2019 Red Hat, Inc. All Rights Reserved.
.\" Written by David Howells (dhowells@redhat.com)
.\"
.\" This program is free software; you can redistribute it and/or
.\" modify it under the terms of the GNU General Public Licence
.\" as published by the Free Software Foundation; either version
.\" 2 of the Licence, or (at your option) any later version.
.\"
.TH WATCH_QUEUE 7 "07 Aug 2019" Linux "Linux Programmer's Manual"
.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
.SH NAME
/dev/watch_queue \- General kernel notification queue
.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
.SH SYNOPSIS
#include <linux/watch_queue.h>
.EX
pipe2(fds, O_NOTIFICATION_QUEUE);
ioctl(fds[0], IOC_WATCH_QUEUE_SET_SIZE, max_message_count);
ioctl(fds[0], IOC_WATCH_QUEUE_SET_FILTER, &filter);
.EE
.SH OVERVIEW
.PP
The general kernel notification queue is a general purpose transport for kernel
notification messages to userspace. Notification messages are marked with type
information so that events from multiple sources can be distinguished.
Messages are also of variable length to accommodate different information for
each type.
.PP
Queues are implemented on top of standard pipes and multiple independent queues
can be created. After creation, queues are configured with the size and
filtering, event sources are attached and then the pipe is read or polled to
wait for messages.
.PP
Multiple messages may be read out of the queue at a time if the buffer is large
enough, but messages will not get split amongst multiple reads. If the buffer
isn't large enough for a message,
.B ENOBUFS
will be returned.
.PP
In the case of message loss,
.BR read (2)
will fabricate a loss message and write that into the buffer immediately after
the point at which the loss occurred.
.PP
A notification pipe a certain amount of locked kernel memory (so that the
kernel can write a notification into it from contexts where swapping cannot be
performed), and so is subject to pipe resource limit restrictions.
.PP
Sources must be attached to a queue manually; there's no single global event
source, but rather a variety of sources, each of which can be attached to by
multiple queues. Attachments can be set up by:
.TP
.BR keyctl_watch_key (3)
Monitor a key or keyring for changes.
.TP
.BR device_notify (2)
Monitor a global source of device events from USB and block devices, such as
device detection, device removal and I/O errors.
.PP
Because a source can produce a lot of different events, not all of which may be
of interest to the watcher, a filter can be set on a queue to determine whether
a particular event will get inserted in a queue at the point of posting inside
the kernel.
.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
.SH MESSAGE STRUCTURE
.PP
The output from reading the pipe is divided into variable length messages.
Read will never split a message across two separate read calls. Each message
begins with a header of the form:
.PP
.in +4n
.EX
struct watch_notification {
__u32 type:24;
__u32 subtype:8;
__u32 info;
};
.EE
.in
.PP
Where
.I type
indicates the general class of notification,
.I subtype
indicates the specific type of notification within that class and
.I info
includes the message length (in bytes), the watcher's ID and some type-specific
information.
.PP
In the event that the ring is full when the kernel needs to insert a
notification into the pipe and a message is lost, the reader will insert a
.BR WATCH_META_LOSS_NOTIFICATION -subtype
message after the message that was last in the pipe at the time the loss
occurred is read.
.PP
If a notification source goes away whilst it is being watched, a
.BR WATCH_META_REMOVAL_NOTIFICATION -subtype
message is posted to the queue. This comes in two lengths: a short variant
that carries just the header and a long variant that includes a 64-bit
identifier as well that identifies the source more precisely (the identifier is
source dependent).
.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
.SH IOCTL COMMANDS
The device has the following
.IR ioctl ()
commands:
.TP
.B IOC_WATCH_QUEUE_SET_SIZE
The ioctl argument is indicates the maximum number of messages that can be
inserted into the pipe. This must be a power of two. This command also
pre-allocates memory to hold messages.
.IP
This may only be done once and the queue cannot be used until this command has
been done.
.TP
.B IOC_WATCH_QUEUE_SET_FILTER
This is used to set filters on the notifications that get written into the
buffer. The ioctl argument points to a structure of the following form:
.IP
.in +4n
.EX
struct watch_notification_filter {
__u32 nr_filters;
__u32 __reserved;
struct watch_notification_type_filter filters[];
};
.EE
.in
.IP
Where
.I nr_filters
indicates the number of elements in the
.IR filters []
array. Each element in the filters array specifies a filter and is of the
following form:
.IP
.in +4n
.EX
struct watch_notification_type_filter {
__u32 type;
__u32 info_filter;
__u32 info_mask;
__u32 subtype_filter[8];
};
.EE
.in
.IP
Where
.I type
refer to the type field in a notification record header, info_filter and
info_mask refer to the info field and subtype_filter is a bit-mask of subtypes.
.IP
If no filters are installed, all notifications are allowed by default and if
one or more filters are installed, notifications are disallowed by default.
.IP
A notifications matches a filter if, for notification N and filter F:
.IP
.in +4n
.EX
N->type == F->type &&
(F->subtype_filter[N->subtype >> 5] &
(1U << (N->subtype & 31))) &&
(N->info & F->info_mask) == F->info_filter)
.EE
.in
.IP
.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
.SH EXAMPLE
To use the notification mechanism, first of all the device has to be opened,
the size must be set:
.PP
.in +4n
.EX
int fds[2];
pipe2(fd[0], O_NOTIFICATION_QUEUE);
int wfd = fd[0];
ioctl(wfd, IOC_WATCH_QUEUE_SET_SIZE, 1);
.EE
.in
.PP
From this point, the buffer is open for business. Filters can be set to
restrict the notifications that get inserted into the buffer from the sources
that are watched. For example:
.PP
.in +4n
.EX
static struct watch_notification_filter filter = {
.nr_filters = 2,
.__reserved = 0,
.filters = {
[0] = {
.type = WATCH_TYPE_KEY_NOTIFY,
.subtype_filter[0] = 1 << NOTIFY_KEY_LINKED,
.info_filter = 1 << WATCH_INFO_FLAG_2,
.info_mask = 1 << WATCH_INFO_FLAG_2,
},
[1] = {
.type = WATCH_TYPE_USB_NOTIFY,
.subtype_filter[0] = 1 << NOTIFY_USB_DEVICE_ADD,
},
},
};
ioctl(wfd, IOC_WATCH_QUEUE_SET_FILTER, &filter);
.EE
.in
.PP
will only allow key-change notifications that indicate a key is linked into a
keyring and then only if type-specific flag WATCH_INFO_FLAG_2 is set on the
notification and will only allow USB device-add notifications, blocking other
USB notifications and all block device notifications.
.PP
Sources can then be watched, for example:
.PP
.in +4n
.EX
keyctl_watch_key(KEY_SPEC_SESSION_KEYRING, wfd, 0x33);
watch_devices(wfd, 0x55, 0);
.EE
.in
.PP
The first places a watch on the process's session keyring, directing the
notifications to the buffer we just created and specifying that they should be
tagged with 0x33 in the info ID field. The second places a watch on the global
device notifications queue, specifying that notifications from that should be
tagged with info ID 0x55.
.PP
When it is determined that there is something in the buffer, messages can be
read out of the ring with something like the following:
.PP
.in +4n
.EX
for (;;) {
unsigned char buf[128];
read(fd, buf, sizeof(buf));
struct watch_notification *n = (struct watch_notification *)buf;
switch (n->type) {
case WATCH_TYPE_META:
switch (n->subtype) {
case WATCH_META_REMOVAL_NOTIFICATION:
saw_removal_notification(n);
break;
case WATCH_META_LOSS_NOTIFICATION:
printf("-- LOSS --\n");
break;
}
break;
case WATCH_TYPE_KEY_NOTIFY:
saw_key_change(n);
break;
case WATCH_TYPE_BLOCK_NOTIFY:
saw_block_change(n);
break;
case WATCH_TYPE_USB_NOTIFY:
saw_usb_event(n);
break;
}
}
.EE
.in
.PP
.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
.SH VERSIONS
The notification queue driver first appeared in v??? of the Linux kernel.
.SH SEE ALSO
.ad l
.nh
.BR keyctl (1),
.BR ioctl (2),
.BR read (2),
.BR keyctl_watch_key (3)