Skip to content

fs: implement inotify(2)#1440

Open
gburd wants to merge 2 commits into
cloudius-systems:masterfrom
gburd:pr/inotify
Open

fs: implement inotify(2)#1440
gburd wants to merge 2 commits into
cloudius-systems:masterfrom
gburd:pr/inotify

Conversation

@gburd

@gburd gburd commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

What

inotify was stubbed (inotify_init returned EMFILE, add_watch/rm_watch
returned EINVAL), so programs that watch the filesystem for changes could not
run.

How

Implemented against OSv's VFS. All path mutations route through a handful of
central functions in fs/vfs/vfs_syscalls.cc; those now call
osv_inotify_notify() with the absolute path affected and the event mask.
libc/inotify.cc keeps a registry of inotify instances (each a pollable
special_file, modeled on eventfd), matches every event against their watches,
and queues a struct inotify_event for the fd, waking any poller.

  • inotify_init/inotify_init1 create the fd (IN_CLOEXEC/IN_NONBLOCK
    honored).
  • inotify_add_watch resolves the path to absolute, adds (or merges, with
    IN_MASK_ADD) a watch, and returns a watch descriptor.
  • inotify_rm_watch removes a watch and queues IN_IGNORED.
  • read() returns as many packed inotify_event structures as fit in the
    buffer (blocking, or EAGAIN when non-blocking), rejecting a too-small buffer
    with EINVAL; poll() reports POLLIN when events are queued.

A directory watch fires for changes to entries within it (reporting the entry
name); a watch on the object itself fires with no name. Events wired:
IN_CREATE (mkdir, open O_CREAT), IN_DELETE (rmdir, unlink), IN_MOVED_FROM /
IN_MOVED_TO (rename), each with IN_ISDIR when the object is a directory. The
rename hook rebuilds the full destination path because sys_rename truncates
dest to its parent in place before the VOP.

Not yet covered (follow-ups): IN_MODIFY/IN_CLOSE_WRITE on writes (needs an
fd-to-path lookup), IN_ACCESS/IN_OPEN, and recursive watches.

Testing

tests/tst-inotify.cc covers create/delete/move on files and a subdirectory
(names and IN_ISDIR), IN_IGNORED on watch removal, and the EAGAIN/EINVAL
paths. Passes on OSv under KVM. tst-remove (unlink/rename/rmdir) continues to
pass, so the VFS mutation paths are unaffected.

(Recreated from #1422, which GitHub auto-closed when its branch was rebased onto current master. Same change, rebased and verified on master 3aba46c.)

@gburd gburd mentioned this pull request Jul 13, 2026
gburd added 2 commits July 15, 2026 08:35
inotify was stubbed (inotify_init returned EMFILE, add_watch/rm_watch returned
EINVAL), so programs that watch the filesystem for changes could not run.

Implement it against OSv's VFS.  All path mutations route through a handful of
central functions in fs/vfs/vfs_syscalls.cc; those now call osv_inotify_notify()
with the absolute path affected and the event mask.  libc/inotify.cc keeps a
registry of inotify instances (each a pollable special_file, modeled on
eventfd), matches every event against their watches, and queues a
struct inotify_event for the fd, waking any poller.

- inotify_init/inotify_init1 create the fd (IN_CLOEXEC/IN_NONBLOCK honored).
- inotify_add_watch resolves the path to absolute, adds (or merges, with
  IN_MASK_ADD) a watch, and returns a watch descriptor.
- inotify_rm_watch removes a watch and queues IN_IGNORED.
- read() returns as many packed inotify_event structures as fit in the buffer
  (blocking, or EAGAIN when non-blocking), rejecting a too-small buffer with
  EINVAL; poll() reports POLLIN when events are queued.

A directory watch fires for changes to entries within it (reporting the entry
name); a watch on the object itself fires with no name.  Events wired:
IN_CREATE (mkdir, open O_CREAT), IN_DELETE (rmdir, unlink), IN_MOVED_FROM /
IN_MOVED_TO (rename), each with IN_ISDIR when the object is a directory.

The rename hook rebuilds the full destination path because sys_rename truncates
`dest` to its parent in place before the VOP.

Not yet covered (follow-ups): IN_MODIFY/IN_CLOSE_WRITE on writes (needs an
fd-to-path lookup), IN_ACCESS/IN_OPEN, and recursive watches.

Add tests/tst-inotify.cc covering create/delete/move on files and a
subdirectory (names and IN_ISDIR), IN_IGNORED on watch removal, and the
EAGAIN/EINVAL paths.  Passes on OSv under KVM; tst-remove (unlink/rename/rmdir)
continues to pass, so the VFS mutation paths are unaffected.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant