Commit | Line | Data |
---|---|---|
e615ceaf DM |
1 | /* |
2 | * falloc: ioengine for git://git.kernel.dk/fio.git | |
3 | * | |
4 | * IO engine that does regular fallocate to simulate data transfer | |
5 | * as fio ioengine. | |
6 | * DDIR_READ does fallocate(,mode = FALLOC_FL_KEEP_SIZE,) | |
7 | * DDIR_WRITE does fallocate(,mode = 0) : fallocate with size extention | |
8 | * DDIR_TRIM does fallocate(,mode = FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE) | |
9 | * | |
10 | */ | |
11 | #include <stdio.h> | |
12 | #include <stdlib.h> | |
13 | #include <unistd.h> | |
14 | #include <sys/uio.h> | |
15 | #include <errno.h> | |
16 | #include <assert.h> | |
17 | #include <fcntl.h> | |
18 | ||
19 | #include "../fio.h" | |
20 | #include "../filehash.h" | |
21 | ||
22 | /* | |
23 | * generic_open_file is not appropriate because does not allow to perform | |
24 | * TRIM in to file | |
25 | */ | |
26 | int open_file(struct thread_data *td, struct fio_file *f) | |
27 | { | |
28 | int from_hash = 0; | |
29 | ||
30 | dprint(FD_FILE, "fd open %s\n", f->file_name); | |
31 | ||
32 | if (f->filetype != FIO_TYPE_FILE) { | |
33 | log_err("fio: only files are supported fallocate \n"); | |
34 | return 1; | |
35 | } | |
36 | if (!strcmp(f->file_name, "-")) { | |
37 | log_err("fio: can't read/write to stdin/out\n"); | |
38 | return 1; | |
39 | } | |
40 | ||
41 | open_again: | |
42 | from_hash = file_lookup_open(f, O_CREAT|O_RDWR); | |
43 | ||
44 | if (f->fd == -1) { | |
45 | char buf[FIO_VERROR_SIZE]; | |
46 | int __e = errno; | |
47 | snprintf(buf, sizeof(buf) - 1, "open(%s)", f->file_name); | |
48 | td_verror(td, __e, buf); | |
49 | } | |
50 | ||
51 | if (!from_hash && f->fd != -1) { | |
52 | if (add_file_hash(f)) { | |
53 | int fio_unused ret; | |
54 | ||
55 | /* | |
56 | * OK to ignore, we haven't done anything with it | |
57 | */ | |
58 | ret = generic_close_file(td, f); | |
59 | goto open_again; | |
60 | } | |
61 | } | |
62 | ||
63 | return 0; | |
64 | } | |
65 | ||
66 | #ifndef FALLOC_FL_KEEP_SIZE | |
67 | #define FALLOC_FL_KEEP_SIZE 0x01 /* default is extend size */ | |
68 | #endif | |
69 | #ifndef FALLOC_FL_PUNCH_HOLE | |
70 | #define FALLOC_FL_PUNCH_HOLE 0x02 /* de-allocates range */ | |
71 | #endif | |
72 | static int fio_fallocate_queue(struct thread_data *td, struct io_u *io_u) | |
73 | { | |
74 | struct fio_file *f = io_u->file; | |
75 | int ret; | |
76 | int flags = 0; | |
77 | ||
78 | fio_ro_check(td, io_u); | |
79 | ||
80 | if (io_u->ddir == DDIR_READ) | |
81 | flags = FALLOC_FL_KEEP_SIZE; | |
82 | else if (io_u->ddir == DDIR_WRITE) | |
83 | flags = 0; | |
84 | else if (io_u->ddir == DDIR_TRIM) | |
85 | flags = FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE; | |
86 | ||
87 | ret = fallocate(f->fd, flags, io_u->offset, io_u->xfer_buflen); | |
88 | ||
89 | if (ret) { | |
90 | io_u->error = errno; | |
91 | if (io_u->error) | |
92 | td_verror(td, io_u->error, "xfer"); | |
93 | } | |
e615ceaf DM |
94 | |
95 | if (io_u->file && ret == 0 && ddir_rw(io_u->ddir)) | |
96 | io_u->file->file_pos = io_u->offset + ret; | |
97 | ||
98 | return FIO_Q_COMPLETED; | |
99 | } | |
100 | ||
101 | static struct ioengine_ops ioengine = { | |
102 | .name = "falloc", | |
103 | .version = FIO_IOOPS_VERSION, | |
104 | .queue = fio_fallocate_queue, | |
105 | .open_file = open_file, | |
106 | .close_file = generic_close_file, | |
107 | .get_file_size = generic_get_file_size, | |
108 | .flags = FIO_SYNCIO | |
109 | }; | |
110 | ||
111 | static void fio_init fio_syncio_register(void) | |
112 | { | |
113 | register_ioengine(&ioengine); | |
114 | } | |
115 | ||
116 | static void fio_exit fio_syncio_unregister(void) | |
117 | { | |
118 | unregister_ioengine(&ioengine); | |
119 | } |