summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Buetow <pbuetow@mimecast.com>2018-03-30 10:21:02 +0100
committerPaul Buetow <pbuetow@mimecast.com>2018-03-30 10:21:02 +0100
commit712a25f115bf34dc73f81e5a4f1971b586fb524a (patch)
tree30a4620b9df7f72897d7bb0c4d587461cc748a61
parentfd779da9cfd81db6bf1d01404149235d7dd3e9df (diff)
add file hole support
-rw-r--r--.gitignore1
-rw-r--r--README.md1
-rw-r--r--ioriot/src/datas/btree.c180
-rw-r--r--ioriot/src/datas/btree.h21
-rw-r--r--ioriot/src/datas/list.c1
-rw-r--r--ioriot/src/defaults.h8
-rw-r--r--ioriot/src/generate/generate.c29
-rw-r--r--ioriot/src/generate/gioop.c21
-rw-r--r--ioriot/src/generate/gioop.h1
-rw-r--r--ioriot/src/generate/vsize.c97
-rw-r--r--ioriot/src/generate/vsize.h23
-rw-r--r--ioriot/src/init/init.c20
-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/opcodes.h1
-rw-r--r--ioriot/src/replay/rioop.c1
-rw-r--r--ioriot/src/utests.c4
-rw-r--r--ioriot/src/utils/futils.c24
-rw-r--r--ioriot/src/utils/futils.h9
-rw-r--r--ioriot/src/utils/utils.c56
-rw-r--r--ioriot/tags661
-rw-r--r--systemtap/src/ioriot.stp14
-rw-r--r--systemtap/src/javaioriot.stp14
-rw-r--r--systemtap/src/targetedioriot.stp14
25 files changed, 428 insertions, 792 deletions
diff --git a/.gitignore b/.gitignore
index ab4c720..07f2f4b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,4 +3,5 @@
docs/html/
docs/latex/
ioriot/ioriot
+ioriot/tags
systemtap/downloads/
diff --git a/README.md b/README.md
index be6aa8f..0ab83cd 100644
--- a/README.md
+++ b/README.md
@@ -339,6 +339,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/src/datas/btree.c b/ioriot/src/datas/btree.c
index b150066..a70c442 100644
--- a/ioriot/src/datas/btree.c
+++ b/ioriot/src/datas/btree.c
@@ -37,7 +37,7 @@ void btree_destroy2(btree_s* b)
free(b);
}
-int btree_insert(btree_s* b, int key, void *data)
+int btree_insert(btree_s* b, long key, void *data)
{
int ret = 0;
@@ -48,13 +48,13 @@ int btree_insert(btree_s* b, int key, void *data)
ret = btreelem_insert_r(b->root, key, data);
}
- if (ret == 0)
+ if (ret == 1)
b->size++;
return ret;
}
-void* btree_get(btree_s* b, int key)
+void* btree_get(btree_s* b, long key)
{
if (b->root == NULL)
return NULL;
@@ -62,17 +62,45 @@ void* btree_get(btree_s* b, int 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);
+ if (data)
+ return (long)data;
+ else
+ return -1;
+}
+
+void btree_ensure_range_l(btree_s* b, const long start, const long end, const long threshold)
+{
+ if (b->root == NULL) {
+ btree_insert(b, start, (void*)end);
+ } else {
+ if (1 == btreelem_ensure_range_lr(b->root, start, end, threshold))
+ b->size++;
+ }
+}
+
void btree_print(btree_s* b)
{
- btreelem_print_r(b->root, 0);
+ Put("btree:%p size:%d", (void*)b, b->size);
+ 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(int key, void *data)
+btreelem_s* btreelem_new(long key, void *data)
{
btreelem_s *e = Malloc(btreelem_s);
@@ -105,7 +133,7 @@ void btreelem_destroy_r2(btreelem_s* e)
free(e);
}
-int btreelem_insert_r(btreelem_s* e, int key, void *data)
+int btreelem_insert_r(btreelem_s* e, long key, void *data)
{
int ret = 1;
@@ -130,19 +158,65 @@ int btreelem_insert_r(btreelem_s* e, int key, void *data)
return ret;
}
-void* btreelem_get_r(btreelem_s* e, int key)
+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;
+
+ //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 > start) {
+ if (e->left == NULL) {
+ 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, start, end, threshold);
+ }
+
+ } 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(start, (void*)end);
+ ret = 1;
+ } else {
+ ret = btreelem_ensure_range_lr(e->right, start, end, threshold);
+ }
+ }
+ }
+
+ return ret;
+}
+
+void* btreelem_get_r(btreelem_s* e, long key)
{
void *data = NULL;
- if (e->key == key)
+ if (e->key == key) {
data = e->data;
- else if (e->key > key) {
+ } else if (e->key > key) {
if (e->left)
data = btreelem_get_r(e->left, key);
- }
- else {
+ } else {
if (e->right)
data = btreelem_get_r(e->right, key);
}
@@ -150,6 +224,27 @@ void* btreelem_get_r(btreelem_s* e, int 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)
@@ -157,7 +252,7 @@ void btreelem_print_r(btreelem_s* e, int depth)
for (int i = 0; i < depth; ++i)
Out(" ");
- Put("key:%d data:%ld\n", e->key, (long) e->data);
+ Put("key:%ld data:%ld", e->key, (long) e->data);
if (e->left)
btreelem_print_r(e->left, depth);
@@ -166,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)
@@ -186,23 +281,68 @@ void btree_test(void)
void* somedata = (void*)b;
assert(1 == btree_insert(b, 1, (void*)1));
+ assert(1 == b->size);
assert(1 == btree_insert(b, 2, (void*)2));
+ assert(2 == b->size);
assert(1 == btree_insert(b, 3, (void*)3));
- assert(1 == (long)btree_get(b, 1));
+ assert(3 == b->size);
+ assert(1 == btree_get_l(b, 1));
assert(1 == btree_insert(b, 1234, somedata));
+ assert(4 == b->size);
assert(1 == btree_insert(b, 13, somedata));
+ assert(5 == b->size);
assert(1 == btree_insert(b, 666, somedata));
+ assert(6 == b->size);
assert(0 == btree_insert(b, 13, somedata));
+ assert(6 == b->size);
assert(NULL != btree_get(b, 666));
assert(NULL == btree_get(b, 777));
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);
+ b = btree_new();
+ assert(0 == b->size);
+
+ 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));
+
+ 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, 200, 3321, 0);
+ assert(2 == b->size);
+
+ btree_ensure_range_l(b, 200, 1000, 0);
+ assert(2 == b->size);
+ assert(3321 == 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);
}
diff --git a/ioriot/src/datas/btree.h b/ioriot/src/datas/btree.h
index acc5477..0a05cee 100644
--- a/ioriot/src/datas/btree.h
+++ b/ioriot/src/datas/btree.h
@@ -23,7 +23,7 @@
typedef struct btreelem_ {
struct btreelem_ *left; /**< The next element to the left */
struct btreelem_ *right; /**< The next element to the right */
- int key; /**< The key of the element */
+ long key; /**< The key of the element */
void *data; /**< A pointer to the data stored in this element */
} btreelem_s;
@@ -38,18 +38,23 @@ typedef struct btree_s_ {
btree_s* btree_new();
void btree_destroy(btree_s *b);
void btree_destroy2(btree_s *b);
-int btree_insert(btree_s *b, int key, void *data);
-void* btree_get(btree_s *b, int key);
+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);
+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(int key, void *data);
+btreelem_s* btreelem_new(long key, void *data);
void btreelem_destroy_r(btreelem_s *e);
void btreelem_destroy_r2(btreelem_s *e);
-int btreelem_insert_r(btreelem_s *e, int key, void *data);
-void* btreelem_get_r(btreelem_s *e, int key);
+int btreelem_insert_r(btreelem_s *e, long key, void *data);
+void* btreelem_get_r(btreelem_s *e, long key);
+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/datas/list.c b/ioriot/src/datas/list.c
index 9cc78db..81e3e57 100644
--- a/ioriot/src/datas/list.c
+++ b/ioriot/src/datas/list.c
@@ -14,7 +14,6 @@
#include "list.h"
-
list_s *list_new()
{
list_s *l = Malloc(list_s);
diff --git a/ioriot/src/defaults.h b/ioriot/src/defaults.h
index c0833c8..d822423 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 */
@@ -30,11 +30,13 @@
/** Version of I/O Riot */
#define IORIOT_VERSION "0.4-develop"
/** 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 ee7178c..53751de 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);
@@ -189,14 +188,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, -l->vsize_deficit, 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 01701bc..d5b9a28 100644
--- a/ioriot/src/generate/gioop.c
+++ b/ioriot/src/generate/gioop.c
@@ -27,7 +27,7 @@ status_e gioop_run(gwriter_s *w, gtask_s *t)
generate_s *g = w->generate;
// Get the virtual process data object from the virtual PID space and store
- // a pointer to it to t->gprocess
+ // a pointer to it at t->gprocess
generate_gprocess_by_realpid(g, t);
// One of the open syscalls may openes a file handle succesfully
@@ -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 f2d56ba..4bf8433 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
@@ -35,14 +34,14 @@ vsize_s* vsize_new(char *file_path, const unsigned long id,
v->inserted = false;
v->is_dir = false;
v->is_file = false;
- v->offset = -1;
v->path = Clone(file_path);
v->renamed = false;
v->required = false;
v->unsure = false;
v->updates = 0;
- v->vsize = 0;
- v->vsize_deficit = 0;
+ v->bytes = 0;
+ v->read_ranges = NULL;
+ v->write_ranges = NULL;
return v;
}
@@ -52,6 +51,11 @@ void vsize_destroy(vsize_s *v)
if (!v)
return;
+ if (v->read_ranges)
+ btree_destroy(v->read_ranges);
+ if (v->write_ranges)
+ btree_destroy(v->write_ranges);
+
free(v->path);
free(v);
}
@@ -91,9 +95,9 @@ void init_parent_dir(vsize_s *v, const char *path)
void vsize_open(vsize_s *v, void *vfd, const char *path, const int flags)
{
- // v->first_encounter == false means, that this is the first occurance of
+ // v->updates == 0 means, that this is the first occurance of
// this path and we didn't initialise it (means we didn't ensure that
- // we want to create all parent directories etc.
+ // we want to create all parent directories etc.)
if (v->updates == 0) {
// We may use a recycled vfd object! When opening a file we always
@@ -161,56 +165,87 @@ void vsize_rename(vsize_s *v, vsize_s *v2,
// We are not 100% sure that this is really a file,
// the path might be still a directory though!
_Set_unsure(v2);
+ v2->updates++;
// For debugging purposes only
_Set_renamed(v2);
- v2->updates++;
}
}
-void vsize_adjust(vsize_s *v, vfd_s* vfd)
+void vsize_ensure_data_range(vsize_s *v, btree_s **ranges, const long offset, const long bytes)
{
- if (v->vsize >= vfd->offset)
- return;
+ if (*ranges == NULL) {
+ if (offset == 0) {
+ if (v->bytes + IGNORE_FILE_HOLE_BYTES < bytes) {
+ // No file hole, just set the new (larger) vsize
+ v->bytes = bytes;
+ } else {
+ // Nothing to do, vsize is already sufficient
+ }
+
+ } else { // if (offset > 0)
+ if (offset <= v->bytes) {
+ // We won't add a hole to the file here either
+ if (v->bytes < bytes) {
+ // No file hole, just set the new (larger) bytes
+ v->bytes = bytes;
+ } else {
+ // Nothing to do, bytes is already sufficient
+ }
+ } 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(*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->bytes = -1;
+
+ // Rerun this function with a data range btree initialised
+ vsize_ensure_data_range(v, ranges, offset, bytes);
+ }
+ }
- long deficit = v->vsize - vfd->offset;
- if (deficit < v->vsize_deficit) {
- v->vsize_deficit = deficit;
- _Set_required(v);
- _Set_file(v);
+ } 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;
+
+ 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;
- vsize_adjust(v, vfd_);
v->updates++;
}
-void vsize_seek(vsize_s *v, void *vfd, const long new_offset)
+void vsize_write(vsize_s *v, void *vfd, const char *path, const int bytes)
{
- //vfd_s *vfd_ = vfd;
-
- // 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 and is allowed. However, this behaviour
- // does not suit the estimation of the file size before we want to run the
- // test.
-
- // TODO: Implement file hole support!
- //v->updates++;
+ vfd_s *vfd_ = vfd;
+ vsize_ensure_data_range(v, &v->write_ranges, vfd_->offset, bytes);
+ vfd_->offset += bytes;
+ v->updates++;
}
-void vsize_write(vsize_s *v, void *vfd, const char *path, const int bytes)
+void vsize_seek(vsize_s *v, void *vfd, const long new_offset)
{
vfd_s *vfd_ = vfd;
- vfd_->offset += bytes;
- if (v->vsize < vfd_->offset)
- v->vsize = vfd_->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++;
}
diff --git a/ioriot/src/generate/vsize.h b/ioriot/src/generate/vsize.h
index 8556ec0..ffda9e5 100644
--- a/ioriot/src/generate/vsize.h
+++ b/ioriot/src/generate/vsize.h
@@ -16,7 +16,7 @@
#define VSIZE_H
#include "../utils/utils.h"
-#include "../datas/hmap.h"
+#include "../datas/btree.h"
#include "../vfd.h"
/**
@@ -30,11 +30,11 @@
*/
typedef struct vsize_s_ {
char *path; /**< The path to the file/directory */
- off_t offset; /**< The current file offset */
+ 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 */
- long vsize; /**< The virtual size */
- long vsize_deficit; /**< Size to use for file creating during init mode */
bool renamed; /**< True if file/dir has been renamed */
bool required; /**< True if init mode will create this file/dir */
bool is_dir; /**< True if this file/dir is a directory */
@@ -72,19 +72,18 @@ void vsize_destroy(vsize_s *v);
void init_parent_dir(vsize_s *v, const char *path);
/**
- * @brief Adjusts the vsize
+ * @brief Ensure that we have a data range in the virtual file
*
* Compares the virtual file size of the file in the vsize
- * object to the the offset in the virtual file descriptor.
- * In case the offset is higher we have a size deficit and
- * we need to mark it. That way ioriot can ensure that
- * during init mode it will create a file with the correct
- * size prior of running the test!
+ * object to the the given offsets. This is required just in case
+ * we have holes in the file to be replayed.
*
* @param v The virtual size object
- * @param vfd The virtual file descriptor object
+ * @param ranges The ranges object to operaet on
+ * @param offset The start offset
+ * @param bytes The amount of bytes
*/
-void vsize_adjust(vsize_s *v, vfd_s* vfd);
+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..3f9d8a0 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);
@@ -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/ioriot/src/init/itask.h
@@ -23,7 +23,8 @@
typedef struct itask_s_ {
bool is_dir;
bool is_file;
- long vsize;
+ long offset;
+ long bytes;
char *path;
long dirs_created;
long files_created;
diff --git a/ioriot/src/init/ithread.c b/ioriot/src/init/ithread.c
index a580e70..bcc31f3 100644
--- a/ioriot/src/init/ithread.c
+++ b/ioriot/src/init/ithread.c
@@ -90,9 +90,13 @@ void ithread_run_task(ithread_s *t, itask_s *task)
} else if (task->is_file) {
if (!ensure_file_exists(task->path, &task->dirs_created)) {
task->files_created++;
- if (task->vsize > 0) {
- append_random_to_file(task->path, task->vsize);
- task->sizes_created += task->vsize;
+ if (task->bytes > 0) {
+ if (task->offset > 0) {
+ write_random_to_file(task->path, task->bytes, task->offset);
+ } else {
+ append_random_to_file(task->path, task->bytes);
+ }
+ task->sizes_created += task->bytes;
}
}
}
diff --git a/ioriot/src/opcodes.h b/ioriot/src/opcodes.h
index 3d5c114..0dd060c 100644
--- a/ioriot/src/opcodes.h
+++ b/ioriot/src/opcodes.h
@@ -69,6 +69,7 @@ typedef enum {
FCNTL = 70,
GETDENTS,
LSEEK,
+ LLSEEK,
// mmap syscalls
MMAP2 = 80,
diff --git a/ioriot/src/replay/rioop.c b/ioriot/src/replay/rioop.c
index 2e16c94..0ce19c5 100644
--- a/ioriot/src/replay/rioop.c
+++ b/ioriot/src/replay/rioop.c
@@ -151,6 +151,7 @@ void rioop_run(rprocess_s *p, rthread_s *t, rtask_s *task)
rioop_getdents(p, t, task);
break;
case LSEEK:
+ case LLSEEK:
rioop_lseek(p, t, task);
break;
diff --git a/ioriot/src/utests.c b/ioriot/src/utests.c
index 0fc53c3..7cae7e8 100644
--- a/ioriot/src/utests.c
+++ b/ioriot