ore.c 30.4 KB
Newer Older
1
2
/*
 * Copyright (C) 2005, 2006
Boaz Harrosh's avatar
Boaz Harrosh committed
3
 * Avishay Traeger (avishay@gmail.com)
4
 * Copyright (C) 2008, 2009
5
 * Boaz Harrosh <ooo@electrozaur.com>
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 *
 * This file is part of exofs.
 *
 * exofs is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation.  Since it is based on ext2, and the only
 * valid version of GPL for the Linux kernel is version 2, the only valid
 * version of GPL for exofs is version 2.
 *
 * exofs is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with exofs; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

25
#include <linux/slab.h>
26
#include <linux/module.h>
Boaz Harrosh's avatar
Boaz Harrosh committed
27
#include <asm/div64.h>
Boaz Harrosh's avatar
Boaz Harrosh committed
28
#include <linux/lcm.h>
29

Boaz Harrosh's avatar
Boaz Harrosh committed
30
#include "ore_raid.h"
31

32
MODULE_AUTHOR("Boaz Harrosh <ooo@electrozaur.com>");
Boaz Harrosh's avatar
Boaz Harrosh committed
33
34
35
MODULE_DESCRIPTION("Objects Raid Engine ore.ko");
MODULE_LICENSE("GPL");

36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
/* ore_verify_layout does a couple of things:
 * 1. Given a minimum number of needed parameters fixes up the rest of the
 *    members to be operatonals for the ore. The needed parameters are those
 *    that are defined by the pnfs-objects layout STD.
 * 2. Check to see if the current ore code actually supports these parameters
 *    for example stripe_unit must be a multple of the system PAGE_SIZE,
 *    and etc...
 * 3. Cache some havily used calculations that will be needed by users.
 */

enum { BIO_MAX_PAGES_KMALLOC =
		(PAGE_SIZE - sizeof(struct bio)) / sizeof(struct bio_vec),};

int ore_verify_layout(unsigned total_comps, struct ore_layout *layout)
{
	u64 stripe_length;

Boaz Harrosh's avatar
Boaz Harrosh committed
53
54
55
56
57
58
59
60
	switch (layout->raid_algorithm) {
	case PNFS_OSD_RAID_0:
		layout->parity = 0;
		break;
	case PNFS_OSD_RAID_5:
		layout->parity = 1;
		break;
	case PNFS_OSD_RAID_PQ:
Boaz Harrosh's avatar
Boaz Harrosh committed
61
62
		layout->parity = 2;
		break;
Boaz Harrosh's avatar
Boaz Harrosh committed
63
64
	case PNFS_OSD_RAID_4:
	default:
Boaz Harrosh's avatar
Boaz Harrosh committed
65
66
		ORE_ERR("Only RAID_0/5/6 for now received-enum=%d\n",
			layout->raid_algorithm);
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
		return -EINVAL;
	}
	if (0 != (layout->stripe_unit & ~PAGE_MASK)) {
		ORE_ERR("Stripe Unit(0x%llx)"
			  " must be Multples of PAGE_SIZE(0x%lx)\n",
			  _LLU(layout->stripe_unit), PAGE_SIZE);
		return -EINVAL;
	}
	if (layout->group_width) {
		if (!layout->group_depth) {
			ORE_ERR("group_depth == 0 && group_width != 0\n");
			return -EINVAL;
		}
		if (total_comps < (layout->group_width * layout->mirrors_p1)) {
			ORE_ERR("Data Map wrong, "
				"numdevs=%d < group_width=%d * mirrors=%d\n",
				total_comps, layout->group_width,
				layout->mirrors_p1);
			return -EINVAL;
		}
		layout->group_count = total_comps / layout->mirrors_p1 /
						layout->group_width;
	} else {
		if (layout->group_depth) {
			printk(KERN_NOTICE "Warning: group_depth ignored "
				"group_width == 0 && group_depth == %lld\n",
				_LLU(layout->group_depth));
		}
		layout->group_width = total_comps / layout->mirrors_p1;
		layout->group_depth = -1;
		layout->group_count = 1;
	}

	stripe_length = (u64)layout->group_width * layout->stripe_unit;
	if (stripe_length >= (1ULL << 32)) {
		ORE_ERR("Stripe_length(0x%llx) >= 32bit is not supported\n",
			_LLU(stripe_length));
		return -EINVAL;
	}

	layout->max_io_length =
		(BIO_MAX_PAGES_KMALLOC * PAGE_SIZE - layout->stripe_unit) *
109
					(layout->group_width - layout->parity);
Boaz Harrosh's avatar
Boaz Harrosh committed
110
111
112
113
114
115
116
117
	if (layout->parity) {
		unsigned stripe_length =
				(layout->group_width - layout->parity) *
				layout->stripe_unit;

		layout->max_io_length /= stripe_length;
		layout->max_io_length *= stripe_length;
	}
Boaz Harrosh's avatar
Boaz Harrosh committed
118
119
	ORE_DBGMSG("max_io_length=0x%lx\n", layout->max_io_length);

120
121
122
123
	return 0;
}
EXPORT_SYMBOL(ore_verify_layout);

124
static u8 *_ios_cred(struct ore_io_state *ios, unsigned index)
125
{
126
	return ios->oc->comps[index & ios->oc->single_comp].cred;
127
128
}

129
static struct osd_obj_id *_ios_obj(struct ore_io_state *ios, unsigned index)
130
{
131
	return &ios->oc->comps[index & ios->oc->single_comp].obj;
132
133
}

134
static struct osd_dev *_ios_od(struct ore_io_state *ios, unsigned index)
135
{
136
137
138
139
	ORE_DBGMSG2("oc->first_dev=%d oc->numdevs=%d i=%d oc->ods=%p\n",
		    ios->oc->first_dev, ios->oc->numdevs, index,
		    ios->oc->ods);

140
	return ore_comp_dev(ios->oc, index);
141
142
}

Boaz Harrosh's avatar
Boaz Harrosh committed
143
int  _ore_get_io_state(struct ore_layout *layout,
Boaz Harrosh's avatar
Boaz Harrosh committed
144
145
146
			struct ore_components *oc, unsigned numdevs,
			unsigned sgs_per_dev, unsigned num_par_pages,
			struct ore_io_state **pios)
