]>
Commit | Line | Data |
---|---|---|
1 | // SPDX-License-Identifier: GPL-2.0 | |
2 | /* | |
3 | * Copyright (c) 2000-2005 Silicon Graphics, Inc. | |
4 | * All Rights Reserved. | |
5 | */ | |
6 | #include "libxfs_priv.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_bmap_btree.h" | |
17 | #include "xfs_trans_space.h" | |
18 | #include "xfs_trans.h" | |
19 | #include "xfs_rtbitmap.h" | |
20 | #include "xfs_health.h" | |
21 | #include "xfs_sb.h" | |
22 | #include "xfs_errortag.h" | |
23 | ||
24 | /* | |
25 | * Realtime allocator bitmap functions shared with userspace. | |
26 | */ | |
27 | ||
28 | static xfs_failaddr_t | |
29 | xfs_rtbuf_verify( | |
30 | struct xfs_buf *bp) | |
31 | { | |
32 | struct xfs_mount *mp = bp->b_mount; | |
33 | struct xfs_rtbuf_blkinfo *hdr = bp->b_addr; | |
34 | ||
35 | if (!xfs_verify_magic(bp, hdr->rt_magic)) | |
36 | return __this_address; | |
37 | if (!xfs_has_rtgroups(mp)) | |
38 | return __this_address; | |
39 | if (!xfs_has_crc(mp)) | |
40 | return __this_address; | |
41 | if (!uuid_equal(&hdr->rt_uuid, &mp->m_sb.sb_meta_uuid)) | |
42 | return __this_address; | |
43 | if (hdr->rt_blkno != cpu_to_be64(xfs_buf_daddr(bp))) | |
44 | return __this_address; | |
45 | return NULL; | |
46 | } | |
47 | ||
48 | static void | |
49 | xfs_rtbuf_verify_read( | |
50 | struct xfs_buf *bp) | |
51 | { | |
52 | struct xfs_mount *mp = bp->b_mount; | |
53 | struct xfs_rtbuf_blkinfo *hdr = bp->b_addr; | |
54 | xfs_failaddr_t fa; | |
55 | ||
56 | if (!xfs_has_rtgroups(mp)) | |
57 | return; | |
58 | ||
59 | if (!xfs_log_check_lsn(mp, be64_to_cpu(hdr->rt_lsn))) { | |
60 | fa = __this_address; | |
61 | goto fail; | |
62 | } | |
63 | ||
64 | if (!xfs_buf_verify_cksum(bp, XFS_RTBUF_CRC_OFF)) { | |
65 | fa = __this_address; | |
66 | goto fail; | |
67 | } | |
68 | ||
69 | fa = xfs_rtbuf_verify(bp); | |
70 | if (fa) | |
71 | goto fail; | |
72 | ||
73 | return; | |
74 | fail: | |
75 | xfs_verifier_error(bp, -EFSCORRUPTED, fa); | |
76 | } | |
77 | ||
78 | static void | |
79 | xfs_rtbuf_verify_write( | |
80 | struct xfs_buf *bp) | |
81 | { | |
82 | struct xfs_mount *mp = bp->b_mount; | |
83 | struct xfs_rtbuf_blkinfo *hdr = bp->b_addr; | |
84 | struct xfs_buf_log_item *bip = bp->b_log_item; | |
85 | xfs_failaddr_t fa; | |
86 | ||
87 | if (!xfs_has_rtgroups(mp)) | |
88 | return; | |
89 | ||
90 | fa = xfs_rtbuf_verify(bp); | |
91 | if (fa) { | |
92 | xfs_verifier_error(bp, -EFSCORRUPTED, fa); | |
93 | return; | |
94 | } | |
95 | ||
96 | if (bip) | |
97 | hdr->rt_lsn = cpu_to_be64(bip->bli_item.li_lsn); | |
98 | xfs_buf_update_cksum(bp, XFS_RTBUF_CRC_OFF); | |
99 | } | |
100 | ||
101 | const struct xfs_buf_ops xfs_rtbuf_ops = { | |
102 | .name = "rtbuf", | |
103 | .verify_read = xfs_rtbuf_verify_read, | |
104 | .verify_write = xfs_rtbuf_verify_write, | |
105 | }; | |
106 | ||
107 | const struct xfs_buf_ops xfs_rtbitmap_buf_ops = { | |
108 | .name = "xfs_rtbitmap", | |
109 | .magic = { 0, cpu_to_be32(XFS_RTBITMAP_MAGIC) }, | |
110 | .verify_read = xfs_rtbuf_verify_read, | |
111 | .verify_write = xfs_rtbuf_verify_write, | |
112 | .verify_struct = xfs_rtbuf_verify, | |
113 | }; | |
114 | ||
115 | const struct xfs_buf_ops xfs_rtsummary_buf_ops = { | |
116 | .name = "xfs_rtsummary", | |
117 | .magic = { 0, cpu_to_be32(XFS_RTSUMMARY_MAGIC) }, | |
118 | .verify_read = xfs_rtbuf_verify_read, | |
119 | .verify_write = xfs_rtbuf_verify_write, | |
120 | .verify_struct = xfs_rtbuf_verify, | |
121 | }; | |
122 | ||
123 | /* Release cached rt bitmap and summary buffers. */ | |
124 | void | |
125 | xfs_rtbuf_cache_relse( | |
126 | struct xfs_rtalloc_args *args) | |
127 | { | |
128 | if (args->rbmbp) { | |
129 | xfs_trans_brelse(args->tp, args->rbmbp); | |
130 | args->rbmbp = NULL; | |
131 | args->rbmoff = NULLFILEOFF; | |
132 | } | |
133 | if (args->sumbp) { | |
134 | xfs_trans_brelse(args->tp, args->sumbp); | |
135 | args->sumbp = NULL; | |
136 | args->sumoff = NULLFILEOFF; | |
137 | } | |
138 | } | |
139 | ||
140 | /* | |
141 | * Get a buffer for the bitmap or summary file block specified. | |
142 | * The buffer is returned read and locked. | |
143 | */ | |
144 | static int | |
145 | xfs_rtbuf_get( | |
146 | struct xfs_rtalloc_args *args, | |
147 | xfs_fileoff_t block, /* block number in bitmap or summary */ | |
148 | enum xfs_rtg_inodes type) | |
149 | { | |
150 | struct xfs_inode *ip = args->rtg->rtg_inodes[type]; | |
151 | struct xfs_mount *mp = args->mp; | |
152 | struct xfs_buf **cbpp; /* cached block buffer */ | |
153 | xfs_fileoff_t *coffp; /* cached block number */ | |
154 | struct xfs_buf *bp; /* block buffer, result */ | |
155 | struct xfs_bmbt_irec map; | |
156 | enum xfs_blft buf_type; | |
157 | int nmap = 1; | |
158 | int error; | |
159 | ||
160 | switch (type) { | |
161 | case XFS_RTGI_SUMMARY: | |
162 | cbpp = &args->sumbp; | |
163 | coffp = &args->sumoff; | |
164 | buf_type = XFS_BLFT_RTSUMMARY_BUF; | |
165 | break; | |
166 | case XFS_RTGI_BITMAP: | |
167 | cbpp = &args->rbmbp; | |
168 | coffp = &args->rbmoff; | |
169 | buf_type = XFS_BLFT_RTBITMAP_BUF; | |
170 | break; | |
171 | default: | |
172 | return -EINVAL; | |
173 | } | |
174 | ||
175 | /* | |
176 | * If we have a cached buffer, and the block number matches, use that. | |
177 | */ | |
178 | if (*cbpp && *coffp == block) | |
179 | return 0; | |
180 | ||
181 | /* | |
182 | * Otherwise we have to have to get the buffer. If there was an old | |
183 | * one, get rid of it first. | |
184 | */ | |
185 | if (*cbpp) { | |
186 | xfs_trans_brelse(args->tp, *cbpp); | |
187 | *cbpp = NULL; | |
188 | } | |
189 | ||
190 | error = xfs_bmapi_read(ip, block, 1, &map, &nmap, 0); | |
191 | if (error) | |
192 | return error; | |
193 | ||
194 | if (XFS_IS_CORRUPT(mp, nmap == 0 || !xfs_bmap_is_written_extent(&map))) { | |
195 | xfs_rtginode_mark_sick(args->rtg, type); | |
196 | return -EFSCORRUPTED; | |
197 | } | |
198 | ||
199 | ASSERT(map.br_startblock != NULLFSBLOCK); | |
200 | error = xfs_trans_read_buf(mp, args->tp, mp->m_ddev_targp, | |
201 | XFS_FSB_TO_DADDR(mp, map.br_startblock), | |
202 | mp->m_bsize, 0, &bp, | |
203 | xfs_rtblock_ops(mp, type)); | |
204 | if (xfs_metadata_is_sick(error)) | |
205 | xfs_rtginode_mark_sick(args->rtg, type); | |
206 | if (error) | |
207 | return error; | |
208 | ||
209 | if (xfs_has_rtgroups(mp)) { | |
210 | struct xfs_rtbuf_blkinfo *hdr = bp->b_addr; | |
211 | ||
212 | if (hdr->rt_owner != cpu_to_be64(ip->i_ino)) { | |
213 | xfs_buf_mark_corrupt(bp); | |
214 | xfs_trans_brelse(args->tp, bp); | |
215 | xfs_rtginode_mark_sick(args->rtg, type); | |
216 | return -EFSCORRUPTED; | |
217 | } | |
218 | } | |
219 | ||
220 | xfs_trans_buf_set_type(args->tp, bp, buf_type); | |
221 | *cbpp = bp; | |
222 | *coffp = block; | |
223 | return 0; | |
224 | } | |
225 | ||
226 | int | |
227 | xfs_rtbitmap_read_buf( | |
228 | struct xfs_rtalloc_args *args, | |
229 | xfs_fileoff_t block) | |
230 | { | |
231 | struct xfs_mount *mp = args->mp; | |
232 | ||
233 | if (XFS_IS_CORRUPT(mp, block >= mp->m_sb.sb_rbmblocks)) { | |
234 | xfs_rtginode_mark_sick(args->rtg, XFS_RTGI_BITMAP); | |
235 | return -EFSCORRUPTED; | |
236 | } | |
237 | ||
238 | return xfs_rtbuf_get(args, block, XFS_RTGI_BITMAP); | |
239 | } | |
240 | ||
241 | int | |
242 | xfs_rtsummary_read_buf( | |
243 | struct xfs_rtalloc_args *args, | |
244 | xfs_fileoff_t block) | |
245 | { | |
246 | struct xfs_mount *mp = args->mp; | |
247 | ||
248 | if (XFS_IS_CORRUPT(mp, block >= mp->m_rsumblocks)) { | |
249 | xfs_rtginode_mark_sick(args->rtg, XFS_RTGI_SUMMARY); | |
250 | return -EFSCORRUPTED; | |
251 | } | |
252 | return xfs_rtbuf_get(args, block, XFS_RTGI_SUMMARY); | |
253 | } | |
254 | ||
255 | /* | |
256 | * Searching backward from start find the first block whose allocated/free state | |
257 | * is different from start's. | |
258 | */ | |
259 | int | |
260 | xfs_rtfind_back( | |
261 | struct xfs_rtalloc_args *args, | |
262 | xfs_rtxnum_t start, /* starting rtext to look at */ | |
263 | xfs_rtxnum_t *rtx) /* out: start rtext found */ | |
264 | { | |
265 | struct xfs_mount *mp = args->mp; | |
266 | int bit; /* bit number in the word */ | |
267 | xfs_fileoff_t block; /* bitmap block number */ | |
268 | int error; /* error value */ | |
269 | xfs_rtxnum_t firstbit; /* first useful bit in the word */ | |
270 | xfs_rtxnum_t i; /* current bit number rel. to start */ | |
271 | xfs_rtxnum_t len; /* length of inspected area */ | |
272 | xfs_rtword_t mask; /* mask of relevant bits for value */ | |
273 | xfs_rtword_t want; /* mask for "good" values */ | |
274 | xfs_rtword_t wdiff; /* difference from wanted value */ | |
275 | xfs_rtword_t incore; | |
276 | unsigned int word; /* word number in the buffer */ | |
277 | ||
278 | /* | |
279 | * Compute and read in starting bitmap block for starting block. | |
280 | */ | |
281 | block = xfs_rtx_to_rbmblock(mp, start); | |
282 | error = xfs_rtbitmap_read_buf(args, block); | |
283 | if (error) | |
284 | return error; | |
285 | ||
286 | /* | |
287 | * Get the first word's index & point to it. | |
288 | */ | |
289 | word = xfs_rtx_to_rbmword(mp, start); | |
290 | bit = (int)(start & (XFS_NBWORD - 1)); | |
291 | len = start + 1; | |
292 | /* | |
293 | * Compute match value, based on the bit at start: if 1 (free) | |
294 | * then all-ones, else all-zeroes. | |
295 | */ | |
296 | incore = xfs_rtbitmap_getword(args, word); | |
297 | want = (incore & ((xfs_rtword_t)1 << bit)) ? -1 : 0; | |
298 | /* | |
299 | * If the starting position is not word-aligned, deal with the | |
300 | * partial word. | |
301 | */ | |
302 | if (bit < XFS_NBWORD - 1) { | |
303 | /* | |
304 | * Calculate first (leftmost) bit number to look at, | |
305 | * and mask for all the relevant bits in this word. | |
306 | */ | |
307 | firstbit = max_t(xfs_srtblock_t, bit - len + 1, 0); | |
308 | mask = (((xfs_rtword_t)1 << (bit - firstbit + 1)) - 1) << | |
309 | firstbit; | |
310 | /* | |
311 | * Calculate the difference between the value there | |
312 | * and what we're looking for. | |
313 | */ | |
314 | if ((wdiff = (incore ^ want) & mask)) { | |
315 | /* | |
316 | * Different. Mark where we are and return. | |
317 | */ | |
318 | i = bit - xfs_highbit32(wdiff); | |
319 | *rtx = start - i + 1; | |
320 | return 0; | |
321 | } | |
322 | i = bit - firstbit + 1; | |
323 | /* | |
324 | * Go on to previous block if that's where the previous word is | |
325 | * and we need the previous word. | |
326 | */ | |
327 | if (--word == -1 && i < len) { | |
328 | /* | |
329 | * If done with this block, get the previous one. | |
330 | */ | |
331 | error = xfs_rtbitmap_read_buf(args, --block); | |
332 | if (error) | |
333 | return error; | |
334 | ||
335 | word = mp->m_blockwsize - 1; | |
336 | } | |
337 | } else { | |
338 | /* | |
339 | * Starting on a word boundary, no partial word. | |
340 | */ | |
341 | i = 0; | |
342 | } | |
343 | /* | |
344 | * Loop over whole words in buffers. When we use up one buffer | |
345 | * we move on to the previous one. | |
346 | */ | |
347 | while (len - i >= XFS_NBWORD) { | |
348 | /* | |
349 | * Compute difference between actual and desired value. | |
350 | */ | |
351 | incore = xfs_rtbitmap_getword(args, word); | |
352 | if ((wdiff = incore ^ want)) { | |
353 | /* | |
354 | * Different, mark where we are and return. | |
355 | */ | |
356 | i += XFS_NBWORD - 1 - xfs_highbit32(wdiff); | |
357 | *rtx = start - i + 1; | |
358 | return 0; | |
359 | } | |
360 | i += XFS_NBWORD; | |
361 | /* | |
362 | * Go on to previous block if that's where the previous word is | |
363 | * and we need the previous word. | |
364 | */ | |
365 | if (--word == -1 && i < len) { | |
366 | /* | |
367 | * If done with this block, get the previous one. | |
368 | */ | |
369 | error = xfs_rtbitmap_read_buf(args, --block); | |
370 | if (error) | |
371 | return error; | |
372 | ||
373 | word = mp->m_blockwsize - 1; | |
374 | } | |
375 | } | |
376 | /* | |
377 | * If not ending on a word boundary, deal with the last | |
378 | * (partial) word. | |
379 | */ | |
380 | if (len - i) { | |
381 | /* | |
382 | * Calculate first (leftmost) bit number to look at, | |
383 | * and mask for all the relevant bits in this word. | |
384 | */ | |
385 | firstbit = XFS_NBWORD - (len - i); | |
386 | mask = (((xfs_rtword_t)1 << (len - i)) - 1) << firstbit; | |
387 | /* | |
388 | * Compute difference between actual and desired value. | |
389 | */ | |
390 | incore = xfs_rtbitmap_getword(args, word); | |
391 | if ((wdiff = (incore ^ want) & mask)) { | |
392 | /* | |
393 | * Different, mark where we are and return. | |
394 | */ | |
395 | i += XFS_NBWORD - 1 - xfs_highbit32(wdiff); | |
396 | *rtx = start - i + 1; | |
397 | return 0; | |
398 | } else | |
399 | i = len; | |
400 | } | |
401 | /* | |
402 | * No match, return that we scanned the whole area. | |
403 | */ | |
404 | *rtx = start - i + 1; | |
405 | return 0; | |
406 | } | |
407 | ||
408 | /* | |
409 | * Searching forward from start to limit, find the first block whose | |
410 | * allocated/free state is different from start's. | |
411 | */ | |
412 | int | |
413 | xfs_rtfind_forw( | |
414 | struct xfs_rtalloc_args *args, | |
415 | xfs_rtxnum_t start, /* starting rtext to look at */ | |
416 | xfs_rtxnum_t limit, /* last rtext to look at */ | |
417 | xfs_rtxnum_t *rtx) /* out: start rtext found */ | |
418 | { | |
419 | struct xfs_mount *mp = args->mp; | |
420 | int bit; /* bit number in the word */ | |
421 | xfs_fileoff_t block; /* bitmap block number */ | |
422 | int error; | |
423 | xfs_rtxnum_t i; /* current bit number rel. to start */ | |
424 | xfs_rtxnum_t lastbit;/* last useful bit in the word */ | |
425 | xfs_rtxnum_t len; /* length of inspected area */ | |
426 | xfs_rtword_t mask; /* mask of relevant bits for value */ | |
427 | xfs_rtword_t want; /* mask for "good" values */ | |
428 | xfs_rtword_t wdiff; /* difference from wanted value */ | |
429 | xfs_rtword_t incore; | |
430 | unsigned int word; /* word number in the buffer */ | |
431 | ||
432 | ASSERT(start <= limit); | |
433 | ||
434 | /* | |
435 | * Compute and read in starting bitmap block for starting block. | |
436 | */ | |
437 | block = xfs_rtx_to_rbmblock(mp, start); | |
438 | error = xfs_rtbitmap_read_buf(args, block); | |
439 | if (error) | |
440 | return error; | |
441 | ||
442 | /* | |
443 | * Get the first word's index & point to it. | |
444 | */ | |
445 | word = xfs_rtx_to_rbmword(mp, start); | |
446 | bit = (int)(start & (XFS_NBWORD - 1)); | |
447 | len = limit - start + 1; | |
448 | /* | |
449 | * Compute match value, based on the bit at start: if 1 (free) | |
450 | * then all-ones, else all-zeroes. | |
451 | */ | |
452 | incore = xfs_rtbitmap_getword(args, word); | |
453 | want = (incore & ((xfs_rtword_t)1 << bit)) ? -1 : 0; | |
454 | /* | |
455 | * If the starting position is not word-aligned, deal with the | |
456 | * partial word. | |
457 | */ | |
458 | if (bit) { | |
459 | /* | |
460 | * Calculate last (rightmost) bit number to look at, | |
461 | * and mask for all the relevant bits in this word. | |
462 | */ | |
463 | lastbit = min(bit + len, XFS_NBWORD); | |
464 | mask = (((xfs_rtword_t)1 << (lastbit - bit)) - 1) << bit; | |
465 | /* | |
466 | * Calculate the difference between the value there | |
467 | * and what we're looking for. | |
468 | */ | |
469 | if ((wdiff = (incore ^ want) & mask)) { | |
470 | /* | |
471 | * Different. Mark where we are and return. | |
472 | */ | |
473 | i = xfs_lowbit32(wdiff) - bit; | |
474 | *rtx = start + i - 1; | |
475 | return 0; | |
476 | } | |
477 | i = lastbit - bit; | |
478 | /* | |
479 | * Go on to next block if that's where the next word is | |
480 | * and we need the next word. | |
481 | */ | |
482 | if (++word == mp->m_blockwsize && i < len) { | |
483 | /* | |
484 | * If done with this block, get the previous one. | |
485 | */ | |
486 | error = xfs_rtbitmap_read_buf(args, ++block); | |
487 | if (error) | |
488 | return error; | |
489 | ||
490 | word = 0; | |
491 | } | |
492 | } else { | |
493 | /* | |
494 | * Starting on a word boundary, no partial word. | |
495 | */ | |
496 | i = 0; | |
497 | } | |
498 | /* | |
499 | * Loop over whole words in buffers. When we use up one buffer | |
500 | * we move on to the next one. | |
501 | */ | |
502 | while (len - i >= XFS_NBWORD) { | |
503 | /* | |
504 | * Compute difference between actual and desired value. | |
505 | */ | |
506 | incore = xfs_rtbitmap_getword(args, word); | |
507 | if ((wdiff = incore ^ want)) { | |
508 | /* | |
509 | * Different, mark where we are and return. | |
510 | */ | |
511 | i += xfs_lowbit32(wdiff); | |
512 | *rtx = start + i - 1; | |
513 | return 0; | |
514 | } | |
515 | i += XFS_NBWORD; | |
516 | /* | |
517 | * Go on to next block if that's where the next word is | |
518 | * and we need the next word. | |
519 | */ | |
520 | if (++word == mp->m_blockwsize && i < len) { | |
521 | /* | |
522 | * If done with this block, get the next one. | |
523 | */ | |
524 | error = xfs_rtbitmap_read_buf(args, ++block); | |
525 | if (error) | |
526 | return error; | |
527 | ||
528 | word = 0; | |
529 | } | |
530 | } | |
531 | /* | |
532 | * If not ending on a word boundary, deal with the last | |
533 | * (partial) word. | |
534 | */ | |
535 | if ((lastbit = len - i)) { | |
536 | /* | |
537 | * Calculate mask for all the relevant bits in this word. | |
538 | */ | |
539 | mask = ((xfs_rtword_t)1 << lastbit) - 1; | |
540 | /* | |
541 | * Compute difference between actual and desired value. | |
542 | */ | |
543 | incore = xfs_rtbitmap_getword(args, word); | |
544 | if ((wdiff = (incore ^ want) & mask)) { | |
545 | /* | |
546 | * Different, mark where we are and return. | |
547 | */ | |
548 | i += xfs_lowbit32(wdiff); | |
549 | *rtx = start + i - 1; | |
550 | return 0; | |
551 | } else | |
552 | i = len; | |
553 | } | |
554 | /* | |
555 | * No match, return that we scanned the whole area. | |
556 | */ | |
557 | *rtx = start + i - 1; | |
558 | return 0; | |
559 | } | |
560 | ||
561 | /* Log rtsummary counter at @infoword. */ | |
562 | static inline void | |
563 | xfs_trans_log_rtsummary( | |
564 | struct xfs_rtalloc_args *args, | |
565 | unsigned int infoword) | |
566 | { | |
567 | struct xfs_buf *bp = args->sumbp; | |
568 | size_t first, last; | |
569 | ||
570 | first = (void *)xfs_rsumblock_infoptr(args, infoword) - bp->b_addr; | |
571 | last = first + sizeof(xfs_suminfo_t) - 1; | |
572 | ||
573 | xfs_trans_log_buf(args->tp, bp, first, last); | |
574 | } | |
575 | ||
576 | /* | |
577 | * Modify the summary information for a given extent size, bitmap block | |
578 | * combination. | |
579 | */ | |
580 | int | |
581 | xfs_rtmodify_summary( | |
582 | struct xfs_rtalloc_args *args, | |
583 | int log, /* log2 of extent size */ | |
584 | xfs_fileoff_t bbno, /* bitmap block number */ | |
585 | int delta) /* in/out: summary block number */ | |
586 | { | |
587 | struct xfs_mount *mp = args->mp; | |
588 | xfs_rtsumoff_t so = xfs_rtsumoffs(mp, log, bbno); | |
589 | uint8_t *rsum_cache = args->rtg->rtg_rsum_cache; | |
590 | unsigned int infoword; | |
591 | xfs_suminfo_t val; | |
592 | int error; | |
593 | ||
594 | error = xfs_rtsummary_read_buf(args, xfs_rtsumoffs_to_block(mp, so)); | |
595 | if (error) | |
596 | return error; | |
597 | ||
598 | infoword = xfs_rtsumoffs_to_infoword(mp, so); | |
599 | val = xfs_suminfo_add(args, infoword, delta); | |
600 | ||
601 | if (rsum_cache) { | |
602 | if (val == 0 && log + 1 == rsum_cache[bbno]) | |
603 | rsum_cache[bbno] = log; | |
604 | if (val != 0 && log >= rsum_cache[bbno]) | |
605 | rsum_cache[bbno] = log + 1; | |
606 | } | |
607 | ||
608 | xfs_trans_log_rtsummary(args, infoword); | |
609 | return 0; | |
610 | } | |
611 | ||
612 | /* | |
613 | * Read and return the summary information for a given extent size, bitmap block | |
614 | * combination. | |
615 | */ | |
616 | int | |
617 | xfs_rtget_summary( | |
618 | struct xfs_rtalloc_args *args, | |
619 | int log, /* log2 of extent size */ | |
620 | xfs_fileoff_t bbno, /* bitmap block number */ | |
621 | xfs_suminfo_t *sum) /* out: summary info for this block */ | |
622 | { | |
623 | struct xfs_mount *mp = args->mp; | |
624 | xfs_rtsumoff_t so = xfs_rtsumoffs(mp, log, bbno); | |
625 | int error; | |
626 | ||
627 | error = xfs_rtsummary_read_buf(args, xfs_rtsumoffs_to_block(mp, so)); | |
628 | if (!error) | |
629 | *sum = xfs_suminfo_get(args, xfs_rtsumoffs_to_infoword(mp, so)); | |
630 | return error; | |
631 | } | |
632 | ||
633 | /* Log rtbitmap block from the word @from to the byte before @next. */ | |
634 | static inline void | |
635 | xfs_trans_log_rtbitmap( | |
636 | struct xfs_rtalloc_args *args, | |
637 | unsigned int from, | |
638 | unsigned int next) | |
639 | { | |
640 | struct xfs_buf *bp = args->rbmbp; | |
641 | size_t first, last; | |
642 | ||
643 | first = (void *)xfs_rbmblock_wordptr(args, from) - bp->b_addr; | |
644 | last = ((void *)xfs_rbmblock_wordptr(args, next) - 1) - bp->b_addr; | |
645 | ||
646 | xfs_trans_log_buf(args->tp, bp, first, last); | |
647 | } | |
648 | ||
649 | /* | |
650 | * Set the given range of bitmap bits to the given value. | |
651 | * Do whatever I/O and logging is required. | |
652 | */ | |
653 | int | |
654 | xfs_rtmodify_range( | |
655 | struct xfs_rtalloc_args *args, | |
656 | xfs_rtxnum_t start, /* starting rtext to modify */ | |
657 | xfs_rtxlen_t len, /* length of extent to modify */ | |
658 | int val) /* 1 for free, 0 for allocated */ | |
659 | { | |
660 | struct xfs_mount *mp = args->mp; | |
661 | int bit; /* bit number in the word */ | |
662 | xfs_fileoff_t block; /* bitmap block number */ | |
663 | int error; | |
664 | int i; /* current bit number rel. to start */ | |
665 | int lastbit; /* last useful bit in word */ | |
666 | xfs_rtword_t mask; /* mask of relevant bits for value */ | |
667 | xfs_rtword_t incore; | |
668 | unsigned int firstword; /* first word used in the buffer */ | |
669 | unsigned int word; /* word number in the buffer */ | |
670 | ||
671 | /* | |
672 | * Compute starting bitmap block number. | |
673 | */ | |
674 | block = xfs_rtx_to_rbmblock(mp, start); | |
675 | /* | |
676 | * Read the bitmap block, and point to its data. | |
677 | */ | |
678 | error = xfs_rtbitmap_read_buf(args, block); | |
679 | if (error) | |
680 | return error; | |
681 | ||
682 | /* | |
683 | * Compute the starting word's address, and starting bit. | |
684 | */ | |
685 | firstword = word = xfs_rtx_to_rbmword(mp, start); | |
686 | bit = (int)(start & (XFS_NBWORD - 1)); | |
687 | /* | |
688 | * 0 (allocated) => all zeroes; 1 (free) => all ones. | |
689 | */ | |
690 | val = -val; | |
691 | /* | |
692 | * If not starting on a word boundary, deal with the first | |
693 | * (partial) word. | |
694 | */ | |
695 | if (bit) { | |
696 | /* | |
697 | * Compute first bit not changed and mask of relevant bits. | |
698 | */ | |
699 | lastbit = min(bit + len, XFS_NBWORD); | |
700 | mask = (((xfs_rtword_t)1 << (lastbit - bit)) - 1) << bit; | |
701 | /* | |
702 | * Set/clear the active bits. | |
703 | */ | |
704 | incore = xfs_rtbitmap_getword(args, word); | |
705 | if (val) | |
706 | incore |= mask; | |
707 | else | |
708 | incore &= ~mask; | |
709 | xfs_rtbitmap_setword(args, word, incore); | |
710 | i = lastbit - bit; | |
711 | /* | |
712 | * Go on to the next block if that's where the next word is | |
713 | * and we need the next word. | |
714 | */ | |
715 | if (++word == mp->m_blockwsize && i < len) { | |
716 | /* | |
717 | * Log the changed part of this block. | |
718 | * Get the next one. | |
719 | */ | |
720 | xfs_trans_log_rtbitmap(args, firstword, word); | |
721 | error = xfs_rtbitmap_read_buf(args, ++block); | |
722 | if (error) | |
723 | return error; | |
724 | ||
725 | firstword = word = 0; | |
726 | } | |
727 | } else { | |
728 | /* | |
729 | * Starting on a word boundary, no partial word. | |
730 | */ | |
731 | i = 0; | |
732 | } | |
733 | /* | |
734 | * Loop over whole words in buffers. When we use up one buffer | |
735 | * we move on to the next one. | |
736 | */ | |
737 | while (len - i >= XFS_NBWORD) { | |
738 | /* | |
739 | * Set the word value correctly. | |
740 | */ | |
741 | xfs_rtbitmap_setword(args, word, val); | |
742 | i += XFS_NBWORD; | |
743 | /* | |
744 | * Go on to the next block if that's where the next word is | |
745 | * and we need the next word. | |
746 | */ | |
747 | if (++word == mp->m_blockwsize && i < len) { | |
748 | /* | |
749 | * Log the changed part of this block. | |
750 | * Get the next one. | |
751 | */ | |
752 | xfs_trans_log_rtbitmap(args, firstword, word); | |
753 | error = xfs_rtbitmap_read_buf(args, ++block); | |
754 | if (error) | |
755 | return error; | |
756 | ||
757 | firstword = word = 0; | |
758 | } | |
759 | } | |
760 | /* | |
761 | * If not ending on a word boundary, deal with the last | |
762 | * (partial) word. | |
763 | */ | |
764 | if ((lastbit = len - i)) { | |
765 | /* | |
766 | * Compute a mask of relevant bits. | |
767 | */ | |
768 | mask = ((xfs_rtword_t)1 << lastbit) - 1; | |
769 | /* | |
770 | * Set/clear the active bits. | |
771 | */ | |
772 | incore = xfs_rtbitmap_getword(args, word); | |
773 | if (val) | |
774 | incore |= mask; | |
775 | else | |
776 | incore &= ~mask; | |
777 | xfs_rtbitmap_setword(args, word, incore); | |
778 | word++; | |
779 | } | |
780 | /* | |
781 | * Log any remaining changed bytes. | |
782 | */ | |
783 | if (word > firstword) | |
784 | xfs_trans_log_rtbitmap(args, firstword, word); | |
785 | return 0; | |
786 | } | |
787 | ||
788 | /* | |
789 | * Mark an extent specified by start and len freed. | |
790 | * Updates all the summary information as well as the bitmap. | |
791 | */ | |
792 | int | |
793 | xfs_rtfree_range( | |
794 | struct xfs_rtalloc_args *args, | |
795 | xfs_rtxnum_t start, /* starting rtext to free */ | |
796 | xfs_rtxlen_t len) /* in/out: summary block number */ | |
797 | { | |
798 | struct xfs_mount *mp = args->mp; | |
799 | xfs_rtxnum_t end; /* end of the freed extent */ | |
800 | int error; /* error value */ | |
801 | xfs_rtxnum_t postblock; /* first rtext freed > end */ | |
802 | xfs_rtxnum_t preblock; /* first rtext freed < start */ | |
803 | ||
804 | end = start + len - 1; | |
805 | /* | |
806 | * Modify the bitmap to mark this extent freed. | |
807 | */ | |
808 | error = xfs_rtmodify_range(args, start, len, 1); | |
809 | if (error) { | |
810 | return error; | |
811 | } | |
812 | /* | |
813 | * Assume we're freeing out of the middle of an allocated extent. | |
814 | * We need to find the beginning and end of the extent so we can | |
815 | * properly update the summary. | |
816 | */ | |
817 | error = xfs_rtfind_back(args, start, &preblock); | |
818 | if (error) { | |
819 | return error; | |
820 | } | |
821 | /* | |
822 | * Find the next allocated block (end of allocated extent). | |
823 | */ | |
824 | error = xfs_rtfind_forw(args, end, args->rtg->rtg_extents - 1, | |
825 | &postblock); | |
826 | if (error) | |
827 | return error; | |
828 | /* | |
829 | * If there are blocks not being freed at the front of the | |
830 | * old extent, add summary data for them to be allocated. | |
831 | */ | |
832 | if (preblock < start) { | |
833 | error = xfs_rtmodify_summary(args, | |
834 | xfs_highbit64(start - preblock), | |
835 | xfs_rtx_to_rbmblock(mp, preblock), -1); | |
836 | if (error) { | |
837 | return error; | |
838 | } | |
839 | } | |
840 | /* | |
841 | * If there are blocks not being freed at the end of the | |
842 | * old extent, add summary data for them to be allocated. | |
843 | */ | |
844 | if (postblock > end) { | |
845 | error = xfs_rtmodify_summary(args, | |
846 | xfs_highbit64(postblock - end), | |
847 | xfs_rtx_to_rbmblock(mp, end + 1), -1); | |
848 | if (error) { | |
849 | return error; | |
850 | } | |
851 | } | |
852 | /* | |
853 | * Increment the summary information corresponding to the entire | |
854 | * (new) free extent. | |
855 | */ | |
856 | return xfs_rtmodify_summary(args, | |
857 | xfs_highbit64(postblock + 1 - preblock), | |
858 | xfs_rtx_to_rbmblock(mp, preblock), 1); | |
859 | } | |
860 | ||
861 | /* | |
862 | * Check that the given range is either all allocated (val = 0) or | |
863 | * all free (val = 1). | |
864 | */ | |
865 | int | |
866 | xfs_rtcheck_range( | |
867 | struct xfs_rtalloc_args *args, | |
868 | xfs_rtxnum_t start, /* starting rtext number of extent */ | |
869 | xfs_rtxlen_t len, /* length of extent */ | |
870 | int val, /* 1 for free, 0 for allocated */ | |
871 | xfs_rtxnum_t *new, /* out: first rtext not matching */ | |
872 | int *stat) /* out: 1 for matches, 0 for not */ | |
873 | { | |
874 | struct xfs_mount *mp = args->mp; | |
875 | int bit; /* bit number in the word */ | |
876 | xfs_fileoff_t block; /* bitmap block number */ | |
877 | int error; | |
878 | xfs_rtxnum_t i; /* current bit number rel. to start */ | |
879 | xfs_rtxnum_t lastbit; /* last useful bit in word */ | |
880 | xfs_rtword_t mask; /* mask of relevant bits for value */ | |
881 | xfs_rtword_t wdiff; /* difference from wanted value */ | |
882 | xfs_rtword_t incore; | |
883 | unsigned int word; /* word number in the buffer */ | |
884 | ||
885 | /* | |
886 | * Compute starting bitmap block number | |
887 | */ | |
888 | block = xfs_rtx_to_rbmblock(mp, start); | |
889 | /* | |
890 | * Read the bitmap block. | |
891 | */ | |
892 | error = xfs_rtbitmap_read_buf(args, block); | |
893 | if (error) | |
894 | return error; | |
895 | ||
896 | /* | |
897 | * Compute the starting word's address, and starting bit. | |
898 | */ | |
899 | word = xfs_rtx_to_rbmword(mp, start); | |
900 | bit = (int)(start & (XFS_NBWORD - 1)); | |
901 | /* | |
902 | * 0 (allocated) => all zero's; 1 (free) => all one's. | |
903 | */ | |
904 | val = -val; | |
905 | /* | |
906 | * If not starting on a word boundary, deal with the first | |
907 | * (partial) word. | |
908 | */ | |
909 | if (bit) { | |
910 | /* | |
911 | * Compute first bit not examined. | |
912 | */ | |
913 | lastbit = min(bit + len, XFS_NBWORD); | |
914 | /* | |
915 | * Mask of relevant bits. | |
916 | */ | |
917 | mask = (((xfs_rtword_t)1 << (lastbit - bit)) - 1) << bit; | |
918 | /* | |
919 | * Compute difference between actual and desired value. | |
920 | */ | |
921 | incore = xfs_rtbitmap_getword(args, word); | |
922 | if ((wdiff = (incore ^ val) & mask)) { | |
923 | /* | |
924 | * Different, compute first wrong bit and return. | |
925 | */ | |
926 | i = xfs_lowbit32(wdiff) - bit; | |
927 | *new = start + i; | |
928 | *stat = 0; | |
929 | return 0; | |
930 | } | |
931 | i = lastbit - bit; | |
932 | /* | |
933 | * Go on to next block if that's where the next word is | |
934 | * and we need the next word. | |
935 | */ | |
936 | if (++word == mp->m_blockwsize && i < len) { | |
937 | /* | |
938 | * If done with this block, get the next one. | |
939 | */ | |
940 | error = xfs_rtbitmap_read_buf(args, ++block); | |
941 | if (error) | |
942 | return error; | |
943 | ||
944 | word = 0; | |
945 | } | |
946 | } else { | |
947 | /* | |
948 | * Starting on a word boundary, no partial word. | |
949 | */ | |
950 | i = 0; | |
951 | } | |
952 | /* | |
953 | * Loop over whole words in buffers. When we use up one buffer | |
954 | * we move on to the next one. | |
955 | */ | |
956 | while (len - i >= XFS_NBWORD) { | |
957 | /* | |
958 | * Compute difference between actual and desired value. | |
959 | */ | |
960 | incore = xfs_rtbitmap_getword(args, word); | |
961 | if ((wdiff = incore ^ val)) { | |
962 | /* | |
963 | * Different, compute first wrong bit and return. | |
964 | */ | |
965 | i += xfs_lowbit32(wdiff); | |
966 | *new = start + i; | |
967 | *stat = 0; | |
968 | return 0; | |
969 | } | |
970 | i += XFS_NBWORD; | |
971 | /* | |
972 | * Go on to next block if that's where the next word is | |
973 | * and we need the next word. | |
974 | */ | |
975 | if (++word == mp->m_blockwsize && i < len) { | |
976 | /* | |
977 | * If done with this block, get the next one. | |
978 | */ | |
979 | error = xfs_rtbitmap_read_buf(args, ++block); | |
980 | if (error) | |
981 | return error; | |
982 | ||
983 | word = 0; | |
984 | } | |
985 | } | |
986 | /* | |
987 | * If not ending on a word boundary, deal with the last | |
988 | * (partial) word. | |
989 | */ | |
990 | if ((lastbit = len - i)) { | |
991 | /* | |
992 | * Mask of relevant bits. | |
993 | */ | |
994 | mask = ((xfs_rtword_t)1 << lastbit) - 1; | |
995 | /* | |
996 | * Compute difference between actual and desired value. | |
997 | */ | |
998 | incore = xfs_rtbitmap_getword(args, word); | |
999 | if ((wdiff = (incore ^ val) & mask)) { | |
1000 | /* | |
1001 | * Different, compute first wrong bit and return. | |
1002 | */ | |
1003 | i += xfs_lowbit32(wdiff); | |
1004 | *new = start + i; | |
1005 | *stat = 0; | |
1006 | return 0; | |
1007 | } else | |
1008 | i = len; | |
1009 | } | |
1010 | /* | |
1011 | * Successful, return. | |
1012 | */ | |
1013 | *new = start + i; | |
1014 | *stat = 1; | |
1015 | return 0; | |
1016 | } | |
1017 | ||
1018 | #ifdef DEBUG | |
1019 | /* | |
1020 | * Check that the given extent (block range) is allocated already. | |
1021 | */ | |
1022 | STATIC int | |
1023 | xfs_rtcheck_alloc_range( | |
1024 | struct xfs_rtalloc_args *args, | |
1025 | xfs_rtxnum_t start, /* starting rtext number of extent */ | |
1026 | xfs_rtxlen_t len) /* length of extent */ | |
1027 | { | |
1028 | xfs_rtxnum_t new; /* dummy for xfs_rtcheck_range */ | |
1029 | int stat; | |
1030 | int error; | |
1031 | ||
1032 | error = xfs_rtcheck_range(args, start, len, 0, &new, &stat); | |
1033 | if (error) | |
1034 | return error; | |
1035 | ASSERT(stat); | |
1036 | return 0; | |
1037 | } | |
1038 | #else | |
1039 | #define xfs_rtcheck_alloc_range(a,b,l) (0) | |
1040 | #endif | |
1041 | /* | |
1042 | * Free an extent in the realtime subvolume. Length is expressed in | |
1043 | * realtime extents, as is the block number. | |
1044 | */ | |
1045 | int | |
1046 | xfs_rtfree_extent( | |
1047 | struct xfs_trans *tp, /* transaction pointer */ | |
1048 | struct xfs_rtgroup *rtg, | |
1049 | xfs_rtxnum_t start, /* starting rtext number to free */ | |
1050 | xfs_rtxlen_t len) /* length of extent freed */ | |
1051 | { | |
1052 | struct xfs_mount *mp = tp->t_mountp; | |
1053 | struct xfs_inode *rbmip = rtg_bitmap(rtg); | |
1054 | struct xfs_rtalloc_args args = { | |
1055 | .mp = mp, | |
1056 | .tp = tp, | |
1057 | .rtg = rtg, | |
1058 | }; | |
1059 | int error; | |
1060 | struct timespec64 atime; | |
1061 | ||
1062 | ASSERT(rbmip->i_itemp != NULL); | |
1063 | xfs_assert_ilocked(rbmip, XFS_ILOCK_EXCL); | |
1064 | ||
1065 | if (XFS_TEST_ERROR(false, mp, XFS_ERRTAG_FREE_EXTENT)) | |
1066 | return -EIO; | |
1067 | ||
1068 | error = xfs_rtcheck_alloc_range(&args, start, len); | |
1069 | if (error) | |
1070 | return error; | |
1071 | ||
1072 | /* | |
1073 | * Free the range of realtime blocks. | |
1074 | */ | |
1075 | error = xfs_rtfree_range(&args, start, len); | |
1076 | if (error) | |
1077 | goto out; | |
1078 | ||
1079 | /* | |
1080 | * Mark more blocks free in the superblock. | |
1081 | */ | |
1082 | xfs_trans_mod_sb(tp, XFS_TRANS_SB_FREXTENTS, (long)len); | |
1083 | ||
1084 | /* | |
1085 | * If we've now freed all the blocks, reset the file sequence | |
1086 | * number to 0 for pre-RTG file systems. | |
1087 | */ | |
1088 | if (!xfs_has_rtgroups(mp) && | |
1089 | tp->t_frextents_delta + mp->m_sb.sb_frextents == | |
1090 | mp->m_sb.sb_rextents) { | |
1091 | if (!(rbmip->i_diflags & XFS_DIFLAG_NEWRTBM)) | |
1092 | rbmip->i_diflags |= XFS_DIFLAG_NEWRTBM; | |
1093 | ||
1094 | atime = inode_get_atime(VFS_I(rbmip)); | |
1095 | atime.tv_sec = 0; | |
1096 | inode_set_atime_to_ts(VFS_I(rbmip), atime); | |
1097 | xfs_trans_log_inode(tp, rbmip, XFS_ILOG_CORE); | |
1098 | } | |
1099 | error = 0; | |
1100 | out: | |
1101 | xfs_rtbuf_cache_relse(&args); | |
1102 | return error; | |
1103 | } | |
1104 | ||
1105 | /* | |
1106 | * Free some blocks in the realtime subvolume. rtbno and rtlen are in units of | |
1107 | * rt blocks, not rt extents; must be aligned to the rt extent size; and rtlen | |
1108 | * cannot exceed XFS_MAX_BMBT_EXTLEN. | |
1109 | */ | |
1110 | int | |
1111 | xfs_rtfree_blocks( | |
1112 | struct xfs_trans *tp, | |
1113 | struct xfs_rtgroup *rtg, | |
1114 | xfs_fsblock_t rtbno, | |
1115 | xfs_filblks_t rtlen) | |
1116 | { | |
1117 | struct xfs_mount *mp = tp->t_mountp; | |
1118 | xfs_extlen_t mod; | |
1119 | int error; | |
1120 | ||
1121 | ASSERT(!xfs_has_zoned(mp)); | |
1122 | ASSERT(rtlen <= XFS_MAX_BMBT_EXTLEN); | |
1123 | ||
1124 | mod = xfs_blen_to_rtxoff(mp, rtlen); | |
1125 | if (mod) { | |
1126 | ASSERT(mod == 0); | |
1127 | return -EIO; | |
1128 | } | |
1129 | ||
1130 | mod = xfs_rtb_to_rtxoff(mp, rtbno); | |
1131 | if (mod) { | |
1132 | ASSERT(mod == 0); | |
1133 | return -EIO; | |
1134 | } | |
1135 | ||
1136 | error = xfs_rtfree_extent(tp, rtg, xfs_rtb_to_rtx(mp, rtbno), | |
1137 | xfs_extlen_to_rtxlen(mp, rtlen)); | |
1138 | if (error) | |
1139 | return error; | |
1140 | ||
1141 | if (xfs_has_rtgroups(mp)) | |
1142 | xfs_extent_busy_insert(tp, rtg_group(rtg), | |
1143 | xfs_rtb_to_rgbno(mp, rtbno), rtlen, 0); | |
1144 | ||
1145 | return 0; | |
1146 | } | |
1147 | ||
1148 | /* Find all the free records within a given range. */ | |
1149 | int | |
1150 | xfs_rtalloc_query_range( | |
1151 | struct xfs_rtgroup *rtg, | |
1152 | struct xfs_trans *tp, | |
1153 | xfs_rtxnum_t start, | |
1154 | xfs_rtxnum_t end, | |
1155 | xfs_rtalloc_query_range_fn fn, | |
1156 | void *priv) | |
1157 | { | |
1158 | struct xfs_mount *mp = rtg_mount(rtg); | |
1159 | struct xfs_rtalloc_args args = { | |
1160 | .rtg = rtg, | |
1161 | .mp = mp, | |
1162 | .tp = tp, | |
1163 | }; | |
1164 | int error = 0; | |
1165 | ||
1166 | if (start > end) | |
1167 | return -EINVAL; | |
1168 | if (start == end || start >= rtg->rtg_extents) | |
1169 | return 0; | |
1170 | ||
1171 | end = min(end, rtg->rtg_extents - 1); | |
1172 | ||
1173 | if (xfs_has_zoned(mp)) | |
1174 | return -EINVAL; | |
1175 | ||
1176 | /* Iterate the bitmap, looking for discrepancies. */ | |
1177 | while (start <= end) { | |
1178 | struct xfs_rtalloc_rec rec; | |
1179 | int is_free; | |
1180 | xfs_rtxnum_t rtend; | |
1181 | ||
1182 | /* Is the first block free? */ | |
1183 | error = xfs_rtcheck_range(&args, start, 1, 1, &rtend, | |
1184 | &is_free); | |
1185 | if (error) | |
1186 | break; | |
1187 | ||
1188 | /* How long does the extent go for? */ | |
1189 | error = xfs_rtfind_forw(&args, start, end, &rtend); | |
1190 | if (error) | |
1191 | break; | |
1192 | ||
1193 | if (is_free) { | |
1194 | rec.ar_startext = start; | |
1195 | rec.ar_extcount = rtend - start + 1; | |
1196 | ||
1197 | error = fn(rtg, tp, &rec, priv); | |
1198 | if (error) | |
1199 | break; | |
1200 | } | |
1201 | ||
1202 | start = rtend + 1; | |
1203 | } | |
1204 | ||
1205 | xfs_rtbuf_cache_relse(&args); | |
1206 | return error; | |
1207 | } | |
1208 | ||
1209 | /* Find all the free records. */ | |
1210 | int | |
1211 | xfs_rtalloc_query_all( | |
1212 | struct xfs_rtgroup *rtg, | |
1213 | struct xfs_trans *tp, | |
1214 | xfs_rtalloc_query_range_fn fn, | |
1215 | void *priv) | |
1216 | { | |
1217 | return xfs_rtalloc_query_range(rtg, tp, 0, rtg->rtg_extents - 1, fn, | |
1218 | priv); | |
1219 | } | |
1220 | ||
1221 | /* Is the given extent all free? */ | |
1222 | int | |
1223 | xfs_rtalloc_extent_is_free( | |
1224 | struct xfs_rtgroup *rtg, | |
1225 | struct xfs_trans *tp, | |
1226 | xfs_rtxnum_t start, | |
1227 | xfs_rtxlen_t len, | |
1228 | bool *is_free) | |
1229 | { | |
1230 | struct xfs_rtalloc_args args = { | |
1231 | .mp = rtg_mount(rtg), | |
1232 | .rtg = rtg, | |
1233 | .tp = tp, | |
1234 | }; | |
1235 | xfs_rtxnum_t end; | |
1236 | int matches; | |
1237 | int error; | |
1238 | ||
1239 | error = xfs_rtcheck_range(&args, start, len, 1, &end, &matches); | |
1240 | xfs_rtbuf_cache_relse(&args); | |
1241 | if (error) | |
1242 | return error; | |
1243 | ||
1244 | *is_free = matches; | |
1245 | return 0; | |
1246 | } | |
1247 | ||
1248 | /* Compute the number of rt extents tracked by a single bitmap block. */ | |
1249 | xfs_rtxnum_t | |
1250 | xfs_rtbitmap_rtx_per_rbmblock( | |
1251 | struct xfs_mount *mp) | |
1252 | { | |
1253 | unsigned int rbmblock_bytes = mp->m_sb.sb_blocksize; | |
1254 | ||
1255 | if (xfs_has_rtgroups(mp)) | |
1256 | rbmblock_bytes -= sizeof(struct xfs_rtbuf_blkinfo); | |
1257 | ||
1258 | return rbmblock_bytes * NBBY; | |
1259 | } | |
1260 | ||
1261 | /* | |
1262 | * Compute the number of rtbitmap blocks needed to track the given number of rt | |
1263 | * extents. | |
1264 | */ | |
1265 | xfs_filblks_t | |
1266 | xfs_rtbitmap_blockcount_len( | |
1267 | struct xfs_mount *mp, | |
1268 | xfs_rtbxlen_t rtextents) | |
1269 | { | |
1270 | if (xfs_has_zoned(mp)) | |
1271 | return 0; | |
1272 | return howmany_64(rtextents, xfs_rtbitmap_rtx_per_rbmblock(mp)); | |
1273 | } | |
1274 | ||
1275 | /* How many rt extents does each rtbitmap file track? */ | |
1276 | static inline xfs_rtbxlen_t | |
1277 | xfs_rtbitmap_bitcount( | |
1278 | struct xfs_mount *mp) | |
1279 | { | |
1280 | if (!mp->m_sb.sb_rextents) | |
1281 | return 0; | |
1282 | ||
1283 | /* rtgroup size can be nonzero even if rextents is zero */ | |
1284 | if (xfs_has_rtgroups(mp)) | |
1285 | return mp->m_sb.sb_rgextents; | |
1286 | ||
1287 | return mp->m_sb.sb_rextents; | |
1288 | } | |
1289 | ||
1290 | /* | |
1291 | * Compute the number of rtbitmap blocks used for a given file system. | |
1292 | */ | |
1293 | xfs_filblks_t | |
1294 | xfs_rtbitmap_blockcount( | |
1295 | struct xfs_mount *mp) | |
1296 | { | |
1297 | return xfs_rtbitmap_blockcount_len(mp, xfs_rtbitmap_bitcount(mp)); | |
1298 | } | |
1299 | ||
1300 | /* | |
1301 | * Compute the geometry of the rtsummary file needed to track the given rt | |
1302 | * space. | |
1303 | */ | |
1304 | xfs_filblks_t | |
1305 | xfs_rtsummary_blockcount( | |
1306 | struct xfs_mount *mp, | |
1307 | unsigned int *rsumlevels) | |
1308 | { | |
1309 | xfs_rtbxlen_t rextents = xfs_rtbitmap_bitcount(mp); | |
1310 | unsigned long long rsumwords; | |
1311 | ||
1312 | if (xfs_has_zoned(mp)) { | |
1313 | *rsumlevels = 0; | |
1314 | return 0; | |
1315 | } | |
1316 | ||
1317 | *rsumlevels = xfs_compute_rextslog(rextents) + 1; | |
1318 | rsumwords = xfs_rtbitmap_blockcount_len(mp, rextents) * (*rsumlevels); | |
1319 | return howmany_64(rsumwords, mp->m_blockwsize); | |
1320 | } | |
1321 | ||
1322 | static int | |
1323 | xfs_rtfile_alloc_blocks( | |
1324 | struct xfs_inode *ip, | |
1325 | xfs_fileoff_t offset_fsb, | |
1326 | xfs_filblks_t count_fsb, | |
1327 | struct xfs_bmbt_irec *map) | |
1328 | { | |
1329 | struct xfs_mount *mp = ip->i_mount; | |
1330 | struct xfs_trans *tp; | |
1331 | int nmap = 1; | |
1332 | int error; | |
1333 | ||
1334 | error = xfs_trans_alloc(mp, &M_RES(mp)->tr_growrtalloc, | |
1335 | XFS_GROWFSRT_SPACE_RES(mp, count_fsb), 0, 0, &tp); | |
1336 | if (error) | |
1337 | return error; | |
1338 | ||
1339 | xfs_ilock(ip, XFS_ILOCK_EXCL); | |
1340 | xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); | |
1341 | ||
1342 | error = xfs_iext_count_extend(tp, ip, XFS_DATA_FORK, | |
1343 | XFS_IEXT_ADD_NOSPLIT_CNT); | |
1344 | if (error) | |
1345 | goto out_trans_cancel; | |
1346 | ||
1347 | error = xfs_bmapi_write(tp, ip, offset_fsb, count_fsb, | |
1348 | XFS_BMAPI_METADATA, 0, map, &nmap); | |
1349 | if (error) | |
1350 | goto out_trans_cancel; | |
1351 | ||
1352 | return xfs_trans_commit(tp); | |
1353 | ||
1354 | out_trans_cancel: | |
1355 | xfs_trans_cancel(tp); | |
1356 | return error; | |
1357 | } | |
1358 | ||
1359 | /* Get a buffer for the block. */ | |
1360 | static int | |
1361 | xfs_rtfile_initialize_block( | |
1362 | struct xfs_rtgroup *rtg, | |
1363 | enum xfs_rtg_inodes type, | |
1364 | xfs_fsblock_t fsbno, | |
1365 | void *data) | |
1366 | { | |
1367 | struct xfs_mount *mp = rtg_mount(rtg); | |
1368 | struct xfs_inode *ip = rtg->rtg_inodes[type]; | |
1369 | struct xfs_trans *tp; | |
1370 | struct xfs_buf *bp; | |
1371 | void *bufdata; | |
1372 | const size_t copylen = mp->m_blockwsize << XFS_WORDLOG; | |
1373 | enum xfs_blft buf_type; | |
1374 | int error; | |
1375 | ||
1376 | if (type == XFS_RTGI_BITMAP) | |
1377 | buf_type = XFS_BLFT_RTBITMAP_BUF; | |
1378 | else if (type == XFS_RTGI_SUMMARY) | |
1379 | buf_type = XFS_BLFT_RTSUMMARY_BUF; | |
1380 | else | |
1381 | return -EINVAL; | |
1382 | ||
1383 | error = xfs_trans_alloc(mp, &M_RES(mp)->tr_growrtzero, 0, 0, 0, &tp); | |
1384 | if (error) | |
1385 | return error; | |
1386 | xfs_ilock(ip, XFS_ILOCK_EXCL); | |
1387 | xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); | |
1388 | ||
1389 | error = xfs_trans_get_buf(tp, mp->m_ddev_targp, | |
1390 | XFS_FSB_TO_DADDR(mp, fsbno), mp->m_bsize, 0, &bp); | |
1391 | if (error) { | |
1392 | xfs_trans_cancel(tp); | |
1393 | return error; | |
1394 | } | |
1395 | bufdata = bp->b_addr; | |
1396 | ||
1397 | xfs_trans_buf_set_type(tp, bp, buf_type); | |
1398 | bp->b_ops = xfs_rtblock_ops(mp, type); | |
1399 | ||
1400 | if (xfs_has_rtgroups(mp)) { | |
1401 | struct xfs_rtbuf_blkinfo *hdr = bp->b_addr; | |
1402 | ||
1403 | if (type == XFS_RTGI_BITMAP) | |
1404 | hdr->rt_magic = cpu_to_be32(XFS_RTBITMAP_MAGIC); | |
1405 | else | |
1406 | hdr->rt_magic = cpu_to_be32(XFS_RTSUMMARY_MAGIC); | |
1407 | hdr->rt_owner = cpu_to_be64(ip->i_ino); | |
1408 | hdr->rt_blkno = cpu_to_be64(XFS_FSB_TO_DADDR(mp, fsbno)); | |
1409 | hdr->rt_lsn = 0; | |
1410 | uuid_copy(&hdr->rt_uuid, &mp->m_sb.sb_meta_uuid); | |
1411 | ||
1412 | bufdata += sizeof(*hdr); | |
1413 | } | |
1414 | ||
1415 | if (data) | |
1416 | memcpy(bufdata, data, copylen); | |
1417 | else | |
1418 | memset(bufdata, 0, copylen); | |
1419 | xfs_trans_log_buf(tp, bp, 0, mp->m_sb.sb_blocksize - 1); | |
1420 | return xfs_trans_commit(tp); | |
1421 | } | |
1422 | ||
1423 | /* | |
1424 | * Allocate space to the bitmap or summary file, and zero it, for growfs. | |
1425 | * @data must be a contiguous buffer large enough to fill all blocks in the | |
1426 | * file; or NULL to initialize the contents to zeroes. | |
1427 | */ | |
1428 | int | |
1429 | xfs_rtfile_initialize_blocks( | |
1430 | struct xfs_rtgroup *rtg, | |
1431 | enum xfs_rtg_inodes type, | |
1432 | xfs_fileoff_t offset_fsb, /* offset to start from */ | |
1433 | xfs_fileoff_t end_fsb, /* offset to allocate to */ | |
1434 | void *data) /* data to fill the blocks */ | |
1435 | { | |
1436 | struct xfs_mount *mp = rtg_mount(rtg); | |
1437 | const size_t copylen = mp->m_blockwsize << XFS_WORDLOG; | |
1438 | ||
1439 | while (offset_fsb < end_fsb) { | |
1440 | struct xfs_bmbt_irec map; | |
1441 | xfs_filblks_t i; | |
1442 | int error; | |
1443 | ||
1444 | error = xfs_rtfile_alloc_blocks(rtg->rtg_inodes[type], | |
1445 | offset_fsb, end_fsb - offset_fsb, &map); | |
1446 | if (error) | |
1447 | return error; | |
1448 | ||
1449 | /* | |
1450 | * Now we need to clear the allocated blocks. | |
1451 | * | |
1452 | * Do this one block per transaction, to keep it simple. | |
1453 | */ | |
1454 | for (i = 0; i < map.br_blockcount; i++) { | |
1455 | error = xfs_rtfile_initialize_block(rtg, type, | |
1456 | map.br_startblock + i, data); | |
1457 | if (error) | |
1458 | return error; | |
1459 | if (data) | |
1460 | data += copylen; | |
1461 | } | |
1462 | ||
1463 | offset_fsb = map.br_startoff + map.br_blockcount; | |
1464 | } | |
1465 | ||
1466 | return 0; | |
1467 | } | |
1468 | ||
1469 | int | |
1470 | xfs_rtbitmap_create( | |
1471 | struct xfs_rtgroup *rtg, | |
1472 | struct xfs_inode *ip, | |
1473 | struct xfs_trans *tp, | |
1474 | bool init) | |
1475 | { | |
1476 | struct xfs_mount *mp = rtg_mount(rtg); | |
1477 | ||
1478 | ip->i_disk_size = mp->m_sb.sb_rbmblocks * mp->m_sb.sb_blocksize; | |
1479 | if (init && !xfs_has_rtgroups(mp)) { | |
1480 | ip->i_diflags |= XFS_DIFLAG_NEWRTBM; | |
1481 | inode_set_atime(VFS_I(ip), 0, 0); | |
1482 | } | |
1483 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); | |
1484 | return 0; | |
1485 | } | |
1486 | ||
1487 | int | |
1488 | xfs_rtsummary_create( | |
1489 | struct xfs_rtgroup *rtg, | |
1490 | struct xfs_inode *ip, | |
1491 | struct xfs_trans *tp, | |
1492 | bool init) | |
1493 | { | |
1494 | struct xfs_mount *mp = rtg_mount(rtg); | |
1495 | ||
1496 | ip->i_disk_size = mp->m_rsumblocks * mp->m_sb.sb_blocksize; | |
1497 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); | |
1498 | return 0; | |
1499 | } |