diff options
author | Dave Chinner <dchinner@redhat.com> | 2013-10-14 18:17:56 -0400 |
---|---|---|
committer | Ben Myers <bpm@sgi.com> | 2013-10-23 18:16:32 -0400 |
commit | c963c6193a5adaec58044e238ef23516d04e5a74 (patch) | |
tree | 0e785abb7cafe10276ee8d46ecfbde5b409ba63f /fs/xfs/xfs_rtbitmap.c | |
parent | a4fbe6ab1e7abecf42b75e9c73701ed33b4ab03b (diff) |
xfs: split xfs_rtalloc.c for userspace sanity
xfs_rtalloc.c is partially shared with userspace. Split the file up
into two parts - one that is kernel private and the other which is
wholly shared with userspace.
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Ben Myers <bpm@sgi.com>
Diffstat (limited to 'fs/xfs/xfs_rtbitmap.c')
-rw-r--r-- | fs/xfs/xfs_rtbitmap.c | 973 |
1 files changed, 973 insertions, 0 deletions
diff --git a/fs/xfs/xfs_rtbitmap.c b/fs/xfs/xfs_rtbitmap.c new file mode 100644 index 000000000000..e30efe8be5e6 --- /dev/null +++ b/fs/xfs/xfs_rtbitmap.c | |||
@@ -0,0 +1,973 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2000-2005 Silicon Graphics, Inc. | ||
3 | * All Rights Reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public License as | ||
7 | * published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it would be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write the Free Software Foundation, | ||
16 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
17 | */ | ||
18 | #include "xfs.h" | ||
19 | #include "xfs_fs.h" | ||
20 | #include "xfs_shared.h" | ||
21 | #include "xfs_format.h" | ||
22 | #include "xfs_log_format.h" | ||
23 | #include "xfs_trans_resv.h" | ||
24 | #include "xfs_bit.h" | ||
25 | #include "xfs_sb.h" | ||
26 | #include "xfs_ag.h" | ||
27 | #include "xfs_mount.h" | ||
28 | #include "xfs_inode.h" | ||
29 | #include "xfs_bmap.h" | ||
30 | #include "xfs_bmap_util.h" | ||
31 | #include "xfs_bmap_btree.h" | ||
32 | #include "xfs_alloc.h" | ||
33 | #include "xfs_error.h" | ||
34 | #include "xfs_trans.h" | ||
35 | #include "xfs_trans_space.h" | ||
36 | #include "xfs_trace.h" | ||
37 | #include "xfs_buf.h" | ||
38 | #include "xfs_icache.h" | ||
39 | #include "xfs_dinode.h" | ||
40 | |||
41 | |||
42 | /* | ||
43 | * Realtime allocator bitmap functions shared with userspace. | ||
44 | */ | ||
45 | |||
46 | /* | ||
47 | * Get a buffer for the bitmap or summary file block specified. | ||
48 | * The buffer is returned read and locked. | ||
49 | */ | ||
50 | int | ||
51 | xfs_rtbuf_get( | ||
52 | xfs_mount_t *mp, /* file system mount structure */ | ||
53 | xfs_trans_t *tp, /* transaction pointer */ | ||
54 | xfs_rtblock_t block, /* block number in bitmap or summary */ | ||
55 | int issum, /* is summary not bitmap */ | ||
56 | xfs_buf_t **bpp) /* output: buffer for the block */ | ||
57 | { | ||
58 | xfs_buf_t *bp; /* block buffer, result */ | ||
59 | xfs_inode_t *ip; /* bitmap or summary inode */ | ||
60 | xfs_bmbt_irec_t map; | ||
61 | int nmap = 1; | ||
62 | int error; /* error value */ | ||
63 | |||
64 | ip = issum ? mp->m_rsumip : mp->m_rbmip; | ||
65 | |||
66 | error = xfs_bmapi_read(ip, block, 1, &map, &nmap, XFS_DATA_FORK); | ||
67 | if (error) | ||
68 | return error; | ||
69 | |||
70 | ASSERT(map.br_startblock != NULLFSBLOCK); | ||
71 | error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, | ||
72 | XFS_FSB_TO_DADDR(mp, map.br_startblock), | ||
73 | mp->m_bsize, 0, &bp, NULL); | ||
74 | if (error) | ||
75 | return error; | ||
76 | ASSERT(!xfs_buf_geterror(bp)); | ||
77 | *bpp = bp; | ||
78 | return 0; | ||
79 | } | ||
80 | |||
81 | /* | ||
82 | * Searching backward from start to limit, find the first block whose | ||
83 | * allocated/free state is different from start's. | ||
84 | */ | ||
85 | int | ||
86 | xfs_rtfind_back( | ||
87 | xfs_mount_t *mp, /* file system mount point */ | ||
88 | xfs_trans_t *tp, /* transaction pointer */ | ||
89 | xfs_rtblock_t start, /* starting block to look at */ | ||
90 | xfs_rtblock_t limit, /* last block to look at */ | ||
91 | xfs_rtblock_t *rtblock) /* out: start block found */ | ||
92 | { | ||
93 | xfs_rtword_t *b; /* current word in buffer */ | ||
94 | int bit; /* bit number in the word */ | ||
95 | xfs_rtblock_t block; /* bitmap block number */ | ||
96 | xfs_buf_t *bp; /* buf for the block */ | ||
97 | xfs_rtword_t *bufp; /* starting word in buffer */ | ||
98 | int error; /* error value */ | ||
99 | xfs_rtblock_t firstbit; /* first useful bit in the word */ | ||
100 | xfs_rtblock_t i; /* current bit number rel. to start */ | ||
101 | xfs_rtblock_t len; /* length of inspected area */ | ||
102 | xfs_rtword_t mask; /* mask of relevant bits for value */ | ||
103 | xfs_rtword_t want; /* mask for "good" values */ | ||
104 | xfs_rtword_t wdiff; /* difference from wanted value */ | ||
105 | int word; /* word number in the buffer */ | ||
106 | |||
107 | /* | ||
108 | * Compute and read in starting bitmap block for starting block. | ||
109 | */ | ||
110 | block = XFS_BITTOBLOCK(mp, start); | ||
111 | error = xfs_rtbuf_get(mp, tp, block, 0, &bp); | ||
112 | if (error) { | ||
113 | return error; | ||
114 | } | ||
115 | bufp = bp->b_addr; | ||
116 | /* | ||
117 | * Get the first word's index & point to it. | ||
118 | */ | ||
119 | word = XFS_BITTOWORD(mp, start); | ||
120 | b = &bufp[word]; | ||
121 | bit = (int)(start & (XFS_NBWORD - 1)); | ||
122 | len = start - limit + 1; | ||
123 | /* | ||
124 | * Compute match value, based on the bit at start: if 1 (free) | ||
125 | * then all-ones, else all-zeroes. | ||
126 | */ | ||
127 | want = (*b & ((xfs_rtword_t)1 << bit)) ? -1 : 0; | ||
128 | /* | ||
129 | * If the starting position is not word-aligned, deal with the | ||
130 | * partial word. | ||
131 | */ | ||
132 | if (bit < XFS_NBWORD - 1) { | ||
133 | /* | ||
134 | * Calculate first (leftmost) bit number to look at, | ||
135 | * and mask for all the relevant bits in this word. | ||
136 | */ | ||
137 | firstbit = XFS_RTMAX((xfs_srtblock_t)(bit - len + 1), 0); | ||
138 | mask = (((xfs_rtword_t)1 << (bit - firstbit + 1)) - 1) << | ||
139 | firstbit; | ||
140 | /* | ||
141 | * Calculate the difference between the value there | ||
142 | * and what we're looking for. | ||
143 | */ | ||
144 | if ((wdiff = (*b ^ want) & mask)) { | ||
145 | /* | ||
146 | * Different. Mark where we are and return. | ||
147 | */ | ||
148 | xfs_trans_brelse(tp, bp); | ||
149 | i = bit - XFS_RTHIBIT(wdiff); | ||
150 | *rtblock = start - i + 1; | ||
151 | return 0; | ||
152 | } | ||
153 | i = bit - firstbit + 1; | ||
154 | /* | ||
155 | * Go on to previous block if that's where the previous word is | ||
156 | * and we need the previous word. | ||
157 | */ | ||
158 | if (--word == -1 && i < len) { | ||
159 | /* | ||
160 | * If done with this block, get the previous one. | ||
161 | */ | ||
162 | xfs_trans_brelse(tp, bp); | ||
163 | error = xfs_rtbuf_get(mp, tp, --block, 0, &bp); | ||
164 | if (error) { | ||
165 | return error; | ||
166 | } | ||
167 | bufp = bp->b_addr; | ||
168 | word = XFS_BLOCKWMASK(mp); | ||
169 | b = &bufp[word]; | ||
170 | } else { | ||
171 | /* | ||
172 | * Go on to the previous word in the buffer. | ||
173 | */ | ||
174 | b--; | ||
175 | } | ||
176 | } else { | ||
177 | /* | ||
178 | * Starting on a word boundary, no partial word. | ||
179 | */ | ||
180 | i = 0; | ||
181 | } | ||
182 | /* | ||
183 | * Loop over whole words in buffers. When we use up one buffer | ||
184 | * we move on to the previous one. | ||
185 | */ | ||
186 | while (len - i >= XFS_NBWORD) { | ||
187 | /* | ||
188 | * Compute difference between actual and desired value. | ||
189 | */ | ||
190 | if ((wdiff = *b ^ want)) { | ||
191 | /* | ||
192 | * Different, mark where we are and return. | ||
193 | */ | ||
194 | xfs_trans_brelse(tp, bp); | ||
195 | i += XFS_NBWORD - 1 - XFS_RTHIBIT(wdiff); | ||
196 | *rtblock = start - i + 1; | ||
197 | return 0; | ||
198 | } | ||
199 | i += XFS_NBWORD; | ||
200 | /* | ||
201 | * Go on to previous block if that's where the previous word is | ||
202 | * and we need the previous word. | ||
203 | */ | ||
204 | if (--word == -1 && i < len) { | ||
205 | /* | ||
206 | * If done with this block, get the previous one. | ||
207 | */ | ||
208 | xfs_trans_brelse(tp, bp); | ||
209 | error = xfs_rtbuf_get(mp, tp, --block, 0, &bp); | ||
210 | if (error) { | ||
211 | return error; | ||
212 | } | ||
213 | bufp = bp->b_addr; | ||
214 | word = XFS_BLOCKWMASK(mp); | ||
215 | b = &bufp[word]; | ||
216 | } else { | ||
217 | /* | ||
218 | * Go on to the previous word in the buffer. | ||
219 | */ | ||
220 | b--; | ||
221 | } | ||
222 | } | ||
223 | /* | ||
224 | * If not ending on a word boundary, deal with the last | ||
225 | * (partial) word. | ||
226 | */ | ||
227 | if (len - i) { | ||
228 | /* | ||
229 | * Calculate first (leftmost) bit number to look at, | ||
230 | * and mask for all the relevant bits in this word. | ||
231 | */ | ||
232 | firstbit = XFS_NBWORD - (len - i); | ||
233 | mask = (((xfs_rtword_t)1 << (len - i)) - 1) << firstbit; | ||
234 | /* | ||
235 | * Compute difference between actual and desired value. | ||
236 | */ | ||
237 | if ((wdiff = (*b ^ want) & mask)) { | ||
238 | /* | ||
239 | * Different, mark where we are and return. | ||
240 | */ | ||
241 | xfs_trans_brelse(tp, bp); | ||
242 | i += XFS_NBWORD - 1 - XFS_RTHIBIT(wdiff); | ||
243 | *rtblock = start - i + 1; | ||
244 | return 0; | ||
245 | } else | ||
246 | i = len; | ||
247 | } | ||
248 | /* | ||
249 | * No match, return that we scanned the whole area. | ||
250 | */ | ||
251 | xfs_trans_brelse(tp, bp); | ||
252 | *rtblock = start - i + 1; | ||
253 | return 0; | ||
254 | } | ||
255 | |||
256 | /* | ||
257 | * Searching forward from start to limit, find the first block whose | ||
258 | * allocated/free state is different from start's. | ||
259 | */ | ||
260 | int | ||
261 | xfs_rtfind_forw( | ||
262 | xfs_mount_t *mp, /* file system mount point */ | ||
263 | xfs_trans_t *tp, /* transaction pointer */ | ||
264 | xfs_rtblock_t start, /* starting block to look at */ | ||
265 | xfs_rtblock_t limit, /* last block to look at */ | ||
266 | xfs_rtblock_t *rtblock) /* out: start block found */ | ||
267 | { | ||
268 | xfs_rtword_t *b; /* current word in buffer */ | ||
269 | int bit; /* bit number in the word */ | ||
270 | xfs_rtblock_t block; /* bitmap block number */ | ||
271 | xfs_buf_t *bp; /* buf for the block */ | ||
272 | xfs_rtword_t *bufp; /* starting word in buffer */ | ||
273 | int error; /* error value */ | ||
274 | xfs_rtblock_t i; /* current bit number rel. to start */ | ||
275 | xfs_rtblock_t lastbit; /* last useful bit in the word */ | ||
276 | xfs_rtblock_t len; /* length of inspected area */ | ||
277 | xfs_rtword_t mask; /* mask of relevant bits for value */ | ||
278 | xfs_rtword_t want; /* mask for "good" values */ | ||
279 | xfs_rtword_t wdiff; /* difference from wanted value */ | ||
280 | int word; /* word number in the buffer */ | ||
281 | |||
282 | /* | ||
283 | * Compute and read in starting bitmap block for starting block. | ||
284 | */ | ||
285 | block = XFS_BITTOBLOCK(mp, start); | ||
286 | error = xfs_rtbuf_get(mp, tp, block, 0, &bp); | ||
287 | if (error) { | ||
288 | return error; | ||
289 | } | ||
290 | bufp = bp->b_addr; | ||
291 | /* | ||
292 | * Get the first word's index & point to it. | ||
293 | */ | ||
294 | word = XFS_BITTOWORD(mp, start); | ||
295 | b = &bufp[word]; | ||
296 | bit = (int)(start & (XFS_NBWORD - 1)); | ||
297 | len = limit - start + 1; | ||
298 | /* | ||
299 | * Compute match value, based on the bit at start: if 1 (free) | ||
300 | * then all-ones, else all-zeroes. | ||
301 | */ | ||
302 | want = (*b & ((xfs_rtword_t)1 << bit)) ? -1 : 0; | ||
303 | /* | ||
304 | * If the starting position is not word-aligned, deal with the | ||
305 | * partial word. | ||
306 | */ | ||
307 | if (bit) { | ||
308 | /* | ||
309 | * Calculate last (rightmost) bit number to look at, | ||
310 | * and mask for all the relevant bits in this word. | ||
311 | */ | ||
312 | lastbit = XFS_RTMIN(bit + len, XFS_NBWORD); | ||
313 | mask = (((xfs_rtword_t)1 << (lastbit - bit)) - 1) << bit; | ||
314 | /* | ||
315 | * Calculate the difference between the value there | ||
316 | * and what we're looking for. | ||
317 | */ | ||
318 | if ((wdiff = (*b ^ want) & mask)) { | ||
319 | /* | ||
320 | * Different. Mark where we are and return. | ||
321 | */ | ||
322 | xfs_trans_brelse(tp, bp); | ||
323 | i = XFS_RTLOBIT(wdiff) - bit; | ||
324 | *rtblock = start + i - 1; | ||
325 | return 0; | ||
326 | } | ||
327 | i = lastbit - bit; | ||
328 | /* | ||
329 | * Go on to next block if that's where the next word is | ||
330 | * and we need the next word. | ||
331 | */ | ||
332 | if (++word == XFS_BLOCKWSIZE(mp) && i < len) { | ||
333 | /* | ||
334 | * If done with this block, get the previous one. | ||
335 | */ | ||
336 | xfs_trans_brelse(tp, bp); | ||
337 | error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp); | ||
338 | if (error) { | ||
339 | return error; | ||
340 | } | ||
341 | b = bufp = bp->b_addr; | ||
342 | word = 0; | ||
343 | } else { | ||
344 | /* | ||
345 | * Go on to the previous word in the buffer. | ||
346 | */ | ||
347 | b++; | ||
348 | } | ||
349 | } else { | ||
350 | /* | ||
351 | * Starting on a word boundary, no partial word. | ||
352 | */ | ||
353 | i = 0; | ||
354 | } | ||
355 | /* | ||
356 | * Loop over whole words in buffers. When we use up one buffer | ||
357 | * we move on to the next one. | ||
358 | */ | ||
359 | while (len - i >= XFS_NBWORD) { | ||
360 | /* | ||
361 | * Compute difference between actual and desired value. | ||
362 | */ | ||
363 | if ((wdiff = *b ^ want)) { | ||
364 | /* | ||
365 | * Different, mark where we are and return. | ||
366 | */ | ||
367 | xfs_trans_brelse(tp, bp); | ||
368 | i += XFS_RTLOBIT(wdiff); | ||
369 | *rtblock = start + i - 1; | ||
370 | return 0; | ||
371 | } | ||
372 | i += XFS_NBWORD; | ||
373 | /* | ||
374 | * Go on to next block if that's where the next word is | ||
375 | * and we need the next word. | ||
376 | */ | ||
377 | if (++word == XFS_BLOCKWSIZE(mp) && i < len) { | ||
378 | /* | ||
379 | * If done with this block, get the next one. | ||
380 | */ | ||
381 | xfs_trans_brelse(tp, bp); | ||
382 | error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp); | ||
383 | if (error) { | ||
384 | return error; | ||
385 | } | ||
386 | b = bufp = bp->b_addr; | ||
387 | word = 0; | ||
388 | } else { | ||
389 | /* | ||
390 | * Go on to the next word in the buffer. | ||
391 | */ | ||
392 | b++; | ||
393 | } | ||
394 | } | ||
395 | /* | ||
396 | * If not ending on a word boundary, deal with the last | ||
397 | * (partial) word. | ||
398 | */ | ||
399 | if ((lastbit = len - i)) { | ||
400 | /* | ||
401 | * Calculate mask for all the relevant bits in this word. | ||
402 | */ | ||
403 | mask = ((xfs_rtword_t)1 << lastbit) - 1; | ||
404 | /* | ||
405 | * Compute difference between actual and desired value. | ||
406 | */ | ||
407 | if ((wdiff = (*b ^ want) & mask)) { | ||
408 | /* | ||
409 | * Different, mark where we are and return. | ||
410 | */ | ||
411 | xfs_trans_brelse(tp, bp); | ||
412 | i += XFS_RTLOBIT(wdiff); | ||
413 | *rtblock = start + i - 1; | ||
414 | return 0; | ||
415 | } else | ||
416 | i = len; | ||
417 | } | ||
418 | /* | ||
419 | * No match, return that we scanned the whole area. | ||
420 | */ | ||
421 | xfs_trans_brelse(tp, bp); | ||
422 | *rtblock = start + i - 1; | ||
423 | return 0; | ||
424 | } | ||
425 | |||
426 | /* | ||
427 | * Read and modify the summary information for a given extent size, | ||
428 | * bitmap block combination. | ||
429 | * Keeps track of a current summary block, so we don't keep reading | ||
430 | * it from the buffer cache. | ||
431 | */ | ||
432 | int | ||
433 | xfs_rtmodify_summary( | ||
434 | xfs_mount_t *mp, /* file system mount point */ | ||
435 | xfs_trans_t *tp, /* transaction pointer */ | ||
436 | int log, /* log2 of extent size */ | ||
437 | xfs_rtblock_t bbno, /* bitmap block number */ | ||
438 | int delta, /* change to make to summary info */ | ||
439 | xfs_buf_t **rbpp, /* in/out: summary block buffer */ | ||
440 | xfs_fsblock_t *rsb) /* in/out: summary block number */ | ||
441 | { | ||
442 | xfs_buf_t *bp; /* buffer for the summary block */ | ||
443 | int error; /* error value */ | ||
444 | xfs_fsblock_t sb; /* summary fsblock */ | ||
445 | int so; /* index into the summary file */ | ||
446 | xfs_suminfo_t *sp; /* pointer to returned data */ | ||
447 | |||
448 | /* | ||
449 | * Compute entry number in the summary file. | ||
450 | */ | ||
451 | so = XFS_SUMOFFS(mp, log, bbno); | ||
452 | /* | ||
453 | * Compute the block number in the summary file. | ||
454 | */ | ||
455 | sb = XFS_SUMOFFSTOBLOCK(mp, so); | ||
456 | /* | ||
457 | * If we have an old buffer, and the block number matches, use that. | ||
458 | */ | ||
459 | if (rbpp && *rbpp && *rsb == sb) | ||
460 | bp = *rbpp; | ||
461 | /* | ||
462 | * Otherwise we have to get the buffer. | ||
463 | */ | ||
464 | else { | ||
465 | /* | ||
466 | * If there was an old one, get rid of it first. | ||
467 | */ | ||
468 | if (rbpp && *rbpp) | ||
469 | xfs_trans_brelse(tp, *rbpp); | ||
470 | error = xfs_rtbuf_get(mp, tp, sb, 1, &bp); | ||
471 | if (error) { | ||
472 | return error; | ||
473 | } | ||
474 | /* | ||
475 | * Remember this buffer and block for the next call. | ||
476 | */ | ||
477 | if (rbpp) { | ||
478 | *rbpp = bp; | ||
479 | *rsb = sb; | ||
480 | } | ||
481 | } | ||
482 | /* | ||
483 | * Point to the summary information, modify and log it. | ||
484 | */ | ||
485 | sp = XFS_SUMPTR(mp, bp, so); | ||
486 | *sp += delta; | ||
487 | xfs_trans_log_buf(tp, bp, (uint)((char *)sp - (char *)bp->b_addr), | ||
488 | (uint)((char *)sp - (char *)bp->b_addr + sizeof(*sp) - 1)); | ||
489 | return 0; | ||
490 | } | ||
491 | |||
492 | /* | ||
493 | * Set the given range of bitmap bits to the given value. | ||
494 | * Do whatever I/O and logging is required. | ||
495 | */ | ||
496 | int | ||
497 | xfs_rtmodify_range( | ||
498 | xfs_mount_t *mp, /* file system mount point */ | ||
499 | xfs_trans_t *tp, /* transaction pointer */ | ||
500 | xfs_rtblock_t start, /* starting block to modify */ | ||
501 | xfs_extlen_t len, /* length of extent to modify */ | ||
502 | int val) /* 1 for free, 0 for allocated */ | ||
503 | { | ||
504 | xfs_rtword_t *b; /* current word in buffer */ | ||
505 | int bit; /* bit number in the word */ | ||
506 | xfs_rtblock_t block; /* bitmap block number */ | ||
507 | xfs_buf_t *bp; /* buf for the block */ | ||
508 | xfs_rtword_t *bufp; /* starting word in buffer */ | ||
509 | int error; /* error value */ | ||
510 | xfs_rtword_t *first; /* first used word in the buffer */ | ||
511 | int i; /* current bit number rel. to start */ | ||
512 | int lastbit; /* last useful bit in word */ | ||
513 | xfs_rtword_t mask; /* mask o frelevant bits for value */ | ||
514 | int word; /* word number in the buffer */ | ||
515 | |||
516 | /* | ||
517 | * Compute starting bitmap block number. | ||
518 | */ | ||
519 | block = XFS_BITTOBLOCK(mp, start); | ||
520 | /* | ||
521 | * Read the bitmap block, and point to its data. | ||
522 | */ | ||
523 | error = xfs_rtbuf_get(mp, tp, block, 0, &bp); | ||
524 | if (error) { | ||
525 | return error; | ||
526 | } | ||
527 | bufp = bp->b_addr; | ||
528 | /* | ||
529 | * Compute the starting word's address, and starting bit. | ||
530 | */ | ||
531 | word = XFS_BITTOWORD(mp, start); | ||
532 | first = b = &bufp[word]; | ||
533 | bit = (int)(start & (XFS_NBWORD - 1)); | ||
534 | /* | ||
535 | * 0 (allocated) => all zeroes; 1 (free) => all ones. | ||
536 | */ | ||
537 | val = -val; | ||
538 | /* | ||
539 | * If not starting on a word boundary, deal with the first | ||
540 | * (partial) word. | ||
541 | */ | ||
542 | if (bit) { | ||
543 | /* | ||
544 | * Compute first bit not changed and mask of relevant bits. | ||
545 | */ | ||
546 | lastbit = XFS_RTMIN(bit + len, XFS_NBWORD); | ||
547 | mask = (((xfs_rtword_t)1 << (lastbit - bit)) - 1) << bit; | ||
548 | /* | ||
549 | * Set/clear the active bits. | ||
550 | */ | ||
551 | if (val) | ||
552 | *b |= mask; | ||
553 | else | ||
554 | *b &= ~mask; | ||
555 | i = lastbit - bit; | ||
556 | /* | ||
557 | * Go on to the next block if that's where the next word is | ||
558 | * and we need the next word. | ||
559 | */ | ||
560 | if (++word == XFS_BLOCKWSIZE(mp) && i < len) { | ||
561 | /* | ||
562 | * Log the changed part of this block. | ||
563 | * Get the next one. | ||
564 | */ | ||
565 | xfs_trans_log_buf(tp, bp, | ||
566 | (uint)((char *)first - (char *)bufp), | ||
567 | (uint)((char *)b - (char *)bufp)); | ||
568 | error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp); | ||
569 | if (error) { | ||
570 | return error; | ||
571 | } | ||
572 | first = b = bufp = bp->b_addr; | ||
573 | word = 0; | ||
574 | } else { | ||
575 | /* | ||
576 | * Go on to the next word in the buffer | ||
577 | */ | ||
578 | b++; | ||
579 | } | ||
580 | } else { | ||
581 | /* | ||
582 | * Starting on a word boundary, no partial word. | ||
583 | */ | ||
584 | i = 0; | ||
585 | } | ||
586 | /* | ||
587 | * Loop over whole words in buffers. When we use up one buffer | ||
588 | * we move on to the next one. | ||
589 | */ | ||
590 | while (len - i >= XFS_NBWORD) { | ||
591 | /* | ||
592 | * Set the word value correctly. | ||
593 | */ | ||
594 | *b = val; | ||
595 | i += XFS_NBWORD; | ||
596 | /* | ||
597 | * Go on to the next block if that's where the next word is | ||
598 | * and we need the next word. | ||
599 | */ | ||
600 | if (++word == XFS_BLOCKWSIZE(mp) && i < len) { | ||
601 | /* | ||
602 | * Log the changed part of this block. | ||
603 | * Get the next one. | ||
604 | */ | ||
605 | xfs_trans_log_buf(tp, bp, | ||
606 | (uint)((char *)first - (char *)bufp), | ||
607 | (uint)((char *)b - (char *)bufp)); | ||
608 | error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp); | ||
609 | if (error) { | ||
610 | return error; | ||
611 | } | ||
612 | first = b = bufp = bp->b_addr; | ||
613 | word = 0; | ||
614 | } else { | ||
615 | /* | ||
616 | * Go on to the next word in the buffer | ||
617 | */ | ||
618 | b++; | ||
619 | } | ||
620 | } | ||
621 | /* | ||
622 | * If not ending on a word boundary, deal with the last | ||
623 | * (partial) word. | ||
624 | */ | ||
625 | if ((lastbit = len - i)) { | ||
626 | /* | ||
627 | * Compute a mask of relevant bits. | ||
628 | */ | ||
629 | bit = 0; | ||
630 | mask = ((xfs_rtword_t)1 << lastbit) - 1; | ||
631 | /* | ||
632 | * Set/clear the active bits. | ||
633 | */ | ||
634 | if (val) | ||
635 | *b |= mask; | ||
636 | else | ||
637 | *b &= ~mask; | ||
638 | b++; | ||
639 | } | ||
640 | /* | ||
641 | * Log any remaining changed bytes. | ||
642 | */ | ||
643 | if (b > first) | ||
644 | xfs_trans_log_buf(tp, bp, (uint)((char *)first - (char *)bufp), | ||
645 | (uint)((char *)b - (char *)bufp - 1)); | ||
646 | return 0; | ||
647 | } | ||
648 | |||
649 | /* | ||
650 | * Mark an extent specified by start and len freed. | ||
651 | * Updates all the summary information as well as the bitmap. | ||
652 | */ | ||
653 | int | ||
654 | xfs_rtfree_range( | ||
655 | xfs_mount_t *mp, /* file system mount point */ | ||
656 | xfs_trans_t *tp, /* transaction pointer */ | ||
657 | xfs_rtblock_t start, /* starting block to free */ | ||
658 | xfs_extlen_t len, /* length to free */ | ||
659 | xfs_buf_t **rbpp, /* in/out: summary block buffer */ | ||
660 | xfs_fsblock_t *rsb) /* in/out: summary block number */ | ||
661 | { | ||
662 | xfs_rtblock_t end; /* end of the freed extent */ | ||
663 | int error; /* error value */ | ||
664 | xfs_rtblock_t postblock; /* first block freed > end */ | ||
665 | xfs_rtblock_t preblock; /* first block freed < start */ | ||
666 | |||
667 | end = start + len - 1; | ||
668 | /* | ||
669 | * Modify the bitmap to mark this extent freed. | ||
670 | */ | ||
671 | error = xfs_rtmodify_range(mp, tp, start, len, 1); | ||
672 | if (error) { | ||
673 | return error; | ||
674 | } | ||
675 | /* | ||
676 | * Assume we're freeing out of the middle of an allocated extent. | ||
677 | * We need to find the beginning and end of the extent so we can | ||
678 | * properly update the summary. | ||
679 | */ | ||
680 | error = xfs_rtfind_back(mp, tp, start, 0, &preblock); | ||
681 | if (error) { | ||
682 | return error; | ||
683 | } | ||
684 | /* | ||
685 | * Find the next allocated block (end of allocated extent). | ||
686 | */ | ||
687 | error = xfs_rtfind_forw(mp, tp, end, mp->m_sb.sb_rextents - 1, | ||
688 | &postblock); | ||
689 | if (error) | ||
690 | return error; | ||
691 | /* | ||
692 | * If there are blocks not being freed at the front of the | ||
693 | * old extent, add summary data for them to be allocated. | ||
694 | */ | ||
695 | if (preblock < start) { | ||
696 | error = xfs_rtmodify_summary(mp, tp, | ||
697 | XFS_RTBLOCKLOG(start - preblock), | ||
698 | XFS_BITTOBLOCK(mp, preblock), -1, rbpp, rsb); | ||
699 | if (error) { | ||
700 | return error; | ||
701 | } | ||
702 | } | ||
703 | /* | ||
704 | * If there are blocks not being freed at the end of the | ||
705 | * old extent, add summary data for them to be allocated. | ||
706 | */ | ||
707 | if (postblock > end) { | ||
708 | error = xfs_rtmodify_summary(mp, tp, | ||
709 | XFS_RTBLOCKLOG(postblock - end), | ||
710 | XFS_BITTOBLOCK(mp, end + 1), -1, rbpp, rsb); | ||
711 | if (error) { | ||
712 | return error; | ||
713 | } | ||
714 | } | ||
715 | /* | ||
716 | * Increment the summary information corresponding to the entire | ||
717 | * (new) free extent. | ||
718 | */ | ||
719 | error = xfs_rtmodify_summary(mp, tp, | ||
720 | XFS_RTBLOCKLOG(postblock + 1 - preblock), | ||
721 | XFS_BITTOBLOCK(mp, preblock), 1, rbpp, rsb); | ||
722 | return error; | ||
723 | } | ||
724 | |||
725 | /* | ||
726 | * Check that the given range is either all allocated (val = 0) or | ||
727 | * all free (val = 1). | ||
728 | */ | ||
729 | int | ||
730 | xfs_rtcheck_range( | ||
731 | xfs_mount_t *mp, /* file system mount point */ | ||
732 | xfs_trans_t *tp, /* transaction pointer */ | ||
733 | xfs_rtblock_t start, /* starting block number of extent */ | ||
734 | xfs_extlen_t len, /* length of extent */ | ||
735 | int val, /* 1 for free, 0 for allocated */ | ||
736 | xfs_rtblock_t *new, /* out: first block not matching */ | ||
737 | int *stat) /* out: 1 for matches, 0 for not */ | ||
738 | { | ||
739 | xfs_rtword_t *b; /* current word in buffer */ | ||
740 | int bit; /* bit number in the word */ | ||
741 | xfs_rtblock_t block; /* bitmap block number */ | ||
742 | xfs_buf_t *bp; /* buf for the block */ | ||
743 | xfs_rtword_t *bufp; /* starting word in buffer */ | ||
744 | int error; /* error value */ | ||
745 | xfs_rtblock_t i; /* current bit number rel. to start */ | ||
746 | xfs_rtblock_t lastbit; /* last useful bit in word */ | ||
747 | xfs_rtword_t mask; /* mask of relevant bits for value */ | ||
748 | xfs_rtword_t wdiff; /* difference from wanted value */ | ||
749 | int word; /* word number in the buffer */ | ||
750 | |||
751 | /* | ||
752 | * Compute starting bitmap block number | ||
753 | */ | ||
754 | block = XFS_BITTOBLOCK(mp, start); | ||
755 | /* | ||
756 | * Read the bitmap block. | ||
757 | */ | ||
758 | error = xfs_rtbuf_get(mp, tp, block, 0, &bp); | ||
759 | if (error) { | ||
760 | return error; | ||
761 | } | ||
762 | bufp = bp->b_addr; | ||
763 | /* | ||
764 | * Compute the starting word's address, and starting bit. | ||
765 | */ | ||
766 | word = XFS_BITTOWORD(mp, start); | ||
767 | b = &bufp[word]; | ||
768 | bit = (int)(start & (XFS_NBWORD - 1)); | ||
769 | /* | ||
770 | * 0 (allocated) => all zero's; 1 (free) => all one's. | ||
771 | */ | ||
772 | val = -val; | ||
773 | /* | ||
774 | * If not starting on a word boundary, deal with the first | ||
775 | * (partial) word. | ||
776 | */ | ||
777 | if (bit) { | ||
778 | /* | ||
779 | * Compute first bit not examined. | ||
780 | */ | ||
781 | lastbit = XFS_RTMIN(bit + len, XFS_NBWORD); | ||
782 | /* | ||
783 | * Mask of relevant bits. | ||
784 | */ | ||
785 | mask = (((xfs_rtword_t)1 << (lastbit - bit)) - 1) << bit; | ||
786 | /* | ||
787 | * Compute difference between actual and desired value. | ||
788 | */ | ||
789 | if ((wdiff = (*b ^ val) & mask)) { | ||
790 | /* | ||
791 | * Different, compute first wrong bit and return. | ||
792 | */ | ||
793 | xfs_trans_brelse(tp, bp); | ||
794 | i = XFS_RTLOBIT(wdiff) - bit; | ||
795 | *new = start + i; | ||
796 | *stat = 0; | ||
797 | return 0; | ||
798 | } | ||
799 | i = lastbit - bit; | ||
800 | /* | ||
801 | * Go on to next block if that's where the next word is | ||
802 | * and we need the next word. | ||
803 | */ | ||
804 | if (++word == XFS_BLOCKWSIZE(mp) && i < len) { | ||
805 | /* | ||
806 | * If done with this block, get the next one. | ||
807 | */ | ||
808 | xfs_trans_brelse(tp, bp); | ||
809 | error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp); | ||
810 | if (error) { | ||
811 | return error; | ||
812 | } | ||
813 | b = bufp = bp->b_addr; | ||
814 | word = 0; | ||
815 | } else { | ||
816 | /* | ||
817 | * Go on to the next word in the buffer. | ||
818 | */ | ||
819 | b++; | ||
820 | } | ||
821 | } else { | ||
822 | /* | ||
823 | * Starting on a word boundary, no partial word. | ||
824 | */ | ||
825 | i = 0; | ||
826 | } | ||
827 | /* | ||
828 | * Loop over whole words in buffers. When we use up one buffer | ||
829 | * we move on to the next one. | ||
830 | */ | ||
831 | while (len - i >= XFS_NBWORD) { | ||
832 | /* | ||
833 | * Compute difference between actual and desired value. | ||
834 | */ | ||
835 | if ((wdiff = *b ^ val)) { | ||
836 | /* | ||
837 | * Different, compute first wrong bit and return. | ||
838 | */ | ||
839 | xfs_trans_brelse(tp, bp); | ||
840 | i += XFS_RTLOBIT(wdiff); | ||
841 | *new = start + i; | ||
842 | *stat = 0; | ||
843 | return 0; | ||
844 | } | ||
845 | i += XFS_NBWORD; | ||
846 | /* | ||
847 | * Go on to next block if that's where the next word is | ||
848 | * and we need the next word. | ||
849 | */ | ||
850 | if (++word == XFS_BLOCKWSIZE(mp) && i < len) { | ||
851 | /* | ||
852 | * If done with this block, get the next one. | ||
853 | */ | ||
854 | xfs_trans_brelse(tp, bp); | ||
855 | error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp); | ||
856 | if (error) { | ||
857 | return error; | ||
858 | } | ||
859 | b = bufp = bp->b_addr; | ||
860 | word = 0; | ||
861 | } else { | ||
862 | /* | ||
863 | * Go on to the next word in the buffer. | ||
864 | */ | ||
865 | b++; | ||
866 | } | ||
867 | } | ||
868 | /* | ||
869 | * If not ending on a word boundary, deal with the last | ||
870 | * (partial) word. | ||
871 | */ | ||
872 | if ((lastbit = len - i)) { | ||
873 | /* | ||
874 | * Mask of relevant bits. | ||
875 | */ | ||
876 | mask = ((xfs_rtword_t)1 << lastbit) - 1; | ||
877 | /* | ||
878 | * Compute difference between actual and desired value. | ||
879 | */ | ||
880 | if ((wdiff = (*b ^ val) & mask)) { | ||
881 | /* | ||
882 | * Different, compute first wrong bit and return. | ||
883 | */ | ||
884 | xfs_trans_brelse(tp, bp); | ||
885 | i += XFS_RTLOBIT(wdiff); | ||
886 | *new = start + i; | ||
887 | *stat = 0; | ||
888 | return 0; | ||
889 | } else | ||
890 | i = len; | ||
891 | } | ||
892 | /* | ||
893 | * Successful, return. | ||
894 | */ | ||
895 | xfs_trans_brelse(tp, bp); | ||
896 | *new = start + i; | ||
897 | *stat = 1; | ||
898 | return 0; | ||
899 | } | ||
900 | |||
901 | #ifdef DEBUG | ||
902 | /* | ||
903 | * Check that the given extent (block range) is allocated already. | ||
904 | */ | ||
905 | STATIC int /* error */ | ||
906 | xfs_rtcheck_alloc_range( | ||
907 | xfs_mount_t *mp, /* file system mount point */ | ||
908 | xfs_trans_t *tp, /* transaction pointer */ | ||
909 | xfs_rtblock_t bno, /* starting block number of extent */ | ||
910 | xfs_extlen_t len) /* length of extent */ | ||
911 | { | ||
912 | xfs_rtblock_t new; /* dummy for xfs_rtcheck_range */ | ||
913 | int stat; | ||
914 | int error; | ||
915 | |||
916 | error = xfs_rtcheck_range(mp, tp, bno, len, 0, &new, &stat); | ||
917 | if (error) | ||
918 | return error; | ||
919 | ASSERT(stat); | ||
920 | return 0; | ||
921 | } | ||
922 | #else | ||
923 | #define xfs_rtcheck_alloc_range(m,t,b,l) (0) | ||
924 | #endif | ||
925 | /* | ||
926 | * Free an extent in the realtime subvolume. Length is expressed in | ||
927 | * realtime extents, as is the block number. | ||
928 | */ | ||
929 | int /* error */ | ||
930 | xfs_rtfree_extent( | ||
931 | xfs_trans_t *tp, /* transaction pointer */ | ||
932 | xfs_rtblock_t bno, /* starting block number to free */ | ||
933 | xfs_extlen_t len) /* length of extent freed */ | ||
934 | { | ||
935 | int error; /* error value */ | ||
936 | xfs_mount_t *mp; /* file system mount structure */ | ||
937 | xfs_fsblock_t sb; /* summary file block number */ | ||
938 | xfs_buf_t *sumbp = NULL; /* summary file block buffer */ | ||
939 | |||
940 | mp = tp->t_mountp; | ||
941 | |||
942 | ASSERT(mp->m_rbmip->i_itemp != NULL); | ||
943 | ASSERT(xfs_isilocked(mp->m_rbmip, XFS_ILOCK_EXCL)); | ||
944 | |||
945 | error = xfs_rtcheck_alloc_range(mp, tp, bno, len); | ||
946 | if (error) | ||
947 | return error; | ||
948 | |||
949 | /* | ||
950 | * Free the range of realtime blocks. | ||
951 | */ | ||
952 | error = xfs_rtfree_range(mp, tp, bno, len, &sumbp, &sb); | ||
953 | if (error) { | ||
954 | return error; | ||
955 | } | ||
956 | /* | ||
957 | * Mark more blocks free in the superblock. | ||
958 | */ | ||
959 | xfs_trans_mod_sb(tp, XFS_TRANS_SB_FREXTENTS, (long)len); | ||
960 | /* | ||
961 | * If we've now freed all the blocks, reset the file sequence | ||
962 | * number to 0. | ||
963 | */ | ||
964 | if (tp->t_frextents_delta + mp->m_sb.sb_frextents == | ||
965 | mp->m_sb.sb_rextents) { | ||
966 | if (!(mp->m_rbmip->i_d.di_flags & XFS_DIFLAG_NEWRTBM)) | ||
967 | mp->m_rbmip->i_d.di_flags |= XFS_DIFLAG_NEWRTBM; | ||
968 | *(__uint64_t *)&mp->m_rbmip->i_d.di_atime = 0; | ||
969 | xfs_trans_log_inode(tp, mp->m_rbmip, XFS_ILOG_CORE); | ||
970 | } | ||
971 | return 0; | ||
972 | } | ||
973 | |||