147
{
148
	struct ore_io_state *ios;
Kees Cook's avatar
Kees Cook committed
149
150
151
152
153
154
155
	size_t size_ios, size_extra, size_total;
	void *ios_extra;

	/*
	 * The desired layout looks like this, with the extra_allocation
	 * items pointed at from fields within ios or per_dev:

Boaz Harrosh's avatar
Boaz Harrosh committed
156
157
158
159
160
161
	struct __alloc_all_io_state {
		struct ore_io_state ios;
		struct ore_per_dev_state per_dev[numdevs];
		union {
			struct osd_sg_entry sglist[sgs_per_dev * numdevs];
			struct page *pages[num_par_pages];
Kees Cook's avatar
Kees Cook committed
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
		} extra_allocation;
	} whole_allocation;

	*/

	/* This should never happen, so abort early if it ever does. */
	if (sgs_per_dev && num_par_pages) {
		ORE_DBGMSG("Tried to use both pages and sglist\n");
		*pios = NULL;
		return -EINVAL;
	}

	if (numdevs > (INT_MAX - sizeof(*ios)) /
		       sizeof(struct ore_per_dev_state))
		return -ENOMEM;
	size_ios = sizeof(*ios) + sizeof(struct ore_per_dev_state) * numdevs;

	if (sgs_per_dev * numdevs > INT_MAX / sizeof(struct osd_sg_entry))
		return -ENOMEM;
	if (num_par_pages > INT_MAX / sizeof(struct page *))
		return -ENOMEM;
	size_extra = max(sizeof(struct osd_sg_entry) * (sgs_per_dev * numdevs),
			 sizeof(struct page *) * num_par_pages);

	size_total = size_ios + size_extra;

	if (likely(size_total <= PAGE_SIZE)) {
		ios = kzalloc(size_total, GFP_KERNEL);
		if (unlikely(!ios)) {
			ORE_DBGMSG("Failed kzalloc bytes=%zd\n", size_total);
Boaz Harrosh's avatar
Boaz Harrosh committed
192
193
194
			*pios = NULL;
			return -ENOMEM;
		}
Kees Cook's avatar
Kees Cook committed
195
		ios_extra = (char *)ios + size_ios;
Boaz Harrosh's avatar
Boaz Harrosh committed
196
	} else {
Kees Cook's avatar
Kees Cook committed
197
198
		ios = kzalloc(size_ios, GFP_KERNEL);
		if (unlikely(!ios)) {
Boaz Harrosh's avatar
Boaz Harrosh committed
199
			ORE_DBGMSG("Failed alloc first part bytes=%zd\n",
Kees Cook's avatar
Kees Cook committed
200
				   size_ios);
Boaz Harrosh's avatar
Boaz Harrosh committed
201
202
203
			*pios = NULL;
			return -ENOMEM;
		}
Kees Cook's avatar
Kees Cook committed
204
205
		ios_extra = kzalloc(size_extra, GFP_KERNEL);
		if (unlikely(!ios_extra)) {
Boaz Harrosh's avatar
Boaz Harrosh committed
206
			ORE_DBGMSG("Failed alloc second part bytes=%zd\n",
Kees Cook's avatar
Kees Cook committed
207
208
				   size_extra);
			kfree(ios);
Boaz Harrosh's avatar
Boaz Harrosh committed
209
210
211
			*pios = NULL;
			return -ENOMEM;
		}
212

Boaz Harrosh's avatar
Boaz Harrosh committed
213
214
215
216
217
218
		/* In this case the per_dev[0].sgilist holds the pointer to
		 * be freed
		 */
		ios->extra_part_alloc = true;
	}

Kees Cook's avatar
Kees Cook committed
219
220
	if (num_par_pages) {
		ios->parity_pages = ios_extra;
Boaz Harrosh's avatar
Boaz Harrosh committed
221
222
		ios->max_par_pages = num_par_pages;
	}
Kees Cook's avatar
Kees Cook committed
223
224
	if (sgs_per_dev) {
		struct osd_sg_entry *sgilist = ios_extra;
Boaz Harrosh's avatar
Boaz Harrosh committed
225
226
227
228
229
230
231
		unsigned d;

		for (d = 0; d < numdevs; ++d) {
			ios->per_dev[d].sglist = sgilist;
			sgilist += sgs_per_dev;
		}
		ios->sgs_per_dev = sgs_per_dev;
232
233
	}

234
	ios->layout = layout;
235
	ios->oc = oc;
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
	*pios = ios;
	return 0;
}

/* Allocate an io_state for only a single group of devices
 *
 * If a user needs to call ore_read/write() this version must be used becase it
 * allocates extra stuff for striping and raid.
 * The ore might decide to only IO less then @length bytes do to alignmets
 * and constrains as follows:
 * - The IO cannot cross group boundary.
 * - In raid5/6 The end of the IO must align at end of a stripe eg.
 *   (@offset + @length) % strip_size == 0. Or the complete range is within a
 *   single stripe.
 * - Memory condition only permitted a shorter IO. (A user can use @length=~0
 *   And check the returned ios->length for max_io_size.)
 *
 * The caller must check returned ios->length (and/or ios->nr_pages) and
 * re-issue these pages that fall outside of ios->length
 */
int  ore_get_rw_state(struct ore_layout *layout, struct ore_components *oc,
		      bool is_reading, u64 offset, u64 length,
		      struct ore_io_state **pios)
{
	struct ore_io_state *ios;
	unsigned numdevs = layout->group_width * layout->mirrors_p1;
Boaz Harrosh's avatar
Boaz Harrosh committed
262
	unsigned sgs_per_dev = 0, max_par_pages = 0;
263
264
	int ret;

Boaz Harrosh's avatar
Boaz Harrosh committed
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
	if (layout->parity && length) {
		unsigned data_devs = layout->group_width - layout->parity;
		unsigned stripe_size = layout->stripe_unit * data_devs;
		unsigned pages_in_unit = layout->stripe_unit / PAGE_SIZE;
		u32 remainder;
		u64 num_stripes;
		u64 num_raid_units;

		num_stripes = div_u64_rem(length, stripe_size, &remainder);
		if (remainder)
			++num_stripes;

		num_raid_units =  num_stripes * layout->parity;

		if (is_reading) {
			/* For reads add per_dev sglist array */
			/* TODO: Raid 6 we need twice more. Actually:
			*         num_stripes / LCMdP(W,P);
			*         if (W%P != 0) num_stripes *= parity;
			*/

			/* first/last seg is split */
			num_raid_units += layout->group_width;
288
			sgs_per_dev = div_u64(num_raid_units, data_devs) + 2;
Boaz Harrosh's avatar
Boaz Harrosh committed
289
290
291
292
293
294
295
296
297
		} else {
			/* For Writes add parity pages array. */
			max_par_pages = num_raid_units * pages_in_unit *
						sizeof(struct page *);
		}
	}

