aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_inode.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/xfs_inode.c')
-rw-r--r--fs/xfs/xfs_inode.c470
1 files changed, 351 insertions, 119 deletions
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 1d7f5a7e063e..6459395a0e40 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -76,16 +76,18 @@ STATIC int xfs_iformat_btree(xfs_inode_t *, xfs_dinode_t *, int);
76 */ 76 */
77STATIC void 77STATIC void
78xfs_validate_extents( 78xfs_validate_extents(
79 xfs_bmbt_rec_t *ep, 79 xfs_ifork_t *ifp,
80 int nrecs, 80 int nrecs,
81 int disk, 81 int disk,
82 xfs_exntfmt_t fmt) 82 xfs_exntfmt_t fmt)
83{ 83{
84 xfs_bmbt_rec_t *ep;
84 xfs_bmbt_irec_t irec; 85 xfs_bmbt_irec_t irec;
85 xfs_bmbt_rec_t rec; 86 xfs_bmbt_rec_t rec;
86 int i; 87 int i;
87 88
88 for (i = 0; i < nrecs; i++) { 89 for (i = 0; i < nrecs; i++) {
90 ep = xfs_iext_get_ext(ifp, i);
89 rec.l0 = get_unaligned((__uint64_t*)&ep->l0); 91 rec.l0 = get_unaligned((__uint64_t*)&ep->l0);
90 rec.l1 = get_unaligned((__uint64_t*)&ep->l1); 92 rec.l1 = get_unaligned((__uint64_t*)&ep->l1);
91 if (disk) 93 if (disk)
@@ -94,11 +96,10 @@ xfs_validate_extents(
94 xfs_bmbt_get_all(&rec, &irec); 96 xfs_bmbt_get_all(&rec, &irec);
95 if (fmt == XFS_EXTFMT_NOSTATE) 97 if (fmt == XFS_EXTFMT_NOSTATE)
96 ASSERT(irec.br_state == XFS_EXT_NORM); 98 ASSERT(irec.br_state == XFS_EXT_NORM);
97 ep++;
98 } 99 }
99} 100}
100#else /* DEBUG */ 101#else /* DEBUG */
101#define xfs_validate_extents(ep, nrecs, disk, fmt) 102#define xfs_validate_extents(ifp, nrecs, disk, fmt)
102#endif /* DEBUG */ 103#endif /* DEBUG */
103 104
104/* 105/*
@@ -597,7 +598,6 @@ xfs_iformat_extents(
597 xfs_bmbt_rec_t *ep, *dp; 598 xfs_bmbt_rec_t *ep, *dp;
598 xfs_ifork_t *ifp; 599 xfs_ifork_t *ifp;
599 int nex; 600 int nex;
600 int real_size;
601 int size; 601 int size;
602 int i; 602 int i;
603 603
@@ -619,23 +619,20 @@ xfs_iformat_extents(
619 return XFS_ERROR(EFSCORRUPTED); 619 return XFS_ERROR(EFSCORRUPTED);
620 } 620 }
621 621
622 real_size = 0; 622 ifp->if_real_bytes = 0;
623 if (nex == 0) 623 if (nex == 0)
624 ifp->if_u1.if_extents = NULL; 624 ifp->if_u1.if_extents = NULL;
625 else if (nex <= XFS_INLINE_EXTS) 625 else if (nex <= XFS_INLINE_EXTS)
626 ifp->if_u1.if_extents = ifp->if_u2.if_inline_ext; 626 ifp->if_u1.if_extents = ifp->if_u2.if_inline_ext;
627 else { 627 else
628 ifp->if_u1.if_extents = kmem_alloc(size, KM_SLEEP); 628 xfs_iext_add(ifp, 0, nex);
629 ASSERT(ifp->if_u1.if_extents != NULL); 629
630 real_size = size;
631 }
632 ifp->if_bytes = size; 630 ifp->if_bytes = size;
633 ifp->if_real_bytes = real_size;
634 if (size) { 631 if (size) {
635 dp = (xfs_bmbt_rec_t *) XFS_DFORK_PTR(dip, whichfork); 632 dp = (xfs_bmbt_rec_t *) XFS_DFORK_PTR(dip, whichfork);
636 xfs_validate_extents(dp, nex, 1, XFS_EXTFMT_INODE(ip)); 633 xfs_validate_extents(ifp, nex, 1, XFS_EXTFMT_INODE(ip));
637 ep = ifp->if_u1.if_extents; 634 for (i = 0; i < nex; i++, dp++) {
638 for (i = 0; i < nex; i++, ep++, dp++) { 635 ep = xfs_iext_get_ext(ifp, i);
639 ep->l0 = INT_GET(get_unaligned((__uint64_t*)&dp->l0), 636 ep->l0 = INT_GET(get_unaligned((__uint64_t*)&dp->l0),
640 ARCH_CONVERT); 637 ARCH_CONVERT);
641 ep->l1 = INT_GET(get_unaligned((__uint64_t*)&dp->l1), 638 ep->l1 = INT_GET(get_unaligned((__uint64_t*)&dp->l1),
@@ -646,7 +643,7 @@ xfs_iformat_extents(
646 if (whichfork != XFS_DATA_FORK || 643 if (whichfork != XFS_DATA_FORK ||
647 XFS_EXTFMT_INODE(ip) == XFS_EXTFMT_NOSTATE) 644 XFS_EXTFMT_INODE(ip) == XFS_EXTFMT_NOSTATE)
648 if (unlikely(xfs_check_nostate_extents( 645 if (unlikely(xfs_check_nostate_extents(
649 ifp->if_u1.if_extents, nex))) { 646 ifp, 0, nex))) {
650 XFS_ERROR_REPORT("xfs_iformat_extents(2)", 647 XFS_ERROR_REPORT("xfs_iformat_extents(2)",
651 XFS_ERRLEVEL_LOW, 648 XFS_ERRLEVEL_LOW,
652 ip->i_mount); 649 ip->i_mount);
@@ -1015,6 +1012,7 @@ xfs_iread_extents(
1015{ 1012{
1016 int error; 1013 int error;
1017 xfs_ifork_t *ifp; 1014 xfs_ifork_t *ifp;
1015 xfs_extnum_t nextents;
1018 size_t size; 1016 size_t size;
1019 1017
1020 if (unlikely(XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE)) { 1018 if (unlikely(XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE)) {
@@ -1022,26 +1020,24 @@ xfs_iread_extents(
1022 ip->i_mount); 1020 ip->i_mount);
1023 return XFS_ERROR(EFSCORRUPTED); 1021 return XFS_ERROR(EFSCORRUPTED);
1024 } 1022 }
1025 size = XFS_IFORK_NEXTENTS(ip, whichfork) * (uint)sizeof(xfs_bmbt_rec_t); 1023 nextents = XFS_IFORK_NEXTENTS(ip, whichfork);
1024 size = nextents * sizeof(xfs_bmbt_rec_t);
1026 ifp = XFS_IFORK_PTR(ip, whichfork); 1025 ifp = XFS_IFORK_PTR(ip, whichfork);
1026
1027 /* 1027 /*
1028 * We know that the size is valid (it's checked in iformat_btree) 1028 * We know that the size is valid (it's checked in iformat_btree)
1029 */ 1029 */
1030 ifp->if_u1.if_extents = kmem_alloc(size, KM_SLEEP);
1031 ASSERT(ifp->if_u1.if_extents != NULL);
1032 ifp->if_lastex = NULLEXTNUM; 1030 ifp->if_lastex = NULLEXTNUM;
1033 ifp->if_bytes = ifp->if_real_bytes = (int)size; 1031 ifp->if_bytes = ifp->if_real_bytes = 0;
1034 ifp->if_flags |= XFS_IFEXTENTS; 1032 ifp->if_flags |= XFS_IFEXTENTS;
1033 xfs_iext_add(ifp, 0, nextents);
1035 error = xfs_bmap_read_extents(tp, ip, whichfork); 1034 error = xfs_bmap_read_extents(tp, ip, whichfork);
1036 if (error) { 1035 if (error) {
1037 kmem_free(ifp->if_u1.if_extents, size); 1036 xfs_iext_destroy(ifp);
1038 ifp->if_u1.if_extents = NULL;
1039 ifp->if_bytes = ifp->if_real_bytes = 0;
1040 ifp->if_flags &= ~XFS_IFEXTENTS; 1037 ifp->if_flags &= ~XFS_IFEXTENTS;
1041 return error; 1038 return error;
1042 } 1039 }
1043 xfs_validate_extents((xfs_bmbt_rec_t *)ifp->if_u1.if_extents, 1040 xfs_validate_extents(ifp, nextents, 0, XFS_EXTFMT_INODE(ip));
1044 XFS_IFORK_NEXTENTS(ip, whichfork), 0, XFS_EXTFMT_INODE(ip));
1045 return 0; 1041 return 0;
1046} 1042}
1047 1043
@@ -2476,92 +2472,6 @@ xfs_iroot_realloc(
2476 2472
2477 2473
2478/* 2474/*
2479 * This is called when the amount of space needed for if_extents
2480 * is increased or decreased. The change in size is indicated by
2481 * the number of extents that need to be added or deleted in the
2482 * ext_diff parameter.
2483 *
2484 * If the amount of space needed has decreased below the size of the
2485 * inline buffer, then switch to using the inline buffer. Otherwise,
2486 * use kmem_realloc() or kmem_alloc() to adjust the size of the buffer
2487 * to what is needed.
2488 *
2489 * ip -- the inode whose if_extents area is changing
2490 * ext_diff -- the change in the number of extents, positive or negative,
2491 * requested for the if_extents array.
2492 */
2493void
2494xfs_iext_realloc(
2495 xfs_inode_t *ip,
2496 int ext_diff,
2497 int whichfork)
2498{
2499 int byte_diff;
2500 xfs_ifork_t *ifp;
2501 int new_size;
2502 uint rnew_size;
2503
2504 if (ext_diff == 0) {
2505 return;
2506 }
2507
2508 ifp = XFS_IFORK_PTR(ip, whichfork);
2509 byte_diff = ext_diff * (uint)sizeof(xfs_bmbt_rec_t);
2510 new_size = (int)ifp->if_bytes + byte_diff;
2511 ASSERT(new_size >= 0);
2512
2513 if (new_size == 0) {
2514 if (ifp->if_u1.if_extents != ifp->if_u2.if_inline_ext) {
2515 ASSERT(ifp->if_real_bytes != 0);
2516 kmem_free(ifp->if_u1.if_extents, ifp->if_real_bytes);
2517 }
2518 ifp->if_u1.if_extents = NULL;
2519 rnew_size = 0;
2520 } else if (new_size <= sizeof(ifp->if_u2.if_inline_ext)) {
2521 /*
2522 * If the valid extents can fit in if_inline_ext,
2523 * copy them from the malloc'd vector and free it.
2524 */
2525 if (ifp->if_u1.if_extents != ifp->if_u2.if_inline_ext) {
2526 /*
2527 * For now, empty files are format EXTENTS,
2528 * so the if_extents pointer is null.
2529 */
2530 if (ifp->if_u1.if_extents) {
2531 memcpy(ifp->if_u2.if_inline_ext,
2532 ifp->if_u1.if_extents, new_size);
2533 kmem_free(ifp->if_u1.if_extents,
2534 ifp->if_real_bytes);
2535 }
2536 ifp->if_u1.if_extents = ifp->if_u2.if_inline_ext;
2537 }
2538 rnew_size = 0;
2539 } else {
2540 rnew_size = new_size;
2541 if ((rnew_size & (rnew_size - 1)) != 0)
2542 rnew_size = xfs_iroundup(rnew_size);
2543 /*
2544 * Stuck with malloc/realloc.
2545 */
2546 if (ifp->if_u1.if_extents == ifp->if_u2.if_inline_ext) {
2547 ifp->if_u1.if_extents = (xfs_bmbt_rec_t *)
2548 kmem_alloc(rnew_size, KM_SLEEP);
2549 memcpy(ifp->if_u1.if_extents, ifp->if_u2.if_inline_ext,
2550 sizeof(ifp->if_u2.if_inline_ext));
2551 } else if (rnew_size != ifp->if_real_bytes) {
2552 ifp->if_u1.if_extents = (xfs_bmbt_rec_t *)
2553 kmem_realloc(ifp->if_u1.if_extents,
2554 rnew_size,
2555 ifp->if_real_bytes,
2556 KM_NOFS);
2557 }
2558 }
2559 ifp->if_real_bytes = rnew_size;
2560 ifp->if_bytes = new_size;
2561}
2562
2563
2564/*
2565 * This is called when the amount of space needed for if_data 2475 * This is called when the amount of space needed for if_data
2566 * is increased or decreased. The change in size is indicated by 2476 * is increased or decreased. The change in size is indicated by
2567 * the number of bytes that need to be added or deleted in the 2477 * the number of bytes that need to be added or deleted in the
@@ -2723,9 +2633,7 @@ xfs_idestroy_fork(
2723 (ifp->if_u1.if_extents != NULL) && 2633 (ifp->if_u1.if_extents != NULL) &&
2724 (ifp->if_u1.if_extents != ifp->if_u2.if_inline_ext)) { 2634 (ifp->if_u1.if_extents != ifp->if_u2.if_inline_ext)) {
2725 ASSERT(ifp->if_real_bytes != 0); 2635 ASSERT(ifp->if_real_bytes != 0);
2726 kmem_free(ifp->if_u1.if_extents, ifp->if_real_bytes); 2636 xfs_iext_destroy(ifp);
2727 ifp->if_u1.if_extents = NULL;
2728 ifp->if_real_bytes = 0;
2729 } 2637 }
2730 ASSERT(ifp->if_u1.if_extents == NULL || 2638 ASSERT(ifp->if_u1.if_extents == NULL ||
2731 ifp->if_u1.if_extents == ifp->if_u2.if_inline_ext); 2639 ifp->if_u1.if_extents == ifp->if_u2.if_inline_ext);
@@ -2902,16 +2810,15 @@ xfs_iextents_copy(
2902 * the delayed ones. There must be at least one 2810 * the delayed ones. There must be at least one
2903 * non-delayed extent. 2811 * non-delayed extent.
2904 */ 2812 */
2905 ep = ifp->if_u1.if_extents;
2906 dest_ep = buffer; 2813 dest_ep = buffer;
2907 copied = 0; 2814 copied = 0;
2908 for (i = 0; i < nrecs; i++) { 2815 for (i = 0; i < nrecs; i++) {
2816 ep = xfs_iext_get_ext(ifp, i);
2909 start_block = xfs_bmbt_get_startblock(ep); 2817 start_block = xfs_bmbt_get_startblock(ep);
2910 if (ISNULLSTARTBLOCK(start_block)) { 2818 if (ISNULLSTARTBLOCK(start_block)) {
2911 /* 2819 /*
2912 * It's a delayed allocation extent, so skip it. 2820 * It's a delayed allocation extent, so skip it.
2913 */ 2821 */
2914 ep++;
2915 continue; 2822 continue;
2916 } 2823 }
2917 2824
@@ -2921,11 +2828,10 @@ xfs_iextents_copy(
2921 put_unaligned(INT_GET(ep->l1, ARCH_CONVERT), 2828 put_unaligned(INT_GET(ep->l1, ARCH_CONVERT),
2922 (__uint64_t*)&dest_ep->l1); 2829 (__uint64_t*)&dest_ep->l1);
2923 dest_ep++; 2830 dest_ep++;
2924 ep++;
2925 copied++; 2831 copied++;
2926 } 2832 }
2927 ASSERT(copied != 0); 2833 ASSERT(copied != 0);
2928 xfs_validate_extents(buffer, copied, 1, XFS_EXTFMT_INODE(ip)); 2834 xfs_validate_extents(ifp, copied, 1, XFS_EXTFMT_INODE(ip));
2929 2835
2930 return (copied * (uint)sizeof(xfs_bmbt_rec_t)); 2836 return (copied * (uint)sizeof(xfs_bmbt_rec_t));
2931} 2837}
@@ -2995,8 +2901,10 @@ xfs_iflush_fork(
2995 case XFS_DINODE_FMT_EXTENTS: 2901 case XFS_DINODE_FMT_EXTENTS:
2996 ASSERT((ifp->if_flags & XFS_IFEXTENTS) || 2902 ASSERT((ifp->if_flags & XFS_IFEXTENTS) ||
2997 !(iip->ili_format.ilf_fields & extflag[whichfork])); 2903 !(iip->ili_format.ilf_fields & extflag[whichfork]));
2998 ASSERT((ifp->if_u1.if_extents != NULL) || (ifp->if_bytes == 0)); 2904 ASSERT((xfs_iext_get_ext(ifp, 0) != NULL) ||
2999 ASSERT((ifp->if_u1.if_extents == NULL) || (ifp->if_bytes > 0)); 2905 (ifp->if_bytes == 0));
2906 ASSERT((xfs_iext_get_ext(ifp, 0) == NULL) ||
2907 (ifp->if_bytes > 0));
3000 if ((iip->ili_format.ilf_fields & extflag[whichfork]) && 2908 if ((iip->ili_format.ilf_fields & extflag[whichfork]) &&
3001 (ifp->if_bytes > 0)) { 2909 (ifp->if_bytes > 0)) {
3002 ASSERT(XFS_IFORK_NEXTENTS(ip, whichfork) > 0); 2910 ASSERT(XFS_IFORK_NEXTENTS(ip, whichfork) > 0);
@@ -3704,3 +3612,327 @@ xfs_ilock_trace(xfs_inode_t *ip, int lock, unsigned int lockflags, inst_t *ra)
3704 NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); 3612 NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
3705} 3613}
3706#endif 3614#endif
3615
3616/*
3617 * Return a pointer to the extent record at file index idx.
3618 */
3619xfs_bmbt_rec_t *
3620xfs_iext_get_ext(
3621 xfs_ifork_t *ifp, /* inode fork pointer */
3622 xfs_extnum_t idx) /* index of target extent */
3623{
3624 ASSERT(idx >= 0);
3625 if (ifp->if_bytes) {
3626 return &ifp->if_u1.if_extents[idx];
3627 } else {
3628 return NULL;
3629 }
3630}
3631
3632/*
3633 * Insert new item(s) into the extent records for incore inode
3634 * fork 'ifp'. 'count' new items are inserted at index 'idx'.
3635 */
3636void
3637xfs_iext_insert(
3638 xfs_ifork_t *ifp, /* inode fork pointer */
3639 xfs_extnum_t idx, /* starting index of new items */
3640 xfs_extnum_t count, /* number of inserted items */
3641 xfs_bmbt_irec_t *new) /* items to insert */
3642{
3643 xfs_bmbt_rec_t *ep; /* extent record pointer */
3644 xfs_extnum_t i; /* extent record index */
3645
3646 ASSERT(ifp->if_flags & XFS_IFEXTENTS);
3647 xfs_iext_add(ifp, idx, count);
3648 for (i = idx; i < idx + count; i++, new++) {
3649 ep = xfs_iext_get_ext(ifp, i);
3650 xfs_bmbt_set_all(ep, new);
3651 }
3652}
3653
3654/*
3655 * This is called when the amount of space required for incore file
3656 * extents needs to be increased. The ext_diff parameter stores the
3657 * number of new extents being added and the idx parameter contains
3658 * the extent index where the new extents will be added. If the new
3659 * extents are being appended, then we just need to (re)allocate and
3660 * initialize the space. Otherwise, if the new extents are being
3661 * inserted into the middle of the existing entries, a bit more work
3662 * is required to make room for the new extents to be inserted. The
3663 * caller is responsible for filling in the new extent entries upon
3664 * return.
3665 */
3666void
3667xfs_iext_add(
3668 xfs_ifork_t *ifp, /* inode fork pointer */
3669 xfs_extnum_t idx, /* index to begin adding exts */
3670 int ext_diff) /* nubmer of extents to add */
3671{
3672 int byte_diff; /* new bytes being added */
3673 int new_size; /* size of extents after adding */
3674 xfs_extnum_t nextents; /* number of extents in file */
3675
3676 nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
3677 ASSERT((idx >= 0) && (idx <= nextents));
3678 byte_diff = ext_diff * sizeof(xfs_bmbt_rec_t);
3679 new_size = ifp->if_bytes + byte_diff;
3680 /*
3681 * If the new number of extents (nextents + ext_diff)
3682 * fits inside the inode, then continue to use the inline
3683 * extent buffer.
3684 */
3685 if (nextents + ext_diff <= XFS_INLINE_EXTS) {
3686 if (idx < nextents) {
3687 memmove(&ifp->if_u2.if_inline_ext[idx + ext_diff],
3688 &ifp->if_u2.if_inline_ext[idx],
3689 (nextents - idx) * sizeof(xfs_bmbt_rec_t));
3690 memset(&ifp->if_u2.if_inline_ext[idx], 0, byte_diff);
3691 }
3692 ifp->if_u1.if_extents = ifp->if_u2.if_inline_ext;
3693 ifp->if_real_bytes = 0;
3694 }
3695 /*
3696 * Otherwise use a linear (direct) extent list.
3697 * If the extents are currently inside the inode,
3698 * xfs_iext_realloc_direct will switch us from
3699 * inline to direct extent allocation mode.
3700 */
3701 else {
3702 xfs_iext_realloc_direct(ifp, new_size);
3703 if (idx < nextents) {
3704 memmove(&ifp->if_u1.if_extents[idx + ext_diff],
3705 &ifp->if_u1.if_extents[idx],
3706 (nextents - idx) * sizeof(xfs_bmbt_rec_t));
3707 memset(&ifp->if_u1.if_extents[idx], 0, byte_diff);
3708 }
3709 }
3710 ifp->if_bytes = new_size;
3711}
3712
3713/*
3714 * This is called when the amount of space required for incore file
3715 * extents needs to be decreased. The ext_diff parameter stores the
3716 * number of extents to be removed and the idx parameter contains
3717 * the extent index where the extents will be removed from.
3718 */
3719void
3720xfs_iext_remove(
3721 xfs_ifork_t *ifp, /* inode fork pointer */
3722 xfs_extnum_t idx, /* index to begin removing exts */
3723 int ext_diff) /* number of extents to remove */
3724{
3725 xfs_extnum_t nextents; /* number of extents in file */
3726 int new_size; /* size of extents after removal */
3727
3728 ASSERT(ext_diff > 0);
3729 nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
3730 new_size = (nextents - ext_diff) * sizeof(xfs_bmbt_rec_t);
3731
3732 if (new_size == 0) {
3733 xfs_iext_destroy(ifp);
3734 } else if (ifp->if_real_bytes) {
3735 xfs_iext_remove_direct(ifp, idx, ext_diff);
3736 } else {
3737 xfs_iext_remove_inline(ifp, idx, ext_diff);
3738 }
3739 ifp->if_bytes = new_size;
3740}
3741
3742/*
3743 * This removes ext_diff extents from the inline buffer, beginning
3744 * at extent index idx.
3745 */
3746void
3747xfs_iext_remove_inline(
3748 xfs_ifork_t *ifp, /* inode fork pointer */
3749 xfs_extnum_t idx, /* index to begin removing exts */
3750 int ext_diff) /* number of extents to remove */
3751{
3752 int nextents; /* number of extents in file */
3753
3754 ASSERT(idx < XFS_INLINE_EXTS);
3755 nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
3756 ASSERT(((nextents - ext_diff) > 0) &&
3757 (nextents - ext_diff) < XFS_INLINE_EXTS);
3758
3759 if (idx + ext_diff < nextents) {
3760 memmove(&ifp->if_u2.if_inline_ext[idx],
3761 &ifp->if_u2.if_inline_ext[idx + ext_diff],
3762 (nextents - (idx + ext_diff)) *
3763 sizeof(xfs_bmbt_rec_t));
3764 memset(&ifp->if_u2.if_inline_ext[nextents - ext_diff],
3765 0, ext_diff * sizeof(xfs_bmbt_rec_t));
3766 } else {
3767 memset(&ifp->if_u2.if_inline_ext[idx], 0,
3768 ext_diff * sizeof(xfs_bmbt_rec_t));
3769 }
3770}
3771
3772/*
3773 * This removes ext_diff extents from a linear (direct) extent list,
3774 * beginning at extent index idx. If the extents are being removed
3775 * from the end of the list (ie. truncate) then we just need to re-
3776 * allocate the list to remove the extra space. Otherwise, if the
3777 * extents are being removed from the middle of the existing extent
3778 * entries, then we first need to move the extent records beginning
3779 * at idx + ext_diff up in the list to overwrite the records being
3780 * removed, then remove the extra space via kmem_realloc.
3781 */
3782void
3783xfs_iext_remove_direct(
3784 xfs_ifork_t *ifp, /* inode fork pointer */
3785 xfs_extnum_t idx, /* index to begin removing exts */
3786 int ext_diff) /* number of extents to remove */
3787{
3788 xfs_extnum_t nextents; /* number of extents in file */
3789 int new_size; /* size of extents after removal */
3790
3791 new_size = ifp->if_bytes -
3792 (ext_diff * sizeof(xfs_bmbt_rec_t));
3793 nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
3794
3795 if (new_size == 0) {
3796 xfs_iext_destroy(ifp);
3797 return;
3798 }
3799 /* Move extents up in the list (if needed) */
3800 if (idx + ext_diff < nextents) {
3801 memmove(&ifp->if_u1.if_extents[idx],
3802 &ifp->if_u1.if_extents[idx + ext_diff],
3803 (nextents - (idx + ext_diff)) *
3804 sizeof(xfs_bmbt_rec_t));
3805 }
3806 memset(&ifp->if_u1.if_extents[nextents - ext_diff],
3807 0, ext_diff * sizeof(xfs_bmbt_rec_t));
3808 /*
3809 * Reallocate the direct extent list. If the extents
3810 * will fit inside the inode then xfs_iext_realloc_direct
3811 * will switch from direct to inline extent allocation
3812 * mode for us.
3813 */
3814 xfs_iext_realloc_direct(ifp, new_size);
3815 ifp->if_bytes = new_size;
3816}
3817
3818/*
3819 * Create, destroy, or resize a linear (direct) block of extents.
3820 */
3821void
3822xfs_iext_realloc_direct(
3823 xfs_ifork_t *ifp, /* inode fork pointer */
3824 int new_size) /* new size of extents */
3825{
3826 int rnew_size; /* real new size of extents */
3827
3828 rnew_size = new_size;
3829
3830 /* Free extent records */
3831 if (new_size == 0) {
3832 xfs_iext_destroy(ifp);
3833 }
3834 /* Resize direct extent list and zero any new bytes */
3835 else if (ifp->if_real_bytes) {
3836 /* Check if extents will fit inside the inode */
3837 if (new_size <= XFS_INLINE_EXTS * sizeof(xfs_bmbt_rec_t)) {
3838 xfs_iext_direct_to_inline(ifp, new_size /
3839 (uint)sizeof(xfs_bmbt_rec_t));
3840 ifp->if_bytes = new_size;
3841 return;
3842 }
3843 if ((new_size & (new_size - 1)) != 0) {
3844 rnew_size = xfs_iroundup(new_size);
3845 }
3846 if (rnew_size != ifp->if_real_bytes) {
3847 ifp->if_u1.if_extents = (xfs_bmbt_rec_t *)
3848 kmem_realloc(ifp->if_u1.if_extents,
3849 rnew_size,
3850 ifp->if_real_bytes,
3851 KM_SLEEP);
3852 }
3853 if (rnew_size > ifp->if_real_bytes) {
3854 memset(&ifp->if_u1.if_extents[ifp->if_bytes /
3855 (uint)sizeof(xfs_bmbt_rec_t)], 0,
3856 rnew_size - ifp->if_real_bytes);
3857 }
3858 }
3859 /*
3860 * Switch from the inline extent buffer to a direct
3861 * extent list. Be sure to include the inline extent
3862 * bytes in new_size.
3863 */
3864 else {
3865 new_size += ifp->if_bytes;
3866 if ((new_size & (new_size - 1)) != 0) {
3867 rnew_size = xfs_iroundup(new_size);
3868 }
3869 xfs_iext_inline_to_direct(ifp, rnew_size);
3870 }
3871 ifp->if_real_bytes = rnew_size;
3872 ifp->if_bytes = new_size;
3873}
3874
3875/*
3876 * Switch from linear (direct) extent records to inline buffer.
3877 */
3878void
3879xfs_iext_direct_to_inline(
3880 xfs_ifork_t *ifp, /* inode fork pointer */
3881 xfs_extnum_t nextents) /* number of extents in file */
3882{
3883 ASSERT(ifp->if_flags & XFS_IFEXTENTS);
3884 ASSERT(nextents <= XFS_INLINE_EXTS);
3885 /*
3886 * The inline buffer was zeroed when we switched
3887 * from inline to direct extent allocation mode,
3888 * so we don't need to clear it here.
3889 */
3890 memcpy(ifp->if_u2.if_inline_ext, ifp->if_u1.if_extents,
3891 nextents * sizeof(xfs_bmbt_rec_t));
3892 kmem_free(ifp->if_u1.if_extents, KM_SLEEP);
3893 ifp->if_u1.if_extents = ifp->if_u2.if_inline_ext;
3894 ifp->if_real_bytes = 0;
3895}
3896
3897/*
3898 * Switch from inline buffer to linear (direct) extent records.
3899 * new_size should already be rounded up to the next power of 2
3900 * by the caller (when appropriate), so use new_size as it is.
3901 * However, since new_size may be rounded up, we can't update
3902 * if_bytes here. It is the caller's responsibility to update
3903 * if_bytes upon return.
3904 */
3905void
3906xfs_iext_inline_to_direct(
3907 xfs_ifork_t *ifp, /* inode fork pointer */
3908 int new_size) /* number of extents in file */
3909{
3910 ifp->if_u1.if_extents = (xfs_bmbt_rec_t *)
3911 kmem_alloc(new_size, KM_SLEEP);
3912 memset(ifp->if_u1.if_extents, 0, new_size);
3913 if (ifp->if_bytes) {
3914 memcpy(ifp->if_u1.if_extents, ifp->if_u2.if_inline_ext,
3915 ifp->if_bytes);
3916 memset(ifp->if_u2.if_inline_ext, 0, XFS_INLINE_EXTS *
3917 sizeof(xfs_bmbt_rec_t));
3918 }
3919 ifp->if_real_bytes = new_size;
3920}
3921
3922/*
3923 * Free incore file extents.
3924 */
3925void
3926xfs_iext_destroy(
3927 xfs_ifork_t *ifp) /* inode fork pointer */
3928{
3929 if (ifp->if_real_bytes) {
3930 kmem_free(ifp->if_u1.if_extents, ifp->if_real_bytes);
3931 } else if (ifp->if_bytes) {
3932 memset(ifp->if_u2.if_inline_ext, 0, XFS_INLINE_EXTS *
3933 sizeof(xfs_bmbt_rec_t));
3934 }
3935 ifp->if_u1.if_extents = NULL;
3936 ifp->if_real_bytes = 0;
3937 ifp->if_bytes = 0;
3938}