xfs_bmap.c (6d11fb454b161a4565c57be6f1c5527235741003) | xfs_bmap.c (2c845f5a5f238f42376b6551a7f7716952c8f509) |
---|---|
1/* 2 * Copyright (c) 2000-2006 Silicon Graphics, Inc. 3 * All Rights Reserved. 4 * 5 * This program is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU General Public License as 7 * published by the Free Software Foundation. 8 * --- 5392 unchanged lines hidden (view full) --- 5401 error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR); 5402 } 5403 return error; 5404} 5405 5406/* 5407 * Shift extent records to the left to cover a hole. 5408 * | 1/* 2 * Copyright (c) 2000-2006 Silicon Graphics, Inc. 3 * All Rights Reserved. 4 * 5 * This program is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU General Public License as 7 * published by the Free Software Foundation. 8 * --- 5392 unchanged lines hidden (view full) --- 5401 error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR); 5402 } 5403 return error; 5404} 5405 5406/* 5407 * Shift extent records to the left to cover a hole. 5408 * |
5409 * The maximum number of extents to be shifted in a single operation 5410 * is @num_exts, and @current_ext keeps track of the current extent 5411 * index we have shifted. @offset_shift_fsb is the length by which each 5412 * extent is shifted. If there is no hole to shift the extents 5413 * into, this will be considered invalid operation and we abort immediately. | 5409 * The maximum number of extents to be shifted in a single operation is 5410 * @num_exts. @start_fsb specifies the file offset to start the shift and the 5411 * file offset where we've left off is returned in @next_fsb. @offset_shift_fsb 5412 * is the length by which each extent is shifted. If there is no hole to shift 5413 * the extents into, this will be considered invalid operation and we abort 5414 * immediately. |
5414 */ 5415int 5416xfs_bmap_shift_extents( 5417 struct xfs_trans *tp, 5418 struct xfs_inode *ip, | 5415 */ 5416int 5417xfs_bmap_shift_extents( 5418 struct xfs_trans *tp, 5419 struct xfs_inode *ip, |
5419 int *done, | |
5420 xfs_fileoff_t start_fsb, 5421 xfs_fileoff_t offset_shift_fsb, | 5420 xfs_fileoff_t start_fsb, 5421 xfs_fileoff_t offset_shift_fsb, |
5422 xfs_extnum_t *current_ext, | 5422 int *done, 5423 xfs_fileoff_t *next_fsb, |
5423 xfs_fsblock_t *firstblock, 5424 struct xfs_bmap_free *flist, 5425 int num_exts) 5426{ 5427 struct xfs_btree_cur *cur = NULL; 5428 struct xfs_bmbt_rec_host *gotp; 5429 struct xfs_bmbt_irec got; 5430 struct xfs_bmbt_irec left; 5431 struct xfs_mount *mp = ip->i_mount; 5432 struct xfs_ifork *ifp; 5433 xfs_extnum_t nexts = 0; | 5424 xfs_fsblock_t *firstblock, 5425 struct xfs_bmap_free *flist, 5426 int num_exts) 5427{ 5428 struct xfs_btree_cur *cur = NULL; 5429 struct xfs_bmbt_rec_host *gotp; 5430 struct xfs_bmbt_irec got; 5431 struct xfs_bmbt_irec left; 5432 struct xfs_mount *mp = ip->i_mount; 5433 struct xfs_ifork *ifp; 5434 xfs_extnum_t nexts = 0; |
5435 xfs_extnum_t current_ext; |
|
5434 xfs_fileoff_t startoff; 5435 int error = 0; 5436 int i; 5437 int whichfork = XFS_DATA_FORK; 5438 int logflags = 0; 5439 xfs_filblks_t blockcount = 0; 5440 int total_extents; 5441 --- 4 unchanged lines hidden (view full) --- 5446 XFS_ERROR_REPORT("xfs_bmap_shift_extents", 5447 XFS_ERRLEVEL_LOW, mp); 5448 return -EFSCORRUPTED; 5449 } 5450 5451 if (XFS_FORCED_SHUTDOWN(mp)) 5452 return -EIO; 5453 | 5436 xfs_fileoff_t startoff; 5437 int error = 0; 5438 int i; 5439 int whichfork = XFS_DATA_FORK; 5440 int logflags = 0; 5441 xfs_filblks_t blockcount = 0; 5442 int total_extents; 5443 --- 4 unchanged lines hidden (view full) --- 5448 XFS_ERROR_REPORT("xfs_bmap_shift_extents", 5449 XFS_ERRLEVEL_LOW, mp); 5450 return -EFSCORRUPTED; 5451 } 5452 5453 if (XFS_FORCED_SHUTDOWN(mp)) 5454 return -EIO; 5455 |
5454 ASSERT(current_ext != NULL); | 5456 ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL)); 5457 ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); |
5455 5456 ifp = XFS_IFORK_PTR(ip, whichfork); 5457 if (!(ifp->if_flags & XFS_IFEXTENTS)) { 5458 /* Read in all the extents */ 5459 error = xfs_iread_extents(tp, ip, whichfork); 5460 if (error) 5461 return error; 5462 } 5463 5464 /* | 5458 5459 ifp = XFS_IFORK_PTR(ip, whichfork); 5460 if (!(ifp->if_flags & XFS_IFEXTENTS)) { 5461 /* Read in all the extents */ 5462 error = xfs_iread_extents(tp, ip, whichfork); 5463 if (error) 5464 return error; 5465 } 5466 5467 /* |
5465 * If *current_ext is 0, we would need to lookup the extent 5466 * from where we would start shifting and store it in gotp. | 5468 * Look up the extent index for the fsb where we start shifting. We can 5469 * henceforth iterate with current_ext as extent list changes are locked 5470 * out via ilock. 5471 * 5472 * gotp can be null in 2 cases: 1) if there are no extents or 2) 5473 * start_fsb lies in a hole beyond which there are no extents. Either 5474 * way, we are done. |
5467 */ | 5475 */ |
5468 if (!*current_ext) { 5469 gotp = xfs_iext_bno_to_ext(ifp, start_fsb, current_ext); 5470 /* 5471 * gotp can be null in 2 cases: 1) if there are no extents 5472 * or 2) start_fsb lies in a hole beyond which there are 5473 * no extents. Either way, we are done. 5474 */ 5475 if (!gotp) { 5476 *done = 1; 5477 return 0; 5478 } | 5476 gotp = xfs_iext_bno_to_ext(ifp, start_fsb, ¤t_ext); 5477 if (!gotp) { 5478 *done = 1; 5479 return 0; |
5479 } 5480 5481 if (ifp->if_flags & XFS_IFBROOT) { 5482 cur = xfs_bmbt_init_cursor(mp, tp, ip, whichfork); 5483 cur->bc_private.b.firstblock = *firstblock; 5484 cur->bc_private.b.flist = flist; 5485 cur->bc_private.b.flags = 0; 5486 } 5487 5488 /* 5489 * There may be delalloc extents in the data fork before the range we | 5480 } 5481 5482 if (ifp->if_flags & XFS_IFBROOT) { 5483 cur = xfs_bmbt_init_cursor(mp, tp, ip, whichfork); 5484 cur->bc_private.b.firstblock = *firstblock; 5485 cur->bc_private.b.flist = flist; 5486 cur->bc_private.b.flags = 0; 5487 } 5488 5489 /* 5490 * There may be delalloc extents in the data fork before the range we |
5490 * are collapsing out, so we cannot 5491 * use the count of real extents here. Instead we have to calculate it 5492 * from the incore fork. | 5491 * are collapsing out, so we cannot use the count of real extents here. 5492 * Instead we have to calculate it from the incore fork. |
5493 */ 5494 total_extents = ifp->if_bytes / sizeof(xfs_bmbt_rec_t); | 5493 */ 5494 total_extents = ifp->if_bytes / sizeof(xfs_bmbt_rec_t); |
5495 while (nexts++ < num_exts && *current_ext < total_extents) { | 5495 while (nexts++ < num_exts && current_ext < total_extents) { |
5496 | 5496 |
5497 gotp = xfs_iext_get_ext(ifp, *current_ext); | 5497 gotp = xfs_iext_get_ext(ifp, current_ext); |
5498 xfs_bmbt_get_all(gotp, &got); 5499 startoff = got.br_startoff - offset_shift_fsb; 5500 5501 /* | 5498 xfs_bmbt_get_all(gotp, &got); 5499 startoff = got.br_startoff - offset_shift_fsb; 5500 5501 /* |
5502 * Before shifting extent into hole, make sure that the hole 5503 * is large enough to accomodate the shift. | 5502 * Before shifting extent into hole, make sure that the hole is 5503 * large enough to accommodate the shift. |
5504 */ | 5504 */ |
5505 if (*current_ext) { 5506 xfs_bmbt_get_all(xfs_iext_get_ext(ifp, 5507 *current_ext - 1), &left); 5508 | 5505 if (current_ext > 0) { 5506 xfs_bmbt_get_all(xfs_iext_get_ext(ifp, current_ext - 1), 5507 &left); |
5509 if (startoff < left.br_startoff + left.br_blockcount) 5510 error = -EINVAL; 5511 } else if (offset_shift_fsb > got.br_startoff) { 5512 /* | 5508 if (startoff < left.br_startoff + left.br_blockcount) 5509 error = -EINVAL; 5510 } else if (offset_shift_fsb > got.br_startoff) { 5511 /* |
5513 * When first extent is shifted, offset_shift_fsb 5514 * should be less than the stating offset of 5515 * the first extent. | 5512 * When first extent is shifted, offset_shift_fsb should 5513 * be less than the stating offset of the first extent. |
5516 */ 5517 error = -EINVAL; 5518 } | 5514 */ 5515 error = -EINVAL; 5516 } |
5519 | |
5520 if (error) 5521 goto del_cursor; 5522 5523 if (cur) { 5524 error = xfs_bmbt_lookup_eq(cur, got.br_startoff, 5525 got.br_startblock, 5526 got.br_blockcount, 5527 &i); 5528 if (error) 5529 goto del_cursor; 5530 XFS_WANT_CORRUPTED_GOTO(i == 1, del_cursor); 5531 } 5532 5533 /* Check if we can merge 2 adjacent extents */ | 5517 if (error) 5518 goto del_cursor; 5519 5520 if (cur) { 5521 error = xfs_bmbt_lookup_eq(cur, got.br_startoff, 5522 got.br_startblock, 5523 got.br_blockcount, 5524 &i); 5525 if (error) 5526 goto del_cursor; 5527 XFS_WANT_CORRUPTED_GOTO(i == 1, del_cursor); 5528 } 5529 5530 /* Check if we can merge 2 adjacent extents */ |
5534 if (*current_ext && | 5531 if (current_ext && |
5535 left.br_startoff + left.br_blockcount == startoff && 5536 left.br_startblock + left.br_blockcount == 5537 got.br_startblock && 5538 left.br_state == got.br_state && 5539 left.br_blockcount + got.br_blockcount <= MAXEXTLEN) { 5540 blockcount = left.br_blockcount + 5541 got.br_blockcount; | 5532 left.br_startoff + left.br_blockcount == startoff && 5533 left.br_startblock + left.br_blockcount == 5534 got.br_startblock && 5535 left.br_state == got.br_state && 5536 left.br_blockcount + got.br_blockcount <= MAXEXTLEN) { 5537 blockcount = left.br_blockcount + 5538 got.br_blockcount; |
5542 xfs_iext_remove(ip, *current_ext, 1, 0); | 5539 xfs_iext_remove(ip, current_ext, 1, 0); |
5543 logflags |= XFS_ILOG_CORE; 5544 if (cur) { 5545 error = xfs_btree_delete(cur, &i); 5546 if (error) 5547 goto del_cursor; 5548 XFS_WANT_CORRUPTED_GOTO(i == 1, del_cursor); 5549 } else { 5550 logflags |= XFS_ILOG_DEXT; 5551 } 5552 XFS_IFORK_NEXT_SET(ip, whichfork, 5553 XFS_IFORK_NEXTENTS(ip, whichfork) - 1); | 5540 logflags |= XFS_ILOG_CORE; 5541 if (cur) { 5542 error = xfs_btree_delete(cur, &i); 5543 if (error) 5544 goto del_cursor; 5545 XFS_WANT_CORRUPTED_GOTO(i == 1, del_cursor); 5546 } else { 5547 logflags |= XFS_ILOG_DEXT; 5548 } 5549 XFS_IFORK_NEXT_SET(ip, whichfork, 5550 XFS_IFORK_NEXTENTS(ip, whichfork) - 1); |
5554 gotp = xfs_iext_get_ext(ifp, --*current_ext); | 5551 gotp = xfs_iext_get_ext(ifp, --current_ext); |
5555 xfs_bmbt_get_all(gotp, &got); 5556 5557 /* Make cursor point to the extent we will update */ 5558 if (cur) { 5559 error = xfs_bmbt_lookup_eq(cur, got.br_startoff, 5560 got.br_startblock, 5561 got.br_blockcount, 5562 &i); --- 17 unchanged lines hidden (view full) --- 5580 got.br_blockcount, 5581 got.br_state); 5582 if (error) 5583 goto del_cursor; 5584 } else { 5585 logflags |= XFS_ILOG_DEXT; 5586 } 5587 | 5552 xfs_bmbt_get_all(gotp, &got); 5553 5554 /* Make cursor point to the extent we will update */ 5555 if (cur) { 5556 error = xfs_bmbt_lookup_eq(cur, got.br_startoff, 5557 got.br_startblock, 5558 got.br_blockcount, 5559 &i); --- 17 unchanged lines hidden (view full) --- 5577 got.br_blockcount, 5578 got.br_state); 5579 if (error) 5580 goto del_cursor; 5581 } else { 5582 logflags |= XFS_ILOG_DEXT; 5583 } 5584 |
5588 (*current_ext)++; | 5585 current_ext++; |
5589 total_extents = ifp->if_bytes / sizeof(xfs_bmbt_rec_t); 5590 } 5591 5592 /* Check if we are done */ | 5586 total_extents = ifp->if_bytes / sizeof(xfs_bmbt_rec_t); 5587 } 5588 5589 /* Check if we are done */ |
5593 if (*current_ext == total_extents) | 5590 if (current_ext == total_extents) |
5594 *done = 1; | 5591 *done = 1; |
5592 else if (next_fsb) { 5593 gotp = xfs_iext_get_ext(ifp, current_ext); 5594 xfs_bmbt_get_all(gotp, &got); 5595 *next_fsb = got.br_startoff; 5596 } |
|
5595 5596del_cursor: 5597 if (cur) 5598 xfs_btree_del_cursor(cur, 5599 error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR); 5600 5601 if (logflags) 5602 xfs_trans_log_inode(tp, ip, logflags); | 5597 5598del_cursor: 5599 if (cur) 5600 xfs_btree_del_cursor(cur, 5601 error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR); 5602 5603 if (logflags) 5604 xfs_trans_log_inode(tp, ip, logflags); |
5605 |
|
5603 return error; 5604} | 5606 return error; 5607} |