	ret = _ore_get_io_state(layout, oc, numdevs, sgs_per_dev, max_par_pages,
				pios);
298
299
300
301
	if (unlikely(ret))
		return ret;

	ios = *pios;
302
	ios->reading = is_reading;
303
304
305
	ios->offset = offset;

	if (length) {
Boaz Harrosh's avatar
Boaz Harrosh committed
306
307
		ore_calc_stripe_info(layout, offset, length, &ios->si);
		ios->length = ios->si.length;
308
309
		ios->nr_pages = ((ios->offset & (PAGE_SIZE - 1)) +
				 ios->length + PAGE_SIZE - 1) / PAGE_SIZE;
Boaz Harrosh's avatar
Boaz Harrosh committed
310
311
		if (layout->parity)
			_ore_post_alloc_raid_stuff(ios);
312
	}
313

314
	return 0;
315
}
Boaz Harrosh's avatar
Boaz Harrosh committed
316
EXPORT_SYMBOL(ore_get_rw_state);
317

318
319
320
321
322
323
324
/* Allocate an io_state for all the devices in the comps array
 *
 * This version of io_state allocation is used mostly by create/remove
 * and trunc where we currently need all the devices. The only wastful
 * bit is the read/write_attributes with no IO. Those sites should
 * be converted to use ore_get_rw_state() with length=0
 */
325
int  ore_get_io_state(struct ore_layout *layout, struct ore_components *oc,
326
		      struct ore_io_state **pios)
327
{
Boaz Harrosh's avatar
Boaz Harrosh committed
328
	return _ore_get_io_state(layout, oc, oc->numdevs, 0, 0, pios);
329
}
Boaz Harrosh's avatar
Boaz Harrosh committed
330
EXPORT_SYMBOL(ore_get_io_state);
331

332
void ore_put_io_state(struct ore_io_state *ios)
333
{
334
335
	if (ios) {
		unsigned i;
336

337
		for (i = 0; i < ios->numdevs; i++) {
338
			struct ore_per_dev_state *per_dev = &ios->per_dev[i];
339
340
341
342
343
344
345

			if (per_dev->or)
				osd_end_request(per_dev->or);
			if (per_dev->bio)
				bio_put(per_dev->bio);
		}

Boaz Harrosh's avatar
Boaz Harrosh committed
346
		_ore_free_raid_stuff(ios);
347
		kfree(ios);
348
	}
349
}
Boaz Harrosh's avatar
Boaz Harrosh committed
350
EXPORT_SYMBOL(ore_put_io_state);
351

352
static void _sync_done(struct ore_io_state *ios, void *p)
353
354
{
	struct completion *waiting = p;
355

356
357
358
359
360
	complete(waiting);
}

static void _last_io(struct kref *kref)
{
361
362
	struct ore_io_state *ios = container_of(
					kref, struct ore_io_state, kref);
363
364
365
366
367
368

	ios->done(ios, ios->private);
}

static void _done_io(struct osd_request *or, void *p)
{
369
	struct ore_io_state *ios = p;
370
371
372
373

	kref_put(&ios->kref, _last_io);
}

Boaz Harrosh's avatar
Boaz Harrosh committed
374
int ore_io_execute(struct ore_io_state *ios)
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
{
	DECLARE_COMPLETION_ONSTACK(wait);
	bool sync = (ios->done == NULL);
	int i, ret;

	if (sync) {
		ios->done = _sync_done;
		ios->private = &wait;
	}

	for (i = 0; i < ios->numdevs; i++) {
		struct osd_request *or = ios->per_dev[i].or;
		if (unlikely(!or))
			continue;

390
		ret = osd_finalize_request(or, 0, _ios_cred(ios, i), NULL);
391
		if (unlikely(ret)) {
392
			ORE_DBGMSG("Failed to osd_finalize_request() => %d\n",
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
				     ret);
			return ret;
		}
	}

	kref_init(&ios->kref);

	for (i = 0; i < ios->numdevs; i++) {
		struct osd_request *or = ios->per_dev[i].or;
		if (unlikely(!or))
			continue;

		kref_get(&ios->kref);
		osd_execute_request_async(or, _done_io, ios);
	}

	kref_put(&ios->kref, _last_io);
	ret = 0;

	if (sync) {
		wait_for_completion(&wait);
414
		ret = ore_check_io(ios, NULL);
415
	}
416
417
418
	return ret;
}

419
420
421
422
423
static void _clear_bio(struct bio *bio)
{
	struct bio_vec *bv;
	unsigned i;

424
	bio_for_each_segment_all(bv, bio, i) {
425
426
427
428
429
430
431
432
433
		unsigned this_count = bv->bv_len;

		if (likely(PAGE_SIZE == this_count))
			clear_highpage(bv->bv_page);
		else
			zero_user(bv->bv_page, bv->bv_offset, this_count);
	}
}

