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