diff options
Diffstat (limited to 'ioreplay/src/generate')
| -rw-r--r-- | ioreplay/src/generate/generate.c | 235 | ||||
| -rw-r--r-- | ioreplay/src/generate/generate.h | 112 | ||||
| -rw-r--r-- | ioreplay/src/generate/gioop.c | 838 | ||||
| -rw-r--r-- | ioreplay/src/generate/gioop.h | 102 | ||||
| -rw-r--r-- | ioreplay/src/generate/gparser.c | 356 | ||||
| -rw-r--r-- | ioreplay/src/generate/gparser.h | 113 | ||||
| -rw-r--r-- | ioreplay/src/generate/gprocess.c | 101 | ||||
| -rw-r--r-- | ioreplay/src/generate/gprocess.h | 90 | ||||
| -rw-r--r-- | ioreplay/src/generate/gtask.c | 91 | ||||
| -rw-r--r-- | ioreplay/src/generate/gtask.h | 100 | ||||
| -rw-r--r-- | ioreplay/src/generate/gwriter.c | 85 | ||||
| -rw-r--r-- | ioreplay/src/generate/gwriter.h | 86 | ||||
| -rw-r--r-- | ioreplay/src/generate/vsize.c | 247 | ||||
| -rw-r--r-- | ioreplay/src/generate/vsize.h | 180 |
14 files changed, 2736 insertions, 0 deletions
diff --git a/ioreplay/src/generate/generate.c b/ioreplay/src/generate/generate.c new file mode 100644 index 0000000..ff1be94 --- /dev/null +++ b/ioreplay/src/generate/generate.c @@ -0,0 +1,235 @@ +// Copyright 2018 Mimecast Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "generate.h" + +#include "../meta/meta.h" +#include "gtask.h" +#include "gwriter.h" +#include "gparser.h" + +#include <fcntl.h> + +#define _MAX_PROCESSES 1024*1024*10 + +#define _Perc_filtered (g->num_lines_filtered / (g->lineno/100.0)) + +generate_s* generate_new(options_s *opts) +{ + generate_s *g = Malloc(generate_s); + + g->writer = NULL; + g->lineno = 0; + g->name = opts->name; + g->replay_fd = NULL; + g->mps = mounts_new(opts); + g->num_lines_filtered = 0; + g->num_vsizes = 0; + g->start_time = -1; + g->pid_map = amap_new(_MAX_PROCESSES); + g->vsize_map = hmap_new(_MAX_PROCESSES); + g->mmap_map = hmap_new(1024*1024); + g->vfd_buffer = rbuffer_new(1024); + g->num_mapped_pids = 0; + g->num_mapped_fds = 10; + g->opts = opts; + g->reuse_queue = rbuffer_new(1024); + g->replay_fd = Fopen(opts->replay_file, "w"); + + return g; +} + +void generate_destroy(generate_s *g) +{ + // TODO: Also clean the contets of these maps + amap_destroy(g->pid_map); + hmap_destroy(g->vsize_map); + hmap_destroy(g->mmap_map); + rbuffer_destroy(g->vfd_buffer); + mounts_destroy(g->mps); + + gtask_s *task = NULL; + while (NULL != (task = rbuffer_get_next(g->reuse_queue))) + gtask_destroy(task); + rbuffer_destroy(g->reuse_queue); + + fclose(g->replay_fd); + free(g); +} + + +status_e generate_run(options_s *opts) +{ + generate_s *g = generate_new(opts); + Put("Parsing file %s, writing output to %s", opts->capture_file, + opts->replay_file); + FILE *capture_fd = Fopen(opts->capture_file, "r"); + + size_t len = 0; + ssize_t read; + char *line = NULL; + + drop_root(opts->user); + + // Reserve first few bytes for meta information + meta_s *meta = meta_new(g->replay_fd); + meta_reserve(meta); + + // The writer will write the .replay file + gwriter_s *writer = gwriter_new(g); + + // The parser will parse every line of the .capture file + gparser_s *parser = gparser_new(g); + + g->writer = writer; + + // Start one writer and one parser thread! + gparser_start(parser); + gwriter_start(writer); + + Out("Processing, it may take a while: "); + + // Process each line of the .capture file. Determine line by line whether + // the I/O operation makes sense or not. It might be that SystemTap skipped + // some I/O ops due to system overload or other issues. The result is that + // some lines may be corrupt or contain I/O operations on unknown file + // handles. It could also be that there are operations on unknown + // file handles such as sockets etc. These will be all filtered out by + // either the parser or the writer thread! + + while ((read = getline(&line, &len, capture_fd)) != -1) { + if (0 > ++g->lineno) { + Error("lineno:%lu Line number overflow", g->lineno); + } + if (strlen(line) >= MAX_LINE_LEN) { + Error("lineno:%lu Exceeded max line length", g->lineno); + } + + // Create a new generate task (try to reuse a task object)... + gtask_s *t = rbuffer_get_next(g->reuse_queue); + if (!t) { + t = gtask_new(g); + } else if (t->ret != 0) { + g->num_lines_filtered++; + } + gtask_init(t, line, g->lineno); + + // ...pass it to the parser queue + while (!rbuffer_insert(parser->queue, t)) + usleep(100); + + if (g->lineno % 1000000 == 0) { + Out(" %lu (filtered:%.2lf%%)", g->lineno, _Perc_filtered); + } + } + + Put("\nDone reading input file!"); + + Put("Waiting for parser thread..."); + gparser_terminate(parser); + gparser_destroy(parser); + + Put("Waiting for writer thread..."); + gwriter_terminate(writer); + gwriter_destroy(writer); + + // Retrieve all left over processed tasks to collect the + // statistics! + gtask_s *t; + while (NULL != (t = rbuffer_get_next(g->reuse_queue))) { + if (t->ret != 0) + g->num_lines_filtered++; + gtask_destroy(t); + } + + Put("Processed %lu lines in total, had to filter out %.2lf%%", + g->lineno, _Perc_filtered); + + Put("Writing init section to '%s'...", opts->replay_file); + fprintf(g->replay_fd, "#INIT\n"); + off_t init_offset = ftello(g->replay_fd); + hmap_run_cb(g->vsize_map, generate_write_init_cb); + + Put("Writing meta header to '%s'...", opts->replay_file); + meta_write_start(meta); + + // The meta header is being written to the first line of the .replay + // file and used by ioreplay to do various things (e.g. initializing + // the test correctly, creating the internal data structures with the + // correct sizes etc. + + meta_write_l(meta, "replay_version", REPLAY_VERSION); + meta_write_l(meta, "init_offset", init_offset); + + meta_write_s(meta, "user", opts->user); + meta_write_s(meta, "name", opts->name); + + meta_write_l(meta, "num_vsizes", g->num_vsizes); + meta_write_l(meta, "num_mapped_pids", g->num_mapped_pids); + meta_write_l(meta, "num_mapped_fds", g->num_mapped_fds); + meta_write_l(meta, "num_lines", g->lineno - g->num_lines_filtered); + + meta_destroy(meta); + fclose(capture_fd); + + Put("Generating '%s' done", opts->replay_file); + generate_destroy(g); + + return SUCCESS; +} + +void generate_write_init_cb(void *data) +{ + vsize_s *l = data; + generate_s *g = l->generate; + + 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); + } +} + +vsize_s* generate_vsize_by_path(generate_s *g, gtask_s *t, + char *path) +{ + vsize_s *v = NULL; + + if (!path && t) + path = t->path; + + Error_if(!path, "No path specified"); + v = hmap_get(g->vsize_map, path); + + if (!v) { + v = vsize_new(path, ++g->num_vsizes, g); + hmap_insert(g->vsize_map, path, v); + } + + if (t) + t->vsize = v; + + return v; +} + +void generate_gprocess_by_realpid(generate_s *g, gtask_s *t) +{ + // Get the virtual process data object from the virtual PID space. + t->gprocess = amap_get(g->pid_map, t->pid); + if (t->gprocess == NULL) { + t->gprocess = gprocess_new(t->pid, ++g->num_mapped_pids); + if (amap_set(g->pid_map, t->pid, t->gprocess)) { + Error("lineno:%lu Can not insert PID %ld", t->lineno, t->pid); + } + } +} diff --git a/ioreplay/src/generate/generate.h b/ioreplay/src/generate/generate.h new file mode 100644 index 0000000..cf096d2 --- /dev/null +++ b/ioreplay/src/generate/generate.h @@ -0,0 +1,112 @@ +// Copyright 2018 Mimecast Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef GENERATE_H +#define GENERATE_H + +#include "gwriter.h" +#include "../datas/amap.h" +#include "../datas/hmap.h" +#include "../datas/rbuffer.h" +#include "../defaults.h" +#include "../mounts.h" +#include "../options.h" + +// Forward declarations (header include hell) +struct gtask_s_; + +/** + * @brief The generate object definition + * + * This is the general data structure required to generate a .replay file from + * the .capture file. + */ +typedef struct generate_s_ { + long lineno; /**< The current line number */ + long num_lines_filtered; /**< The amount of lines filtered out */ + long start_time; /**< The start time from the .capture file */ + char *name; /**< The name of the test specified by the user */ + FILE *replay_fd; /**< The fd of the .replay file */ + mounts_s *mps; /**< The mounts object */ + hmap_s *mmap_map; /**< mmap address mappings */ + amap_s *pid_map; /**< A map of all virtual process objects */ + unsigned long num_mapped_pids; /**< The amount of mapped PIDs */ + unsigned long num_mapped_fds; /**< The amount of mapped FDs */ + hmap_s *vsize_map; /**< A hash map of all virtual size objects */ + unsigned long num_vsizes; /**< The amount of virtual sizes */ + options_s *opts; /**< A pointer to the options object */ + rbuffer_s *vfd_buffer; /**< A virtual fd buffer, for reusing these */ + rbuffer_s *reuse_queue; /**< A task buffer, for reusing these */ + struct gwriter_s_ *writer; /**< A pointer to the writer object */ +} generate_s; + +/** + * @brief Creates a new generate object + * + * @param opts The options object + * @return The new generate object + */ +generate_s* generate_new(options_s *opts); + +/** + * @brief Destroys a generate object + * + * @param g The generate object to destroy + */ +void generate_destroy(generate_s* g); + +/** + * @brief Generates a .replay file from a .capture file + * + * @param opts The options object + * @return SUCCESS on success + */ +status_e generate_run(options_s *opts); + +/** + * @brief Callback to write the INIT section to the .replay file + * + * This function writes a list of all pre-required + * paths to the .replay file. That then can be used + * by ioreplay to initialise the test enironment. + * + * @param data A pointer to the vsize timestamp object + */ +void generate_write_init_cb(void *data); + +/** + * @brief Retrieves the virtual size object of a given path + * + * A new one will be created in case there is no such virtual size object yet. + * + * @param g The generate object + * @param t The task object (vfd will be stored to t->vfd) + * @param path The file path + * @return The virtual size object + */ +vsize_s* generate_vsize_by_path(generate_s *g, struct gtask_s_ *t, + char *path); + +/** + * @brief Retrieves the virtual process object of a given real PID + * + * A new one will be created in case there is no such virtual process object + * yet. + * + * @param g The generate object + * @param t The task object (vfd will be stored to t->gprocess) + */ +void generate_gprocess_by_realpid(generate_s *g, struct gtask_s_ *t); + +#endif // GENERATE_H diff --git a/ioreplay/src/generate/gioop.c b/ioreplay/src/generate/gioop.c new file mode 100644 index 0000000..01701bc --- /dev/null +++ b/ioreplay/src/generate/gioop.c @@ -0,0 +1,838 @@ +// Copyright 2018 Mimecast Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "gioop.h" + +status_e gioop_run(gwriter_s *w, gtask_s *t) +{ + status_e ret = SUCCESS; + + // There was already an error in the parser (parser.c) processing this + // task! Don't process it futher. + if (t->ret != SUCCESS) { + Cleanup(t->ret); + } + + 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 + generate_gprocess_by_realpid(g, t); + + // One of the open syscalls may openes a file handle succesfully + if (Eq(t->op, "open")) { + Cleanup(gioop_open(w, t, g)); + + } else if (Eq(t->op, "openat")) { + Cleanup(gioop_openat(w, t, g)); + + } else if (Eq(t->op, "creat")) { + Cleanup(gioop_creat(w, t, g)); + } + + // Get the virtual file descriptor of a given real fd and store a pointer + // to it to t->vfd. + if (t->has_fd) { + ret = gprocess_vfd_by_realfd(t->gprocess, t); + Cleanup_unless(SUCCESS, ret); + } + + + if (Eq(t->op, "close")) { + Cleanup(gioop_close(w, t, g)); + + } else if (Eq(t->op, "stat")) { + Cleanup(gioop_stat(w, t, g)); + + } else if (Eq(t->op, "statfs")) { + Cleanup(gioop_statfs(w, t, g)); + + } else if (Eq(t->op, "statfs64")) { + Cleanup(gioop_statfs64(w, t, g)); + + } else if (Eq(t->op, "fstat")) { + Cleanup(gioop_fstat(w, t, g)); + + } else if (Eq(t->op, "fstatat")) { + Cleanup(gioop_fstatat(w, t, g)); + + } else if (Eq(t->op, "fstatfs")) { + Cleanup(gioop_fstatfs(w, t, g)); + + } else if (Eq(t->op, "fstatfs64")) { + Cleanup(gioop_fstatfs64(w, t, g)); + + } else if (Eq(t->op, "rename")) { + Cleanup(gioop_rename(w, t, g)); + + } else if (Eq(t->op, "renameat")) { + Cleanup(gioop_renameat(w, t, g)); + + } else if (Eq(t->op, "renameat2")) { + Cleanup(gioop_renameat2(w, t, g)); + + } else if (Eq(t->op, "read")) { + Cleanup(gioop_read(w, t, g)); + + } else if (Eq(t->op, "readv")) { + Cleanup(gioop_readv(w, t, g)); + + } else if (Eq(t->op, "readahead")) { + Cleanup(gioop_readahead(w, t, g)); + + } else if (Eq(t->op, "readdir")) { + Cleanup(gioop_readdir(w, t, g)); + + } else if (Eq(t->op, "readlink")) { + Cleanup(gioop_readlink(w, t, g)); + + } else if (Eq(t->op, "readlinkat")) { + Cleanup(gioop_readlinkat(w, t, g)); + + } else if (Eq(t->op, "write")) { + Cleanup(gioop_write(w, t, g)); + + } else if (Eq(t->op, "writev")) { + Cleanup(gioop_writev(w, t, g)); + + } else if (Eq(t->op, "lseek")) { + Cleanup(gioop_lseek(w, t, g)); + + } else if (Eq(t->op, "getdents")) { + Cleanup(gioop_getdents(w, t, g)); + + } else if (Eq(t->op, "mkdir")) { + Cleanup(gioop_mkdir(w, t, g)); + + } else if (Eq(t->op, "rmdir")) { + Cleanup(gioop_rmdir(w, t, g)); + + } else if (Eq(t->op, "mkdirat")) { + Cleanup(gioop_mkdirat(w, t, g)); + + } else if (Eq(t->op, "unlink")) { + Cleanup(gioop_unlink(w, t, g)); + + } else if (Eq(t->op, "unlinkat")) { + Cleanup(gioop_unlinkat(w, t, g)); + + } else if (Eq(t->op, "lstat")) { + Cleanup(gioop_lstat(w, t, g)); + + } else if (Eq(t->op, "fsync")) { + Cleanup(gioop_fsync(w, t, g)); + + } else if (Eq(t->op, "fdatasync")) { + Cleanup(gioop_fdatasync(w, t, g)); + + } else if (Eq(t->op, "sync")) { + Cleanup(gioop_sync(w, t, g)); + + } else if (Eq(t->op, "syncfs")) { + Cleanup(gioop_syncfs(w, t, g)); + + } else if (Eq(t->op, "sync_file_range")) { + Cleanup(gioop_sync_file_range(w, t, g)); + + } else if (Eq(t->op, "fcntl")) { + Cleanup(gioop_fcntl(w, t, g)); + + } else if (Eq(t->op, "fcntl")) { + Cleanup(gioop_fcntl(w, t, g)); + + } else if (Eq(t->op, "mmap2")) { + // Support for mmap added later + + } else if (Eq(t->op, "munmap")) { + // Support for mmap added later + + } else if (Eq(t->op, "mremap")) { + // Support for mmap added later + + } else if (Eq(t->op, "msync")) { + // Support for mmap added later + + } else if (Eq(t->op, "chmod")) { + Cleanup(gioop_chmod(w, t, g)); + + } else if (Eq(t->op, "fchmodat")) { + Cleanup(gioop_chmod(w, t, g)); + + } else if (Eq(t->op, "fchmod")) { + Cleanup(gioop_fchmod(w, t, g)); + + } else if (Eq(t->op, "chown")) { + Cleanup(gioop_chown(w, t, g)); + + } else if (Eq(t->op, "chown16")) { + Cleanup(gioop_chown(w, t, g)); + + } else if (Eq(t->op, "lchown")) { + Cleanup(gioop_lchown(w, t, g)); + + } else if (Eq(t->op, "lchown16")) { + Cleanup(gioop_lchown(w, t, g)); + + } else if (Eq(t->op, "fchown")) { + Cleanup(gioop_fchown(w, t, g)); + + } else if (Eq(t->op, "fchownat")) { + Cleanup(gioop_chown(w, t, g)); + + } else if (Eq(t->op, "exit_group")) { + Cleanup(gioop_exit_group(w, t, g)); + + } else { + Cleanup(ERROR;); + } + +cleanup: + +#ifdef LOG_FILTERED + if (ret != SUCCESS) + t->filtered_where = __FILE__; +#endif + + t->ret = ret; + return ret; +} + +status_e gioop_open(gwriter_s *w, gtask_s *t, generate_s *g) +{ + if (!t->has_fd || t->path == NULL || t->flags == -1) { + return ERROR; + } + + gprocess_create_vfd_by_realfd(t->gprocess, t, g); + generate_vsize_by_path(g, t, NULL); + + Gioop_write(OPEN, "%ld|%s|%d|%d|open", + t->mapped_fd, t->path, t->mode, t->flags); + + if (t->fd > 0) + vsize_open(t->vsize, t->vfd, t->path, t->flags); + + return SUCCESS; +} + +status_e gioop_openat(gwriter_s *w, gtask_s *t, generate_s *g) +{ + if (!t->has_fd || t->path == NULL || t->flags == -1) { + return ERROR; + } + + gprocess_create_vfd_by_realfd(t->gprocess, t, g); + generate_vsize_by_path(g, t, NULL); + Gioop_write(OPEN_AT, "%ld|%s|%d|%d|openat", + t->mapped_fd,t->path, t->mode, t->flags); + if (t->fd > 0) + vsize_open(t->vsize, t->vfd, t->path, t->flags); + + return SUCCESS; +} + +status_e gioop_creat(gwriter_s *w, gtask_s *t, generate_s *g) +{ + if (!t->has_fd || t->path == NULL || t->flags == -1) { + return ERROR; + } + + gprocess_create_vfd_by_realfd(t->gprocess, t, g); + generate_vsize_by_path(g, t, NULL); + + Gioop_write(CREAT, "%ld|%s|%d|%d|creat", + t->mapped_fd, t->path, t->mode, t->flags); + if (t->fd > 0) + vsize_open(t->vsize, t->vfd, t->path, t->flags); + + return SUCCESS; +} + + +status_e gioop_close(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(CLOSE, "%ld|%d|close", t->mapped_fd, t->status); + + if (t->status == 0) + vsize_close(t->vsize, t->vfd); + + hmap_remove_l(t->gprocess->fd_map, t->fd); + hmap_remove_l(t->gprocess->vfd_map, t->mapped_fd); + + if (!(rbuffer_insert(g->vfd_buffer, t->vfd))) + vfd_destroy(t->vfd); + + return SUCCESS; +} + +status_e gioop_stat(gwriter_s *w, gtask_s *t, generate_s *g) +{ + if (t->path == NULL) { + return ERROR; + } + + generate_vsize_by_path(g, t, NULL); + Gioop_write(STAT, "%s|%d|stat", t->path, t->status); + + if (t->status == 0) + vsize_stat(t->vsize, t->path); + + return SUCCESS; +} + +status_e gioop_statfs(gwriter_s *w, gtask_s *t, generate_s *g) +{ + if (t->path == NULL) { + return ERROR; + } + + generate_vsize_by_path(g, t, NULL); + Gioop_write(STATFS, "%s|%d|statfs", t->path, t->status); + + if (t->status == 0) + vsize_stat(t->vsize, t->path); + + return SUCCESS; +} + +status_e gioop_statfs64(gwriter_s *w, gtask_s *t, generate_s *g) +{ + if (t->path == NULL) { + return ERROR; + } + + generate_vsize_by_path(g, t, NULL); + Gioop_write(STATFS64, "%s|%d|statfs64", t->path, t->status); + + if (t->status == 0) + vsize_stat(t->vsize, t->path); + + return SUCCESS; +} + +status_e gioop_fstat(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(FSTAT, "%ld|%d|fstat", t->mapped_fd, t->status); + + return SUCCESS; +} + +status_e gioop_fstatat(gwriter_s *w, gtask_s *t, generate_s *g) +{ + if (t->path == NULL) { + return ERROR; + } + + generate_vsize_by_path(g, t, NULL); + Gioop_write(FSTAT_AT, "%s|%d|fstatat", t->path, t->status); + + if (t->status == 0) + vsize_stat(t->vsize, t->path); + + return SUCCESS; +} + +status_e gioop_fstatfs(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(FSTATFS, "%ld|%d|fstatfs", t->mapped_fd, t->status); + + return SUCCESS; +} + +status_e gioop_fstatfs64(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(FSTATFS64, "%ld|%d|fstatfs64", t->mapped_fd, t->status); + + return SUCCESS; +} + +status_e gioop_rename(gwriter_s *w, gtask_s *t, generate_s *g) +{ + if (t->path == NULL || t->path2 == NULL ) { + return ERROR; + } + + generate_vsize_by_path(g, t, NULL); + Gioop_write(RENAME, "%s|%s|%d|rename", t->path, t->path2, t->status); + + if (t->status == 0) { + t->vsize2 = generate_vsize_by_path(g, NULL, t->path2); + vsize_rename(t->vsize, t->vsize2, t->path, t->path2); + } + + return SUCCESS; +} + +status_e gioop_renameat(gwriter_s *w, gtask_s *t, generate_s *g) +{ + if (t->path == NULL || t->path2 == NULL ) { + return ERROR; + } + + generate_vsize_by_path(g, t, NULL); + Gioop_write(RENAME_AT, "%s|%s|%d|renameat", t->path, t->path2, t->status); + + if (t->status == 0) { + t->vsize2 = generate_vsize_by_path(g, NULL, t->path2); + vsize_rename(t->vsize, t->vsize2, t->path, t->path2); + } + + return SUCCESS; +} +status_e gioop_renameat2(gwriter_s *w, gtask_s *t, generate_s *g) +{ + if (t->path == NULL || t->path2 == NULL ) { + return ERROR; + } + + generate_vsize_by_path(g, t, NULL); + Gioop_write(RENAME_AT2, "%s|%s|%d|renameat2", + t->path, t->path2, t->status); + + if (t->status == 0) { + t->vsize2 = generate_vsize_by_path(g, NULL, t->path2); + vsize_rename(t->vsize, t->vsize2, t->path, t->path2); + } + + return SUCCESS; +} + +status_e gioop_read(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(READ, "%ld|%ld|read", t->mapped_fd, t->bytes); + + if (t->bytes > 0) + vsize_read(t->vsize, t->vfd, t->vfd->path, t->bytes); + + return SUCCESS; +} + +status_e gioop_readv(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(READ, "%ld|%ld|readv", t->mapped_fd, t->bytes); + + if (t->bytes > 0) + vsize_read(t->vsize, t->vfd, t->vfd->path, t->bytes); + + return SUCCESS; +} + +status_e gioop_readahead(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(READAHEAD, "%ld|%ld|%ld|readahead", + t->mapped_fd, t->offset, t->count); + + return SUCCESS; +} + +status_e gioop_readdir(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(READDIR, "%ld|%d|readdir", t->mapped_fd, t->status); + + return SUCCESS; +} + +status_e gioop_readlink(gwriter_s *w, gtask_s *t, generate_s *g) +{ + if (t->path == NULL) { + return ERROR; + } + + generate_vsize_by_path(g, t, NULL); + Gioop_write(READLINK, "%s|%d|readlink", t->path, t->status); + + if (t->status == 0) + vsize_stat(t->vsize, t->path); + + return SUCCESS; +} + +status_e gioop_readlinkat(gwriter_s *w, gtask_s *t, generate_s *g) +{ + if (t->path == NULL) { + return ERROR; + } + + generate_vsize_by_path(g, t, NULL); + Gioop_write(READLINK_AT, "%s|%d|readlinkat", t->path, t->status); + + if (t->status == 0) + vsize_stat(t->vsize, t->path); + + return SUCCESS; +} + +status_e gioop_write(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(WRITE, "%ld|%ld|write", t->mapped_fd, t->bytes); + + if (t->bytes > 0) + vsize_write(t->vsize, t->vfd, t->path, t->bytes); + + return SUCCESS; +} + +status_e gioop_writev(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(WRITEV, "%ld|%ld|writev", t->mapped_fd, t->bytes); + + if (t->bytes > 0) + vsize_write(t->vsize, t->vfd, t->path, t->bytes); + + return SUCCESS; +} + +status_e gioop_lseek(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(LSEEK, "%ld|%ld|%ld|%ld|lseek", + 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) { + return ERROR; + } + + generate_vsize_by_path(g, t, t->vfd->path); + Gioop_write(GETDENTS, "%ld|%ld|%ld|getdents", + t->mapped_fd, t->count, t->bytes); + + return SUCCESS; +} + +status_e gioop_mkdir(gwriter_s *w, gtask_s *t, generate_s *g) +{ + if (t->path == NULL) { + return ERROR; + } + + generate_vsize_by_path(g, t, NULL); + Gioop_write(MKDIR, "%s|%d|%d|mkdir", t->path, t->mode, t->status); + + if (t->status == 0) + vsize_mkdir(t->vsize, t->path); + + return SUCCESS; +} +status_e gioop_rmdir(gwriter_s *w, gtask_s *t, generate_s *g) +{ + if (t->path == NULL) { + return ERROR; + } + + generate_vsize_by_path(g, t, NULL); + Gioop_write(MKDIR, "%s|%d|rmdir", t->path, t->status); + + if (t->status == 0) + vsize_rmdir(t->vsize, t->path); + + return SUCCESS; +} +status_e gioop_mkdirat(gwriter_s *w, gtask_s *t, generate_s *g) +{ + if (t->path == NULL) { + return ERROR; + } + + generate_vsize_by_path(g, t, NULL); + Gioop_write(MKDIR_AT, "%s|%d|%d|mkdirat", t->path, t->mode, t->status); + + if (t->status == 0) + vsize_mkdir(t->vsize, t->path); + + return SUCCESS; +} + +status_e gioop_unlink(gwriter_s *w, gtask_s *t, generate_s *g) +{ + if (t->path == NULL) { + return ERROR; + } + + generate_vsize_by_path(g, t, NULL); + Gioop_write(UNLINK, "%s|%d|unlink", t->path, t->status); + + if (t->status == 0) + vsize_unlink(t->vsize, t->path); + + return SUCCESS; +} + +status_e gioop_unlinkat(gwriter_s *w, gtask_s *t, generate_s *g) +{ + if (t->path == NULL) { + return ERROR; + } + + generate_vsize_by_path(g, t, NULL); + Gioop_write(UNLINK_AT, "%s|%d|unlinkat", t->path, t->status); + + if (t->status == 0) + vsize_unlink(t->vsize, t->path); + + return SUCCESS; +} + +status_e gioop_lstat(gwriter_s *w, gtask_s *t, generate_s *g) +{ + if (t->path == NULL) { + return ERROR; + } + + generate_vsize_by_path(g, t, NULL); + Gioop_write(LSTAT, "%s|%d|lstat", t->path, t->status); + + if (t->status == 0) + vsize_stat(t->vsize, t->path); + + return SUCCESS; +} + +status_e gioop_fsync(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(FSYNC, "%ld|%d|fsync", t->mapped_fd, t->status); + + return SUCCESS; +} + +status_e gioop_fdatasync(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(FDATASYNC, "%ld|%d|fdatasync", t->mapped_fd, t->status); + + return SUCCESS; +} + +status_e gioop_sync(gwriter_s *w, gtask_s *t, generate_s *g) +{ + Gioop_write(SYNC, "%d|sync", t->status); + + return SUCCESS; +} + +status_e gioop_syncfs(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(SYNCFS, "%ld|%d|syncfs", t->mapped_fd, t->status); + + return SUCCESS; +} + +status_e gioop_sync_file_range(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(SYNC_FILE_RANGE, "%ld|%ld|%ld|%d|sync_file_range", + t->mapped_fd, t->offset, t->bytes, t->status); + + return SUCCESS; +} + +status_e gioop_fcntl(gwriter_s *w, gtask_s *t, generate_s *g) +{ + if (!t->has_fd) { + return ERROR; |