434
int ore_check_io(struct ore_io_state *ios, ore_on_dev_error on_dev_error)
435
{
436
437
438
	enum osd_err_priority acumulated_osd_err = 0;
	int acumulated_lin_err = 0;
	int i;
439

440
441
	for (i = 0; i < ios->numdevs; i++) {
		struct osd_sense_info osi;
442
443
		struct ore_per_dev_state *per_dev = &ios->per_dev[i];
		struct osd_request *or = per_dev->or;
444
445
446
447
		int ret;

		if (unlikely(!or))
			continue;
448

449
		ret = osd_req_decode_sense(or, &osi);
450
451
452
		if (likely(!ret))
			continue;

453
454
455
456
457
458
		if ((OSD_ERR_PRI_CLEAR_PAGES == osi.osd_err_pri) &&
		    per_dev->bio) {
			/* start read offset passed endof file.
			 * Note: if we do not have bio it means read-attributes
			 * In this case we should return error to caller.
			 */
459
			_clear_bio(per_dev->bio);
460
			ORE_DBGMSG("start read offset passed end of file "
461
				"offset=0x%llx, length=0x%llx\n",
462
463
				_LLU(per_dev->offset),
				_LLU(per_dev->length));
464
465

			continue; /* we recovered */
466
467
		}

468
469
470
471
		if (on_dev_error) {
			u64 residual = ios->reading ?
					or->in.residual : or->out.residual;
			u64 offset = (ios->offset + ios->length) - residual;
472
473
			unsigned dev = per_dev->dev - ios->oc->first_dev;
			struct ore_dev *od = ios->oc->ods[dev];
474

475
			on_dev_error(ios, od, dev, osi.osd_err_pri,
476
477
				     offset, residual);
		}
478
479
480
481
482
483
484
485
		if (osi.osd_err_pri >= acumulated_osd_err) {
			acumulated_osd_err = osi.osd_err_pri;
			acumulated_lin_err = ret;
		}
	}

	return acumulated_lin_err;
}
Boaz Harrosh's avatar
Boaz Harrosh committed
486
EXPORT_SYMBOL(ore_check_io);
487

Boaz Harrosh's avatar
Boaz Harrosh committed
488
489
490
/*
 * L - logical offset into the file
 *
Boaz Harrosh's avatar
Boaz Harrosh committed
491
492
 * D - number of Data devices
 *	D = group_width - parity
Boaz Harrosh's avatar
Boaz Harrosh committed
493
 *
Boaz Harrosh's avatar
Boaz Harrosh committed
494
495
 * U - The number of bytes in a stripe within a group
 *	U =  stripe_unit * D
Boaz Harrosh's avatar
Boaz Harrosh committed
496
 *
Boaz Harrosh's avatar
Boaz Harrosh committed
497
498
 * T - The number of bytes striped within a group of component objects
 *     (before advancing to the next group)
Boaz Harrosh's avatar
Boaz Harrosh committed
499
 *	T = U * group_depth
Boaz Harrosh's avatar
Boaz Harrosh committed
500
501
502
 *
 * S - The number of bytes striped across all component objects
 *     before the pattern repeats
Boaz Harrosh's avatar
Boaz Harrosh committed
503
 *	S = T * group_count
Boaz Harrosh's avatar
Boaz Harrosh committed
504
 *
Boaz Harrosh's avatar
Boaz Harrosh committed
505
 * M - The "major" (i.e., across all components) cycle number
Boaz Harrosh's avatar
Boaz Harrosh committed
506
507
 *	M = L / S
 *
Boaz Harrosh's avatar
Boaz Harrosh committed
508
 * G - Counts the groups from the beginning of the major cycle
Boaz Harrosh's avatar
Boaz Harrosh committed
509
510
511
512
513
514
515
 *	G = (L - (M * S)) / T	[or (L % S) / T]
 *
 * H - The byte offset within the group
 *	H = (L - (M * S)) % T	[or (L % S) % T]
 *
 * N - The "minor" (i.e., across the group) stripe number
 *	N = H / U
Boaz Harrosh's avatar
Boaz Harrosh committed
516
517
518
 *
 * C - The component index coresponding to L
 *
Boaz Harrosh's avatar
Boaz Harrosh committed
519
520
 *	C = (H - (N * U)) / stripe_unit + G * D
 *	[or (L % U) / stripe_unit + G * D]
Boaz Harrosh's avatar
Boaz Harrosh committed
521
522
 *
 * O - The component offset coresponding to L
Boaz Harrosh's avatar
Boaz Harrosh committed
523
 *	O = L % stripe_unit + N * stripe_unit + M * group_depth * stripe_unit
Boaz Harrosh's avatar
Boaz Harrosh committed
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
 *
 * LCMdP – Parity cycle: Lowest Common Multiple of group_width, parity
 *          divide by parity
 *	LCMdP = lcm(group_width, parity) / parity
 *
 * R - The parity Rotation stripe
 *     (Note parity cycle always starts at a group's boundary)
 *	R = N % LCMdP
 *
 * I = the first parity device index
 *	I = (group_width + group_width - R*parity - parity) % group_width
 *
 * Craid - The component index Rotated
 *	Craid = (group_width + C - R*parity) % group_width
 *      (We add the group_width to avoid negative numbers modulo math)
Boaz Harrosh's avatar
Boaz Harrosh committed
539
 */
540
void ore_calc_stripe_info(struct ore_layout *layout, u64 file_offset,
Boaz Harrosh's avatar
Boaz Harrosh committed
541
			  u64 length, struct ore_striping_info *si)
