aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Seebach <peter.seebach@windriver.com>2015-08-20 17:28:04 -0500
committerPeter Seebach <peter.seebach@windriver.com>2015-08-20 17:29:02 -0500
commit1b920ba0441dc7de038a1970c35f4b9b99744400 (patch)
treef8d7e0e0282e39062bc40cca0a1cfc87f72da5e4
parent79cd74c8643eeaef52e9f78135f60a9652bcf65c (diff)
downloadpseudo-1b920ba0441dc7de038a1970c35f4b9b99744400.tar.gz
pseudo-1b920ba0441dc7de038a1970c35f4b9b99744400.tar.bz2
pseudo-1b920ba0441dc7de038a1970c35f4b9b99744400.zip
New option: Use extended attributes to store db values.
This is a moderately experimental feature which stores values in an extended attribute called 'user.pseudo_data' instead of in the database. Still missing: Database<->filesystem synchronization for this. For at least some workloads, this can dramatically improve performance. Signed-off-by: Peter Seebach <peter.seebach@windriver.com>
-rw-r--r--Makefile.in14
-rwxr-xr-xconfigure26
-rw-r--r--offsets.c2
-rw-r--r--ports/darwin/guts/stat.c2
-rw-r--r--ports/unix/guts/fchown.c11
-rw-r--r--ports/unix/guts/fchownat.c14
-rw-r--r--ports/unix/guts/linkat.c2
-rw-r--r--pseudo_client.c180
-rw-r--r--pseudo_util.c6
-rw-r--r--pseudo_wrappers.c18
10 files changed, 244 insertions, 31 deletions
diff --git a/Makefile.in b/Makefile.in
index 1c8bd6a..ea90b5b 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -26,13 +26,19 @@ SQLITE_LIB=@SQLITE_LIB@
SQLITE_MEMORY=@SQLITE_MEMORY@
FORCE_ASYNC=@FORCE_ASYNC@
XATTR=@XATTR@
-ifeq (true,@PROFILING@)
- PROFILING=-DPSEUDO_PROFILING
+XATTRDB=@XATTRDB@
+PROFILING=@PROFILING@
+ifeq (true,$(PROFILING))
PSEUDO_PROFILE=$(BIN)/pseudo_profile
else
- PROFILING=
PSEUDO_PROFILE=
endif
+define cond
+ $(if $(filter true,$($(1))),-D$(2))
+endef
+OPTDEFS=$(call cond,XATTR,PSEUDO_XATTR_SUPPORT) \
+ $(call cond,XATTRDB,PSEUDO_XATTRDB) \
+ $(call cond,PROFILING,PSEUDO_PROFILING)
PASSWD_FALLBACK=@PASSWD_FALLBACK@
BITS=@BITS@
ARCH_FLAGS=@ARCH_FLAGS@
@@ -48,7 +54,7 @@ LOCALSTATEDIR=$(PREFIX)/$(LOCALSTATE)
CFLAGS_BASE=-pipe -std=gnu99 -Wall -W -Wextra
CFLAGS_CODE=-fPIC -D_LARGEFILE64_SOURCE -D_ATFILE_SOURCE $(ARCH_FLAGS)
-CFLAGS_DEFS=-DPSEUDO_PREFIX='"$(PREFIX)"' -DPSEUDO_SUFFIX='"$(SUFFIX)"' -DPSEUDO_BINDIR='"$(BIN)"' -DPSEUDO_LIBDIR='"$(LIB)"' -DPSEUDO_LOCALSTATEDIR='"$(LOCALSTATE)"' -DPSEUDO_VERSION='"$(VERSION)"' $(SQLITE_MEMORY) $(FORCE_ASYNC) -DPSEUDO_PASSWD_FALLBACK='$(PASSWD_FALLBACK)' $(PROFILING)
+CFLAGS_DEFS=-DPSEUDO_PREFIX='"$(PREFIX)"' -DPSEUDO_SUFFIX='"$(SUFFIX)"' -DPSEUDO_BINDIR='"$(BIN)"' -DPSEUDO_LIBDIR='"$(LIB)"' -DPSEUDO_LOCALSTATEDIR='"$(LOCALSTATE)"' -DPSEUDO_VERSION='"$(VERSION)"' $(SQLITE_MEMORY) $(FORCE_ASYNC) -DPSEUDO_PASSWD_FALLBACK='$(PASSWD_FALLBACK)' $(OPTDEFS)
CFLAGS_DEBUG=-O2 -g
@DEFAULT_SQLITE@CFLAGS_SQL=-L$(SQLITE)/$(SQLITE_LIB) -I$(SQLITE)/include $(RPATH)
CFLAGS_PSEUDO=$(CFLAGS_BASE) $(CFLAGS_CODE) $(CFLAGS_DEFS) \
diff --git a/configure b/configure
index 9472701..e5ef9ce 100755
--- a/configure
+++ b/configure
@@ -28,6 +28,7 @@ opt_rpath=
opt_memory=
opt_async=
opt_xattr=
+opt_xattrdb=false
opt_profile=false
opt_passwd_fallback='""'
@@ -42,6 +43,7 @@ usage()
echo >&2 " [--suffix=...]"
echo >&2 " [--enable-memory-db]"
echo >&2 " [--enable-xattr]"
+ echo >&2 " [--enable-xattrdb]"
echo >&2 " [--enable-profiling]"
echo >&2 " [--enable-force-async]"
echo >&2 " [--with-sqlite=...]"
@@ -76,7 +78,7 @@ do
else
maybe_prefix=$opt_prefix
fi
- if [ "$maybe_prefix" == "$(pwd)" ]; then
+ if [ "$maybe_prefix" = "$(pwd)" ]; then
echo >&2 "ERROR: Prefix is current directory. That doesn't work."
exit 1
fi
@@ -119,6 +121,12 @@ do
--enable-xattr=yes | --enable-xattr)
opt_xattr=true
;;
+ --enable-xattrdb=no)
+ opt_xattrdb=false
+ ;;
+ --enable-xattrdb=yes | --enable-xattrdb)
+ opt_xattrdb=true
+ ;;
--enable-memory-db=no)
opt_memory=false
;;
@@ -259,16 +267,21 @@ fi
if [ -z "$opt_xattr" ]; then
- if $xattr_runs; then
+ if $opt_xattrdb; then
opt_xattr=true
- echo "getfattr runs, enabling extended attribute support"
+ echo "xattr DB support implies extended attribute support"
else
- opt_xattr=false
- echo "getfattr fails, disabling extended attribute support"
+ if $xattr_runs; then
+ opt_xattr=true
+ echo "getfattr runs, enabling extended attribute support"
+ else
+ opt_xattr=false
+ echo "getfattr fails, disabling extended attribute support"
+ fi
fi
fi
-if $opt_xattr; then
+if $opt_xattr || $opt_xattrdb; then
if ! $xattr_runs; then
echo >&2 "WARNING: getfattr doesn't work, but xattr-related features requestd."
fi
@@ -308,6 +321,7 @@ touch func_deps.mk
sed -e '
s,@PREFIX@,'"$opt_prefix"',g
s,@XATTR@,'"$opt_xattr"',g
+ s,@XATTRDB@,'"$opt_xattrdb"',g
s,@PROFILING@,'"$opt_profiling"',g
s,@LIBDIR@,'"$opt_libdir"',g
s,@LIB@,'"$opt_lib"',g
diff --git a/offsets.c b/offsets.c
index 7e59d05..5e9cddd 100644
--- a/offsets.c
+++ b/offsets.c
@@ -17,7 +17,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
+#ifndef _LARGEFILE64_SOURCE
#define _LARGEFILE64_SOURCE
+#endif
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
diff --git a/ports/darwin/guts/stat.c b/ports/darwin/guts/stat.c
index 1e1cf67..8a0742c 100644
--- a/ports/darwin/guts/stat.c
+++ b/ports/darwin/guts/stat.c
@@ -20,7 +20,7 @@
* don't need to check for a symlink on this end
*/
msg = pseudo_client_op(OP_STAT, 0, -1, AT_FDCWD, path, buf);
- if (msg) {
+ if (msg && msg->result == RESULT_SUCCEED) {
pseudo_stat_msg(buf, msg);
}
diff --git a/ports/unix/guts/fchown.c b/ports/unix/guts/fchown.c
index 6e33f0f..89cabe2 100644
--- a/ports/unix/guts/fchown.c
+++ b/ports/unix/guts/fchown.c
@@ -20,15 +20,10 @@
if (owner == (uid_t) -1 || group == (gid_t) -1) {
msg = pseudo_client_op(OP_STAT, 0, fd, -1, NULL, &buf);
/* copy in any existing values... */
- if (msg) {
- if (msg->result == RESULT_SUCCEED) {
- pseudo_stat_msg(&buf, msg);
- } else {
- pseudo_debug(PDBGF_FILE, "fchown fd %d, ino %llu, unknown file.\n",
- fd, (unsigned long long) buf.st_ino);
- }
+ if (msg && msg->result == RESULT_SUCCEED) {
+ pseudo_stat_msg(&buf, msg);
} else {
- pseudo_diag("stat within chown of fd %d [%llu] failed.\n",
+ pseudo_debug(PDBGF_FILE, "fchown fd %d, ino %llu, unknown file.\n",
fd, (unsigned long long) buf.st_ino);
}
}
diff --git a/ports/unix/guts/fchownat.c b/ports/unix/guts/fchownat.c
index f976d91..295726b 100644
--- a/ports/unix/guts/fchownat.c
+++ b/ports/unix/guts/fchownat.c
@@ -36,14 +36,12 @@
if (owner == (uid_t) -1 || group == (gid_t) -1) {
msg = pseudo_client_op(OP_STAT, 0, -1, -1, path, &buf);
/* copy in any existing values... */
- if (msg) {
- if (msg->result == RESULT_SUCCEED) {
- pseudo_stat_msg(&buf, msg);
- } else {
- pseudo_debug(PDBGF_FILE, "chownat to %d:%d on %d/%s, ino %llu, new file.\n",
- owner, group, dirfd, path,
- (unsigned long long) buf.st_ino);
- }
+ if (msg && msg->result == RESULT_SUCCEED) {
+ pseudo_stat_msg(&buf, msg);
+ } else {
+ pseudo_debug(PDBGF_FILE, "chownat to %d:%d on %d/%s, ino %llu, new file.\n",
+ owner, group, dirfd, path,
+ (unsigned long long) buf.st_ino);
}
}
/* now override with arguments */
diff --git a/ports/unix/guts/linkat.c b/ports/unix/guts/linkat.c
index fe29b39..ec27e47 100644
--- a/ports/unix/guts/linkat.c
+++ b/ports/unix/guts/linkat.c
@@ -55,7 +55,7 @@
return rc;
}
msg = pseudo_client_op(OP_STAT, 0, -1, -1, oldpath, &buf);
- if (msg) {
+ if (msg && msg->result == RESULT_SUCCEED) {
pseudo_stat_msg(&buf, msg);
}
/* Long story short: I am pretty sure we still want OP_LINK even
diff --git a/pseudo_client.c b/pseudo_client.c
index 7f30467..bb9e1e8 100644
--- a/pseudo_client.c
+++ b/pseudo_client.c
@@ -37,6 +37,10 @@
#include <pwd.h>
#include <grp.h>
+#ifdef PSEUDO_XATTRDB
+#include <sys/xattr.h>
+#endif
+
#include "pseudo.h"
#include "pseudo_ipc.h"
#include "pseudo_client.h"
@@ -190,6 +194,125 @@ build_passwd_paths(void)
return;
}
+#ifdef PSEUDO_XATTRDB
+/* We really want to avoid calling the wrappers for these inside the
+ * implementation. pseudo_wrappers will reinitialize these after it's
+ * gotten the real_* found.
+ */
+ssize_t (*pseudo_real_lgetxattr)(const char *, const char *, void *, size_t) = lgetxattr;
+ssize_t (*pseudo_real_fgetxattr)(int, const char *, void *, size_t) = fgetxattr;
+int (*pseudo_real_lsetxattr)(const char *, const char *, const void *, size_t, int) = lsetxattr;
+int (*pseudo_real_fsetxattr)(int, const char *, const void *, size_t, int) = fsetxattr;
+/* Executive summary: We use an extended attribute,
+ * user.pseudo_data, to store exactly the data we would otherwise
+ * have stored in the database. Which is to say, uid, gid, mode, rdev.
+ *
+ * If we don't find a value, save an empty one with a lower version
+ * number to indicate that we don't have data to reduce round trips.
+ */
+typedef struct {
+ int version;
+ uid_t uid;
+ gid_t gid;
+ mode_t mode;
+ dev_t rdev;
+} pseudo_db_data_t;
+
+static pseudo_msg_t xattrdb_data;
+
+pseudo_msg_t *
+pseudo_xattrdb_save(int fd, const char *path, const struct stat64 *buf) {
+ int rc = -1;
+ if (!path && fd < 0)
+ return NULL;
+ if (!buf)
+ return NULL;
+ pseudo_db_data_t pseudo_db_data = {
+ .version = 1,
+ .uid = buf->st_uid,
+ .gid = buf->st_gid,
+ .mode = buf->st_mode,
+ .rdev = buf->st_rdev
+ };
+ if (path) {
+ rc = pseudo_real_lsetxattr(path, "user.pseudo_data", &pseudo_db_data, sizeof(pseudo_db_data), 0);
+ } else if (fd >= 0) {
+ rc = pseudo_real_fsetxattr(fd, "user.pseudo_data", &pseudo_db_data, sizeof(pseudo_db_data), 0);
+ }
+ pseudo_debug(PDBGF_XATTRDB, "tried to save data for %s/%d: uid %d, mode %o, rc %d.\n",
+ path ? path : "<nil>", fd, (int) pseudo_db_data.uid, (int) pseudo_db_data.mode, rc);
+ /* none of the other fields are checked on save, and the value
+ * is currently only really used by mknod.
+ */
+ if (rc == 0) {
+ xattrdb_data.result = RESULT_SUCCEED;
+ return &xattrdb_data;
+ }
+ return NULL;
+}
+
+pseudo_msg_t *
+pseudo_xattrdb_load(int fd, const char *path, const struct stat64 *buf) {
+ int rc = -1, retryrc = -1;
+ if (!path && fd < 0)
+ return NULL;
+ /* don't try to getxattr on a thing unless we think it is
+ * likely to work.
+ */
+ if (buf) {
+ if (!S_ISDIR(buf->st_mode) && !S_ISREG(buf->st_mode)) {
+ return NULL;
+ }
+ }
+ pseudo_db_data_t pseudo_db_data;
+ if (path) {
+ rc = pseudo_real_lgetxattr(path, "user.pseudo_data", &pseudo_db_data, sizeof(pseudo_db_data));
+ if (rc == -1) {
+ pseudo_db_data = (pseudo_db_data_t) { .version = 0 };
+ retryrc = pseudo_real_lsetxattr(path, "user.pseudo_data", &pseudo_db_data, sizeof(pseudo_db_data), 0);
+ }
+ } else if (fd >= 0) {
+ rc = pseudo_real_fgetxattr(fd, "user.pseudo_data", &pseudo_db_data, sizeof(pseudo_db_data));
+ if (rc == -1) {
+ pseudo_db_data = (pseudo_db_data_t) { .version = 0 };
+ retryrc = pseudo_real_fsetxattr(fd, "user.pseudo_data", &pseudo_db_data, sizeof(pseudo_db_data), 0);
+ }
+ }
+ pseudo_debug(PDBGF_XATTRDB, "tried to load data for %s/%d: rc %d, version %d.\n",
+ path ? path : "<nil>", fd, rc, pseudo_db_data.version);
+ if (rc == -1 && retryrc == 0) {
+ /* there's no data, but there could have been; treat
+ * this as an empty database result.
+ */
+ xattrdb_data.result = RESULT_FAIL;
+ return &xattrdb_data;
+ } else if (rc == -1) {
+ /* we can't create an extended attribute, so we may have
+ * used the database.
+ */
+ return NULL;
+ }
+ /* Version 0 = just recording that we looked and found
+ * nothing.
+ * Version 1 = actually implemented.
+ */
+ switch (pseudo_db_data.version) {
+ case 0:
+ default:
+ xattrdb_data.result = RESULT_FAIL;
+ break;
+ case 1:
+ xattrdb_data.uid = pseudo_db_data.uid;
+ xattrdb_data.gid = pseudo_db_data.gid;
+ xattrdb_data.mode = pseudo_db_data.mode;
+ xattrdb_data.rdev = pseudo_db_data.rdev;
+ xattrdb_data.result = RESULT_SUCCEED;
+ break;
+ }
+ return &xattrdb_data;
+}
+#endif
+
#ifdef PSEUDO_PROFILING
static int pseudo_profile_pid = -2;
@@ -379,7 +502,8 @@ pseudo_init_client(void) {
pseudo_set_value("PSEUDO_ALLOW_FSYNC", env);
}
if (env) {
- pseudo_allow_fsync = 1;
+ // stupid hack
+ // pseudo_allow_fsync = 1;
} else {
pseudo_allow_fsync = 0;
}
@@ -1309,6 +1433,42 @@ pseudo_client_op(pseudo_op_t op, int access, int fd, int dirfd, const char *path
}
}
+#ifdef PSEUDO_XATTRDB
+ /* maybe use xattr instead */
+ /* note: if we use xattr, logging won't work reliably
+ * because the server won't get messages if these work.
+ */
+ switch (op) {
+ case OP_CHMOD:
+ case OP_CREAT:
+ case OP_FCHMOD:
+ case OP_MKDIR:
+ case OP_MKNOD:
+ {
+ /* use magic uid/gid */
+ struct stat64 bufcopy;
+ bufcopy = *buf;
+ bufcopy.st_uid = pseudo_fuid;
+ bufcopy.st_gid = pseudo_fgid;
+ result = pseudo_xattrdb_save(fd, path, &bufcopy);
+ }
+ break;
+ case OP_CHOWN:
+ case OP_FCHOWN:
+ case OP_LINK:
+ result = pseudo_xattrdb_save(fd, path, buf);
+ break;
+ case OP_FSTAT:
+ case OP_STAT:
+ result = pseudo_xattrdb_load(fd, path, buf);
+ break;
+ default:
+ break;
+ }
+ if (result)
+ goto skip_path;
+#endif
+
if (op == OP_RENAME) {
va_list ap;
if (!path) {
@@ -1427,6 +1587,13 @@ pseudo_client_op(pseudo_op_t op, int access, int fd, int dirfd, const char *path
}
}
+#ifdef PSEUDO_XATTRDB
+ /* If we were able to store things in xattr, we can easily skip
+ * most of the fancy path computations and such.
+ */
+ skip_path:
+#endif
+
if (buf)
pseudo_msg_stat(&msg, buf);
@@ -1555,7 +1722,10 @@ pseudo_client_op(pseudo_op_t op, int access, int fd, int dirfd, const char *path
pseudo_diag("error: unknown or unimplemented operator %d (%s)", op, pseudo_op_name(op));
break;
}
- if (do_request) {
+ /* result can only be set when PSEUDO_XATTRDB resulted in a
+ * successful store to or read from the local database.
+ */
+ if (do_request && !result) {
#ifdef PSEUDO_PROFILING
struct timeval tv1_ipc, tv2_ipc;
#endif
@@ -1598,6 +1768,12 @@ pseudo_client_op(pseudo_op_t op, int access, int fd, int dirfd, const char *path
} else if (!result) {
pseudo_debug(PDBGF_OP, "(%d) (no request)", getpid());
}
+ #ifdef PSEUDO_XATTRDB
+ else {
+ pseudo_debug(PDBGF_OP, "(%d) (handled through xattrdb)", getpid());
+ pseudo_debug(PDBGF_OP, "result: %d\n", result->result);
+ }
+ #endif
pseudo_debug(PDBGF_OP, "\n");
#ifdef PSEUDO_PROFILING
diff --git a/pseudo_util.c b/pseudo_util.c
index 865222a..7142670 100644
--- a/pseudo_util.c
+++ b/pseudo_util.c
@@ -82,6 +82,10 @@ static struct pseudo_variables pseudo_env[] = {
*/
static int pseudo_util_initted = -1; /* Not yet run */
+/* bypass wrapper logic on path computations */
+int (*pseudo_real_lstat)(const char *path, struct stat *buf) = lstat;
+int (*pseudo_real_fstat)(int, struct stat *buf) = fstat;
+
#if 0
static void
dump_env(char **envp) {
@@ -512,7 +516,7 @@ pseudo_append_element(char *newpath, char *root, size_t allocated, char **pcurre
/* if lstat fails, that's fine -- nonexistent files aren't symlinks */
if (!leave_this) {
int is_link;
- is_link = (lstat(newpath, &buf) != -1) && S_ISLNK(buf.st_mode);
+ is_link = (pseudo_real_lstat(newpath, &buf) != -1) && S_ISLNK(buf.st_mode);
if (link_recursion >= PSEUDO_MAX_LINK_RECURSION && is_link) {
pseudo_diag("link recursion too deep, not expanding path '%s'.\n", newpath);
is_link = 0;
diff --git a/pseudo_wrappers.c b/pseudo_wrappers.c
index b2e3810..7920f9e 100644
--- a/pseudo_wrappers.c
+++ b/pseudo_wrappers.c
@@ -86,6 +86,15 @@ extern struct timeval *pseudo_wrapper_time;
#define PROFILE_DONE do {} while(0)
#endif
+#ifdef PSEUDO_XATTRDB
+extern ssize_t (*pseudo_real_lgetxattr)(const char *, const char *, void *, size_t);
+extern ssize_t (*pseudo_real_fgetxattr)(int, const char *, void *, size_t);
+extern int (*pseudo_real_lsetxattr)(const char *, const char *, const void *, size_t, int);
+extern int (*pseudo_real_fsetxattr)(int, const char *, const void *, size_t, int);
+#endif
+extern int (*pseudo_real_lstat)(const char *, struct stat *);
+extern int (*pseudo_real_fstat)(int, struct stat *);
+
static void
_libpseudo_init(void) {
pseudo_getlock();
@@ -160,6 +169,15 @@ pseudo_init_wrappers(void) {
done = 1;
}
+#ifdef PSEUDO_XATTRDB
+ pseudo_real_lgetxattr = real_lgetxattr;
+ pseudo_real_fgetxattr = real_fgetxattr;
+ pseudo_real_lsetxattr = real_lsetxattr;
+ pseudo_real_fsetxattr = real_fsetxattr;
+#endif
+ pseudo_real_lstat = real_lstat;
+ pseudo_real_fstat = real_fstat;
+
/* Once the wrappers are setup, we can now use open... so
* setup the logfile, if necessary...
*/