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, &current_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}