Boaz Harrosh's avatar
Boaz Harrosh committed
542
{
543
544
545
	u32	stripe_unit = layout->stripe_unit;
	u32	group_width = layout->group_width;
	u64	group_depth = layout->group_depth;
Boaz Harrosh's avatar
Boaz Harrosh committed
546
	u32	parity      = layout->parity;
Boaz Harrosh's avatar
Boaz Harrosh committed
547

Boaz Harrosh's avatar
Boaz Harrosh committed
548
549
	u32	D = group_width - parity;
	u32	U = D * stripe_unit;
Boaz Harrosh's avatar
Boaz Harrosh committed
550
	u64	T = U * group_depth;
551
	u64	S = T * layout->group_count;
Boaz Harrosh's avatar
Boaz Harrosh committed
552
553
554
555
556
557
558
559
560
561
562
	u64	M = div64_u64(file_offset, S);

	/*
	G = (L - (M * S)) / T
	H = (L - (M * S)) % T
	*/
	u64	LmodS = file_offset - M * S;
	u32	G = div64_u64(LmodS, T);
	u64	H = LmodS - G * T;

	u32	N = div_u64(H, U);
563
	u32	Nlast;
Boaz Harrosh's avatar
Boaz Harrosh committed
564
565

	/* "H - (N * U)" is just "H % U" so it's bound to u32 */
Boaz Harrosh's avatar
Boaz Harrosh committed
566
	u32	C = (u32)(H - (N * U)) / stripe_unit + G * group_width;
567
	u32 first_dev = C - C % group_width;
Boaz Harrosh's avatar
Boaz Harrosh committed
568

Boaz Harrosh's avatar
Boaz Harrosh committed
569
	div_u64_rem(file_offset, stripe_unit, &si->unit_off);
Boaz Harrosh's avatar
Boaz Harrosh committed
570

Boaz Harrosh's avatar
Boaz Harrosh committed
571
572
	si->obj_offset = si->unit_off + (N * stripe_unit) +
				  (M * group_depth * stripe_unit);
573
574
	si->cur_comp = C - first_dev;
	si->cur_pg = si->unit_off / PAGE_SIZE;
Boaz Harrosh's avatar
Boaz Harrosh committed
575

Boaz Harrosh's avatar
Boaz Harrosh committed
576
577
578
579
580
581
582
	if (parity) {
		u32 LCMdP = lcm(group_width, parity) / parity;
		/* R     = N % LCMdP; */
		u32 RxP   = (N % LCMdP) * parity;

		si->par_dev = (group_width + group_width - parity - RxP) %
			      group_width + first_dev;
Boaz Harrosh's avatar
Boaz Harrosh committed
583
584
		si->dev = (group_width + group_width + C - RxP) %
			  group_width + first_dev;
Boaz Harrosh's avatar
Boaz Harrosh committed
585
586
587
588
589
590
591
592
593
594
595
596
597
598
		si->bytes_in_stripe = U;
		si->first_stripe_start = M * S + G * T + N * U;
	} else {
		/* Make the math correct see _prepare_one_group */
		si->par_dev = group_width;
		si->dev = C;
	}

	si->dev *= layout->mirrors_p1;
	si->par_dev *= layout->mirrors_p1;
	si->offset = file_offset;
	si->length = T - H;
	if (si->length > length)
		si->length = length;
599
600
601
602

	Nlast = div_u64(H + si->length + U - 1, U);
	si->maxdevUnits = Nlast - N;

603
	si->M = M;
Boaz Harrosh's avatar
Boaz Harrosh committed
604
}
605
EXPORT_SYMBOL(ore_calc_stripe_info);
Boaz Harrosh's avatar
Boaz Harrosh committed
606

Boaz Harrosh's avatar
Boaz Harrosh committed
607
608
609
int _ore_add_stripe_unit(struct ore_io_state *ios,  unsigned *cur_pg,
			 unsigned pgbase, struct page **pages,
			 struct ore_per_dev_state *per_dev, int cur_len)
Boaz Harrosh's avatar
Boaz Harrosh committed
610
{
611
	unsigned pg = *cur_pg;
Boaz Harrosh's avatar
Boaz Harrosh committed
612
	struct request_queue *q =
613
			osd_request_queue(_ios_od(ios, per_dev->dev));
614
615
	unsigned len = cur_len;
	int ret;
Boaz Harrosh's avatar
Boaz Harrosh committed
616
617

	if (per_dev->bio == NULL) {
618
619
620
621
622
623
624
625
626
627
		unsigned bio_size;

		if (!ios->reading) {
			bio_size = ios->si.maxdevUnits;
		} else {
			bio_size = (ios->si.maxdevUnits + 1) *
			     (ios->layout->group_width - ios->layout->parity) /
			     ios->layout->group_width;
		}
		bio_size *= (ios->layout->stripe_unit / PAGE_SIZE);
Boaz Harrosh's avatar
Boaz Harrosh committed
628
629
630

		per_dev->bio = bio_kmalloc(GFP_KERNEL, bio_size);
		if (unlikely(!per_dev->bio)) {
631
			ORE_DBGMSG("Failed to allocate BIO size=%u\n",
Boaz Harrosh's avatar
Boaz Harrosh committed
632
				     bio_size);
633
634
			ret = -ENOMEM;
			goto out;
Boaz Harrosh's avatar
Boaz Harrosh committed
635
636
637
638
		}
	}

	while (cur_len > 0) {
639
640
		unsigned pglen = min_t(unsigned, PAGE_SIZE - pgbase, cur_len);
		unsigned added_len;
Boaz Harrosh's avatar
Boaz Harrosh committed
641

642
		cur_len -= pglen;
Boaz Harrosh's avatar
Boaz Harrosh committed
643

Boaz Harrosh's avatar
Boaz Harrosh committed
644
		added_len = bio_add_pc_page(q, per_dev->bio, pages[pg],
645
					    pglen, pgbase);
646
		if (unlikely(pglen != added_len)) {
647
648
649
650
651
652
			/* If bi_vcnt == bi_max then this is a SW BUG */
			ORE_DBGMSG("Failed bio_add_pc_page bi_vcnt=0x%x "
				   "bi_max=0x%x BIO_MAX=0x%x cur_len=0x%x\n",
				   per_dev->bio->bi_vcnt,
				   per_dev->bio->bi_max_vecs,
				   BIO_MAX_PAGES_KMALLOC, cur_len);
653
654
655
			ret = -ENOMEM;
			goto out;
		}
Boaz Harrosh's avatar
Boaz Harrosh committed
656
657
		_add_stripe_page(ios->sp2d, &ios->si, pages[pg]);

658
659
		pgbase = 0;
		++pg;
Boaz Harrosh's avatar
Boaz Harrosh committed
660
661
662
	}
	BUG_ON(cur_len);

663
	per_dev->length += len;
664
	*cur_pg = pg;
665
666
667
668
669
670
671
	ret = 0;
out:	/* we fail the complete unit on an error eg don't advance
	 * per_dev->length and cur_pg. This means that we might have a bigger
	 * bio than the CDB requested length (per_dev->length). That's fine
	 * only the oposite is fatal.
	 */
	return ret;
Boaz Harrosh's avatar
Boaz Harrosh committed
672
673
}

Boaz Harrosh's avatar
Boaz Harrosh committed
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
static int _add_parity_units(struct ore_io_state *ios,
			     struct ore_striping_info *si,
			     unsigned dev, unsigned first_dev,
			     unsigned mirrors_p1, unsigned devs_in_group,
			     unsigned cur_len)
{
	unsigned do_parity;
	int ret = 0;

	for (do_parity = ios->layout->parity; do_parity; --do_parity) {
		struct ore_per_dev_state *per_dev;

		per_dev = &ios->per_dev[dev - first_dev];
		if (!per_dev->length && !per_dev->offset) {
			/* Only/always the parity unit of the first
			 * stripe will be empty. So this is a chance to
			 * initialize the per_dev info.
			 */
			per_dev->dev = dev;
			per_dev->offset = si->obj_offset - si->unit_off;
		}

		ret = _ore_add_parity_unit(ios, si, per_dev, cur_len,
					   do_parity == 1);
		if (unlikely(ret))
				break;

		if (do_parity != 1) {
			dev = ((dev + mirrors_p1) % devs_in_group) + first_dev;
			si->cur_comp = (si->cur_comp + 1) %
						       ios->layout->group_width;
		}
	}

	return ret;
}

