fsev_t, FSE*()

Structure and macros for filesystem events

Synopsis:

#include <sys/fs_events.h>

typedef struct fse_event_s {
    uint32_t        signature;          /* Version and fixed identifier      */
    uint16_t        length;             /* Type and length of the event data */
    uint16_t        command;            /* Command / request information     */
    uint32_t        properties;         /* Classification of the event       */
    uint32_t        reserved;           /* Reserved for future use (zero)    */
    uint32_t        identity;           /* Locale and ID of the event        */
} fsev_t;

Description:

The <sys/fs_events.h> header file includes everything necessary to read and process events from the filesystem event manager, fsevmgr.

The fsev_t structure is a header that describes a filesystem event, including its origin, locale, and identity. It's followed by any data associated with the event. Generally the data is a path string, but depends on the type of event.

Events are organized into tuples that have a common header, a description of the event, and length of that event. The length field represents the entire length from the starting address of the tuple.

Note: Don't use sizeof() to determine the size of an event, because this header structure might be followed by a flexarray or be part of another structure.

You read an event from the event manager into an array of bytes, but there's no guarantee of alignment, so you should use the FSE_READ_EVENT_S() macro—which is a cover for the memcpy() function—to copy the data into an fsev_t structure:

#define FSE_READ_EVENT_S(pev, pdata)

where pev is a pointer to a fsev_t structure, and pdata is a pointer to the array of bytes.

To access a tuple, use the following FSE_*() macros, which take as an argument a pointer to an fsev_t structure:

FSE_CMD_VAL(p)
Get the command or request. The possible values include:
  • FSE_CMD_FILTER — used by clients when they want to set a filter against a file descriptor.
  • FSE_CMD_POST — used by the filesystem for sending data to the event manager.
  • FSE_CMD_REPORT — not currently used.
FSE_DATA_LEN(p)
Return the length of data that's attached to the tuple. The maximum length is given by FSE_MAX_EVENT_LENGTH. It accommodates at least two paths of 1024 bytes; some name-based operations may have three paths, consisting of a mountpoint and the two relative paths.
Note: Events with longer data might be lost.
FSE_DATA_PTR(p)
Get a pointer to the event data.
FSE_IDENTITY_VAL(p)
Get the locale and ID of the event.
FSE_ID_ISDIR_VAL(p)
Return a nonzero value if the event concerns a directory.
FSE_ID_VAL(p)
Return the event ID.
FSE_IS_V1_EVENT(p)
Return a nonzero value if the event has a valid signature and is version 1. You should use this macro first, to make sure that the event is valid.
FSE_LEN_VAL(p)
Get the length of the event data.
FSE_LOCALE_VAL(p)
Return the locale of the event.
FSE_PROP_VAL(p)
Return the event properties.
FSE_SIG_VAL(p)
Get the event's signature.
FSE_TUPLE_LEN(p)
Return the total size of the event tuple, which includes the fsev_t structure and its data.
FSE_VERSION_OF(p)
Get the version of the filesystem event software.

Properties

Properties are boolean attributes of an event that help to describe its purpose, data, and/or impact to the system. An event can have multiple properties ORed together.

To assist in the filtering of events, properties are organized into a few groups: types, class, and data. FSE_TYPE_* properties indicate the purpose of an event; FSE_CLASS_* properties indicate the impact an event might have on a system; FSE_DATA_* properties describe attributes of the data attached to the event.

Properties of events aren't exclusive; some events may have two class properties.

FSE_TYPE_DEBUG
Not currently used.
FSE_TYPE_GENERAL
General purpose events are those that an event handler may be interested in. Most events have this property.
FSE_TYPE_TRACE
Reserved for tracking code execution.
FSE_TYPE_INTERNAL
Internal events are reserved for future use.
FSE_DATA_ZSTRING
The event's data is a number of zero-byte terminated strings. Lack of this property suggests the event data is binary, but that depends on the specific event.
FSE_CLASS_UPDATE
A change has resulted or may result from the event.
FSE_CLASS_UPDATE2
A change has resulted or may result from the event.
FSE_CLASS_ACCESS
The event doesn't result in a change. For instance, a read from a file, or an open as read-only is an access class.
FSE_CLASS_INFO
Events that are informational only (e.g., a stat() of a file).
FSE_CLASS_PRIVATE
Reserved for internal use only.

