From alexl@redhat.com Wed Feb 4 08:21:21 2004 Received: with ECARTIS (v1.0.0; list fam); Wed, 04 Feb 2004 08:21:31 -0800 (PST) Received: from mx1.redhat.com (mx1.redhat.com [66.187.233.31]) by oss.sgi.com (8.12.10/8.12.9) with SMTP id i14GLKKO009982 for ; Wed, 4 Feb 2004 08:21:20 -0800 Received: from int-mx1.corp.redhat.com (int-mx1.corp.redhat.com [172.16.52.254]) by mx1.redhat.com (8.11.6/8.11.6) with ESMTP id i14Fahb18429 for ; Wed, 4 Feb 2004 10:36:43 -0500 Received: from devserv.devel.redhat.com (devserv.devel.redhat.com [172.16.58.1]) by int-mx1.corp.redhat.com (8.11.6/8.11.6) with ESMTP id i14Faga22742 for ; Wed, 4 Feb 2004 10:36:43 -0500 Received: from localhost (sebastian-int.corp.redhat.com [172.16.52.221]) by devserv.devel.redhat.com (8.12.10/8.12.10) with ESMTP id i14FaCkC010471 for ; Wed, 4 Feb 2004 10:36:12 -0500 Subject: new dnotify patc From: Alexander Larsson To: fam@oss.sgi.com Content-Type: multipart/mixed; boundary="=-yaPmd/An3u6aVmsTUeP2" Message-Id: <1075909001.4965.16.camel@localhost.localdomain> Mime-Version: 1.0 X-Mailer: Ximian Evolution 1.3.92 (Preview Release) Date: 04 Feb 2004 16:36:41 +0100 X-archive-position: 216 X-ecartis-version: Ecartis v1.0.0 Sender: fam-bounce@oss.sgi.com Errors-to: fam-bounce@oss.sgi.com X-original-sender: alexl@redhat.com Precedence: bulk X-list: fam --=-yaPmd/An3u6aVmsTUeP2 Content-Type: text/plain Content-Transfer-Encoding: 7bit There is a bug in the dnotify patch that sometimes made it leak monitors on files. This happens when a file with the same device/inode shows up in two directories (either because of a hardlink, or because the file was moved and we read the new file before forgetting the old one). Here is a new version of the patch, against fam 2.6.10, that fixes this issue. I've added it to the redhat rpm, and i've done some minimal testing. It seems to work. An easy way to reproduce the bug is: mkdir /tmp/x mkdir /tmp/y echo "test" > /tmp/x/file1 ln /tmp/x/file1 /tmp/y/file2 (fam_test -f /tmp/y/file2& fam_test -f /tmp/x/file1) Now fam will have an fd open, but no clients. (fam_test is built from test/test.c++ in the fam sources) ( =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= Alexander Larsson Red Hat, Inc alexl@redhat.com alla@lysator.liu.se He's a benighted Catholic waffle chef with nothing left to lose. She's a transdimensional bisexual bounty hunter with a knack for trouble. They fight crime! --=-yaPmd/An3u6aVmsTUeP2 Content-Disposition: attachment; filename=fam-2.6.10-dnotify.patch Content-Type: text/x-patch; name=fam-2.6.10-dnotify.patch; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit --- /dev/null 2003-09-15 15:40:47.000000000 +0200 +++ fam-2.6.10/fam/DNotify.c++ 2004-02-04 11:13:04.000000000 +0100 @@ -0,0 +1,655 @@ +// Copyright (C) 2001 Red Hat, Inc. All Rights Reserved. +// Copyright (C) 1999 Silicon Graphics, Inc. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of version 2 of the GNU General Public License as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it would be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Further, any +// license provided herein, whether implied or otherwise, is limited to +// this program in accordance with the express provisions of the GNU +// General Public License. Patent licenses, if any, provided herein do not +// apply to combinations of this program with other product or programs, or +// any other product whatsoever. This program is distributed without any +// warranty that the program is delivered free of the rightful claim of any +// third person by way of infringement or the like. See the GNU General +// Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write the Free Software Foundation, Inc., 59 +// Temple Place - Suite 330, Boston MA 02111-1307, USA. + +#define _GNU_SOURCE +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "DNotify.h" + +#include "Interest.h" +#include "Log.h" +#include "Scheduler.h" +#include "alloc.h" + + +int DNotify::pipe_write_fd = -2; +int DNotify::pipe_read_fd = -2; +volatile sig_atomic_t DNotify::queue_overflowed = 0; +volatile sig_atomic_t DNotify::queue_changed = 0; +int DNotify::change_queue[QUEUESIZE]; +volatile int DNotify::queue_head = 0; // Only modified by read handler +volatile int DNotify::queue_tail = 0; // Only modified by signal handler +DNotify::EventHandler DNotify::ehandler; + +DNotify::DirWatch *DNotify::dir_hash[DIR_HASHSIZE]; +DNotify::FileWatch *DNotify::file_hash[FILE_HASHSIZE]; + +struct DNotify::FileWatch +{ + DirWatch **dir_watch; + int n_dir_watches; + dev_t file_dev; + ino_t file_ino; + FileWatch *hash_link; + + FileWatch(void) { + dir_watch = NULL; + n_dir_watches = 0; + } + + void add_dir_watch (DirWatch *w); + bool has_dir_watch (DirWatch *w); +}; + + +struct DNotify::DirWatch +{ + class FileWatchList { + public: + struct Node { + FileWatch *watch; + Node *next; + }; + + Node *first; + + FileWatchList(void) { + first = NULL; + } + + void prepend(FileWatch *watch); + void remove(FileWatch *watch); + bool empty(void); + int len(void); + + }; + + dev_t dir_dev; + ino_t dir_ino; + int fd; + + DirWatch *hash_link; + FileWatchList file_watches; +}; + +struct DNotify::ChangeEventData +{ + dev_t file_dev; + ino_t file_ino; +}; + +bool +DNotify::FileWatch::has_dir_watch (DirWatch *w) +{ + int i; + + for (i = 0; i < n_dir_watches; i++) { + if (dir_watch[i] == w) + return true; + } + return false; +} + + +void +DNotify::FileWatch::add_dir_watch (DirWatch *w) +{ + n_dir_watches++; + dir_watch = (DirWatch **)realloc (dir_watch, n_dir_watches*sizeof(DirWatch *)); + dir_watch[n_dir_watches-1] = w; +} + +bool +DNotify::DirWatch::FileWatchList::empty(void) +{ + return first == NULL; +} + +int +DNotify::DirWatch::FileWatchList::len(void) +{ + int i; + Node *n; + + i = 0; + n = first; + while (n) { + i++; + n = n->next; + } + + return i; +} + + +void +DNotify::DirWatch::FileWatchList::prepend(FileWatch *watch) +{ + Node *node; + + node = new Node; + node->watch = watch; + node->next = first; + + first = node; +} + +void +DNotify::DirWatch::FileWatchList::remove(FileWatch *watch) { + Node *l, *prev; + + l = first; + prev = NULL; + while (l) { + if (l->watch == watch) { + if (prev) + prev->next = l->next; + else + first = l->next; + + delete l; + break; + } + prev = l; + l = prev->next; + } +} + + +DNotify::DNotify(EventHandler h) +{ + assert(ehandler == NULL); + ehandler = h; +} + +DNotify::~DNotify() +{ + if (pipe_read_fd >= 0) { + // Tell the scheduler. + + (void) Scheduler::remove_read_handler(pipe_read_fd); + + // Close the pipe. + + if (close(pipe_read_fd) < 0) + Log::perror("can't pipe read end"); + else + Log::debug("closed pipe read end"); + + if (close(pipe_write_fd) < 0) + Log::perror("can't pipe write end"); + else + Log::debug("closed pipe write end"); + pipe_read_fd = -1; + } + ehandler = NULL; +} + +void +DNotify::overflow_signal_handler(int sig, siginfo_t *si, void *data) +{ + char c = 'x'; + + { + char *str = "*************** overflow sigqueue ***********************\n"; + write (STDERR_FILENO, str, strlen(str)); + } + + if (!queue_overflowed) { + queue_overflowed = 1; + // Trigger the read handler + write(pipe_write_fd, &c, 1); + } +} + +void +DNotify::signal_handler(int sig, siginfo_t *si, void *data) +{ + int left; + char c = 'x'; + + if (queue_head <= queue_tail) + left = (QUEUESIZE + queue_head) - queue_tail; + else + left = queue_head - queue_tail; + + // Must leave at least one item unused to see difference + // Betweeen empty and full + if (left <= 1) { + queue_overflowed = 1; + { + char *str = "*************** overflow famqueue ****************\n"; + write (STDERR_FILENO, str, strlen(str)); + } + } else { + change_queue[queue_tail] = si->si_fd; + queue_tail = (queue_tail + 1) % QUEUESIZE; + } + + if (!queue_changed) { + queue_changed = 1; + // Trigger the read handler + write(pipe_write_fd, &c, 1); + } +} + +bool +DNotify::is_active() +{ + if (pipe_read_fd == -2) { + int filedes[2]; + int res; + + res = pipe (filedes); + if (res >= 0) { + Log::debug("opened pipe"); + pipe_read_fd = filedes[0]; + pipe_write_fd = filedes[1]; + + // Setup signal handler: + struct sigaction act; + + act.sa_sigaction = signal_handler; + sigemptyset(&act.sa_mask); + act.sa_flags = SA_SIGINFO; + sigaction(SIGRTMIN, &act, NULL); + + // When the RT queue overflows we get a SIGIO + act.sa_sigaction = overflow_signal_handler; + sigemptyset(&act.sa_mask); + sigaction(SIGIO, &act, NULL); + + (void) Scheduler::install_read_handler(pipe_read_fd, read_handler, NULL); + } + } + return pipe_read_fd >= 0; +} + +DNotify::DirWatch * +DNotify::lookup_dirwatch (int fd) +{ + DirWatch **p; + DirWatch *w; + + p = dir_hashchain (fd); + + while (*p) { + w = *p; + + if (w->fd == fd) + return w; + + p = &w->hash_link; + } + + return *p; +} + +// This colud be made faster by using another hash table. +// But it's not that bad, since it is only used by express/revoke +DNotify::DirWatch * +DNotify::lookup_dirwatch (dev_t dir_dev, ino_t dir_ino) +{ + DirWatch *p; + int i; + + for (i=0;idir_dev == dir_dev && p->dir_ino == dir_ino) + return p; + + p = p->hash_link; + } + } + + return NULL; +} + +DNotify::FileWatch * +DNotify::lookup_filewatch (dev_t dev, ino_t ino) +{ + FileWatch **p; + FileWatch *w; + + p = file_hashchain (dev, ino); + + while (*p) { + w = *p; + + if (w->file_dev == dev && w->file_ino == ino) + return w; + + p = &w->hash_link; + } + + return *p; +} + +// Make sure w is not already in the hash table before calling +// this function. +void +DNotify::hash_dirwatch(DirWatch *w) +{ + DirWatch **p; + p = dir_hashchain (w->fd); + w->hash_link = *p; + *p = w; +} + +// Make sure w is not already in the hash table before calling +// this function. +void +DNotify::hash_filewatch(FileWatch *w) +{ + FileWatch **p; + p = file_hashchain (w->file_dev, w->file_ino); + w->hash_link = *p; + *p = w; +} + +void +DNotify::unhash_dirwatch(DirWatch *w) +{ + DirWatch **p; + + p = dir_hashchain (w->fd); + + while (*p) { + if (*p == w) { + *p = w->hash_link; + break; + } + p = &(*p)->hash_link; + } + w->hash_link = NULL; +} + +void +DNotify::unhash_filewatch(FileWatch *w) +{ + FileWatch **p; + + p = file_hashchain (w->file_dev, w->file_ino); + + while (*p) { + if (*p == w) { + *p = w->hash_link; + break; + } + p = &(*p)->hash_link; + } + w->hash_link = NULL; +} + +DNotify::Status +DNotify::watch_dir(const char *notify_dir, dev_t file_dev, ino_t file_ino) +{ + struct stat stat; + dev_t dir_dev; + ino_t dir_ino; + DirWatch *dwatch; + FileWatch *fw; + + if (lstat (notify_dir, &stat) == -1) + return BAD; + + dwatch = lookup_dirwatch(stat.st_dev, stat.st_ino); + if (!dwatch) { + Log::debug ("New DirWatch for %s (%x %x)\n", + notify_dir, (int)stat.st_dev, (int)stat.st_ino); + dwatch = new DirWatch; + dwatch->hash_link = NULL; + dwatch->dir_dev = stat.st_dev; + dwatch->dir_ino = stat.st_ino; + dwatch->fd = open(notify_dir, O_RDONLY); + fcntl (dwatch->fd, F_SETSIG, SIGRTMIN); + fcntl (dwatch->fd, F_NOTIFY, + (DN_MODIFY|DN_CREATE|DN_DELETE|DN_RENAME|DN_ATTRIB) | DN_MULTISHOT); + hash_dirwatch (dwatch); + } + + fw = lookup_filewatch(file_dev, file_ino); + if (fw) { + if (!fw->has_dir_watch(dwatch)) { + fw->add_dir_watch(dwatch); + dwatch->file_watches.prepend(fw); + } + return OK; + } + + // No old FileWatch, need to add one: + Log::debug("New FileWatch for %x %x\n", (int)file_dev, (int)file_ino); + fw = new FileWatch; + fw->add_dir_watch(dwatch); + dwatch->file_watches.prepend(fw); + fw->file_dev = file_dev; + fw->file_ino = file_ino; + hash_filewatch(fw); + return OK; +} + +char * +dirname_dup (const char *name) +{ + char *copy = strdup(name); + char *res = dirname(copy); + res = strdup(res); + free (copy); + return res; +} + +DNotify::Status +DNotify::express(const char *name, struct stat *status) +{ + struct stat stat; + char *notify_dir; + int res; + Status s; + dev_t dev; + ino_t ino; + + Log::debug("express() name: %s\n", name); + + if (!is_active()) + return BAD; + + if (::lstat (name, &stat) == -1) + return BAD; + + dev = stat.st_dev; + ino = stat.st_ino; + + if ((stat.st_mode & S_IFMT) != S_IFDIR) + notify_dir = dirname_dup (name); + else + notify_dir = (char *)name; + + s = watch_dir (notify_dir, dev, ino); + if (notify_dir != name) + free (notify_dir); + if (s) + return s; + + // Check for a race condition; if someone removed or changed the + // file at the same time that we are expressing interest in it, + // revoke the interest so we don't get notifications about changes + // to a recycled inode that we don't otherwise care about. + // + struct stat st; + if (status == NULL) { + status = &st; + } + if (::lstat(name, status) == -1) { + Log::perror("stat on \"%s\" failed", name); + revoke(name, stat.st_dev, stat.st_ino); + return BAD; + } + if (status->st_dev != stat.st_dev + || status->st_ino != stat.st_ino) { + Log::error("File \"%s\" changed between express and stat", + name); + revoke(name, stat.st_dev, stat.st_ino); + return BAD; + } + + Log::debug("told dnotify to monitor \"%s\" = dev %d/%d, ino %d", name, + major(status->st_dev), minor(status->st_dev), + status->st_ino); + return OK; +} + +DNotify::Status +DNotify::revoke(const char *name, dev_t dev, ino_t ino) +{ + FileWatch *fwatch; + DirWatch *dwatch; + int i; + + Log::debug("revoke() name: %s, dev: %x, ino: %x\n", name, dev, ino); + + if (!is_active()) + return BAD; + + // Lookup FileWatch by dev:ino, and its DirWatch. + fwatch = lookup_filewatch (dev, ino); + if (fwatch == NULL) + return BAD; + + // delete FileWatch, if last FileWatch: close fd, delete DirWatch + Log::debug ("Destroying FileWatch for (%x %x)\n", + (int)fwatch->file_dev, (int)fwatch->file_ino); + for (i = 0; i < fwatch->n_dir_watches; i++) { + dwatch = fwatch->dir_watch[i]; + dwatch->file_watches.remove (fwatch); + + if (dwatch->file_watches.empty()) { + Log::debug ("Destroying DirWatch for (%x %x)\n", + (int)dwatch->dir_dev, (int)dwatch->dir_ino); + close(dwatch->fd); + unhash_dirwatch(dwatch); + delete dwatch; + } + } + unhash_filewatch(fwatch); + delete fwatch; + + return OK; +} + + +void +DNotify::all_watches_changed(void) +{ + int i; + FileWatch *fw; + + for (i=0; ifile_dev, fw->file_ino, CHANGE); + + fw = fw->hash_link; + } + } +} + + +void +DNotify::read_handler(int fd, void *) +{ + static char readbuf[5000]; + DirWatch *dw; + FileWatch *fw; + int snap_queue_tail; + int last_fd; + + int rc = read(fd, readbuf, sizeof readbuf); + queue_changed = 0; + if (rc < 0) + Log::perror("pipe read"); + else if (queue_overflowed) { + // There is a *slight* race condition here. Between reading + // the queue_overflow flag and resetting it. But it doesn't + // matter, since I'm gonna handle the overflow after reseting + // anyway. + queue_overflowed = false; + + // We're soon gonna check all watches anyway, so + // get rid of the current queue + queue_head = queue_tail; + + all_watches_changed (); + } else { + // Don't read events that happen later than + // the initial read. (Otherwise skipping fd's + // might miss some changes). + snap_queue_tail = queue_tail; + last_fd = -1; + while (queue_head != snap_queue_tail) { + fd = change_queue[queue_head]; + queue_head = (queue_head + 1) % QUEUESIZE; + + // Skip multiple changes to the same fd + if (fd != last_fd) { + dw = lookup_dirwatch (fd); + if (dw) { + int n_watches, i; + ChangeEventData *data; + DirWatch::FileWatchList::Node *n; + + Log::debug("dnotify said dev %d/%d, ino %ld changed", + major(dw->dir_dev), minor(dw->dir_dev), dw->dir_ino); + + n_watches = dw->file_watches.len(); + data = new ChangeEventData[n_watches]; + + i = 0; + for (n=dw->file_watches.first; n; n=n->next) { + data[i].file_dev = n->watch->file_dev; + data[i].file_ino = n->watch->file_ino; + i++; + } + assert(i == n_watches); + + for (i = 0; i < n_watches; i++) { + (*ehandler)(data[i].file_dev, data[i].file_ino, CHANGE); + } + + delete[] data; + } + } + last_fd = fd; + } + } +} + --- /dev/null 2003-09-15 15:40:47.000000000 +0200 +++ fam-2.6.10/fam/DNotify.h 2004-02-03 18:30:26.000000000 +0100 @@ -0,0 +1,98 @@ +// Copyright (C) 2001 Red Hat, Inc. All Rights Reserved. +// Copyright (C) 1999 Silicon Graphics, Inc. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of version 2 of the GNU General Public License as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it would be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Further, any +// license provided herein, whether implied or otherwise, is limited to +// this program in accordance with the express provisions of the GNU +// General Public License. Patent licenses, if any, provided herein do not +// apply to combinations of this program with other product or programs, or +// any other product whatsoever. This program is distributed without any +// warranty that the program is delivered free of the rightful claim of any +// third person by way of infringement or the like. See the GNU General +// Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write the Free Software Foundation, Inc., 59 +// Temple Place - Suite 330, Boston MA 02111-1307, USA. + +#ifndef DNotify_included +#define DNotify_included + +#include "config.h" +#include "Monitor.h" +#include + +// DNotify is an object encapsulating the dnotify linux fcntl. +// It "emulates" the IMon interface. +// There can only be one instantiation of the DNotify object. +// +// The user of this object uses express() and revoke() to +// express/revoke interest in a file. There is also +// a callback, the EventHandler. When an dnotify event comes in, +// the EventHandler is called. +// +// The user of the DNotify object is the Interest class. + +class DNotify : public Monitor { +public: + DNotify(EventHandler h); + ~DNotify(); + + static bool is_active(); + + virtual Status express(const char *name, struct stat *stat_return); + virtual Status revoke(const char *name, dev_t dev, ino_t ino); + +private: + struct FileWatch; + struct DirWatch; + struct ChangeEventData; + + // Class Variables + enum { QUEUESIZE = 1024 }; + static int pipe_write_fd; + static int pipe_read_fd; + static int change_queue[QUEUESIZE]; + static volatile sig_atomic_t DNotify::queue_overflowed; + static volatile sig_atomic_t DNotify::queue_changed; + static volatile int queue_head; // Only modified by read handler + static volatile int queue_tail; // Only modified by signal handler + static EventHandler ehandler; + static void overflow_signal_handler(int sig, siginfo_t *si, void *data); + static void signal_handler(int sig, siginfo_t *si, void *data); + static void read_handler(int fd, void *closure); + + enum { DIR_HASHSIZE = 367 }; + static DirWatch *dir_hash[DIR_HASHSIZE]; + enum { FILE_HASHSIZE = 823 }; + static FileWatch *file_hash[FILE_HASHSIZE]; + + static DirWatch **dir_hashchain(int fd) + { return &dir_hash[(unsigned) (fd) % DIR_HASHSIZE]; } + static FileWatch **file_hashchain(dev_t d, ino_t i) + { return &file_hash[(unsigned) (d+i) % FILE_HASHSIZE]; } + + static DirWatch *lookup_dirwatch (int fd); + static DirWatch *lookup_dirwatch (dev_t dir_dev, ino_t dir_ino); + static FileWatch *lookup_filewatch (dev_t file_dev, ino_t file_ino); + static void hash_dirwatch(DirWatch *w); + static void hash_filewatch(FileWatch *w); + static void unhash_dirwatch(DirWatch *w); + static void unhash_filewatch(FileWatch *w); + static Status watch_dir(const char *notify_dir, dev_t file_dev, ino_t file_ino); + + static void all_watches_changed(void); + + DNotify(const DNotify&); // Do not copy + DNotify & operator = (const DNotify&); // or assign. +}; + +#endif /* !IMon_included */ + + --- fam-2.6.10/fam/IMon.h.dnotify 2003-04-15 06:21:34.000000000 +0200 +++ fam-2.6.10/fam/IMon.h 2004-02-03 18:30:26.000000000 +0100 @@ -24,10 +24,7 @@ #define IMon_included #include "config.h" -#include -#include - -#include "Boolean.h" +#include "Monitor.h" struct stat; @@ -41,25 +38,18 @@ // // The user of the IMon object is the Interest class. -class IMon { +class IMon : public Monitor { public: - - enum Status { OK = 0, BAD = -1 }; - enum Event { EXEC, EXIT, CHANGE }; - - typedef void (*EventHandler)(dev_t, ino_t, int event); - IMon(EventHandler h); ~IMon(); static bool is_active(); - Status express(const char *name, struct stat *stat_return); - Status revoke(const char *name, dev_t dev, ino_t ino); + virtual Status express(const char *name, struct stat *stat_return); + virtual Status revoke(const char *name, dev_t dev, ino_t ino); private: - // Class Variables static int imonfd; --- fam-2.6.10/fam/Interest.c++.dnotify 2003-04-15 06:21:34.000000000 +0200 +++ fam-2.6.10/fam/Interest.c++ 2004-02-03 18:30:26.000000000 +0100 @@ -43,12 +43,21 @@ #include "Event.h" #include "FileSystem.h" #include "IMon.h" +#include "DNotify.h" #include "Log.h" #include "Pollster.h" #include "timeval.h" Interest *Interest::hashtable[]; -IMon Interest::imon(imon_handler); + +#ifdef USE_DNOTIFY +static DNotify dnotify(Interest::monitor_handler); +Monitor * Interest::monitor = &dnotify; +#else +static IMon imon(Interest::monitor_handler); +Monitor * Interest::monitor = &imon; +#endif + bool Interest::xtab_verification = true; Interest::Interest(const char *name, FileSystem *fs, in_addr host, ExportVerification ev) @@ -60,11 +69,11 @@ myhost(host), mypath_exported_to_host(ev == NO_VERIFY_EXPORTED) { - memset(&old_stat, 0, sizeof(old_stat)); - IMon::Status s = IMon::BAD; - - s = imon.express(name, &old_stat); - if (s != IMon::OK) + memset(&old_stat, 0, sizeof(old_stat)); + + Monitor::Status s = Monitor::BAD; + s = monitor->express(name, &old_stat); + if (s != Monitor::OK) { int rc = lstat(name, &old_stat); if (rc < 0) { Log::info("can't lstat %s", name); @@ -101,7 +110,7 @@ } #endif - if (exported_to_host()) fs->ll_monitor(this, s == IMon::OK); + if (exported_to_host()) fs->ll_monitor(this, s == Monitor::OK); } Interest::~Interest() @@ -129,7 +138,7 @@ pp = &p->hashlink; // move to next element } if (!found_same) - (void) imon.revoke(name(), dev, ino); + (void) monitor->revoke(name(), dev, ino); } } @@ -148,7 +157,7 @@ // Express interest. IMon::Status s = IMon::BAD; - s = imon.express(name(), NULL); + s = monitor->express(name(), NULL); if (s != IMon::OK) { return true; } @@ -249,23 +258,23 @@ } void -Interest::imon_handler(dev_t device, ino_t inumber, int event) +Interest::monitor_handler(dev_t device, ino_t inumber, int event) { assert(device || inumber); for (Interest *p = *hashchain(device, inumber), *next = p; p; p = next) { next = p->hashlink; if (p->ino == inumber && p->dev == device) - { if (event == IMon::EXEC) + { if (event == Monitor::EXEC) { p->cur_exec_state = EXECUTING; (void) p->report_exec_state(); } - else if (event == IMon::EXIT) + else if (event == Monitor::EXIT) { p->cur_exec_state = NOT_EXECUTING; (void) p->report_exec_state(); } else - { assert(event == IMon::CHANGE); + { assert(event == Monitor::CHANGE); p->scan(); } } --- fam-2.6.10/fam/Interest.h.dnotify 2003-04-15 06:21:34.000000000 +0200 +++ fam-2.6.10/fam/Interest.h 2004-02-03 18:30:26.000000000 +0100 @@ -32,7 +32,7 @@ class Event; class FileSystem; -class IMon; +class Monitor; struct stat; // Interest -- abstract base class for filesystem entities of interest. @@ -74,7 +74,7 @@ // Public Class Method - static void imon_handler(dev_t, ino_t, int event); + static void monitor_handler(dev_t, ino_t, int event); static void enable_xtab_verification(bool enable); @@ -121,7 +121,7 @@ // Class Variables - static IMon imon; + static Monitor *monitor; static Interest *hashtable[HASHSIZE]; static bool xtab_verification; --- fam-2.6.10/fam/Makefile.am.dnotify 2003-04-15 06:21:26.000000000 +0200 +++ fam-2.6.10/fam/Makefile.am 2004-02-03 18:30:26.000000000 +0100 @@ -3,6 +3,12 @@ bin_PROGRAMS = fam sysconf_DATA = fam.conf +if USE_DNOTIFY +DNOTIFY_FILES = DNotify.c++ +else +DNOTIFY_FILES = +endif + fam_SOURCES = \ Activity.c++ \ Activity.h \ @@ -20,6 +26,7 @@ Directory.h \ DirectoryScanner.c++ \ DirectoryScanner.h \ + DNotify.h \ Event.c++ \ Event.h \ File.c++ \ @@ -48,6 +55,7 @@ NFSFileSystem.h \ NetConnection.c++ \ NetConnection.h \ + Monitor.h \ Pollster.c++ \ Pollster.h \ Request.h \ @@ -72,9 +80,10 @@ main.c++ \ timeval.c++ \ timeval.h \ - @IMON_FUNCS@.c++ + @IMON_FUNCS@.c++ \ + $(DNOTIFY_FILES) -EXTRA_fam_SOURCES = IMonIrix.c++ IMonLinux.c++ IMonNone.c++ +EXTRA_fam_SOURCES = IMonIrix.c++ IMonLinux.c++ IMonNone.c++ DNotify.c++ fam_LDADD = -lrpcsvc $(top_srcdir)/support/libsupport.a --- /dev/null 2003-09-15 15:40:47.000000000 +0200 +++ fam-2.6.10/fam/Monitor.h 2004-02-03 18:30:26.000000000 +0100 @@ -0,0 +1,57 @@ +// Copyright (C) 2001 Red Hat, Inc. All Rights Reserved. +// Copyright (C) 1999 Silicon Graphics, Inc. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of version 2 of the GNU General Public License as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it would be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Further, any +// license provided herein, whether implied or otherwise, is limited to +// this program in accordance with the express provisions of the GNU +// General Public License. Patent licenses, if any, provided herein do not +// apply to combinations of this program with other product or programs, or +// any other product whatsoever. This program is distributed without any +// warranty that the program is delivered free of the rightful claim of any +// third person by way of infringement or the like. See the GNU General +// Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write the Free Software Foundation, Inc., 59 +// Temple Place - Suite 330, Boston MA 02111-1307, USA. + +#ifndef Monitor_included +#define Monitor_included + +#include "config.h" +#include +#include + +struct stat; + +// Monitor is an abstract baseclass for differend file monitoring +// systems. The original system used was IMon, and the Montor API +// is heavily influenced by that. +// There can only be one instantiation of the Monitor object. +// +// The user of this object uses express() and revoke() to +// express/revoke interest in a file to imon. There is also +// a callback, the EventHandler. When an event comes in, +// the EventHandler is called. +// +// The main implementers of the Monitor class is IMon and DNotify + +class Monitor { +public: + + enum Status { OK = 0, BAD = -1 }; + enum Event { EXEC, EXIT, CHANGE }; + + typedef void (*EventHandler)(dev_t, ino_t, int event); + + virtual Status express(const char *name, struct stat *stat_return) = 0; + virtual Status revoke(const char *name, dev_t dev, ino_t ino) = 0; +}; + +#endif /* !Monitor_included */ --- fam-2.6.10/include/BTree.h.dnotify 2003-04-15 06:21:19.000000000 +0200 +++ fam-2.6.10/include/BTree.h 2004-02-03 18:30:26.000000000 +0100 @@ -271,7 +271,7 @@ n += that->n + 1; link[n] = that->link[that->n]; that->n = 0; - that->link[0] = NULL; + that->link[0] = 0; } /////////////////////////////////////////////////////////////////////////////// @@ -280,7 +280,7 @@ template BTree::BTree() - : root(NULL), npairs(0) + : root(0), npairs(0) { assert(!(fanout % 2)); } @@ -407,7 +407,7 @@ BTree::Closure BTree::insert(Node *p, const Key& key, const Value& value) { - if (!p) return Closure(key, value, NULL); + if (!p) return Closure(key, value, 0); // If you're running Purify on a client linking with libfam, and it says // that line is causing a 3-byte UMR for BTree::insert() in // FAMNextEvent() ("Reading 8 bytes from 0x... on the stack (3 bytes at @@ -475,7 +475,7 @@ case UNDER: if (root->n == 0) { Node *nr = root->link[0]; - root->link[0] = NULL; // don't delete subtree + root->link[0] = 0; // don't delete subtree delete root; root = nr; } @@ -507,8 +507,8 @@ Node *cp = p->link[i]; assert(cp); - Node *rp = i < p->n ? p->link[i + 1] : NULL; - Node *lp = i > 0 ? p->link[i - 1] : NULL; + Node *rp = i < p->n ? p->link[i + 1] : 0; + Node *lp = i > 0 ? p->link[i - 1] : 0; assert(!rp || rp->n >= fanout / 2); assert(!lp || lp->n >= fanout / 2); --- fam-2.6.10/acconfig.h.dnotify 2003-04-15 06:20:36.000000000 +0200 +++ fam-2.6.10/acconfig.h 2004-02-03 18:30:26.000000000 +0100 @@ -17,6 +17,9 @@ /* Define if the system has imon and IMONIOC_ ioctl flags. */ #undef HAVE_IMON +/* Define if the system has the dnotify fcntl and it's gonna be used. */ +#undef USE_DNOTIFY + /* Define if the system has the struct revokdi and the IMONIOC_REVOKDI ** ioctl flag. (IRIX 5.3 doesn't.) */ --- fam-2.6.10/configure.in.dnotify 2003-04-15 08:05:00.000000000 +0200 +++ fam-2.6.10/configure.in 2004-02-03 18:30:26.000000000 +0100 @@ -100,6 +100,24 @@ dnl AC_CHECK_HEADERS(fcntl.h limits.h sys/time.h syslog.h unistd.h) dnl +dnl Test for the linux dnotify fcntl +dnl +AC_MSG_CHECKING([for dnotify fcntl support]) +fam_save_cppflags="$CPPFLAGS" +CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE" +AC_TRY_COMPILE([ +#define _GNU_SOURCE +#include +#include +], +[ int fd = 1; + fcntl (fd, F_NOTIFY, (DN_MODIFY|DN_CREATE|DN_DELETE|DN_RENAME|DN_ATTRIB)|DN_MULTISHOT); +], have_dnotify=yes, have_dnotify=no) +use_dnotify=false +CPPFLAGS="$pango_save_cppflags" +AC_MSG_RESULT($have_dnotify) + +dnl dnl See if imon is available; if so, is it IRIX or Linux? dnl if test `uname` = 'IRIX' || test `uname` = 'IRIX64'; then @@ -122,11 +140,17 @@ if test "$have_imon" != "yes"; then have_imon=no AC_DEFINE(HAVE_IMON, 0) + if test "$have_dnotify" = "yes"; then + AC_DEFINE(USE_DNOTIFY) + use_dnotify=true + fi IMON_FUNCS=IMonNone fi +AM_CONDITIONAL(USE_DNOTIFY, $use_dnotify) AC_SUBST(IMON_FUNCS) echo "Using imon support module $IMON_FUNCS" + AC_CHECK_HEADER(sys/statvfs.h, [AC_DEFINE(HAVE_STATVFS, 1) have_statvfs="yes"], [AC_DEFINE(HAVE_STATVFS, 0) have_statvfs="no"]) AC_CHECK_HEADER(sys/syssgi.h, AC_DEFINE(HAVE_SYSSGI, 1), AC_DEFINE(HAVE_SYSSGI, 0)) AC_CHECK_HEADER(sys/fs/nfs_clnt.h, AC_DEFINE(HAVE_SYS_FS_NFS_CLNT_H, 1), AC_DEFINE(HAVE_SYS_FS_NFS_CLNT_H, 0)) @@ -570,7 +594,7 @@ dnl dnl fam is a good deal less interesting without imon. dnl -if test "$have_imon" != 'yes'; then +if test "$have_imon" != 'yes' -a "$have_dnotify" != 'yes'; then cat << EOF ****************************************************************** --=-yaPmd/An3u6aVmsTUeP2-- From esr@thyrsus.com Mon Feb 16 22:01:20 2004 Received: with ECARTIS (v1.0.0; list fam); Mon, 16 Feb 2004 22:01:23 -0800 (PST) Received: from snark.thyrsus.com (dsl092-053-140.phl1.dsl.speakeasy.net [66.92.53.140]) by oss.sgi.com (8.12.10/8.12.9) with SMTP id i1H61JKO006913 for ; Mon, 16 Feb 2004 22:01:20 -0800 Received: from snark.thyrsus.com (localhost [127.0.0.1]) by snark.thyrsus.com (8.12.10/8.12.10) with ESMTP id i1H5ucIG008963 for ; Tue, 17 Feb 2004 00:56:38 -0500 Date: Tue, 17 Feb 2004 00:56:38 -0500 From: esr@thyrsus.com Message-Id: <200402170556.i1H5ucIG008963@snark.thyrsus.com> To: fam@oss.sgi.com Subject: problems in one or more man pages you maintain X-archive-position: 217 X-ecartis-version: Ecartis v1.0.0 Sender: fam-bounce@oss.sgi.com Errors-to: fam-bounce@oss.sgi.com X-original-sender: esr@thyrsus.com Precedence: bulk X-list: fam This is automatically generated email about problems in a man page for which you appear to be responsible. If you are not the right person or list, tell me and I will attempt to correct my database. See http://catb.org/~esr/doclifter/problems.html for details on how and why these patches were generated. Feel free to email me with any questions. Note: This patch does not change the mod date of the manual page. You may wish to do that by hand. Problems with fam.3x: 1. Unknown or invalid macro. That is, one that does not fit in the macro set that the man page seems to be using. This is a serious error; it often means part of your text is being lost or rendered incorrectly. 2. Broken command synopsis syntax. This may mean you're using a construction in the command synopsis other than the standard [ ] | { }, or it may mean you have running text in the command synopsis section (the latter is not technically an error, but it's impossible to translate into DocBook markup). --- fam.3x-orig 2003-11-30 04:55:50.000000000 -0500 +++ fam.3x 2003-11-30 04:56:36.000000000 -0500 @@ -1,5 +1,5 @@ '\"macro stdmacro -.if n .pH g3x.fam @(#)fam 30.3 of 1/19/86 +.\" g3x.fam @(#)fam 30.3 of 1/19/86 .nr X .if \nX=0 .ds x} FAM 3X "Specialized Libraries" "\&" .if \nX=1 .ds x} FAM 3X "Specialized Libraries" @@ -79,8 +79,6 @@ .SH USING FAM Here are the steps required to use \fIFAM \fPin an application: .PP -.AL -.LI .IP 1. Create a connection to \fIfam\fP by calling FAMOpen. This routine will pass back a FAMConnection structure used in all \fIfam \fP @@ -262,8 +260,6 @@ .PP There are two ways to for applications to receive \fIFAM \fPevents: .PP -.AL -.LI 1. The Select approach - The application selects on the file descriptor returned from FAMOpen, in the FAMConnection structure. When this file descriptor becomes active, the application calls -- Eric S. Raymond From benasselstine@canada.com Tue Feb 24 06:40:38 2004 Received: with ECARTIS (v1.0.0; list fam); Tue, 24 Feb 2004 06:40:42 -0800 (PST) Received: from c009.snv.cp.net (h014.c009.snv.cp.net [209.228.34.127]) by oss.sgi.com (8.12.10/8.12.9) with SMTP id i1OEebKO023212 for ; Tue, 24 Feb 2004 06:40:38 -0800 Received: (cpmta 24234 invoked from network); 24 Feb 2004 06:40:37 -0800 Received: from 209.228.34.120 (HELO mail.canada.com.criticalpath.net) by smtp.canada.com (209.228.34.127) with SMTP; 24 Feb 2004 06:40:37 -0800 X-Sent: 24 Feb 2004 14:40:37 GMT Received: from [131.137.245.197] by mail.canada.com with HTTP; Tue, 24 Feb 2004 06:40:36 -0800 (PST) Content-Type: text/plain; charset=iso-8859-1 Content-Disposition: inline Content-Transfer-Encoding: 7bit MIME-Version: 1.0 To: fam@oss.sgi.com From: "Ben Asselstine" Subject: ANNOUNCE: fileschanged 0.6.0 X-Sent-From: benasselstine@canada.com Date: Tue, 24 Feb 2004 06:40:36 -0800 (PST) X-Mailer: Web Mail 5.6.0-2_sol28 Message-Id: <20040224064037.224.h007.c009.wm@mail.canada.com.criticalpath.net> X-archive-position: 218 X-ecartis-version: Ecartis v1.0.0 Sender: fam-bounce@oss.sgi.com Errors-to: fam-bounce@oss.sgi.com X-original-sender: benjamindavidasselstine@hotmail.com Precedence: bulk X-list: fam Hi, fileschanged 0.6.0 has been released. The version is a large rewrite, making it run somewhat more efficient. Useless options have been removed, and a new "--show-all" option has been added. Also The -f option is now the default instead of -l. This means that the files on the command-line refer to files that should be monitored, instead of files that contain filenames that should be monitored. Here is the new usage: Usage: fileschanged [OPTION...] [FILE]... Monitors FILEs for alterations. Display the filenames of FILEs that were created, changed, deleted, started execution or finished executing. -c, --show-created (Default) Display newly created files -C, --show-changed (Default) Display changed files -d, --show-deleted Display deleted files -e, --show-executing Display executing files -E, --show-executed Display files that have stopped executing -a, --show-all Same as -c -C -d -e -E -p -f, --files-to-monitor (Default) Monitor the FILEs on the command line -l, --filelist=FILENAME Monitor the list of filenames inside FILE -r, --recursive Monitor subdirectories of directories -t, --timeout=N Delay showing changed files for N seconds (Def=2) -p, --prepend-action Also display action when displaying altered files -?, --help Give this help list --usage Give a short usage message -V, --version Print program version FILEs must already exist before they are monitored, or they will not be monitored. Report bugs to . thanks, Ben From mdt@emdete.de Sun Feb 29 07:36:32 2004 Received: with ECARTIS (v1.0.0; list fam); Sun, 29 Feb 2004 07:36:37 -0800 (PST) Received: from mercier.office.emdete.de ([80.84.0.108]) by oss.sgi.com (8.12.10/8.12.9) with SMTP id i1TFaUKO015225 for ; Sun, 29 Feb 2004 07:36:31 -0800 Received: from mdt by mercier.office.emdete.de with local (Exim 3.36 #1 (Debian)) id 1AxSzb-0001hz-00 for ; Sun, 29 Feb 2004 16:36:35 +0100 Date: Sun, 29 Feb 2004 16:36:35 +0100 From: "M. Dietrich" To: fam@oss.sgi.com Subject: what happens if client core-dumps? Message-ID: <20040229153635.GB2559@emdete.de> Reply-To: mdt@emdete.de Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Organization: emdete User-Agent: Mutt/1.5.5.1+cvs20040105i X-archive-position: 219 X-ecartis-version: Ecartis v1.0.0 Sender: fam-bounce@oss.sgi.com Errors-to: fam-bounce@oss.sgi.com X-original-sender: mdt@emdete.de Precedence: bulk X-list: fam Hi, i recently had troubles with fam if a client program (nautilus) coredumps while watching a directory. fam keeps looking into it and i couldn't unmount that resource until i stopped fam. is this a bug in fam or a mistake in my setup? best regards, michael