711
static int _prepare_for_striping(struct ore_io_state *ios)
Boaz Harrosh's avatar
Boaz Harrosh committed
712
{
713
	struct ore_striping_info *si = &ios->si;
Boaz Harrosh's avatar
Boaz Harrosh committed
714
	unsigned stripe_unit = ios->layout->stripe_unit;
Boaz Harrosh's avatar
Boaz Harrosh committed
715
	unsigned mirrors_p1 = ios->layout->mirrors_p1;
Boaz Harrosh's avatar
Boaz Harrosh committed
716
717
	unsigned group_width = ios->layout->group_width;
	unsigned devs_in_group = group_width * mirrors_p1;
Boaz Harrosh's avatar
Boaz Harrosh committed
718
	unsigned dev = si->dev;
Boaz Harrosh's avatar
Boaz Harrosh committed
719
720
	unsigned first_dev = dev - (dev % devs_in_group);
	unsigned cur_pg = ios->pages_consumed;
721
	u64 length = ios->length;
722
	int ret = 0;
Boaz Harrosh's avatar
Boaz Harrosh committed
723

724
725
726
727
728
	if (!ios->pages) {
		ios->numdevs = ios->layout->mirrors_p1;
		return 0;
	}

Boaz Harrosh's avatar
Boaz Harrosh committed
729
730
	BUG_ON(length > si->length);

Boaz Harrosh's avatar
Boaz Harrosh committed
731
	while (length) {
732
733
		struct ore_per_dev_state *per_dev =
						&ios->per_dev[dev - first_dev];
Boaz Harrosh's avatar
Boaz Harrosh committed
734
		unsigned cur_len, page_off = 0;
Boaz Harrosh's avatar
Boaz Harrosh committed
735

Boaz Harrosh's avatar
Boaz Harrosh committed
736
737
		if (!per_dev->length && !per_dev->offset) {
			/* First time initialize the per_dev info. */
Boaz Harrosh's avatar
Boaz Harrosh committed
738
			per_dev->dev = dev;
Boaz Harrosh's avatar
Boaz Harrosh committed
739
740
			if (dev == si->dev) {
				WARN_ON(dev == si->par_dev);
Boaz Harrosh's avatar
Boaz Harrosh committed
741
742
743
744
				per_dev->offset = si->obj_offset;
				cur_len = stripe_unit - si->unit_off;
				page_off = si->unit_off & ~PAGE_MASK;
				BUG_ON(page_off && (page_off != ios->pgbase));
Boaz Harrosh's avatar
Boaz Harrosh committed
745
			} else {
Boaz Harrosh's avatar
Boaz Harrosh committed
746
				per_dev->offset = si->obj_offset - si->unit_off;
Boaz Harrosh's avatar
Boaz Harrosh committed
747
748
				cur_len = stripe_unit;
			}
Boaz Harrosh's avatar
Boaz Harrosh committed
749
		} else {
Boaz Harrosh's avatar
Boaz Harrosh committed
750
			cur_len = stripe_unit;
Boaz Harrosh's avatar
Boaz Harrosh committed
751
		}
Boaz Harrosh's avatar
Boaz Harrosh committed
752
753
		if (cur_len >= length)
			cur_len = length;
Boaz Harrosh's avatar
Boaz Harrosh committed
754

Boaz Harrosh's avatar
Boaz Harrosh committed
755
756
		ret = _ore_add_stripe_unit(ios, &cur_pg, page_off, ios->pages,
					   per_dev, cur_len);
Boaz Harrosh's avatar
Boaz Harrosh committed
757
758
759
760
		if (unlikely(ret))
			goto out;

		length -= cur_len;
Boaz Harrosh's avatar
Boaz Harrosh committed
761

762
		dev = ((dev + mirrors_p1) % devs_in_group) + first_dev;
Boaz Harrosh's avatar
Boaz Harrosh committed
763
		si->cur_comp = (si->cur_comp + 1) % group_width;
Boaz Harrosh's avatar
Boaz Harrosh committed
764
765
		if (unlikely((dev == si->par_dev) || (!length && ios->sp2d))) {
			if (!length && ios->sp2d) {
Boaz Harrosh's avatar
Boaz Harrosh committed
766
767
768
769
				/* If we are writing and this is the very last
				 * stripe. then operate on parity dev.
				 */
				dev = si->par_dev;
770
771
				/* If last stripe operate on parity comp */
				si->cur_comp = group_width - ios->layout->parity;
Boaz Harrosh's avatar
Boaz Harrosh committed
772
			}
Boaz Harrosh's avatar
Boaz Harrosh committed
773

774
775
776
			/* In writes cur_len just means if it's the
			 * last one. See _ore_add_parity_unit.
			 */
Boaz Harrosh's avatar
Boaz Harrosh committed
777
778
			ret = _add_parity_units(ios, si, dev, first_dev,
						mirrors_p1, devs_in_group,
779
						ios->sp2d ? length : cur_len);
Boaz Harrosh's avatar
Boaz Harrosh committed
780
781
782
783
784
785
786
787
788
			if (unlikely(ret))
					goto out;

			/* Rotate next par_dev backwards with wraping */
			si->par_dev = (devs_in_group + si->par_dev -
				       ios->layout->parity * mirrors_p1) %
				      devs_in_group + first_dev;
			/* Next stripe, start fresh */
			si->cur_comp = 0;
Boaz Harrosh's avatar
Boaz Harrosh committed
789
			si->cur_pg = 0;
Boaz Harrosh's avatar
Boaz Harrosh committed
790
791
			si->obj_offset += cur_len;
			si->unit_off = 0;
Boaz Harrosh's avatar
Boaz Harrosh committed
792
		}
Boaz Harrosh's avatar
Boaz Harrosh committed
793
794
	}
out:
795
	ios->numdevs = devs_in_group;
Boaz Harrosh's avatar
Boaz Harrosh committed
796
	ios->pages_consumed = cur_pg;
797
	return ret;
Boaz Harrosh's avatar
Boaz Harrosh committed
798
799
}

