summaryrefslogtreecommitdiff
path: root/ioreplay/src/replay/rioop.c
diff options
context:
space:
mode:
Diffstat (limited to 'ioreplay/src/replay/rioop.c')
-rw-r--r--ioreplay/src/replay/rioop.c425
1 files changed, 425 insertions, 0 deletions
diff --git a/ioreplay/src/replay/rioop.c b/ioreplay/src/replay/rioop.c
new file mode 100644
index 0000000..2e16c94
--- /dev/null
+++ b/ioreplay/src/replay/rioop.c
@@ -0,0 +1,425 @@
+// 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 "rioop.h"
+
+#include "../vfd.h"
+#include "rworker.h"
+
+// Printing error messages
+#define _Error(...) \
+ fprintf(stderr, "%s:%d ERROR: ", __FILE__, __LINE__); \
+ fprintf(stderr, __VA_ARGS__); \
+ fprintf(stderr, "\nlineno:%ld path:%s\n", task->lineno, vfd->path); \
+ fflush(stdout); \
+ fflush(stderr); \
+ exit(ERROR);
+
+#define _Errno(...) \
+ fprintf(stderr, "%s:%d ERROR: %s (%d). ", __FILE__, __LINE__, \
+ strerror(errno), errno); \
+ fprintf(stderr, __VA_ARGS__); \
+ fprintf(stderr, "\nlineno:%ld path:%s\n", task->lineno, vfd->path); \
+ fflush(stdout); \
+ fflush(stderr); \
+ exit(ERROR);
+
+#define _Init_arg(num) int arg = atoi(task->toks[num])
+#define _Init_cmd(num) int cmd = atoi(task->toks[num])
+#define _Init_fd(num) long fd = atol(task->toks[num])
+#define _Init_flags(num) int flags = atoi(task->toks[num])
+//#define _Init_mode(num) int mode = atoi(task->toks[num])
+#define _Init_offset(num) long offset = atol(task->toks[num])
+#define _Init_op(num) int op = atoi(task->toks[num])
+#define _Init_path2(num) char *path2 = task->toks[num]
+#define _Init_path(num) char *path = task->toks[num]
+#define _Init_rc(num) int rc = atoi(task->toks[num])
+#define _Init_whence(num) long whence = atol(task->toks[num])
+
+#define _Init_bytes(num) \
+ int bytes = atoi(task->toks[num]); \
+ if (bytes <= 0) return
+
+#define _Init_virtfd \
+ vfd_s *vfd = amap_get(p->fds_map, fd); \
+ if (vfd == NULL) return
+
+void rioop_run(rprocess_s *p, rthread_s *t, rtask_s *task)
+{
+ _Init_op(2);
+
+ switch (op) {
+ // stat() syscalls
+ case FSTAT:
+ rioop_fstat(p, t, task);
+ break;
+ case FSTATFS:
+ case FSTATFS64:
+ //Error("op(%d) not implemented", op);
+ break;
+ case FSTAT_AT:
+ case LSTAT:
+ case STAT:
+ rioop_stat(p, t, task);
+ break;
+ case STATFS:
+ case STATFS64:
+ //Error("op(%d) not implemented", op);
+ break;
+
+ // read() syscalls
+ case READ:
+ case READV:
+ rioop_read(p, t, task);
+ break;
+ case READAHEAD:
+ //Error("op(%d) not implemented", op);
+ break;
+ case READLINK:
+ case READLINK_AT:
+ //Error("op(%d) not implemented", op);
+ break;
+
+ // write() syscalls
+ case WRITE:
+ case WRITEV:
+ rioop_write(p, t, task);
+ break;
+
+ // open() and other syscalls which may creat
+ case OPEN:
+ case OPEN_AT:
+ rioop_open(p, t, task, -1);
+ break;
+ case CREAT:
+ // A call to crat() is equivalent to calling open() with flags..
+ rioop_open(p, t, task, O_CREAT|O_WRONLY|O_TRUNC);
+ break;
+ case MKDIR:
+ case MKDIR_AT:
+ rioop_mkdir(p, t, task);
+ break;
+
+ // rename() syscalls
+ case RENAME:
+ case RENAME_AT:
+ case RENAME_AT2:
+ rioop_rename(p, t, task);
+ break;
+
+ // close() and unlink() syscalls
+ case CLOSE:
+ rioop_close(p, t, task);
+ break;
+ case UNLINK:
+ case UNLINK_AT:
+ rioop_unlink(p, t, task);
+ break;
+ case RMDIR:
+ rioop_rmdir(p, t, task);
+ break;
+
+ // sync() syscalls
+ case FSYNC:
+ rioop_fsync(p, t, task);
+ break;
+ case FDATASYNC:
+ rioop_fdatasync(p, t, task);
+ break;
+ case SYNC:
+ case SYNCFS:
+ case SYNC_FILE_RANGE:
+ //Error("op(%d) not implemented", op);
+ break;
+
+ // Other syscalls
+ case FCNTL:
+ rioop_fcntl(p, t, task);
+ break;
+ case GETDENTS:
+ rioop_getdents(p, t, task);
+ break;
+ case LSEEK:
+ rioop_lseek(p, t, task);
+ break;
+
+ // chmod() syscalls
+ case CHMOD:
+ rioop_chmod(p, t, task);
+ break;
+ case FCHMOD:
+ rioop_fchmod(p, t, task);
+ break;
+
+ // chown() syscalls
+ case CHOWN:
+ rioop_chown(p, t, task);
+ break;
+ case FCHOWN:
+ case FCHOWNAT:
+ rioop_fchown(p, t, task);
+ break;
+ case LCHOWN:
+ rioop_lchown(p, t, task);
+ break;
+
+ // Meta operations (I/O replay internal use only).
+ case META_EXIT_GROUP:
+ break;
+ case META_TIMELINE:
+ break;
+
+ default:
+ Error("op(%d) not implemented", op);
+ break;
+ }
+}
+
+void rioop_stat(rprocess_s *p, rthread_s *t, rtask_s *task)
+{
+ _Init_path(3);
+ struct stat buf;
+ stat(path, &buf);
+}
+
+void rioop_fstat(rprocess_s *p, rthread_s *t, rtask_s *task)
+{
+ _Init_fd(3);
+ _Init_virtfd;
+ struct stat buf;
+ fstat(vfd->fd, &buf);
+}
+
+void rioop_rename(rprocess_s *p, rthread_s *t, rtask_s *task)
+{
+ _Init_path(3);
+ _Init_path2(4);
+ rename(path, path2);
+}
+
+void rioop_read(rprocess_s *p, rthread_s *t, rtask_s *task)
+{
+ _Init_fd(3);
+ _Init_bytes(4);
+ _Init_virtfd;
+
+ char *buf = Calloc(bytes+1, char);
+ read(vfd->fd, buf, bytes);
+ free(buf);
+}
+
+void rioop_write(rprocess_s *p, rthread_s *t, rtask_s *task)
+{
+ _Init_fd(3);
+ _Init_bytes(4);
+ _Init_virtfd;
+
+ char *buf = Calloc(bytes+1, char);
+ sprintf(buf, "%ld", task->lineno);
+ Fill_with_stuff(buf, bytes);
+ if (vfd->fd == 0) {
+ Debug("%d %d %ld", vfd->fd, vfd->debug, task->lineno);
+ _Error("ERROR");
+ }
+ write(vfd->fd, buf, bytes);
+ free(buf);
+}
+
+void rioop_open(rprocess_s *p, rthread_s *t, rtask_s *task, int flags_)
+{
+ _Init_fd(3);
+ _Init_path(4);
+ _Init_flags(6);
+
+ // Special case as this is creat() now
+ if (flags_ != -1)
+ flags = flags_;
+
+ bool directory = Has(flags, O_DIRECTORY);
+
+ if (fd > 0) {
+ if (directory) {
+ // We can not open a directory via open() otherwise!
+ flags &= (O_RDONLY & ~(O_RDWR|O_WRONLY|O_CREAT));
+ } else {
+ // We don't want to open the file in read only mode.
+ // SystemTap could have skipped syscalls to fcntl or open
+ flags &= ~O_RDONLY;
+ }
+ // flags |= O_DIRECT|O_SYNC;
+ flags &= ~O_EXCL;
+ }
+
+ int ret = open(path, flags, S_IRWXU|S_IRWXG|S_IRWXO);
+
+ if (fd < 0 && ret > 0) {
+ close(ret);
+#ifdef THREAD_DEBUG
+ fprintf(t->rthread_fd, "TRACE OPEN|open+close|%s|\n", path);
+ fflush(t->rthread_fd);
+#endif
+ }
+
+ if (fd > 0 && ret > 0) {
+ vfd_s *vfd = vfd_new(ret, fd, path);
+ amap_set(p->fds_map, fd, vfd);
+
+#ifdef THREAD_DEBUG
+ fprintf(t->rthread_fd, "TRACE OPEN|open|%s|\n", path);
+ fflush(t->rthread_fd);
+#endif
+ }
+}
+
+void rioop_close(rprocess_s *p, rthread_s *t, rtask_s *task)
+{
+ _Init_fd(3);
+ _Init_virtfd;
+
+ amap_unset(p->fds_map, fd);
+ if (vfd->dirfd) {
+ closedir(vfd->dirfd);
+#ifdef THREAD_DEBUG
+ fprintf(t->rthread_fd, "TRACE OPEN|closedir|%s|\n", vfd->path);
+ fflush(t->rthread_fd);
+#endif
+ } else {
+ close(vfd->fd);
+#ifdef THREAD_DEBUG
+ fprintf(t->rthread_fd, "TRACE OPEN|close|%s|\n", vfd->path);
+ fflush(t->rthread_fd);
+#endif
+ }
+ vfd_destroy(vfd);
+}
+
+void rioop_getdents(rprocess_s *p, rthread_s *t, rtask_s *task)
+{
+ _Init_fd(3);
+ _Init_virtfd;
+
+ // getdents expects a dirfd
+ DIR *dirfd = fdopendir(vfd->fd);
+ if (dirfd) {
+ vfd->dirfd = dirfd;
+ readdir(dirfd);
+#ifdef THREAD_DEBUG
+ fprintf(t->rthread_fd, "TRACE OPEN|fdopendir|%s|\n", vfd->path);
+ fflush(t->rthread_fd);
+#endif
+ }
+}
+
+void rioop_mkdir(rprocess_s *p, rthread_s *t, rtask_s *task)
+{
+ _Init_path(3);
+ mkdir(path, S_IRWXU|S_IRWXG|S_IRWXO);
+}
+
+void rioop_unlink(rprocess_s *p, rthread_s *t, rtask_s *task)
+{
+ _Init_path(3);
+ unlink(path);
+}
+
+void rioop_rmdir(rprocess_s *p, rthread_s *t, rtask_s *task)
+{
+ _Init_path(3);
+ rmdir(path);
+}
+
+void rioop_lseek(rprocess_s *p, rthread_s *t, rtask_s *task)
+{
+ _Init_fd(3);
+ _Init_bytes(6);
+ _Init_virtfd;
+ lseek(vfd->fd, bytes, SEEK_SET);
+}
+
+void rioop_fsync(rprocess_s *p, rthread_s *t, rtask_s *task)
+{
+ _Init_fd(3);
+ _Init_virtfd;
+ fsync(vfd->fd);
+}
+
+void rioop_fdatasync(rprocess_s *p, rthread_s *t, rtask_s *task)
+{
+ _Init_fd(3);
+ _Init_virtfd;
+ fdatasync(vfd->fd);
+}
+
+void rioop_fcntl(rprocess_s *p, rthread_s *t, rtask_s *task)
+{
+ _Init_fd(3);
+ _Init_cmd(4);
+ _Init_arg(5);
+ _Init_virtfd;
+
+ switch (cmd) {
+ case F_GETFD:
+ case F_GETFL:
+ fcntl(vfd->fd, cmd);
+ break;
+ case F_SETFD:
+ case F_SETFL:
+ fcntl(vfd->fd, cmd, arg);
+ break;
+ default:
+ break;
+ }
+}
+
+void rioop_chmod(rprocess_s *p, rthread_s *t, rtask_s *task)
+{
+ _Init_path(3);
+ chmod(path, S_IRWXU|S_IRWXG|S_IRWXO);
+}
+
+void rioop_fchmod(rprocess_s *p, rthread_s *t, rtask_s *task)
+{
+ _Init_fd(3);
+ _Init_virtfd;
+ fchmod(vfd->fd, S_IRWXU|S_IRWXG|S_IRWXO);
+}
+
+void rioop_chown(rprocess_s *p, rthread_s *t, rtask_s *task)
+{
+ _Init_path(3);
+ rworker_s *w = t->worker;
+ options_s *opts = w->opts;
+ struct passwd *pwd = getpwnam(opts->user);
+ chown(path, pwd->pw_uid, -1);
+}
+
+void rioop_fchown(rprocess_s *p, rthread_s *t, rtask_s *task)
+{
+ _Init_fd(3);
+ _Init_virtfd;
+ rworker_s *w = t->worker;
+ options_s *opts = w->opts;
+ struct passwd *pwd = getpwnam(opts->user);
+ fchown(vfd->fd, pwd->pw_uid, -1);
+}
+
+void rioop_lchown(rprocess_s *p, rthread_s *t, rtask_s *task)
+{
+ _Init_path(3);
+ rworker_s *w = t->worker;
+ options_s *opts = w->opts;
+ struct passwd *pwd = getpwnam(opts->user);
+ lchown(path, pwd->pw_uid, -1);
+}
+