---
title: fsnotify
sidebar_position: 0
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# fsnotify

The fsnotify gadget detects applications using inotify or fanotify and enriches the events with the process-related metadata.

This gadget requires Linux >= 5.4. Additionally, the field `i_ino` is only available in Linux >= 5.11.

## Requirements

- Minimum Kernel Version : 5.4

## Getting started

Running the gadget:

<Tabs groupId="env">
    <TabItem value="kubectl-gadget" label="kubectl gadget">
        ```bash
        $ kubectl gadget run ghcr.io/inspektor-gadget/gadget/fsnotify:%IG_TAG% [flags]
        ```
    </TabItem>

    <TabItem value="ig" label="ig">
        ```bash
        $ sudo ig run ghcr.io/inspektor-gadget/gadget/fsnotify:%IG_TAG% [flags]
        ```
    </TabItem>
</Tabs>
## Flags

### `--fanotify-only`

Show only fanotify events

Default value: ""

### `--inotify-only`

Show only inotify events

Default value: ""

### `--tracee-pid`

Show only fsnotify events generated by processes with this pid

Default value: ""

### `--tracer-group`

Show only fsnotify events generated by a struct fsnotify_group with this address. You can find this address in Golang with kfilefields.ReadPrivateDataFromFd(). See https://pkg.go.dev/github.com/inspektor-gadget/inspektor-gadget/pkg/kfilefields#ReadPrivateDataFromFd

Default value: ""

### `--tracer-pid`

Show only fsnotify events generated for processes with this pid

Default value: ""

## Guide

### Example with inotify

Start an application using inotify:
```bash
inotifywatch /tmp/
```

You can generate events in another terminal with:
```bash
touch /tmp/ABCDE
```

The fsnotify gadget can observe and enrich the inotify events in the following way:
```bash
$ sudo ig run ghcr.io/inspektor-gadget/gadget/fsnotify:%IG_TAG% --inotify-only --fields=tracer_comm,tracee_comm,i_mask,name
TRACER_COMM    TRACEE_COMM   I_MASK      NAME
inotifywatch   touch         0x8000020   ABCDE
inotifywatch   touch         0x8000004   ABCDE
inotifywatch   touch         0x8000008   ABCDE
```

The mask uses the same flags as inotify (`IN_ACCESS`, etc.) + some internal ones:
```bash
134217760 = 0x08000020 = FS_OPEN | FS_EVENT_ON_CHILD
134217732 = 0x08000004 = FS_ATTRIB | FS_EVENT_ON_CHILD
134217736 = 0x08000008 = FS_CLOSE_WRITE | FS_EVENT_ON_CHILD
```

### Example with fanotify

ig itself uses fanotify to watch containers. You can generate events in another terminal with:
```bash
docker run -ti --rm busybox date
```

The fsnotify gadget can observe and enrich the fanotify events in the following way:
```bash
$ sudo ig run ghcr.io/inspektor-gadget/gadget/fsnotify:%IG_TAG% --fanotify-only --fields=tracer_comm,tracee_comm,type,fa_type,fa_response,name
TRACER_COMM  TRACEE_COMM      TYPE       FA_TYPE                         FA_RESPONSE   NAME
ig           containerd-shim  fanotify   FANOTIFY_EVENT_TYPE_PATH_PERM   na            /usr/bin/runc
ig           containerd-shim  fa_resp    FANOTIFY_EVENT_TYPE_PATH_PERM   allow         /usr/bin/runc
ig           containerd-shim  fanotify   FANOTIFY_EVENT_TYPE_PATH_PERM   na            /run/containerd/io.containerd.runtime.v2.task/mob…
ig           containerd-shim  fa_resp    FANOTIFY_EVENT_TYPE_PATH_PERM   allow         /run/containerd/io.containerd.runtime.v2.task/mob…
ig           containerd-shim  fanotify   FANOTIFY_EVENT_TYPE_PATH_PERM   na            /usr/bin/runc
ig           containerd-shim  fa_resp    FANOTIFY_EVENT_TYPE_PATH_PERM   allow         /usr/bin/runc
ig           containerd-shim  fanotify   FANOTIFY_EVENT_TYPE_PATH_PERM   na            /usr/bin/runc
ig           containerd-shim  fa_resp    FANOTIFY_EVENT_TYPE_PATH_PERM   allow         /usr/bin/runc
ig           containerd-shim  fanotify   FANOTIFY_EVENT_TYPE_PATH_PERM   na            /usr/bin/runc
ig           containerd-shim  fa_resp    FANOTIFY_EVENT_TYPE_PATH_PERM   allow         /usr/bin/runc
```

