diff options
author | Ilya Dryomov <idryomov@gmail.com> | 2018-02-02 09:23:22 -0500 |
---|---|---|
committer | Ilya Dryomov <idryomov@gmail.com> | 2018-04-02 04:12:42 -0400 |
commit | ed0811d2d243c4195580a9671266031907c02ca7 (patch) | |
tree | 723bbd958115c273371277f2f0a549889c0cbf19 /net | |
parent | ecc633caebcc84a1469892e3f6f6f4b6a16f41af (diff) |
libceph: striping framework implementation
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Diffstat (limited to 'net')
-rw-r--r-- | net/ceph/Makefile | 1 | ||||
-rw-r--r-- | net/ceph/striper.c | 226 |
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 | */ | ||
17 | static struct ceph_object_extent * | ||
18 | lookup_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 | |||
38 | static struct ceph_object_extent * | ||
39 | lookup_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 | */ | ||
75 | int 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 | } | ||
133 | EXPORT_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 | */ | ||
139 | int 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 | } | ||
167 | EXPORT_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 | */ | ||
176 | int 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 | } | ||
226 | EXPORT_SYMBOL(ceph_extent_to_file); | ||