bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2010-2018 Dovecot authors, see the included COPYING file */
ea19bfdfc2205af178a70915054c809ed2b8709eTimo Sirainenstruct fs_api_module_register fs_api_module_register = { 0 };
60eda49183dbec5f3d5ec18b38433581e28e2ebaTimo Sirainenstatic void fs_classes_init(void);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenfs_alloc(const struct fs *fs_class, const char *args,
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen const struct fs_settings *set, struct fs **fs_r, const char **error_r)
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen /* a bit kludgy way to allow data stack frame usage in normal
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen conditions but still be able to return error message from
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen data stack. */
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen *error_r = t_strdup_printf("%s: %s", fs_class->name,
60eda49183dbec5f3d5ec18b38433581e28e2ebaTimo Sirainenvoid fs_class_register(const struct fs *fs_class)
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainenstatic const struct fs *fs_class_find(const char *driver)
0bf2d5782f1637e6816efa82865ca7eacbadd20cTimo Sirainenstatic const char *fs_driver_module_name(const char *driver)
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainenstatic void fs_class_try_load_plugin(const char *driver)
0bf2d5782f1637e6816efa82865ca7eacbadd20cTimo Sirainen t_strdup_printf("fs_%s", fs_driver_module_name(driver));
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen fs_modules = module_dir_load_missing(fs_modules, MODULE_DIR,
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen module = module_dir_find(fs_modules, module_name);
0bf2d5782f1637e6816efa82865ca7eacbadd20cTimo Sirainen "fs_class_%s", fs_driver_module_name(driver)));
fc59aba4be5d2f57908e84f0f7477c467a72d567Timo Sirainenstatic struct event *fs_create_event(struct fs *fs, struct event *parent)
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainenint fs_init(const char *driver, const char *args,
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainen *error_r = t_strdup_printf("Unknown fs driver: %s", driver);
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen if (fs_alloc(fs_class, args, set, fs_r, error_r) < 0)
fc59aba4be5d2f57908e84f0f7477c467a72d567Timo Sirainen (*fs_r)->event = fs_create_event(*fs_r, set->event);
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen temp_file_prefix = set->temp_file_prefix != NULL ?
3927a2114ac30fcc747741dc08151fe70e400463Baofeng Wang (*fs_r)->temp_path_prefix = i_strconcat("/tmp/",
3927a2114ac30fcc747741dc08151fe70e400463Baofeng Wang (*fs_r)->temp_path_prefix = i_strconcat(set->temp_dir, "/",
c69b62e5d86e153dfbbfcb99d115f34a25902908Aki Tuomiint fs_init_from_string(const char *str, const struct fs_settings *set,
ea19bfdfc2205af178a70915054c809ed2b8709eTimo Sirainen struct array module_contexts_arr = fs->module_contexts.arr;
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen unsigned int i;
92093e6d8bdddeac59e169bcde6d0080a17e66efTimo Sirainen i_panic("fs-%s: %u files still open (first = %s)",
92093e6d8bdddeac59e169bcde6d0080a17e66efTimo Sirainen fs->name, fs->files_open_count, fs_file_path(fs->files));
46e5bbded013e2bc415e8277a0d937b59ca59785Timo Sirainen for (i = 0; i < FS_OP_COUNT; i++) {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenstruct fs_file *fs_file_init(struct fs *fs, const char *path, int mode_flags)
fc59aba4be5d2f57908e84f0f7477c467a72d567Timo Sirainen return fs_file_init_with_event(fs, fs->event, path, mode_flags);
fc59aba4be5d2f57908e84f0f7477c467a72d567Timo Sirainenstruct fs_file *fs_file_init_with_event(struct fs *fs, struct event *event,
60fe2f162e61eae1c2821bf9705c7ff7987c8adeTimo Sirainen i_assert((mode_flags & FS_OPEN_FLAG_ASYNC_NOQUEUE) == 0 ||
86ad48a2e740bd63a9b7299d7f3e229831d9b303Timo Sirainen file->flags = mode_flags & ~FS_OPEN_MODE_MASK;
86ad48a2e740bd63a9b7299d7f3e229831d9b303Timo Sirainen fs->v.file_init(file, path, mode_flags & FS_OPEN_MODE_MASK,
15fa038377f9e3da24d088aa8a908919581c60a6Timo Sirainen fs_set_metadata(file, FS_METADATA_ORIG_PATH, path);
6d035effc27b2556393e6b26fbe1a846741cdb8eAki Tuomi fs_write_stream_abort_error(file, &file->copy_output, "fs_file_close(%s)",
0ee52dafcc5b25c031e289d1d65ecccc859ebd3cTimo Sirainen /* check this only after closing, because some of the fs backends keep
0ee52dafcc5b25c031e289d1d65ecccc859ebd3cTimo Sirainen the istream internally open and don't call the destroy-callback
0ee52dafcc5b25c031e289d1d65ecccc859ebd3cTimo Sirainen until after file_close() */
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenenum fs_properties fs_get_properties(struct fs *fs)
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen file->metadata_pool = pool_alloconly_create("fs metadata", 1024);
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen p_array_init(&file->metadata, file->metadata_pool, 8);
185f63aeffefe857e823bc4eeaea53898f574d57Timo Sirainenvoid fs_metadata_init_or_clear(struct fs_file *file)
185f63aeffefe857e823bc4eeaea53898f574d57Timo Sirainen if (strncmp(md->key, FS_METADATA_INTERNAL_PREFIX,
185f63aeffefe857e823bc4eeaea53898f574d57Timo Sirainen array_append_array(&file->metadata, &internal_metadata);
8f900bf5b01a78ac9be748e7502aad7cf3486420Timo Sirainenstatic struct fs_metadata *
8f900bf5b01a78ac9be748e7502aad7cf3486420Timo Sirainenfs_metadata_find_md(const ARRAY_TYPE(fs_metadata) *metadata,
8f900bf5b01a78ac9be748e7502aad7cf3486420Timo Sirainen const char *key)
84669c712403b742cc07ae70229725c486ef1235Timo Sirainenvoid fs_default_set_metadata(struct fs_file *file,
8f900bf5b01a78ac9be748e7502aad7cf3486420Timo Sirainen metadata = fs_metadata_find_md(&file->metadata, key);
8f900bf5b01a78ac9be748e7502aad7cf3486420Timo Sirainen metadata = array_append_space(&file->metadata);
8f900bf5b01a78ac9be748e7502aad7cf3486420Timo Sirainen metadata->key = p_strdup(file->metadata_pool, key);
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen metadata->value = p_strdup(file->metadata_pool, value);
5b302b077a61204beb6852b89927952840458ccbTimo Sirainenconst char *fs_metadata_find(const ARRAY_TYPE(fs_metadata) *metadata,
5b302b077a61204beb6852b89927952840458ccbTimo Sirainen const char *key)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenvoid fs_set_metadata(struct fs_file *file, const char *key, const char *value)
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen if (file->fs->v.set_metadata != NULL) T_BEGIN {
4c649f0338c2031afdd62a503c336e3f74bc9954Timo Sirainen /* internal metadata change, which isn't stored. */
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainenstatic void fs_file_timing_start(struct fs_file *file, enum fs_op op)
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen if (gettimeofday(&file->timing_start[op], NULL) < 0)
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainenfs_timing_end(struct stats_dist **timing, const struct timeval *start_tv)
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainenvoid fs_file_timing_end(struct fs_file *file, enum fs_op op)
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen if (!file->fs->set.enable_timing || file->timing_start[op].tv_sec == 0)
46e5bbded013e2bc415e8277a0d937b59ca59785Timo Sirainen fs_timing_end(&file->fs->stats.timings[op], &file->timing_start[op]);
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen /* don't count this again */
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_set_error(file->fs, "Metadata not supported by backend");
5e9e9f07ba5177d4208581b77434ec6368cdaa8aTimo Sirainen ret = file->fs->v.get_metadata(file, metadata_r);
9a1ab9488c75f8a68871d0fcdff4e0d0e3543299Timo Sirainenint fs_lookup_metadata(struct fs_file *file, const char *key,
9a1ab9488c75f8a68871d0fcdff4e0d0e3543299Timo Sirainen const char **value_r)
3dcb9fd82c1edd40bea1ad572ed39f024686e463Timo Sirainen return file->fs->v.get_path == NULL ? file->path :
fc59aba4be5d2f57908e84f0f7477c467a72d567Timo Sirainenstruct event *fs_file_event(struct fs_file *file)
c4e3c997c04eb6f93f782c5fa53354390ed07a02Timo Sirainenfs_set_verror(struct fs *fs, const char *fmt, va_list args)
c4e3c997c04eb6f93f782c5fa53354390ed07a02Timo Sirainen /* the error is always kept in the parentmost fs */
c4e3c997c04eb6f93f782c5fa53354390ed07a02Timo Sirainen /* the error is always kept in the parentmost fs */
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return "BUG: Unknown fs error";
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenconst char *fs_file_last_error(struct fs_file *file)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenbool fs_prefetch(struct fs_file *file, uoff_t length)
84669c712403b742cc07ae70229725c486ef1235Timo Sirainenssize_t fs_read_via_stream(struct fs_file *file, void *buf, size_t size)
251457b81928bab1ad25193e8a09bda829abe9eeTimo Sirainen file->pending_read_input = fs_read_stream(file, size+1);
573424407a2d3c1453638a643583a7cf10c129e1Phil Carmody ret = i_stream_read_bytes(file->pending_read_input, &data,
251457b81928bab1ad25193e8a09bda829abe9eeTimo Sirainen if (ret < 0 && file->pending_read_input->stream_errno != 0) {
46453c751e7714dbe2b57752b34b5a3427375ccfTimo Sirainen i_stream_get_error(file->pending_read_input));
84669c712403b742cc07ae70229725c486ef1235Timo Sirainenssize_t fs_read(struct fs_file *file, void *buf, size_t size)
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen /* backend didn't bother to implement read(), but we can do it with
0ee52dafcc5b25c031e289d1d65ecccc859ebd3cTimo Sirainenstatic void fs_file_istream_destroyed(struct fs_file *file)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstruct istream *fs_read_stream(struct fs_file *file, size_t max_buffer_size)
db5d7fbdb3eaf8b588633f874190aa34363e5597Timo Sirainen /* allow multiple open streams, each in a different position */
db5d7fbdb3eaf8b588633f874190aa34363e5597Timo Sirainen input = i_stream_create_limit(file->seekable_input, (uoff_t)-1);
e062a4b1f8d94929f6fb9e6d27acfddf50439437Timo Sirainen input = file->fs->v.read_stream(file, max_buffer_size);
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen /* read failed already */
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen struct istream *input2 = i_stream_create_fs_stats(input, file);
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen if ((file->flags & FS_OPEN_FLAG_SEEKABLE) != 0)
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen else if ((file->flags & FS_OPEN_FLAG_ASYNC) == 0 && !input->blocking)
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen /* need to make the stream seekable */
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen input = i_stream_create_seekable_path(inputs, max_buffer_size,
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen i_stream_set_name(input, i_stream_get_name(inputs[0]));
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen if ((file->flags & FS_OPEN_FLAG_ASYNC) == 0 && !input->blocking) {
a06af8e117e14e2ddc5835bcbe0d2f0370cbc0a1Timo Sirainen /* read the whole input stream before returning */
3858a7a5da361c35f1e6e50c8e3214dc0cf379d6Phil Carmody while ((ret = i_stream_read_more(input, &data, &size)) >= 0) {
0ee52dafcc5b25c031e289d1d65ecccc859ebd3cTimo Sirainen i_stream_add_destroy_callback(input, fs_file_istream_destroyed, file);
84669c712403b742cc07ae70229725c486ef1235Timo Sirainenint fs_write_via_stream(struct fs_file *file, const void *data, size_t size)
0fb5804c1c6023fecccd979fdb25d2affda934a4Timo Sirainen if ((ret = o_stream_send(output, data, size)) < 0) {
be6fab2b1eded6b57d6688c6aa5a7c784f943865Aki Tuomi fs_write_stream_abort_error(file, &output, "fs_write(%s) failed: %s",
84669c712403b742cc07ae70229725c486ef1235Timo Sirainenint fs_write(struct fs_file *file, const void *data, size_t size)
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen /* backend didn't bother to implement write(), but we can do it with
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstruct ostream *fs_write_stream(struct fs_file *file)
825e349a826ee2a984069edf394460bed5bc3426Timo Sirainenstatic int fs_write_stream_finish_int(struct fs_file *file, bool success)
825e349a826ee2a984069edf394460bed5bc3426Timo Sirainen ret = file->fs->v.write_stream_finish(file, success);
825e349a826ee2a984069edf394460bed5bc3426Timo Sirainen /* write didn't finish yet. this shouldn't happen if we
825e349a826ee2a984069edf394460bed5bc3426Timo Sirainen indicated a failure. */
825e349a826ee2a984069edf394460bed5bc3426Timo Sirainenint fs_write_stream_finish(struct fs_file *file, struct ostream **output)
f6754d90ea6bbe1386eb4d39f603cf01edde4ef1Timo Sirainen i_assert(*output == file->output || *output == NULL);
ad9afb64630511d5e25bc5bc11c5304986156928Timo Sirainen if ((ret = o_stream_finish(file->output)) <= 0) {
4244105be4eee427a90983d17070b438f6e2cdecTimo Sirainen fs_set_error(file->fs, "write(%s) failed: %s",
507dcd9fee9b8f032a60af3ea35de4da0e5653c9Timo Sirainen file->fs->stats.write_bytes += file->output->offset;
825e349a826ee2a984069edf394460bed5bc3426Timo Sirainen return fs_write_stream_finish_int(file, success);
ba886767d3817d210b20e1d42983078d189fb13cTimo Sirainenint fs_write_stream_finish_async(struct fs_file *file)
825e349a826ee2a984069edf394460bed5bc3426Timo Sirainen return fs_write_stream_finish_int(file, TRUE);
0c1f911643fd8542fb488bfe23a54000372cde80Aki Tuomistatic void fs_write_stream_abort(struct fs_file *file, struct ostream **output)
eaac2584903d75da935eeee5098a7baa904f1afdTimo Sirainen /* make sure we don't have an old error lying around */
a0cf7d3924dec409e6eadaf3237fcecd4194ec75Timo Sirainen ret = fs_write_stream_finish_int(file, FALSE);
0c1f911643fd8542fb488bfe23a54000372cde80Aki Tuomivoid fs_write_stream_abort_error(struct fs_file *file, struct ostream **output, const char *error_fmt, ...)
0c1f911643fd8542fb488bfe23a54000372cde80Aki Tuomivoid fs_write_stream_abort_parent(struct fs_file *file, struct ostream **output)
72e25ec1e51eeeaf038584835171fcad0203497fTimo Sirainen i_assert(fs_file_last_error(file->parent) != NULL);
67a163f3a07593446fab1cbbb8f92a89d4c6cb57Timo Sirainenvoid fs_write_set_hash(struct fs_file *file, const struct hash_method *method,
67a163f3a07593446fab1cbbb8f92a89d4c6cb57Timo Sirainen file->write_digest = i_malloc(method->digest_size);
67a163f3a07593446fab1cbbb8f92a89d4c6cb57Timo Sirainen memcpy(file->write_digest, digest, method->digest_size);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenvoid fs_file_set_async_callback(struct fs_file *file,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen file->fs->v.set_async_callback(file, callback, context);
5804ddddad82319839785885fdacbba60e0c9581Timo Sirainen /* recursion not allowed */
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenint fs_lock(struct fs_file *file, unsigned int secs, struct fs_lock **lock_r)
b6ecc96ac80d70e25a5e83d14383e2b8e17d29ddTimo Sirainen /* fallback to stat() */
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenint fs_stat(struct fs_file *file, struct stat *st_r)
741a7e61d484bcc975b4d47a51548ac76334e1c1Timo Sirainen fs_set_error(file->fs, "fs_stat() not supported");
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen !file->lookup_metadata_counted && !file->stat_counted) {
a63cd84128875485e40ed804dbf0b0945526989cTimo Sirainenint fs_get_nlinks(struct fs_file *file, nlink_t *nlinks_r)
a63cd84128875485e40ed804dbf0b0945526989cTimo Sirainen !file->lookup_metadata_counted && !file->stat_counted) {
84669c712403b742cc07ae70229725c486ef1235Timo Sirainenint fs_default_copy(struct fs_file *src, struct fs_file *dest)
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen /* we're going to be counting this as read+write, so remove the
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainen copy_count we just added */
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen i_assert(src == NULL || src == dest->copy_src);
84669c712403b742cc07ae70229725c486ef1235Timo Sirainen dest->copy_input = fs_read_stream(src, IO_BLOCK_SIZE);
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen switch (o_stream_send_istream(dest->copy_output, dest->copy_input)) {
be6fab2b1eded6b57d6688c6aa5a7c784f943865Aki Tuomi fs_write_stream_abort_error(dest, &dest->copy_output,
be6fab2b1eded6b57d6688c6aa5a7c784f943865Aki Tuomi "read(%s) failed: %s",
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen case OSTREAM_SEND_ISTREAM_RESULT_ERROR_OUTPUT:
fdef08644ba66b9db8fe4fc041ecc31a1ec9524bAki Tuomi /* errno might not survive abort error */
be6fab2b1eded6b57d6688c6aa5a7c784f943865Aki Tuomi fs_write_stream_abort_error(dest, &dest->copy_output,
be6fab2b1eded6b57d6688c6aa5a7c784f943865Aki Tuomi "write(%s) failed: %s",
3010259e7834bdad8cb77e8bcbb9fc5c700897a2Timo Sirainen if (fs_write_stream_finish(dest, &dest->copy_output) <= 0)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenint fs_copy(struct fs_file *src, struct fs_file *dest)
741a7e61d484bcc975b4d47a51548ac76334e1c1Timo Sirainen fs_set_error(src->fs, "fs_copy() not supported");
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenint fs_rename(struct fs_file *src, struct fs_file *dest)
63e94e8f57920b510fcdc479c5482ba9f4337a5cTimo Sirainenfs_iter_init(struct fs *fs, const char *path, enum fs_iter_flags flags)
fc59aba4be5d2f57908e84f0f7477c467a72d567Timo Sirainen return fs_iter_init_with_event(fs, fs->event, path, flags);
fc59aba4be5d2f57908e84f0f7477c467a72d567Timo Sirainenfs_iter_init_with_event(struct fs *fs, struct event *event,
8656b625c110d849ece2d040d7880eec20058694Timo Sirainen i_assert((flags & FS_ITER_FLAG_OBJECTIDS) == 0 ||
8656b625c110d849ece2d040d7880eec20058694Timo Sirainen (fs_get_properties(fs) & FS_PROPERTY_OBJECTIDS) != 0);
7603577788c59274c81dd9e4f6661dfdb5f87f4fAki Tuomi fs_set_error(iter->fs, "FS iteration not supported");
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen /* first result returned - count this as the finish time, since
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen we don't want to count the time caller spends on this
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen iteration. */
46e5bbded013e2bc415e8277a0d937b59ca59785Timo Sirainen fs_timing_end(&iter->fs->stats.timings[FS_OP_ITER], &iter->start_time);
1c244f6fdbb509cca857982368f5d426e999f2d1Timo Sirainen /* don't count this again */
9c45f33d0e0ca0b8f87f9a3318dd505a78fd198eTimo Sirainenvoid fs_iter_set_async_callback(struct fs_iter *iter,
302167a8a77cf3597f0b33e644a1805aa3313a8cTimo Sirainenconst struct fs_stats *fs_get_stats(struct fs *fs)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenvoid fs_set_error(struct fs *fs, const char *fmt, ...)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenvoid fs_set_critical(struct fs *fs, const char *fmt, ...)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_set_error(fs, "Asynchronous operation in progress");
46e5bbded013e2bc415e8277a0d937b59ca59785Timo Sirainenfs_stats_count_ops(const struct fs_stats *stats, const enum fs_op ops[],
46e5bbded013e2bc415e8277a0d937b59ca59785Timo Sirainen for (unsigned int i = 0; i < ops_count; i++) {
5f08b0309190ec818d46bfe0e497468b30714a93Timo Sirainen ret += stats_dist_get_sum(stats->timings[ops[i]]);
3d2d3501736ff917f2de8a38f253c741c6f84e1eTimo Sirainenuint64_t fs_stats_get_read_usecs(const struct fs_stats *stats)
46e5bbded013e2bc415e8277a0d937b59ca59785Timo Sirainen FS_OP_METADATA, FS_OP_PREFETCH, FS_OP_READ, FS_OP_EXISTS,
46e5bbded013e2bc415e8277a0d937b59ca59785Timo Sirainen return fs_stats_count_ops(stats, read_ops, N_ELEMENTS(read_ops));
3d2d3501736ff917f2de8a38f253c741c6f84e1eTimo Sirainenuint64_t fs_stats_get_write_usecs(const struct fs_stats *stats)
46e5bbded013e2bc415e8277a0d937b59ca59785Timo Sirainen return fs_stats_count_ops(stats, write_ops, N_ELEMENTS(write_ops));
6d1218e68ce883735ffde9d7907e626ab81b9fb5Timo Sirainenfs_file_init_parent(struct fs_file *parent, const char *path, int mode_flags)
fc59aba4be5d2f57908e84f0f7477c467a72d567Timo Sirainen return fs_file_init_with_event(parent->fs->parent, parent->event,