1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
4 * Copyright (C) 2002, 2003 Cluster File Systems, Inc.
6 * This file is part of Lustre, http://www.lustre.org.
8 * Lustre is free software; you can redistribute it and/or
9 * modify it under the terms of version 2 of the GNU General Public
10 * License as published by the Free Software Foundation.
12 * Lustre is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Lustre; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 # define EXPORT_SYMTAB
25 #define DEBUG_SUBSYSTEM S_LOV
28 #include <asm/div64.h>
30 #include <liblustre.h>
33 #include <linux/obd_class.h>
34 #include <linux/obd_lov.h>
36 #include "lov_internal.h"
38 /* compute object size given "stripeno" and the ost size */
39 obd_size lov_stripe_size(struct lov_stripe_md *lsm, obd_size ost_size,
42 unsigned long ssize = lsm->lsm_stripe_size;
43 unsigned long swidth = ssize * lsm->lsm_stripe_count;
44 unsigned long stripe_size;
51 /* do_div(a, b) returns a % b, and a = a / b */
52 stripe_size = do_div(ost_size, ssize);
54 lov_size = ost_size * swidth + stripeno * ssize + stripe_size;
56 lov_size = (ost_size - 1) * swidth + (stripeno + 1) * ssize;
61 /* we have an offset in file backed by an lov and want to find out where
62 * that offset lands in our given stripe of the file. for the easy
63 * case where the offset is within the stripe, we just have to scale the
64 * offset down to make it relative to the stripe instead of the lov.
66 * the harder case is what to do when the offset doesn't intersect the
67 * stripe. callers will want start offsets clamped ahead to the start
68 * of the nearest stripe in the file. end offsets similarly clamped to the
69 * nearest ending byte of a stripe in the file:
71 * all this function does is move offsets to the nearest region of the
72 * stripe, and it does its work "mod" the full length of all the stripes.
73 * consider a file with 3 stripes:
76 * ---------------------------------------------------------------------
77 * | 0 | 1 | 2 | 0 | 1 | 2 |
78 * ---------------------------------------------------------------------
80 * to find stripe 1's offsets for S and E, it divides by the full stripe
81 * width and does its math in the context of a single set of stripes:
84 * -----------------------------------
86 * -----------------------------------
88 * it'll notice that E is outside stripe 1 and clamp it to the end of the
89 * stripe, then multiply it back out by lov_off to give the real offsets in
93 * ---------------------------------------------------------------------
94 * | 1 | 1 | 1 | 1 | 1 | 1 |
95 * ---------------------------------------------------------------------
97 * it would have done similarly and pulled S forward to the start of a 1
98 * stripe if, say, S had landed in a 0 stripe.
100 * this rounding isn't always correct. consider an E lov offset that lands
101 * on a 0 stripe, the "mod stripe width" math will pull it forward to the
102 * start of a 1 stripe, when in fact it wanted to be rounded back to the end
103 * of a previous 1 stripe. this logic is handled by callers and this is why:
105 * this function returns < 0 when the offset was "before" the stripe and
106 * was moved forward to the start of the stripe in question; 0 when it
107 * falls in the stripe and no shifting was done; > 0 when the offset
108 * was outside the stripe and was pulled back to its final byte. */
109 int lov_stripe_offset(struct lov_stripe_md *lsm, obd_off lov_off,
110 int stripeno, obd_off *obd_off)
112 unsigned long ssize = lsm->lsm_stripe_size;
113 unsigned long swidth = ssize * lsm->lsm_stripe_count;
114 unsigned long stripe_off, this_stripe;
117 if (lov_off == OBD_OBJECT_EOF) {
118 *obd_off = OBD_OBJECT_EOF;
122 /* do_div(a, b) returns a % b, and a = a / b */
123 stripe_off = do_div(lov_off, swidth);
125 this_stripe = stripeno * ssize;
126 if (stripe_off < this_stripe) {
130 stripe_off -= this_stripe;
132 if (stripe_off >= ssize) {
138 *obd_off = lov_off * ssize + stripe_off;
142 /* Given a whole-file size and a stripe number, give the file size which
143 * corresponds to the individual object of that stripe.
145 * This behaves basically in the same was as lov_stripe_offset, except that
146 * file sizes falling before the beginning of a stripe are clamped to the end
147 * of the previous stripe, not the beginning of the next:
150 * ---------------------------------------------------------------------
151 * | 0 | 1 | 2 | 0 | 1 | 2 |
152 * ---------------------------------------------------------------------
154 * if clamped to stripe 2 becomes:
157 * ---------------------------------------------------------------------
158 * | 0 | 1 | 2 | 0 | 1 | 2 |
159 * ---------------------------------------------------------------------
161 obd_off lov_size_to_stripe(struct lov_stripe_md *lsm, obd_off file_size,
164 unsigned long ssize = lsm->lsm_stripe_size;
165 unsigned long swidth = ssize * lsm->lsm_stripe_count;
166 unsigned long stripe_off, this_stripe;
168 if (file_size == OBD_OBJECT_EOF)
169 return OBD_OBJECT_EOF;
171 /* do_div(a, b) returns a % b, and a = a / b */
172 stripe_off = do_div(file_size, swidth);
174 this_stripe = stripeno * ssize;
175 if (stripe_off < this_stripe) {
176 /* Move to end of previous stripe, or zero */
184 stripe_off -= this_stripe;
186 if (stripe_off >= ssize) {
187 /* Clamp to end of this stripe */
192 return (file_size * ssize + stripe_off);
195 /* given an extent in an lov and a stripe, calculate the extent of the stripe
196 * that is contained within the lov extent. this returns true if the given
197 * stripe does intersect with the lov extent. */
198 int lov_stripe_intersects(struct lov_stripe_md *lsm, int stripeno,
199 obd_off start, obd_off end,
200 obd_off *obd_start, obd_off *obd_end)
202 int start_side, end_side;
204 start_side = lov_stripe_offset(lsm, start, stripeno, obd_start);
205 end_side = lov_stripe_offset(lsm, end, stripeno, obd_end);
207 CDEBUG(D_INODE, "["LPU64"->"LPU64"] -> [(%d) "LPU64"->"LPU64" (%d)]\n",
208 start, end, start_side, *obd_start, *obd_end, end_side);
210 /* this stripe doesn't intersect the file extent when neither
211 * start or the end intersected the stripe and obd_start and
212 * obd_end got rounded up to the save value. */
213 if (start_side != 0 && end_side != 0 && *obd_start == *obd_end)
216 /* as mentioned in the lov_stripe_offset commentary, end
217 * might have been shifted in the wrong direction. This
218 * happens when an end offset is before the stripe when viewed
219 * through the "mod stripe size" math. we detect it being shifted
220 * in the wrong direction and touch it up.
221 * interestingly, this can't underflow since end must be > start
222 * if we passed through the previous check.
223 * (should we assert for that somewhere?) */
230 /* compute which stripe number "lov_off" will be written into */
231 int lov_stripe_number(struct lov_stripe_md *lsm, obd_off lov_off)
233 unsigned long ssize = lsm->lsm_stripe_size;
234 unsigned long swidth = ssize * lsm->lsm_stripe_count;
235 unsigned long stripe_off;
237 stripe_off = do_div(lov_off, swidth);
239 return stripe_off / ssize;