Locales

Locales indicate the source of the event. An event can have only a single locale. In general, event client handlers filter out those events that don't match the locale that they're monitoring.

FSE_LOCALE_BLOCK
Reserved for use by the block-level operations, cache, and partition level operations.
FSE_LOCALE_EVMGR
The source of the event was the event manager. This may be used for debugging purposes or for events that are injected directly through use of the fsevmgr itself.
FSE_LOCALE_EXT
The event came from somewhere outside the io-blk.so filesystem.
FSE_LOCALE_FSYS
Not currently used.
FSE_LOCALE_SYSCALL
Most notable public entry points to the filesystems will have this locale. Events with this locale are often generic and apply to any filesystem.
FSE_LOCALE_VFS
Not currently used. The VFS locale describes events generated by io-blk.so and which are specific to its implementation. These might include specific ioctl() commands or specific mount operations.

Event IDs

Event IDs indicate the cause of the event and the data associated with it. If the event data includes any strings, they're null-terminated.

ID Properties Description
FSE_ID_CHECK   Used internally for testing.
FSE_ID_CHMOD FSE_TYPE_GENERAL, FSE_CLASS_UPDATE, FSE_DATA_ZSTRING Sent upon successful recording of a file's read, write, and execute modes. This event indicates only that a file mode bits might have changed. Mode information isn't available. The data consists of:
  • the mountpoint
  • the name of the file that changed
FSE_ID_CHOWN FSE_TYPE_GENERAL, FSE_CLASS_UPDATE, FSE_DATA_ZSTRING Sent on the successful recording of a file's ownership. Note this event indicates that the ownership information might have changed. Ownership information isn't available. The data consists of:
  • the mountpoint
  • the name of the file that changed
FSE_ID_CLOSE_OTHER   Reserved for future use.
FSE_ID_CLOSE_UPDATE FSE_TYPE_GENERAL, FSE_CLASS_UPDATE, FSE_DATA_ZSTRING The last close of a file handle that has write access to the inode generates this event. Note that this may not be the same file name that was reported in an earlier FSE_OPEN_UPDATE event. The data consists of:
  • the mountpoint
  • the name of the file
FSE_ID_CREATE   Reserved for future use.
FSE_ID_DEVCTL   Reserved for future use.
FSE_ID_FDINFO   Reserved for future use.
FSE_ID_FREE_SPACE FSE_TYPE_GENERAL, FSE_CLASS_UPDATE, FSE_DATA_ZSTRING The block I/O system attempts to estimate disk space usage based on IO_WRITE and IO_SPACE messages; when it estimates that a certain threshold has been crossed, it queries the filesystem for the real change. Once the real change is confirmed to be above a certain threshold, a FSE_ID_FREE_SPACE event is emitted. The data consists of:
  • the mountpoint
  • the amount of free space, in bytes (as a string converted from an unsigned 64-bit integer)
FSE_ID_LINK FSE_TYPE_GENERAL, FSE_CLASS_UPDATE, FSE_DATA_ZSTRING The link field indicates a filename has successfully been created and associated with an inode. The target file name is unknown. The data consists of:
  • the mountpoint
  • the name of the file that was created
FSE_ID_MKDIR FSE_TYPE_GENERAL, FSE_CLASS_UPDATE, FSE_DATA_ZSTRING A directory (or node) has been successfully created within the filesystem. The data consists of:
  • the mountpoint
  • the name of the new directory
FSE_ID_MOUNT FSE_TYPE_GENERAL, FSE_CLASS_INFO, FSE_DATA_ZSTRING A volume has been successfully mounted (e.g., mount /dev/umass0 /fs/usb0). The data consists of:
  • the block special device (e.g., /dev/hd0)
  • the mountpoint (e.g., /fs/dos)
