Commit | Line | Data |
---|---|---|
d7e09d03 PT |
1 | /* |
2 | * GPL HEADER START | |
3 | * | |
4 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License version 2 only, | |
8 | * as published by the Free Software Foundation. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, but | |
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | * General Public License version 2 for more details (a copy is included | |
14 | * in the LICENSE file that accompanied this code). | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * version 2 along with this program; If not, see | |
18 | * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf | |
19 | * | |
20 | * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, | |
21 | * CA 95054 USA or visit www.sun.com if you need additional information or | |
22 | * have any questions. | |
23 | * | |
24 | * GPL HEADER END | |
25 | */ | |
26 | /* | |
27 | * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. | |
28 | * Use is subject to license terms. | |
29 | * | |
30 | * Copyright (c) 2011, Intel Corporation. | |
31 | */ | |
32 | /* | |
33 | * This file is part of Lustre, http://www.lustre.org/ | |
34 | * Lustre is a trademark of Sun Microsystems, Inc. | |
35 | */ | |
36 | ||
37 | #define DEBUG_SUBSYSTEM S_LOV | |
38 | ||
39 | #include <linux/libcfs/libcfs.h> | |
40 | ||
41 | #include <obd_class.h> | |
42 | #include <obd_lov.h> | |
43 | ||
44 | #include "lov_internal.h" | |
45 | ||
46 | /* compute object size given "stripeno" and the ost size */ | |
47 | obd_size lov_stripe_size(struct lov_stripe_md *lsm, obd_size ost_size, | |
48 | int stripeno) | |
49 | { | |
50 | unsigned long ssize = lsm->lsm_stripe_size; | |
51 | unsigned long stripe_size; | |
52 | obd_off swidth; | |
53 | obd_size lov_size; | |
54 | int magic = lsm->lsm_magic; | |
d7e09d03 PT |
55 | |
56 | if (ost_size == 0) | |
0a3bdb00 | 57 | return 0; |
d7e09d03 PT |
58 | |
59 | LASSERT(lsm_op_find(magic) != NULL); | |
60 | lsm_op_find(magic)->lsm_stripe_by_index(lsm, &stripeno, NULL, &swidth); | |
61 | ||
62 | /* lov_do_div64(a, b) returns a % b, and a = a / b */ | |
63 | stripe_size = lov_do_div64(ost_size, ssize); | |
64 | if (stripe_size) | |
65 | lov_size = ost_size * swidth + stripeno * ssize + stripe_size; | |
66 | else | |
67 | lov_size = (ost_size - 1) * swidth + (stripeno + 1) * ssize; | |
68 | ||
0a3bdb00 | 69 | return lov_size; |
d7e09d03 PT |
70 | } |
71 | ||
72 | /* we have an offset in file backed by an lov and want to find out where | |
73 | * that offset lands in our given stripe of the file. for the easy | |
74 | * case where the offset is within the stripe, we just have to scale the | |
75 | * offset down to make it relative to the stripe instead of the lov. | |
76 | * | |
77 | * the harder case is what to do when the offset doesn't intersect the | |
78 | * stripe. callers will want start offsets clamped ahead to the start | |
79 | * of the nearest stripe in the file. end offsets similarly clamped to the | |
80 | * nearest ending byte of a stripe in the file: | |
81 | * | |
82 | * all this function does is move offsets to the nearest region of the | |
83 | * stripe, and it does its work "mod" the full length of all the stripes. | |
84 | * consider a file with 3 stripes: | |
85 | * | |
86 | * S E | |
87 | * --------------------------------------------------------------------- | |
88 | * | 0 | 1 | 2 | 0 | 1 | 2 | | |
89 | * --------------------------------------------------------------------- | |
90 | * | |
91 | * to find stripe 1's offsets for S and E, it divides by the full stripe | |
92 | * width and does its math in the context of a single set of stripes: | |
93 | * | |
94 | * S E | |
95 | * ----------------------------------- | |
96 | * | 0 | 1 | 2 | | |
97 | * ----------------------------------- | |
98 | * | |
99 | * it'll notice that E is outside stripe 1 and clamp it to the end of the | |
100 | * stripe, then multiply it back out by lov_off to give the real offsets in | |
101 | * the stripe: | |
102 | * | |
103 | * S E | |
104 | * --------------------------------------------------------------------- | |
105 | * | 1 | 1 | 1 | 1 | 1 | 1 | | |
106 | * --------------------------------------------------------------------- | |
107 | * | |
108 | * it would have done similarly and pulled S forward to the start of a 1 | |
109 | * stripe if, say, S had landed in a 0 stripe. | |
110 | * | |
111 | * this rounding isn't always correct. consider an E lov offset that lands | |
112 | * on a 0 stripe, the "mod stripe width" math will pull it forward to the | |
113 | * start of a 1 stripe, when in fact it wanted to be rounded back to the end | |
114 | * of a previous 1 stripe. this logic is handled by callers and this is why: | |
115 | * | |
116 | * this function returns < 0 when the offset was "before" the stripe and | |
117 | * was moved forward to the start of the stripe in question; 0 when it | |
118 | * falls in the stripe and no shifting was done; > 0 when the offset | |
119 | * was outside the stripe and was pulled back to its final byte. */ | |
120 | int lov_stripe_offset(struct lov_stripe_md *lsm, obd_off lov_off, | |
121 | int stripeno, obd_off *obdoff) | |
122 | { | |
123 | unsigned long ssize = lsm->lsm_stripe_size; | |
124 | obd_off stripe_off, this_stripe, swidth; | |
125 | int magic = lsm->lsm_magic; | |
126 | int ret = 0; | |
127 | ||
128 | if (lov_off == OBD_OBJECT_EOF) { | |
129 | *obdoff = OBD_OBJECT_EOF; | |
130 | return 0; | |
131 | } | |
132 | ||
133 | LASSERT(lsm_op_find(magic) != NULL); | |
134 | ||
135 | lsm_op_find(magic)->lsm_stripe_by_index(lsm, &stripeno, &lov_off, | |
136 | &swidth); | |
137 | ||
138 | /* lov_do_div64(a, b) returns a % b, and a = a / b */ | |
139 | stripe_off = lov_do_div64(lov_off, swidth); | |
140 | ||
141 | this_stripe = (obd_off)stripeno * ssize; | |
142 | if (stripe_off < this_stripe) { | |
143 | stripe_off = 0; | |
144 | ret = -1; | |
145 | } else { | |
146 | stripe_off -= this_stripe; | |
147 | ||
148 | if (stripe_off >= ssize) { | |
149 | stripe_off = ssize; | |
150 | ret = 1; | |
151 | } | |
152 | } | |
153 | ||
154 | *obdoff = lov_off * ssize + stripe_off; | |
155 | return ret; | |
156 | } | |
157 | ||
158 | /* Given a whole-file size and a stripe number, give the file size which | |
159 | * corresponds to the individual object of that stripe. | |
160 | * | |
161 | * This behaves basically in the same was as lov_stripe_offset, except that | |
162 | * file sizes falling before the beginning of a stripe are clamped to the end | |
163 | * of the previous stripe, not the beginning of the next: | |
164 | * | |
165 | * S | |
166 | * --------------------------------------------------------------------- | |
167 | * | 0 | 1 | 2 | 0 | 1 | 2 | | |
168 | * --------------------------------------------------------------------- | |
169 | * | |
170 | * if clamped to stripe 2 becomes: | |
171 | * | |
172 | * S | |
173 | * --------------------------------------------------------------------- | |
174 | * | 0 | 1 | 2 | 0 | 1 | 2 | | |
175 | * --------------------------------------------------------------------- | |
176 | */ | |
177 | obd_off lov_size_to_stripe(struct lov_stripe_md *lsm, obd_off file_size, | |
178 | int stripeno) | |
179 | { | |
180 | unsigned long ssize = lsm->lsm_stripe_size; | |
181 | obd_off stripe_off, this_stripe, swidth; | |
182 | int magic = lsm->lsm_magic; | |
183 | ||
184 | if (file_size == OBD_OBJECT_EOF) | |
185 | return OBD_OBJECT_EOF; | |
186 | ||
187 | LASSERT(lsm_op_find(magic) != NULL); | |
188 | lsm_op_find(magic)->lsm_stripe_by_index(lsm, &stripeno, &file_size, | |
189 | &swidth); | |
190 | ||
191 | /* lov_do_div64(a, b) returns a % b, and a = a / b */ | |
192 | stripe_off = lov_do_div64(file_size, swidth); | |
193 | ||
194 | this_stripe = (obd_off)stripeno * ssize; | |
195 | if (stripe_off < this_stripe) { | |
196 | /* Move to end of previous stripe, or zero */ | |
197 | if (file_size > 0) { | |
198 | file_size--; | |
199 | stripe_off = ssize; | |
200 | } else { | |
201 | stripe_off = 0; | |
202 | } | |
203 | } else { | |
204 | stripe_off -= this_stripe; | |
205 | ||
206 | if (stripe_off >= ssize) { | |
207 | /* Clamp to end of this stripe */ | |
208 | stripe_off = ssize; | |
209 | } | |
210 | } | |
211 | ||
212 | return (file_size * ssize + stripe_off); | |
213 | } | |
214 | ||
215 | /* given an extent in an lov and a stripe, calculate the extent of the stripe | |
216 | * that is contained within the lov extent. this returns true if the given | |
217 | * stripe does intersect with the lov extent. */ | |
218 | int lov_stripe_intersects(struct lov_stripe_md *lsm, int stripeno, | |
219 | obd_off start, obd_off end, | |
220 | obd_off *obd_start, obd_off *obd_end) | |
221 | { | |
222 | int start_side, end_side; | |
223 | ||
224 | start_side = lov_stripe_offset(lsm, start, stripeno, obd_start); | |
225 | end_side = lov_stripe_offset(lsm, end, stripeno, obd_end); | |
226 | ||
227 | CDEBUG(D_INODE, "["LPU64"->"LPU64"] -> [(%d) "LPU64"->"LPU64" (%d)]\n", | |
228 | start, end, start_side, *obd_start, *obd_end, end_side); | |
229 | ||
230 | /* this stripe doesn't intersect the file extent when neither | |
231 | * start or the end intersected the stripe and obd_start and | |
232 | * obd_end got rounded up to the save value. */ | |
233 | if (start_side != 0 && end_side != 0 && *obd_start == *obd_end) | |
234 | return 0; | |
235 | ||
236 | /* as mentioned in the lov_stripe_offset commentary, end | |
237 | * might have been shifted in the wrong direction. This | |
238 | * happens when an end offset is before the stripe when viewed | |
239 | * through the "mod stripe size" math. we detect it being shifted | |
240 | * in the wrong direction and touch it up. | |
241 | * interestingly, this can't underflow since end must be > start | |
242 | * if we passed through the previous check. | |
243 | * (should we assert for that somewhere?) */ | |
244 | if (end_side != 0) | |
245 | (*obd_end)--; | |
246 | ||
247 | return 1; | |
248 | } | |
249 | ||
250 | /* compute which stripe number "lov_off" will be written into */ | |
251 | int lov_stripe_number(struct lov_stripe_md *lsm, obd_off lov_off) | |
252 | { | |
253 | unsigned long ssize = lsm->lsm_stripe_size; | |
254 | obd_off stripe_off, swidth; | |
255 | int magic = lsm->lsm_magic; | |
256 | ||
257 | LASSERT(lsm_op_find(magic) != NULL); | |
258 | lsm_op_find(magic)->lsm_stripe_by_offset(lsm, NULL, &lov_off, &swidth); | |
259 | ||
260 | stripe_off = lov_do_div64(lov_off, swidth); | |
261 | ||
262 | /* Puts stripe_off/ssize result into stripe_off */ | |
263 | lov_do_div64(stripe_off, ssize); | |
264 | ||
265 | return stripe_off; | |
266 | } |