Part 5 โ€“ dnotify vs inotify

 

๐Ÿ”„ Part 5 โ€“ dnotify vs inotify
The old mechanism vs the modern one โ€” and why inotify won

What is dnotify?

Before inotify, Linux had a mechanism called dnotify (directory notify), available since kernel 2.4. It let applications monitor directories for changes. However, dnotify had so many limitations that the Linux kernel developers created inotify as a complete replacement. dnotify is now considered obsolete.

You will still encounter dnotify references in older codebases and interview questions, so it is worth understanding what it did wrong.

How dnotify Works (Brief Overview)

dnotify uses the fcntl() system call with the F_NOTIFY command:

#include <fcntl.h>
#include <signal.h>

/* Step 1: Open the directory you want to watch */
int dir_fd = open("/tmp/mydir", O_RDONLY);

/* Step 2: Request notification via signal (default: SIGIO) */
fcntl(dir_fd, F_NOTIFY, DN_CREATE | DN_DELETE | DN_MODIFY);

/* When something changes in /tmp/mydir, your process receives SIGIO */
/* You must set up a signal handler to process it */

dnotify sends a real-time signal (or SIGIO) to your process when something in the watched directory changes. Your signal handler then has to figure out what changed.

Side-by-Side Comparison
Feature โŒ dnotify โœ… inotify
Notification method Signals (SIGIO or real-time signal) โ€” complicates design File descriptor โ€” clean read() API
Granularity Directory only โ€” you know something changed but not which file Directory OR individual file โ€” exact filename returned
File descriptor overhead Requires an open fd for each watched directory. Busy fs can’t be unmounted. One fd for the entire inotify instance, regardless of how many paths are watched
Unmount-safe No โ€” open fd keeps filesystem busy, blocking umount Yes โ€” sends IN_UNMOUNT event and removes watch
Event detail Tells you an event type (create/delete/modify) but not the filename involved Returns the exact filename, event type, and cookie for renames
Reliability Unreliable in some circumstances โ€” events can be missed Reliable ordered event queue with overflow detection
Library use Very difficult โ€” signal handlers conflict with the calling program’s signal setup Works cleanly in libraries โ€” just another fd
Available since Kernel 2.4 Kernel 2.6.13
Status today Obsolete โ€” avoid in new code Recommended โ€” use this

The Deep Problem with Signal-Based Notification

The biggest design flaw of dnotify is using signals for notification. Here is why that is bad:

Problem 1 โ€“ Signal handlers are process-wide: If you use dnotify inside a library, and your signal handler for SIGIO conflicts with the calling application’s signal handler, one of them will silently stop working. There is no way to give each component its own private signal.
Problem 2 โ€“ Async-signal-safety restrictions: Inside a signal handler, you can only call a tiny set of “async-signal-safe” functions. You cannot call printf(), malloc(), or most library functions safely. This makes it very hard to do anything useful in response to a dnotify event.
Problem 3 โ€“ Race conditions: Signals can arrive at any time, interrupting your main code at random points. Properly synchronizing between signal handlers and main code requires careful use of volatile sig_atomic_t flags and is easy to get wrong.
inotify solves all of this: No signals, no conflict. Your program reads from the inotify fd at its own pace, using the normal read() call or integrating with select()/epoll naturally.

The File Descriptor Overhead Problem

With dnotify, you must keep an open file descriptor for each directory you watch:

โŒ dnotify โ€” 1 fd per directory
/home/ravi โ†’ fd=5
/home/ravi/docs โ†’ fd=6
/home/ravi/pics โ†’ fd=7
/etc โ†’ fd=8
10000 dirs = 10000 open fds!
โœ… inotify โ€” 1 fd for everything
inotify fd=5
wd=1 โ†’ /home/ravi
wd=2 โ†’ /home/ravi/docs
wd=3 โ†’ /home/ravi/pics
wd=4 โ†’ /etc
10000 dirs = still 1 fd!

The dnotify approach hits the per-process file descriptor limit (ulimit -n, usually 1024 or 4096) very quickly on large directory trees. inotify has no such problem.

๐Ÿ’ป Code Comparison โ€“ dnotify vs inotify

Here is the same task โ€” “tell me when a file is created in /tmp/mydir” โ€” implemented both ways:

โŒ dnotify approach (old, complex, signal-based):

#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <dirent.h>
#include <string.h>
#include <unistd.h>

static int dir_fd;
static char known_files[1000][256];
static int known_count = 0;

/* Signal handler โ€” very limited in what it can do here */
static void dnotify_handler(int sig)
{
    /* We know SOMETHING changed but NOT WHAT.
       Must rescan the entire directory! */
    DIR *d = opendir("/tmp/mydir");   /* Warning: not safe in signal handler! */
    struct dirent *entry;
    while ((entry = readdir(d)) != NULL) {
        /* Compare against known_files to find what's new */
        /* This is complex, error-prone, and racy */
    }
    closedir(d);
}

int main(void)
{
    signal(SIGIO, dnotify_handler);

    /* Must open the directory with a real fd */
    dir_fd = open("/tmp/mydir", O_RDONLY);
    if (dir_fd == -1) { perror("open"); return 1; }

    /* Request notification */
    fcntl(dir_fd, F_SETSIG, SIGIO);
    fcntl(dir_fd, F_NOTIFY, DN_CREATE | DN_MULTISHOT);

    /* Main loop โ€” must handle async signal interruptions */
    for (;;) { pause(); }

    close(dir_fd);
    return 0;
}

โœ… inotify approach (modern, clean, fd-based):

#include <sys/inotify.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define BUF_SIZE 4096

int main(void)
{
    int fd = inotify_init1(IN_CLOEXEC);
    inotify_add_watch(fd, "/tmp/mydir", IN_CREATE);

    char buf[BUF_SIZE];
    ssize_t n = read(fd, buf, BUF_SIZE);  /* blocks until event */

    struct inotify_event *event = (struct inotify_event *) buf;
    /* We know EXACTLY which file was created */
    printf("Created: %s\n", event->name);

    close(fd);
    return 0;
}

The inotify version is shorter, cleaner, and gives you the exact filename directly, with no signal handler complexity.

Summary โ€“ Why inotify Replaced dnotify
dnotify Limitation inotify Solution
Uses signals โ€” complicated and library-unfriendly Uses file descriptor โ€” fits naturally into any event loop
Only watches directories, not individual files Watches files and directories
Doesn’t tell you which file changed inside the directory Gives you the exact filename in the name field
Requires one open fd per watched directory One fd for all watches in one inotify instance
Open fd prevents unmounting of filesystem No open fds on watched paths; graceful unmount handling
Unreliable in some edge cases Reliable ordered queue with overflow reporting

Final Step: Interview Questions

Test your knowledge with 20+ interview questions on inotify covering all topics.

Interview Q&A โ†’ โ† Part 4

Leave a Reply

Your email address will not be published. Required fields are marked *