#define _XOPEN_SOURCE 500
#include <unistd.h>
+#include "lock-tracking.h"
+
static ssize_t pwrite_check(int fd, const void *buf, size_t count, off_t offset);
static ssize_t write_check(int fd, const void *buf, size_t count);
-static int fcntl_check(int fd, int cmd, ... /* arg */ );
static int ftruncate_check(int fd, off_t length);
#define pwrite pwrite_check
#define write write_check
-#define fcntl fcntl_check
+#define fcntl fcntl_with_lockcheck
#define ftruncate ftruncate_check
#include <ccan/tdb/tdb.h>
#include <ccan/tdb/transaction.c>
#include <ccan/tdb/error.c>
#include <ccan/tdb/open.c>
+#include <ccan/tdb/check.c>
#include <ccan/tap/tap.h>
#include <stdlib.h>
#include <stdbool.h>
static char *snapshot;
static off_t snapshot_len;
static bool clear_if_first;
-#define TEST_DBNAME "/tmp/test7.tdb"
+#define TEST_DBNAME "run-open-during-transaction.tdb"
#undef write
#undef pwrite
#undef fcntl
#undef ftruncate
+static void taplog(struct tdb_context *tdb,
+ enum tdb_debug_level level,
+ const char *fmt, ...)
+{
+ va_list ap;
+ char line[200];
+
+ va_start(ap, fmt);
+ vsprintf(line, fmt, ap);
+ va_end(ap);
+
+ diag("%s", line);
+}
+
static void save_file_contents(int fd)
{
struct stat st;
if (!external_agent_operation_check(agent, block, &res))
return;
- if (res != 0)
+ if (res != 1)
err(1, "Agent failed open");
agent_pending = false;
static void check_file_contents(int fd)
{
+ if (!in_transaction)
+ return;
+
if (agent_pending)
check_for_agent(fd, false);
{
ssize_t ret;
- if (in_transaction)
- check_file_contents(fd);
+ check_file_contents(fd);
snapshot_uptodate = false;
ret = pwrite(fd, buf, count, offset);
if (ret != count)
return ret;
- if (in_transaction)
- check_file_contents(fd);
+ check_file_contents(fd);
return ret;
}
{
ssize_t ret;
- if (in_transaction)
- check_file_contents(fd);
+ check_file_contents(fd);
snapshot_uptodate = false;
if (ret != count)
return ret;
- if (in_transaction)
- check_file_contents(fd);
- return ret;
-}
-
-/* This seems to be a macro for glibc... */
-extern int fcntl(int fd, int cmd, ... /* arg */ );
-
-static int fcntl_check(int fd, int cmd, ... /* arg */ )
-{
- va_list ap;
- int ret, arg3;
- struct flock *fl;
-
- if (cmd != F_SETLK && cmd != F_SETLKW) {
- /* This may be totally bogus, but we don't know in general. */
- va_start(ap, cmd);
- arg3 = va_arg(ap, int);
- va_end(ap);
-
- return fcntl(fd, cmd, arg3);
- }
-
- va_start(ap, cmd);
- fl = va_arg(ap, struct flock *);
- va_end(ap);
-
- ret = fcntl(fd, cmd, fl);
-
- if (in_transaction && fl->l_type == F_UNLCK)
- check_file_contents(fd);
+ check_file_contents(fd);
return ret;
}
{
int ret;
- if (in_transaction)
- check_file_contents(fd);
+ check_file_contents(fd);
snapshot_uptodate = false;
ret = ftruncate(fd, length);
- if (in_transaction)
- check_file_contents(fd);
+ check_file_contents(fd);
return ret;
}
int main(int argc, char *argv[])
{
+ struct tdb_logging_context logctx = { taplog, NULL };
const int flags[] = { TDB_DEFAULT,
TDB_CLEAR_IF_FIRST,
TDB_NOMMAP,
TDB_DATA key, data;
plan_tests(20);
+ unlock_callback = check_file_contents;
agent = prepare_external_agent();
if (!agent)
err(1, "preparing agent");
nice(15);
for (i = 0; i < sizeof(flags)/sizeof(flags[0]); i++) {
+ clear_if_first = (flags[i] & TDB_CLEAR_IF_FIRST);
+ diag("Test with %s and %s\n",
+ clear_if_first ? "CLEAR" : "DEFAULT",
+ (flags[i] & TDB_NOMMAP) ? "no mmap" : "mmap");
unlink(TEST_DBNAME);
- tdb = tdb_open(TEST_DBNAME, 1024, flags[i],
- O_CREAT|O_TRUNC|O_RDWR, 0600);
+ tdb = tdb_open_ex(TEST_DBNAME, 1024, flags[i],
+ O_CREAT|O_TRUNC|O_RDWR, 0600,
+ &logctx, NULL);
ok1(tdb);
- clear_if_first = (flags[i] & TDB_CLEAR_IF_FIRST);
ok1(tdb_transaction_start(tdb) == 0);
in_transaction = true;
ok1(tdb_transaction_commit(tdb) == 0);
if (agent_pending)
check_for_agent(tdb->fd, true);
- ok(errors == 0, "We had %u errors", errors);
+ ok(errors == 0, "We had %u unexpected changes", errors);
tdb_close(tdb);
}