First patch adds support for immutable/read-only filesystems in fam. Such filesystems are assumed to never change and thus, they are not polled/dnotify-ed. This is mostly usable for iso9660 and autofs filesystems. First patch also adds autodetection of read-only filesystems in fam (optional, by command-line flag or entry in fam[d].conf). This fixes bug 245448. However more generic solution is implemented in second patch. It adds support for /etc/fam.hints file where immuatable filesystems can be described by filesystem type. The second patch requres the first one to be already applied. The first patch requries dnotify patch to be already applied (included in debian package diff).
/etc/fam.hints syntax is something like: immutablefstype autofs immutablefstype iso9660 The inotify patch for linux kernel in combination with inotify patch for fam maybe will fix these problems too, but it is not in official Linux kernels (yet) (it's not in 2.6.10).
diff -ru fam-2.7.0/conf/fam.conf fam-2.7.0.detectrofs/conf/fam.conf
--- fam-2.7.0/conf/fam.conf 2005-01-19 05:55:04.000000000 +0200
+++ fam-2.7.0.detectrofs/conf/fam.conf 2005-01-19 05:56:00.000000000 +0200
@@ -51,3 +51,8 @@
#
#nfs_polling_interval = 6
+#
+# detect_readonly_filesystems enables automatic detection of read-only
+# filesystems. Such filesystems are assumed to never change.
+#
+#detect_readonly_filesystems = false
diff -ru fam-2.7.0/man/famd.8 fam-2.7.0.detectrofs/man/famd.8
--- fam-2.7.0/man/famd.8 2005-01-19 05:55:04.000000000 +0200
+++ fam-2.7.0.detectrofs/man/famd.8 2005-01-19 05:56:00.000000000 +0200
@@ -47,6 +47,9 @@
\fB\-L\fR
Only accept connections from local clients.
.TP
+\fB\-r\fR
+Detect read-only filesystems.
+.TP
\fB\-p\fR \fIprog\fR.\fIvers\fR
Register with the portmapper using the specifed RPC program
and version numbers.
diff -ru fam-2.7.0/man/famd.conf.5 fam-2.7.0.detectrofs/man/famd.conf.5
--- fam-2.7.0/man/famd.conf.5 2005-01-19 05:55:04.000000000 +0200
+++ fam-2.7.0.detectrofs/man/famd.conf.5 2005-01-19 05:56:00.000000000 +0200
@@ -48,5 +48,11 @@
service remote requests without attempting to perform the verification. If
the \fBlocal_only\fR configuration option or \fB-L\fR command line option is
used, \fBxtab_verification\fR has no effect.
+.TP
+\fBdetect_readonly_filesystems\fR
+If set to \fItrue\fR, \fBfamd\fR will try to detect read-only filesystems.
+Such filesystems are assumed to never change. This is \fIfalse\fR by default.
+Setting this option to \fBtrue\fR is the same as using the \fB\-r\fR command
+line option.
.SH "SEE ALSO"
diff -ru fam-2.7.0/src/ClientInterest.h fam-2.7.0.detectrofs/src/ClientInterest.h
--- fam-2.7.0/src/ClientInterest.h 2005-01-19 05:55:04.000000000 +0200
+++ fam-2.7.0.detectrofs/src/ClientInterest.h 2005-01-19 05:56:00.000000000 +0200
@@ -71,6 +71,8 @@
ClientInterest(const char *name, Client *, Request, const Cred&, Type);
void post_event(const Event&, const char * = NULL);
+ virtual FileSystem * get_filesystem() { return myfilesystem; }
+
private:
enum { ACTIVE_STATE = 1 << 0 };
diff -ru fam-2.7.0/src/FileSystem.c++ fam-2.7.0.detectrofs/src/FileSystem.c++
--- fam-2.7.0/src/FileSystem.c++ 2005-01-19 05:55:04.000000000 +0200
+++ fam-2.7.0.detectrofs/src/FileSystem.c++ 2005-01-19 05:56:00.000000000 +0200
@@ -29,7 +29,8 @@
FileSystem::FileSystem(const mntent& mnt)
: mydir (strcpy(new char[strlen(mnt.mnt_dir ) + 1], mnt.mnt_dir )),
- myfsname(strcpy(new char[strlen(mnt.mnt_fsname) + 1], mnt.mnt_fsname))
+ myfsname(strcpy(new char[strlen(mnt.mnt_fsname) + 1], mnt.mnt_fsname)),
+ myreadonly(false)
{ }
FileSystem::~FileSystem()
@@ -69,3 +70,21 @@
hl_cancel(request);
myinterests.remove(cip);
}
+
+bool
+FileSystem::is_readonly() const
+{
+ return myreadonly;
+}
+
+void
+FileSystem::set_readonly()
+{
+ myreadonly = true;
+}
+
+void
+FileSystem::set_readwrite()
+{
+ myreadonly = false;
+}
diff -ru fam-2.7.0/src/FileSystem.h fam-2.7.0.detectrofs/src/FileSystem.h
--- fam-2.7.0/src/FileSystem.h 2005-01-19 05:55:04.000000000 +0200
+++ fam-2.7.0.detectrofs/src/FileSystem.h 2005-01-19 05:56:00.000000000 +0200
@@ -103,6 +103,9 @@
virtual bool dir_entries_scanned() const = 0;
void relocate_interests();
virtual int get_attr_cache_timeout() const = 0;
+ bool is_readonly() const;
+ void set_readonly();
+ void set_readwrite();
// High level monitoring interface
@@ -126,6 +129,7 @@
char *mydir;
char *myfsname;
Interests myinterests;
+ bool myreadonly;
virtual Request hl_monitor(ClientInterest *, ClientInterest::Type) = 0;
virtual void hl_cancel(Request) = 0;
diff -ru fam-2.7.0/src/FileSystemTable.c++ fam-2.7.0.detectrofs/src/FileSystemTable.c++
--- fam-2.7.0/src/FileSystemTable.c++ 2005-01-19 05:55:04.000000000 +0200
+++ fam-2.7.0.detectrofs/src/FileSystemTable.c++ 2005-01-19 05:56:00.000000000 +0200
@@ -56,6 +56,8 @@
InternalClient *FileSystemTable::mtab_watcher;
FileSystem *FileSystemTable::root;
+extern bool g_detect_readonly_fs;
+
#ifdef HAPPY_PURIFY
//////////////////////////////////////////////////////////////////////////////
@@ -168,7 +170,14 @@
assert(parent);
mount_parents.insert(parent->dir(), parent);
}
- }
+
+ if (g_detect_readonly_fs && hasmntopt(mp, MNTOPT_RO))
+ {
+ Log::debug("mtab: new local \"%s\" on \"%s\" is read-only",
+ mp->mnt_fsname, mp->mnt_dir);
+ fs->set_readonly();
+ }
+ }
if (!strcmp(mp->mnt_dir, "/"))
root = fs;
}
diff -ru fam-2.7.0/src/Interest.c++ fam-2.7.0.detectrofs/src/Interest.c++
--- fam-2.7.0/src/Interest.c++ 2005-01-19 05:55:04.000000000 +0200
+++ fam-2.7.0.detectrofs/src/Interest.c++ 2005-01-19 05:58:53.000000000 +0200
@@ -71,7 +71,12 @@
memset(&old_stat, 0, sizeof(old_stat));
Monitor::Status s = Monitor::BAD;
- s = monitor->express(name, &old_stat);
+
+ if (!fs->is_readonly())
+ {
+ s = monitor->express(name, &old_stat);
+ }
+
if (s != Monitor::OK)
{ int rc = lstat(name, &old_stat);
if (rc < 0)
@@ -156,7 +161,13 @@
// Express interest.
IMon::Status s = IMon::BAD;
- s = monitor->express(name(), NULL);
+
+ FileSystem *fs = get_filesystem();
+ if (!fs || !fs->is_readonly())
+ {
+ s = monitor->express(name(), NULL);
+ }
+
if (s != IMon::OK) {
return true;
}
Only in fam-2.7.0.detectrofs/src: Interest.c++.orig
Only in fam-2.7.0.detectrofs/src: Interest.c++.rej
diff -ru fam-2.7.0/src/Interest.h fam-2.7.0.detectrofs/src/Interest.h
--- fam-2.7.0/src/Interest.h 2005-01-19 05:55:04.000000000 +0200
+++ fam-2.7.0.detectrofs/src/Interest.h 2005-01-19 05:56:00.000000000 +0200
@@ -89,6 +89,7 @@
const in_addr& host() const { return myhost; }
void verify_exported_to_host();
bool exported_to_host() const { return mypath_exported_to_host; }
+ virtual FileSystem * get_filesystem() { return NULL; }
private:
diff -ru fam-2.7.0/src/LocalFileSystem.c++ fam-2.7.0.detectrofs/src/LocalFileSystem.c++
--- fam-2.7.0/src/LocalFileSystem.c++ 2005-01-19 05:55:04.000000000 +0200
+++ fam-2.7.0.detectrofs/src/LocalFileSystem.c++ 2005-01-19 05:56:00.000000000 +0200
@@ -78,9 +78,8 @@
void
LocalFileSystem::ll_monitor(Interest *ip, bool imonitored)
{
- if (!imonitored)
+ if (!imonitored && !is_readonly())
{
- Log::debug("will poll %s", ip->name());
Pollster::watch(ip);
}
}
@@ -95,5 +94,8 @@
void
LocalFileSystem::ll_notify_deleted(Interest *ip)
{
- Pollster::watch(ip);
+ if (!is_readonly())
+ {
+ Pollster::watch(ip);
+ }
}
diff -ru fam-2.7.0/src/main.c++ fam-2.7.0.detectrofs/src/main.c++
--- fam-2.7.0/src/main.c++ 2005-01-19 05:55:04.000000000 +0200
+++ fam-2.7.0.detectrofs/src/main.c++ 2005-01-19 05:56:00.000000000 +0200
@@ -65,6 +65,7 @@
#define CFG_UNTRUSTED_USER "untrusted_user"
#define CFG_IDLE_TIMEOUT "idle_timeout"
#define CFG_NFS_POLLING_INTERVAL "nfs_polling_interval"
+#define CFG_DETECT_READONLY_FILESYSTEMS "detect_readonly_filesystems"
static void parse_config(config_opts &opts);
static void parse_config_line(config_opts &opts, int line,
const char *k, const char *v);
@@ -79,6 +80,8 @@
return tail;
}
+bool g_detect_readonly_fs = false;
+
void usage()
{ fprintf(stderr,
"fam, version %s\n"
@@ -96,6 +99,7 @@
fprintf(stderr, "\t-c config_file\tpath to alternate configuration file\n");
fprintf(stderr, "\t\t\t (default is %s)\n", FAM_CONF);
fprintf(stderr, "\t-C\t\tinsecure compatibility\n");
+ fprintf(stderr, "\t-r\t\tdetect read-only filesystems\n");
fprintf(stderr, "\n");
exit(1);
}
@@ -183,6 +187,10 @@
opts.disable_pollster = true;
break;
+ case 'r':
+ g_detect_readonly_fs = true;
+ break;
+
case 'p':
if (++i >= argc)
usage();
@@ -409,6 +417,10 @@
// opts.config_file, lineno, key);
// }
}
+ else if(!strcmp(key, CFG_DETECT_READONLY_FILESYSTEMS))
+ {
+ g_detect_readonly_fs = is_true(val);
+ }
else if(!strcmp(key, "disable_audit"))
{
opts.disable_audit = is_true(val);
diff -ruN fam-2.7.0-debugging_in_background/src/FileSystemTable.c++ fam-2.7.0/src/FileSystemTable.c++
--- fam-2.7.0-debugging_in_background/src/FileSystemTable.c++ 2005-01-25 23:13:48.000000000 +0200
+++ fam-2.7.0/src/FileSystemTable.c++ 2005-01-25 23:48:10.000000000 +0200
@@ -38,6 +38,7 @@
#include "LocalFileSystem.h"
#include "Log.h"
#include "NFSFileSystem.h"
+#include "hints.h"
// Fam has two tables of mounted filesystems -- fs_by_name and
// fs_by_id. They are keyed by mountpoint and by filesystem ID,
@@ -177,6 +178,12 @@
mp->mnt_fsname, mp->mnt_dir);
fs->set_readonly();
}
+ else if (hints_is_immuatable_fs(mp->mnt_type))
+ {
+ Log::debug("mtab: new local \"%s\" on \"%s\" is of type \"%s\" and has immutable hint",
+ mp->mnt_fsname, mp->mnt_dir, mp->mnt_type);
+ fs->set_readonly();
+ }
}
if (!strcmp(mp->mnt_dir, "/"))
root = fs;
diff -ruN fam-2.7.0-debugging_in_background/src/Makefile.am fam-2.7.0/src/Makefile.am
--- fam-2.7.0-debugging_in_background/src/Makefile.am 2005-01-25 23:13:48.000000000 +0200
+++ fam-2.7.0/src/Makefile.am 2005-01-25 23:17:29.000000000 +0200
@@ -74,6 +74,8 @@
Monitor.h \
DNotify.h \
DNotify.c++ \
+ hints.h \
+ hints.c++ \
@[EMAIL PROTECTED]
EXTRA_famd_SOURCES = IMonIrix.c++ IMonLinux.c++ IMonNone.c++ DNotify.c++ \
diff -ruN fam-2.7.0-debugging_in_background/src/hints.c++ fam-2.7.0/src/hints.c++
--- fam-2.7.0-debugging_in_background/src/hints.c++ 1970-01-01 02:00:00.000000000 +0200
+++ fam-2.7.0/src/hints.c++ 2005-01-26 00:57:38.000000000 +0200
@@ -0,0 +1,211 @@
+// Copyright (C) 2005 Nedko Arnaudov, 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.
+
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include "Log.h"
+#include "hints.h"
+
+#define FAM_HINTS_FILE "/etc/fam.hints"
+#define FAM_HINTS_FILE_MAX_SIZE (1024*1024) // 1 MiB looks reasonable
+#define FAM_HINTS_MAX_IMMUTABLE_FS_TYPES 100
+#define FAM_HINTS_MAX_TOKENS (FAM_HINTS_MAX_IMMUTABLE_FS_TYPES * 2)
+#define FAM_HINTS_TOKEN_SEPS " \n"
+
+const char * fam_hints_immutable_fs_types[FAM_HINTS_MAX_IMMUTABLE_FS_TYPES];
+const char * fam_hints_tokens[FAM_HINTS_MAX_TOKENS];
+char * fam_hints_buffer = NULL;
+
+void
+hints_init()
+{
+ struct stat st;
+ char * ptr, * last;
+ ssize_t bytes_left, bytes_read;
+ int fd;
+ int i;
+ int immutable_fs_type_index;
+
+ Log::debug("hints_init() called.");
+
+ if (stat(FAM_HINTS_FILE, &st) != 0)
+ {
+ if (errno != ENOENT)
+ {
+ Log::error("Cannot stat \"%s\", error is %d", errno);
+ }
+
+ return;
+ }
+
+ Log::debug("\"%s\" is of size %u", FAM_HINTS_FILE, (unsigned int)st.st_size);
+ if (st.st_size > FAM_HINTS_FILE_MAX_SIZE)
+ {
+ Log::error("\"%s\" too big");
+ return;
+ }
+
+ fam_hints_buffer = new char[st.st_size+1];
+ if (fam_hints_buffer == NULL)
+ {
+ Log::error("Out of memory");
+ return;
+ }
+
+ fd = open(FAM_HINTS_FILE, O_RDONLY);
+ if (fd == -1)
+ {
+ Log::error("Out of memory");
+ goto FailDeleteBuffer;
+ }
+
+ bytes_left = (ssize_t)st.st_size;
+ ptr = fam_hints_buffer;
+
+ while (bytes_left > 0)
+ {
+ bytes_read = read(fd, ptr, bytes_left);
+ if (bytes_read == -1)
+ {
+ Log::error("Read of \"%s\" failed with %d", FAM_HINTS_FILE, errno);
+ goto FailCloseFile;
+ }
+
+ if (bytes_read == 0)
+ {
+ Log::error("Truncating of \"%s\" detected", FAM_HINTS_FILE);
+ goto FailCloseFile;
+ }
+
+ if (bytes_read > bytes_left)
+ {
+ Log::error("read() insanity while reading \"%s\"", FAM_HINTS_FILE);
+ goto FailCloseFile;
+ }
+
+ bytes_left -= bytes_read;
+ ptr += bytes_read;
+ }
+
+ bytes_read = read(fd, ptr, 1);
+ if (bytes_read == -1)
+ {
+ Log::error("Read of \"%s\" failed with %d", FAM_HINTS_FILE, errno);
+ goto FailCloseFile;
+ }
+
+ if (bytes_read != 0)
+ {
+ Log::error("Expanding of \"%s\" detected", FAM_HINTS_FILE);
+ goto FailCloseFile;
+ }
+
+ close(fd);
+
+ *ptr = 0;
+
+ i = 0;
+ ptr = strtok_r(fam_hints_buffer, FAM_HINTS_TOKEN_SEPS, &last);
+
+ while (ptr != NULL)
+ {
+ if (i < FAM_HINTS_MAX_TOKENS - 1)
+ {
+ Log::debug("token: \"%s\"", ptr);
+ fam_hints_tokens[i] = ptr;
+ }
+ else
+ {
+ break;
+ }
+
+ ptr = strtok_r(NULL, FAM_HINTS_TOKEN_SEPS, &last);
+ i++;
+ }
+
+ fam_hints_tokens[i] = NULL;
+
+ i = 0;
+ immutable_fs_type_index = 0;
+
+ while (fam_hints_tokens[i] != NULL)
+ {
+ if (strcmp(fam_hints_tokens[i], "immutablefstype") == 0)
+ {
+ i++;
+ if (fam_hints_tokens[i] == NULL)
+ {
+ Log::error("Syntax error in \"%s\"", FAM_HINTS_FILE);
+ goto FailDeleteBuffer;
+ }
+
+ Log::debug("Immutable fs type: \"%s\"", fam_hints_tokens[i]);
+ fam_hints_immutable_fs_types[immutable_fs_type_index] = fam_hints_tokens[i];
+ i++;
+ immutable_fs_type_index++;
+ continue;
+ }
+ }
+
+ return;
+
+FailCloseFile:
+ close(fd);
+FailDeleteBuffer:
+ delete fam_hints_buffer;
+ fam_hints_buffer = NULL;
+}
+
+bool
+hints_is_immuatable_fs(
+ const char * fsname)
+{
+ int i;
+
+ i = 0;
+
+ while (fam_hints_immutable_fs_types[i] != NULL)
+ {
+ if (strcmp(fsname, fam_hints_immutable_fs_types[i]) == 0)
+ {
+ return true;
+ }
+
+ i++;
+ }
+
+ return false;
+}
+
+// It looks like this is never called because SIGTERM is not processed
+void
+hints_uninit()
+{
+ Log::debug("hints_uninit() called.");
+ delete fam_hints_buffer;
+ fam_hints_buffer = NULL;
+}
diff -ruN fam-2.7.0-debugging_in_background/src/hints.h fam-2.7.0/src/hints.h
--- fam-2.7.0-debugging_in_background/src/hints.h 1970-01-01 02:00:00.000000000 +0200
+++ fam-2.7.0/src/hints.h 2005-01-25 23:43:15.000000000 +0200
@@ -0,0 +1,56 @@
+//
+// 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.
+
+#if !defined(FAM_HINTS_INCLUDED)
+#define FAM_HINTS_INCLUDED
+
+//
+// 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.
+
+void
+hints_init();
+
+bool
+hints_is_immuatable_fs(
+ const char * fsname);
+
+void
+hints_uninit();
+
+#endif
diff -ruN fam-2.7.0-debugging_in_background/src/main.c++ fam-2.7.0/src/main.c++
--- fam-2.7.0-debugging_in_background/src/main.c++ 2005-01-25 23:13:48.000000000 +0200
+++ fam-2.7.0/src/main.c++ 2005-01-25 23:47:21.000000000 +0200
@@ -39,6 +39,7 @@
#include "Scheduler.h"
#include "Cred.h"
#include "Interest.h"
+#include "hints.h"
const char *program_name;
@@ -301,7 +302,12 @@
(void) signal(SIGCHLD, SIG_IGN);
#endif
new Listener(started_by_inetd, opts.local_only, program, version);
+ hints_init();
Scheduler::loop();
+
+ // There is not need to call hints_uninit(), because fam has no cleanup method.
+ // Installing SIGTERM hook looks to be good thing but is not required.
+ //hints_uninit();
return 0;
}
-- Nedko Arnaudov <GnuPG KeyID: DE1716B0>
pgprW4T8yMDUN.pgp
Description: PGP signature

