Whamcloud - gitweb
LU-14487 modules: remove references to Sun Trademark.
[fs/lustre-release.git] / lustre / lov / lov_offset.c
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.gnu.org/licenses/gpl-2.0.html
19  *
20  * GPL HEADER END
21  */
22 /*
23  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Use is subject to license terms.
25  *
26  * Copyright (c) 2012, 2017, Intel Corporation.
27  */
28 /*
29  * This file is part of Lustre, http://www.lustre.org/
30  */
31
32 #define DEBUG_SUBSYSTEM S_LOV
33
34 #include <libcfs/libcfs.h>
35
36 #include <obd_class.h>
37
38 #include "lov_internal.h"
39
40 loff_t stripe_width(struct lov_stripe_md *lsm, unsigned int index)
41 {
42         struct lov_stripe_md_entry *entry = lsm->lsm_entries[index];
43
44         LASSERT(index < lsm->lsm_entry_count);
45
46         if (lsme_is_dom(entry))
47                 return (loff_t)entry->lsme_stripe_size;
48
49         return (loff_t)entry->lsme_stripe_size * entry->lsme_stripe_count;
50 }
51
52 /* compute object size given "stripeno" and the ost size */
53 u64 lov_stripe_size(struct lov_stripe_md *lsm, int index, u64 ost_size,
54                     int stripeno)
55 {
56         unsigned long ssize = lsm->lsm_entries[index]->lsme_stripe_size;
57         unsigned long stripe_size;
58         loff_t swidth;
59         loff_t lov_size;
60
61         ENTRY;
62
63         if (ost_size == 0)
64                 RETURN(0);
65
66         swidth = stripe_width(lsm, index);
67
68         /* lov_do_div64(a, b) returns a % b, and a = a / b */
69         stripe_size = lov_do_div64(ost_size, ssize);
70         if (stripe_size)
71                 lov_size = ost_size * swidth + stripeno * ssize + stripe_size;
72         else
73                 lov_size = (ost_size - 1) * swidth + (stripeno + 1) * ssize;
74
75         RETURN(lov_size);
76 }
77
78 /**
79  * Compute file level page index by stripe level page offset
80  */
81 pgoff_t lov_stripe_pgoff(struct lov_stripe_md *lsm, int index,
82                          pgoff_t stripe_index, int stripe)
83 {
84         loff_t offset;
85
86         offset = lov_stripe_size(lsm, index,
87                                  (stripe_index << PAGE_SHIFT) + 1,
88                                  stripe);
89         return offset >> PAGE_SHIFT;
90 }
91
92 /*
93  * we have an offset in file backed by an lov and want to find out where
94  * that offset lands in our given stripe of the file.  for the easy
95  * case where the offset is within the stripe, we just have to scale the
96  * offset down to make it relative to the stripe instead of the lov.
97  *
98  * the harder case is what to do when the offset doesn't intersect the
99  * stripe.  callers will want start offsets clamped ahead to the start
100  * of the nearest stripe in the file.  end offsets similarly clamped to the
101  * nearest ending byte of a stripe in the file:
102  *
103  * all this function does is move offsets to the nearest region of the
104  * stripe, and it does its work "mod" the full length of all the stripes.
105  * consider a file with 3 stripes:
106  *
107  *             S                                              E
108  * ---------------------------------------------------------------------
109  * |    0    |     1     |     2     |    0    |     1     |     2     |
110  * ---------------------------------------------------------------------
111  *
112  * to find stripe 1's offsets for S and E, it divides by the full stripe
113  * width and does its math in the context of a single set of stripes:
114  *
115  *             S         E
116  * -----------------------------------
117  * |    0    |     1     |     2     |
118  * -----------------------------------
119  *
120  * it'll notice that E is outside stripe 1 and clamp it to the end of the
121  * stripe, then multiply it back out by lov_off to give the real offsets in
122  * the stripe:
123  *
124  *   S                   E
125  * ---------------------------------------------------------------------
126  * |    1    |     1     |     1     |    1    |     1     |     1     |
127  * ---------------------------------------------------------------------
128  *
129  * it would have done similarly and pulled S forward to the start of a 1
130  * stripe if, say, S had landed in a 0 stripe.
131  *
132  * this rounding isn't always correct.  consider an E lov offset that lands
133  * on a 0 stripe, the "mod stripe width" math will pull it forward to the
134  * start of a 1 stripe, when in fact it wanted to be rounded back to the end
135  * of a previous 1 stripe.  this logic is handled by callers and this is why:
136  *
137  * this function returns < 0 when the offset was "before" the stripe and
138  * was moved forward to the start of the stripe in question;  0 when it
139  * falls in the stripe and no shifting was done; > 0 when the offset
140  * was outside the stripe and was pulled back to its final byte.
141  */
142 int lov_stripe_offset(struct lov_stripe_md *lsm, int index, loff_t lov_off,
143                       int stripeno, loff_t *obdoff)
144 {
145         unsigned long ssize  = lsm->lsm_entries[index]->lsme_stripe_size;
146         loff_t stripe_off;
147         loff_t this_stripe;
148         loff_t swidth;
149         int ret = 0;
150
151         if (lov_off == OBD_OBJECT_EOF) {
152                 *obdoff = OBD_OBJECT_EOF;
153                 return 0;
154         }
155
156         swidth = stripe_width(lsm, index);
157
158         /* lov_do_div64(a, b) returns a % b, and a = a / b */
159         stripe_off = lov_do_div64(lov_off, swidth);
160
161         this_stripe = (loff_t)stripeno * ssize;
162         if (stripe_off < this_stripe) {
163                 stripe_off = 0;
164                 ret = -1;
165         } else {
166                 stripe_off -= this_stripe;
167
168                 if (stripe_off >= ssize) {
169                         stripe_off = ssize;
170                         ret = 1;
171                 }
172         }
173
174         *obdoff = lov_off * ssize + stripe_off;
175         return ret;
176 }
177
178 /*
179  * Given a whole-file size and a stripe number, give the file size which
180  * corresponds to the individual object of that stripe.
181  *
182  * This behaves basically in the same was as lov_stripe_offset, except that
183  * file sizes falling before the beginning of a stripe are clamped to the end
184  * of the previous stripe, not the beginning of the next:
185  *
186  *                                               S
187  * ---------------------------------------------------------------------
188  * |    0    |     1     |     2     |    0    |     1     |     2     |
189  * ---------------------------------------------------------------------
190  *
191  * if clamped to stripe 2 becomes:
192  *
193  *                                   S
194  * ---------------------------------------------------------------------
195  * |    0    |     1     |     2     |    0    |     1     |     2     |
196  * ---------------------------------------------------------------------
197  */
198 loff_t lov_size_to_stripe(struct lov_stripe_md *lsm, int index, u64 file_size,
199                           int stripeno)
200 {
201         unsigned long ssize = lsm->lsm_entries[index]->lsme_stripe_size;
202         loff_t stripe_off;
203         loff_t this_stripe;
204         loff_t swidth;
205
206         if (file_size == OBD_OBJECT_EOF)
207                 return OBD_OBJECT_EOF;
208
209         swidth = stripe_width(lsm, index);
210
211         /* lov_do_div64(a, b) returns a % b, and a = a / b */
212         stripe_off = lov_do_div64(file_size, swidth);
213
214         this_stripe = (loff_t)stripeno * ssize;
215         if (stripe_off < this_stripe) {
216                 /* Move to end of previous stripe, or zero */
217                 if (file_size > 0) {
218                         file_size--;
219                         stripe_off = ssize;
220                 } else {
221                         stripe_off = 0;
222                 }
223         } else {
224                 stripe_off -= this_stripe;
225
226                 if (stripe_off >= ssize) {
227                         /* Clamp to end of this stripe */
228                         stripe_off = ssize;
229                 }
230         }
231
232         return (file_size * ssize + stripe_off);
233 }
234
235 /*
236  * given an extent in an lov and a stripe, calculate the extent of the stripe
237  * that is contained within the lov extent.  this returns true if the given
238  * stripe does intersect with the lov extent.
239  *
240  * Closed interval [@obd_start, @obd_end] will be returned if caller needs them.
241  */
242 int lov_stripe_intersects(struct lov_stripe_md *lsm, int index, int stripeno,
243                           struct lu_extent *ext, u64 *obd_start, u64 *obd_end)
244 {
245         struct lov_stripe_md_entry *entry = lsm->lsm_entries[index];
246         u64 start, end;
247         int start_side, end_side;
248         u64 loc_start, loc_end;
249
250         if (!lu_extent_is_overlapped(ext, &entry->lsme_extent))
251                         return 0;
252
253         if (!obd_start)
254                 obd_start = &loc_start;
255         if (!obd_end)
256                 obd_end = &loc_end;
257
258         start = max_t(__u64, ext->e_start, entry->lsme_extent.e_start);
259         end = min_t(__u64, ext->e_end, entry->lsme_extent.e_end);
260         if (end != OBD_OBJECT_EOF)
261                 end--;
262
263         start_side = lov_stripe_offset(lsm, index, start, stripeno, obd_start);
264         end_side = lov_stripe_offset(lsm, index, end, stripeno, obd_end);
265
266         CDEBUG(D_INODE, "[%lld->%lld] -> [(%d) %lld->%lld (%d)]\n",
267                 start, end, start_side, *obd_start, *obd_end, end_side);
268
269         /*
270          * this stripe doesn't intersect the file extent when neither
271          * start or the end intersected the stripe and obd_start and
272          * obd_end got rounded up to the save value.
273          */
274         if (start_side != 0 && end_side != 0 && *obd_start == *obd_end)
275                 return 0;
276
277         /*
278          * as mentioned in the lov_stripe_offset commentary, end
279          * might have been shifted in the wrong direction.  This
280          * happens when an end offset is before the stripe when viewed
281          * through the "mod stripe size" math. we detect it being shifted
282          * in the wrong direction and touch it up.
283          * interestingly, this can't underflow since end must be > start
284          * if we passed through the previous check.
285          * (should we assert for that somewhere?)
286          */
287         if (end_side != 0)
288                 (*obd_end)--;
289
290         return 1;
291 }
292
293 /* compute which stripe number "lov_off" will be written into */
294 int lov_stripe_number(struct lov_stripe_md *lsm, int index, loff_t lov_off)
295 {
296         unsigned long ssize = lsm->lsm_entries[index]->lsme_stripe_size;
297         loff_t stripe_off;
298         loff_t swidth;
299
300         swidth = stripe_width(lsm, index);
301
302         stripe_off = lov_do_div64(lov_off, swidth);
303
304         /* Puts stripe_off/ssize result into stripe_off */
305         lov_do_div64(stripe_off, ssize);
306
307         return stripe_off;
308 }