800
int ore_create(struct ore_io_state *ios)
801
802
803
{
	int i, ret;

804
	for (i = 0; i < ios->oc->numdevs; i++) {
805
806
		struct osd_request *or;

807
		or = osd_start_request(_ios_od(ios, i));
808
		if (unlikely(!or)) {
809
			ORE_ERR("%s: osd_start_request failed\n", __func__);
810
811
812
813
814
815
			ret = -ENOMEM;
			goto out;
		}
		ios->per_dev[i].or = or;
		ios->numdevs++;

816
		osd_req_create_object(or, _ios_obj(ios, i));
817
	}
818
	ret = ore_io_execute(ios);
819
820
821
822

out:
	return ret;
}
Boaz Harrosh's avatar
Boaz Harrosh committed
823
EXPORT_SYMBOL(ore_create);
824

825
int ore_remove(struct ore_io_state *ios)
826
827
828
{
	int i, ret;

829
	for (i = 0; i < ios->oc->numdevs; i++) {
830
831
		struct osd_request *or;

832
		or = osd_start_request(_ios_od(ios, i));
833
		if (unlikely(!or)) {
834
			ORE_ERR("%s: osd_start_request failed\n", __func__);
835
836
837
838
839
840
			ret = -ENOMEM;
			goto out;
		}
		ios->per_dev[i].or = or;
		ios->numdevs++;

841
		osd_req_remove_object(or, _ios_obj(ios, i));
842
	}
843
	ret = ore_io_execute(ios);
844
845
846
847

out:
	return ret;
}
Boaz Harrosh's avatar
Boaz Harrosh committed
848
EXPORT_SYMBOL(ore_remove);
849

850
static int _write_mirror(struct ore_io_state *ios, int cur_comp)
851
{
852
	struct ore_per_dev_state *master_dev = &ios->per_dev[cur_comp];
Boaz Harrosh's avatar
Boaz Harrosh committed
853
854
855
	unsigned dev = ios->per_dev[cur_comp].dev;
	unsigned last_comp = cur_comp + ios->layout->mirrors_p1;
	int ret = 0;
856

Boaz Harrosh's avatar
Boaz Harrosh committed
857
858
859
	if (ios->pages && !master_dev->length)
		return 0; /* Just an empty slot */

Boaz Harrosh's avatar
Boaz Harrosh committed
860
	for (; cur_comp < last_comp; ++cur_comp, ++dev) {
861
		struct ore_per_dev_state *per_dev = &ios->per_dev[cur_comp];
862
863
		struct osd_request *or;

864
		or = osd_start_request(_ios_od(ios, dev));
865
		if (unlikely(!or)) {
866
			ORE_ERR("%s: osd_start_request failed\n", __func__);
867
868
869
			ret = -ENOMEM;
			goto out;
		}
Boaz Harrosh's avatar
Boaz Harrosh committed
870
		per_dev->or = or;
871

872
		if (ios->pages) {
873
874
			struct bio *bio;

Boaz Harrosh's avatar
Boaz Harrosh committed
875
			if (per_dev != master_dev) {
876
877
				bio = bio_clone_kmalloc(master_dev->bio,
							GFP_KERNEL);
878
				if (unlikely(!bio)) {
879
					ORE_DBGMSG(
Paul Bolle's avatar
Paul Bolle committed
880
					      "Failed to allocate BIO size=%u\n",
Boaz Harrosh's avatar
Boaz Harrosh committed
881
					      master_dev->bio->bi_max_vecs);
882
883
884
885
					ret = -ENOMEM;
					goto out;
				}

886
				bio->bi_disk = NULL;
887
				bio->bi_next = NULL;
888
				per_dev->offset = master_dev->offset;
Boaz Harrosh's avatar
Boaz Harrosh committed
889
890
891
				per_dev->length = master_dev->length;
				per_dev->bio =  bio;
				per_dev->dev = dev;
892
			} else {
Boaz Harrosh's avatar
Boaz Harrosh committed
893
894
				bio = master_dev->bio;
				/* FIXME: bio_set_dir() */
895
				bio_set_op_attrs(bio, REQ_OP_WRITE, 0);
896
			}
897

898
899
			osd_req_write(or, _ios_obj(ios, cur_comp),
				      per_dev->offset, bio, per_dev->length);
900
			ORE_DBGMSG("write(0x%llx) offset=0x%llx "
Boaz Harrosh's avatar
Boaz Harrosh committed
901
				      "length=0x%llx dev=%d\n",
902
				     _LLU(_ios_obj(ios, cur_comp)->id),
903
				     _LLU(per_dev->offset),
Boaz Harrosh's avatar
Boaz Harrosh committed
904
				     _LLU(per_dev->length), dev);
905
		} else if (ios->kern_buff) {
906
907
908
909
910
911
912
913
			per_dev->offset = ios->si.obj_offset;
			per_dev->dev = ios->si.dev + dev;

			/* no cross device without page array */
			BUG_ON((ios->layout->group_width > 1) &&
			       (ios->si.unit_off + ios->length >
				ios->layout->stripe_unit));

914
			ret = osd_req_write_kern(or, _ios_obj(ios, cur_comp),
915
916
						 per_dev->offset,
						 ios->kern_buff, ios->length);
Boaz Harrosh's avatar
Boaz Harrosh committed
917
918
			if (unlikely(ret))
				goto out;
919
			ORE_DBGMSG2("write_kern(0x%llx) offset=0x%llx "
Boaz Harrosh's avatar
Boaz Harrosh committed
920
				      "length=0x%llx dev=%d\n",
921
				     _LLU(_ios_obj(ios, cur_comp)->id),
922
				     _LLU(per_dev->offset),
923
				     _LLU(ios->length), per_dev->dev);
924
		} else {
925
			osd_req_set_attributes(or, _ios_obj(ios, cur_comp));
926
			ORE_DBGMSG2("obj(0x%llx) set_attributes=%d dev=%d\n",
927
				     _LLU(_ios_obj(ios, cur_comp)->id),
928
				     ios->out_attr_len, dev);
929
930
931
932
933
934
935
936
937
		}

		if (ios->out_attr)
			osd_req_add_set_attr_list(or, ios->out_attr,
						  ios->out_attr_len);

		if (ios->in_attr)
			osd_req_add_get_attr_list(or, ios->in_attr,
						  ios->in_attr_len);
938
	}
939
940
941
942
943

out:
	return ret;
}

