blob: 4f679317ca54a39b49d45bf8446895993b620d7b [file] [log] [blame]
Boaz Harroshb14f8ab2008-10-27 18:27:55 +02001/*
2 * Copyright (C) 2005, 2006
Boaz Harrosh27d2e142009-06-14 17:23:09 +03003 * Avishay Traeger (avishay@gmail.com)
Boaz Harroshb14f8ab2008-10-27 18:27:55 +02004 * 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>
Boaz Harroshb14f8ab2008-10-27 18:27:55 +020026
27#include "exofs.h"
28
Boaz Harrosh34ce4e72009-12-15 19:34:17 +020029#define EXOFS_DBGMSG2(M...) do {} while (0)
30/* #define EXOFS_DBGMSG2 EXOFS_DBGMSG */
31
Boaz Harroshb14f8ab2008-10-27 18:27:55 +020032void exofs_make_credential(u8 cred_a[OSD_CAP_LEN], const struct osd_obj_id *obj)
33{
34 osd_sec_init_nosec_doall_caps(cred_a, obj, false, true);
35}
36
Boaz Harrosh06886a52009-11-08 14:54:08 +020037int exofs_read_kern(struct osd_dev *od, u8 *cred, struct osd_obj_id *obj,
38 u64 offset, void *p, unsigned length)
Boaz Harroshb14f8ab2008-10-27 18:27:55 +020039{
Boaz Harrosh06886a52009-11-08 14:54:08 +020040 struct osd_request *or = osd_start_request(od, GFP_KERNEL);
41/* struct osd_sense_info osi = {.key = 0};*/
Boaz Harroshb14f8ab2008-10-27 18:27:55 +020042 int ret;
43
Boaz Harrosh06886a52009-11-08 14:54:08 +020044 if (unlikely(!or)) {
45 EXOFS_DBGMSG("%s: osd_start_request failed.\n", __func__);
46 return -ENOMEM;
47 }
48 ret = osd_req_read_kern(or, obj, offset, p, length);
49 if (unlikely(ret)) {
50 EXOFS_DBGMSG("%s: osd_req_read_kern failed.\n", __func__);
51 goto out;
52 }
53
54 ret = osd_finalize_request(or, 0, cred, NULL);
55 if (unlikely(ret)) {
Boaz Harroshb14f8ab2008-10-27 18:27:55 +020056 EXOFS_DBGMSG("Faild to osd_finalize_request() => %d\n", ret);
Boaz Harrosh06886a52009-11-08 14:54:08 +020057 goto out;
Boaz Harroshb14f8ab2008-10-27 18:27:55 +020058 }
59
60 ret = osd_execute_request(or);
Boaz Harrosh06886a52009-11-08 14:54:08 +020061 if (unlikely(ret))
Boaz Harroshb14f8ab2008-10-27 18:27:55 +020062 EXOFS_DBGMSG("osd_execute_request() => %d\n", ret);
63 /* osd_req_decode_sense(or, ret); */
Boaz Harrosh06886a52009-11-08 14:54:08 +020064
65out:
66 osd_end_request(or);
Boaz Harroshb14f8ab2008-10-27 18:27:55 +020067 return ret;
68}
69
Boaz Harrosh45d3abc2010-01-28 11:46:16 +020070int exofs_get_io_state(struct exofs_layout *layout,
71 struct exofs_io_state **pios)
Boaz Harroshb14f8ab2008-10-27 18:27:55 +020072{
Boaz Harrosh06886a52009-11-08 14:54:08 +020073 struct exofs_io_state *ios;
Boaz Harroshb14f8ab2008-10-27 18:27:55 +020074
Boaz Harrosh06886a52009-11-08 14:54:08 +020075 /*TODO: Maybe use kmem_cach per sbi of size
Boaz Harrosh45d3abc2010-01-28 11:46:16 +020076 * exofs_io_state_size(layout->s_numdevs)
Boaz Harrosh06886a52009-11-08 14:54:08 +020077 */
Boaz Harrosh45d3abc2010-01-28 11:46:16 +020078 ios = kzalloc(exofs_io_state_size(layout->s_numdevs), GFP_KERNEL);
Boaz Harrosh06886a52009-11-08 14:54:08 +020079 if (unlikely(!ios)) {
Boaz Harrosh34ce4e72009-12-15 19:34:17 +020080 EXOFS_DBGMSG("Faild kzalloc bytes=%d\n",
Boaz Harrosh45d3abc2010-01-28 11:46:16 +020081 exofs_io_state_size(layout->s_numdevs));
Boaz Harrosh06886a52009-11-08 14:54:08 +020082 *pios = NULL;
83 return -ENOMEM;
Boaz Harroshb14f8ab2008-10-27 18:27:55 +020084 }
85
Boaz Harrosh45d3abc2010-01-28 11:46:16 +020086 ios->layout = layout;
87 ios->obj.partition = layout->s_pid;
Boaz Harrosh06886a52009-11-08 14:54:08 +020088 *pios = ios;
89 return 0;
90}
Boaz Harroshb14f8ab2008-10-27 18:27:55 +020091
Boaz Harrosh06886a52009-11-08 14:54:08 +020092void exofs_put_io_state(struct exofs_io_state *ios)
93{
94 if (ios) {
95 unsigned i;
96
97 for (i = 0; i < ios->numdevs; i++) {
98 struct exofs_per_dev_state *per_dev = &ios->per_dev[i];
99
100 if (per_dev->or)
101 osd_end_request(per_dev->or);
102 if (per_dev->bio)
103 bio_put(per_dev->bio);
104 }
105
106 kfree(ios);
107 }
108}
109
110static void _sync_done(struct exofs_io_state *ios, void *p)
111{
112 struct completion *waiting = p;
113
114 complete(waiting);
115}
116
117static void _last_io(struct kref *kref)
118{
119 struct exofs_io_state *ios = container_of(
120 kref, struct exofs_io_state, kref);
121
122 ios->done(ios, ios->private);
123}
124
125static void _done_io(struct osd_request *or, void *p)
126{
127 struct exofs_io_state *ios = p;
128
129 kref_put(&ios->kref, _last_io);
130}
131
132static int exofs_io_execute(struct exofs_io_state *ios)
133{
134 DECLARE_COMPLETION_ONSTACK(wait);
135 bool sync = (ios->done == NULL);
136 int i, ret;
137
138 if (sync) {
139 ios->done = _sync_done;
140 ios->private = &wait;
141 }
142
143 for (i = 0; i < ios->numdevs; i++) {
144 struct osd_request *or = ios->per_dev[i].or;
145 if (unlikely(!or))
146 continue;
147
148 ret = osd_finalize_request(or, 0, ios->cred, NULL);
149 if (unlikely(ret)) {
150 EXOFS_DBGMSG("Faild to osd_finalize_request() => %d\n",
151 ret);
152 return ret;
153 }
154 }
155
156 kref_init(&ios->kref);
157
158 for (i = 0; i < ios->numdevs; i++) {
159 struct osd_request *or = ios->per_dev[i].or;
160 if (unlikely(!or))
161 continue;
162
163 kref_get(&ios->kref);
164 osd_execute_request_async(or, _done_io, ios);
165 }
166
167 kref_put(&ios->kref, _last_io);
168 ret = 0;
169
170 if (sync) {
171 wait_for_completion(&wait);
172 ret = exofs_check_io(ios, NULL);
173 }
Boaz Harroshb14f8ab2008-10-27 18:27:55 +0200174 return ret;
175}
176
Boaz Harrosh22ddc552010-01-19 19:24:45 +0200177static void _clear_bio(struct bio *bio)
178{
179 struct bio_vec *bv;
180 unsigned i;
181
182 __bio_for_each_segment(bv, bio, i, 0) {
183 unsigned this_count = bv->bv_len;
184
185 if (likely(PAGE_SIZE == this_count))
186 clear_highpage(bv->bv_page);
187 else
188 zero_user(bv->bv_page, bv->bv_offset, this_count);
189 }
190}
191
Boaz Harrosh06886a52009-11-08 14:54:08 +0200192int exofs_check_io(struct exofs_io_state *ios, u64 *resid)
193{
194 enum osd_err_priority acumulated_osd_err = 0;
195 int acumulated_lin_err = 0;
196 int i;
197
198 for (i = 0; i < ios->numdevs; i++) {
199 struct osd_sense_info osi;
Boaz Harrosh22ddc552010-01-19 19:24:45 +0200200 struct osd_request *or = ios->per_dev[i].or;
201 int ret;
Boaz Harrosh06886a52009-11-08 14:54:08 +0200202
Boaz Harrosh22ddc552010-01-19 19:24:45 +0200203 if (unlikely(!or))
204 continue;
205
206 ret = osd_req_decode_sense(or, &osi);
Boaz Harrosh06886a52009-11-08 14:54:08 +0200207 if (likely(!ret))
208 continue;
209
Boaz Harrosh22ddc552010-01-19 19:24:45 +0200210 if (OSD_ERR_PRI_CLEAR_PAGES == osi.osd_err_pri) {
211 /* start read offset passed endof file */
212 _clear_bio(ios->per_dev[i].bio);
213 EXOFS_DBGMSG("start read offset passed end of file "
214 "offset=0x%llx, length=0x%llx\n",
215 _LLU(ios->offset),
216 _LLU(ios->length));
217
218 continue; /* we recovered */
Boaz Harrosh06886a52009-11-08 14:54:08 +0200219 }
220
221 if (osi.osd_err_pri >= acumulated_osd_err) {
222 acumulated_osd_err = osi.osd_err_pri;
223 acumulated_lin_err = ret;
224 }
225 }
226
227 /* TODO: raid specific residual calculations */
228 if (resid) {
229 if (likely(!acumulated_lin_err))
230 *resid = 0;
231 else
232 *resid = ios->length;
233 }
234
235 return acumulated_lin_err;
236}
237
238int exofs_sbi_create(struct exofs_io_state *ios)
239{
240 int i, ret;
241
Boaz Harrosh45d3abc2010-01-28 11:46:16 +0200242 for (i = 0; i < ios->layout->s_numdevs; i++) {
Boaz Harrosh06886a52009-11-08 14:54:08 +0200243 struct osd_request *or;
244
Boaz Harrosh45d3abc2010-01-28 11:46:16 +0200245 or = osd_start_request(ios->layout->s_ods[i], GFP_KERNEL);
Boaz Harrosh06886a52009-11-08 14:54:08 +0200246 if (unlikely(!or)) {
247 EXOFS_ERR("%s: osd_start_request failed\n", __func__);
248 ret = -ENOMEM;
249 goto out;
250 }
251 ios->per_dev[i].or = or;
252 ios->numdevs++;
253
254 osd_req_create_object(or, &ios->obj);
255 }
256 ret = exofs_io_execute(ios);
257
258out:
259 return ret;
260}
261
262int exofs_sbi_remove(struct exofs_io_state *ios)
263{
264 int i, ret;
265
Boaz Harrosh45d3abc2010-01-28 11:46:16 +0200266 for (i = 0; i < ios->layout->s_numdevs; i++) {
Boaz Harrosh06886a52009-11-08 14:54:08 +0200267 struct osd_request *or;
268
Boaz Harrosh45d3abc2010-01-28 11:46:16 +0200269 or = osd_start_request(ios->layout->s_ods[i], GFP_KERNEL);
Boaz Harrosh06886a52009-11-08 14:54:08 +0200270 if (unlikely(!or)) {
271 EXOFS_ERR("%s: osd_start_request failed\n", __func__);
272 ret = -ENOMEM;
273 goto out;
274 }
275 ios->per_dev[i].or = or;
276 ios->numdevs++;
277
278 osd_req_remove_object(or, &ios->obj);
279 }
280 ret = exofs_io_execute(ios);
281
282out:
283 return ret;
284}
285
286int exofs_sbi_write(struct exofs_io_state *ios)
287{
288 int i, ret;
289
Boaz Harrosh45d3abc2010-01-28 11:46:16 +0200290 for (i = 0; i < ios->layout->s_numdevs; i++) {
Boaz Harrosh06886a52009-11-08 14:54:08 +0200291 struct osd_request *or;
292
Boaz Harrosh45d3abc2010-01-28 11:46:16 +0200293 or = osd_start_request(ios->layout->s_ods[i], GFP_KERNEL);
Boaz Harrosh06886a52009-11-08 14:54:08 +0200294 if (unlikely(!or)) {
295 EXOFS_ERR("%s: osd_start_request failed\n", __func__);
296 ret = -ENOMEM;
297 goto out;
298 }
299 ios->per_dev[i].or = or;
300 ios->numdevs++;
301
302 if (ios->bio) {
303 struct bio *bio;
304
Boaz Harrosh04dc1e82009-11-16 16:03:05 +0200305 if (i != 0) {
306 bio = bio_kmalloc(GFP_KERNEL,
307 ios->bio->bi_max_vecs);
308 if (unlikely(!bio)) {
Boaz Harrosh34ce4e72009-12-15 19:34:17 +0200309 EXOFS_DBGMSG(
310 "Faild to allocate BIO size=%u\n",
311 ios->bio->bi_max_vecs);
Boaz Harrosh04dc1e82009-11-16 16:03:05 +0200312 ret = -ENOMEM;
313 goto out;
314 }
315
316 __bio_clone(bio, ios->bio);
317 bio->bi_bdev = NULL;
318 bio->bi_next = NULL;
319 ios->per_dev[i].bio = bio;
320 } else {
321 bio = ios->bio;
322 }
Boaz Harrosh06886a52009-11-08 14:54:08 +0200323
324 osd_req_write(or, &ios->obj, ios->offset, bio,
325 ios->length);
Boaz Harrosh34ce4e72009-12-15 19:34:17 +0200326 EXOFS_DBGMSG("write(0x%llx) offset=0x%llx "
327 "length=0x%llx dev=%d\n",
328 _LLU(ios->obj.id), _LLU(ios->offset),
329 _LLU(ios->length), i);
Boaz Harrosh06886a52009-11-08 14:54:08 +0200330 } else if (ios->kern_buff) {
331 osd_req_write_kern(or, &ios->obj, ios->offset,
332 ios->kern_buff, ios->length);
Boaz Harrosh34ce4e72009-12-15 19:34:17 +0200333 EXOFS_DBGMSG2("write_kern(0x%llx) offset=0x%llx "
334 "length=0x%llx dev=%d\n",
335 _LLU(ios->obj.id), _LLU(ios->offset),
336 _LLU(ios->length), i);
Boaz Harrosh06886a52009-11-08 14:54:08 +0200337 } else {
338 osd_req_set_attributes(or, &ios->obj);
Boaz Harrosh34ce4e72009-12-15 19:34:17 +0200339 EXOFS_DBGMSG2("obj(0x%llx) set_attributes=%d dev=%d\n",
340 _LLU(ios->obj.id), ios->out_attr_len, i);
Boaz Harrosh06886a52009-11-08 14:54:08 +0200341 }
342
343 if (ios->out_attr)
344 osd_req_add_set_attr_list(or, ios->out_attr,
345 ios->out_attr_len);
346
347 if (ios->in_attr)
348 osd_req_add_get_attr_list(or, ios->in_attr,
349 ios->in_attr_len);
350 }
351 ret = exofs_io_execute(ios);
352
353out:
354 return ret;
355}
356
357int exofs_sbi_read(struct exofs_io_state *ios)
358{
Boaz Harrosh46f4d972010-02-01 11:37:30 +0200359 struct osd_request *or;
360 struct exofs_per_dev_state *per_dev = &ios->per_dev[0];
361 unsigned first_dev = (unsigned)ios->obj.id;
Boaz Harrosh06886a52009-11-08 14:54:08 +0200362
Boaz Harrosh46f4d972010-02-01 11:37:30 +0200363 first_dev %= ios->layout->s_numdevs;
364 or = osd_start_request(ios->layout->s_ods[first_dev], GFP_KERNEL);
365 if (unlikely(!or)) {
366 EXOFS_ERR("%s: osd_start_request failed\n", __func__);
367 return -ENOMEM;
Boaz Harrosh06886a52009-11-08 14:54:08 +0200368 }
Boaz Harrosh46f4d972010-02-01 11:37:30 +0200369 per_dev->or = or;
370 ios->numdevs++;
Boaz Harrosh06886a52009-11-08 14:54:08 +0200371
Boaz Harrosh46f4d972010-02-01 11:37:30 +0200372 if (ios->bio) {
373 osd_req_read(or, &ios->obj, ios->offset, ios->bio, ios->length);
374 EXOFS_DBGMSG("read(0x%llx) offset=0x%llx length=0x%llx"
375 " dev=%d\n", _LLU(ios->obj.id),
376 _LLU(ios->offset), _LLU(ios->length),
377 first_dev);
378 } else if (ios->kern_buff) {
379 int ret = osd_req_read_kern(or, &ios->obj, ios->offset,
380 ios->kern_buff, ios->length);
381
382 EXOFS_DBGMSG2("read_kern(0x%llx) offset=0x%llx "
383 "length=0x%llx dev=%d ret=>%d\n",
384 _LLU(ios->obj.id), _LLU(ios->offset),
385 _LLU(ios->length), first_dev, ret);
386 if (unlikely(ret))
387 return ret;
388 } else {
389 osd_req_get_attributes(or, &ios->obj);
390 EXOFS_DBGMSG2("obj(0x%llx) get_attributes=%d dev=%d\n",
391 _LLU(ios->obj.id), ios->in_attr_len, first_dev);
392 }
393
394 if (ios->out_attr)
395 osd_req_add_set_attr_list(or, ios->out_attr, ios->out_attr_len);
396
397 if (ios->in_attr)
398 osd_req_add_get_attr_list(or, ios->in_attr, ios->in_attr_len);
399
400 return exofs_io_execute(ios);
Boaz Harrosh06886a52009-11-08 14:54:08 +0200401}
402
403int extract_attr_from_ios(struct exofs_io_state *ios, struct osd_attr *attr)
Boaz Harroshb14f8ab2008-10-27 18:27:55 +0200404{
405 struct osd_attr cur_attr = {.attr_page = 0}; /* start with zeros */
406 void *iter = NULL;
407 int nelem;
408
409 do {
410 nelem = 1;
Boaz Harrosh06886a52009-11-08 14:54:08 +0200411 osd_req_decode_get_attr_list(ios->per_dev[0].or,
412 &cur_attr, &nelem, &iter);
Boaz Harroshb14f8ab2008-10-27 18:27:55 +0200413 if ((cur_attr.attr_page == attr->attr_page) &&
414 (cur_attr.attr_id == attr->attr_id)) {
415 attr->len = cur_attr.len;
416 attr->val_ptr = cur_attr.val_ptr;
417 return 0;
418 }
419 } while (iter);
420
421 return -EIO;
422}
Boaz Harrosh06886a52009-11-08 14:54:08 +0200423
424int exofs_oi_truncate(struct exofs_i_info *oi, u64 size)
425{
426 struct exofs_sb_info *sbi = oi->vfs_inode.i_sb->s_fs_info;
427 struct exofs_io_state *ios;
428 struct osd_attr attr;
429 __be64 newsize;
430 int i, ret;
431
Boaz Harrosh45d3abc2010-01-28 11:46:16 +0200432 if (exofs_get_io_state(&sbi->layout, &ios))
Boaz Harrosh06886a52009-11-08 14:54:08 +0200433 return -ENOMEM;
434
435 ios->obj.id = exofs_oi_objno(oi);
436 ios->cred = oi->i_cred;
437
438 newsize = cpu_to_be64(size);
439 attr = g_attr_logical_length;
440 attr.val_ptr = &newsize;
441
Boaz Harrosh45d3abc2010-01-28 11:46:16 +0200442 for (i = 0; i < sbi->layout.s_numdevs; i++) {
Boaz Harrosh06886a52009-11-08 14:54:08 +0200443 struct osd_request *or;
444
Boaz Harrosh45d3abc2010-01-28 11:46:16 +0200445 or = osd_start_request(sbi->layout.s_ods[i], GFP_KERNEL);
Boaz Harrosh06886a52009-11-08 14:54:08 +0200446 if (unlikely(!or)) {
447 EXOFS_ERR("%s: osd_start_request failed\n", __func__);
448 ret = -ENOMEM;
449 goto out;
450 }
451 ios->per_dev[i].or = or;
452 ios->numdevs++;
453
454 osd_req_set_attributes(or, &ios->obj);
455 osd_req_add_set_attr_list(or, &attr, 1);
456 }
457 ret = exofs_io_execute(ios);
458
459out:
460 exofs_put_io_state(ios);
461 return ret;
462}