In September, 2004, LWN.net
took a look
at the inotify patch.
This patch has been reworked a number of times by its primary
developers, and has been living in the -mm kernel tree for a few months.
With the recent
What to merge for 2.6.13?
discussion, inotify was mentioned as something that might be
considered for merging into the main kernel tree. One thing that few
kernel developers had paid attention to in the inotify patch was
the userspace interface to the feature. So, let's take a look at how a
programmer is supposed to interact with inotify.
From the documentation included in the kernel patch, inotify
communicates to userspace through a character device, /dev/inotify.
This is a misc character device (it uses the misc_register() kernel interface
to create its character device), and if you use udev to manage /dev, the
device node is automatically created. If not, the character node needs
to be created by hand:
mknod /dev/inotify c 10 63
Inotify works with something called "watches". A "watch" is
an object and a mask that describe an event that the user wants to
receive notification events from. The object is either a file or a
directory, as represented by an open file descriptor, and the mask is a
bitmask of events. The different types of events that can be monitored
are:
IN_ACCESS The file was accessed
IN_MODIFY The file was modified
IN_ATTRIB The metadata changed
IN_CLOSE_WRITE The writtable file was closed
IN_CLOSE_NOWRITE The unwrittable file closed
IN_OPEN The file was opened
IN_MOVED_FROM The file was moved from location X
IN_MOVED_TO The file was moved to location Y
IN_CREATE A subfile was created
IN_DELETE A subfile was deleted
IN_DELETE_SELF self was deleted
If the user wants to monitor all events, a handy IN_ALL_EVENTS macro is
defined which includes all of the above event flags combined together.
To create a watch and register it with the kernel, an ioctl is called on
the /dev/inotify node:
struct inotify_request request = { fd, mask };
int watch_desc = ioctl(dev_fd, INOTIFY_WATCH, &request);
where fd is the open file descriptor of the file or directory you wish
to watch, and mask is the type of event to monitor.
To remove a watch that is already in place, another ioctl should be
sent:
ioctl(dev_fd, INOTIFY_IGNORE, watch_desc);
Once a watch has been registered with the kernel, a simple read() call
to the device node is used to retrieve events based on that watch (and
all other watches that have been registered for this process.) The
structure of the data that read from the kernel is described in the
following C struct:
struct inotify_event {
__s32 wd; /* watch descriptor */
__u32 mask; /* watch mask */
__u32 cookie; /* cookie to synchronize two events */
__u32 len; /* length (including nulls) of name */
char name[0]; /* stub for possible name */
};
All of the fields are pretty self explanatory, with the exception of
"cookie". If this field is not set to 0, then it is used to tell
userspace that multiple events happened at the same time on the same
object. An example of this is renaming a file. If a directory is being
watched and the following file rename happens in it:
mv foo baz
there would be 2 events generated, an IN_MOVE_FROM and an IN_MOVE_TO
event. They would both have the same cookie value, which allows
userspace to coordinate the events.
The /dev/inotify node allows select() and poll() to be called on it, so
a blocking read() is not necessary, which would tie up a program's
thread.
The FIONREAD ioctl is also supported by inotify, and returns the size of
the current pending event queue, if userspace wishes to do dynamic
buffer allocation to place the events into.
When the userspace program that had the /dev/inotify node open exits, or
when the node is closed, all watches that were registered with the
kernel are destroyed and cleaned up properly.
For a very simple example program that shows how to register for events,
and read events as they happen, see the inotify-utils package that can
be found
here.
For more details on the kernel design decisions that the inotify
developers went through in creating this system, please see the inotify
documentation in the kernel patch. It describes why a character node
was used instead of signals, and other details.
(
Log in to post comments)