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