Commit | Line | Data |
---|---|---|
a7e8aae0 KB |
1 | /* |
2 | * Note: This is similar to a very basic setup | |
3 | * of ZBD devices | |
4 | * | |
5 | * Specify fdp=1 (With char devices /dev/ng0n1) | |
6 | */ | |
7 | ||
8 | #include <errno.h> | |
9 | #include <string.h> | |
10 | #include <stdlib.h> | |
11 | #include <unistd.h> | |
a7e8aae0 | 12 | #include "fio.h" |
7d352b12 | 13 | #include "file.h" |
a7e8aae0 KB |
14 | |
15 | #include "pshared.h" | |
c60d54ae | 16 | #include "dataplacement.h" |
a7e8aae0 KB |
17 | |
18 | static int fdp_ruh_info(struct thread_data *td, struct fio_file *f, | |
19 | struct fio_ruhs_info *ruhs) | |
20 | { | |
21 | int ret = -EINVAL; | |
22 | ||
5a85d6d8 JA |
23 | if (!td->io_ops) { |
24 | log_err("fio: no ops set in fdp init?!\n"); | |
25 | return ret; | |
26 | } | |
27 | ||
28 | if (td->io_ops->fdp_fetch_ruhs) { | |
a7e8aae0 KB |
29 | ret = td->io_ops->fdp_fetch_ruhs(td, f, ruhs); |
30 | if (ret < 0) { | |
31 | td_verror(td, errno, "fdp fetch ruhs failed"); | |
32 | log_err("%s: fdp fetch ruhs failed (%d)\n", | |
33 | f->file_name, errno); | |
34 | } | |
5a85d6d8 | 35 | } else { |
a7e8aae0 KB |
36 | log_err("%s: engine (%s) lacks fetch ruhs\n", |
37 | f->file_name, td->io_ops->name); | |
5a85d6d8 | 38 | } |
a7e8aae0 KB |
39 | |
40 | return ret; | |
41 | } | |
42 | ||
43 | static int init_ruh_info(struct thread_data *td, struct fio_file *f) | |
44 | { | |
45 | struct fio_ruhs_info *ruhs, *tmp; | |
46 | int i, ret; | |
47 | ||
98cd3c0e | 48 | ruhs = scalloc(1, sizeof(*ruhs) + FDP_MAX_RUHS * sizeof(*ruhs->plis)); |
a7e8aae0 KB |
49 | if (!ruhs) |
50 | return -ENOMEM; | |
51 | ||
1a3a21b7 VF |
52 | /* set up the data structure used for FDP to work with the supplied stream IDs */ |
53 | if (td->o.dp_type == FIO_DP_STREAMS) { | |
54 | if (!td->o.dp_nr_ids) { | |
55 | log_err("fio: stream IDs must be provided for dataplacement=streams\n"); | |
56 | return -EINVAL; | |
57 | } | |
58 | ruhs->nr_ruhs = td->o.dp_nr_ids; | |
59 | for (int i = 0; i < ruhs->nr_ruhs; i++) | |
60 | ruhs->plis[i] = td->o.dp_ids[i]; | |
61 | ||
62 | f->ruhs_info = ruhs; | |
63 | return 0; | |
64 | } | |
65 | ||
a7e8aae0 KB |
66 | ret = fdp_ruh_info(td, f, ruhs); |
67 | if (ret) { | |
68 | log_info("fio: ruh info failed for %s (%d)\n", | |
69 | f->file_name, -ret); | |
70 | goto out; | |
71 | } | |
72 | ||
98cd3c0e AK |
73 | if (ruhs->nr_ruhs > FDP_MAX_RUHS) |
74 | ruhs->nr_ruhs = FDP_MAX_RUHS; | |
a7e8aae0 | 75 | |
65ca6791 | 76 | if (td->o.dp_nr_ids == 0) { |
a7e8aae0 KB |
77 | f->ruhs_info = ruhs; |
78 | return 0; | |
79 | } | |
80 | ||
65ca6791 VF |
81 | for (i = 0; i < td->o.dp_nr_ids; i++) { |
82 | if (td->o.dp_ids[i] >= ruhs->nr_ruhs) { | |
a7e8aae0 KB |
83 | ret = -EINVAL; |
84 | goto out; | |
85 | } | |
86 | } | |
87 | ||
88 | tmp = scalloc(1, sizeof(*tmp) + ruhs->nr_ruhs * sizeof(*tmp->plis)); | |
89 | if (!tmp) { | |
90 | ret = -ENOMEM; | |
91 | goto out; | |
92 | } | |
93 | ||
65ca6791 VF |
94 | tmp->nr_ruhs = td->o.dp_nr_ids; |
95 | for (i = 0; i < td->o.dp_nr_ids; i++) | |
96 | tmp->plis[i] = ruhs->plis[td->o.dp_ids[i]]; | |
a7e8aae0 KB |
97 | f->ruhs_info = tmp; |
98 | out: | |
99 | sfree(ruhs); | |
100 | return ret; | |
101 | } | |
102 | ||
04d5add8 HP |
103 | static int init_ruh_scheme(struct thread_data *td, struct fio_file *f) |
104 | { | |
105 | struct fio_ruhs_scheme *ruh_scheme; | |
106 | FILE *scheme_fp; | |
107 | unsigned long long start, end; | |
108 | uint16_t pli; | |
109 | int ret = 0; | |
110 | ||
111 | if (td->o.dp_id_select != FIO_DP_SCHEME) | |
112 | return 0; | |
113 | ||
114 | /* Get the scheme from the file */ | |
115 | scheme_fp = fopen(td->o.dp_scheme_file, "r"); | |
116 | ||
117 | if (!scheme_fp) { | |
118 | log_err("fio: ruh scheme failed to open scheme file %s\n", | |
119 | td->o.dp_scheme_file); | |
120 | ret = -errno; | |
121 | goto out; | |
122 | } | |
123 | ||
124 | ruh_scheme = scalloc(1, sizeof(*ruh_scheme)); | |
125 | if (!ruh_scheme) { | |
126 | ret = -ENOMEM; | |
127 | goto out_with_close_fp; | |
128 | } | |
129 | ||
130 | for (int i = 0; | |
131 | i < DP_MAX_SCHEME_ENTRIES && fscanf(scheme_fp, "%llu,%llu,%hu\n", &start, &end, &pli) == 3; | |
132 | i++) { | |
133 | ||
134 | ruh_scheme->scheme_entries[i].start_offset = start; | |
135 | ruh_scheme->scheme_entries[i].end_offset = end; | |
136 | ruh_scheme->scheme_entries[i].pli = pli; | |
137 | ruh_scheme->nr_schemes++; | |
138 | } | |
139 | ||
140 | if (fscanf(scheme_fp, "%llu,%llu,%hu\n", &start, &end, &pli) == 3) | |
141 | log_info("fio: too many scheme entries in %s. Only the first %d scheme entries are applied\n", | |
142 | td->o.dp_scheme_file, | |
143 | DP_MAX_SCHEME_ENTRIES); | |
144 | ||
145 | f->ruhs_scheme = ruh_scheme; | |
146 | ||
147 | out_with_close_fp: | |
148 | fclose(scheme_fp); | |
149 | out: | |
150 | return ret; | |
151 | } | |
152 | ||
c60d54ae | 153 | int dp_init(struct thread_data *td) |
a7e8aae0 KB |
154 | { |
155 | struct fio_file *f; | |
156 | int i, ret = 0; | |
157 | ||
158 | for_each_file(td, f, i) { | |
159 | ret = init_ruh_info(td, f); | |
160 | if (ret) | |
161 | break; | |
04d5add8 HP |
162 | |
163 | ret = init_ruh_scheme(td, f); | |
164 | if (ret) | |
165 | break; | |
a7e8aae0 KB |
166 | } |
167 | return ret; | |
168 | } | |
169 | ||
170 | void fdp_free_ruhs_info(struct fio_file *f) | |
171 | { | |
172 | if (!f->ruhs_info) | |
173 | return; | |
174 | sfree(f->ruhs_info); | |
175 | f->ruhs_info = NULL; | |
04d5add8 HP |
176 | |
177 | if (!f->ruhs_scheme) | |
178 | return; | |
179 | sfree(f->ruhs_scheme); | |
180 | f->ruhs_scheme = NULL; | |
a7e8aae0 KB |
181 | } |
182 | ||
c60d54ae | 183 | void dp_fill_dspec_data(struct thread_data *td, struct io_u *io_u) |
a7e8aae0 KB |
184 | { |
185 | struct fio_file *f = io_u->file; | |
186 | struct fio_ruhs_info *ruhs = f->ruhs_info; | |
187 | int dspec; | |
188 | ||
189 | if (!ruhs || io_u->ddir != DDIR_WRITE) { | |
190 | io_u->dtype = 0; | |
191 | io_u->dspec = 0; | |
192 | return; | |
193 | } | |
194 | ||
65ca6791 | 195 | if (td->o.dp_id_select == FIO_DP_RR) { |
d3e310c5 AK |
196 | if (ruhs->pli_loc >= ruhs->nr_ruhs) |
197 | ruhs->pli_loc = 0; | |
198 | ||
199 | dspec = ruhs->plis[ruhs->pli_loc++]; | |
04d5add8 HP |
200 | } else if (td->o.dp_id_select == FIO_DP_SCHEME) { |
201 | struct fio_ruhs_scheme *ruhs_scheme = f->ruhs_scheme; | |
202 | unsigned long long offset = io_u->offset; | |
203 | int i; | |
204 | ||
205 | for (i = 0; i < ruhs_scheme->nr_schemes; i++) { | |
206 | if (offset >= ruhs_scheme->scheme_entries[i].start_offset && | |
207 | offset < ruhs_scheme->scheme_entries[i].end_offset) { | |
208 | dspec = ruhs_scheme->scheme_entries[i].pli; | |
209 | break; | |
210 | } | |
211 | } | |
212 | ||
213 | /* | |
214 | * If the write offset is not affected by any scheme entry, | |
215 | * 0(default RUH) will be assigned to dspec | |
216 | */ | |
217 | if (i == ruhs_scheme->nr_schemes) | |
218 | dspec = 0; | |
d3e310c5 AK |
219 | } else { |
220 | ruhs->pli_loc = rand_between(&td->fdp_state, 0, ruhs->nr_ruhs - 1); | |
221 | dspec = ruhs->plis[ruhs->pli_loc]; | |
222 | } | |
3b3c9877 | 223 | |
1a3a21b7 | 224 | io_u->dtype = td->o.dp_type == FIO_DP_FDP ? FDP_DIR_DTYPE : STREAMS_DIR_DTYPE; |
a7e8aae0 | 225 | io_u->dspec = dspec; |
61d22139 | 226 | dprint(FD_IO, "dtype set to 0x%x, dspec set to 0x%x\n", io_u->dtype, io_u->dspec); |
a7e8aae0 | 227 | } |