summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorIlya Dryomov <idryomov@gmail.com>2018-02-02 09:23:22 -0500
committerIlya Dryomov <idryomov@gmail.com>2018-04-02 04:12:42 -0400
commited0811d2d243c4195580a9671266031907c02ca7 (patch)
tree723bbd958115c273371277f2f0a549889c0cbf19 /net
parentecc633caebcc84a1469892e3f6f6f4b6a16f41af (diff)
libceph: striping framework implementation
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Diffstat (limited to 'net')
-rw-r--r--net/ceph/Makefile1
-rw-r--r--net/ceph/striper.c226
2 files changed, 227 insertions, 0 deletions
diff --git a/net/ceph/Makefile b/net/ceph/Makefile
index b4bded4b5396..12bf49772d24 100644
--- a/net/ceph/Makefile
+++ b/net/ceph/Makefile
@@ -8,6 +8,7 @@ libceph-y := ceph_common.o messenger.o msgpool.o buffer.o pagelist.o \
8 mon_client.o \ 8 mon_client.o \
9 cls_lock_client.o \ 9 cls_lock_client.o \
10 osd_client.o osdmap.o crush/crush.o crush/mapper.o crush/hash.o \ 10 osd_client.o osdmap.o crush/crush.o crush/mapper.o crush/hash.o \
11 striper.o \
11 debugfs.o \ 12 debugfs.o \
12 auth.o auth_none.o \ 13 auth.o auth_none.o \
13 crypto.o armor.o \ 14 crypto.o armor.o \
diff --git a/net/ceph/striper.c b/net/ceph/striper.c
new file mode 100644
index 000000000000..bc1e4de30df9
--- /dev/null
+++ b/net/ceph/striper.c
@@ -0,0 +1,226 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2
3#include <linux/ceph/ceph_debug.h>
4
5#include <linux/math64.h>
6#include <linux/slab.h>
7
8#include <linux/ceph/osdmap.h>
9#include <linux/ceph/striper.h>
10#include <linux/ceph/types.h>
11
12/*
13 * Return the last extent with given objno (@object_extents is sorted
14 * by objno). If not found, return NULL and set @add_pos so that the
15 * new extent can be added with list_add(add_pos, new_ex).
16 */
17static struct ceph_object_extent *
18lookup_last(struct list_head *object_extents, u64 objno,
19 struct list_head **add_pos)
20{
21 struct list_head *pos;
22
23 list_for_each_prev(pos, object_extents) {
24 struct ceph_object_extent *ex =
25 list_entry(pos, typeof(*ex), oe_item);
26
27 if (ex->oe_objno == objno)
28 return ex;
29
30 if (ex->oe_objno < objno)
31 break;
32 }
33
34 *add_pos = pos;
35 return NULL;
36}
37
38static struct ceph_object_extent *
39lookup_containing(struct list_head *object_extents, u64 objno,
40 u64 objoff, u32 xlen)
41{
42 struct ceph_object_extent *ex;
43
44 list_for_each_entry(ex, object_extents, oe_item) {
45 if (ex->oe_objno == objno &&
46 ex->oe_off <= objoff &&
47 ex->oe_off + ex->oe_len >= objoff + xlen) /* paranoia */
48 return ex;
49
50 if (ex->oe_objno > objno)
51 break;
52 }
53
54 return NULL;
55}
56
57/*
58 * Map a file extent to a sorted list of object extents.
59 *
60 * We want only one (or as few as possible) object extents per object.
61 * Adjacent object extents will be merged together, each returned object
62 * extent may reverse map to multiple different file extents.
63 *
64 * Call @alloc_fn for each new object extent and @action_fn for each
65 * mapped stripe unit, whether it was merged into an already allocated
66 * object extent or started a new object extent.
67 *
68 * Newly allocated object extents are added to @object_extents.
69 * To keep @object_extents sorted, successive calls to this function
70 * must map successive file extents (i.e. the list of file extents that
71 * are mapped using the same @object_extents must be sorted).
72 *
73 * The caller is responsible for @object_extents.
74 */
75int ceph_file_to_extents(struct ceph_file_layout *l, u64 off, u64 len,
76 struct list_head *object_extents,
77 struct ceph_object_extent *alloc_fn(void *arg),
78 void *alloc_arg,
79 ceph_object_extent_fn_t action_fn,
80 void *action_arg)
81{
82 struct ceph_object_extent *last_ex, *ex;
83
84 while (len) {
85 struct list_head *add_pos = NULL;
86 u64 objno, objoff;
87 u32 xlen;
88
89 ceph_calc_file_object_mapping(l, off, len, &objno, &objoff,
90 &xlen);
91
92 last_ex = lookup_last(object_extents, objno, &add_pos);
93 if (!last_ex || last_ex->oe_off + last_ex->oe_len != objoff) {
94 ex = alloc_fn(alloc_arg);
95 if (!ex)
96 return -ENOMEM;
97
98 ex->oe_objno = objno;
99 ex->oe_off = objoff;
100 ex->oe_len = xlen;
101 if (action_fn)
102 action_fn(ex, xlen, action_arg);
103
104 if (!last_ex)
105 list_add(&ex->oe_item, add_pos);
106 else
107 list_add(&ex->oe_item, &last_ex->oe_item);
108 } else {
109 last_ex->oe_len += xlen;
110 if (action_fn)
111 action_fn(last_ex, xlen, action_arg);
112 }
113
114 off += xlen;
115 len -= xlen;
116 }
117
118 for (last_ex = list_first_entry(object_extents, typeof(*ex), oe_item),
119 ex = list_next_entry(last_ex, oe_item);
120 &ex->oe_item != object_extents;
121 last_ex = ex, ex = list_next_entry(ex, oe_item)) {
122 if (last_ex->oe_objno > ex->oe_objno ||
123 (last_ex->oe_objno == ex->oe_objno &&
124 last_ex->oe_off + last_ex->oe_len >= ex->oe_off)) {
125 WARN(1, "%s: object_extents list not sorted!\n",
126 __func__);
127 return -EINVAL;
128 }
129 }
130
131 return 0;
132}
133EXPORT_SYMBOL(ceph_file_to_extents);
134
135/*
136 * A stripped down, non-allocating version of ceph_file_to_extents(),
137 * for when @object_extents is already populated.
138 */
139int ceph_iterate_extents(struct ceph_file_layout *l, u64 off, u64 len,
140 struct list_head *object_extents,
141 ceph_object_extent_fn_t action_fn,
142 void *action_arg)
143{
144 while (len) {
145 struct ceph_object_extent *ex;
146 u64 objno, objoff;
147 u32 xlen;
148
149 ceph_calc_file_object_mapping(l, off, len, &objno, &objoff,
150 &xlen);
151
152 ex = lookup_containing(object_extents, objno, objoff, xlen);
153 if (!ex) {
154 WARN(1, "%s: objno %llu %llu~%u not found!\n",
155 __func__, objno, objoff, xlen);
156 return -EINVAL;
157 }
158
159 action_fn(ex, xlen, action_arg);
160
161 off += xlen;
162 len -= xlen;
163 }
164
165 return 0;
166}
167EXPORT_SYMBOL(ceph_iterate_extents);
168
169/*
170 * Reverse map an object extent to a sorted list of file extents.
171 *
172 * On success, the caller is responsible for:
173 *
174 * kfree(file_extents)
175 */
176int ceph_extent_to_file(struct ceph_file_layout *l,
177 u64 objno, u64 objoff, u64 objlen,
178 struct ceph_file_extent **file_extents,
179 u32 *num_file_extents)
180{
181 u32 stripes_per_object = l->object_size / l->stripe_unit;
182 u64 blockno; /* which su */
183 u32 blockoff; /* offset into su */
184 u64 stripeno; /* which stripe */
185 u32 stripepos; /* which su in the stripe,
186 which object in the object set */
187 u64 objsetno; /* which object set */
188 u32 i = 0;
189
190 if (!objlen) {
191 *file_extents = NULL;
192 *num_file_extents = 0;
193 return 0;
194 }
195
196 *num_file_extents = DIV_ROUND_UP_ULL(objoff + objlen, l->stripe_unit) -
197 DIV_ROUND_DOWN_ULL(objoff, l->stripe_unit);
198 *file_extents = kmalloc_array(*num_file_extents, sizeof(**file_extents),
199 GFP_NOIO);
200 if (!*file_extents)
201 return -ENOMEM;
202
203 div_u64_rem(objoff, l->stripe_unit, &blockoff);
204 while (objlen) {
205 u64 off, len;
206
207 objsetno = div_u64_rem(objno, l->stripe_count, &stripepos);
208 stripeno = div_u64(objoff, l->stripe_unit) +
209 objsetno * stripes_per_object;
210 blockno = stripeno * l->stripe_count + stripepos;
211 off = blockno * l->stripe_unit + blockoff;
212 len = min_t(u64, objlen, l->stripe_unit - blockoff);
213
214 (*file_extents)[i].fe_off = off;
215 (*file_extents)[i].fe_len = len;
216
217 blockoff = 0;
218 objoff += len;
219 objlen -= len;
220 i++;
221 }
222
223 BUG_ON(i != *num_file_extents);
224 return 0;
225}
226EXPORT_SYMBOL(ceph_extent_to_file);