[gvfs/f18] Fix metadata issues on NFS homedirs (#561904)
Tomas Bzatek
tbzatek at fedoraproject.org
Tue May 14 15:54:26 UTC 2013
commit b6cfb15fd4de70a94fade719620674d3179c3a0d
Author: Tomas Bzatek <tbzatek at redhat.com>
Date: Tue May 14 17:54:22 2013 +0200
Fix metadata issues on NFS homedirs (#561904)
...Be-more-resistive-to-broken-journal-files.patch | 58 +++
...ta-Create-new-journal-if-it-doesn-t-exist.patch | 101 ++++++
...ush-all-scheduled-writeouts-on-daemon-exi.patch | 98 +++++
...Force-tree-re-read-after-successful-flush.patch | 89 +++++
...t-journal-in-XDG_RUNTIME_DIR-for-shared-N.patch | 370 ++++++++++++++++++++
...adata-Use-shorter-writeout-timeout-on-NFS.patch | 78 ++++
gvfs.spec | 21 +-
7 files changed, 814 insertions(+), 1 deletions(-)
---
diff --git a/gvfs-1.17.1-metadata-Be-more-resistive-to-broken-journal-files.patch b/gvfs-1.17.1-metadata-Be-more-resistive-to-broken-journal-files.patch
new file mode 100644
index 0000000..1c3e5b3
--- /dev/null
+++ b/gvfs-1.17.1-metadata-Be-more-resistive-to-broken-journal-files.patch
@@ -0,0 +1,58 @@
+From 21811b3ae17ec705327484c1ce0be75fec95bb0e Mon Sep 17 00:00:00 2001
+From: Tomas Bzatek <tbzatek at redhat.com>
+Date: Mon, 13 May 2013 17:40:01 +0200
+Subject: [PATCH 2/6] metadata: Be more resistive to broken journal files
+
+In shared NFS homedir case with multiple clients writing to the same
+mmaped journal file data can get easily corrupted. The daemon iterates
+over a journal file on flush taking in account variable entry size and
+advances according to the data read.
+
+However in certain case invalid data are read making us to jump out of
+bounds. In case of zero entry size we would stand at the same place
+leading to infinite loop.
+
+This patch checks if the indicated entry size is at least the size of
+the structure we're getting the size from (it's a first element) and breaks
+the iteration cycle if it's not. This may lead to partial data loss on flush
+as we don't process the rest of the journal file. Old data from existing
+tree file will be preserved of course, only few recent changes would get lost.
+
+https://bugzilla.gnome.org/show_bug.cgi?id=637095
+---
+ metadata/metatree.c | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+diff --git a/metadata/metatree.c b/metadata/metatree.c
+index 015300e..20b7862 100644
+--- a/metadata/metatree.c
++++ b/metadata/metatree.c
+@@ -1304,6 +1304,11 @@ meta_journal_iterate (MetaJournal *journal,
+ {
+ sizep = (guint32 *)entry;
+ entry = (MetaJournalEntry *)((char *)entry - GUINT32_FROM_BE (*(sizep-1)));
++ if (GUINT32_FROM_BE (*(sizep)) < sizeof (MetaJournalEntry) && entry > journal->first_entry)
++ {
++ g_warning ("meta_journal_iterate: found short sized entry, possible journal corruption\n");
++ break;
++ }
+
+ mtime = GUINT64_FROM_BE (entry->mtime);
+ journal_path = &entry->path[0];
+@@ -2343,6 +2348,13 @@ apply_journal_to_builder (MetaTree *tree,
+
+ sizep = (guint32 *)entry;
+ entry = (MetaJournalEntry *)((char *)entry + GUINT32_FROM_BE (*(sizep)));
++ if (GUINT32_FROM_BE (*(sizep)) < sizeof (MetaJournalEntry) && entry < journal->last_entry)
++ {
++ /* This shouldn't happen, we found an entry that is shorter than its data */
++ /* See https://bugzilla.gnome.org/show_bug.cgi?id=637095 for discussion */
++ g_warning ("apply_journal_to_builder: found short sized entry, possible journal corruption\n");
++ break;
++ }
+ }
+ }
+
+--
+1.8.1.4
+
diff --git a/gvfs-1.17.1-metadata-Create-new-journal-if-it-doesn-t-exist.patch b/gvfs-1.17.1-metadata-Create-new-journal-if-it-doesn-t-exist.patch
new file mode 100644
index 0000000..4b1ed7f
--- /dev/null
+++ b/gvfs-1.17.1-metadata-Create-new-journal-if-it-doesn-t-exist.patch
@@ -0,0 +1,101 @@
+From 3381859ba7a92f4824ff09a7aa951407bf4e1c72 Mon Sep 17 00:00:00 2001
+From: Tomas Bzatek <tbzatek at redhat.com>
+Date: Mon, 13 May 2013 17:40:40 +0200
+Subject: [PATCH 3/6] metadata: Create new journal if it doesn't exist
+
+With concurrent access of multiple daemons there may be a moment when
+tree file exists but not the journal file. The daemon can't write
+anything without journal and is doomed until next rotation. Missing
+journal file can also happen on system crash etc.
+
+This patch tries to create new journal file only when it doesn't exist,
+other errors still lead to inability to store anything.
+
+This will also allow us to have journal file somewhere else, e.g. on
+a non-persistent storage.
+
+https://bugzilla.gnome.org/show_bug.cgi?id=637095
+---
+ metadata/metabuilder.c | 6 +++---
+ metadata/metabuilder.h | 2 ++
+ metadata/metatree.c | 16 +++++++++++++---
+ 3 files changed, 18 insertions(+), 6 deletions(-)
+
+diff --git a/metadata/metabuilder.c b/metadata/metabuilder.c
+index 58bb57b..c7e69fa 100644
+--- a/metadata/metabuilder.c
++++ b/metadata/metabuilder.c
+@@ -843,8 +843,8 @@ get_journal_filename (const char *filename, guint32 random_tag)
+ return g_strconcat (filename, "-", tag, ".log", NULL);
+ }
+
+-static gboolean
+-create_new_journal (const char *filename, guint32 random_tag)
++gboolean
++meta_builder_create_new_journal (const char *filename, guint32 random_tag)
+ {
+ char *journal_name;
+ guint32 size_offset;
+@@ -1016,7 +1016,7 @@ meta_builder_write (MetaBuilder *builder,
+ if (!write_all_data_and_close (fd, out->str, out->len))
+ goto out;
+
+- if (!create_new_journal (filename, random_tag))
++ if (!meta_builder_create_new_journal (filename, random_tag))
+ goto out;
+
+ /* Open old file so we can set it rotated */
+diff --git a/metadata/metabuilder.h b/metadata/metabuilder.h
+index 364c0d8..ad3876f 100644
+--- a/metadata/metabuilder.h
++++ b/metadata/metabuilder.h
+@@ -68,6 +68,8 @@ void meta_builder_copy (MetaBuilder *builder,
+ guint64 mtime);
+ gboolean meta_builder_write (MetaBuilder *builder,
+ const char *filename);
++gboolean meta_builder_create_new_journal (const char *filename,
++ guint32 random_tag);
+ MetaFile * metafile_new (const char *name,
+ MetaFile *parent);
+ void metafile_free (MetaFile *file);
+diff --git a/metadata/metatree.c b/metadata/metatree.c
+index 20b7862..8e2ab46 100644
+--- a/metadata/metatree.c
++++ b/metadata/metatree.c
+@@ -1146,20 +1146,30 @@ meta_journal_open (MetaTree *tree, const char *filename, gboolean for_write, gui
+ char *data;
+ char *journal_filename;
+ int open_flags, mmap_prot;
++ gboolean retried;
+
+ g_assert (sizeof (MetaJournalHeader) == 20);
+-
+- journal_filename = get_journal_filename (filename, tag);
++ retried = FALSE;
+
+ if (for_write)
+ open_flags = O_RDWR;
+ else
+ open_flags = O_RDONLY;
+
++ retry:
++ journal_filename = get_journal_filename (filename, tag);
+ fd = safe_open (tree, journal_filename, open_flags);
+ g_free (journal_filename);
+ if (fd == -1)
+- return NULL;
++ {
++ if (errno == ENOENT && tree->for_write && !retried)
++ {
++ retried = TRUE;
++ if (meta_builder_create_new_journal (filename, tag))
++ goto retry;
++ }
++ return NULL;
++ }
+
+ if (fstat (fd, &statbuf) != 0 ||
+ statbuf.st_size < sizeof (MetaJournalHeader))
+--
+1.8.1.4
+
diff --git a/gvfs-1.17.1-metadata-Flush-all-scheduled-writeouts-on-daemon-exi.patch b/gvfs-1.17.1-metadata-Flush-all-scheduled-writeouts-on-daemon-exi.patch
new file mode 100644
index 0000000..d06d2e5
--- /dev/null
+++ b/gvfs-1.17.1-metadata-Flush-all-scheduled-writeouts-on-daemon-exi.patch
@@ -0,0 +1,98 @@
+From e793a0476feeaa0a3cc4f1fd043c15c297707455 Mon Sep 17 00:00:00 2001
+From: Tomas Bzatek <tbzatek at redhat.com>
+Date: Mon, 13 May 2013 17:43:40 +0200
+Subject: [PATCH 6/6] metadata: Flush all scheduled writeouts on daemon exit
+
+This patch ensures that we safely write all data from journals to
+metatrees on exit. E.g. if anything happens to session bus or we get
+replaced by some other instance.
+
+https://bugzilla.gnome.org/show_bug.cgi?id=637095
+---
+ metadata/meta-daemon.c | 46 ++++++++++++++++++++++++++++++++++++++++------
+ 1 file changed, 40 insertions(+), 6 deletions(-)
+
+diff --git a/metadata/meta-daemon.c b/metadata/meta-daemon.c
+index f29e7f0..05e1630 100644
+--- a/metadata/meta-daemon.c
++++ b/metadata/meta-daemon.c
+@@ -79,6 +79,24 @@ tree_info_schedule_writeout (TreeInfo *info)
+ }
+ }
+
++static void
++flush_single (const gchar *filename,
++ TreeInfo *info,
++ gpointer user_data)
++{
++ if (info->writeout_timeout != 0)
++ {
++ g_source_remove (info->writeout_timeout);
++ writeout_timeout (info);
++ }
++}
++
++static void
++flush_all ()
++{
++ g_hash_table_foreach (tree_infos, (GHFunc) flush_single, NULL);
++}
++
+ static TreeInfo *
+ tree_info_new (const char *filename)
+ {
+@@ -433,9 +451,22 @@ on_name_lost (GDBusConnection *connection,
+ GMainLoop *loop = user_data;
+
+ /* means that someone has claimed our name (we allow replacement) */
++ flush_all ();
+ g_main_loop_quit (loop);
+ }
+
++static void
++on_connection_closed (GDBusConnection *connection,
++ gboolean remote_peer_vanished,
++ GError *error,
++ gpointer user_data)
++{
++ GMainLoop *loop = user_data;
++
++ /* session bus died */
++ flush_all ();
++ g_main_loop_quit (loop);
++}
+
+ int
+ main (int argc, char *argv[])
+@@ -496,7 +527,15 @@ main (int argc, char *argv[])
+ g_error_free (error);
+ return 1;
+ }
+-
++
++ tree_infos = g_hash_table_new_full (g_str_hash,
++ g_str_equal,
++ NULL,
++ (GDestroyNotify)tree_info_free);
++
++ g_dbus_connection_set_exit_on_close (conn, FALSE);
++ g_signal_connect (conn, "closed", G_CALLBACK (on_connection_closed), loop);
++
+ flags = G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT;
+ if (replace)
+ flags |= G_BUS_NAME_OWNER_FLAGS_REPLACE;
+@@ -509,11 +548,6 @@ main (int argc, char *argv[])
+ loop,
+ NULL);
+
+- tree_infos = g_hash_table_new_full (g_str_hash,
+- g_str_equal,
+- NULL,
+- (GDestroyNotify)tree_info_free);
+-
+ g_main_loop_run (loop);
+
+ if (skeleton)
+--
+1.8.1.4
+
diff --git a/gvfs-1.17.1-metadata-Force-tree-re-read-after-successful-flush.patch b/gvfs-1.17.1-metadata-Force-tree-re-read-after-successful-flush.patch
new file mode 100644
index 0000000..c71f184
--- /dev/null
+++ b/gvfs-1.17.1-metadata-Force-tree-re-read-after-successful-flush.patch
@@ -0,0 +1,89 @@
+From 6b12c3d7b33c87a7fea228106f39ecf2a3e0f310 Mon Sep 17 00:00:00 2001
+From: Tomas Bzatek <tbzatek at redhat.com>
+Date: Mon, 13 May 2013 17:39:26 +0200
+Subject: [PATCH 1/6] metadata: Force tree re-read after successful flush
+
+Once we flush the journal and write new tree file we need to re-read
+it to refresh internal data structures (and mmap data from the right
+file). We originally left this work on meta_tree_refresh_locked() and
+meta_tree_needs_rereading() respectively where we checked the rotated
+bit.
+
+In detail, metabuilder wrote a new temp tree file, then explicitly opened
+the current (old) one, wrote the rotated bit and atomically replaced the
+temp file. Then the metadata daemon having mmapped the old file detected
+the rotated bit and scheduled journal and tree file reopen+reread.
+
+However in concurrent environment like NFS homedir where multiple metadata
+daemons are handling the same database we may run in a race and not getting
+the rotated bit detected properly.
+
+This led to an infinite loop between meta_journal_add_entry() -
+meta_tree_flush_locked() - meta_tree_refresh_locked() - meta_journal_add_entry()
+since we had full journal, didn't detect the rotation and since the files
+were already unlinked, there was no force to break that loop. This patch
+forces tree file re-read after successful flush to prevent this issue.
+
+https://bugzilla.gnome.org/show_bug.cgi?id=637095
+---
+ metadata/metatree.c | 14 ++++++++------
+ 1 file changed, 8 insertions(+), 6 deletions(-)
+
+diff --git a/metadata/metatree.c b/metadata/metatree.c
+index 3bcf9a6..015300e 100644
+--- a/metadata/metatree.c
++++ b/metadata/metatree.c
+@@ -169,7 +169,8 @@ struct _MetaTree {
+ MetaJournal *journal;
+ };
+
+-static void meta_tree_refresh_locked (MetaTree *tree);
++static void meta_tree_refresh_locked (MetaTree *tree,
++ gboolean force_reread);
+ static MetaJournal *meta_journal_open (MetaTree *tree,
+ const char *filename,
+ gboolean for_write,
+@@ -510,7 +511,7 @@ meta_tree_init (MetaTree *tree)
+ journal. However we can detect this case by looking at the tree and see
+ if its been rotated, we do this to ensure we have an uptodate tree+journal
+ combo. */
+- meta_tree_refresh_locked (tree);
++ meta_tree_refresh_locked (tree, FALSE);
+
+ return TRUE;
+
+@@ -658,10 +659,10 @@ meta_tree_has_new_journal_entries (MetaTree *tree)
+
+ /* Must be called with a write lock held */
+ static void
+-meta_tree_refresh_locked (MetaTree *tree)
++meta_tree_refresh_locked (MetaTree *tree, gboolean force_reread)
+ {
+ /* Needs to recheck since we dropped read lock */
+- if (meta_tree_needs_rereading (tree))
++ if (force_reread || meta_tree_needs_rereading (tree))
+ {
+ if (tree->header)
+ meta_tree_clear (tree);
+@@ -685,7 +686,7 @@ meta_tree_refresh (MetaTree *tree)
+ if (needs_refresh)
+ {
+ g_rw_lock_writer_lock (&metatree_lock);
+- meta_tree_refresh_locked (tree);
++ meta_tree_refresh_locked (tree, FALSE);
+ g_rw_lock_writer_unlock (&metatree_lock);
+ }
+ }
+@@ -2363,7 +2364,8 @@ meta_tree_flush_locked (MetaTree *tree)
+ res = meta_builder_write (builder,
+ meta_tree_get_filename (tree));
+ if (res)
+- meta_tree_refresh_locked (tree);
++ /* Force re-read since we wrote a new file */
++ meta_tree_refresh_locked (tree, TRUE);
+
+ meta_builder_free (builder);
+
+--
+1.8.1.4
+
diff --git a/gvfs-1.17.1-metadata-Put-journal-in-XDG_RUNTIME_DIR-for-shared-N.patch b/gvfs-1.17.1-metadata-Put-journal-in-XDG_RUNTIME_DIR-for-shared-N.patch
new file mode 100644
index 0000000..c7b0f68
--- /dev/null
+++ b/gvfs-1.17.1-metadata-Put-journal-in-XDG_RUNTIME_DIR-for-shared-N.patch
@@ -0,0 +1,370 @@
+From 749c872b9192a84e65d83bc0f0eb697ab247fdd8 Mon Sep 17 00:00:00 2001
+From: Tomas Bzatek <tbzatek at redhat.com>
+Date: Mon, 13 May 2013 17:43:02 +0200
+Subject: [PATCH 4/6] metadata: Put journal in $XDG_RUNTIME_DIR for shared NFS
+ homedir case
+
+This essentially moves is_on_nfs() from metatree.c in metabuilder.c
+as the more appropriate place for shared functions. It's used in
+meta_builder_get_journal_filename() to determine whether to use original
+metadata directory or temporary $XDG_RUNTIME_DIR location to work around
+certain NFS issues.
+
+The idea behind this change is to have separate journals for every client
+that is accessing shared homedir. Then the only possible point of conflict
+is on rotation which is backed up by atomic file rename. Without this,
+there were multiple metadata daemons writing to the same journal file,
+overwriting changes to each other and being racy in flush and rotation.
+
+There will always be a conflict between clients, overwriting tree file
+data by flushing their journals.
+
+https://bugzilla.gnome.org/show_bug.cgi?id=637095
+---
+ metadata/metabuilder.c | 135 +++++++++++++++++++++++++++++++++++++++++++++++--
+ metadata/metabuilder.h | 3 ++
+ metadata/metatree.c | 103 +------------------------------------
+ 3 files changed, 136 insertions(+), 105 deletions(-)
+
+diff --git a/metadata/metabuilder.c b/metadata/metabuilder.c
+index c7e69fa..af9e99d 100644
+--- a/metadata/metabuilder.c
++++ b/metadata/metabuilder.c
+@@ -1,3 +1,4 @@
++#include "config.h"
+ #include "metabuilder.h"
+ #include <sys/types.h>
+ #include <sys/stat.h>
+@@ -8,6 +9,44 @@
+ #include <sys/mman.h>
+ #include <glib/gstdio.h>
+
++#if HAVE_SYS_STATFS_H
++#include <sys/statfs.h>
++#endif
++#if HAVE_SYS_STATVFS_H
++#include <sys/statvfs.h>
++#endif
++#if HAVE_SYS_VFS_H
++#include <sys/vfs.h>
++#elif HAVE_SYS_MOUNT_H
++#if HAVE_SYS_PARAM_H
++#include <sys/param.h>
++#endif
++#include <sys/mount.h>
++#endif
++
++#if defined(HAVE_STATFS) && defined(HAVE_STATVFS)
++/* Some systems have both statfs and statvfs, pick the
++ most "native" for these */
++# if !defined(HAVE_STRUCT_STATFS_F_BAVAIL)
++ /* on solaris and irix, statfs doesn't even have the
++ f_bavail field */
++# define USE_STATVFS
++# else
++ /* at least on linux, statfs is the actual syscall */
++# define USE_STATFS
++# endif
++
++#elif defined(HAVE_STATFS)
++
++# define USE_STATFS
++
++#elif defined(HAVE_STATVFS)
++
++# define USE_STATVFS
++
++#endif
++
++
+ #define MAJOR_VERSION 1
+ #define MINOR_VERSION 0
+ #define MAJOR_JOURNAL_VERSION 1
+@@ -825,12 +864,89 @@ write_all_data_and_close (int fd, char *data, gsize len)
+ return res;
+ }
+
++gboolean
++meta_builder_is_on_nfs (const char *filename)
++{
++#ifdef USE_STATFS
++ struct statfs statfs_buffer;
++ int statfs_result;
++#elif defined(USE_STATVFS) && defined(HAVE_STRUCT_STATVFS_F_BASETYPE)
++ struct statvfs statfs_buffer;
++ int statfs_result;
++#endif
++ char *dirname;
++ gboolean res;
++
++ dirname = g_path_get_dirname (filename);
++
++ res = FALSE;
++
++#ifdef USE_STATFS
++
++# if STATFS_ARGS == 2
++ statfs_result = statfs (dirname, &statfs_buffer);
++# elif STATFS_ARGS == 4
++ statfs_result = statfs (dirname, &statfs_buffer,
++ sizeof (statfs_buffer), 0);
++# endif
++ if (statfs_result == 0)
++#ifdef __OpenBSD__
++ res = strcmp(statfs_buffer.f_fstypename, MOUNT_NFS) == 0;
++#else
++ res = statfs_buffer.f_type == 0x6969;
++#endif
++
++#elif defined(USE_STATVFS) && defined(HAVE_STRUCT_STATVFS_F_BASETYPE)
++ statfs_result = statvfs (dirname, &statfs_buffer);
++
++ if (statfs_result == 0)
++ res = strcmp (statfs_buffer.f_basetype, "nfs") == 0;
++#endif
++
++ g_free (dirname);
++
++ return res;
++}
++
+ static char *
+-get_journal_filename (const char *filename, guint32 random_tag)
++get_runtime_journal_dir (const char *tree_filename)
++{
++ const char *rd;
++ char *dbname;
++ char *real_path;
++ char *ret;
++
++ rd = g_get_user_runtime_dir ();
++ if (! rd || *rd == '\0')
++ return NULL;
++
++ real_path = g_build_filename (rd, "gvfs-metadata", NULL);
++ if (! g_file_test (real_path, G_FILE_TEST_EXISTS))
++ {
++ if (g_mkdir_with_parents (real_path, 0700) != 0)
++ {
++ g_free (real_path);
++ return NULL;
++ }
++ }
++
++ dbname = g_path_get_basename (tree_filename);
++ ret = g_build_filename (real_path, dbname, NULL);
++
++ g_free (dbname);
++ g_free (real_path);
++
++ return ret;
++}
++
++char *
++meta_builder_get_journal_filename (const char *tree_filename, guint32 random_tag)
+ {
+ const char *hexdigits = "0123456789abcdef";
+ char tag[9];
+ int i;
++ char *ret;
++ char *real_filename = NULL;
+
+ for (i = 7; i >= 0; i--)
+ {
+@@ -840,7 +956,18 @@ get_journal_filename (const char *filename, guint32 random_tag)
+
+ tag[8] = 0;
+
+- return g_strconcat (filename, "-", tag, ".log", NULL);
++ if (meta_builder_is_on_nfs (tree_filename))
++ {
++ /* Put the journal in $XDG_RUNTIME_DIR to avoid file usage from concurrent clients */
++ real_filename = get_runtime_journal_dir (tree_filename);
++ }
++
++ if (! real_filename)
++ return g_strconcat (tree_filename, "-", tag, ".log", NULL);
++
++ ret = g_strconcat (real_filename, "-", tag, ".log", NULL);
++ g_free (real_filename);
++ return ret;
+ }
+
+ gboolean
+@@ -852,7 +979,7 @@ meta_builder_create_new_journal (const char *filename, guint32 random_tag)
+ gsize pos;
+ gboolean res;
+
+- journal_name = get_journal_filename (filename, random_tag);
++ journal_name = meta_builder_get_journal_filename (filename, random_tag);
+
+ out = g_string_new (NULL);
+
+@@ -1055,7 +1182,7 @@ meta_builder_write (MetaBuilder *builder,
+ munmap (data, RANDOM_TAG_OFFSET + 4);
+ close (fd2);
+
+- old_log = get_journal_filename (filename, old_tag);
++ old_log = meta_builder_get_journal_filename (filename, old_tag);
+ g_unlink (old_log);
+ g_free (old_log);
+ }
+diff --git a/metadata/metabuilder.h b/metadata/metabuilder.h
+index ad3876f..aa173c5 100644
+--- a/metadata/metabuilder.h
++++ b/metadata/metabuilder.h
+@@ -70,6 +70,9 @@ gboolean meta_builder_write (MetaBuilder *builder,
+ const char *filename);
+ gboolean meta_builder_create_new_journal (const char *filename,
+ guint32 random_tag);
++char * meta_builder_get_journal_filename (const char *tree_filename,
++ guint32 random_tag);
++gboolean meta_builder_is_on_nfs (const char *filename);
+ MetaFile * metafile_new (const char *name,
+ MetaFile *parent);
+ void metafile_free (MetaFile *file);
+diff --git a/metadata/metatree.c b/metadata/metatree.c
+index 8e2ab46..31ef8a6 100644
+--- a/metadata/metatree.c
++++ b/metadata/metatree.c
+@@ -9,43 +9,6 @@
+ #include <stdlib.h>
+ #include <time.h>
+
+-#if HAVE_SYS_STATFS_H
+-#include <sys/statfs.h>
+-#endif
+-#if HAVE_SYS_STATVFS_H
+-#include <sys/statvfs.h>
+-#endif
+-#if HAVE_SYS_VFS_H
+-#include <sys/vfs.h>
+-#elif HAVE_SYS_MOUNT_H
+-#if HAVE_SYS_PARAM_H
+-#include <sys/param.h>
+-#endif
+-#include <sys/mount.h>
+-#endif
+-
+-#if defined(HAVE_STATFS) && defined(HAVE_STATVFS)
+-/* Some systems have both statfs and statvfs, pick the
+- most "native" for these */
+-# if !defined(HAVE_STRUCT_STATFS_F_BAVAIL)
+- /* on solaris and irix, statfs doesn't even have the
+- f_bavail field */
+-# define USE_STATVFS
+-# else
+- /* at least on linux, statfs is the actual syscall */
+-# define USE_STATFS
+-# endif
+-
+-#elif defined(HAVE_STATFS)
+-
+-# define USE_STATFS
+-
+-#elif defined(HAVE_STATVFS)
+-
+-# define USE_STATVFS
+-
+-#endif
+-
+ #include "metatree.h"
+ #include "metabuilder.h"
+ #include <glib.h>
+@@ -278,50 +241,6 @@ meta_tree_clear (MetaTree *tree)
+ }
+
+ static gboolean
+-is_on_nfs (char *filename)
+-{
+-#ifdef USE_STATFS
+- struct statfs statfs_buffer;
+- int statfs_result;
+-#elif defined(USE_STATVFS) && defined(HAVE_STRUCT_STATVFS_F_BASETYPE)
+- struct statvfs statfs_buffer;
+- int statfs_result;
+-#endif
+- char *dirname;
+- gboolean res;
+-
+- dirname = g_path_get_dirname (filename);
+-
+- res = FALSE;
+-
+-#ifdef USE_STATFS
+-
+-# if STATFS_ARGS == 2
+- statfs_result = statfs (dirname, &statfs_buffer);
+-# elif STATFS_ARGS == 4
+- statfs_result = statfs (dirname, &statfs_buffer,
+- sizeof (statfs_buffer), 0);
+-# endif
+- if (statfs_result == 0)
+-#ifdef __OpenBSD__
+- res = strcmp(statfs_buffer.f_fstypename, MOUNT_NFS) == 0;
+-#else
+- res = statfs_buffer.f_type == 0x6969;
+-#endif
+-
+-#elif defined(USE_STATVFS) && defined(HAVE_STRUCT_STATVFS_F_BASETYPE)
+- statfs_result = statvfs (dirname, &statfs_buffer);
+-
+- if (statfs_result == 0)
+- res = strcmp (statfs_buffer.f_basetype, "nfs") == 0;
+-#endif
+-
+- g_free (dirname);
+-
+- return res;
+-}
+-
+-static gboolean
+ link_to_tmp (const char *source, char *tmpl)
+ {
+ char *XXXXXX;
+@@ -431,7 +350,7 @@ meta_tree_init (MetaTree *tree)
+
+ retried = FALSE;
+ retry:
+- tree->on_nfs = is_on_nfs (tree->filename);
++ tree->on_nfs = meta_builder_is_on_nfs (tree->filename);
+ fd = safe_open (tree, tree->filename, O_RDONLY);
+ if (fd == -1)
+ {
+@@ -845,24 +764,6 @@ meta_data_get_key (MetaTree *tree,
+ return dataent;
+ }
+
+-static char *
+-get_journal_filename (const char *filename, guint32 random_tag)
+-{
+- const char *hexdigits = "0123456789abcdef";
+- char tag[9];
+- int i;
+-
+- for (i = 7; i >= 0; i--)
+- {
+- tag[i] = hexdigits[random_tag % 0x10];
+- random_tag >>= 4;
+- }
+-
+- tag[8] = 0;
+-
+- return g_strconcat (filename, "-", tag, ".log", NULL);
+-}
+-
+ static void
+ meta_journal_free (MetaJournal *journal)
+ {
+@@ -1157,7 +1058,7 @@ meta_journal_open (MetaTree *tree, const char *filename, gboolean for_write, gui
+ open_flags = O_RDONLY;
+
+ retry:
+- journal_filename = get_journal_filename (filename, tag);
++ journal_filename = meta_builder_get_journal_filename (filename, tag);
+ fd = safe_open (tree, journal_filename, open_flags);
+ g_free (journal_filename);
+ if (fd == -1)
+--
+1.8.1.4
+
diff --git a/gvfs-1.17.1-metadata-Use-shorter-writeout-timeout-on-NFS.patch b/gvfs-1.17.1-metadata-Use-shorter-writeout-timeout-on-NFS.patch
new file mode 100644
index 0000000..dd3eedf
--- /dev/null
+++ b/gvfs-1.17.1-metadata-Use-shorter-writeout-timeout-on-NFS.patch
@@ -0,0 +1,78 @@
+From c8e7d1375715545f28a0943ce7657330e3b70acd Mon Sep 17 00:00:00 2001
+From: Tomas Bzatek <tbzatek at redhat.com>
+Date: Mon, 13 May 2013 17:43:19 +0200
+Subject: [PATCH 5/6] metadata: Use shorter writeout timeout on NFS
+
+Since we've moved journal to a non-volatile storage, let's flush
+more often to minimize a chance of data loss.
+
+https://bugzilla.gnome.org/show_bug.cgi?id=637095
+---
+ metadata/meta-daemon.c | 12 +++++++++---
+ metadata/metatree.c | 6 ++++++
+ metadata/metatree.h | 1 +
+ 3 files changed, 16 insertions(+), 3 deletions(-)
+
+diff --git a/metadata/meta-daemon.c b/metadata/meta-daemon.c
+index ce34b73..f29e7f0 100644
+--- a/metadata/meta-daemon.c
++++ b/metadata/meta-daemon.c
+@@ -32,6 +32,7 @@
+ #include "metadata-dbus.h"
+
+ #define WRITEOUT_TIMEOUT_SECS 60
++#define WRITEOUT_TIMEOUT_SECS_NFS 15
+
+ typedef struct {
+ char *filename;
+@@ -67,10 +68,15 @@ writeout_timeout (gpointer data)
+ static void
+ tree_info_schedule_writeout (TreeInfo *info)
+ {
++ gboolean on_nfs;
++
+ if (info->writeout_timeout == 0)
+- info->writeout_timeout =
+- g_timeout_add_seconds (WRITEOUT_TIMEOUT_SECS,
+- writeout_timeout, info);
++ {
++ on_nfs = meta_tree_is_on_nfs (info->tree);
++ info->writeout_timeout =
++ g_timeout_add_seconds (on_nfs ? WRITEOUT_TIMEOUT_SECS_NFS : WRITEOUT_TIMEOUT_SECS,
++ writeout_timeout, info);
++ }
+ }
+
+ static TreeInfo *
+diff --git a/metadata/metatree.c b/metadata/metatree.c
+index 31ef8a6..6aef33c 100644
+--- a/metadata/metatree.c
++++ b/metadata/metatree.c
+@@ -472,6 +472,12 @@ meta_tree_exists (MetaTree *tree)
+ return tree->fd != -1;
+ }
+
++gboolean
++meta_tree_is_on_nfs (MetaTree *tree)
++{
++ return tree->on_nfs;
++}
++
+ static GHashTable *cached_trees = NULL;
+ G_LOCK_DEFINE_STATIC (cached_trees);
+
+diff --git a/metadata/metatree.h b/metadata/metatree.h
+index 4bbb192..f24b4e9 100644
+--- a/metadata/metatree.h
++++ b/metadata/metatree.h
+@@ -66,6 +66,7 @@ void meta_tree_unref (MetaTree *tree);
+ void meta_tree_refresh (MetaTree *tree);
+ const char *meta_tree_get_filename (MetaTree *tree);
+ gboolean meta_tree_exists (MetaTree *tree);
++gboolean meta_tree_is_on_nfs (MetaTree *tree);
+
+ MetaKeyType meta_tree_lookup_key_type (MetaTree *tree,
+ const char *path,
+--
+1.8.1.4
+
diff --git a/gvfs.spec b/gvfs.spec
index c8bb44d..f633816 100644
--- a/gvfs.spec
+++ b/gvfs.spec
@@ -1,7 +1,7 @@
Summary: Backends for the gio framework in GLib
Name: gvfs
Version: 1.14.2
-Release: 3%{?dist}
+Release: 4%{?dist}
License: GPLv3 and LGPLv2+
Group: System Environment/Libraries
URL: http://www.gtk.org
@@ -41,6 +41,16 @@ Patch0: gvfs-archive-integration.patch
# from upstream
Patch1: gvfs-1.15.4-tmpfilesd.patch
+# https://bugzilla.redhat.com/show_bug.cgi?id=561904
+# gvfsd-metadata producing large amounts of traffic to nfs server
+Patch10: gvfs-1.17.1-metadata-Be-more-resistive-to-broken-journal-files.patch
+Patch11: gvfs-1.17.1-metadata-Force-tree-re-read-after-successful-flush.patch
+Patch12: gvfs-1.17.1-metadata-Create-new-journal-if-it-doesn-t-exist.patch
+Patch13: gvfs-1.17.1-metadata-Put-journal-in-XDG_RUNTIME_DIR-for-shared-N.patch
+Patch14: gvfs-1.17.1-metadata-Use-shorter-writeout-timeout-on-NFS.patch
+Patch15: gvfs-1.17.1-metadata-Flush-all-scheduled-writeouts-on-daemon-exi.patch
+
+
Obsoletes: gnome-mount <= 0.8
Obsoletes: gnome-mount-nautilus-properties <= 0.8
@@ -155,6 +165,12 @@ to applications using gvfs.
%setup -q
%patch0 -p1 -b .archive-integration
%patch1 -p1 -b .tmpfilesd
+%patch10 -p1 -b .metadata-Be-more-resistive-to-broken-journal-files
+%patch11 -p1 -b .metadata-Force-tree-re-read-after-successful-flush
+%patch12 -p1 -b .metadata-Create-new-journal-if-it-doesn-t-exist
+%patch13 -p1 -b .metadata-Put-journal-in-XDG_RUNTIME_DIR-for-shared-NFS
+%patch14 -p1 -b .metadata-Use-shorter-writeout-timeout-on-NFS
+%patch15 -p1 -b .metadata-Flush-all-scheduled-writeouts-on-daemon-exit
%build
# Needed for gvfs-0.2.1-archive-integration.patch
@@ -335,6 +351,9 @@ killall -USR1 gvfsd >&/dev/null || :
%{_datadir}/gvfs/mounts/afp-browse.mount
%changelog
+* Tue May 14 2013 Tomas Bzatek <tbzatek at redhat.com> - 1.14.2-4
+- Fix metadata issues on NFS homedirs (#561904)
+
* Wed Feb 6 2013 Tomas Bzatek <tbzatek at redhat.com> - 1.14.2-3
- Install systemd tmpfiles.d exclusion file for gvfs-fuse (#902743)
More information about the scm-commits
mailing list