FSE_ID_OPENFD   Reserved for future use.
FSE_ID_OPEN_OTHER   Reserved for future use.
FSE_ID_OPEN_UPDATE FSE_TYPE_GENERAL, FSE_CLASS_UPDATE, FSE_DATA_ZSTRING The open update event is a result of the first open of an inode which includes write access. Subsequent opens with write access of the inode (regardless of the source file name) aren't reported. Note that if the inode is opened again, but through a different link, there will be no additional event. The data consists of:
  • the mountpoint
  • the source file name
FSE_ID_READ   Reserved for future use.
FSE_ID_READLINK   Reserved for future use.
FSE_ID_RENAME FSE_TYPE_GENERAL, FSE_CLASS_UPDATE, FSE_DATA_ZSTRING Sent as a result of a successful renaming operation within a single filesystem. Renaming operations across filesystems are generally implemented as a copy and delete sequence. The data consists of:
  • the mountpoint
  • the original file name
  • the new file name
FSE_ID_SEEK   Reserved for future use.
FSE_ID_STAT   Reserved for future use.
FSE_ID_TRUNCATE FSE_TYPE_GENERAL, FSE_CLASS_UPDATE, FSE_DATA_ZSTRING Sent upon a truncate operation that results in a change to a file size. The data consists of:
  • the mountpoint
  • the name of the file whose size has changed
FSE_ID_UNLINK FSE_TYPE_GENERAL, FSE_CLASS_UPDATE, FSE_DATA_ZSTRING Sent as a result of a successful unlink operation. The data consists of:
  • the mountpoint
  • the file name that's been deleted
FSE_ID_UNMOUNT FSE_TYPE_GENERAL, FSE_CLASS_ACCESS, FSE_DATA_ZSTRING A volume has been successfully unmounted. The data consists of:
  • the block special device (e.g., /dev/hd0)
  • the mountpoint (e.g., /fs/dos)
FSE_ID_WRITE   Reserved for future use.

Here's an example of extracting the information associated with an event:

char *data, *mntpath, *spacestr;
size_t len;
uint64_t freespace;

if (FSE_ID_VAL(event) == FSE_ID_FREE_SPACE)
{
    data = FSE_DATA_PTR(event);
    len  = FSE_DATA_LEN(event);

    /*  Determine the starting buffer offsets for the mount path and freespace
        integer value.
    */
    mntpath  = data;
    spacestr = data + strlen(mntpath) + 1;

    /*  If the path exceeds the data buffer, then there's no freespace value
        present.
    */
    if (spacestr >= (data + len)) {
        LOG(LOG_ERROR, "freespace data exceeds event buffer length (%p >= %p)",
            spacestr, data+len);
        return;
    }
    /*  Convert the freespace string to a 64-bit unsigned integer value.
    */
    else if (sscanf(spacestr, "%" PRIu64, &freespace) != 1) {
        LOG(LOG_ERROR, "freespace data conversion failed");
        return;
    }
}

Notes

There are several unique situations that clients of the event manager should be aware of:

Initializing events

If your client application has opened the event manager's device for writing, you can inject events. You can initialize an event structure by using the FSE_INIT_EVENT() macro:

#define FSE_INIT_EVENT(p, cmd, loc, id, prop, len)...

The arguments are:

p
A pointer to the fsev_t structure that you want to initialize.
cmd
The command indicating the operation to complete (FSE_CMD_*).
loc
An indicator of the source of the event (FSE_LOCALE_*).
id
A specific event identifier (FSE_ID_*).
prop
Properties of this event (a bitwise OR of the appropriate FSE_TYPE_*, FSE_CLASS_*, and FSE_DATA_* bits).
len
The length, in bytes, of the data that's associated with this event.

The event manager checks the event data to ensure it's well-formed; if it isn't, the event manager aborts the writing of all events that were sent in the write operation.