1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Copyright (c) 2000-2005 Silicon Graphics, Inc. |
4 | * All Rights Reserved. |
5 | */ |
6 | #include "xfs.h" |
7 | #include "xfs_fs.h" |
8 | #include "xfs_shared.h" |
9 | #include "xfs_format.h" |
10 | #include "xfs_log_format.h" |
11 | #include "xfs_trans_resv.h" |
12 | #include "xfs_bit.h" |
13 | #include "xfs_mount.h" |
14 | #include "xfs_inode.h" |
15 | #include "xfs_bmap.h" |
16 | #include "xfs_trans.h" |
17 | #include "xfs_rtalloc.h" |
18 | #include "xfs_error.h" |
19 | #include "xfs_rtbitmap.h" |
20 | #include "xfs_health.h" |
21 | |
22 | /* |
23 | * Realtime allocator bitmap functions shared with userspace. |
24 | */ |
25 | |
26 | /* |
27 | * Real time buffers need verifiers to avoid runtime warnings during IO. |
28 | * We don't have anything to verify, however, so these are just dummy |
29 | * operations. |
30 | */ |
31 | static void |
32 | xfs_rtbuf_verify_read( |
33 | struct xfs_buf *bp) |
34 | { |
35 | return; |
36 | } |
37 | |
38 | static void |
39 | xfs_rtbuf_verify_write( |
40 | struct xfs_buf *bp) |
41 | { |
42 | return; |
43 | } |
44 | |
45 | const struct xfs_buf_ops xfs_rtbuf_ops = { |
46 | .name = "rtbuf" , |
47 | .verify_read = xfs_rtbuf_verify_read, |
48 | .verify_write = xfs_rtbuf_verify_write, |
49 | }; |
50 | |
51 | /* Release cached rt bitmap and summary buffers. */ |
52 | void |
53 | xfs_rtbuf_cache_relse( |
54 | struct xfs_rtalloc_args *args) |
55 | { |
56 | if (args->rbmbp) { |
57 | xfs_trans_brelse(args->tp, args->rbmbp); |
58 | args->rbmbp = NULL; |
59 | args->rbmoff = NULLFILEOFF; |
60 | } |
61 | if (args->sumbp) { |
62 | xfs_trans_brelse(args->tp, args->sumbp); |
63 | args->sumbp = NULL; |
64 | args->sumoff = NULLFILEOFF; |
65 | } |
66 | } |
67 | |
68 | /* |
69 | * Get a buffer for the bitmap or summary file block specified. |
70 | * The buffer is returned read and locked. |
71 | */ |
72 | int |
73 | xfs_rtbuf_get( |
74 | struct xfs_rtalloc_args *args, |
75 | xfs_fileoff_t block, /* block number in bitmap or summary */ |
76 | int issum) /* is summary not bitmap */ |
77 | { |
78 | struct xfs_mount *mp = args->mp; |
79 | struct xfs_buf **cbpp; /* cached block buffer */ |
80 | xfs_fileoff_t *coffp; /* cached block number */ |
81 | struct xfs_buf *bp; /* block buffer, result */ |
82 | struct xfs_inode *ip; /* bitmap or summary inode */ |
83 | struct xfs_bmbt_irec map; |
84 | enum xfs_blft type; |
85 | int nmap = 1; |
86 | int error; |
87 | |
88 | if (issum) { |
89 | cbpp = &args->sumbp; |
90 | coffp = &args->sumoff; |
91 | ip = mp->m_rsumip; |
92 | type = XFS_BLFT_RTSUMMARY_BUF; |
93 | } else { |
94 | cbpp = &args->rbmbp; |
95 | coffp = &args->rbmoff; |
96 | ip = mp->m_rbmip; |
97 | type = XFS_BLFT_RTBITMAP_BUF; |
98 | } |
99 | |
100 | /* |
101 | * If we have a cached buffer, and the block number matches, use that. |
102 | */ |
103 | if (*cbpp && *coffp == block) |
104 | return 0; |
105 | |
106 | /* |
107 | * Otherwise we have to have to get the buffer. If there was an old |
108 | * one, get rid of it first. |
109 | */ |
110 | if (*cbpp) { |
111 | xfs_trans_brelse(args->tp, *cbpp); |
112 | *cbpp = NULL; |
113 | } |
114 | |
115 | error = xfs_bmapi_read(ip, block, 1, &map, &nmap, 0); |
116 | if (error) |
117 | return error; |
118 | |
119 | if (XFS_IS_CORRUPT(mp, nmap == 0 || !xfs_bmap_is_written_extent(&map))) { |
120 | xfs_rt_mark_sick(mp, mask: issum ? XFS_SICK_RT_SUMMARY : |
121 | XFS_SICK_RT_BITMAP); |
122 | return -EFSCORRUPTED; |
123 | } |
124 | |
125 | ASSERT(map.br_startblock != NULLFSBLOCK); |
126 | error = xfs_trans_read_buf(mp, args->tp, mp->m_ddev_targp, |
127 | XFS_FSB_TO_DADDR(mp, map.br_startblock), |
128 | mp->m_bsize, 0, &bp, &xfs_rtbuf_ops); |
129 | if (xfs_metadata_is_sick(error)) |
130 | xfs_rt_mark_sick(mp, mask: issum ? XFS_SICK_RT_SUMMARY : |
131 | XFS_SICK_RT_BITMAP); |
132 | if (error) |
133 | return error; |
134 | |
135 | xfs_trans_buf_set_type(args->tp, bp, type); |
136 | *cbpp = bp; |
137 | *coffp = block; |
138 | return 0; |
139 | } |
140 | |
141 | /* |
142 | * Searching backward from start to limit, find the first block whose |
143 | * allocated/free state is different from start's. |
144 | */ |
145 | int |
146 | xfs_rtfind_back( |
147 | struct xfs_rtalloc_args *args, |
148 | xfs_rtxnum_t start, /* starting rtext to look at */ |
149 | xfs_rtxnum_t limit, /* last rtext to look at */ |
150 | xfs_rtxnum_t *rtx) /* out: start rtext found */ |
151 | { |
152 | struct xfs_mount *mp = args->mp; |
153 | int bit; /* bit number in the word */ |
154 | xfs_fileoff_t block; /* bitmap block number */ |
155 | int error; /* error value */ |
156 | xfs_rtxnum_t firstbit; /* first useful bit in the word */ |
157 | xfs_rtxnum_t i; /* current bit number rel. to start */ |
158 | xfs_rtxnum_t len; /* length of inspected area */ |
159 | xfs_rtword_t mask; /* mask of relevant bits for value */ |
160 | xfs_rtword_t want; /* mask for "good" values */ |
161 | xfs_rtword_t wdiff; /* difference from wanted value */ |
162 | xfs_rtword_t incore; |
163 | unsigned int word; /* word number in the buffer */ |
164 | |
165 | /* |
166 | * Compute and read in starting bitmap block for starting block. |
167 | */ |
168 | block = xfs_rtx_to_rbmblock(mp, start); |
169 | error = xfs_rtbitmap_read_buf(args, block); |
170 | if (error) |
171 | return error; |
172 | |
173 | /* |
174 | * Get the first word's index & point to it. |
175 | */ |
176 | word = xfs_rtx_to_rbmword(mp, start); |
177 | bit = (int)(start & (XFS_NBWORD - 1)); |
178 | len = start - limit + 1; |
179 | /* |
180 | * Compute match value, based on the bit at start: if 1 (free) |
181 | * then all-ones, else all-zeroes. |
182 | */ |
183 | incore = xfs_rtbitmap_getword(args, word); |
184 | want = (incore & ((xfs_rtword_t)1 << bit)) ? -1 : 0; |
185 | /* |
186 | * If the starting position is not word-aligned, deal with the |
187 | * partial word. |
188 | */ |
189 | if (bit < XFS_NBWORD - 1) { |
190 | /* |
191 | * Calculate first (leftmost) bit number to look at, |
192 | * and mask for all the relevant bits in this word. |
193 | */ |
194 | firstbit = max_t(xfs_srtblock_t, bit - len + 1, 0); |
195 | mask = (((xfs_rtword_t)1 << (bit - firstbit + 1)) - 1) << |
196 | firstbit; |
197 | /* |
198 | * Calculate the difference between the value there |
199 | * and what we're looking for. |
200 | */ |
201 | if ((wdiff = (incore ^ want) & mask)) { |
202 | /* |
203 | * Different. Mark where we are and return. |
204 | */ |
205 | i = bit - xfs_highbit32(wdiff); |
206 | *rtx = start - i + 1; |
207 | return 0; |
208 | } |
209 | i = bit - firstbit + 1; |
210 | /* |
211 | * Go on to previous block if that's where the previous word is |
212 | * and we need the previous word. |
213 | */ |
214 | if (--word == -1 && i < len) { |
215 | /* |
216 | * If done with this block, get the previous one. |
217 | */ |
218 | error = xfs_rtbitmap_read_buf(args, --block); |
219 | if (error) |
220 | return error; |
221 | |
222 | word = mp->m_blockwsize - 1; |
223 | } |
224 | } else { |
225 | /* |
226 | * Starting on a word boundary, no partial word. |
227 | */ |
228 | i = 0; |
229 | } |
230 | /* |
231 | * Loop over whole words in buffers. When we use up one buffer |
232 | * we move on to the previous one. |
233 | */ |
234 | while (len - i >= XFS_NBWORD) { |
235 | /* |
236 | * Compute difference between actual and desired value. |
237 | */ |
238 | incore = xfs_rtbitmap_getword(args, word); |
239 | if ((wdiff = incore ^ want)) { |
240 | /* |
241 | * Different, mark where we are and return. |
242 | */ |
243 | i += XFS_NBWORD - 1 - xfs_highbit32(wdiff); |
244 | *rtx = start - i + 1; |
245 | return 0; |
246 | } |
247 | i += XFS_NBWORD; |
248 | /* |
249 | * Go on to previous block if that's where the previous word is |
250 | * and we need the previous word. |
251 | */ |
252 | if (--word == -1 && i < len) { |
253 | /* |
254 | * If done with this block, get the previous one. |
255 | */ |
256 | error = xfs_rtbitmap_read_buf(args, --block); |
257 | if (error) |
258 | return error; |
259 | |
260 | word = mp->m_blockwsize - 1; |
261 | } |
262 | } |
263 | /* |
264 | * If not ending on a word boundary, deal with the last |
265 | * (partial) word. |
266 | */ |
267 | if (len - i) { |
268 | /* |
269 | * Calculate first (leftmost) bit number to look at, |
270 | * and mask for all the relevant bits in this word. |
271 | */ |
272 | firstbit = XFS_NBWORD - (len - i); |
273 | mask = (((xfs_rtword_t)1 << (len - i)) - 1) << firstbit; |
274 | /* |
275 | * Compute difference between actual and desired value. |
276 | */ |
277 | incore = xfs_rtbitmap_getword(args, word); |
278 | if ((wdiff = (incore ^ want) & mask)) { |
279 | /* |
280 | * Different, mark where we are and return. |
281 | */ |
282 | i += XFS_NBWORD - 1 - xfs_highbit32(wdiff); |
283 | *rtx = start - i + 1; |
284 | return 0; |
285 | } else |
286 | i = len; |
287 | } |
288 | /* |
289 | * No match, return that we scanned the whole area. |
290 | */ |
291 | *rtx = start - i + 1; |
292 | return 0; |
293 | } |
294 | |
295 | /* |
296 | * Searching forward from start to limit, find the first block whose |
297 | * allocated/free state is different from start's. |
298 | */ |
299 | int |
300 | xfs_rtfind_forw( |
301 | struct xfs_rtalloc_args *args, |
302 | xfs_rtxnum_t start, /* starting rtext to look at */ |
303 | xfs_rtxnum_t limit, /* last rtext to look at */ |
304 | xfs_rtxnum_t *rtx) /* out: start rtext found */ |
305 | { |
306 | struct xfs_mount *mp = args->mp; |
307 | int bit; /* bit number in the word */ |
308 | xfs_fileoff_t block; /* bitmap block number */ |
309 | int error; |
310 | xfs_rtxnum_t i; /* current bit number rel. to start */ |
311 | xfs_rtxnum_t lastbit;/* last useful bit in the word */ |
312 | xfs_rtxnum_t len; /* length of inspected area */ |
313 | xfs_rtword_t mask; /* mask of relevant bits for value */ |
314 | xfs_rtword_t want; /* mask for "good" values */ |
315 | xfs_rtword_t wdiff; /* difference from wanted value */ |
316 | xfs_rtword_t incore; |
317 | unsigned int word; /* word number in the buffer */ |
318 | |
319 | /* |
320 | * Compute and read in starting bitmap block for starting block. |
321 | */ |
322 | block = xfs_rtx_to_rbmblock(mp, start); |
323 | error = xfs_rtbitmap_read_buf(args, block); |
324 | if (error) |
325 | return error; |
326 | |
327 | /* |
328 | * Get the first word's index & point to it. |
329 | */ |
330 | word = xfs_rtx_to_rbmword(mp, start); |
331 | bit = (int)(start & (XFS_NBWORD - 1)); |
332 | len = limit - start + 1; |
333 | /* |
334 | * Compute match value, based on the bit at start: if 1 (free) |
335 | * then all-ones, else all-zeroes. |
336 | */ |
337 | incore = xfs_rtbitmap_getword(args, word); |
338 | want = (incore & ((xfs_rtword_t)1 << bit)) ? -1 : 0; |
339 | /* |
340 | * If the starting position is not word-aligned, deal with the |
341 | * partial word. |
342 | */ |
343 | if (bit) { |
344 | /* |
345 | * Calculate last (rightmost) bit number to look at, |
346 | * and mask for all the relevant bits in this word. |
347 | */ |
348 | lastbit = min(bit + len, XFS_NBWORD); |
349 | mask = (((xfs_rtword_t)1 << (lastbit - bit)) - 1) << bit; |
350 | /* |
351 | * Calculate the difference between the value there |
352 | * and what we're looking for. |
353 | */ |
354 | if ((wdiff = (incore ^ want) & mask)) { |
355 | /* |
356 | * Different. Mark where we are and return. |
357 | */ |
358 | i = xfs_lowbit32(wdiff) - bit; |
359 | *rtx = start + i - 1; |
360 | return 0; |
361 | } |
362 | i = lastbit - bit; |
363 | /* |
364 | * Go on to next block if that's where the next word is |
365 | * and we need the next word. |
366 | */ |
367 | if (++word == mp->m_blockwsize && i < len) { |
368 | /* |
369 | * If done with this block, get the previous one. |
370 | */ |
371 | error = xfs_rtbitmap_read_buf(args, ++block); |
372 | if (error) |
373 | return error; |
374 | |
375 | word = 0; |
376 | } |
377 | } else { |
378 | /* |
379 | * Starting on a word boundary, no partial word. |
380 | */ |
381 | i = 0; |
382 | } |
383 | /* |
384 | * Loop over whole words in buffers. When we use up one buffer |
385 | * we move on to the next one. |
386 | */ |
387 | while (len - i >= XFS_NBWORD) { |
388 | /* |
389 | * Compute difference between actual and desired value. |
390 | */ |
391 | incore = xfs_rtbitmap_getword(args, word); |
392 | if ((wdiff = incore ^ want)) { |
393 | /* |
394 | * Different, mark where we are and return. |
395 | */ |
396 | i += xfs_lowbit32(wdiff); |
397 | *rtx = start + i - 1; |
398 | return 0; |
399 | } |
400 | i += XFS_NBWORD; |
401 | /* |
402 | * Go on to next block if that's where the next word is |
403 | * and we need the next word. |
404 | */ |
405 | if (++word == mp->m_blockwsize && i < len) { |
406 | /* |
407 | * If done with this block, get the next one. |
408 | */ |
409 | error = xfs_rtbitmap_read_buf(args, ++block); |
410 | if (error) |
411 | return error; |
412 | |
413 | word = 0; |
414 | } |
415 | } |
416 | /* |
417 | * If not ending on a word boundary, deal with the last |
418 | * (partial) word. |
419 | */ |
420 | if ((lastbit = len - i)) { |
421 | /* |
422 | * Calculate mask for all the relevant bits in this word. |
423 | */ |
424 | mask = ((xfs_rtword_t)1 << lastbit) - 1; |
425 | /* |
426 | * Compute difference between actual and desired value. |
427 | */ |
428 | incore = xfs_rtbitmap_getword(args, word); |
429 | if ((wdiff = (incore ^ want) & mask)) { |
430 | /* |
431 | * Different, mark where we are and return. |
432 | */ |
433 | i += xfs_lowbit32(wdiff); |
434 | *rtx = start + i - 1; |
435 | return 0; |
436 | } else |
437 | i = len; |
438 | } |
439 | /* |
440 | * No match, return that we scanned the whole area. |
441 | */ |
442 | *rtx = start + i - 1; |
443 | return 0; |
444 | } |
445 | |
446 | /* Log rtsummary counter at @infoword. */ |
447 | static inline void |
448 | xfs_trans_log_rtsummary( |
449 | struct xfs_rtalloc_args *args, |
450 | unsigned int infoword) |
451 | { |
452 | struct xfs_buf *bp = args->sumbp; |
453 | size_t first, last; |
454 | |
455 | first = (void *)xfs_rsumblock_infoptr(args, infoword) - bp->b_addr; |
456 | last = first + sizeof(xfs_suminfo_t) - 1; |
457 | |
458 | xfs_trans_log_buf(args->tp, bp, first, last); |
459 | } |
460 | |
461 | /* |
462 | * Modify the summary information for a given extent size, bitmap block |
463 | * combination. |
464 | */ |
465 | int |
466 | xfs_rtmodify_summary( |
467 | struct xfs_rtalloc_args *args, |
468 | int log, /* log2 of extent size */ |
469 | xfs_fileoff_t bbno, /* bitmap block number */ |
470 | int delta) /* in/out: summary block number */ |
471 | { |
472 | struct xfs_mount *mp = args->mp; |
473 | xfs_rtsumoff_t so = xfs_rtsumoffs(mp, log, bbno); |
474 | unsigned int infoword; |
475 | xfs_suminfo_t val; |
476 | int error; |
477 | |
478 | error = xfs_rtsummary_read_buf(args, xfs_rtsumoffs_to_block(mp, so)); |
479 | if (error) |
480 | return error; |
481 | |
482 | infoword = xfs_rtsumoffs_to_infoword(mp, so); |
483 | val = xfs_suminfo_add(args, infoword, delta); |
484 | |
485 | if (mp->m_rsum_cache) { |
486 | if (val == 0 && log + 1 == mp->m_rsum_cache[bbno]) |
487 | mp->m_rsum_cache[bbno] = log; |
488 | if (val != 0 && log >= mp->m_rsum_cache[bbno]) |
489 | mp->m_rsum_cache[bbno] = log + 1; |
490 | } |
491 | |
492 | xfs_trans_log_rtsummary(args, infoword); |
493 | return 0; |
494 | } |
495 | |
496 | /* |
497 | * Read and return the summary information for a given extent size, bitmap block |
498 | * combination. |
499 | */ |
500 | int |
501 | xfs_rtget_summary( |
502 | struct xfs_rtalloc_args *args, |
503 | int log, /* log2 of extent size */ |
504 | xfs_fileoff_t bbno, /* bitmap block number */ |
505 | xfs_suminfo_t *sum) /* out: summary info for this block */ |
506 | { |
507 | struct xfs_mount *mp = args->mp; |
508 | xfs_rtsumoff_t so = xfs_rtsumoffs(mp, log, bbno); |
509 | int error; |
510 | |
511 | error = xfs_rtsummary_read_buf(args, xfs_rtsumoffs_to_block(mp, so)); |
512 | if (!error) |
513 | *sum = xfs_suminfo_get(args, xfs_rtsumoffs_to_infoword(mp, so)); |
514 | return error; |
515 | } |
516 | |
517 | /* Log rtbitmap block from the word @from to the byte before @next. */ |
518 | static inline void |
519 | xfs_trans_log_rtbitmap( |
520 | struct xfs_rtalloc_args *args, |
521 | unsigned int from, |
522 | unsigned int next) |
523 | { |
524 | struct xfs_buf *bp = args->rbmbp; |
525 | size_t first, last; |
526 | |
527 | first = (void *)xfs_rbmblock_wordptr(args, from) - bp->b_addr; |
528 | last = ((void *)xfs_rbmblock_wordptr(args, next) - 1) - bp->b_addr; |
529 | |
530 | xfs_trans_log_buf(args->tp, bp, first, last); |
531 | } |
532 | |
533 | /* |
534 | * Set the given range of bitmap bits to the given value. |
535 | * Do whatever I/O and logging is required. |
536 | */ |
537 | int |
538 | xfs_rtmodify_range( |
539 | struct xfs_rtalloc_args *args, |
540 | xfs_rtxnum_t start, /* starting rtext to modify */ |
541 | xfs_rtxlen_t len, /* length of extent to modify */ |
542 | int val) /* 1 for free, 0 for allocated */ |
543 | { |
544 | struct xfs_mount *mp = args->mp; |
545 | int bit; /* bit number in the word */ |
546 | xfs_fileoff_t block; /* bitmap block number */ |
547 | int error; |
548 | int i; /* current bit number rel. to start */ |
549 | int lastbit; /* last useful bit in word */ |
550 | xfs_rtword_t mask; /* mask of relevant bits for value */ |
551 | xfs_rtword_t incore; |
552 | unsigned int firstword; /* first word used in the buffer */ |
553 | unsigned int word; /* word number in the buffer */ |
554 | |
555 | /* |
556 | * Compute starting bitmap block number. |
557 | */ |
558 | block = xfs_rtx_to_rbmblock(mp, start); |
559 | /* |
560 | * Read the bitmap block, and point to its data. |
561 | */ |
562 | error = xfs_rtbitmap_read_buf(args, block); |
563 | if (error) |
564 | return error; |
565 | |
566 | /* |
567 | * Compute the starting word's address, and starting bit. |
568 | */ |
569 | firstword = word = xfs_rtx_to_rbmword(mp, start); |
570 | bit = (int)(start & (XFS_NBWORD - 1)); |
571 | /* |
572 | * 0 (allocated) => all zeroes; 1 (free) => all ones. |
573 | */ |
574 | val = -val; |
575 | /* |
576 | * If not starting on a word boundary, deal with the first |
577 | * (partial) word. |
578 | */ |
579 | if (bit) { |
580 | /* |
581 | * Compute first bit not changed and mask of relevant bits. |
582 | */ |
583 | lastbit = min(bit + len, XFS_NBWORD); |
584 | mask = (((xfs_rtword_t)1 << (lastbit - bit)) - 1) << bit; |
585 | /* |
586 | * Set/clear the active bits. |
587 | */ |
588 | incore = xfs_rtbitmap_getword(args, word); |
589 | if (val) |
590 | incore |= mask; |
591 | else |
592 | incore &= ~mask; |
593 | xfs_rtbitmap_setword(args, word, incore); |
594 | i = lastbit - bit; |
595 | /* |
596 | * Go on to the next block if that's where the next word is |
597 | * and we need the next word. |
598 | */ |
599 | if (++word == mp->m_blockwsize && i < len) { |
600 | /* |
601 | * Log the changed part of this block. |
602 | * Get the next one. |
603 | */ |
604 | xfs_trans_log_rtbitmap(args, from: firstword, next: word); |
605 | error = xfs_rtbitmap_read_buf(args, ++block); |
606 | if (error) |
607 | return error; |
608 | |
609 | firstword = word = 0; |
610 | } |
611 | } else { |
612 | /* |
613 | * Starting on a word boundary, no partial word. |
614 | */ |
615 | i = 0; |
616 | } |
617 | /* |
618 | * Loop over whole words in buffers. When we use up one buffer |
619 | * we move on to the next one. |
620 | */ |
621 | while (len - i >= XFS_NBWORD) { |
622 | /* |
623 | * Set the word value correctly. |
624 | */ |
625 | xfs_rtbitmap_setword(args, word, val); |
626 | i += XFS_NBWORD; |
627 | /* |
628 | * Go on to the next block if that's where the next word is |
629 | * and we need the next word. |
630 | */ |
631 | if (++word == mp->m_blockwsize && i < len) { |
632 | /* |
633 | * Log the changed part of this block. |
634 | * Get the next one. |
635 | */ |
636 | xfs_trans_log_rtbitmap(args, from: firstword, next: word); |
637 | error = xfs_rtbitmap_read_buf(args, ++block); |
638 | if (error) |
639 | return error; |
640 | |
641 | firstword = word = 0; |
642 | } |
643 | } |
644 | /* |
645 | * If not ending on a word boundary, deal with the last |
646 | * (partial) word. |
647 | */ |
648 | if ((lastbit = len - i)) { |
649 | /* |
650 | * Compute a mask of relevant bits. |
651 | */ |
652 | mask = ((xfs_rtword_t)1 << lastbit) - 1; |
653 | /* |
654 | * Set/clear the active bits. |
655 | */ |
656 | incore = xfs_rtbitmap_getword(args, word); |
657 | if (val) |
658 | incore |= mask; |
659 | else |
660 | incore &= ~mask; |
661 | xfs_rtbitmap_setword(args, word, incore); |
662 | word++; |
663 | } |
664 | /* |
665 | * Log any remaining changed bytes. |
666 | */ |
667 | if (word > firstword) |
668 | xfs_trans_log_rtbitmap(args, from: firstword, next: word); |
669 | return 0; |
670 | } |
671 | |
672 | /* |
673 | * Mark an extent specified by start and len freed. |
674 | * Updates all the summary information as well as the bitmap. |
675 | */ |
676 | int |
677 | xfs_rtfree_range( |
678 | struct xfs_rtalloc_args *args, |
679 | xfs_rtxnum_t start, /* starting rtext to free */ |
680 | xfs_rtxlen_t len) /* in/out: summary block number */ |
681 | { |
682 | struct xfs_mount *mp = args->mp; |
683 | xfs_rtxnum_t end; /* end of the freed extent */ |
684 | int error; /* error value */ |
685 | xfs_rtxnum_t postblock; /* first rtext freed > end */ |
686 | xfs_rtxnum_t preblock; /* first rtext freed < start */ |
687 | |
688 | end = start + len - 1; |
689 | /* |
690 | * Modify the bitmap to mark this extent freed. |
691 | */ |
692 | error = xfs_rtmodify_range(args, start, len, 1); |
693 | if (error) { |
694 | return error; |
695 | } |
696 | /* |
697 | * Assume we're freeing out of the middle of an allocated extent. |
698 | * We need to find the beginning and end of the extent so we can |
699 | * properly update the summary. |
700 | */ |
701 | error = xfs_rtfind_back(args, start, 0, &preblock); |
702 | if (error) { |
703 | return error; |
704 | } |
705 | /* |
706 | * Find the next allocated block (end of allocated extent). |
707 | */ |
708 | error = xfs_rtfind_forw(args, end, mp->m_sb.sb_rextents - 1, |
709 | &postblock); |
710 | if (error) |
711 | return error; |
712 | /* |
713 | * If there are blocks not being freed at the front of the |
714 | * old extent, add summary data for them to be allocated. |
715 | */ |
716 | if (preblock < start) { |
717 | error = xfs_rtmodify_summary(args, |
718 | xfs_highbit64(start - preblock), |
719 | xfs_rtx_to_rbmblock(mp, preblock), -1); |
720 | if (error) { |
721 | return error; |
722 | } |
723 | } |
724 | /* |
725 | * If there are blocks not being freed at the end of the |
726 | * old extent, add summary data for them to be allocated. |
727 | */ |
728 | if (postblock > end) { |
729 | error = xfs_rtmodify_summary(args, |
730 | xfs_highbit64(postblock - end), |
731 | xfs_rtx_to_rbmblock(mp, end + 1), -1); |
732 | if (error) { |
733 | return error; |
734 | } |
735 | } |
736 | /* |
737 | * Increment the summary information corresponding to the entire |
738 | * (new) free extent. |
739 | */ |
740 | return xfs_rtmodify_summary(args, |
741 | xfs_highbit64(postblock + 1 - preblock), |
742 | xfs_rtx_to_rbmblock(mp, preblock), 1); |
743 | } |
744 | |
745 | /* |
746 | * Check that the given range is either all allocated (val = 0) or |
747 | * all free (val = 1). |
748 | */ |
749 | int |
750 | xfs_rtcheck_range( |
751 | struct xfs_rtalloc_args *args, |
752 | xfs_rtxnum_t start, /* starting rtext number of extent */ |
753 | xfs_rtxlen_t len, /* length of extent */ |
754 | int val, /* 1 for free, 0 for allocated */ |
755 | xfs_rtxnum_t *new, /* out: first rtext not matching */ |
756 | int *stat) /* out: 1 for matches, 0 for not */ |
757 | { |
758 | struct xfs_mount *mp = args->mp; |
759 | int bit; /* bit number in the word */ |
760 | xfs_fileoff_t block; /* bitmap block number */ |
761 | int error; |
762 | xfs_rtxnum_t i; /* current bit number rel. to start */ |
763 | xfs_rtxnum_t lastbit; /* last useful bit in word */ |
764 | xfs_rtword_t mask; /* mask of relevant bits for value */ |
765 | xfs_rtword_t wdiff; /* difference from wanted value */ |
766 | xfs_rtword_t incore; |
767 | unsigned int word; /* word number in the buffer */ |
768 | |
769 | /* |
770 | * Compute starting bitmap block number |
771 | */ |
772 | block = xfs_rtx_to_rbmblock(mp, start); |
773 | /* |
774 | * Read the bitmap block. |
775 | */ |
776 | error = xfs_rtbitmap_read_buf(args, block); |
777 | if (error) |
778 | return error; |
779 | |
780 | /* |
781 | * Compute the starting word's address, and starting bit. |
782 | */ |
783 | word = xfs_rtx_to_rbmword(mp, start); |
784 | bit = (int)(start & (XFS_NBWORD - 1)); |
785 | /* |
786 | * 0 (allocated) => all zero's; 1 (free) => all one's. |
787 | */ |
788 | val = -val; |
789 | /* |
790 | * If not starting on a word boundary, deal with the first |
791 | * (partial) word. |
792 | */ |
793 | if (bit) { |
794 | /* |
795 | * Compute first bit not examined. |
796 | */ |
797 | lastbit = min(bit + len, XFS_NBWORD); |
798 | /* |
799 | * Mask of relevant bits. |
800 | */ |
801 | mask = (((xfs_rtword_t)1 << (lastbit - bit)) - 1) << bit; |
802 | /* |
803 | * Compute difference between actual and desired value. |
804 | */ |
805 | incore = xfs_rtbitmap_getword(args, word); |
806 | if ((wdiff = (incore ^ val) & mask)) { |
807 | /* |
808 | * Different, compute first wrong bit and return. |
809 | */ |
810 | i = xfs_lowbit32(wdiff) - bit; |
811 | *new = start + i; |
812 | *stat = 0; |
813 | return 0; |
814 | } |
815 | i = lastbit - bit; |
816 | /* |
817 | * Go on to next block if that's where the next word is |
818 | * and we need the next word. |
819 | */ |
820 | if (++word == mp->m_blockwsize && i < len) { |
821 | /* |
822 | * If done with this block, get the next one. |
823 | */ |
824 | error = xfs_rtbitmap_read_buf(args, ++block); |
825 | if (error) |
826 | return error; |
827 | |
828 | word = 0; |
829 | } |
830 | } else { |
831 | /* |
832 | * Starting on a word boundary, no partial word. |
833 | */ |
834 | i = 0; |
835 | } |
836 | /* |
837 | * Loop over whole words in buffers. When we use up one buffer |
838 | * we move on to the next one. |
839 | */ |
840 | while (len - i >= XFS_NBWORD) { |
841 | /* |
842 | * Compute difference between actual and desired value. |
843 | */ |
844 | incore = xfs_rtbitmap_getword(args, word); |
845 | if ((wdiff = incore ^ val)) { |
846 | /* |
847 | * Different, compute first wrong bit and return. |
848 | */ |
849 | i += xfs_lowbit32(wdiff); |
850 | *new = start + i; |
851 | *stat = 0; |
852 | return 0; |
853 | } |
854 | i += XFS_NBWORD; |
855 | /* |
856 | * Go on to next block if that's where the next word is |
857 | * and we need the next word. |
858 | */ |
859 | if (++word == mp->m_blockwsize && i < len) { |
860 | /* |
861 | * If done with this block, get the next one. |
862 | */ |
863 | error = xfs_rtbitmap_read_buf(args, ++block); |
864 | if (error) |
865 | return error; |
866 | |
867 | word = 0; |
868 | } |
869 | } |
870 | /* |
871 | * If not ending on a word boundary, deal with the last |
872 | * (partial) word. |
873 | */ |
874 | if ((lastbit = len - i)) { |
875 | /* |
876 | * Mask of relevant bits. |
877 | */ |
878 | mask = ((xfs_rtword_t)1 << lastbit) - 1; |
879 | /* |
880 | * Compute difference between actual and desired value. |
881 | */ |
882 | incore = xfs_rtbitmap_getword(args, word); |
883 | if ((wdiff = (incore ^ val) & mask)) { |
884 | /* |
885 | * Different, compute first wrong bit and return. |
886 | */ |
887 | i += xfs_lowbit32(wdiff); |
888 | *new = start + i; |
889 | *stat = 0; |
890 | return 0; |
891 | } else |
892 | i = len; |
893 | } |
894 | /* |
895 | * Successful, return. |
896 | */ |
897 | *new = start + i; |
898 | *stat = 1; |
899 | return 0; |
900 | } |
901 | |
902 | #ifdef DEBUG |
903 | /* |
904 | * Check that the given extent (block range) is allocated already. |
905 | */ |
906 | STATIC int |
907 | xfs_rtcheck_alloc_range( |
908 | struct xfs_rtalloc_args *args, |
909 | xfs_rtxnum_t start, /* starting rtext number of extent */ |
910 | xfs_rtxlen_t len) /* length of extent */ |
911 | { |
912 | xfs_rtxnum_t new; /* dummy for xfs_rtcheck_range */ |
913 | int stat; |
914 | int error; |
915 | |
916 | error = xfs_rtcheck_range(args, start, 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(a,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 |
930 | xfs_rtfree_extent( |
931 | struct xfs_trans *tp, /* transaction pointer */ |
932 | xfs_rtxnum_t start, /* starting rtext number to free */ |
933 | xfs_rtxlen_t len) /* length of extent freed */ |
934 | { |
935 | struct xfs_mount *mp = tp->t_mountp; |
936 | struct xfs_rtalloc_args args = { |
937 | .mp = mp, |
938 | .tp = tp, |
939 | }; |
940 | int error; |
941 | struct timespec64 atime; |
942 | |
943 | ASSERT(mp->m_rbmip->i_itemp != NULL); |
944 | xfs_assert_ilocked(mp->m_rbmip, XFS_ILOCK_EXCL); |
945 | |
946 | error = xfs_rtcheck_alloc_range(&args, start, len); |
947 | if (error) |
948 | return error; |
949 | |
950 | /* |
951 | * Free the range of realtime blocks. |
952 | */ |
953 | error = xfs_rtfree_range(&args, start, len); |
954 | if (error) |
955 | goto out; |
956 | |
957 | /* |
958 | * Mark more blocks free in the superblock. |
959 | */ |
960 | xfs_trans_mod_sb(tp, XFS_TRANS_SB_FREXTENTS, (long)len); |
961 | /* |
962 | * If we've now freed all the blocks, reset the file sequence |
963 | * number to 0. |
964 | */ |
965 | if (tp->t_frextents_delta + mp->m_sb.sb_frextents == |
966 | mp->m_sb.sb_rextents) { |
967 | if (!(mp->m_rbmip->i_diflags & XFS_DIFLAG_NEWRTBM)) |
968 | mp->m_rbmip->i_diflags |= XFS_DIFLAG_NEWRTBM; |
969 | |
970 | atime = inode_get_atime(VFS_I(mp->m_rbmip)); |
971 | atime.tv_sec = 0; |
972 | inode_set_atime_to_ts(VFS_I(mp->m_rbmip), atime); |
973 | xfs_trans_log_inode(tp, mp->m_rbmip, XFS_ILOG_CORE); |
974 | } |
975 | error = 0; |
976 | out: |
977 | xfs_rtbuf_cache_relse(args: &args); |
978 | return error; |
979 | } |
980 | |
981 | /* |
982 | * Free some blocks in the realtime subvolume. rtbno and rtlen are in units of |
983 | * rt blocks, not rt extents; must be aligned to the rt extent size; and rtlen |
984 | * cannot exceed XFS_MAX_BMBT_EXTLEN. |
985 | */ |
986 | int |
987 | xfs_rtfree_blocks( |
988 | struct xfs_trans *tp, |
989 | xfs_fsblock_t rtbno, |
990 | xfs_filblks_t rtlen) |
991 | { |
992 | struct xfs_mount *mp = tp->t_mountp; |
993 | xfs_rtxnum_t start; |
994 | xfs_filblks_t len; |
995 | xfs_extlen_t mod; |
996 | |
997 | ASSERT(rtlen <= XFS_MAX_BMBT_EXTLEN); |
998 | |
999 | len = xfs_rtb_to_rtxrem(mp, rtlen, &mod); |
1000 | if (mod) { |
1001 | ASSERT(mod == 0); |
1002 | return -EIO; |
1003 | } |
1004 | |
1005 | start = xfs_rtb_to_rtxrem(mp, rtbno, &mod); |
1006 | if (mod) { |
1007 | ASSERT(mod == 0); |
1008 | return -EIO; |
1009 | } |
1010 | |
1011 | return xfs_rtfree_extent(tp, start, len); |
1012 | } |
1013 | |
1014 | /* Find all the free records within a given range. */ |
1015 | int |
1016 | xfs_rtalloc_query_range( |
1017 | struct xfs_mount *mp, |
1018 | struct xfs_trans *tp, |
1019 | const struct xfs_rtalloc_rec *low_rec, |
1020 | const struct xfs_rtalloc_rec *high_rec, |
1021 | xfs_rtalloc_query_range_fn fn, |
1022 | void *priv) |
1023 | { |
1024 | struct xfs_rtalloc_args args = { |
1025 | .mp = mp, |
1026 | .tp = tp, |
1027 | }; |
1028 | struct xfs_rtalloc_rec rec; |
1029 | xfs_rtxnum_t rtstart; |
1030 | xfs_rtxnum_t rtend; |
1031 | xfs_rtxnum_t high_key; |
1032 | int is_free; |
1033 | int error = 0; |
1034 | |
1035 | if (low_rec->ar_startext > high_rec->ar_startext) |
1036 | return -EINVAL; |
1037 | if (low_rec->ar_startext >= mp->m_sb.sb_rextents || |
1038 | low_rec->ar_startext == high_rec->ar_startext) |
1039 | return 0; |
1040 | |
1041 | high_key = min(high_rec->ar_startext, mp->m_sb.sb_rextents - 1); |
1042 | |
1043 | /* Iterate the bitmap, looking for discrepancies. */ |
1044 | rtstart = low_rec->ar_startext; |
1045 | while (rtstart <= high_key) { |
1046 | /* Is the first block free? */ |
1047 | error = xfs_rtcheck_range(&args, rtstart, 1, 1, &rtend, |
1048 | &is_free); |
1049 | if (error) |
1050 | break; |
1051 | |
1052 | /* How long does the extent go for? */ |
1053 | error = xfs_rtfind_forw(&args, rtstart, high_key, &rtend); |
1054 | if (error) |
1055 | break; |
1056 | |
1057 | if (is_free) { |
1058 | rec.ar_startext = rtstart; |
1059 | rec.ar_extcount = rtend - rtstart + 1; |
1060 | |
1061 | error = fn(mp, tp, &rec, priv); |
1062 | if (error) |
1063 | break; |
1064 | } |
1065 | |
1066 | rtstart = rtend + 1; |
1067 | } |
1068 | |
1069 | xfs_rtbuf_cache_relse(args: &args); |
1070 | return error; |
1071 | } |
1072 | |
1073 | /* Find all the free records. */ |
1074 | int |
1075 | xfs_rtalloc_query_all( |
1076 | struct xfs_mount *mp, |
1077 | struct xfs_trans *tp, |
1078 | xfs_rtalloc_query_range_fn fn, |
1079 | void *priv) |
1080 | { |
1081 | struct xfs_rtalloc_rec keys[2]; |
1082 | |
1083 | keys[0].ar_startext = 0; |
1084 | keys[1].ar_startext = mp->m_sb.sb_rextents - 1; |
1085 | keys[0].ar_extcount = keys[1].ar_extcount = 0; |
1086 | |
1087 | return xfs_rtalloc_query_range(mp, tp, low_rec: &keys[0], high_rec: &keys[1], fn, priv); |
1088 | } |
1089 | |
1090 | /* Is the given extent all free? */ |
1091 | int |
1092 | xfs_rtalloc_extent_is_free( |
1093 | struct xfs_mount *mp, |
1094 | struct xfs_trans *tp, |
1095 | xfs_rtxnum_t start, |
1096 | xfs_rtxlen_t len, |
1097 | bool *is_free) |
1098 | { |
1099 | struct xfs_rtalloc_args args = { |
1100 | .mp = mp, |
1101 | .tp = tp, |
1102 | }; |
1103 | xfs_rtxnum_t end; |
1104 | int matches; |
1105 | int error; |
1106 | |
1107 | error = xfs_rtcheck_range(&args, start, len, 1, &end, &matches); |
1108 | xfs_rtbuf_cache_relse(args: &args); |
1109 | if (error) |
1110 | return error; |
1111 | |
1112 | *is_free = matches; |
1113 | return 0; |
1114 | } |
1115 | |
1116 | /* |
1117 | * Compute the number of rtbitmap blocks needed to track the given number of rt |
1118 | * extents. |
1119 | */ |
1120 | xfs_filblks_t |
1121 | xfs_rtbitmap_blockcount( |
1122 | struct xfs_mount *mp, |
1123 | xfs_rtbxlen_t rtextents) |
1124 | { |
1125 | return howmany_64(rtextents, NBBY * mp->m_sb.sb_blocksize); |
1126 | } |
1127 | |
1128 | /* |
1129 | * Compute the number of rtbitmap words needed to populate every block of a |
1130 | * bitmap that is large enough to track the given number of rt extents. |
1131 | */ |
1132 | unsigned long long |
1133 | xfs_rtbitmap_wordcount( |
1134 | struct xfs_mount *mp, |
1135 | xfs_rtbxlen_t rtextents) |
1136 | { |
1137 | xfs_filblks_t blocks; |
1138 | |
1139 | blocks = xfs_rtbitmap_blockcount(mp, rtextents); |
1140 | return XFS_FSB_TO_B(mp, blocks) >> XFS_WORDLOG; |
1141 | } |
1142 | |
1143 | /* Compute the number of rtsummary blocks needed to track the given rt space. */ |
1144 | xfs_filblks_t |
1145 | xfs_rtsummary_blockcount( |
1146 | struct xfs_mount *mp, |
1147 | unsigned int rsumlevels, |
1148 | xfs_extlen_t rbmblocks) |
1149 | { |
1150 | unsigned long long rsumwords; |
1151 | |
1152 | rsumwords = (unsigned long long)rsumlevels * rbmblocks; |
1153 | return XFS_B_TO_FSB(mp, rsumwords << XFS_WORDLOG); |
1154 | } |
1155 | |
1156 | /* |
1157 | * Compute the number of rtsummary info words needed to populate every block of |
1158 | * a summary file that is large enough to track the given rt space. |
1159 | */ |
1160 | unsigned long long |
1161 | xfs_rtsummary_wordcount( |
1162 | struct xfs_mount *mp, |
1163 | unsigned int rsumlevels, |
1164 | xfs_extlen_t rbmblocks) |
1165 | { |
1166 | xfs_filblks_t blocks; |
1167 | |
1168 | blocks = xfs_rtsummary_blockcount(mp, rsumlevels, rbmblocks); |
1169 | return XFS_FSB_TO_B(mp, blocks) >> XFS_WORDLOG; |
1170 | } |
1171 | |