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; | |
56d12245 | 46 | uint32_t nr_ruhs; |
a7e8aae0 KB |
47 | int i, ret; |
48 | ||
1a3a21b7 VF |
49 | /* set up the data structure used for FDP to work with the supplied stream IDs */ |
50 | if (td->o.dp_type == FIO_DP_STREAMS) { | |
51 | if (!td->o.dp_nr_ids) { | |
52 | log_err("fio: stream IDs must be provided for dataplacement=streams\n"); | |
53 | return -EINVAL; | |
54 | } | |
8ac0eec7 | 55 | ruhs = scalloc(1, sizeof(*ruhs) + td->o.dp_nr_ids * sizeof(*ruhs->plis)); |
56d12245 AK |
56 | if (!ruhs) |
57 | return -ENOMEM; | |
58 | ||
1a3a21b7 VF |
59 | ruhs->nr_ruhs = td->o.dp_nr_ids; |
60 | for (int i = 0; i < ruhs->nr_ruhs; i++) | |
61 | ruhs->plis[i] = td->o.dp_ids[i]; | |
62 | ||
63 | f->ruhs_info = ruhs; | |
64 | return 0; | |
65 | } | |
66 | ||
56d12245 AK |
67 | /* |
68 | * Since we don't know the actual number of ruhs. Only fetch the header. | |
69 | * We will reallocate this buffer and then fetch all the ruhs again. | |
70 | */ | |
71 | ruhs = calloc(1, sizeof(*ruhs)); | |
a7e8aae0 KB |
72 | ret = fdp_ruh_info(td, f, ruhs); |
73 | if (ret) { | |
6715cca2 AK |
74 | log_err("fio: ruh info failed for %s (%d)\n", |
75 | f->file_name, -ret); | |
a7e8aae0 KB |
76 | goto out; |
77 | } | |
78 | ||
56d12245 AK |
79 | nr_ruhs = ruhs->nr_ruhs; |
80 | ruhs = realloc(ruhs, sizeof(*ruhs) + nr_ruhs * sizeof(*ruhs->plis)); | |
81 | if (!ruhs) { | |
6715cca2 AK |
82 | log_err("fio: ruhs buffer realloc failed for %s\n", |
83 | f->file_name); | |
56d12245 AK |
84 | ret = -ENOMEM; |
85 | goto out; | |
86 | } | |
a7e8aae0 | 87 | |
56d12245 AK |
88 | ruhs->nr_ruhs = nr_ruhs; |
89 | ret = fdp_ruh_info(td, f, ruhs); | |
90 | if (ret) { | |
6715cca2 AK |
91 | log_err("fio: ruh info failed for %s (%d)\n", |
92 | f->file_name, -ret); | |
56d12245 | 93 | goto out; |
a7e8aae0 KB |
94 | } |
95 | ||
56d12245 | 96 | if (td->o.dp_nr_ids == 0) { |
481b6e3d AK |
97 | if (ruhs->nr_ruhs > FIO_MAX_DP_IDS) |
98 | ruhs->nr_ruhs = FIO_MAX_DP_IDS; | |
56d12245 | 99 | } else { |
56d12245 AK |
100 | for (i = 0; i < td->o.dp_nr_ids; i++) { |
101 | if (td->o.dp_ids[i] >= ruhs->nr_ruhs) { | |
481b6e3d AK |
102 | log_err("fio: for %s PID index %d must be smaller than %d\n", |
103 | f->file_name, td->o.dp_ids[i], | |
104 | ruhs->nr_ruhs); | |
56d12245 AK |
105 | ret = -EINVAL; |
106 | goto out; | |
107 | } | |
108 | } | |
109 | ruhs->nr_ruhs = td->o.dp_nr_ids; | |
a7e8aae0 KB |
110 | } |
111 | ||
112 | tmp = scalloc(1, sizeof(*tmp) + ruhs->nr_ruhs * sizeof(*tmp->plis)); | |
113 | if (!tmp) { | |
114 | ret = -ENOMEM; | |
115 | goto out; | |
116 | } | |
117 | ||
56d12245 AK |
118 | if (td->o.dp_nr_ids == 0) { |
119 | for (i = 0; i < ruhs->nr_ruhs; i++) | |
120 | tmp->plis[i] = ruhs->plis[i]; | |
121 | ||
122 | tmp->nr_ruhs = ruhs->nr_ruhs; | |
123 | f->ruhs_info = tmp; | |
124 | free(ruhs); | |
125 | ||
126 | return 0; | |
127 | } | |
128 | ||
65ca6791 VF |
129 | tmp->nr_ruhs = td->o.dp_nr_ids; |
130 | for (i = 0; i < td->o.dp_nr_ids; i++) | |
131 | tmp->plis[i] = ruhs->plis[td->o.dp_ids[i]]; | |
a7e8aae0 KB |
132 | f->ruhs_info = tmp; |
133 | out: | |
56d12245 | 134 | free(ruhs); |
a7e8aae0 KB |
135 | return ret; |
136 | } | |
137 | ||
04d5add8 HP |
138 | static int init_ruh_scheme(struct thread_data *td, struct fio_file *f) |
139 | { | |
140 | struct fio_ruhs_scheme *ruh_scheme; | |
141 | FILE *scheme_fp; | |
142 | unsigned long long start, end; | |
143 | uint16_t pli; | |
144 | int ret = 0; | |
145 | ||
146 | if (td->o.dp_id_select != FIO_DP_SCHEME) | |
147 | return 0; | |
148 | ||
149 | /* Get the scheme from the file */ | |
150 | scheme_fp = fopen(td->o.dp_scheme_file, "r"); | |
151 | ||
152 | if (!scheme_fp) { | |
153 | log_err("fio: ruh scheme failed to open scheme file %s\n", | |
6715cca2 | 154 | td->o.dp_scheme_file); |
04d5add8 HP |
155 | ret = -errno; |
156 | goto out; | |
157 | } | |
158 | ||
159 | ruh_scheme = scalloc(1, sizeof(*ruh_scheme)); | |
160 | if (!ruh_scheme) { | |
161 | ret = -ENOMEM; | |
162 | goto out_with_close_fp; | |
163 | } | |
164 | ||
165 | for (int i = 0; | |
166 | i < DP_MAX_SCHEME_ENTRIES && fscanf(scheme_fp, "%llu,%llu,%hu\n", &start, &end, &pli) == 3; | |
167 | i++) { | |
168 | ||
169 | ruh_scheme->scheme_entries[i].start_offset = start; | |
170 | ruh_scheme->scheme_entries[i].end_offset = end; | |
171 | ruh_scheme->scheme_entries[i].pli = pli; | |
172 | ruh_scheme->nr_schemes++; | |
173 | } | |
174 | ||
175 | if (fscanf(scheme_fp, "%llu,%llu,%hu\n", &start, &end, &pli) == 3) | |
176 | log_info("fio: too many scheme entries in %s. Only the first %d scheme entries are applied\n", | |
177 | td->o.dp_scheme_file, | |
178 | DP_MAX_SCHEME_ENTRIES); | |
179 | ||
180 | f->ruhs_scheme = ruh_scheme; | |
181 | ||
182 | out_with_close_fp: | |
183 | fclose(scheme_fp); | |
184 | out: | |
185 | return ret; | |
186 | } | |
187 | ||
c60d54ae | 188 | int dp_init(struct thread_data *td) |
a7e8aae0 KB |
189 | { |
190 | struct fio_file *f; | |
191 | int i, ret = 0; | |
192 | ||
193 | for_each_file(td, f, i) { | |
194 | ret = init_ruh_info(td, f); | |
195 | if (ret) | |
196 | break; | |
04d5add8 HP |
197 | |
198 | ret = init_ruh_scheme(td, f); | |
199 | if (ret) | |
200 | break; | |
a7e8aae0 KB |
201 | } |
202 | return ret; | |
203 | } | |
204 | ||
205 | void fdp_free_ruhs_info(struct fio_file *f) | |
206 | { | |
207 | if (!f->ruhs_info) | |
208 | return; | |
209 | sfree(f->ruhs_info); | |
210 | f->ruhs_info = NULL; | |
04d5add8 HP |
211 | |
212 | if (!f->ruhs_scheme) | |
213 | return; | |
214 | sfree(f->ruhs_scheme); | |
215 | f->ruhs_scheme = NULL; | |
a7e8aae0 KB |
216 | } |
217 | ||
c60d54ae | 218 | void dp_fill_dspec_data(struct thread_data *td, struct io_u *io_u) |
a7e8aae0 KB |
219 | { |
220 | struct fio_file *f = io_u->file; | |
221 | struct fio_ruhs_info *ruhs = f->ruhs_info; | |
222 | int dspec; | |
223 | ||
224 | if (!ruhs || io_u->ddir != DDIR_WRITE) { | |
225 | io_u->dtype = 0; | |
226 | io_u->dspec = 0; | |
227 | return; | |
228 | } | |
229 | ||
65ca6791 | 230 | if (td->o.dp_id_select == FIO_DP_RR) { |
d3e310c5 AK |
231 | if (ruhs->pli_loc >= ruhs->nr_ruhs) |
232 | ruhs->pli_loc = 0; | |
233 | ||
234 | dspec = ruhs->plis[ruhs->pli_loc++]; | |
04d5add8 HP |
235 | } else if (td->o.dp_id_select == FIO_DP_SCHEME) { |
236 | struct fio_ruhs_scheme *ruhs_scheme = f->ruhs_scheme; | |
237 | unsigned long long offset = io_u->offset; | |
238 | int i; | |
239 | ||
240 | for (i = 0; i < ruhs_scheme->nr_schemes; i++) { | |
241 | if (offset >= ruhs_scheme->scheme_entries[i].start_offset && | |
242 | offset < ruhs_scheme->scheme_entries[i].end_offset) { | |
243 | dspec = ruhs_scheme->scheme_entries[i].pli; | |
244 | break; | |
245 | } | |
246 | } | |
247 | ||
248 | /* | |
249 | * If the write offset is not affected by any scheme entry, | |
250 | * 0(default RUH) will be assigned to dspec | |
251 | */ | |
252 | if (i == ruhs_scheme->nr_schemes) | |
253 | dspec = 0; | |
d3e310c5 AK |
254 | } else { |
255 | ruhs->pli_loc = rand_between(&td->fdp_state, 0, ruhs->nr_ruhs - 1); | |
256 | dspec = ruhs->plis[ruhs->pli_loc]; | |
257 | } | |
3b3c9877 | 258 | |
1a3a21b7 | 259 | io_u->dtype = td->o.dp_type == FIO_DP_FDP ? FDP_DIR_DTYPE : STREAMS_DIR_DTYPE; |
a7e8aae0 | 260 | io_u->dspec = dspec; |
61d22139 | 261 | dprint(FD_IO, "dtype set to 0x%x, dspec set to 0x%x\n", io_u->dtype, io_u->dspec); |
a7e8aae0 | 262 | } |