bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2015-2018 Dovecot authors, see the included COPYING file */
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen#include "lib.h"
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen#include "istream.h"
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen#include "istream-private.h"
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen#include "istream-concat.h"
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen#include "istream-failure-at.h"
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen#include "ostream-failure-at.h"
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen#include "ostream.h"
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen#include "fs-api-private.h"
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen#define RANDOMFAIL_ERROR "Random failure injection"
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainenstatic const char *fs_op_names[FS_OP_COUNT] = {
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen "wait", "metadata", "prefetch", "read", "write", "lock", "exists",
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen "stat", "copy", "rename", "delete", "iter"
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen};
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainenstruct randomfail_fs {
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen struct fs fs;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen unsigned int op_probability[FS_OP_COUNT];
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen uoff_t range_start[FS_OP_COUNT], range_end[FS_OP_COUNT];
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen};
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainenstruct randomfail_fs_file {
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen struct fs_file file;
19126597f92e5cdde901ac472090aa423e0e5541Timo Sirainen struct fs_file *super_read;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen struct istream *input;
90dd3c6ed38f3501fff3cf79ac9fb0478b25969fTimo Sirainen bool op_pending[FS_OP_COUNT];
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen struct ostream *super_output;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen};
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainenstruct randomfail_fs_iter {
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen struct fs_iter iter;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen struct fs_iter *super;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen unsigned int fail_pos;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen};
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainenstatic struct fs *fs_randomfail_alloc(void)
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen{
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen struct randomfail_fs *fs;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen fs = i_new(struct randomfail_fs, 1);
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen fs->fs = fs_class_randomfail;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen return &fs->fs;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen}
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainenstatic bool fs_op_find(const char *str, enum fs_op *op_r)
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen{
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen enum fs_op op;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen for (op = 0; op < FS_OP_COUNT; op++) {
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen if (strcmp(fs_op_names[op], str) == 0) {
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen *op_r = op;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen return TRUE;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen }
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen }
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen return FALSE;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen}
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
d9a7e950a9cd21f2b4a90ec7759fca9e8fcc7995Timo Sirainenstatic int
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainenfs_randomfail_add_probability(struct randomfail_fs *fs,
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen const char *key, const char *value,
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen const char **error_r)
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen{
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen unsigned int num;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen enum fs_op op;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen bool invalid_value = FALSE;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen if (str_to_uint(value, &num) < 0 || num > 100)
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen invalid_value = TRUE;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen if (fs_op_find(key, &op)) {
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen if (invalid_value) {
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen *error_r = "Invalid probability value";
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen return -1;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen }
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen fs->op_probability[op] = num;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen return 1;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen }
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen if (strcmp(key, "all") == 0) {
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen if (invalid_value) {
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen *error_r = "Invalid probability value";
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen return -1;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen }
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen for (op = 0; op < FS_OP_COUNT; op++)
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen fs->op_probability[op] = num;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen return 1;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen }
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen return 0;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen}
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainenstatic int
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainenfs_randomfail_add_probability_range(struct randomfail_fs *fs,
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen const char *key, const char *value,
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen const char **error_r)
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen{
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen enum fs_op op;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen const char *p;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen uoff_t num1, num2;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen if (strcmp(key, "read-range") == 0)
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen op = FS_OP_READ;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen else if (strcmp(key, "write-range") == 0)
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen op = FS_OP_WRITE;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen else if (strcmp(key, "iter-range") == 0)
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen op = FS_OP_ITER;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen else
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen return 0;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen p = strchr(value, '-');
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen if (p == NULL) {
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen if (str_to_uoff(value, &num1) < 0) {
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen *error_r = "Invalid range value";
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen return -1;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen }
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen num2 = num1;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen } else if (str_to_uoff(t_strdup_until(value, p), &num1) < 0 ||
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen str_to_uoff(p+1, &num2) < 0 || num1 > num2) {
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen *error_r = "Invalid range values";
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen return -1;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen }
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen fs->range_start[op] = num1;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen fs->range_end[op] = num2;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen return 1;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen}
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainenstatic int fs_randomfail_parse_params(struct randomfail_fs *fs,
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen const char *params, const char **error_r)
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen{
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen const char *const *tmp;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen int ret;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen for (tmp = t_strsplit_spaces(params, ","); *tmp != NULL; tmp++) {
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen const char *key = *tmp;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen const char *value = strchr(key, '=');
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen if (value == NULL) {
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen *error_r = "Missing '='";
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen return -1;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen }
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen key = t_strdup_until(key, value++);
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen if ((ret = fs_randomfail_add_probability(fs, key, value, error_r)) != 0) {
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen if (ret < 0)
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen return -1;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen continue;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen }
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen if ((ret = fs_randomfail_add_probability_range(fs, key, value, error_r)) != 0) {
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen if (ret < 0)
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen return -1;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen continue;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen }
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen *error_r = t_strdup_printf("Unknown key '%s'", key);
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen return -1;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen }
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen return 0;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen}
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainenstatic int
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainenfs_randomfail_init(struct fs *_fs, const char *args,
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen const struct fs_settings *set)
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen{
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen struct randomfail_fs *fs = (struct randomfail_fs *)_fs;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen const char *p, *parent_name, *parent_args, *error;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen p = strchr(args, ':');
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen if (p == NULL) {
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen fs_set_error(_fs, "Randomfail parameters missing");
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen return -1;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen }
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen if (fs_randomfail_parse_params(fs, t_strdup_until(args, p++), &error) < 0) {
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen fs_set_error(_fs, "Invalid randomfail parameters: %s", error);
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen return -1;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen }
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen args = p;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen if (*args == '\0') {
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen fs_set_error(_fs, "Parent filesystem not given as parameter");
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen return -1;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen }
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen parent_args = strchr(args, ':');
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen if (parent_args == NULL) {
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen parent_name = args;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen parent_args = "";
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen } else {
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen parent_name = t_strdup_until(args, parent_args);
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen parent_args++;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen }
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen if (fs_init(parent_name, parent_args, set, &_fs->parent, &error) < 0) {
1cc7a6c6a986b972fdb7eac146f4ca8036aca4e6Timo Sirainen fs_set_error(_fs, "%s", error);
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen return -1;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen }
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen return 0;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen}
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainenstatic void fs_randomfail_deinit(struct fs *_fs)
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen{
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen struct randomfail_fs *fs = (struct randomfail_fs *)_fs;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen if (_fs->parent != NULL)
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen fs_deinit(&_fs->parent);
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen i_free(fs);
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen}
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainenstatic enum fs_properties fs_randomfail_get_properties(struct fs *_fs)
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen{
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen return fs_get_properties(_fs->parent);
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen}
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
86ad48a2e740bd63a9b7299d7f3e229831d9b303Timo Sirainenstatic struct fs_file *fs_randomfail_file_alloc(void)
86ad48a2e740bd63a9b7299d7f3e229831d9b303Timo Sirainen{
86ad48a2e740bd63a9b7299d7f3e229831d9b303Timo Sirainen struct randomfail_fs_file *file = i_new(struct randomfail_fs_file, 1);
86ad48a2e740bd63a9b7299d7f3e229831d9b303Timo Sirainen return &file->file;
86ad48a2e740bd63a9b7299d7f3e229831d9b303Timo Sirainen}
86ad48a2e740bd63a9b7299d7f3e229831d9b303Timo Sirainen
86ad48a2e740bd63a9b7299d7f3e229831d9b303Timo Sirainenstatic void
86ad48a2e740bd63a9b7299d7f3e229831d9b303Timo Sirainenfs_randomfail_file_init(struct fs_file *_file, const char *path,
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen enum fs_open_mode mode, enum fs_open_flags flags)
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen{
86ad48a2e740bd63a9b7299d7f3e229831d9b303Timo Sirainen struct randomfail_fs_file *file = (struct randomfail_fs_file *)_file;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen file->file.path = i_strdup(path);
6d1218e68ce883735ffde9d7907e626ab81b9fb5Timo Sirainen file->file.parent = fs_file_init_parent(_file, path, mode | flags);
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen}
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainenstatic void fs_randomfail_file_deinit(struct fs_file *_file)
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen{
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen struct randomfail_fs_file *file = (struct randomfail_fs_file *)_file;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
19126597f92e5cdde901ac472090aa423e0e5541Timo Sirainen fs_file_deinit(&file->file.parent);
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen i_free(file->file.path);
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen i_free(file);
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen}
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
90dd3c6ed38f3501fff3cf79ac9fb0478b25969fTimo Sirainenstatic bool fs_random_fail(struct fs *_fs, int divider, enum fs_op op)
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen{
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen struct randomfail_fs *fs = (struct randomfail_fs *)_fs;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen if (fs->op_probability[op] == 0)
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen return FALSE;
191153d1a5b0eb0c129139570e3aa5212f28d2acJosef 'Jeff' Sipek if ((unsigned int)i_rand_limit(100 * divider) <= fs->op_probability[op]) {
05d12810ed20a2d1271410b953e1f2b5a8595b71Timo Sirainen errno = EIO;
cc8fdda7b8e82de63115d2dfc80ea63cdde51e3eTimo Sirainen fs_set_error(_fs, RANDOMFAIL_ERROR);
cc8fdda7b8e82de63115d2dfc80ea63cdde51e3eTimo Sirainen return TRUE;
cc8fdda7b8e82de63115d2dfc80ea63cdde51e3eTimo Sirainen }
cc8fdda7b8e82de63115d2dfc80ea63cdde51e3eTimo Sirainen return FALSE;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen}
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
90dd3c6ed38f3501fff3cf79ac9fb0478b25969fTimo Sirainenstatic bool
90dd3c6ed38f3501fff3cf79ac9fb0478b25969fTimo Sirainenfs_file_random_fail_begin(struct randomfail_fs_file *file, enum fs_op op)
90dd3c6ed38f3501fff3cf79ac9fb0478b25969fTimo Sirainen{
90dd3c6ed38f3501fff3cf79ac9fb0478b25969fTimo Sirainen if (!file->op_pending[op]) {
90dd3c6ed38f3501fff3cf79ac9fb0478b25969fTimo Sirainen if (fs_random_fail(file->file.fs, 2, op))
90dd3c6ed38f3501fff3cf79ac9fb0478b25969fTimo Sirainen return TRUE;
90dd3c6ed38f3501fff3cf79ac9fb0478b25969fTimo Sirainen }
90dd3c6ed38f3501fff3cf79ac9fb0478b25969fTimo Sirainen file->op_pending[op] = TRUE;
90dd3c6ed38f3501fff3cf79ac9fb0478b25969fTimo Sirainen return FALSE;
90dd3c6ed38f3501fff3cf79ac9fb0478b25969fTimo Sirainen}
90dd3c6ed38f3501fff3cf79ac9fb0478b25969fTimo Sirainen
90dd3c6ed38f3501fff3cf79ac9fb0478b25969fTimo Sirainenstatic int
90dd3c6ed38f3501fff3cf79ac9fb0478b25969fTimo Sirainenfs_file_random_fail_end(struct randomfail_fs_file *file,
90dd3c6ed38f3501fff3cf79ac9fb0478b25969fTimo Sirainen int ret, enum fs_op op)
90dd3c6ed38f3501fff3cf79ac9fb0478b25969fTimo Sirainen{
50072aa4241f048dbdf4800c554b2766615c31d9Timo Sirainen if (ret == 0 || errno != EAGAIN) {
90dd3c6ed38f3501fff3cf79ac9fb0478b25969fTimo Sirainen if (fs_random_fail(file->file.fs, 2, op))
49b6e2d72cfaa5c244c798ddbae5b61489b0f728Timo Sirainen return -1;
90dd3c6ed38f3501fff3cf79ac9fb0478b25969fTimo Sirainen file->op_pending[op] = FALSE;
90dd3c6ed38f3501fff3cf79ac9fb0478b25969fTimo Sirainen }
90dd3c6ed38f3501fff3cf79ac9fb0478b25969fTimo Sirainen return ret;
90dd3c6ed38f3501fff3cf79ac9fb0478b25969fTimo Sirainen}
90dd3c6ed38f3501fff3cf79ac9fb0478b25969fTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainenstatic bool
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainenfs_random_fail_range(struct fs *_fs, enum fs_op op, uoff_t *offset_r)
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen{
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen struct randomfail_fs *fs = (struct randomfail_fs *)_fs;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
90dd3c6ed38f3501fff3cf79ac9fb0478b25969fTimo Sirainen if (!fs_random_fail(_fs, 1, op))
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen return FALSE;
191153d1a5b0eb0c129139570e3aa5212f28d2acJosef 'Jeff' Sipek *offset_r = i_rand_minmax(fs->range_start[op], fs->range_end[op]);
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen return TRUE;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen}
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainenstatic int
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainenfs_randomfail_get_metadata(struct fs_file *_file,
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen const ARRAY_TYPE(fs_metadata) **metadata_r)
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen{
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen struct randomfail_fs_file *file = (struct randomfail_fs_file *)_file;
90dd3c6ed38f3501fff3cf79ac9fb0478b25969fTimo Sirainen int ret;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
90dd3c6ed38f3501fff3cf79ac9fb0478b25969fTimo Sirainen if (fs_file_random_fail_begin(file, FS_OP_METADATA))
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen return -1;
19126597f92e5cdde901ac472090aa423e0e5541Timo Sirainen ret = fs_get_metadata(_file->parent, metadata_r);
90dd3c6ed38f3501fff3cf79ac9fb0478b25969fTimo Sirainen return fs_file_random_fail_end(file, ret, FS_OP_METADATA);
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen}
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainenstatic bool fs_randomfail_prefetch(struct fs_file *_file, uoff_t length)
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen{
90dd3c6ed38f3501fff3cf79ac9fb0478b25969fTimo Sirainen if (fs_random_fail(_file->fs, 1, FS_OP_PREFETCH))
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen return TRUE;
19126597f92e5cdde901ac472090aa423e0e5541Timo Sirainen return fs_prefetch(_file->parent, length);
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen}
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainenstatic ssize_t fs_randomfail_read(struct fs_file *_file, void *buf, size_t size)
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen{
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen struct randomfail_fs_file *file = (struct randomfail_fs_file *)_file;
90dd3c6ed38f3501fff3cf79ac9fb0478b25969fTimo Sirainen int ret;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
90dd3c6ed38f3501fff3cf79ac9fb0478b25969fTimo Sirainen if (fs_file_random_fail_begin(file, FS_OP_READ))
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen return -1;
19126597f92e5cdde901ac472090aa423e0e5541Timo Sirainen ret = fs_read(_file->parent, buf, size);
d7ff3c153fdf39acd70b6883482a0fdbf9d7917fTimo Sirainen if (fs_file_random_fail_end(file, ret < 0 ? -1 : 0, FS_OP_READ) < 0)
d7ff3c153fdf39acd70b6883482a0fdbf9d7917fTimo Sirainen return -1;
d7ff3c153fdf39acd70b6883482a0fdbf9d7917fTimo Sirainen return ret;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen}
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainenstatic struct istream *
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainenfs_randomfail_read_stream(struct fs_file *_file, size_t max_buffer_size)
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen{
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen struct istream *input, *input2;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen uoff_t offset;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
19126597f92e5cdde901ac472090aa423e0e5541Timo Sirainen input = fs_read_stream(_file->parent, max_buffer_size);
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen if (!fs_random_fail_range(_file->fs, FS_OP_READ, &offset))
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen return input;
a4985564b81d51caaddd38376792432428fd449bStephan Bosch input2 = i_stream_create_failure_at(input, offset, EIO, RANDOMFAIL_ERROR);
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen i_stream_unref(&input);
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen return input2;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen}
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainenstatic int fs_randomfail_write(struct fs_file *_file, const void *data, size_t size)
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen{
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen struct randomfail_fs_file *file = (struct randomfail_fs_file *)_file;
90dd3c6ed38f3501fff3cf79ac9fb0478b25969fTimo Sirainen int ret;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
90dd3c6ed38f3501fff3cf79ac9fb0478b25969fTimo Sirainen if (fs_file_random_fail_begin(file, FS_OP_WRITE))
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen return -1;
19126597f92e5cdde901ac472090aa423e0e5541Timo Sirainen ret = fs_write(_file->parent, data, size);
90dd3c6ed38f3501fff3cf79ac9fb0478b25969fTimo Sirainen return fs_file_random_fail_end(file, ret, FS_OP_EXISTS);
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen}
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainenstatic void fs_randomfail_write_stream(struct fs_file *_file)
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen{
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen struct randomfail_fs_file *file = (struct randomfail_fs_file *)_file;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen uoff_t offset;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen i_assert(_file->output == NULL);
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
19126597f92e5cdde901ac472090aa423e0e5541Timo Sirainen file->super_output = fs_write_stream(_file->parent);
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen if (!fs_random_fail_range(_file->fs, FS_OP_WRITE, &offset))
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen _file->output = file->super_output;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen else {
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen _file->output = o_stream_create_failure_at(file->super_output, offset,
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen RANDOMFAIL_ERROR);
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen }
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen}
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainenstatic int fs_randomfail_write_stream_finish(struct fs_file *_file, bool success)
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen{
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen struct randomfail_fs_file *file = (struct randomfail_fs_file *)_file;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen if (_file->output != NULL) {
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen if (_file->output == file->super_output)
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen _file->output = NULL;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen else
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen o_stream_unref(&_file->output);
72e25ec1e51eeeaf038584835171fcad0203497fTimo Sirainen if (!success) {
b8f4e3aa58caa7ee16cf21a21f92521bf05cbdc4Aki Tuomi fs_write_stream_abort_parent(_file, &file->super_output);
72e25ec1e51eeeaf038584835171fcad0203497fTimo Sirainen return -1;
72e25ec1e51eeeaf038584835171fcad0203497fTimo Sirainen }
ba1b959d6bd83a0e3d6a3f927844543376019eacTimo Sirainen if (fs_random_fail(_file->fs, 1, FS_OP_WRITE)) {
19126597f92e5cdde901ac472090aa423e0e5541Timo Sirainen fs_write_stream_abort_error(_file->parent, &file->super_output, RANDOMFAIL_ERROR);
90dd3c6ed38f3501fff3cf79ac9fb0478b25969fTimo Sirainen return -1;
90dd3c6ed38f3501fff3cf79ac9fb0478b25969fTimo Sirainen }
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen }
19126597f92e5cdde901ac472090aa423e0e5541Timo Sirainen return fs_write_stream_finish(_file->parent, &file->super_output);
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen}
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainenstatic int
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainenfs_randomfail_lock(struct fs_file *_file, unsigned int secs, struct fs_lock **lock_r)
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen{
90dd3c6ed38f3501fff3cf79ac9fb0478b25969fTimo Sirainen if (fs_random_fail(_file->fs, 1, FS_OP_LOCK))
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen return -1;
19126597f92e5cdde901ac472090aa423e0e5541Timo Sirainen return fs_lock(_file->parent, secs, lock_r);
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen}
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainenstatic void fs_randomfail_unlock(struct fs_lock *_lock ATTR_UNUSED)
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen{
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen i_unreached();
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen}
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainenstatic int fs_randomfail_exists(struct fs_file *_file)
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen{
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen struct randomfail_fs_file *file = (struct randomfail_fs_file *)_file;
90dd3c6ed38f3501fff3cf79ac9fb0478b25969fTimo Sirainen int ret;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
90dd3c6ed38f3501fff3cf79ac9fb0478b25969fTimo Sirainen if (fs_file_random_fail_begin(file, FS_OP_EXISTS))
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen return -1;
19126597f92e5cdde901ac472090aa423e0e5541Timo Sirainen ret = fs_exists(_file->parent);
90dd3c6ed38f3501fff3cf79ac9fb0478b25969fTimo Sirainen return fs_file_random_fail_end(file, ret, FS_OP_EXISTS);
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen}
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainenstatic int fs_randomfail_stat(struct fs_file *_file, struct stat *st_r)
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen{
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen struct randomfail_fs_file *file = (struct randomfail_fs_file *)_file;
90dd3c6ed38f3501fff3cf79ac9fb0478b25969fTimo Sirainen int ret;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
90dd3c6ed38f3501fff3cf79ac9fb0478b25969fTimo Sirainen if (fs_file_random_fail_begin(file, FS_OP_STAT))
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen return -1;
19126597f92e5cdde901ac472090aa423e0e5541Timo Sirainen ret = fs_stat(_file->parent, st_r);
90dd3c6ed38f3501fff3cf79ac9fb0478b25969fTimo Sirainen return fs_file_random_fail_end(file, ret, FS_OP_STAT);
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen}
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
a63cd84128875485e40ed804dbf0b0945526989cTimo Sirainenstatic int fs_randomfail_get_nlinks(struct fs_file *_file, nlink_t *nlinks_r)
a63cd84128875485e40ed804dbf0b0945526989cTimo Sirainen{
a63cd84128875485e40ed804dbf0b0945526989cTimo Sirainen struct randomfail_fs_file *file = (struct randomfail_fs_file *)_file;
a63cd84128875485e40ed804dbf0b0945526989cTimo Sirainen int ret;
a63cd84128875485e40ed804dbf0b0945526989cTimo Sirainen
a63cd84128875485e40ed804dbf0b0945526989cTimo Sirainen if (fs_file_random_fail_begin(file, FS_OP_STAT))
a63cd84128875485e40ed804dbf0b0945526989cTimo Sirainen return -1;
19126597f92e5cdde901ac472090aa423e0e5541Timo Sirainen ret = fs_get_nlinks(_file->parent, nlinks_r);
a63cd84128875485e40ed804dbf0b0945526989cTimo Sirainen return fs_file_random_fail_end(file, ret, FS_OP_STAT);
a63cd84128875485e40ed804dbf0b0945526989cTimo Sirainen}
a63cd84128875485e40ed804dbf0b0945526989cTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainenstatic int fs_randomfail_copy(struct fs_file *_src, struct fs_file *_dest)
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen{
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen struct randomfail_fs_file *dest = (struct randomfail_fs_file *)_dest;
90dd3c6ed38f3501fff3cf79ac9fb0478b25969fTimo Sirainen int ret;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
90dd3c6ed38f3501fff3cf79ac9fb0478b25969fTimo Sirainen if (fs_file_random_fail_begin(dest, FS_OP_COPY))
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen return -1;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen if (_src != NULL)
19126597f92e5cdde901ac472090aa423e0e5541Timo Sirainen ret = fs_copy(_src->parent, _dest->parent);
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen else
19126597f92e5cdde901ac472090aa423e0e5541Timo Sirainen ret = fs_copy_finish_async(_dest->parent);
90dd3c6ed38f3501fff3cf79ac9fb0478b25969fTimo Sirainen return fs_file_random_fail_end(dest, ret, FS_OP_COPY);
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen}
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainenstatic int fs_randomfail_rename(struct fs_file *_src, struct fs_file *_dest)
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen{
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen struct randomfail_fs_file *dest = (struct randomfail_fs_file *)_dest;
90dd3c6ed38f3501fff3cf79ac9fb0478b25969fTimo Sirainen int ret;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
90dd3c6ed38f3501fff3cf79ac9fb0478b25969fTimo Sirainen if (fs_file_random_fail_begin(dest, FS_OP_RENAME))
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen return -1;
19126597f92e5cdde901ac472090aa423e0e5541Timo Sirainen ret = fs_rename(_src->parent, _dest->parent);
90dd3c6ed38f3501fff3cf79ac9fb0478b25969fTimo Sirainen return fs_file_random_fail_end(dest, ret, FS_OP_RENAME);
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen}
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainenstatic int fs_randomfail_delete(struct fs_file *_file)
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen{
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen struct randomfail_fs_file *file = (struct randomfail_fs_file *)_file;
90dd3c6ed38f3501fff3cf79ac9fb0478b25969fTimo Sirainen int ret;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
90dd3c6ed38f3501fff3cf79ac9fb0478b25969fTimo Sirainen if (fs_file_random_fail_begin(file, FS_OP_DELETE))
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen return -1;
19126597f92e5cdde901ac472090aa423e0e5541Timo Sirainen ret = fs_delete(_file->parent);
90dd3c6ed38f3501fff3cf79ac9fb0478b25969fTimo Sirainen return fs_file_random_fail_end(file, ret, FS_OP_DELETE);
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen}
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
4d71d712b42285afbd2a997f3408142ef0d5f899Timo Sirainenstatic struct fs_iter *fs_randomfail_iter_alloc(void)
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen{
4d71d712b42285afbd2a997f3408142ef0d5f899Timo Sirainen struct randomfail_fs_iter *iter = i_new(struct randomfail_fs_iter, 1);
4d71d712b42285afbd2a997f3408142ef0d5f899Timo Sirainen return &iter->iter;
4d71d712b42285afbd2a997f3408142ef0d5f899Timo Sirainen}
4d71d712b42285afbd2a997f3408142ef0d5f899Timo Sirainen
4d71d712b42285afbd2a997f3408142ef0d5f899Timo Sirainenstatic void
4d71d712b42285afbd2a997f3408142ef0d5f899Timo Sirainenfs_randomfail_iter_init(struct fs_iter *_iter, const char *path,
4d71d712b42285afbd2a997f3408142ef0d5f899Timo Sirainen enum fs_iter_flags flags)
4d71d712b42285afbd2a997f3408142ef0d5f899Timo Sirainen{
4d71d712b42285afbd2a997f3408142ef0d5f899Timo Sirainen struct randomfail_fs_iter *iter = (struct randomfail_fs_iter *)_iter;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen uoff_t pos;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
6d1218e68ce883735ffde9d7907e626ab81b9fb5Timo Sirainen iter->super = fs_iter_init_parent(_iter, path, flags);
4d71d712b42285afbd2a997f3408142ef0d5f899Timo Sirainen if (fs_random_fail_range(_iter->fs, FS_OP_ITER, &pos))
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen iter->fail_pos = pos + 1;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen}
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainenstatic const char *fs_randomfail_iter_next(struct fs_iter *_iter)
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen{
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen struct randomfail_fs_iter *iter = (struct randomfail_fs_iter *)_iter;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen const char *fname;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen if (iter->fail_pos > 0) {
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen if (iter->fail_pos == 1)
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen return NULL;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen iter->fail_pos--;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen }
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen iter->super->async_callback = _iter->async_callback;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen iter->super->async_context = _iter->async_context;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen fname = fs_iter_next(iter->super);
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen _iter->async_have_more = iter->super->async_have_more;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen return fname;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen}
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainenstatic int fs_randomfail_iter_deinit(struct fs_iter *_iter)
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen{
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen struct randomfail_fs_iter *iter = (struct randomfail_fs_iter *)_iter;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen int ret;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen ret = fs_iter_deinit(&iter->super);
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen if (iter->fail_pos == 1) {
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen fs_set_error(_iter->fs, RANDOMFAIL_ERROR);
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen errno = EIO;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen ret = -1;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen }
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen i_free(iter);
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen return ret;
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen}
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainenconst struct fs fs_class_randomfail = {
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen .name = "randomfail",
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen .v = {
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen fs_randomfail_alloc,
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen fs_randomfail_init,
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen fs_randomfail_deinit,
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen fs_randomfail_get_properties,
86ad48a2e740bd63a9b7299d7f3e229831d9b303Timo Sirainen fs_randomfail_file_alloc,
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen fs_randomfail_file_init,
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen fs_randomfail_file_deinit,
19126597f92e5cdde901ac472090aa423e0e5541Timo Sirainen fs_wrapper_file_close,
19126597f92e5cdde901ac472090aa423e0e5541Timo Sirainen fs_wrapper_file_get_path,
19126597f92e5cdde901ac472090aa423e0e5541Timo Sirainen fs_wrapper_set_async_callback,
19126597f92e5cdde901ac472090aa423e0e5541Timo Sirainen fs_wrapper_wait_async,
19126597f92e5cdde901ac472090aa423e0e5541Timo Sirainen fs_wrapper_set_metadata,
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen fs_randomfail_get_metadata,
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen fs_randomfail_prefetch,
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen fs_randomfail_read,
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen fs_randomfail_read_stream,
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen fs_randomfail_write,
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen fs_randomfail_write_stream,
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen fs_randomfail_write_stream_finish,
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen fs_randomfail_lock,
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen fs_randomfail_unlock,
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen fs_randomfail_exists,
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen fs_randomfail_stat,
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen fs_randomfail_copy,
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen fs_randomfail_rename,
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen fs_randomfail_delete,
4d71d712b42285afbd2a997f3408142ef0d5f899Timo Sirainen fs_randomfail_iter_alloc,
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen fs_randomfail_iter_init,
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen fs_randomfail_iter_next,
8296531314913c7f9d4ab1857c6f79ff1308a12fTimo Sirainen fs_randomfail_iter_deinit,
a63cd84128875485e40ed804dbf0b0945526989cTimo Sirainen NULL,
a63cd84128875485e40ed804dbf0b0945526989cTimo Sirainen fs_randomfail_get_nlinks,
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen }
5a441a6d97225cbdc67dad7bdd80de3c7bfedaabTimo Sirainen};