aboutsummaryrefslogtreecommitdiffstats
path: root/fs/exofs/ore_raid.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/exofs/ore_raid.c')
-rw-r--r--fs/exofs/ore_raid.c140
1 files changed, 140 insertions, 0 deletions
diff --git a/fs/exofs/ore_raid.c b/fs/exofs/ore_raid.c
new file mode 100644
index 000000000000..8d4b93a93c67
--- /dev/null
+++ b/fs/exofs/ore_raid.c
@@ -0,0 +1,140 @@
1/*
2 * Copyright (C) 2011
3 * Boaz Harrosh <bharrosh@panasas.com>
4 *
5 * This file is part of the objects raid engine (ore).
6 *
7 * It is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as published
9 * by the Free Software Foundation.
10 *
11 * You should have received a copy of the GNU General Public License
12 * along with "ore". If not, write to the Free Software Foundation, Inc:
13 * "Free Software Foundation <info@fsf.org>"
14 */
15
16#include <linux/gfp.h>
17
18#include "ore_raid.h"
19
20struct page *_raid_page_alloc(void)
21{
22 return alloc_page(GFP_KERNEL);
23}
24
25void _raid_page_free(struct page *p)
26{
27 __free_page(p);
28}
29
30void _ore_add_sg_seg(struct ore_per_dev_state *per_dev, unsigned cur_len,
31 bool not_last)
32{
33 struct osd_sg_entry *sge;
34
35 ORE_DBGMSG("dev=%d cur_len=0x%x not_last=%d cur_sg=%d "
36 "offset=0x%llx length=0x%x last_sgs_total=0x%x\n",
37 per_dev->dev, cur_len, not_last, per_dev->cur_sg,
38 _LLU(per_dev->offset), per_dev->length,
39 per_dev->last_sgs_total);
40
41 if (!per_dev->cur_sg) {
42 sge = per_dev->sglist;
43
44 /* First time we prepare two entries */
45 if (per_dev->length) {
46 ++per_dev->cur_sg;
47 sge->offset = per_dev->offset;
48 sge->len = per_dev->length;
49 } else {
50 /* Here the parity is the first unit of this object.
51 * This happens every time we reach a parity device on
52 * the same stripe as the per_dev->offset. We need to
53 * just skip this unit.
54 */
55 per_dev->offset += cur_len;
56 return;
57 }
58 } else {
59 /* finalize the last one */
60 sge = &per_dev->sglist[per_dev->cur_sg - 1];
61 sge->len = per_dev->length - per_dev->last_sgs_total;
62 }
63
64 if (not_last) {
65 /* Partly prepare the next one */
66 struct osd_sg_entry *next_sge = sge + 1;
67
68 ++per_dev->cur_sg;
69 next_sge->offset = sge->offset + sge->len + cur_len;
70 /* Save cur len so we know how mutch was added next time */
71 per_dev->last_sgs_total = per_dev->length;
72 next_sge->len = 0;
73 } else if (!sge->len) {
74 /* Optimize for when the last unit is a parity */
75 --per_dev->cur_sg;
76 }
77}
78
79/* In writes @cur_len means length left. .i.e cur_len==0 is the last parity U */
80int _ore_add_parity_unit(struct ore_io_state *ios,
81 struct ore_striping_info *si,
82 struct ore_per_dev_state *per_dev,
83 unsigned cur_len)
84{
85 if (ios->reading) {
86 BUG_ON(per_dev->cur_sg >= ios->sgs_per_dev);
87 _ore_add_sg_seg(per_dev, cur_len, true);
88 } else {
89 struct page **pages = ios->parity_pages + ios->cur_par_page;
90 unsigned num_pages = ios->layout->stripe_unit / PAGE_SIZE;
91 unsigned array_start = 0;
92 unsigned i;
93 int ret;
94
95 for (i = 0; i < num_pages; i++) {
96 pages[i] = _raid_page_alloc();
97 if (unlikely(!pages[i]))
98 return -ENOMEM;
99
100 ++(ios->cur_par_page);
101 /* TODO: only read support for now */
102 clear_highpage(pages[i]);
103 }
104
105 ORE_DBGMSG("writing dev=%d num_pages=%d cur_par_page=%d",
106 per_dev->dev, num_pages, ios->cur_par_page);
107
108 ret = _ore_add_stripe_unit(ios, &array_start, 0, pages,
109 per_dev, num_pages * PAGE_SIZE);
110 if (unlikely(ret))
111 return ret;
112 }
113 return 0;
114}
115
116int _ore_post_alloc_raid_stuff(struct ore_io_state *ios)
117{
118 /*TODO: Only raid writes has stuff to add here */
119 return 0;
120}
121
122void _ore_free_raid_stuff(struct ore_io_state *ios)
123{
124 if (ios->parity_pages) { /* writing and raid */
125 unsigned i;
126
127 for (i = 0; i < ios->cur_par_page; i++) {
128 struct page *page = ios->parity_pages[i];
129
130 if (page)
131 _raid_page_free(page);
132 }
133 if (ios->extra_part_alloc)
134 kfree(ios->parity_pages);
135 } else {
136 /* Will only be set if raid reading && sglist is big */
137 if (ios->extra_part_alloc)
138 kfree(ios->per_dev[0].sglist);
139 }
140}