diff options
Diffstat (limited to 'fs/exofs/ios.c')
-rw-r--r-- | fs/exofs/ios.c | 421 |
1 files changed, 421 insertions, 0 deletions
diff --git a/fs/exofs/ios.c b/fs/exofs/ios.c new file mode 100644 index 000000000000..5bad01fa1f9f --- /dev/null +++ b/fs/exofs/ios.c | |||
@@ -0,0 +1,421 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005, 2006 | ||
3 | * Avishay Traeger (avishay@gmail.com) | ||
4 | * Copyright (C) 2008, 2009 | ||
5 | * Boaz Harrosh <bharrosh@panasas.com> | ||
6 | * | ||
7 | * This file is part of exofs. | ||
8 | * | ||
9 | * exofs is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation. Since it is based on ext2, and the only | ||
12 | * valid version of GPL for the Linux kernel is version 2, the only valid | ||
13 | * version of GPL for exofs is version 2. | ||
14 | * | ||
15 | * exofs is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with exofs; if not, write to the Free Software | ||
22 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
23 | */ | ||
24 | |||
25 | #include <scsi/scsi_device.h> | ||
26 | |||
27 | #include "exofs.h" | ||
28 | |||
29 | void exofs_make_credential(u8 cred_a[OSD_CAP_LEN], const struct osd_obj_id *obj) | ||
30 | { | ||
31 | osd_sec_init_nosec_doall_caps(cred_a, obj, false, true); | ||
32 | } | ||
33 | |||
34 | int exofs_read_kern(struct osd_dev *od, u8 *cred, struct osd_obj_id *obj, | ||
35 | u64 offset, void *p, unsigned length) | ||
36 | { | ||
37 | struct osd_request *or = osd_start_request(od, GFP_KERNEL); | ||
38 | /* struct osd_sense_info osi = {.key = 0};*/ | ||
39 | int ret; | ||
40 | |||
41 | if (unlikely(!or)) { | ||
42 | EXOFS_DBGMSG("%s: osd_start_request failed.\n", __func__); | ||
43 | return -ENOMEM; | ||
44 | } | ||
45 | ret = osd_req_read_kern(or, obj, offset, p, length); | ||
46 | if (unlikely(ret)) { | ||
47 | EXOFS_DBGMSG("%s: osd_req_read_kern failed.\n", __func__); | ||
48 | goto out; | ||
49 | } | ||
50 | |||
51 | ret = osd_finalize_request(or, 0, cred, NULL); | ||
52 | if (unlikely(ret)) { | ||
53 | EXOFS_DBGMSG("Faild to osd_finalize_request() => %d\n", ret); | ||
54 | goto out; | ||
55 | } | ||
56 | |||
57 | ret = osd_execute_request(or); | ||
58 | if (unlikely(ret)) | ||
59 | EXOFS_DBGMSG("osd_execute_request() => %d\n", ret); | ||
60 | /* osd_req_decode_sense(or, ret); */ | ||
61 | |||
62 | out: | ||
63 | osd_end_request(or); | ||
64 | return ret; | ||
65 | } | ||
66 | |||
67 | int exofs_get_io_state(struct exofs_sb_info *sbi, struct exofs_io_state** pios) | ||
68 | { | ||
69 | struct exofs_io_state *ios; | ||
70 | |||
71 | /*TODO: Maybe use kmem_cach per sbi of size | ||
72 | * exofs_io_state_size(sbi->s_numdevs) | ||
73 | */ | ||
74 | ios = kzalloc(exofs_io_state_size(sbi->s_numdevs), GFP_KERNEL); | ||
75 | if (unlikely(!ios)) { | ||
76 | *pios = NULL; | ||
77 | return -ENOMEM; | ||
78 | } | ||
79 | |||
80 | ios->sbi = sbi; | ||
81 | ios->obj.partition = sbi->s_pid; | ||
82 | *pios = ios; | ||
83 | return 0; | ||
84 | } | ||
85 | |||
86 | void exofs_put_io_state(struct exofs_io_state *ios) | ||
87 | { | ||
88 | if (ios) { | ||
89 | unsigned i; | ||
90 | |||
91 | for (i = 0; i < ios->numdevs; i++) { | ||
92 | struct exofs_per_dev_state *per_dev = &ios->per_dev[i]; | ||
93 | |||
94 | if (per_dev->or) | ||
95 | osd_end_request(per_dev->or); | ||
96 | if (per_dev->bio) | ||
97 | bio_put(per_dev->bio); | ||
98 | } | ||
99 | |||
100 | kfree(ios); | ||
101 | } | ||
102 | } | ||
103 | |||
104 | static void _sync_done(struct exofs_io_state *ios, void *p) | ||
105 | { | ||
106 | struct completion *waiting = p; | ||
107 | |||
108 | complete(waiting); | ||
109 | } | ||
110 | |||
111 | static void _last_io(struct kref *kref) | ||
112 | { | ||
113 | struct exofs_io_state *ios = container_of( | ||
114 | kref, struct exofs_io_state, kref); | ||
115 | |||
116 | ios->done(ios, ios->private); | ||
117 | } | ||
118 | |||
119 | static void _done_io(struct osd_request *or, void *p) | ||
120 | { | ||
121 | struct exofs_io_state *ios = p; | ||
122 | |||
123 | kref_put(&ios->kref, _last_io); | ||
124 | } | ||
125 | |||
126 | static int exofs_io_execute(struct exofs_io_state *ios) | ||
127 | { | ||
128 | DECLARE_COMPLETION_ONSTACK(wait); | ||
129 | bool sync = (ios->done == NULL); | ||
130 | int i, ret; | ||
131 | |||
132 | if (sync) { | ||
133 | ios->done = _sync_done; | ||
134 | ios->private = &wait; | ||
135 | } | ||
136 | |||
137 | for (i = 0; i < ios->numdevs; i++) { | ||
138 | struct osd_request *or = ios->per_dev[i].or; | ||
139 | if (unlikely(!or)) | ||
140 | continue; | ||
141 | |||
142 | ret = osd_finalize_request(or, 0, ios->cred, NULL); | ||
143 | if (unlikely(ret)) { | ||
144 | EXOFS_DBGMSG("Faild to osd_finalize_request() => %d\n", | ||
145 | ret); | ||
146 | return ret; | ||
147 | } | ||
148 | } | ||
149 | |||
150 | kref_init(&ios->kref); | ||
151 | |||
152 | for (i = 0; i < ios->numdevs; i++) { | ||
153 | struct osd_request *or = ios->per_dev[i].or; | ||
154 | if (unlikely(!or)) | ||
155 | continue; | ||
156 | |||
157 | kref_get(&ios->kref); | ||
158 | osd_execute_request_async(or, _done_io, ios); | ||
159 | } | ||
160 | |||
161 | kref_put(&ios->kref, _last_io); | ||
162 | ret = 0; | ||
163 | |||
164 | if (sync) { | ||
165 | wait_for_completion(&wait); | ||
166 | ret = exofs_check_io(ios, NULL); | ||
167 | } | ||
168 | return ret; | ||
169 | } | ||
170 | |||
171 | int exofs_check_io(struct exofs_io_state *ios, u64 *resid) | ||
172 | { | ||
173 | enum osd_err_priority acumulated_osd_err = 0; | ||
174 | int acumulated_lin_err = 0; | ||
175 | int i; | ||
176 | |||
177 | for (i = 0; i < ios->numdevs; i++) { | ||
178 | struct osd_sense_info osi; | ||
179 | int ret = osd_req_decode_sense(ios->per_dev[i].or, &osi); | ||
180 | |||
181 | if (likely(!ret)) | ||
182 | continue; | ||
183 | |||
184 | if (unlikely(ret == -EFAULT)) { | ||
185 | EXOFS_DBGMSG("%s: EFAULT Need page clear\n", __func__); | ||
186 | /*FIXME: All the pages in this device range should: | ||
187 | * clear_highpage(page); | ||
188 | */ | ||
189 | } | ||
190 | |||
191 | if (osi.osd_err_pri >= acumulated_osd_err) { | ||
192 | acumulated_osd_err = osi.osd_err_pri; | ||
193 | acumulated_lin_err = ret; | ||
194 | } | ||
195 | } | ||
196 | |||
197 | /* TODO: raid specific residual calculations */ | ||
198 | if (resid) { | ||
199 | if (likely(!acumulated_lin_err)) | ||
200 | *resid = 0; | ||
201 | else | ||
202 | *resid = ios->length; | ||
203 | } | ||
204 | |||
205 | return acumulated_lin_err; | ||
206 | } | ||
207 | |||
208 | int exofs_sbi_create(struct exofs_io_state *ios) | ||
209 | { | ||
210 | int i, ret; | ||
211 | |||
212 | for (i = 0; i < ios->sbi->s_numdevs; i++) { | ||
213 | struct osd_request *or; | ||
214 | |||
215 | or = osd_start_request(ios->sbi->s_ods[i], GFP_KERNEL); | ||
216 | if (unlikely(!or)) { | ||
217 | EXOFS_ERR("%s: osd_start_request failed\n", __func__); | ||
218 | ret = -ENOMEM; | ||
219 | goto out; | ||
220 | } | ||
221 | ios->per_dev[i].or = or; | ||
222 | ios->numdevs++; | ||
223 | |||
224 | osd_req_create_object(or, &ios->obj); | ||
225 | } | ||
226 | ret = exofs_io_execute(ios); | ||
227 | |||
228 | out: | ||
229 | return ret; | ||
230 | } | ||
231 | |||
232 | int exofs_sbi_remove(struct exofs_io_state *ios) | ||
233 | { | ||
234 | int i, ret; | ||
235 | |||
236 | for (i = 0; i < ios->sbi->s_numdevs; i++) { | ||
237 | struct osd_request *or; | ||
238 | |||
239 | or = osd_start_request(ios->sbi->s_ods[i], GFP_KERNEL); | ||
240 | if (unlikely(!or)) { | ||
241 | EXOFS_ERR("%s: osd_start_request failed\n", __func__); | ||
242 | ret = -ENOMEM; | ||
243 | goto out; | ||
244 | } | ||
245 | ios->per_dev[i].or = or; | ||
246 | ios->numdevs++; | ||
247 | |||
248 | osd_req_remove_object(or, &ios->obj); | ||
249 | } | ||
250 | ret = exofs_io_execute(ios); | ||
251 | |||
252 | out: | ||
253 | return ret; | ||
254 | } | ||
255 | |||
256 | int exofs_sbi_write(struct exofs_io_state *ios) | ||
257 | { | ||
258 | int i, ret; | ||
259 | |||
260 | for (i = 0; i < ios->sbi->s_numdevs; i++) { | ||
261 | struct osd_request *or; | ||
262 | |||
263 | or = osd_start_request(ios->sbi->s_ods[i], GFP_KERNEL); | ||
264 | if (unlikely(!or)) { | ||
265 | EXOFS_ERR("%s: osd_start_request failed\n", __func__); | ||
266 | ret = -ENOMEM; | ||
267 | goto out; | ||
268 | } | ||
269 | ios->per_dev[i].or = or; | ||
270 | ios->numdevs++; | ||
271 | |||
272 | if (ios->bio) { | ||
273 | struct bio *bio; | ||
274 | |||
275 | if (i != 0) { | ||
276 | bio = bio_kmalloc(GFP_KERNEL, | ||
277 | ios->bio->bi_max_vecs); | ||
278 | if (unlikely(!bio)) { | ||
279 | ret = -ENOMEM; | ||
280 | goto out; | ||
281 | } | ||
282 | |||
283 | __bio_clone(bio, ios->bio); | ||
284 | bio->bi_bdev = NULL; | ||
285 | bio->bi_next = NULL; | ||
286 | ios->per_dev[i].bio = bio; | ||
287 | } else { | ||
288 | bio = ios->bio; | ||
289 | } | ||
290 | |||
291 | osd_req_write(or, &ios->obj, ios->offset, bio, | ||
292 | ios->length); | ||
293 | /* EXOFS_DBGMSG("write sync=%d\n", sync);*/ | ||
294 | } else if (ios->kern_buff) { | ||
295 | osd_req_write_kern(or, &ios->obj, ios->offset, | ||
296 | ios->kern_buff, ios->length); | ||
297 | /* EXOFS_DBGMSG("write_kern sync=%d\n", sync);*/ | ||
298 | } else { | ||
299 | osd_req_set_attributes(or, &ios->obj); | ||
300 | /* EXOFS_DBGMSG("set_attributes sync=%d\n", sync);*/ | ||
301 | } | ||
302 | |||
303 | if (ios->out_attr) | ||
304 | osd_req_add_set_attr_list(or, ios->out_attr, | ||
305 | ios->out_attr_len); | ||
306 | |||
307 | if (ios->in_attr) | ||
308 | osd_req_add_get_attr_list(or, ios->in_attr, | ||
309 | ios->in_attr_len); | ||
310 | } | ||
311 | ret = exofs_io_execute(ios); | ||
312 | |||
313 | out: | ||
314 | return ret; | ||
315 | } | ||
316 | |||
317 | int exofs_sbi_read(struct exofs_io_state *ios) | ||
318 | { | ||
319 | int i, ret; | ||
320 | |||
321 | for (i = 0; i < 1; i++) { | ||
322 | struct osd_request *or; | ||
323 | unsigned first_dev = (unsigned)ios->obj.id; | ||
324 | |||
325 | first_dev %= ios->sbi->s_numdevs; | ||
326 | or = osd_start_request(ios->sbi->s_ods[first_dev], GFP_KERNEL); | ||
327 | if (unlikely(!or)) { | ||
328 | EXOFS_ERR("%s: osd_start_request failed\n", __func__); | ||
329 | ret = -ENOMEM; | ||
330 | goto out; | ||
331 | } | ||
332 | ios->per_dev[i].or = or; | ||
333 | ios->numdevs++; | ||
334 | |||
335 | if (ios->bio) { | ||
336 | osd_req_read(or, &ios->obj, ios->offset, ios->bio, | ||
337 | ios->length); | ||
338 | /* EXOFS_DBGMSG("read sync=%d\n", sync);*/ | ||
339 | } else if (ios->kern_buff) { | ||
340 | osd_req_read_kern(or, &ios->obj, ios->offset, | ||
341 | ios->kern_buff, ios->length); | ||
342 | /* EXOFS_DBGMSG("read_kern sync=%d\n", sync);*/ | ||
343 | } else { | ||
344 | osd_req_get_attributes(or, &ios->obj); | ||
345 | /* EXOFS_DBGMSG("get_attributes sync=%d\n", sync);*/ | ||
346 | } | ||
347 | |||
348 | if (ios->out_attr) | ||
349 | osd_req_add_set_attr_list(or, ios->out_attr, | ||
350 | ios->out_attr_len); | ||
351 | |||
352 | if (ios->in_attr) | ||
353 | osd_req_add_get_attr_list(or, ios->in_attr, | ||
354 | ios->in_attr_len); | ||
355 | } | ||
356 | ret = exofs_io_execute(ios); | ||
357 | |||
358 | out: | ||
359 | return ret; | ||
360 | } | ||
361 | |||
362 | int extract_attr_from_ios(struct exofs_io_state *ios, struct osd_attr *attr) | ||
363 | { | ||
364 | struct osd_attr cur_attr = {.attr_page = 0}; /* start with zeros */ | ||
365 | void *iter = NULL; | ||
366 | int nelem; | ||
367 | |||
368 | do { | ||
369 | nelem = 1; | ||
370 | osd_req_decode_get_attr_list(ios->per_dev[0].or, | ||
371 | &cur_attr, &nelem, &iter); | ||
372 | if ((cur_attr.attr_page == attr->attr_page) && | ||
373 | (cur_attr.attr_id == attr->attr_id)) { | ||
374 | attr->len = cur_attr.len; | ||
375 | attr->val_ptr = cur_attr.val_ptr; | ||
376 | return 0; | ||
377 | } | ||
378 | } while (iter); | ||
379 | |||
380 | return -EIO; | ||
381 | } | ||
382 | |||
383 | int exofs_oi_truncate(struct exofs_i_info *oi, u64 size) | ||
384 | { | ||
385 | struct exofs_sb_info *sbi = oi->vfs_inode.i_sb->s_fs_info; | ||
386 | struct exofs_io_state *ios; | ||
387 | struct osd_attr attr; | ||
388 | __be64 newsize; | ||
389 | int i, ret; | ||
390 | |||
391 | if (exofs_get_io_state(sbi, &ios)) | ||
392 | return -ENOMEM; | ||
393 | |||
394 | ios->obj.id = exofs_oi_objno(oi); | ||
395 | ios->cred = oi->i_cred; | ||
396 | |||
397 | newsize = cpu_to_be64(size); | ||
398 | attr = g_attr_logical_length; | ||
399 | attr.val_ptr = &newsize; | ||
400 | |||
401 | for (i = 0; i < sbi->s_numdevs; i++) { | ||
402 | struct osd_request *or; | ||
403 | |||
404 | or = osd_start_request(sbi->s_ods[i], GFP_KERNEL); | ||
405 | if (unlikely(!or)) { | ||
406 | EXOFS_ERR("%s: osd_start_request failed\n", __func__); | ||
407 | ret = -ENOMEM; | ||
408 | goto out; | ||
409 | } | ||
410 | ios->per_dev[i].or = or; | ||
411 | ios->numdevs++; | ||
412 | |||
413 | osd_req_set_attributes(or, &ios->obj); | ||
414 | osd_req_add_set_attr_list(or, &attr, 1); | ||
415 | } | ||
416 | ret = exofs_io_execute(ios); | ||
417 | |||
418 | out: | ||
419 | exofs_put_io_state(ios); | ||
420 | return ret; | ||
421 | } | ||