summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Bütow <pbuetow@mimecast.com>2018-03-30 12:38:57 +0100
committerPaul Bütow <pbuetow@mimecast.com>2018-03-30 12:38:57 +0100
commit0bf0f8cc86cab23668e45fbca3a4f46aa87cfe88 (patch)
tree6002540e7902278dc04eeb9950fd1f0685b1b377
parent49612db2713ccce2022495814c724e290c0e2b0f (diff)
parent79b99c0ad4c1761b4da71721d18c94648fb64d32 (diff)
Merge branch 'develop'0.4
-rw-r--r--Makefile2
-rw-r--r--README.md4
-rw-r--r--ioriot/Makefile4
-rw-r--r--ioriot/src/capture/capture.c2
-rw-r--r--ioriot/src/datas/btree.c125
-rw-r--r--ioriot/src/datas/btree.h10
-rw-r--r--ioriot/src/defaults.h10
-rw-r--r--ioriot/src/generate/generate.c49
-rw-r--r--ioriot/src/generate/gioop.c19
-rw-r--r--ioriot/src/generate/gioop.h1
-rw-r--r--ioriot/src/generate/vsize.c77
-rw-r--r--ioriot/src/generate/vsize.h12
-rw-r--r--ioriot/src/init/init.c30
-rw-r--r--ioriot/src/init/itask.c6
-rw-r--r--ioriot/src/init/itask.h3
-rw-r--r--ioriot/src/init/ithread.c10
-rw-r--r--ioriot/src/main.c6
-rw-r--r--ioriot/src/meta/meta.c2
-rw-r--r--ioriot/src/opcodes.h1
-rw-r--r--ioriot/src/options.c2
-rw-r--r--ioriot/src/replay/replay.c2
-rw-r--r--ioriot/src/replay/rioop.c1
-rw-r--r--ioriot/src/replay/rstats.c2
-rw-r--r--ioriot/src/utests.c4
-rw-r--r--ioriot/src/utils/futils.c23
-rw-r--r--ioriot/src/utils/futils.h9
-rw-r--r--ioriot/src/utils/utils.c34
-rw-r--r--systemtap/src/ioriot.stp28
-rw-r--r--systemtap/src/javaioriot.stp28
-rw-r--r--systemtap/src/targetedioriot.stp28
30 files changed, 376 insertions, 158 deletions
diff --git a/Makefile b/Makefile
index d5ab493..7e7099d 100644
--- a/Makefile
+++ b/Makefile
@@ -17,3 +17,5 @@ loc:
wc -l ./systemtap/src/*.stp ./ioriot/src/*.{h,c} ./ioriot/src/*/*.{h,c} | tail -n 1
doxygen:
doxygen ./docs/doxygen.conf
+test:
+ $(MAKE) -C ioriot test
diff --git a/README.md b/README.md
index be6aa8f..e668f94 100644
--- a/README.md
+++ b/README.md
@@ -114,6 +114,7 @@ sudo ioriot -c ~/io.capture -m targetedioriot.ko -p PID
The resulting capture log looks like this and can be multiple GB in size:
```sh
+#|capture_version=2|
t=1511381122062;:,i=7764:8093;:,o=open;:,d=162;:,p=///usr/local/mimecast/someapp/somesubdir/vd11-9:1;:,f=0;:,m=438;:,
t=1511381122062;:,i=7764:8093;:,o=fstat;:,d=162;:,s=0;:,
t=1511381122062;:,i=7764:8093;:,o=read;:,d=162;:,b=12;:,
@@ -186,7 +187,7 @@ After producing ``io.capture`` it must be pre-processed. The resulting replay lo
To generate the the replay log ``io.replay`` from the capture log ``io.capture`` run:
```sh
-sudo ioriot -c io.capture -r io.replay -n NAME -u USER
+ioriot -c io.capture -r io.replay -n NAME -u USER
```
In which NAME is a freely chosen name and USER must be a valid system user. It is the system user under which the replay test will run. This command also creates all required top level directories such as ``/.ioriot/NAME/``, ``/mnt/.ioriot/NAME/`` in all mounted file systems. These are the directories where the replay test will read/write files from/to. These directories will belong to user USER.
@@ -339,6 +340,7 @@ Currently, these file I/O related syscalls are supported (as of CentOS 7):
open
openat
lseek
+llseek
fcntl
creat
write
diff --git a/ioriot/Makefile b/ioriot/Makefile
index d65915c..7474d05 100644
--- a/ioriot/Makefile
+++ b/ioriot/Makefile
@@ -11,7 +11,7 @@ all: compile
quick: clean ctags compile sudo_install
cshell: compile
gdb -ex='break main; run' --args ./$(NAME)
-test: compile
+gdbtest: compile
gdb -ex=run --args ./$(NAME) -U
compile: $(OBJS)
$(CC) $(STATIC) $(DEBUG) $(LIBS) $(OBJS) -o $(NAME)
@@ -34,3 +34,5 @@ todo:
fgrep ../TODO ./src/*
ctags:
ctags ./src/*.{h,c} ./src/*/*.{h,c}
+test: clean all
+ ./ioriot -U
diff --git a/ioriot/src/capture/capture.c b/ioriot/src/capture/capture.c
index aaad6cb..5e8771d 100644
--- a/ioriot/src/capture/capture.c
+++ b/ioriot/src/capture/capture.c
@@ -77,7 +77,7 @@ status_e capture_run(options_s *opts)
Out("NOTICE: It is good practise first to stop all processes, then to ");
Out("start capturing, and then to start all processes again. The reason ");
Out("is that processes may have already open file handles. In that case ");
- Out("I/O Riot would be unable to replay these! This may be improved ");
+ Out("I/O Riot would be unable to replay these! This may be improved ");
Put("in a future release!");
Put("To abort capturing now send Ctrl+C, otherwise wait 1h");
Put("Capturing I/O via: '%s'", staprun_command);
diff --git a/ioriot/src/datas/btree.c b/ioriot/src/datas/btree.c
index 90cb889..21b5ab9 100644
--- a/ioriot/src/datas/btree.c
+++ b/ioriot/src/datas/btree.c
@@ -62,6 +62,14 @@ void* btree_get(btree_s* b, long key)
return btreelem_get_r(b->root, key);
}
+bool btree_has_range_l(btree_s* b, const long start, const long end)
+{
+ if (b->root == NULL)
+ return false;
+
+ return btreelem_has_range_lr(b->root, start, end);
+}
+
long btree_get_l(btree_s* b, long key)
{
void *data = btree_get(b, key);
@@ -71,12 +79,12 @@ long btree_get_l(btree_s* b, long key)
return -1;
}
-void btree_ensure_range_l(btree_s* b, long from, long to)
+void btree_ensure_range_l(btree_s* b, const long start, const long end, const long threshold)
{
if (b->root == NULL) {
- btree_insert(b, from, (void*)to);
+ btree_insert(b, start, (void*)end);
} else {
- if (1 == btreelem_ensure_range_lr(b->root, from, to))
+ if (1 == btreelem_ensure_range_lr(b->root, start, end, threshold))
b->size++;
}
}
@@ -87,9 +95,9 @@ void btree_print(btree_s* b)
btreelem_print_r(b->root, 1);
}
-void btree_run_cb2(btree_s* b, void (*cb)(void *data, void *data2))
+void btree_run_cb2(btree_s* b, void (*cb)(long key, void *data, void *data2), void *data2)
{
- btreelem_run_cb2_r(b->root, cb);
+ btreelem_run_cb2_r(b->root, cb, data2);
}
btreelem_s* btreelem_new(long key, void *data)
@@ -107,7 +115,7 @@ void btreelem_destroy_r(btreelem_s* e)
{
if (e->left)
btreelem_destroy_r(e->left);
- if (e->right)
+ if (e->right)
btreelem_destroy_r(e->right);
free(e);
@@ -150,39 +158,46 @@ int btreelem_insert_r(btreelem_s* e, long key, void *data)
return ret;
}
-int btreelem_ensure_range_lr(btreelem_s *e, const long from, const long to)
+int btreelem_ensure_range_lr(btreelem_s *e, const long start, const long end, const long threshold)
{
int ret = 0;
long value = (long) e->data;
- if (e->key == from) {
- if (value < to) {
- e->data = (void*) to;
+ //Debug("%ld %ld %ld", start, end, threshold);
+
+ if (e->key == start) {
+ if (value < end) {
+ e->data = (void*) end;
} else {
// Nothing to do, range already present
}
- } else if (e->key > from) {
+ } else if (e->key > start) {
if (e->left == NULL) {
- e->left = btreelem_new(from, (void*)to);
- ret = 1;
+ if (value <= end) {
+ e->key = start;
+ e->data = (void*)end;
+ } else {
+ e->left = btreelem_new(start, (void*)end);
+ ret = 1;
+ }
} else {
- ret = btreelem_ensure_range_lr(e->left, from, to);
+ ret = btreelem_ensure_range_lr(e->left, start, end, threshold);
}
- } else { // if (e->key < from)
- if (value >= from) {
- if (value < to) {
- e->data = (void*) to;
+ } else { // if (e->key < start)
+ if (value >= start) {
+ if (value < end) {
+ e->data = (void*) end;
} else {
// Nothing to do, range already present
}
} else {
if (e->right == NULL) {
- e->right = btreelem_new(from, (void*)to);
+ e->right = btreelem_new(start, (void*)end);
ret = 1;
} else {
- ret = btreelem_ensure_range_lr(e->right, from, to);
+ ret = btreelem_ensure_range_lr(e->right, start, end, threshold);
}
}
}
@@ -209,6 +224,27 @@ void* btreelem_get_r(btreelem_s* e, long key)
return data;
}
+bool btreelem_has_range_lr(btreelem_s* e, const long start, const long end)
+{
+ long value = (long)e->data;
+
+ if (e->key <= start && value >= end) {
+ return true;
+
+ } else if (e->key > start) {
+ if (e->left)
+ return btreelem_has_range_lr(e->left, start, end);
+ else
+ return false;
+
+ } else {
+ if (e->right)
+ return btreelem_has_range_lr(e->right, start, end);
+ else
+ return false;
+ }
+}
+
void btreelem_print_r(btreelem_s* e, int depth)
{
if (!e)
@@ -225,18 +261,18 @@ void btreelem_print_r(btreelem_s* e, int depth)
btreelem_print_r(e->right, depth+1);
}
-void btreelem_run_cb2_r(btreelem_s* e, void (*cb)(void *data, void *data2))
+void btreelem_run_cb2_r(btreelem_s* e, void (*cb)(long key, void *data, void *data2), void *data2)
{
if (!e)
return;
- cb((void*)(long)e->key, e->data);
+ cb(e->key, e->data, data2);
if (e->left)
- btreelem_run_cb2_r(e->left, cb);
+ btreelem_run_cb2_r(e->left, cb, data2);
if (e->right)
- btreelem_run_cb2_r(e->right, cb);
+ btreelem_run_cb2_r(e->right, cb, data2);
}
void btree_test(void)
@@ -250,7 +286,7 @@ void btree_test(void)
assert(2 == b->size);
assert(1 == btree_insert(b, 3, (void*)3));
assert(3 == b->size);
- assert(1 == (long)btree_get(b, 1));
+ assert(1 == btree_get_l(b, 1));
assert(1 == btree_insert(b, 1234, somedata));
assert(4 == b->size);
@@ -266,7 +302,7 @@ void btree_test(void)
assert(0 == btree_insert(b, 666, somedata));
assert(1 == btree_insert(b, 42, (void*)42));
- assert(42 == (long)btree_get(b, 42));
+ assert(42 == btree_get_l(b, 42));
btree_print(b);
btree_destroy(b);
@@ -274,29 +310,40 @@ void btree_test(void)
b = btree_new();
assert(0 == b->size);
- btree_ensure_range_l(b, 0, 23);
+ btree_ensure_range_l(b, 0, 23, 0);
assert(btree_get_l(b, 0) == (long) btree_get(b, 0));
assert(23 == btree_get_l(b, 0));
+ assert(btree_has_range_l(b, 2, 10));
- btree_ensure_range_l(b, 0, 23);
- btree_ensure_range_l(b, 10, 10);
- btree_ensure_range_l(b, 22, 25);
- assert(25 == btree_get_l(b, 0));
- assert(1 == b->size);
+ assert(!btree_has_range_l(b, 300, 325));
+ btree_ensure_range_l(b, 300, 325, 0);
+ assert(2 == b->size);
+ assert(325 == btree_get_l(b, 300));
+ assert(btree_has_range_l(b, 300, 325));
+ assert(!btree_has_range_l(b, 300, 326));
- btree_ensure_range_l(b, 300, 25);
+ btree_ensure_range_l(b, 200, 3321, 0);
assert(2 == b->size);
- btree_ensure_range_l(b, 200, 25);
- assert(3 == b->size);
- assert(25 == btree_get_l(b, 200));
+ btree_ensure_range_l(b, 200, 1000, 0);
+ assert(2 == b->size);
+ assert(3321 == btree_get_l(b, 200));
- btree_ensure_range_l(b, 200, 1000);
- assert(3 == b->size);
- assert(1000 == btree_get_l(b, 200));
+ btree_ensure_range_l(b, 0, 23, 0);
+ btree_ensure_range_l(b, 10, 10, 0);
+ btree_ensure_range_l(b, 22, 25, 0);
+ assert(25 == btree_get_l(b, 0));
+ assert(2 == b->size);
+ assert(!btree_has_range_l(b, 4000, 4000));
+ btree_ensure_range_l(b, 4000, 4000, 0);
+ assert(3 == b->size);
+ assert(btree_has_range_l(b, 4000, 4000));
+ assert(!btree_has_range_l(b, 4000, 4001));
+ assert(!btree_has_range_l(b, 3999, 4000));
btree_print(b);
+ btree_print(b);
btree_destroy(b);
exit(0);
diff --git a/ioriot/src/datas/btree.h b/ioriot/src/datas/btree.h
index a1ca7ef..0a05cee 100644
--- a/ioriot/src/datas/btree.h
+++ b/ioriot/src/datas/btree.h
@@ -41,9 +41,10 @@ void btree_destroy2(btree_s *b);
int btree_insert(btree_s *b, long key, void *data);
void* btree_get(btree_s *b, long key);
long btree_get_l(btree_s *b, long key);
-void btree_ensure_range_l(btree_s *b, const long from, const long to);
+bool btree_has_range_l(btree_s *b, const long start, const long end);
+void btree_ensure_range_l(btree_s *b, const long start, const long end, const long threshold);
void btree_print(btree_s *b);
-void btree_run_cb2(btree_s* b, void (*cb)(void *data, void *data2));
+void btree_run_cb2(btree_s* b, void (*cb)(long key, void *data, void *data2), void *data2);
void btree_test(void);
btreelem_s* btreelem_new(long key, void *data);
@@ -51,8 +52,9 @@ void btreelem_destroy_r(btreelem_s *e);
void btreelem_destroy_r2(btreelem_s *e);
int btreelem_insert_r(btreelem_s *e, long key, void *data);
void* btreelem_get_r(btreelem_s *e, long key);
-int btreelem_ensure_range_lr(btreelem_s *e, const long from, const long to);
+bool btreelem_has_range_lr(btreelem_s *e, const long start, const long end);
+int btreelem_ensure_range_lr(btreelem_s *e, const long start, const long end, const long threshold);
void btreelem_print_r(btreelem_s *e, int depth);
-void btreelem_run_cb2_r(btreelem_s* e, void (*cb)(void *data, void *data2));
+void btreelem_run_cb2_r(btreelem_s* e, void (*cb)(long key, void *data, void *data2), void *data2);
#endif // BTREE_H
diff --git a/ioriot/src/defaults.h b/ioriot/src/defaults.h
index c0833c8..b4adc83 100644
--- a/ioriot/src/defaults.h
+++ b/ioriot/src/defaults.h
@@ -18,9 +18,9 @@
#include "utils/utils.h"
/** Version of the supported .capture format */
-#define CAPTURE_VERSION 1
+#define CAPTURE_VERSION 2
/** Version of the supported .replay format */
-#define REPLAY_VERSION 1
+#define REPLAY_VERSION 2
/** Max amount of tokens per line in the .capture file */
#define MAX_TOKENS 10
/** Max line length in either .capture or .replay file */
@@ -28,13 +28,15 @@
/** Controls how many tasks can be queued and buffered per worker thread */
#define TASK_BUFFER_PER_THREAD 512
/** Version of I/O Riot */
-#define IORIOT_VERSION "0.4-develop"
+#define IORIOT_VERSION "0.4"
/** Copyright information */
-#define IORIOT_COPYRIGHT "Mimecast 2017, 2018 (c)"
+#define IORIOT_COPYRIGHT "(c) Mimecast 2018"
/** Max open files resource user limit */
#define SET_RLIMIT_NOFILE 369216
/** Max processes resource user limit */
#define SET_RLIMIT_NPROC 30768
+/** Ignore file hole size */
+#define IGNORE_FILE_HOLE_BYTES 1024*1024*10
// The following are for debugging purposes only
diff --git a/ioriot/src/generate/generate.c b/ioriot/src/generate/generate.c
index baff401..0185c50 100644
--- a/ioriot/src/generate/generate.c
+++ b/ioriot/src/generate/generate.c
@@ -68,7 +68,6 @@ void generate_destroy(generate_s *g)
free(g);
}
-
status_e generate_run(options_s *opts)
{
generate_s *g = generate_new(opts);
@@ -82,8 +81,23 @@ status_e generate_run(options_s *opts)
set_limits_drop_root(opts->user);
+ // Check for correct capture format version
+ meta_s *meta = meta_new(capture_fd);
+ meta_read_start(meta);
+
+ long capture_version = 0;
+ if (meta_read_l(meta, "capture_version", &capture_version)) {
+ Put("Capture version is '%ld'", capture_version);
+ if (capture_version != CAPTURE_VERSION) {
+ Error(".capture file of incompatible version, got %x, expected %x",
+ (int)capture_version, CAPTURE_VERSION);
+ }
+ }
+
+ meta_destroy(meta);
+
// Reserve first few bytes for meta information
- meta_s *meta = meta_new(g->replay_fd);
+ meta = meta_new(g->replay_fd);
meta_reserve(meta);
// The writer will write the .replay file
@@ -109,6 +123,9 @@ status_e generate_run(options_s *opts)
// either the parser or the writer thread!
while ((read = getline(&line, &len, capture_fd)) != -1) {
+ if (line[0] == '#')
+ continue;
+
if (0 > ++g->lineno) {
Error("lineno:%lu Line number overflow", g->lineno);
}
@@ -189,14 +206,30 @@ status_e generate_run(options_s *opts)
return SUCCESS;
}
-void generate_write_init_cb(void *data)
+void _write_ranges_cb(long start, void *data, void *data2)
{
- vsize_s *l = data;
- generate_s *g = l->generate;
+ vsize_s *v = data2;
+ generate_s *g = v->generate;
+ long end = (long) data;
+ long bytes = end-start;
+ if (bytes > 0) {
+ fprintf(g->replay_fd, "%d|%d|%ld|%ld|%s|\n",
+ v->is_dir, v->is_file, start, bytes, v->path);
+ }
+}
- if (l->required && strlen(l->path) > 0) {
- fprintf(g->replay_fd, "%d|%d|%ld|%s|\n",
- l->is_dir, l->is_file, 666L, l->path);
+void generate_write_init_cb(void *data)
+{
+ vsize_s *v = data;
+ generate_s *g = v->generate;
+
+ if (v->required && strlen(v->path) > 0) {
+ if (v->read_ranges) {
+ btree_run_cb2(v->read_ranges, _write_ranges_cb, data);
+ } else if (v->bytes >= 0) {
+ fprintf(g->replay_fd, "%d|%d|%ld|%ld|%s|\n",
+ v->is_dir, v->is_file, 0L, v->bytes, v->path);
+ }
}
}
diff --git a/ioriot/src/generate/gioop.c b/ioriot/src/generate/gioop.c
index df48ef8..d5b9a28 100644
--- a/ioriot/src/generate/gioop.c
+++ b/ioriot/src/generate/gioop.c
@@ -109,6 +109,9 @@ status_e gioop_run(gwriter_s *w, gtask_s *t)
} else if (Eq(t->op, "lseek")) {
Cleanup(gioop_lseek(w, t, g));
+ } else if (Eq(t->op, "llseek")) {
+ Cleanup(gioop_llseek(w, t, g));
+
} else if (Eq(t->op, "getdents")) {
Cleanup(gioop_getdents(w, t, g));
@@ -559,6 +562,22 @@ status_e gioop_lseek(gwriter_s *w, gtask_s *t, generate_s *g)
return SUCCESS;
}
+status_e gioop_llseek(gwriter_s *w, gtask_s *t, generate_s *g)
+{
+ if (!t->has_fd) {
+ return ERROR;
+ }
+
+ generate_vsize_by_path(g, t, t->vfd->path);
+ Gioop_write(LLSEEK, "%ld|%ld|%ld|%ld|llseek",
+ t->mapped_fd, t->offset, t->whence, t->bytes);
+
+ if (t->bytes >= 0)
+ vsize_seek(t->vsize, t->vfd, t->bytes);
+
+ return SUCCESS;
+}
+
status_e gioop_getdents(gwriter_s *w, gtask_s *t, generate_s *g)
{
if (!t->has_fd) {
diff --git a/ioriot/src/generate/gioop.h b/ioriot/src/generate/gioop.h
index ad49713..1df57c1 100644
--- a/ioriot/src/generate/gioop.h
+++ b/ioriot/src/generate/gioop.h
@@ -79,6 +79,7 @@ status_e gioop_readlinkat(gwriter_s *w, gtask_s *t, generate_s *g);
status_e gioop_write(gwriter_s *w, gtask_s *t, generate_s *g);
status_e gioop_writev(gwriter_s *w, gtask_s *t, generate_s *g);
status_e gioop_lseek(gwriter_s *w, gtask_s *t, generate_s *g);
+status_e gioop_llseek(gwriter_s *w, gtask_s *t, generate_s *g);
status_e gioop_getdents(gwriter_s *w, gtask_s *t, generate_s *g);
status_e gioop_mkdir(gwriter_s *w, gtask_s *t, generate_s *g);
status_e gioop_rmdir(gwriter_s *w, gtask_s *t, generate_s *g);
diff --git a/ioriot/src/generate/vsize.c b/ioriot/src/generate/vsize.c
index 93be77b..b38f1bc 100644
--- a/ioriot/src/generate/vsize.c
+++ b/ioriot/src/generate/vsize.c
@@ -17,7 +17,6 @@
#include "generate.h"
// Helper macros
-
#define _Set_file(v) v->is_file = true; v->unsure = v->is_dir = false
#define _Set_dir(v) v->is_dir = true; v->unsure = v->is_file = false
#define _Set_unsure(v) v->unsure = true
@@ -40,8 +39,9 @@ vsize_s* vsize_new(char *file_path, const unsigned long id,
v->required = false;
v->unsure = false;
v->updates = 0;
- v->vsize = 0;
- v->ranges = NULL;
+ v->bytes = 0;
+ v->read_ranges = NULL;
+ v->write_ranges = NULL;
return v;
}
@@ -51,8 +51,10 @@ void vsize_destroy(vsize_s *v)
if (!v)
return;
- if (v->ranges)
- btree_destroy(v->ranges);
+ if (v->read_ranges)
+ btree_destroy(v->read_ranges);
+ if (v->write_ranges)
+ btree_destroy(v->write_ranges);
free(v->path);
free(v);
@@ -170,52 +172,67 @@ void vsize_rename(vsize_s *v, vsize_s *v2,
}
}
-void vsize_ensure_data_range(vsize_s *v, const long from, const long to)
+void vsize_ensure_data_range(vsize_s *v, btree_s **ranges, const long offset, const long bytes)
{
- if (v->ranges == NULL) {
- if (from == 0) {
- if (v->vsize < to) {
+ if (*ranges == NULL) {
+ if (offset == 0) {
+ if (v->bytes + IGNORE_FILE_HOLE_BYTES < bytes) {
// No file hole, just set the new (larger) vsize
- v->vsize = to;
+ v->bytes = bytes;
} else {
// Nothing to do, vsize is already sufficient
}
- } else { // if (from > 0)
- if (from <= v->vsize) {
+ } else { // if (offset > 0)
+ if (offset <= v->bytes) {
// We won't add a hole to the file here either
- if (v->vsize < to) {
- // No file hole, just set the new (larger) vsize
- v->vsize = to;
+ if (v->bytes < bytes) {
+ // No file hole, just set the new (larger) bytes
+ v->bytes = bytes;
} else {
- // Nothing to do, vsize is already sufficient
+ // Nothing to do, bytes is already sufficient
}
- } else { // if (from > v->vsize)
- // From offset larger than vsize, we have a hole in the file!
- v->ranges = btree_new();
+ } else { // if (offset > v->bytes)
+ // From offset larger than bytes, we have a hole in the file!
+ *ranges = btree_new();
// Insert root data range
- btree_insert(v->ranges, 0, (void*)v->vsize);
+ btree_insert(*ranges, 0, (void*)v->bytes);
// This value is not used anymore, we use the btree instead from now
// to store all used data ranges of a file.
- v->vsize = -1;
+ v->bytes = -1;
// Rerun this function with a data range btree initialised
- vsize_ensure_data_range(v, from, to);
+ vsize_ensure_data_range(v, ranges, offset, bytes);
}
}
- } else { // if (v->ranges != NULL)
- btree_ensure_range_l(v->ranges, from, to);
+ } else { // if (*ranges != NULL)
+ btree_ensure_range_l(*ranges, offset, offset+bytes,
+ IGNORE_FILE_HOLE_BYTES);
}
}
void vsize_read(vsize_s *v, void *vfd, const char *path, const int bytes)
{
vfd_s *vfd_ = vfd;
- // We may try to read data from a file with holes!
- vsize_ensure_data_range(v, vfd_->offset, bytes);
+
+ if (v->write_ranges == NULL ||
+ !btree_has_range_l(v->write_ranges, vfd_->offset, vfd_->offset+bytes)) {
+ vsize_ensure_data_range(v, &v->read_ranges, vfd_->offset, bytes);
+ _Set_required(v);
+ _Set_file(v);
+ }
+
+ vfd_->offset += bytes;
+ v->updates++;
+}
+
+void vsize_write(vsize_s *v, void *vfd, const char *path, const int bytes)
+{
+ vfd_s *vfd_ = vfd;
+ vsize_ensure_data_range(v, &v->write_ranges, vfd_->offset, bytes);
vfd_->offset += bytes;
v->updates++;
}
@@ -227,14 +244,8 @@ void vsize_seek(vsize_s *v, void *vfd, const long new_offset)
// The file's offset can be greater than the file's current size, in which
// case the next write to the file will extend the file. This is referred
// to as creating a hole in a file.
- vfd_->offset = new_offset;
- v->updates++;
-}
-void vsize_write(vsize_s *v, void *vfd, const char *path, const int bytes)
-{
- vfd_s *vfd_ = vfd;
- vfd_->offset += bytes;
+ vfd_->offset = new_offset;
v->updates++;
}
diff --git a/ioriot/src/generate/vsize.h b/ioriot/src/generate/vsize.h
index d0111fa..ffda9e5 100644
--- a/ioriot/src/generate/vsize.h
+++ b/ioriot/src/generate/vsize.h
@@ -30,8 +30,9 @@
*/
typedef struct vsize_s_ {
char *path; /**< The path to the file/directory */
- long vsize; /**< The virtual size */
- btree_s *ranges; /**< Used to store used data ranges in a file with holes */
+ long bytes; /**< The virtual size */
+ btree_s *read_ranges; /**< Used to store used data ranges in a file with holes */
+ btree_s *write_ranges; /**< Used to store used data ranges in a file with holes */
unsigned long id; /**< The vsize id */
void *generate; /**< A pointer to the generate object */
bool renamed; /**< True if file/dir has been renamed */
@@ -78,10 +79,11 @@ void init_parent_dir(vsize_s *v, const char *path);
* we have holes in the file to be replayed.
*
* @param v The virtual size object
- * @param from The start offset
- * @param to The end offset
+ * @param ranges The ranges object to operaet on
+ * @param offset The start offset
+ * @param bytes The amount of bytes
*/
-void vsize_ensure_data_range(vsize_s *v, const long from, const long to);
+void vsize_ensure_data_range(vsize_s *v, btree_s **ranges, const long offset, const long bytes);
/**
* @brief Adjust vsize on open
diff --git a/ioriot/src/init/init.c b/ioriot/src/init/init.c
index e375379..659d59a 100644
--- a/ioriot/src/init/init.c
+++ b/ioriot/src/init/init.c
@@ -21,7 +21,6 @@
#include "../mounts.h"
#include "../utils/futils.h"
-
init_s *init_new(options_s *opts)
{
init_s *i = Malloc(init_s);
@@ -60,12 +59,12 @@ void init_extract_header(init_s *i, off_t *init_offset)
meta_s *m = meta_new(i->replay_fd);
meta_read_start(m);
- long version = 0;
- if (meta_read_l(m, "version", &version)) {
- Put("Replay version is '%ld'", version);
- if (version != REPLAY_VERSION) {
+ long replay_version = 0;
+ if (meta_read_l(m, "replay_version", &replay_version)) {
+ Put("Replay version is '%ld'", replay_version);
+ if (replay_version != REPLAY_VERSION) {
Error(".replay file of incompatible version, got %x, expected %x",
- (int)version, REPLAY_VERSION);
+ (int)replay_version, REPLAY_VERSION);
}
}
@@ -118,7 +117,8 @@ status_e init_run(options_s *opts)
fseeko(i->replay_fd, init_offset, SEEK_SET);
bool is_file = false, is_dir = false;
- long vsize = 0;
+ long offset = 0;
+ long bytes = 0;
char *path;
// Stats
@@ -136,6 +136,7 @@ status_e init_run(options_s *opts)
// Process the INIT section of the .replay file line by line.
while ((read = getline(&line, &len, i->replay_fd)) != -1) {
+ //Debug(line);
char *tok = strtok_r(line, "|", &saveptr);
for (int ntok = 0; tok; ntok++) {
@@ -147,12 +148,18 @@ status_e init_run(options_s *opts)
is_file = atoi(tok) == 1;
break;
case 2:
- vsize = atol(tok);
- if (vsize < 0) {
- Error("Size overflow");
+ offset = atol(tok);
+ if (offset < 0) {
+ Error("Offset overflow: '%ld'", offset);
}
break;
case 3:
+ bytes = atol(tok);
+ if (bytes < 0) {
+ Error("Size overflow: '%ld'", bytes);
+ }
+ break;
+ case 4:
path = tok;
break;
default:
@@ -178,7 +185,8 @@ status_e init_run(options_s *opts)
} else if (is_file) {
task->is_file = true;
- task->vsize = vsize;
+ task->bytes = bytes;
+ task->offset = offset;
}
task->path = Clone(path);
diff --git a/ioriot/src/init/itask.c b/ioriot/src/init/itask.c
index f04ce33..de7c551 100644
--- a/ioriot/src/init/itask.c
+++ b/ioriot/src/init/itask.c
@@ -35,7 +35,7 @@ void itask_destroy(itask_s *task)
void itask_reset_stats(itask_s *task)
{
task->is_dir = task->is_file = false;
- task->sizes_created = task->vsize = 0;
+ task->sizes_created = task->offset = task->bytes = 0;
task->dirs_created = task->files_created = 0;
if (task->path) {
@@ -60,7 +60,7 @@ void itask_extract_stats(itask_s *task, long* dirs_created, long *files_created,
void itask_print(itask_s *task)
{
- Put("itask(%p): is_dir:%d is_file:%d vsize:%ld path:%s",
+ Put("itask(%p): is_dir:%d is_file:%d offset:%ld bytes:%ld path:%s",
(void*)task, task->is_dir, task->is_file,
- task->vsize, task->path);
+ task->offset, task->bytes, task->path);
}
diff --git a/ioriot/src/init/itask.h b/ioriot/src/init/itask.h
index b10d515..21afba4 100644
--- a/ioriot/src/init/itask.h
+++ b/