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