summaryrefslogtreecommitdiff
path: root/metadata/metabuilder.c
diff options
context:
space:
mode:
authorTomas Bzatek <tbzatek@redhat.com>2013-05-13 17:43:02 +0200
committerTomas Bzatek <tbzatek@redhat.com>2013-05-13 17:43:02 +0200
commit749c872b9192a84e65d83bc0f0eb697ab247fdd8 (patch)
tree594ccff738957328d573b104688446b60ac829ba /metadata/metabuilder.c
parent3381859ba7a92f4824ff09a7aa951407bf4e1c72 (diff)
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
Diffstat (limited to 'metadata/metabuilder.c')
-rw-r--r--metadata/metabuilder.c135
1 files changed, 131 insertions, 4 deletions
diff --git a/metadata/metabuilder.c b/metadata/metabuilder.c
index c7e69fac..af9e99da 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);
}