diff options
author | Darrick J. Wong <darrick.wong@oracle.com> | 2016-10-03 12:11:21 -0400 |
---|---|---|
committer | Darrick J. Wong <darrick.wong@oracle.com> | 2016-10-03 12:11:21 -0400 |
commit | 3172725814f9a689d6e8b3c7979b66403abf5dae (patch) | |
tree | 6372a73150404f3390969f48433c1d978c580d4a | |
parent | f997ee2137175f5b2bd7ced52acf1ca51f04f420 (diff) |
xfs: adjust refcount of an extent of blocks in refcount btree
Provide functions to adjust the reference counts for an extent of
physical blocks stored in the refcount btree.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>
-rw-r--r-- | fs/xfs/libxfs/xfs_refcount.c | 814 | ||||
-rw-r--r-- | fs/xfs/xfs_error.h | 4 |
2 files changed, 817 insertions, 1 deletions
diff --git a/fs/xfs/libxfs/xfs_refcount.c b/fs/xfs/libxfs/xfs_refcount.c index de1340652933..f522fe130a16 100644 --- a/fs/xfs/libxfs/xfs_refcount.c +++ b/fs/xfs/libxfs/xfs_refcount.c | |||
@@ -37,6 +37,12 @@ | |||
37 | #include "xfs_bit.h" | 37 | #include "xfs_bit.h" |
38 | #include "xfs_refcount.h" | 38 | #include "xfs_refcount.h" |
39 | 39 | ||
40 | /* Allowable refcount adjustment amounts. */ | ||
41 | enum xfs_refc_adjust_op { | ||
42 | XFS_REFCOUNT_ADJUST_INCREASE = 1, | ||
43 | XFS_REFCOUNT_ADJUST_DECREASE = -1, | ||
44 | }; | ||
45 | |||
40 | /* | 46 | /* |
41 | * Look up the first record less than or equal to [bno, len] in the btree | 47 | * Look up the first record less than or equal to [bno, len] in the btree |
42 | * given by cur. | 48 | * given by cur. |
@@ -175,3 +181,811 @@ out_error: | |||
175 | cur->bc_private.a.agno, error, _RET_IP_); | 181 | cur->bc_private.a.agno, error, _RET_IP_); |
176 | return error; | 182 | return error; |
177 | } | 183 | } |
184 | |||
185 | /* | ||
186 | * Adjusting the Reference Count | ||
187 | * | ||
188 | * As stated elsewhere, the reference count btree (refcbt) stores | ||
189 | * >1 reference counts for extents of physical blocks. In this | ||
190 | * operation, we're either raising or lowering the reference count of | ||
191 | * some subrange stored in the tree: | ||
192 | * | ||
193 | * <------ adjustment range ------> | ||
194 | * ----+ +---+-----+ +--+--------+--------- | ||
195 | * 2 | | 3 | 4 | |17| 55 | 10 | ||
196 | * ----+ +---+-----+ +--+--------+--------- | ||
197 | * X axis is physical blocks number; | ||
198 | * reference counts are the numbers inside the rectangles | ||
199 | * | ||
200 | * The first thing we need to do is to ensure that there are no | ||
201 | * refcount extents crossing either boundary of the range to be | ||
202 | * adjusted. For any extent that does cross a boundary, split it into | ||
203 | * two extents so that we can increment the refcount of one of the | ||
204 | * pieces later: | ||
205 | * | ||
206 | * <------ adjustment range ------> | ||
207 | * ----+ +---+-----+ +--+--------+----+---- | ||
208 | * 2 | | 3 | 2 | |17| 55 | 10 | 10 | ||
209 | * ----+ +---+-----+ +--+--------+----+---- | ||
210 | * | ||
211 | * For this next step, let's assume that all the physical blocks in | ||
212 | * the adjustment range are mapped to a file and are therefore in use | ||
213 | * at least once. Therefore, we can infer that any gap in the | ||
214 | * refcount tree within the adjustment range represents a physical | ||
215 | * extent with refcount == 1: | ||
216 | * | ||
217 | * <------ adjustment range ------> | ||
218 | * ----+---+---+-----+-+--+--------+----+---- | ||
219 | * 2 |"1"| 3 | 2 |1|17| 55 | 10 | 10 | ||
220 | * ----+---+---+-----+-+--+--------+----+---- | ||
221 | * ^ | ||
222 | * | ||
223 | * For each extent that falls within the interval range, figure out | ||
224 | * which extent is to the left or the right of that extent. Now we | ||
225 | * have a left, current, and right extent. If the new reference count | ||
226 | * of the center extent enables us to merge left, center, and right | ||
227 | * into one record covering all three, do so. If the center extent is | ||
228 | * at the left end of the range, abuts the left extent, and its new | ||
229 | * reference count matches the left extent's record, then merge them. | ||
230 | * If the center extent is at the right end of the range, abuts the | ||
231 | * right extent, and the reference counts match, merge those. In the | ||
232 | * example, we can left merge (assuming an increment operation): | ||
233 | * | ||
234 | * <------ adjustment range ------> | ||
235 | * --------+---+-----+-+--+--------+----+---- | ||
236 | * 2 | 3 | 2 |1|17| 55 | 10 | 10 | ||
237 | * --------+---+-----+-+--+--------+----+---- | ||
238 | * ^ | ||
239 | * | ||
240 | * For all other extents within the range, adjust the reference count | ||
241 | * or delete it if the refcount falls below 2. If we were | ||
242 | * incrementing, the end result looks like this: | ||
243 | * | ||
244 | * <------ adjustment range ------> | ||
245 | * --------+---+-----+-+--+--------+----+---- | ||
246 | * 2 | 4 | 3 |2|18| 56 | 11 | 10 | ||
247 | * --------+---+-----+-+--+--------+----+---- | ||
248 | * | ||
249 | * The result of a decrement operation looks as such: | ||
250 | * | ||
251 | * <------ adjustment range ------> | ||
252 | * ----+ +---+ +--+--------+----+---- | ||
253 | * 2 | | 2 | |16| 54 | 9 | 10 | ||
254 | * ----+ +---+ +--+--------+----+---- | ||
255 | * DDDD 111111DD | ||
256 | * | ||
257 | * The blocks marked "D" are freed; the blocks marked "1" are only | ||
258 | * referenced once and therefore the record is removed from the | ||
259 | * refcount btree. | ||
260 | */ | ||
261 | |||
262 | /* Next block after this extent. */ | ||
263 | static inline xfs_agblock_t | ||
264 | xfs_refc_next( | ||
265 | struct xfs_refcount_irec *rc) | ||
266 | { | ||
267 | return rc->rc_startblock + rc->rc_blockcount; | ||
268 | } | ||
269 | |||
270 | /* | ||
271 | * Split a refcount extent that crosses agbno. | ||
272 | */ | ||
273 | STATIC int | ||
274 | xfs_refcount_split_extent( | ||
275 | struct xfs_btree_cur *cur, | ||
276 | xfs_agblock_t agbno, | ||
277 | bool *shape_changed) | ||
278 | { | ||
279 | struct xfs_refcount_irec rcext, tmp; | ||
280 | int found_rec; | ||
281 | int error; | ||
282 | |||
283 | *shape_changed = false; | ||
284 | error = xfs_refcount_lookup_le(cur, agbno, &found_rec); | ||
285 | if (error) | ||
286 | goto out_error; | ||
287 | if (!found_rec) | ||
288 | return 0; | ||
289 | |||
290 | error = xfs_refcount_get_rec(cur, &rcext, &found_rec); | ||
291 | if (error) | ||
292 | goto out_error; | ||
293 | XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); | ||
294 | if (rcext.rc_startblock == agbno || xfs_refc_next(&rcext) <= agbno) | ||
295 | return 0; | ||
296 | |||
297 | *shape_changed = true; | ||
298 | trace_xfs_refcount_split_extent(cur->bc_mp, cur->bc_private.a.agno, | ||
299 | &rcext, agbno); | ||
300 | |||
301 | /* Establish the right extent. */ | ||
302 | tmp = rcext; | ||
303 | tmp.rc_startblock = agbno; | ||
304 | tmp.rc_blockcount -= (agbno - rcext.rc_startblock); | ||
305 | error = xfs_refcount_update(cur, &tmp); | ||
306 | if (error) | ||
307 | goto out_error; | ||
308 | |||
309 | /* Insert the left extent. */ | ||
310 | tmp = rcext; | ||
311 | tmp.rc_blockcount = agbno - rcext.rc_startblock; | ||
312 | error = xfs_refcount_insert(cur, &tmp, &found_rec); | ||
313 | if (error) | ||
314 | goto out_error; | ||
315 | XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); | ||
316 | return error; | ||
317 | |||
318 | out_error: | ||
319 | trace_xfs_refcount_split_extent_error(cur->bc_mp, | ||
320 | cur->bc_private.a.agno, error, _RET_IP_); | ||
321 | return error; | ||
322 | } | ||
323 | |||
324 | /* | ||
325 | * Merge the left, center, and right extents. | ||
326 | */ | ||
327 | STATIC int | ||
328 | xfs_refcount_merge_center_extents( | ||
329 | struct xfs_btree_cur *cur, | ||
330 | struct xfs_refcount_irec *left, | ||
331 | struct xfs_refcount_irec *center, | ||
332 | struct xfs_refcount_irec *right, | ||
333 | unsigned long long extlen, | ||
334 | xfs_agblock_t *agbno, | ||
335 | xfs_extlen_t *aglen) | ||
336 | { | ||
337 | int error; | ||
338 | int found_rec; | ||
339 | |||
340 | trace_xfs_refcount_merge_center_extents(cur->bc_mp, | ||
341 | cur->bc_private.a.agno, left, center, right); | ||
342 | |||
343 | /* | ||
344 | * Make sure the center and right extents are not in the btree. | ||
345 | * If the center extent was synthesized, the first delete call | ||
346 | * removes the right extent and we skip the second deletion. | ||
347 | * If center and right were in the btree, then the first delete | ||
348 | * call removes the center and the second one removes the right | ||
349 | * extent. | ||
350 | */ | ||
351 | error = xfs_refcount_lookup_ge(cur, center->rc_startblock, | ||
352 | &found_rec); | ||
353 | if (error) | ||
354 | goto out_error; | ||
355 | XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); | ||
356 | |||
357 | error = xfs_refcount_delete(cur, &found_rec); | ||
358 | if (error) | ||
359 | goto out_error; | ||
360 | XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); | ||
361 | |||
362 | if (center->rc_refcount > 1) { | ||
363 | error = xfs_refcount_delete(cur, &found_rec); | ||
364 | if (error) | ||
365 | goto out_error; | ||
366 | XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, | ||
367 | out_error); | ||
368 | } | ||
369 | |||
370 | /* Enlarge the left extent. */ | ||
371 | error = xfs_refcount_lookup_le(cur, left->rc_startblock, | ||
372 | &found_rec); | ||
373 | if (error) | ||
374 | goto out_error; | ||
375 | XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); | ||
376 | |||
377 | left->rc_blockcount = extlen; | ||
378 | error = xfs_refcount_update(cur, left); | ||
379 | if (error) | ||
380 | goto out_error; | ||
381 | |||
382 | *aglen = 0; | ||
383 | return error; | ||
384 | |||
385 | out_error: | ||
386 | trace_xfs_refcount_merge_center_extents_error(cur->bc_mp, | ||
387 | cur->bc_private.a.agno, error, _RET_IP_); | ||
388 | return error; | ||
389 | } | ||
390 | |||
391 | /* | ||
392 | * Merge with the left extent. | ||
393 | */ | ||
394 | STATIC int | ||
395 | xfs_refcount_merge_left_extent( | ||
396 | struct xfs_btree_cur *cur, | ||
397 | struct xfs_refcount_irec *left, | ||
398 | struct xfs_refcount_irec *cleft, | ||
399 | xfs_agblock_t *agbno, | ||
400 | xfs_extlen_t *aglen) | ||
401 | { | ||
402 | int error; | ||
403 | int found_rec; | ||
404 | |||
405 | trace_xfs_refcount_merge_left_extent(cur->bc_mp, | ||
406 | cur->bc_private.a.agno, left, cleft); | ||
407 | |||
408 | /* If the extent at agbno (cleft) wasn't synthesized, remove it. */ | ||
409 | if (cleft->rc_refcount > 1) { | ||
410 | error = xfs_refcount_lookup_le(cur, cleft->rc_startblock, | ||
411 | &found_rec); | ||
412 | if (error) | ||
413 | goto out_error; | ||
414 | XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, | ||
415 | out_error); | ||
416 | |||
417 | error = xfs_refcount_delete(cur, &found_rec); | ||
418 | if (error) | ||
419 | goto out_error; | ||
420 | XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, | ||
421 | out_error); | ||
422 | } | ||
423 | |||
424 | /* Enlarge the left extent. */ | ||
425 | error = xfs_refcount_lookup_le(cur, left->rc_startblock, | ||
426 | &found_rec); | ||
427 | if (error) | ||
428 | goto out_error; | ||
429 | XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); | ||
430 | |||
431 | left->rc_blockcount += cleft->rc_blockcount; | ||
432 | error = xfs_refcount_update(cur, left); | ||
433 | if (error) | ||
434 | goto out_error; | ||
435 | |||
436 | *agbno += cleft->rc_blockcount; | ||
437 | *aglen -= cleft->rc_blockcount; | ||
438 | return error; | ||
439 | |||
440 | out_error: | ||
441 | trace_xfs_refcount_merge_left_extent_error(cur->bc_mp, | ||
442 | cur->bc_private.a.agno, error, _RET_IP_); | ||
443 | return error; | ||
444 | } | ||
445 | |||
446 | /* | ||
447 | * Merge with the right extent. | ||
448 | */ | ||
449 | STATIC int | ||
450 | xfs_refcount_merge_right_extent( | ||
451 | struct xfs_btree_cur *cur, | ||
452 | struct xfs_refcount_irec *right, | ||
453 | struct xfs_refcount_irec *cright, | ||
454 | xfs_agblock_t *agbno, | ||
455 | xfs_extlen_t *aglen) | ||
456 | { | ||
457 | int error; | ||
458 | int found_rec; | ||
459 | |||
460 | trace_xfs_refcount_merge_right_extent(cur->bc_mp, | ||
461 | cur->bc_private.a.agno, cright, right); | ||
462 | |||
463 | /* | ||
464 | * If the extent ending at agbno+aglen (cright) wasn't synthesized, | ||
465 | * remove it. | ||
466 | */ | ||
467 | if (cright->rc_refcount > 1) { | ||
468 | error = xfs_refcount_lookup_le(cur, cright->rc_startblock, | ||
469 | &found_rec); | ||
470 | if (error) | ||
471 | goto out_error; | ||
472 | XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, | ||
473 | out_error); | ||
474 | |||
475 | error = xfs_refcount_delete(cur, &found_rec); | ||
476 | if (error) | ||
477 | goto out_error; | ||
478 | XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, | ||
479 | out_error); | ||
480 | } | ||
481 | |||
482 | /* Enlarge the right extent. */ | ||
483 | error = xfs_refcount_lookup_le(cur, right->rc_startblock, | ||
484 | &found_rec); | ||
485 | if (error) | ||
486 | goto out_error; | ||
487 | XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); | ||
488 | |||
489 | right->rc_startblock -= cright->rc_blockcount; | ||
490 | right->rc_blockcount += cright->rc_blockcount; | ||
491 | error = xfs_refcount_update(cur, right); | ||
492 | if (error) | ||
493 | goto out_error; | ||
494 | |||
495 | *aglen -= cright->rc_blockcount; | ||
496 | return error; | ||
497 | |||
498 | out_error: | ||
499 | trace_xfs_refcount_merge_right_extent_error(cur->bc_mp, | ||
500 | cur->bc_private.a.agno, error, _RET_IP_); | ||
501 | return error; | ||
502 | } | ||
503 | |||
504 | /* | ||
505 | * Find the left extent and the one after it (cleft). This function assumes | ||
506 | * that we've already split any extent crossing agbno. | ||
507 | */ | ||
508 | STATIC int | ||
509 | xfs_refcount_find_left_extents( | ||
510 | struct xfs_btree_cur *cur, | ||
511 | struct xfs_refcount_irec *left, | ||
512 | struct xfs_refcount_irec *cleft, | ||
513 | xfs_agblock_t agbno, | ||
514 | xfs_extlen_t aglen) | ||
515 | { | ||
516 | struct xfs_refcount_irec tmp; | ||
517 | int error; | ||
518 | int found_rec; | ||
519 | |||
520 | left->rc_startblock = cleft->rc_startblock = NULLAGBLOCK; | ||
521 | error = xfs_refcount_lookup_le(cur, agbno - 1, &found_rec); | ||
522 | if (error) | ||
523 | goto out_error; | ||
524 | if (!found_rec) | ||
525 | return 0; | ||
526 | |||
527 | error = xfs_refcount_get_rec(cur, &tmp, &found_rec); | ||
528 | if (error) | ||
529 | goto out_error; | ||
530 | XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); | ||
531 | |||
532 | if (xfs_refc_next(&tmp) != agbno) | ||
533 | return 0; | ||
534 | /* We have a left extent; retrieve (or invent) the next right one */ | ||
535 | *left = tmp; | ||
536 | |||
537 | error = xfs_btree_increment(cur, 0, &found_rec); | ||
538 | if (error) | ||
539 | goto out_error; | ||
540 | if (found_rec) { | ||
541 | error = xfs_refcount_get_rec(cur, &tmp, &found_rec); | ||
542 | if (error) | ||
543 | goto out_error; | ||
544 | XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, | ||
545 | out_error); | ||
546 | |||
547 | /* if tmp starts at the end of our range, just use that */ | ||
548 | if (tmp.rc_startblock == agbno) | ||
549 | *cleft = tmp; | ||
550 | else { | ||
551 | /* | ||
552 | * There's a gap in the refcntbt at the start of the | ||
553 | * range we're interested in (refcount == 1) so | ||
554 | * synthesize the implied extent and pass it back. | ||
555 | * We assume here that the agbno/aglen range was | ||
556 | * passed in from a data fork extent mapping and | ||
557 | * therefore is allocated to exactly one owner. | ||
558 | */ | ||
559 | cleft->rc_startblock = agbno; | ||
560 | cleft->rc_blockcount = min(aglen, | ||
561 | tmp.rc_startblock - agbno); | ||
562 | cleft->rc_refcount = 1; | ||
563 | } | ||
564 | } else { | ||
565 | /* | ||
566 | * No extents, so pretend that there's one covering the whole | ||
567 | * range. | ||
568 | */ | ||
569 | cleft->rc_startblock = agbno; | ||
570 | cleft->rc_blockcount = aglen; | ||
571 | cleft->rc_refcount = 1; | ||
572 | } | ||
573 | trace_xfs_refcount_find_left_extent(cur->bc_mp, cur->bc_private.a.agno, | ||
574 | left, cleft, agbno); | ||
575 | return error; | ||
576 | |||
577 | out_error: | ||
578 | trace_xfs_refcount_find_left_extent_error(cur->bc_mp, | ||
579 | cur->bc_private.a.agno, error, _RET_IP_); | ||
580 | return error; | ||
581 | } | ||
582 | |||
583 | /* | ||
584 | * Find the right extent and the one before it (cright). This function | ||
585 | * assumes that we've already split any extents crossing agbno + aglen. | ||
586 | */ | ||
587 | STATIC int | ||
588 | xfs_refcount_find_right_extents( | ||
589 | struct xfs_btree_cur *cur, | ||
590 | struct xfs_refcount_irec *right, | ||
591 | struct xfs_refcount_irec *cright, | ||
592 | xfs_agblock_t agbno, | ||
593 | xfs_extlen_t aglen) | ||
594 | { | ||
595 | struct xfs_refcount_irec tmp; | ||
596 | int error; | ||
597 | int found_rec; | ||
598 | |||
599 | right->rc_startblock = cright->rc_startblock = NULLAGBLOCK; | ||
600 | error = xfs_refcount_lookup_ge(cur, agbno + aglen, &found_rec); | ||
601 | if (error) | ||
602 | goto out_error; | ||
603 | if (!found_rec) | ||
604 | return 0; | ||
605 | |||
606 | error = xfs_refcount_get_rec(cur, &tmp, &found_rec); | ||
607 | if (error) | ||
608 | goto out_error; | ||
609 | XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); | ||
610 | |||
611 | if (tmp.rc_startblock != agbno + aglen) | ||
612 | return 0; | ||
613 | /* We have a right extent; retrieve (or invent) the next left one */ | ||
614 | *right = tmp; | ||
615 | |||
616 | error = xfs_btree_decrement(cur, 0, &found_rec); | ||
617 | if (error) | ||
618 | goto out_error; | ||
619 | if (found_rec) { | ||
620 | error = xfs_refcount_get_rec(cur, &tmp, &found_rec); | ||
621 | if (error) | ||
622 | goto out_error; | ||
623 | XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, | ||
624 | out_error); | ||
625 | |||
626 | /* if tmp ends at the end of our range, just use that */ | ||
627 | if (xfs_refc_next(&tmp) == agbno + aglen) | ||
628 | *cright = tmp; | ||
629 | else { | ||
630 | /* | ||
631 | * There's a gap in the refcntbt at the end of the | ||
632 | * range we're interested in (refcount == 1) so | ||
633 | * create the implied extent and pass it back. | ||
634 | * We assume here that the agbno/aglen range was | ||
635 | * passed in from a data fork extent mapping and | ||
636 | * therefore is allocated to exactly one owner. | ||
637 | */ | ||
638 | cright->rc_startblock = max(agbno, xfs_refc_next(&tmp)); | ||
639 | cright->rc_blockcount = right->rc_startblock - | ||
640 | cright->rc_startblock; | ||
641 | cright->rc_refcount = 1; | ||
642 | } | ||
643 | } else { | ||
644 | /* | ||
645 | * No extents, so pretend that there's one covering the whole | ||
646 | * range. | ||
647 | */ | ||
648 | cright->rc_startblock = agbno; | ||
649 | cright->rc_blockcount = aglen; | ||
650 | cright->rc_refcount = 1; | ||
651 | } | ||
652 | trace_xfs_refcount_find_right_extent(cur->bc_mp, cur->bc_private.a.agno, | ||
653 | cright, right, agbno + aglen); | ||
654 | return error; | ||
655 | |||
656 | out_error: | ||
657 | trace_xfs_refcount_find_right_extent_error(cur->bc_mp, | ||
658 | cur->bc_private.a.agno, error, _RET_IP_); | ||
659 | return error; | ||
660 | } | ||
661 | |||
662 | /* Is this extent valid? */ | ||
663 | static inline bool | ||
664 | xfs_refc_valid( | ||
665 | struct xfs_refcount_irec *rc) | ||
666 | { | ||
667 | return rc->rc_startblock != NULLAGBLOCK; | ||
668 | } | ||
669 | |||
670 | /* | ||
671 | * Try to merge with any extents on the boundaries of the adjustment range. | ||
672 | */ | ||
673 | STATIC int | ||
674 | xfs_refcount_merge_extents( | ||
675 | struct xfs_btree_cur *cur, | ||
676 | xfs_agblock_t *agbno, | ||
677 | xfs_extlen_t *aglen, | ||
678 | enum xfs_refc_adjust_op adjust, | ||
679 | bool *shape_changed) | ||
680 | { | ||
681 | struct xfs_refcount_irec left = {0}, cleft = {0}; | ||
682 | struct xfs_refcount_irec cright = {0}, right = {0}; | ||
683 | int error; | ||
684 | unsigned long long ulen; | ||
685 | bool cequal; | ||
686 | |||
687 | *shape_changed = false; | ||
688 | /* | ||
689 | * Find the extent just below agbno [left], just above agbno [cleft], | ||
690 | * just below (agbno + aglen) [cright], and just above (agbno + aglen) | ||
691 | * [right]. | ||
692 | */ | ||
693 | error = xfs_refcount_find_left_extents(cur, &left, &cleft, *agbno, | ||
694 | *aglen); | ||
695 | if (error) | ||
696 | return error; | ||
697 | error = xfs_refcount_find_right_extents(cur, &right, &cright, *agbno, | ||
698 | *aglen); | ||
699 | if (error) | ||
700 | return error; | ||
701 | |||
702 | /* No left or right extent to merge; exit. */ | ||
703 | if (!xfs_refc_valid(&left) && !xfs_refc_valid(&right)) | ||
704 | return 0; | ||
705 | |||
706 | cequal = (cleft.rc_startblock == cright.rc_startblock) && | ||
707 | (cleft.rc_blockcount == cright.rc_blockcount); | ||
708 | |||
709 | /* Try to merge left, cleft, and right. cleft must == cright. */ | ||
710 | ulen = (unsigned long long)left.rc_blockcount + cleft.rc_blockcount + | ||
711 | right.rc_blockcount; | ||
712 | if (xfs_refc_valid(&left) && xfs_refc_valid(&right) && | ||
713 | xfs_refc_valid(&cleft) && xfs_refc_valid(&cright) && cequal && | ||
714 | left.rc_refcount == cleft.rc_refcount + adjust && | ||
715 | right.rc_refcount == cleft.rc_refcount + adjust && | ||
716 | ulen < MAXREFCEXTLEN) { | ||
717 | *shape_changed = true; | ||
718 | return xfs_refcount_merge_center_extents(cur, &left, &cleft, | ||
719 | &right, ulen, agbno, aglen); | ||
720 | } | ||
721 | |||
722 | /* Try to merge left and cleft. */ | ||
723 | ulen = (unsigned long long)left.rc_blockcount + cleft.rc_blockcount; | ||
724 | if (xfs_refc_valid(&left) && xfs_refc_valid(&cleft) && | ||
725 | left.rc_refcount == cleft.rc_refcount + adjust && | ||
726 | ulen < MAXREFCEXTLEN) { | ||
727 | *shape_changed = true; | ||
728 | error = xfs_refcount_merge_left_extent(cur, &left, &cleft, | ||
729 | agbno, aglen); | ||
730 | if (error) | ||
731 | return error; | ||
732 | |||
733 | /* | ||
734 | * If we just merged left + cleft and cleft == cright, | ||
735 | * we no longer have a cright to merge with right. We're done. | ||
736 | */ | ||
737 | if (cequal) | ||
738 | return 0; | ||
739 | } | ||
740 | |||
741 | /* Try to merge cright and right. */ | ||
742 | ulen = (unsigned long long)right.rc_blockcount + cright.rc_blockcount; | ||
743 | if (xfs_refc_valid(&right) && xfs_refc_valid(&cright) && | ||
744 | right.rc_refcount == cright.rc_refcount + adjust && | ||
745 | ulen < MAXREFCEXTLEN) { | ||
746 | *shape_changed = true; | ||
747 | return xfs_refcount_merge_right_extent(cur, &right, &cright, | ||
748 | agbno, aglen); | ||
749 | } | ||
750 | |||
751 | return error; | ||
752 | } | ||
753 | |||
754 | /* | ||
755 | * While we're adjusting the refcounts records of an extent, we have | ||
756 | * to keep an eye on the number of extents we're dirtying -- run too | ||
757 | * many in a single transaction and we'll exceed the transaction's | ||
758 | * reservation and crash the fs. Each record adds 12 bytes to the | ||
759 | * log (plus any key updates) so we'll conservatively assume 24 bytes | ||
760 | * per record. We must also leave space for btree splits on both ends | ||
761 | * of the range and space for the CUD and a new CUI. | ||
762 | * | ||
763 | * XXX: This is a pretty hand-wavy estimate. The penalty for guessing | ||
764 | * true incorrectly is a shutdown FS; the penalty for guessing false | ||
765 | * incorrectly is more transaction rolls than might be necessary. | ||
766 | * Be conservative here. | ||
767 | */ | ||
768 | static bool | ||
769 | xfs_refcount_still_have_space( | ||
770 | struct xfs_btree_cur *cur) | ||
771 | { | ||
772 | unsigned long overhead; | ||
773 | |||
774 | overhead = cur->bc_private.a.priv.refc.shape_changes * | ||
775 | xfs_allocfree_log_count(cur->bc_mp, 1); | ||
776 | overhead *= cur->bc_mp->m_sb.sb_blocksize; | ||
777 | |||
778 | /* | ||
779 | * Only allow 2 refcount extent updates per transaction if the | ||
780 | * refcount continue update "error" has been injected. | ||
781 | */ | ||
782 | if (cur->bc_private.a.priv.refc.nr_ops > 2 && | ||
783 | XFS_TEST_ERROR(false, cur->bc_mp, | ||
784 | XFS_ERRTAG_REFCOUNT_CONTINUE_UPDATE, | ||
785 | XFS_RANDOM_REFCOUNT_CONTINUE_UPDATE)) | ||
786 | return false; | ||
787 | |||
788 | if (cur->bc_private.a.priv.refc.nr_ops == 0) | ||
789 | return true; | ||
790 | else if (overhead > cur->bc_tp->t_log_res) | ||
791 | return false; | ||
792 | return cur->bc_tp->t_log_res - overhead > | ||
793 | cur->bc_private.a.priv.refc.nr_ops * 32; | ||
794 | } | ||
795 | |||
796 | /* | ||
797 | * Adjust the refcounts of middle extents. At this point we should have | ||
798 | * split extents that crossed the adjustment range; merged with adjacent | ||
799 | * extents; and updated agbno/aglen to reflect the merges. Therefore, | ||
800 | * all we have to do is update the extents inside [agbno, agbno + aglen]. | ||
801 | */ | ||
802 | STATIC int | ||
803 | xfs_refcount_adjust_extents( | ||
804 | struct xfs_btree_cur *cur, | ||
805 | xfs_agblock_t *agbno, | ||
806 | xfs_extlen_t *aglen, | ||
807 | enum xfs_refc_adjust_op adj, | ||
808 | struct xfs_defer_ops *dfops, | ||
809 | struct xfs_owner_info *oinfo) | ||
810 | { | ||
811 | struct xfs_refcount_irec ext, tmp; | ||
812 | int error; | ||
813 | int found_rec, found_tmp; | ||
814 | xfs_fsblock_t fsbno; | ||
815 | |||
816 | /* Merging did all the work already. */ | ||
817 | if (*aglen == 0) | ||
818 | return 0; | ||
819 | |||
820 | error = xfs_refcount_lookup_ge(cur, *agbno, &found_rec); | ||
821 | if (error) | ||
822 | goto out_error; | ||
823 | |||
824 | while (*aglen > 0 && xfs_refcount_still_have_space(cur)) { | ||
825 | error = xfs_refcount_get_rec(cur, &ext, &found_rec); | ||
826 | if (error) | ||
827 | goto out_error; | ||
828 | if (!found_rec) { | ||
829 | ext.rc_startblock = cur->bc_mp->m_sb.sb_agblocks; | ||
830 | ext.rc_blockcount = 0; | ||
831 | ext.rc_refcount = 0; | ||
832 | } | ||
833 | |||
834 | /* | ||
835 | * Deal with a hole in the refcount tree; if a file maps to | ||
836 | * these blocks and there's no refcountbt record, pretend that | ||
837 | * there is one with refcount == 1. | ||
838 | */ | ||
839 | if (ext.rc_startblock != *agbno) { | ||
840 | tmp.rc_startblock = *agbno; | ||
841 | tmp.rc_blockcount = min(*aglen, | ||
842 | ext.rc_startblock - *agbno); | ||
843 | tmp.rc_refcount = 1 + adj; | ||
844 | trace_xfs_refcount_modify_extent(cur->bc_mp, | ||
845 | cur->bc_private.a.agno, &tmp); | ||
846 | |||
847 | /* | ||
848 | * Either cover the hole (increment) or | ||
849 | * delete the range (decrement). | ||
850 | */ | ||
851 | if (tmp.rc_refcount) { | ||
852 | error = xfs_refcount_insert(cur, &tmp, | ||
853 | &found_tmp); | ||
854 | if (error) | ||
855 | goto out_error; | ||
856 | XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, | ||
857 | found_tmp == 1, out_error); | ||
858 | cur->bc_private.a.priv.refc.nr_ops++; | ||
859 | } else { | ||
860 | fsbno = XFS_AGB_TO_FSB(cur->bc_mp, | ||
861 | cur->bc_private.a.agno, | ||
862 | tmp.rc_startblock); | ||
863 | xfs_bmap_add_free(cur->bc_mp, dfops, fsbno, | ||
864 | tmp.rc_blockcount, oinfo); | ||
865 | } | ||
866 | |||
867 | (*agbno) += tmp.rc_blockcount; | ||
868 | (*aglen) -= tmp.rc_blockcount; | ||
869 | |||
870 | error = xfs_refcount_lookup_ge(cur, *agbno, | ||
871 | &found_rec); | ||
872 | if (error) | ||
873 | goto out_error; | ||
874 | } | ||
875 | |||
876 | /* Stop if there's nothing left to modify */ | ||
877 | if (*aglen == 0 || !xfs_refcount_still_have_space(cur)) | ||
878 | break; | ||
879 | |||
880 | /* | ||
881 | * Adjust the reference count and either update the tree | ||
882 | * (incr) or free the blocks (decr). | ||
883 | */ | ||
884 | if (ext.rc_refcount == MAXREFCOUNT) | ||
885 | goto skip; | ||
886 | ext.rc_refcount += adj; | ||
887 | trace_xfs_refcount_modify_extent(cur->bc_mp, | ||
888 | cur->bc_private.a.agno, &ext); | ||
889 | if (ext.rc_refcount > 1) { | ||
890 | error = xfs_refcount_update(cur, &ext); | ||
891 | if (error) | ||
892 | goto out_error; | ||
893 | cur->bc_private.a.priv.refc.nr_ops++; | ||
894 | } else if (ext.rc_refcount == 1) { | ||
895 | error = xfs_refcount_delete(cur, &found_rec); | ||
896 | if (error) | ||
897 | goto out_error; | ||
898 | XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, | ||
899 | found_rec == 1, out_error); | ||
900 | cur->bc_private.a.priv.refc.nr_ops++; | ||
901 | goto advloop; | ||
902 | } else { | ||
903 | fsbno = XFS_AGB_TO_FSB(cur->bc_mp, | ||
904 | cur->bc_private.a.agno, | ||
905 | ext.rc_startblock); | ||
906 | xfs_bmap_add_free(cur->bc_mp, dfops, fsbno, | ||
907 | ext.rc_blockcount, oinfo); | ||
908 | } | ||
909 | |||
910 | skip: | ||
911 | error = xfs_btree_increment(cur, 0, &found_rec); | ||
912 | if (error) | ||
913 | goto out_error; | ||
914 | |||
915 | advloop: | ||
916 | (*agbno) += ext.rc_blockcount; | ||
917 | (*aglen) -= ext.rc_blockcount; | ||
918 | } | ||
919 | |||
920 | return error; | ||
921 | out_error: | ||
922 | trace_xfs_refcount_modify_extent_error(cur->bc_mp, | ||
923 | cur->bc_private.a.agno, error, _RET_IP_); | ||
924 | return error; | ||
925 | } | ||
926 | |||
927 | /* Adjust the reference count of a range of AG blocks. */ | ||
928 | STATIC int | ||
929 | xfs_refcount_adjust( | ||
930 | struct xfs_btree_cur *cur, | ||
931 | xfs_agblock_t agbno, | ||
932 | xfs_extlen_t aglen, | ||
933 | xfs_agblock_t *new_agbno, | ||
934 | xfs_extlen_t *new_aglen, | ||
935 | enum xfs_refc_adjust_op adj, | ||
936 | struct xfs_defer_ops *dfops, | ||
937 | struct xfs_owner_info *oinfo) | ||
938 | { | ||
939 | bool shape_changed; | ||
940 | int shape_changes = 0; | ||
941 | int error; | ||
942 | |||
943 | *new_agbno = agbno; | ||
944 | *new_aglen = aglen; | ||
945 | if (adj == XFS_REFCOUNT_ADJUST_INCREASE) | ||
946 | trace_xfs_refcount_increase(cur->bc_mp, cur->bc_private.a.agno, | ||
947 | agbno, aglen); | ||
948 | else | ||
949 | trace_xfs_refcount_decrease(cur->bc_mp, cur->bc_private.a.agno, | ||
950 | agbno, aglen); | ||
951 | |||
952 | /* | ||
953 | * Ensure that no rcextents cross the boundary of the adjustment range. | ||
954 | */ | ||
955 | error = xfs_refcount_split_extent(cur, agbno, &shape_changed); | ||
956 | if (error) | ||
957 | goto out_error; | ||
958 | if (shape_changed) | ||
959 | shape_changes++; | ||
960 | |||
961 | error = xfs_refcount_split_extent(cur, agbno + aglen, &shape_changed); | ||
962 | if (error) | ||
963 | goto out_error; | ||
964 | if (shape_changed) | ||
965 | shape_changes++; | ||
966 | |||
967 | /* | ||
968 | * Try to merge with the left or right extents of the range. | ||
969 | */ | ||
970 | error = xfs_refcount_merge_extents(cur, new_agbno, new_aglen, adj, | ||
971 | &shape_changed); | ||
972 | if (error) | ||
973 | goto out_error; | ||
974 | if (shape_changed) | ||
975 | shape_changes++; | ||
976 | if (shape_changes) | ||
977 | cur->bc_private.a.priv.refc.shape_changes++; | ||
978 | |||
979 | /* Now that we've taken care of the ends, adjust the middle extents */ | ||
980 | error = xfs_refcount_adjust_extents(cur, new_agbno, new_aglen, | ||
981 | adj, dfops, oinfo); | ||
982 | if (error) | ||
983 | goto out_error; | ||
984 | |||
985 | return 0; | ||
986 | |||
987 | out_error: | ||
988 | trace_xfs_refcount_adjust_error(cur->bc_mp, cur->bc_private.a.agno, | ||
989 | error, _RET_IP_); | ||
990 | return error; | ||
991 | } | ||
diff --git a/fs/xfs/xfs_error.h b/fs/xfs/xfs_error.h index 3d224702fbc0..d9675c646572 100644 --- a/fs/xfs/xfs_error.h +++ b/fs/xfs/xfs_error.h | |||
@@ -92,7 +92,8 @@ extern void xfs_verifier_error(struct xfs_buf *bp); | |||
92 | #define XFS_ERRTAG_BMAPIFORMAT 21 | 92 | #define XFS_ERRTAG_BMAPIFORMAT 21 |
93 | #define XFS_ERRTAG_FREE_EXTENT 22 | 93 | #define XFS_ERRTAG_FREE_EXTENT 22 |
94 | #define XFS_ERRTAG_RMAP_FINISH_ONE 23 | 94 | #define XFS_ERRTAG_RMAP_FINISH_ONE 23 |
95 | #define XFS_ERRTAG_MAX 24 | 95 | #define XFS_ERRTAG_REFCOUNT_CONTINUE_UPDATE 24 |
96 | #define XFS_ERRTAG_MAX 25 | ||
96 | 97 | ||
97 | /* | 98 | /* |
98 | * Random factors for above tags, 1 means always, 2 means 1/2 time, etc. | 99 | * Random factors for above tags, 1 means always, 2 means 1/2 time, etc. |
@@ -121,6 +122,7 @@ extern void xfs_verifier_error(struct xfs_buf *bp); | |||
121 | #define XFS_RANDOM_BMAPIFORMAT XFS_RANDOM_DEFAULT | 122 | #define XFS_RANDOM_BMAPIFORMAT XFS_RANDOM_DEFAULT |
122 | #define XFS_RANDOM_FREE_EXTENT 1 | 123 | #define XFS_RANDOM_FREE_EXTENT 1 |
123 | #define XFS_RANDOM_RMAP_FINISH_ONE 1 | 124 | #define XFS_RANDOM_RMAP_FINISH_ONE 1 |
125 | #define XFS_RANDOM_REFCOUNT_CONTINUE_UPDATE 1 | ||
124 | 126 | ||
125 | #ifdef DEBUG | 127 | #ifdef DEBUG |
126 | extern int xfs_error_test_active; | 128 | extern int xfs_error_test_active; |