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