944
int ore_write(struct ore_io_state *ios)
Boaz Harrosh's avatar
Boaz Harrosh committed
945
946
947
948
{
	int i;
	int ret;

Boaz Harrosh's avatar
Boaz Harrosh committed
949
950
951
952
953
954
955
956
	if (unlikely(ios->sp2d && !ios->r4w)) {
		/* A library is attempting a RAID-write without providing
		 * a pages lock interface.
		 */
		WARN_ON_ONCE(1);
		return -ENOTSUPP;
	}

Boaz Harrosh's avatar
Boaz Harrosh committed
957
958
959
960
961
	ret = _prepare_for_striping(ios);
	if (unlikely(ret))
		return ret;

	for (i = 0; i < ios->numdevs; i += ios->layout->mirrors_p1) {
962
		ret = _write_mirror(ios, i);
Boaz Harrosh's avatar
Boaz Harrosh committed
963
964
965
966
		if (unlikely(ret))
			return ret;
	}

967
	ret = ore_io_execute(ios);
Boaz Harrosh's avatar
Boaz Harrosh committed
968
969
	return ret;
}
Boaz Harrosh's avatar
Boaz Harrosh committed
970
EXPORT_SYMBOL(ore_write);
Boaz Harrosh's avatar
Boaz Harrosh committed
971

Boaz Harrosh's avatar
Boaz Harrosh committed
972
int _ore_read_mirror(struct ore_io_state *ios, unsigned cur_comp)
973
{
Boaz Harrosh's avatar
Boaz Harrosh committed
974
	struct osd_request *or;
975
	struct ore_per_dev_state *per_dev = &ios->per_dev[cur_comp];
976
977
	struct osd_obj_id *obj = _ios_obj(ios, cur_comp);
	unsigned first_dev = (unsigned)obj->id;
978

Boaz Harrosh's avatar
Boaz Harrosh committed
979
980
981
	if (ios->pages && !per_dev->length)
		return 0; /* Just an empty slot */

Boaz Harrosh's avatar
Boaz Harrosh committed
982
	first_dev = per_dev->dev + first_dev % ios->layout->mirrors_p1;
983
	or = osd_start_request(_ios_od(ios, first_dev));
Boaz Harrosh's avatar
Boaz Harrosh committed
984
	if (unlikely(!or)) {
985
		ORE_ERR("%s: osd_start_request failed\n", __func__);
Boaz Harrosh's avatar
Boaz Harrosh committed
986
987
988
989
		return -ENOMEM;
	}
	per_dev->or = or;

990
	if (ios->pages) {
Boaz Harrosh's avatar
Boaz Harrosh committed
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
		if (per_dev->cur_sg) {
			/* finalize the last sg_entry */
			_ore_add_sg_seg(per_dev, 0, false);
			if (unlikely(!per_dev->cur_sg))
				return 0; /* Skip parity only device */

			osd_req_read_sg(or, obj, per_dev->bio,
					per_dev->sglist, per_dev->cur_sg);
		} else {
			/* The no raid case */
			osd_req_read(or, obj, per_dev->offset,
				     per_dev->bio, per_dev->length);
		}

1005
		ORE_DBGMSG("read(0x%llx) offset=0x%llx length=0x%llx"
Boaz Harrosh's avatar
Boaz Harrosh committed
1006
			     " dev=%d sg_len=%d\n", _LLU(obj->id),
Boaz Harrosh's avatar
Boaz Harrosh committed
1007
			     _LLU(per_dev->offset), _LLU(per_dev->length),
Boaz Harrosh's avatar
Boaz Harrosh committed
1008
			     first_dev, per_dev->cur_sg);
Boaz Harrosh's avatar
Boaz Harrosh committed
1009
	} else {
1010
1011
		BUG_ON(ios->kern_buff);

1012
		osd_req_get_attributes(or, obj);
1013
		ORE_DBGMSG2("obj(0x%llx) get_attributes=%d dev=%d\n",
1014
1015
			      _LLU(obj->id),
			      ios->in_attr_len, first_dev);
Boaz Harrosh's avatar
Boaz Harrosh committed
1016
1017
1018
	}
	if (ios->out_attr)
		osd_req_add_set_attr_list(or, ios->out_attr, ios->out_attr_len);
1019

Boaz Harrosh's avatar
Boaz Harrosh committed
1020
1021
	if (ios->in_attr)
		osd_req_add_get_attr_list(or, ios->in_attr, ios->in_attr_len);
1022

Boaz Harrosh's avatar
Boaz Harrosh committed
1023
1024
1025
	return 0;
}

1026
int ore_read(struct ore_io_state *ios)
Boaz Harrosh's avatar
Boaz Harrosh committed
1027
1028
1029
1030
1031
1032
1033
1034
1035
{
	int i;
	int ret;

	ret = _prepare_for_striping(ios);
	if (unlikely(ret))
		return ret;

	for (i = 0; i < ios->numdevs; i += ios->layout->mirrors_p1) {
Boaz Harrosh's avatar
Boaz Harrosh committed
1036
		ret = _ore_read_mirror(ios, i);
Boaz Harrosh's avatar
Boaz Harrosh committed
1037
1038
1039
1040
		if (unlikely(ret))
			return ret;
	}

1041
	ret = ore_io_execute(ios);
Boaz Harrosh's avatar
Boaz Harrosh committed
1042
	return ret;
1043
}
Boaz Harrosh's avatar
Boaz Harrosh committed
1044
EXPORT_SYMBOL(ore_read);
1045

1046
int extract_attr_from_ios(struct ore_io_state *ios, struct osd_attr *attr)
1047
1048
1049
1050
1051
1052
1053
{
	struct osd_attr cur_attr = {.attr_page = 0}; /* start with zeros */
	void *iter = NULL;
	int nelem;

	do {
		nelem = 1;
1054
1055
		osd_req_decode_get_attr_list(ios->per_dev[0].or,
					     &cur_attr, &nelem, &iter);
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
		if ((cur_attr.attr_page == attr->attr_page) &&
		    (cur_attr.attr_id == attr->attr_id)) {
			attr->len = cur_attr.len;
			attr->val_ptr = cur_attr.val_ptr;
			return 0;
		}
	} while (iter);

	return -EIO;
}