blob: 2b81f99fd62c2da67fef999eca350eaf2b65e689 [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
Boaz Harroshd9c740d2010-01-28 11:58:08 +0200110unsigned exofs_layout_od_id(struct exofs_layout *layout,
111 osd_id obj_no, unsigned layout_index)
112{
113 return layout_index;
114}
115
116static inline struct osd_dev *exofs_ios_od(struct exofs_io_state *ios,
117 unsigned layout_index)
118{
119 return ios->layout->s_ods[
120 exofs_layout_od_id(ios->layout, ios->obj.id, layout_index)];
121}
122
Boaz Harrosh06886a52009-11-08 14:54:08 +0200123static void _sync_done(struct exofs_io_state *ios, void *p)
124{
125 struct completion *waiting = p;
126
127 complete(waiting);
128}
129
130static void _last_io(struct kref *kref)
131{
132 struct exofs_io_state *ios = container_of(
133 kref, struct exofs_io_state, kref);
134
135 ios->done(ios, ios->private);
136}
137
138static void _done_io(struct osd_request *or, void *p)
139{
140 struct exofs_io_state *ios = p;
141
142 kref_put(&ios->kref, _last_io);
143}
144
145static int exofs_io_execute(struct exofs_io_state *ios)
146{
147 DECLARE_COMPLETION_ONSTACK(wait);
148 bool sync = (ios->done == NULL);
149 int i, ret;
150
151 if (sync) {
152 ios->done = _sync_done;
153 ios->private = &wait;
154 }
155
156 for (i = 0; i < ios->numdevs; i++) {
157 struct osd_request *or = ios->per_dev[i].or;
158 if (unlikely(!or))
159 continue;
160
161 ret = osd_finalize_request(or, 0, ios->cred, NULL);
162 if (unlikely(ret)) {
163 EXOFS_DBGMSG("Faild to osd_finalize_request() => %d\n",
164 ret);
165 return ret;
166 }
167 }
168
169 kref_init(&ios->kref);
170
171 for (i = 0; i < ios->numdevs; i++) {
172 struct osd_request *or = ios->per_dev[i].or;
173 if (unlikely(!or))
174 continue;
175
176 kref_get(&ios->kref);
177 osd_execute_request_async(or, _done_io, ios);
178 }
179
180 kref_put(&ios->kref, _last_io);
181 ret = 0;
182
183 if (sync) {
184 wait_for_completion(&wait);
185 ret = exofs_check_io(ios, NULL);
186 }
Boaz Harroshb14f8ab2008-10-27 18:27:55 +0200187 return ret;
188}
189
Boaz Harrosh22ddc552010-01-19 19:24:45 +0200190static void _clear_bio(struct bio *bio)
191{
192 struct bio_vec *bv;
193 unsigned i;
194
195 __bio_for_each_segment(bv, bio, i, 0) {
196 unsigned this_count = bv->bv_len;
197
198 if (likely(PAGE_SIZE == this_count))
199 clear_highpage(bv->bv_page);
200 else
201 zero_user(bv->bv_page, bv->bv_offset, this_count);
202 }
203}
204
Boaz Harrosh06886a52009-11-08 14:54:08 +0200205int exofs_check_io(struct exofs_io_state *ios, u64 *resid)
206{
207 enum osd_err_priority acumulated_osd_err = 0;
208 int acumulated_lin_err = 0;
209 int i;
210
211 for (i = 0; i < ios->numdevs; i++) {
212 struct osd_sense_info osi;
Boaz Harrosh22ddc552010-01-19 19:24:45 +0200213 struct osd_request *or = ios->per_dev[i].or;
214 int ret;
Boaz Harrosh06886a52009-11-08 14:54:08 +0200215
Boaz Harrosh22ddc552010-01-19 19:24:45 +0200216 if (unlikely(!or))
217 continue;
218
219 ret = osd_req_decode_sense(or, &osi);
Boaz Harrosh06886a52009-11-08 14:54:08 +0200220 if (likely(!ret))
221 continue;
222
Boaz Harrosh22ddc552010-01-19 19:24:45 +0200223 if (OSD_ERR_PRI_CLEAR_PAGES == osi.osd_err_pri) {
224 /* start read offset passed endof file */
225 _clear_bio(ios->per_dev[i].bio);
226 EXOFS_DBGMSG("start read offset passed end of file "
227 "offset=0x%llx, length=0x%llx\n",
228 _LLU(ios->offset),
229 _LLU(ios->length));
230
231 continue; /* we recovered */
Boaz Harrosh06886a52009-11-08 14:54:08 +0200232 }
233
234 if (osi.osd_err_pri >= acumulated_osd_err) {
235 acumulated_osd_err = osi.osd_err_pri;
236 acumulated_lin_err = ret;
237 }
238 }
239
240 /* TODO: raid specific residual calculations */
241 if (resid) {
242 if (likely(!acumulated_lin_err))
243 *resid = 0;
244 else
245 *resid = ios->length;
246 }
247
248 return acumulated_lin_err;
249}
250
251int exofs_sbi_create(struct exofs_io_state *ios)
252{
253 int i, ret;
254
Boaz Harrosh45d3abc2010-01-28 11:46:16 +0200255 for (i = 0; i < ios->layout->s_numdevs; i++) {
Boaz Harrosh06886a52009-11-08 14:54:08 +0200256 struct osd_request *or;
257
Boaz Harroshd9c740d2010-01-28 11:58:08 +0200258 or = osd_start_request(exofs_ios_od(ios, i), GFP_KERNEL);
Boaz Harrosh06886a52009-11-08 14:54:08 +0200259 if (unlikely(!or)) {
260 EXOFS_ERR("%s: osd_start_request failed\n", __func__);
261 ret = -ENOMEM;
262 goto out;
263 }
264 ios->per_dev[i].or = or;
265 ios->numdevs++;
266
267 osd_req_create_object(or, &ios->obj);
268 }
269 ret = exofs_io_execute(ios);
270
271out:
272 return ret;
273}
274
275int exofs_sbi_remove(struct exofs_io_state *ios)
276{
277 int i, ret;
278
Boaz Harrosh45d3abc2010-01-28 11:46:16 +0200279 for (i = 0; i < ios->layout->s_numdevs; i++) {
Boaz Harrosh06886a52009-11-08 14:54:08 +0200280 struct osd_request *or;
281
Boaz Harroshd9c740d2010-01-28 11:58:08 +0200282 or = osd_start_request(exofs_ios_od(ios, i), GFP_KERNEL);
Boaz Harrosh06886a52009-11-08 14:54:08 +0200283 if (unlikely(!or)) {
284 EXOFS_ERR("%s: osd_start_request failed\n", __func__);
285 ret = -ENOMEM;
286 goto out;
287 }
288 ios->per_dev[i].or = or;
289 ios->numdevs++;
290
291 osd_req_remove_object(or, &ios->obj);
292 }
293 ret = exofs_io_execute(ios);
294
295out:
296 return ret;
297}
298
299int exofs_sbi_write(struct exofs_io_state *ios)
300{
301 int i, ret;
302
Boaz Harrosh45d3abc2010-01-28 11:46:16 +0200303 for (i = 0; i < ios->layout->s_numdevs; i++) {
Boaz Harrosh06886a52009-11-08 14:54:08 +0200304 struct osd_request *or;
305
Boaz Harroshd9c740d2010-01-28 11:58:08 +0200306 or = osd_start_request(exofs_ios_od(ios, i), GFP_KERNEL);
Boaz Harrosh06886a52009-11-08 14:54:08 +0200307 if (unlikely(!or)) {
308 EXOFS_ERR("%s: osd_start_request failed\n", __func__);
309 ret = -ENOMEM;
310 goto out;
311 }
312 ios->per_dev[i].or = or;
313 ios->numdevs++;
314
315 if (ios->bio) {
316 struct bio *bio;
317
Boaz Harrosh04dc1e82009-11-16 16:03:05 +0200318 if (i != 0) {
319 bio = bio_kmalloc(GFP_KERNEL,
320 ios->bio->bi_max_vecs);
321 if (unlikely(!bio)) {
Boaz Harrosh34ce4e72009-12-15 19:34:17 +0200322 EXOFS_DBGMSG(
323 "Faild to allocate BIO size=%u\n",
324 ios->bio->bi_max_vecs);
Boaz Harrosh04dc1e82009-11-16 16:03:05 +0200325 ret = -ENOMEM;
326 goto out;
327 }
328
329 __bio_clone(bio, ios->bio);
330 bio->bi_bdev = NULL;
331 bio->bi_next = NULL;
332 ios->per_dev[i].bio = bio;
333 } else {
334 bio = ios->bio;
335 }
Boaz Harrosh06886a52009-11-08 14:54:08 +0200336
337 osd_req_write(or, &ios->obj, ios->offset, bio,
338 ios->length);
Boaz Harrosh34ce4e72009-12-15 19:34:17 +0200339 EXOFS_DBGMSG("write(0x%llx) offset=0x%llx "
340 "length=0x%llx dev=%d\n",
341 _LLU(ios->obj.id), _LLU(ios->offset),
342 _LLU(ios->length), i);
Boaz Harrosh06886a52009-11-08 14:54:08 +0200343 } else if (ios->kern_buff) {
344 osd_req_write_kern(or, &ios->obj, ios->offset,
345 ios->kern_buff, ios->length);
Boaz Harrosh34ce4e72009-12-15 19:34:17 +0200346 EXOFS_DBGMSG2("write_kern(0x%llx) offset=0x%llx "
347 "length=0x%llx dev=%d\n",
348 _LLU(ios->obj.id), _LLU(ios->offset),
349 _LLU(ios->length), i);
Boaz Harrosh06886a52009-11-08 14:54:08 +0200350 } else {
351 osd_req_set_attributes(or, &ios->obj);
Boaz Harrosh34ce4e72009-12-15 19:34:17 +0200352 EXOFS_DBGMSG2("obj(0x%llx) set_attributes=%d dev=%d\n",
353 _LLU(ios->obj.id), ios->out_attr_len, i);
Boaz Harrosh06886a52009-11-08 14:54:08 +0200354 }
355
356 if (ios->out_attr)
357 osd_req_add_set_attr_list(or, ios->out_attr,
358 ios->out_attr_len);
359
360 if (ios->in_attr)
361 osd_req_add_get_attr_list(or, ios->in_attr,
362 ios->in_attr_len);
363 }
364 ret = exofs_io_execute(ios);
365
366out:
367 return ret;
368}
369
370int exofs_sbi_read(struct exofs_io_state *ios)
371{
Boaz Harrosh46f4d972010-02-01 11:37:30 +0200372 struct osd_request *or;
373 struct exofs_per_dev_state *per_dev = &ios->per_dev[0];
374 unsigned first_dev = (unsigned)ios->obj.id;
Boaz Harrosh06886a52009-11-08 14:54:08 +0200375
Boaz Harrosh46f4d972010-02-01 11:37:30 +0200376 first_dev %= ios->layout->s_numdevs;
Boaz Harroshd9c740d2010-01-28 11:58:08 +0200377 or = osd_start_request(exofs_ios_od(ios, first_dev), GFP_KERNEL);
Boaz Harrosh46f4d972010-02-01 11:37:30 +0200378 if (unlikely(!or)) {
379 EXOFS_ERR("%s: osd_start_request failed\n", __func__);
380 return -ENOMEM;
Boaz Harrosh06886a52009-11-08 14:54:08 +0200381 }
Boaz Harrosh46f4d972010-02-01 11:37:30 +0200382 per_dev->or = or;
383 ios->numdevs++;
Boaz Harrosh06886a52009-11-08 14:54:08 +0200384
Boaz Harrosh46f4d972010-02-01 11:37:30 +0200385 if (ios->bio) {
386 osd_req_read(or, &ios->obj, ios->offset, ios->bio, ios->length);
387 EXOFS_DBGMSG("read(0x%llx) offset=0x%llx length=0x%llx"
388 " dev=%d\n", _LLU(ios->obj.id),
389 _LLU(ios->offset), _LLU(ios->length),
390 first_dev);
391 } else if (ios->kern_buff) {
392 int ret = osd_req_read_kern(or, &ios->obj, ios->offset,
393 ios->kern_buff, ios->length);
394
395 EXOFS_DBGMSG2("read_kern(0x%llx) offset=0x%llx "
396 "length=0x%llx dev=%d ret=>%d\n",
397 _LLU(ios->obj.id), _LLU(ios->offset),
398 _LLU(ios->length), first_dev, ret);
399 if (unlikely(ret))
400 return ret;
401 } else {
402 osd_req_get_attributes(or, &ios->obj);
403 EXOFS_DBGMSG2("obj(0x%llx) get_attributes=%d dev=%d\n",
404 _LLU(ios->obj.id), ios->in_attr_len, first_dev);
405 }
406
407 if (ios->out_attr)
408 osd_req_add_set_attr_list(or, ios->out_attr, ios->out_attr_len);
409
410 if (ios->in_attr)
411 osd_req_add_get_attr_list(or, ios->in_attr, ios->in_attr_len);
412
413 return exofs_io_execute(ios);
Boaz Harrosh06886a52009-11-08 14:54:08 +0200414}
415
416int extract_attr_from_ios(struct exofs_io_state *ios, struct osd_attr *attr)
Boaz Harroshb14f8ab2008-10-27 18:27:55 +0200417{
418 struct osd_attr cur_attr = {.attr_page = 0}; /* start with zeros */
419 void *iter = NULL;
420 int nelem;
421
422 do {
423 nelem = 1;
Boaz Harrosh06886a52009-11-08 14:54:08 +0200424 osd_req_decode_get_attr_list(ios->per_dev[0].or,
425 &cur_attr, &nelem, &iter);
Boaz Harroshb14f8ab2008-10-27 18:27:55 +0200426 if ((cur_attr.attr_page == attr->attr_page) &&
427 (cur_attr.attr_id == attr->attr_id)) {
428 attr->len = cur_attr.len;
429 attr->val_ptr = cur_attr.val_ptr;
430 return 0;
431 }
432 } while (iter);
433
434 return -EIO;
435}
Boaz Harrosh06886a52009-11-08 14:54:08 +0200436
437int exofs_oi_truncate(struct exofs_i_info *oi, u64 size)
438{
439 struct exofs_sb_info *sbi = oi->vfs_inode.i_sb->s_fs_info;
440 struct exofs_io_state *ios;
441 struct osd_attr attr;
442 __be64 newsize;
443 int i, ret;
444
Boaz Harrosh45d3abc2010-01-28 11:46:16 +0200445 if (exofs_get_io_state(&sbi->layout, &ios))
Boaz Harrosh06886a52009-11-08 14:54:08 +0200446 return -ENOMEM;
447
448 ios->obj.id = exofs_oi_objno(oi);
449 ios->cred = oi->i_cred;
450
451 newsize = cpu_to_be64(size);
452 attr = g_attr_logical_length;
453 attr.val_ptr = &newsize;
454
Boaz Harrosh45d3abc2010-01-28 11:46:16 +0200455 for (i = 0; i < sbi->layout.s_numdevs; i++) {
Boaz Harrosh06886a52009-11-08 14:54:08 +0200456 struct osd_request *or;
457
Boaz Harroshd9c740d2010-01-28 11:58:08 +0200458 or = osd_start_request(exofs_ios_od(ios, i), GFP_KERNEL);
Boaz Harrosh06886a52009-11-08 14:54:08 +0200459 if (unlikely(!or)) {
460 EXOFS_ERR("%s: osd_start_request failed\n", __func__);
461 ret = -ENOMEM;
462 goto out;
463 }
464 ios->per_dev[i].or = or;
465 ios->numdevs++;
466
467 osd_req_set_attributes(or, &ios->obj);
468 osd_req_add_set_attr_list(or, &attr, 1);
469 }
470 ret = exofs_io_execute(ios);
471
472out:
473 exofs_put_io_state(ios);
474 return ret;
475}