## Architecture

```mermaid
sequenceDiagram
    box Programs
        participant Tracer
        participant Tracee
    end
    box Maps
        participant fsnotify_insert_event_ctx
        participant enriched_fsnotify_events
        participant fsnotify_remove_first_event_ctx
        participant events ring buffer
    end

alt inotify
    Note over Tracee: kprobe/inotify_handle_inode_event
    Activate Tracee
        rect rgba(0, 0, 255, .1)
        Tracee ->> fsnotify_insert_event_ctx: insert into hash table<br/>Key: pid<br/>Value: {type=inotify, ino=123...}
        Activate fsnotify_insert_event_ctx
    end
else fanotify
    Note over Tracee: kprobe/fanotify_handle_event
    rect rgba(0, 0, 255, .1)
        Tracee ->> fsnotify_insert_event_ctx: insert into hash table<br/>Key: pid<br/>Value: {type=fanotify, ino=123...}
    end
end

    Note over Tracee: kprobe/fsnotify_insert_event<br/>Input: struct fsnotify_group *group, struct fsnotify_event *event
    Activate Tracee
    rect rgba(0, 0, 255, .1)
        Tracee ->> fsnotify_insert_event_ctx: lookup from hash table<br/>Key: pid<br/>Value: {type, ino...}
        Tracee ->> enriched_fsnotify_events: insert into hash table<br/>Key: fsnotify_event<br/>Value: {filename, tracee_comm, ...}
        Activate enriched_fsnotify_events
    end
    Deactivate Tracee

alt inotify
    Note over Tracee: kretprobe/inotify_handle_inode_event
    rect rgba(0, 0, 255, .1)
        Tracee ->> fsnotify_insert_event_ctx: delete entry from hash table<br/>Key: pid
    end
else fanotify
    Note over Tracee: kretprobe/fanotify_handle_event
    rect rgba(0, 0, 255, .1)
        Tracee ->> fsnotify_insert_event_ctx: delete entry from hash table<br/>Key: pid
        Deactivate fsnotify_insert_event_ctx
    end
end
    Deactivate Tracee

    Note over Tracer: kprobe/fsnotify_remove_first_event<br/>Input: struct fsnotify_group *group
    Activate Tracer
    rect rgba(0, 0, 255, .1)
        Tracer ->> fsnotify_remove_first_event_ctx: insert into hash table<br/>Key: pid<br/>Value: fsnotify_group pointer
        Activate fsnotify_remove_first_event_ctx
    end

    Note over Tracer: kretprobe/fsnotify_remove_first_event<br/>Returns: struct fsnotify_event *event
    rect rgba(0, 0, 255, .1)
        Tracer ->> fsnotify_remove_first_event_ctx: lookup+delete from hash table<br/>Key: pid
        Deactivate fsnotify_remove_first_event_ctx
        Tracer ->> enriched_fsnotify_events: lookup from hash table<br/>Key: fsnotify_event<br/>Value: {filename, tracee_comm, ...}
        Tracer ->> events ring buffer: submit event to ring buffer<br/>type = fanotify | inotify
        Note over events ring buffer: Inspektor Gadget<br/>receives the event
    end
    Deactivate Tracer

    Note over Tracee: kprobe/fsnotify_destroy_event<br/>Input: struct fsnotify_group *group, struct fsnotify_event *event
    Activate Tracee
    rect rgba(0, 0, 255, .1)
        alt inotify or fanotify
        Note over events ring buffer: Nothing to send
        else fanotify_perm_response
        Tracee ->> events ring buffer: submit event to ring buffer<br/>type = fanotify_perm_response
        Note over events ring buffer: Inspektor Gadget<br/>receives the event
        end
        Tracee ->> enriched_fsnotify_events: delete from hash table<br/>Key: fsnotify_event
        Deactivate enriched_fsnotify_events
    end
    Deactivate Tracee
```
