Search code examples
clinuxfilesystemsmountprocfs

Monitoring mount point changes via /proc/mounts


According proc manual, one can monitor for mount point changes in linux system by opening "/proc/mounts", and adding the file descriptor to read fd_set in select() call.

Following piece of code works on Ubuntu 9.04, and not in Ubuntu 10.04 (with 2.6.32 linux kernel):

int mfd = open("/proc/mounts", O_RDONLY, 0);

fd_set rfds;
struct timeval tv;
int rv;

FD_ZERO(&rfds);
FD_SET(mfd, &rfds);
tv.tv_sec = 5;
tv.tv_usec = 0;

int changes = 0;
while ((rv = select(mfd+1, &rfds, NULL, NULL, &tv)) >= 0) {
    if (FD_ISSET(mfd, &rfds)) {
        fprintf(stdout, "Mount points changed. %d.\n", changes++);
    }

    FD_ZERO(&rfds);
    FD_SET(mfd, &rfds);
    tv.tv_sec = 5;
    tv.tv_usec = 0;

    if (changes > 10) {
        exit(EXIT_FAILURE);
    }
}

Compilable snippet.

The file descriptor is always readable in one machine, and hence it keeps popping up in the select call. Even there are no changes in mounts.

Am I missing something here?

Thanks in advance for any help!

man 5 proc:

/proc/[pid]/mounts (since Linux 2.4.19)

This is a list of all the file systems currently mounted in the process's mount namespace. The format of this file is documented in fstab(5). Since kernel version 2.6.15, this file is pollable: after opening the file for reading, a change in this file (i.e., a file system mount or unmount) causes select(2) to mark the file descriptor as readable, and poll(2) and epoll_wait(2) mark the file as having an error condition.


Solution

  • There was a bugfix in linux kernel describing that behavior:

    SUSv3 says "Regular files shall always poll TRUE for reading and writing". see http://www.opengroup.org/onlinepubs/009695399/functions/poll.html

    So, you have to use poll with POLLPRI | POLLERR flags. Something like this:

    
         int mfd = open("/proc/mounts", O_RDONLY, 0);
         struct pollfd pfd;
         int rv;
    
         int changes = 0;
         pfd.fd = mfd;
         pfd.events = POLLERR | POLLPRI;
         pfd.revents = 0;
         while ((rv = poll(&pfd, 1, 5)) >= 0) {
              if (pfd.revents & POLLERR) {
                   fprintf(stdout, "Mount points changed. %d.\n", changes++);
              }
    
              pfd.revents = 0;
              if (changes > 10) {
                   exit(EXIT_FAILURE);
              }
         }