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 | ||
9fdaf8c0 | 39 | #include "../../include/linux/libcfs/libcfs.h" |
d7e09d03 PT |
40 | |
41 | #include <obd_class.h> | |
d7e09d03 PT |
42 | |
43 | #include "lov_internal.h" | |
44 | ||
45 | /* compute object size given "stripeno" and the ost size */ | |
46 | obd_size lov_stripe_size(struct lov_stripe_md *lsm, obd_size ost_size, | |
47 | int stripeno) | |
48 | { | |
49 | unsigned long ssize = lsm->lsm_stripe_size; | |
50 | unsigned long stripe_size; | |
51 | obd_off swidth; | |
52 | obd_size lov_size; | |
53 | int magic = lsm->lsm_magic; | |
d7e09d03 PT |
54 | |
55 | if (ost_size == 0) | |
0a3bdb00 | 56 | return 0; |
d7e09d03 PT |
57 | |
58 | LASSERT(lsm_op_find(magic) != NULL); | |
59 | lsm_op_find(magic)->lsm_stripe_by_index(lsm, &stripeno, NULL, &swidth); | |
60 | ||
61 | /* lov_do_div64(a, b) returns a % b, and a = a / b */ | |
62 | stripe_size = lov_do_div64(ost_size, ssize); | |
63 | if (stripe_size) | |
64 | lov_size = ost_size * swidth + stripeno * ssize + stripe_size; | |
65 | else | |
66 | lov_size = (ost_size - 1) * swidth + (stripeno + 1) * ssize; | |
67 | ||
0a3bdb00 | 68 | return lov_size; |
d7e09d03 PT |
69 | } |
70 | ||
71 | /* we have an offset in file backed by an lov and want to find out where | |
72 | * that offset lands in our given stripe of the file. for the easy | |
73 | * case where the offset is within the stripe, we just have to scale the | |
74 | * offset down to make it relative to the stripe instead of the lov. | |
75 | * | |
76 | * the harder case is what to do when the offset doesn't intersect the | |
77 | * stripe. callers will want start offsets clamped ahead to the start | |
78 | * of the nearest stripe in the file. end offsets similarly clamped to the | |
79 | * nearest ending byte of a stripe in the file: | |
80 | * | |
81 | * all this function does is move offsets to the nearest region of the | |
82 | * stripe, and it does its work "mod" the full length of all the stripes. | |
83 | * consider a file with 3 stripes: | |
84 | * | |
85 | * S E | |
86 | * --------------------------------------------------------------------- | |
87 | * | 0 | 1 | 2 | 0 | 1 | 2 | | |
88 | * --------------------------------------------------------------------- | |
89 | * | |
90 | * to find stripe 1's offsets for S and E, it divides by the full stripe | |
91 | * width and does its math in the context of a single set of stripes: | |
92 | * | |
93 | * S E | |
94 | * ----------------------------------- | |
95 | * | 0 | 1 | 2 | | |
96 | * ----------------------------------- | |
97 | * | |
98 | * it'll notice that E is outside stripe 1 and clamp it to the end of the | |
99 | * stripe, then multiply it back out by lov_off to give the real offsets in | |
100 | * the stripe: | |
101 | * | |
102 | * S E | |
103 | * --------------------------------------------------------------------- | |
104 | * | 1 | 1 | 1 | 1 | 1 | 1 | | |
105 | * --------------------------------------------------------------------- | |
106 | * | |
107 | * it would have done similarly and pulled S forward to the start of a 1 | |
108 | * stripe if, say, S had landed in a 0 stripe. | |
109 | * | |
110 | * this rounding isn't always correct. consider an E lov offset that lands | |
111 | * on a 0 stripe, the "mod stripe width" math will pull it forward to the | |
112 | * start of a 1 stripe, when in fact it wanted to be rounded back to the end | |
113 | * of a previous 1 stripe. this logic is handled by callers and this is why: | |
114 | * | |
115 | * this function returns < 0 when the offset was "before" the stripe and | |
116 | * was moved forward to the start of the stripe in question; 0 when it | |
117 | * falls in the stripe and no shifting was done; > 0 when the offset | |
118 | * was outside the stripe and was pulled back to its final byte. */ | |
119 | int lov_stripe_offset(struct lov_stripe_md *lsm, obd_off lov_off, | |
120 | int stripeno, obd_off *obdoff) | |
121 | { | |
122 | unsigned long ssize = lsm->lsm_stripe_size; | |
123 | obd_off stripe_off, this_stripe, swidth; | |
124 | int magic = lsm->lsm_magic; | |
125 | int ret = 0; | |
126 | ||
127 | if (lov_off == OBD_OBJECT_EOF) { | |
128 | *obdoff = OBD_OBJECT_EOF; | |
129 | return 0; | |
130 | } | |
131 | ||
132 | LASSERT(lsm_op_find(magic) != NULL); | |
133 | ||
134 | lsm_op_find(magic)->lsm_stripe_by_index(lsm, &stripeno, &lov_off, | |
135 | &swidth); | |
136 | ||
137 | /* lov_do_div64(a, b) returns a % b, and a = a / b */ | |
138 | stripe_off = lov_do_div64(lov_off, swidth); | |
139 | ||
140 | this_stripe = (obd_off)stripeno * ssize; | |
141 | if (stripe_off < this_stripe) { | |
142 | stripe_off = 0; | |
143 | ret = -1; | |
144 | } else { | |
145 | stripe_off -= this_stripe; | |
146 | ||
147 | if (stripe_off >= ssize) { | |
148 | stripe_off = ssize; | |
149 | ret = 1; | |
150 | } | |
151 | } | |
152 | ||
153 | *obdoff = lov_off * ssize + stripe_off; | |
154 | return ret; | |
155 | } | |
156 | ||
157 | /* Given a whole-file size and a stripe number, give the file size which | |
158 | * corresponds to the individual object of that stripe. | |
159 | * | |
160 | * This behaves basically in the same was as lov_stripe_offset, except that | |
161 | * file sizes falling before the beginning of a stripe are clamped to the end | |
162 | * of the previous stripe, not the beginning of the next: | |
163 | * | |
164 | * S | |
165 | * --------------------------------------------------------------------- | |
166 | * | 0 | 1 | 2 | 0 | 1 | 2 | | |
167 | * --------------------------------------------------------------------- | |
168 | * | |
169 | * if clamped to stripe 2 becomes: | |
170 | * | |
171 | * S | |
172 | * --------------------------------------------------------------------- | |
173 | * | 0 | 1 | 2 | 0 | 1 | 2 | | |
174 | * --------------------------------------------------------------------- | |
175 | */ | |
176 | obd_off lov_size_to_stripe(struct lov_stripe_md *lsm, obd_off file_size, | |
177 | int stripeno) | |
178 | { | |
179 | unsigned long ssize = lsm->lsm_stripe_size; | |
180 | obd_off stripe_off, this_stripe, swidth; | |
181 | int magic = lsm->lsm_magic; | |
182 | ||
183 | if (file_size == OBD_OBJECT_EOF) | |
184 | return OBD_OBJECT_EOF; | |
185 | ||
186 | LASSERT(lsm_op_find(magic) != NULL); | |
187 | lsm_op_find(magic)->lsm_stripe_by_index(lsm, &stripeno, &file_size, | |
188 | &swidth); | |
189 | ||
190 | /* lov_do_div64(a, b) returns a % b, and a = a / b */ | |
191 | stripe_off = lov_do_div64(file_size, swidth); | |
192 | ||
193 | this_stripe = (obd_off)stripeno * ssize; | |
194 | if (stripe_off < this_stripe) { | |
195 | /* Move to end of previous stripe, or zero */ | |
196 | if (file_size > 0) { | |
197 | file_size--; | |
198 | stripe_off = ssize; | |
199 | } else { | |
200 | stripe_off = 0; | |
201 | } | |
202 | } else { | |
203 | stripe_off -= this_stripe; | |
204 | ||
205 | if (stripe_off >= ssize) { | |
206 | /* Clamp to end of this stripe */ | |
207 | stripe_off = ssize; | |
208 | } | |
209 | } | |
210 | ||
211 | return (file_size * ssize + stripe_off); | |
212 | } | |
213 | ||
214 | /* given an extent in an lov and a stripe, calculate the extent of the stripe | |
215 | * that is contained within the lov extent. this returns true if the given | |
216 | * stripe does intersect with the lov extent. */ | |
217 | int lov_stripe_intersects(struct lov_stripe_md *lsm, int stripeno, | |
218 | obd_off start, obd_off end, | |
219 | obd_off *obd_start, obd_off *obd_end) | |
220 | { | |
221 | int start_side, end_side; | |
222 | ||
223 | start_side = lov_stripe_offset(lsm, start, stripeno, obd_start); | |
224 | end_side = lov_stripe_offset(lsm, end, stripeno, obd_end); | |
225 | ||
226 | CDEBUG(D_INODE, "["LPU64"->"LPU64"] -> [(%d) "LPU64"->"LPU64" (%d)]\n", | |
227 | start, end, start_side, *obd_start, *obd_end, end_side); | |
228 | ||
229 | /* this stripe doesn't intersect the file extent when neither | |
230 | * start or the end intersected the stripe and obd_start and | |
231 | * obd_end got rounded up to the save value. */ | |
232 | if (start_side != 0 && end_side != 0 && *obd_start == *obd_end) | |
233 | return 0; | |
234 | ||
235 | /* as mentioned in the lov_stripe_offset commentary, end | |
236 | * might have been shifted in the wrong direction. This | |
237 | * happens when an end offset is before the stripe when viewed | |
238 | * through the "mod stripe size" math. we detect it being shifted | |
239 | * in the wrong direction and touch it up. | |
240 | * interestingly, this can't underflow since end must be > start | |
241 | * if we passed through the previous check. | |
242 | * (should we assert for that somewhere?) */ | |
243 | if (end_side != 0) | |
244 | (*obd_end)--; | |
245 | ||
246 | return 1; | |
247 | } | |
248 | ||
249 | /* compute which stripe number "lov_off" will be written into */ | |
250 | int lov_stripe_number(struct lov_stripe_md *lsm, obd_off lov_off) | |
251 | { | |
252 | unsigned long ssize = lsm->lsm_stripe_size; | |
253 | obd_off stripe_off, swidth; | |
254 | int magic = lsm->lsm_magic; | |
255 | ||
256 | LASSERT(lsm_op_find(magic) != NULL); | |
257 | lsm_op_find(magic)->lsm_stripe_by_offset(lsm, NULL, &lov_off, &swidth); | |
258 | ||
259 | stripe_off = lov_do_div64(lov_off, swidth); | |
260 | ||
261 | /* Puts stripe_off/ssize result into stripe_off */ | |
262 | lov_do_div64(stripe_off, ssize); | |
263 | ||
264 | return stripe_off; | |
265 | } |