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