Whamcloud - gitweb
b=3031
[fs/lustre-release.git] / lustre / lov / lov_offset.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * Copyright (C) 2002, 2003 Cluster File Systems, Inc.
5  *
6  *   This file is part of Lustre, http://www.lustre.org.
7  *
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.
11  *
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.
16  *
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.
20  */
21
22 #ifndef EXPORT_SYMTAB
23 # define EXPORT_SYMTAB
24 #endif
25 #define DEBUG_SUBSYSTEM S_LOV
26
27 #ifdef __KERNEL__
28 #include <asm/div64.h>
29 #else
30 #include <liblustre.h>
31 #endif
32
33 #include <linux/obd_class.h>
34 #include <linux/obd_lov.h>
35
36 #include "lov_internal.h"
37
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,
40                          int stripeno)
41 {
42         unsigned long ssize  = lsm->lsm_stripe_size;
43         unsigned long swidth = ssize * lsm->lsm_stripe_count;
44         unsigned long stripe_size;
45         obd_size lov_size;
46         ENTRY;
47
48         if (ost_size == 0)
49                 RETURN(0);
50
51         /* do_div(a, b) returns a % b, and a = a / b */
52         stripe_size = do_div(ost_size, ssize);
53         if (stripe_size)
54                 lov_size = ost_size * swidth + stripeno * ssize + stripe_size;
55         else
56                 lov_size = (ost_size - 1) * swidth + (stripeno + 1) * ssize;
57
58         RETURN(lov_size);
59 }
60
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.
65  *
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:
70  *
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:
74  *
75  *             S                                              E
76  * ---------------------------------------------------------------------
77  * |    0    |     1     |     2     |    0    |     1     |     2     |
78  * ---------------------------------------------------------------------
79  *
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:
82  *
83  *             S         E
84  * -----------------------------------
85  * |    0    |     1     |     2     |
86  * -----------------------------------
87  *
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
90  * the stripe:
91  *
92  *   S                   E
93  * ---------------------------------------------------------------------
94  * |    1    |     1     |     1     |    1    |     1     |     1     |
95  * ---------------------------------------------------------------------
96  *
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.
99  *
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:
104  *
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)
111 {
112         unsigned long ssize  = lsm->lsm_stripe_size;
113         unsigned long swidth = ssize * lsm->lsm_stripe_count;
114         unsigned long stripe_off, this_stripe;
115         int ret = 0;
116
117         if (lov_off == OBD_OBJECT_EOF) {
118                 *obd_off = OBD_OBJECT_EOF;
119                 return 0;
120         }
121
122         /* do_div(a, b) returns a % b, and a = a / b */
123         stripe_off = do_div(lov_off, swidth);
124
125         this_stripe = stripeno * ssize;
126         if (stripe_off < this_stripe) {
127                 stripe_off = 0;
128                 ret = -1;
129         } else {
130                 stripe_off -= this_stripe;
131
132                 if (stripe_off >= ssize) {
133                         stripe_off = ssize;
134                         ret = 1;
135                 }
136         }
137
138         *obd_off = lov_off * ssize + stripe_off;
139         return ret;
140 }
141
142 /* Given a whole-file size and a stripe number, give the file size which
143  * corresponds to the individual object of that stripe.
144  *
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:
148  *
149  *                                               S
150  * ---------------------------------------------------------------------
151  * |    0    |     1     |     2     |    0    |     1     |     2     |
152  * ---------------------------------------------------------------------
153  *
154  * if clamped to stripe 2 becomes:
155  *
156  *                                   S
157  * ---------------------------------------------------------------------
158  * |    0    |     1     |     2     |    0    |     1     |     2     |
159  * ---------------------------------------------------------------------
160  */
161 obd_off lov_size_to_stripe(struct lov_stripe_md *lsm, obd_off file_size,
162                            int stripeno)
163 {
164         unsigned long ssize  = lsm->lsm_stripe_size;
165         unsigned long swidth = ssize * lsm->lsm_stripe_count;
166         unsigned long stripe_off, this_stripe;
167
168         if (file_size == OBD_OBJECT_EOF)
169                 return OBD_OBJECT_EOF;
170
171         /* do_div(a, b) returns a % b, and a = a / b */
172         stripe_off = do_div(file_size, swidth);
173
174         this_stripe = stripeno * ssize;
175         if (stripe_off < this_stripe) {
176                 /* Move to end of previous stripe, or zero */
177                 if (file_size > 0) {
178                         file_size--;
179                         stripe_off = ssize;
180                 } else {
181                         stripe_off = 0;
182                 }
183         } else {
184                 stripe_off -= this_stripe;
185
186                 if (stripe_off >= ssize) {
187                         /* Clamp to end of this stripe */
188                         stripe_off = ssize;
189                 }
190         }
191
192         return (file_size * ssize + stripe_off);
193 }
194
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)
201 {
202         int start_side, end_side;
203
204         start_side = lov_stripe_offset(lsm, start, stripeno, obd_start);
205         end_side = lov_stripe_offset(lsm, end, stripeno, obd_end);
206
207         CDEBUG(D_INODE, "["LPU64"->"LPU64"] -> [(%d) "LPU64"->"LPU64" (%d)]\n",
208                start, end, start_side, *obd_start, *obd_end, end_side);
209
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)
214                 return 0;
215
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?) */
224         if (end_side != 0)
225                 (*obd_end)--;
226
227         return 1;
228 }
229
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)
232 {
233         unsigned long ssize  = lsm->lsm_stripe_size;
234         unsigned long swidth = ssize * lsm->lsm_stripe_count;
235         unsigned long stripe_off;
236
237         stripe_off = do_div(lov_off, swidth);
238
239         return stripe_off / ssize;
240 }