aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_inode.c
diff options
context:
space:
mode:
authorDave Chinner <dchinner@redhat.com>2013-08-12 06:49:33 -0400
committerBen Myers <bpm@sgi.com>2013-08-12 17:37:32 -0400
commit5c4d97d01a3a7a4a84fb05bfc439145ea25ba989 (patch)
treecdcd065d557ac77afb717ef550c42a1d11a33d09 /fs/xfs/xfs_inode.c
parent7fd36c4418ee86712db6871ac95ab23743224bff (diff)
xfs: move inode fork definitions to a new header file
The inode fork definitions are a combination of on-disk format definition and in-memory tracking and manipulation. They are both shared with userspace, so move them all into their own file so sharing is easy to do and track. This removes all inode fork related information from xfs_inode.h. Do the same for the all the C code that currently resides in xfs_inode.c for the same reason. Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Mark Tinguely <tinguely@sgi.com> Signed-off-by: Ben Myers <bpm@sgi.com>
Diffstat (limited to 'fs/xfs/xfs_inode.c')
-rw-r--r--fs/xfs/xfs_inode.c1876
1 files changed, 2 insertions, 1874 deletions
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 516a70a5a45d..18308aceebc1 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -48,7 +48,6 @@
48#include "xfs_trace.h" 48#include "xfs_trace.h"
49#include "xfs_icache.h" 49#include "xfs_icache.h"
50 50
51kmem_zone_t *xfs_ifork_zone;
52kmem_zone_t *xfs_inode_zone; 51kmem_zone_t *xfs_inode_zone;
53 52
54/* 53/*
@@ -58,9 +57,6 @@ kmem_zone_t *xfs_inode_zone;
58#define XFS_ITRUNC_MAX_EXTENTS 2 57#define XFS_ITRUNC_MAX_EXTENTS 2
59 58
60STATIC int xfs_iflush_int(xfs_inode_t *, xfs_buf_t *); 59STATIC int xfs_iflush_int(xfs_inode_t *, xfs_buf_t *);
61STATIC int xfs_iformat_local(xfs_inode_t *, xfs_dinode_t *, int, int);
62STATIC int xfs_iformat_extents(xfs_inode_t *, xfs_dinode_t *, int);
63STATIC int xfs_iformat_btree(xfs_inode_t *, xfs_dinode_t *, int);
64 60
65/* 61/*
66 * helper function to extract extent size hint from inode 62 * helper function to extract extent size hint from inode
@@ -326,34 +322,6 @@ __xfs_iflock(
326 finish_wait(wq, &wait.wait); 322 finish_wait(wq, &wait.wait);
327} 323}
328 324
329#ifdef DEBUG
330/*
331 * Make sure that the extents in the given memory buffer
332 * are valid.
333 */
334STATIC void
335xfs_validate_extents(
336 xfs_ifork_t *ifp,
337 int nrecs,
338 xfs_exntfmt_t fmt)
339{
340 xfs_bmbt_irec_t irec;
341 xfs_bmbt_rec_host_t rec;
342 int i;
343
344 for (i = 0; i < nrecs; i++) {
345 xfs_bmbt_rec_host_t *ep = xfs_iext_get_ext(ifp, i);
346 rec.l0 = get_unaligned(&ep->l0);
347 rec.l1 = get_unaligned(&ep->l1);
348 xfs_bmbt_get_all(&rec, &irec);
349 if (fmt == XFS_EXTFMT_NOSTATE)
350 ASSERT(irec.br_state == XFS_EXT_NORM);
351 }
352}
353#else /* DEBUG */
354#define xfs_validate_extents(ifp, nrecs, fmt)
355#endif /* DEBUG */
356
357/* 325/*
358 * Check that none of the inode's in the buffer have a next 326 * Check that none of the inode's in the buffer have a next
359 * unlinked field of 0. 327 * unlinked field of 0.
@@ -488,351 +456,6 @@ xfs_imap_to_bp(
488 return 0; 456 return 0;
489} 457}
490 458
491/*
492 * Move inode type and inode format specific information from the
493 * on-disk inode to the in-core inode. For fifos, devs, and sockets
494 * this means set if_rdev to the proper value. For files, directories,
495 * and symlinks this means to bring in the in-line data or extent
496 * pointers. For a file in B-tree format, only the root is immediately
497 * brought in-core. The rest will be in-lined in if_extents when it
498 * is first referenced (see xfs_iread_extents()).
499 */
500STATIC int
501xfs_iformat(
502 xfs_inode_t *ip,
503 xfs_dinode_t *dip)
504{
505 xfs_attr_shortform_t *atp;
506 int size;
507 int error = 0;
508 xfs_fsize_t di_size;
509
510 if (unlikely(be32_to_cpu(dip->di_nextents) +
511 be16_to_cpu(dip->di_anextents) >
512 be64_to_cpu(dip->di_nblocks))) {
513 xfs_warn(ip->i_mount,
514 "corrupt dinode %Lu, extent total = %d, nblocks = %Lu.",
515 (unsigned long long)ip->i_ino,
516 (int)(be32_to_cpu(dip->di_nextents) +
517 be16_to_cpu(dip->di_anextents)),
518 (unsigned long long)
519 be64_to_cpu(dip->di_nblocks));
520 XFS_CORRUPTION_ERROR("xfs_iformat(1)", XFS_ERRLEVEL_LOW,
521 ip->i_mount, dip);
522 return XFS_ERROR(EFSCORRUPTED);
523 }
524
525 if (unlikely(dip->di_forkoff > ip->i_mount->m_sb.sb_inodesize)) {
526 xfs_warn(ip->i_mount, "corrupt dinode %Lu, forkoff = 0x%x.",
527 (unsigned long long)ip->i_ino,
528 dip->di_forkoff);
529 XFS_CORRUPTION_ERROR("xfs_iformat(2)", XFS_ERRLEVEL_LOW,
530 ip->i_mount, dip);
531 return XFS_ERROR(EFSCORRUPTED);
532 }
533
534 if (unlikely((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) &&
535 !ip->i_mount->m_rtdev_targp)) {
536 xfs_warn(ip->i_mount,
537 "corrupt dinode %Lu, has realtime flag set.",
538 ip->i_ino);
539 XFS_CORRUPTION_ERROR("xfs_iformat(realtime)",
540 XFS_ERRLEVEL_LOW, ip->i_mount, dip);
541 return XFS_ERROR(EFSCORRUPTED);
542 }
543
544 switch (ip->i_d.di_mode & S_IFMT) {
545 case S_IFIFO:
546 case S_IFCHR:
547 case S_IFBLK:
548 case S_IFSOCK:
549 if (unlikely(dip->di_format != XFS_DINODE_FMT_DEV)) {
550 XFS_CORRUPTION_ERROR("xfs_iformat(3)", XFS_ERRLEVEL_LOW,
551 ip->i_mount, dip);
552 return XFS_ERROR(EFSCORRUPTED);
553 }
554 ip->i_d.di_size = 0;
555 ip->i_df.if_u2.if_rdev = xfs_dinode_get_rdev(dip);
556 break;
557
558 case S_IFREG:
559 case S_IFLNK:
560 case S_IFDIR:
561 switch (dip->di_format) {
562 case XFS_DINODE_FMT_LOCAL:
563 /*
564 * no local regular files yet
565 */
566 if (unlikely(S_ISREG(be16_to_cpu(dip->di_mode)))) {
567 xfs_warn(ip->i_mount,
568 "corrupt inode %Lu (local format for regular file).",
569 (unsigned long long) ip->i_ino);
570 XFS_CORRUPTION_ERROR("xfs_iformat(4)",
571 XFS_ERRLEVEL_LOW,
572 ip->i_mount, dip);
573 return XFS_ERROR(EFSCORRUPTED);
574 }
575
576 di_size = be64_to_cpu(dip->di_size);
577 if (unlikely(di_size > XFS_DFORK_DSIZE(dip, ip->i_mount))) {
578 xfs_warn(ip->i_mount,
579 "corrupt inode %Lu (bad size %Ld for local inode).",
580 (unsigned long long) ip->i_ino,
581 (long long) di_size);
582 XFS_CORRUPTION_ERROR("xfs_iformat(5)",
583 XFS_ERRLEVEL_LOW,
584 ip->i_mount, dip);
585 return XFS_ERROR(EFSCORRUPTED);
586 }
587
588 size = (int)di_size;
589 error = xfs_iformat_local(ip, dip, XFS_DATA_FORK, size);
590 break;
591 case XFS_DINODE_FMT_EXTENTS:
592 error = xfs_iformat_extents(ip, dip, XFS_DATA_FORK);
593 break;
594 case XFS_DINODE_FMT_BTREE:
595 error = xfs_iformat_btree(ip, dip, XFS_DATA_FORK);
596 break;
597 default:
598 XFS_ERROR_REPORT("xfs_iformat(6)", XFS_ERRLEVEL_LOW,
599 ip->i_mount);
600 return XFS_ERROR(EFSCORRUPTED);
601 }
602 break;
603
604 default:
605 XFS_ERROR_REPORT("xfs_iformat(7)", XFS_ERRLEVEL_LOW, ip->i_mount);
606 return XFS_ERROR(EFSCORRUPTED);
607 }
608 if (error) {
609 return error;
610 }
611 if (!XFS_DFORK_Q(dip))
612 return 0;
613
614 ASSERT(ip->i_afp == NULL);
615 ip->i_afp = kmem_zone_zalloc(xfs_ifork_zone, KM_SLEEP | KM_NOFS);
616
617 switch (dip->di_aformat) {
618 case XFS_DINODE_FMT_LOCAL:
619 atp = (xfs_attr_shortform_t *)XFS_DFORK_APTR(dip);
620 size = be16_to_cpu(atp->hdr.totsize);
621
622 if (unlikely(size < sizeof(struct xfs_attr_sf_hdr))) {
623 xfs_warn(ip->i_mount,
624 "corrupt inode %Lu (bad attr fork size %Ld).",
625 (unsigned long long) ip->i_ino,
626 (long long) size);
627 XFS_CORRUPTION_ERROR("xfs_iformat(8)",
628 XFS_ERRLEVEL_LOW,
629 ip->i_mount, dip);
630 return XFS_ERROR(EFSCORRUPTED);
631 }
632
633 error = xfs_iformat_local(ip, dip, XFS_ATTR_FORK, size);
634 break;
635 case XFS_DINODE_FMT_EXTENTS:
636 error = xfs_iformat_extents(ip, dip, XFS_ATTR_FORK);
637 break;
638 case XFS_DINODE_FMT_BTREE:
639 error = xfs_iformat_btree(ip, dip, XFS_ATTR_FORK);
640 break;
641 default:
642 error = XFS_ERROR(EFSCORRUPTED);
643 break;
644 }
645 if (error) {
646 kmem_zone_free(xfs_ifork_zone, ip->i_afp);
647 ip->i_afp = NULL;
648 xfs_idestroy_fork(ip, XFS_DATA_FORK);
649 }
650 return error;
651}
652
653/*
654 * The file is in-lined in the on-disk inode.
655 * If it fits into if_inline_data, then copy
656 * it there, otherwise allocate a buffer for it
657 * and copy the data there. Either way, set
658 * if_data to point at the data.
659 * If we allocate a buffer for the data, make
660 * sure that its size is a multiple of 4 and
661 * record the real size in i_real_bytes.
662 */
663STATIC int
664xfs_iformat_local(
665 xfs_inode_t *ip,
666 xfs_dinode_t *dip,
667 int whichfork,
668 int size)
669{
670 xfs_ifork_t *ifp;
671 int real_size;
672
673 /*
674 * If the size is unreasonable, then something
675 * is wrong and we just bail out rather than crash in
676 * kmem_alloc() or memcpy() below.
677 */
678 if (unlikely(size > XFS_DFORK_SIZE(dip, ip->i_mount, whichfork))) {
679 xfs_warn(ip->i_mount,
680 "corrupt inode %Lu (bad size %d for local fork, size = %d).",
681 (unsigned long long) ip->i_ino, size,
682 XFS_DFORK_SIZE(dip, ip->i_mount, whichfork));
683 XFS_CORRUPTION_ERROR("xfs_iformat_local", XFS_ERRLEVEL_LOW,
684 ip->i_mount, dip);
685 return XFS_ERROR(EFSCORRUPTED);
686 }
687 ifp = XFS_IFORK_PTR(ip, whichfork);
688 real_size = 0;
689 if (size == 0)
690 ifp->if_u1.if_data = NULL;
691 else if (size <= sizeof(ifp->if_u2.if_inline_data))
692 ifp->if_u1.if_data = ifp->if_u2.if_inline_data;
693 else {
694 real_size = roundup(size, 4);
695 ifp->if_u1.if_data = kmem_alloc(real_size, KM_SLEEP | KM_NOFS);
696 }
697 ifp->if_bytes = size;
698 ifp->if_real_bytes = real_size;
699 if (size)
700 memcpy(ifp->if_u1.if_data, XFS_DFORK_PTR(dip, whichfork), size);
701 ifp->if_flags &= ~XFS_IFEXTENTS;
702 ifp->if_flags |= XFS_IFINLINE;
703 return 0;
704}
705
706/*
707 * The file consists of a set of extents all
708 * of which fit into the on-disk inode.
709 * If there are few enough extents to fit into
710 * the if_inline_ext, then copy them there.
711 * Otherwise allocate a buffer for them and copy
712 * them into it. Either way, set if_extents
713 * to point at the extents.
714 */
715STATIC int
716xfs_iformat_extents(
717 xfs_inode_t *ip,
718 xfs_dinode_t *dip,
719 int whichfork)
720{
721 xfs_bmbt_rec_t *dp;
722 xfs_ifork_t *ifp;
723 int nex;
724 int size;
725 int i;
726
727 ifp = XFS_IFORK_PTR(ip, whichfork);
728 nex = XFS_DFORK_NEXTENTS(dip, whichfork);
729 size = nex * (uint)sizeof(xfs_bmbt_rec_t);
730
731 /*
732 * If the number of extents is unreasonable, then something
733 * is wrong and we just bail out rather than crash in
734 * kmem_alloc() or memcpy() below.
735 */
736 if (unlikely(size < 0 || size > XFS_DFORK_SIZE(dip, ip->i_mount, whichfork))) {
737 xfs_warn(ip->i_mount, "corrupt inode %Lu ((a)extents = %d).",
738 (unsigned long long) ip->i_ino, nex);
739 XFS_CORRUPTION_ERROR("xfs_iformat_extents(1)", XFS_ERRLEVEL_LOW,
740 ip->i_mount, dip);
741 return XFS_ERROR(EFSCORRUPTED);
742 }
743
744 ifp->if_real_bytes = 0;
745 if (nex == 0)
746 ifp->if_u1.if_extents = NULL;
747 else if (nex <= XFS_INLINE_EXTS)
748 ifp->if_u1.if_extents = ifp->if_u2.if_inline_ext;
749 else
750 xfs_iext_add(ifp, 0, nex);
751
752 ifp->if_bytes = size;
753 if (size) {
754 dp = (xfs_bmbt_rec_t *) XFS_DFORK_PTR(dip, whichfork);
755 xfs_validate_extents(ifp, nex, XFS_EXTFMT_INODE(ip));
756 for (i = 0; i < nex; i++, dp++) {
757 xfs_bmbt_rec_host_t *ep = xfs_iext_get_ext(ifp, i);
758 ep->l0 = get_unaligned_be64(&dp->l0);
759 ep->l1 = get_unaligned_be64(&dp->l1);
760 }
761 XFS_BMAP_TRACE_EXLIST(ip, nex, whichfork);
762 if (whichfork != XFS_DATA_FORK ||
763 XFS_EXTFMT_INODE(ip) == XFS_EXTFMT_NOSTATE)
764 if (unlikely(xfs_check_nostate_extents(
765 ifp, 0, nex))) {
766 XFS_ERROR_REPORT("xfs_iformat_extents(2)",
767 XFS_ERRLEVEL_LOW,
768 ip->i_mount);
769 return XFS_ERROR(EFSCORRUPTED);
770 }
771 }
772 ifp->if_flags |= XFS_IFEXTENTS;
773 return 0;
774}
775
776/*
777 * The file has too many extents to fit into
778 * the inode, so they are in B-tree format.
779 * Allocate a buffer for the root of the B-tree
780 * and copy the root into it. The i_extents
781 * field will remain NULL until all of the
782 * extents are read in (when they are needed).
783 */
784STATIC int
785xfs_iformat_btree(
786 xfs_inode_t *ip,
787 xfs_dinode_t *dip,
788 int whichfork)
789{
790 struct xfs_mount *mp = ip->i_mount;
791 xfs_bmdr_block_t *dfp;
792 xfs_ifork_t *ifp;
793 /* REFERENCED */
794 int nrecs;
795 int size;
796
797 ifp = XFS_IFORK_PTR(ip, whichfork);
798 dfp = (xfs_bmdr_block_t *)XFS_DFORK_PTR(dip, whichfork);
799 size = XFS_BMAP_BROOT_SPACE(mp, dfp);
800 nrecs = be16_to_cpu(dfp->bb_numrecs);
801
802 /*
803 * blow out if -- fork has less extents than can fit in
804 * fork (fork shouldn't be a btree format), root btree
805 * block has more records than can fit into the fork,
806 * or the number of extents is greater than the number of
807 * blocks.
808 */
809 if (unlikely(XFS_IFORK_NEXTENTS(ip, whichfork) <=
810 XFS_IFORK_MAXEXT(ip, whichfork) ||
811 XFS_BMDR_SPACE_CALC(nrecs) >
812 XFS_DFORK_SIZE(dip, mp, whichfork) ||
813 XFS_IFORK_NEXTENTS(ip, whichfork) > ip->i_d.di_nblocks)) {
814 xfs_warn(mp, "corrupt inode %Lu (btree).",
815 (unsigned long long) ip->i_ino);
816 XFS_CORRUPTION_ERROR("xfs_iformat_btree", XFS_ERRLEVEL_LOW,
817 mp, dip);
818 return XFS_ERROR(EFSCORRUPTED);
819 }
820
821 ifp->if_broot_bytes = size;
822 ifp->if_broot = kmem_alloc(size, KM_SLEEP | KM_NOFS);
823 ASSERT(ifp->if_broot != NULL);
824 /*
825 * Copy and convert from the on-disk structure
826 * to the in-memory structure.
827 */
828 xfs_bmdr_to_bmbt(ip, dfp, XFS_DFORK_SIZE(dip, ip->i_mount, whichfork),
829 ifp->if_broot, size);
830 ifp->if_flags &= ~XFS_IFEXTENTS;
831 ifp->if_flags |= XFS_IFBROOT;
832
833 return 0;
834}
835
836STATIC void 459STATIC void
837xfs_dinode_from_disk( 460xfs_dinode_from_disk(
838 xfs_icdinode_t *to, 461 xfs_icdinode_t *to,
@@ -1095,13 +718,13 @@ xfs_iread(
1095 /* 718 /*
1096 * If the on-disk inode is already linked to a directory 719 * If the on-disk inode is already linked to a directory
1097 * entry, copy all of the inode into the in-core inode. 720 * entry, copy all of the inode into the in-core inode.
1098 * xfs_iformat() handles copying in the inode format 721 * xfs_iformat_fork() handles copying in the inode format
1099 * specific information. 722 * specific information.
1100 * Otherwise, just get the truly permanent information. 723 * Otherwise, just get the truly permanent information.
1101 */ 724 */
1102 if (dip->di_mode) { 725 if (dip->di_mode) {
1103 xfs_dinode_from_disk(&ip->i_d, dip); 726 xfs_dinode_from_disk(&ip->i_d, dip);
1104 error = xfs_iformat(ip, dip); 727 error = xfs_iformat_fork(ip, dip);
1105 if (error) { 728 if (error) {
1106#ifdef DEBUG 729#ifdef DEBUG
1107 xfs_alert(mp, "%s: xfs_iformat() returned error %d", 730 xfs_alert(mp, "%s: xfs_iformat() returned error %d",
@@ -1178,44 +801,6 @@ xfs_iread(
1178} 801}
1179 802
1180/* 803/*
1181 * Read in extents from a btree-format inode.
1182 * Allocate and fill in if_extents. Real work is done in xfs_bmap.c.
1183 */
1184int
1185xfs_iread_extents(
1186 xfs_trans_t *tp,
1187 xfs_inode_t *ip,
1188 int whichfork)
1189{
1190 int error;
1191 xfs_ifork_t *ifp;
1192 xfs_extnum_t nextents;
1193
1194 if (unlikely(XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE)) {
1195 XFS_ERROR_REPORT("xfs_iread_extents", XFS_ERRLEVEL_LOW,
1196 ip->i_mount);
1197 return XFS_ERROR(EFSCORRUPTED);
1198 }
1199 nextents = XFS_IFORK_NEXTENTS(ip, whichfork);
1200 ifp = XFS_IFORK_PTR(ip, whichfork);
1201
1202 /*
1203 * We know that the size is valid (it's checked in iformat_btree)
1204 */
1205 ifp->if_bytes = ifp->if_real_bytes = 0;
1206 ifp->if_flags |= XFS_IFEXTENTS;
1207 xfs_iext_add(ifp, 0, nextents);
1208 error = xfs_bmap_read_extents(tp, ip, whichfork);
1209 if (error) {
1210 xfs_iext_destroy(ifp);
1211 ifp->if_flags &= ~XFS_IFEXTENTS;
1212 return error;
1213 }
1214 xfs_validate_extents(ifp, nextents, XFS_EXTFMT_INODE(ip));
1215 return 0;
1216}
1217
1218/*
1219 * Allocate an inode on disk and return a copy of its in-core version. 804 * Allocate an inode on disk and return a copy of its in-core version.
1220 * The in-core inode is locked exclusively. Set mode, nlink, and rdev 805 * The in-core inode is locked exclusively. Set mode, nlink, and rdev
1221 * appropriately within the inode. The uid and gid for the inode are 806 * appropriately within the inode. The uid and gid for the inode are
@@ -2094,272 +1679,6 @@ xfs_ifree(
2094} 1679}
2095 1680
2096/* 1681/*
2097 * Reallocate the space for if_broot based on the number of records
2098 * being added or deleted as indicated in rec_diff. Move the records
2099 * and pointers in if_broot to fit the new size. When shrinking this
2100 * will eliminate holes between the records and pointers created by
2101 * the caller. When growing this will create holes to be filled in
2102 * by the caller.
2103 *
2104 * The caller must not request to add more records than would fit in
2105 * the on-disk inode root. If the if_broot is currently NULL, then
2106 * if we adding records one will be allocated. The caller must also
2107 * not request that the number of records go below zero, although
2108 * it can go to zero.
2109 *
2110 * ip -- the inode whose if_broot area is changing
2111 * ext_diff -- the change in the number of records, positive or negative,
2112 * requested for the if_broot array.
2113 */
2114void
2115xfs_iroot_realloc(
2116 xfs_inode_t *ip,
2117 int rec_diff,
2118 int whichfork)
2119{
2120 struct xfs_mount *mp = ip->i_mount;
2121 int cur_max;
2122 xfs_ifork_t *ifp;
2123 struct xfs_btree_block *new_broot;
2124 int new_max;
2125 size_t new_size;
2126 char *np;
2127 char *op;
2128
2129 /*
2130 * Handle the degenerate case quietly.
2131 */
2132 if (rec_diff == 0) {
2133 return;
2134 }
2135
2136 ifp = XFS_IFORK_PTR(ip, whichfork);
2137 if (rec_diff > 0) {
2138 /*
2139 * If there wasn't any memory allocated before, just
2140 * allocate it now and get out.
2141 */
2142 if (ifp->if_broot_bytes == 0) {
2143 new_size = XFS_BMAP_BROOT_SPACE_CALC(mp, rec_diff);
2144 ifp->if_broot = kmem_alloc(new_size, KM_SLEEP | KM_NOFS);
2145 ifp->if_broot_bytes = (int)new_size;
2146 return;
2147 }
2148
2149 /*
2150 * If there is already an existing if_broot, then we need
2151 * to realloc() it and shift the pointers to their new
2152 * location. The records don't change location because
2153 * they are kept butted up against the btree block header.
2154 */
2155 cur_max = xfs_bmbt_maxrecs(mp, ifp->if_broot_bytes, 0);
2156 new_max = cur_max + rec_diff;
2157 new_size = XFS_BMAP_BROOT_SPACE_CALC(mp, new_max);
2158 ifp->if_broot = kmem_realloc(ifp->if_broot, new_size,
2159 XFS_BMAP_BROOT_SPACE_CALC(mp, cur_max),
2160 KM_SLEEP | KM_NOFS);
2161 op = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, ifp->if_broot, 1,
2162 ifp->if_broot_bytes);
2163 np = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, ifp->if_broot, 1,
2164 (int)new_size);
2165 ifp->if_broot_bytes = (int)new_size;
2166 ASSERT(XFS_BMAP_BMDR_SPACE(ifp->if_broot) <=
2167 XFS_IFORK_SIZE(ip, whichfork));
2168 memmove(np, op, cur_max * (uint)sizeof(xfs_dfsbno_t));
2169 return;
2170 }
2171
2172 /*
2173 * rec_diff is less than 0. In this case, we are shrinking the
2174 * if_broot buffer. It must already exist. If we go to zero
2175 * records, just get rid of the root and clear the status bit.
2176 */
2177 ASSERT((ifp->if_broot != NULL) && (ifp->if_broot_bytes > 0));
2178 cur_max = xfs_bmbt_maxrecs(mp, ifp->if_broot_bytes, 0);
2179 new_max = cur_max + rec_diff;
2180 ASSERT(new_max >= 0);
2181 if (new_max > 0)
2182 new_size = XFS_BMAP_BROOT_SPACE_CALC(mp, new_max);
2183 else
2184 new_size = 0;
2185 if (new_size > 0) {
2186 new_broot = kmem_alloc(new_size, KM_SLEEP | KM_NOFS);
2187 /*
2188 * First copy over the btree block header.
2189 */
2190 memcpy(new_broot, ifp->if_broot,
2191 XFS_BMBT_BLOCK_LEN(ip->i_mount));
2192 } else {
2193 new_broot = NULL;
2194 ifp->if_flags &= ~XFS_IFBROOT;
2195 }
2196
2197 /*
2198 * Only copy the records and pointers if there are any.
2199 */
2200 if (new_max > 0) {
2201 /*
2202 * First copy the records.
2203 */
2204 op = (char *)XFS_BMBT_REC_ADDR(mp, ifp->if_broot, 1);
2205 np = (char *)XFS_BMBT_REC_ADDR(mp, new_broot, 1);
2206 memcpy(np, op, new_max * (uint)sizeof(xfs_bmbt_rec_t));
2207
2208 /*
2209 * Then copy the pointers.
2210 */
2211 op = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, ifp->if_broot, 1,
2212 ifp->if_broot_bytes);
2213 np = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, new_broot, 1,
2214 (int)new_size);
2215 memcpy(np, op, new_max * (uint)sizeof(xfs_dfsbno_t));
2216 }
2217 kmem_free(ifp->if_broot);
2218 ifp->if_broot = new_broot;
2219 ifp->if_broot_bytes = (int)new_size;
2220 if (ifp->if_broot)
2221 ASSERT(XFS_BMAP_BMDR_SPACE(ifp->if_broot) <=
2222 XFS_IFORK_SIZE(ip, whichfork));
2223 return;
2224}
2225
2226
2227/*
2228 * This is called when the amount of space needed for if_data
2229 * is increased or decreased. The change in size is indicated by
2230 * the number of bytes that need to be added or deleted in the
2231 * byte_diff parameter.
2232 *
2233 * If the amount of space needed has decreased below the size of the
2234 * inline buffer, then switch to using the inline buffer. Otherwise,
2235 * use kmem_realloc() or kmem_alloc() to adjust the size of the buffer
2236 * to what is needed.
2237 *
2238 * ip -- the inode whose if_data area is changing
2239 * byte_diff -- the change in the number of bytes, positive or negative,
2240 * requested for the if_data array.
2241 */
2242void
2243xfs_idata_realloc(
2244 xfs_inode_t *ip,
2245 int byte_diff,
2246 int whichfork)
2247{
2248 xfs_ifork_t *ifp;
2249 int new_size;
2250 int real_size;
2251
2252 if (byte_diff == 0) {
2253 return;
2254 }
2255
2256 ifp = XFS_IFORK_PTR(ip, whichfork);
2257 new_size = (int)ifp->if_bytes + byte_diff;
2258 ASSERT(new_size >= 0);
2259
2260 if (new_size == 0) {
2261 if (ifp->if_u1.if_data != ifp->if_u2.if_inline_data) {
2262 kmem_free(ifp->if_u1.if_data);
2263 }
2264 ifp->if_u1.if_data = NULL;
2265 real_size = 0;
2266 } else if (new_size <= sizeof(ifp->if_u2.if_inline_data)) {
2267 /*
2268 * If the valid extents/data can fit in if_inline_ext/data,
2269 * copy them from the malloc'd vector and free it.
2270 */
2271 if (ifp->if_u1.if_data == NULL) {
2272 ifp->if_u1.if_data = ifp->if_u2.if_inline_data;
2273 } else if (ifp->if_u1.if_data != ifp->if_u2.if_inline_data) {
2274 ASSERT(ifp->if_real_bytes != 0);
2275 memcpy(ifp->if_u2.if_inline_data, ifp->if_u1.if_data,
2276 new_size);
2277 kmem_free(ifp->if_u1.if_data);
2278 ifp->if_u1.if_data = ifp->if_u2.if_inline_data;
2279 }
2280 real_size = 0;
2281 } else {
2282 /*
2283 * Stuck with malloc/realloc.
2284 * For inline data, the underlying buffer must be
2285 * a multiple of 4 bytes in size so that it can be
2286 * logged and stay on word boundaries. We enforce
2287 * that here.
2288 */
2289 real_size = roundup(new_size, 4);
2290 if (ifp->if_u1.if_data == NULL) {
2291 ASSERT(ifp->if_real_bytes == 0);
2292 ifp->if_u1.if_data = kmem_alloc(real_size,
2293 KM_SLEEP | KM_NOFS);
2294 } else if (ifp->if_u1.if_data != ifp->if_u2.if_inline_data) {
2295 /*
2296 * Only do the realloc if the underlying size
2297 * is really changing.
2298 */
2299 if (ifp->if_real_bytes != real_size) {
2300 ifp->if_u1.if_data =
2301 kmem_realloc(ifp->if_u1.if_data,
2302 real_size,
2303 ifp->if_real_bytes,
2304 KM_SLEEP | KM_NOFS);
2305 }
2306 } else {
2307 ASSERT(ifp->if_real_bytes == 0);
2308 ifp->if_u1.if_data = kmem_alloc(real_size,
2309 KM_SLEEP | KM_NOFS);
2310 memcpy(ifp->if_u1.if_data, ifp->if_u2.if_inline_data,
2311 ifp->if_bytes);
2312 }
2313 }
2314 ifp->if_real_bytes = real_size;
2315 ifp->if_bytes = new_size;
2316 ASSERT(ifp->if_bytes <= XFS_IFORK_SIZE(ip, whichfork));
2317}
2318
2319void
2320xfs_idestroy_fork(
2321 xfs_inode_t *ip,
2322 int whichfork)
2323{
2324 xfs_ifork_t *ifp;
2325
2326 ifp = XFS_IFORK_PTR(ip, whichfork);
2327 if (ifp->if_broot != NULL) {
2328 kmem_free(ifp->if_broot);
2329 ifp->if_broot = NULL;
2330 }
2331
2332 /*
2333 * If the format is local, then we can't have an extents
2334 * array so just look for an inline data array. If we're
2335 * not local then we may or may not have an extents list,
2336 * so check and free it up if we do.
2337 */
2338 if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) {
2339 if ((ifp->if_u1.if_data != ifp->if_u2.if_inline_data) &&
2340 (ifp->if_u1.if_data != NULL)) {
2341 ASSERT(ifp->if_real_bytes != 0);
2342 kmem_free(ifp->if_u1.if_data);
2343 ifp->if_u1.if_data = NULL;
2344 ifp->if_real_bytes = 0;
2345 }
2346 } else if ((ifp->if_flags & XFS_IFEXTENTS) &&
2347 ((ifp->if_flags & XFS_IFEXTIREC) ||
2348 ((ifp->if_u1.if_extents != NULL) &&
2349 (ifp->if_u1.if_extents != ifp->if_u2.if_inline_ext)))) {
2350 ASSERT(ifp->if_real_bytes != 0);
2351 xfs_iext_destroy(ifp);
2352 }
2353 ASSERT(ifp->if_u1.if_extents == NULL ||
2354 ifp->if_u1.if_extents == ifp->if_u2.if_inline_ext);
2355 ASSERT(ifp->if_real_bytes == 0);
2356 if (whichfork == XFS_ATTR_FORK) {
2357 kmem_zone_free(xfs_ifork_zone, ip->i_afp);
2358 ip->i_afp = NULL;
2359 }
2360}
2361
2362/*
2363 * This is called to unpin an inode. The caller must have the inode locked 1682 * This is called to unpin an inode. The caller must have the inode locked
2364 * in at least shared mode so that the buffer cannot be subsequently pinned 1683 * in at least shared mode so that the buffer cannot be subsequently pinned
2365 * once someone is waiting for it to be unpinned. 1684 * once someone is waiting for it to be unpinned.
@@ -2402,164 +1721,6 @@ xfs_iunpin_wait(
2402 __xfs_iunpin_wait(ip); 1721 __xfs_iunpin_wait(ip);
2403} 1722}
2404 1723
2405/*
2406 * xfs_iextents_copy()
2407 *
2408 * This is called to copy the REAL extents (as opposed to the delayed
2409 * allocation extents) from the inode into the given buffer. It
2410 * returns the number of bytes copied into the buffer.
2411 *
2412 * If there are no delayed allocation extents, then we can just
2413 * memcpy() the extents into the buffer. Otherwise, we need to
2414 * examine each extent in turn and skip those which are delayed.
2415 */
2416int
2417xfs_iextents_copy(
2418 xfs_inode_t *ip,
2419 xfs_bmbt_rec_t *dp,
2420 int whichfork)
2421{
2422 int copied;
2423 int i;
2424 xfs_ifork_t *ifp;
2425 int nrecs;
2426 xfs_fsblock_t start_block;
2427
2428 ifp = XFS_IFORK_PTR(ip, whichfork);
2429 ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED));
2430 ASSERT(ifp->if_bytes > 0);
2431
2432 nrecs = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
2433 XFS_BMAP_TRACE_EXLIST(ip, nrecs, whichfork);
2434 ASSERT(nrecs > 0);
2435
2436 /*
2437 * There are some delayed allocation extents in the
2438 * inode, so copy the extents one at a time and skip
2439 * the delayed ones. There must be at least one
2440 * non-delayed extent.
2441 */
2442 copied = 0;
2443 for (i = 0; i < nrecs; i++) {
2444 xfs_bmbt_rec_host_t *ep = xfs_iext_get_ext(ifp, i);
2445 start_block = xfs_bmbt_get_startblock(ep);
2446 if (isnullstartblock(start_block)) {
2447 /*
2448 * It's a delayed allocation extent, so skip it.
2449 */
2450 continue;
2451 }
2452
2453 /* Translate to on disk format */
2454 put_unaligned(cpu_to_be64(ep->l0), &dp->l0);
2455 put_unaligned(cpu_to_be64(ep->l1), &dp->l1);
2456 dp++;
2457 copied++;
2458 }
2459 ASSERT(copied != 0);
2460 xfs_validate_extents(ifp, copied, XFS_EXTFMT_INODE(ip));
2461
2462 return (copied * (uint)sizeof(xfs_bmbt_rec_t));
2463}
2464
2465/*
2466 * Each of the following cases stores data into the same region
2467 * of the on-disk inode, so only one of them can be valid at
2468 * any given time. While it is possible to have conflicting formats
2469 * and log flags, e.g. having XFS_ILOG_?DATA set when the fork is
2470 * in EXTENTS format, this can only happen when the fork has
2471 * changed formats after being modified but before being flushed.
2472 * In these cases, the format always takes precedence, because the
2473 * format indicates the current state of the fork.
2474 */
2475/*ARGSUSED*/
2476STATIC void
2477xfs_iflush_fork(
2478 xfs_inode_t *ip,
2479 xfs_dinode_t *dip,
2480 xfs_inode_log_item_t *iip,
2481 int whichfork,
2482 xfs_buf_t *bp)
2483{
2484 char *cp;
2485 xfs_ifork_t *ifp;
2486 xfs_mount_t *mp;
2487 static const short brootflag[2] =
2488 { XFS_ILOG_DBROOT, XFS_ILOG_ABROOT };
2489 static const short dataflag[2] =
2490 { XFS_ILOG_DDATA, XFS_ILOG_ADATA };
2491 static const short extflag[2] =
2492 { XFS_ILOG_DEXT, XFS_ILOG_AEXT };
2493
2494 if (!iip)
2495 return;
2496 ifp = XFS_IFORK_PTR(ip, whichfork);
2497 /*
2498 * This can happen if we gave up in iformat in an error path,
2499 * for the attribute fork.
2500 */
2501 if (!ifp) {
2502 ASSERT(whichfork == XFS_ATTR_FORK);
2503 return;
2504 }
2505 cp = XFS_DFORK_PTR(dip, whichfork);
2506 mp = ip->i_mount;
2507 switch (XFS_IFORK_FORMAT(ip, whichfork)) {
2508 case XFS_DINODE_FMT_LOCAL:
2509 if ((iip->ili_fields & dataflag[whichfork]) &&
2510 (ifp->if_bytes > 0)) {
2511 ASSERT(ifp->if_u1.if_data != NULL);
2512 ASSERT(ifp->if_bytes <= XFS_IFORK_SIZE(ip, whichfork));
2513 memcpy(cp, ifp->if_u1.if_data, ifp->if_bytes);
2514 }
2515 break;
2516
2517 case XFS_DINODE_FMT_EXTENTS:
2518 ASSERT((ifp->if_flags & XFS_IFEXTENTS) ||
2519 !(iip->ili_fields & extflag[whichfork]));
2520 if ((iip->ili_fields & extflag[whichfork]) &&
2521 (ifp->if_bytes > 0)) {
2522 ASSERT(xfs_iext_get_ext(ifp, 0));
2523 ASSERT(XFS_IFORK_NEXTENTS(ip, whichfork) > 0);
2524 (void)xfs_iextents_copy(ip, (xfs_bmbt_rec_t *)cp,
2525 whichfork);
2526 }
2527 break;
2528
2529 case XFS_DINODE_FMT_BTREE:
2530 if ((iip->ili_fields & brootflag[whichfork]) &&
2531 (ifp->if_broot_bytes > 0)) {
2532 ASSERT(ifp->if_broot != NULL);
2533 ASSERT(XFS_BMAP_BMDR_SPACE(ifp->if_broot) <=
2534 XFS_IFORK_SIZE(ip, whichfork));
2535 xfs_bmbt_to_bmdr(mp, ifp->if_broot, ifp->if_broot_bytes,
2536 (xfs_bmdr_block_t *)cp,
2537 XFS_DFORK_SIZE(dip, mp, whichfork));
2538 }
2539 break;
2540
2541 case XFS_DINODE_FMT_DEV:
2542 if (iip->ili_fields & XFS_ILOG_DEV) {
2543 ASSERT(whichfork == XFS_DATA_FORK);
2544 xfs_dinode_put_rdev(dip, ip->i_df.if_u2.if_rdev);
2545 }
2546 break;
2547
2548 case XFS_DINODE_FMT_UUID:
2549 if (iip->ili_fields & XFS_ILOG_UUID) {
2550 ASSERT(whichfork == XFS_DATA_FORK);
2551 memcpy(XFS_DFORK_DPTR(dip),
2552 &ip->i_df.if_u2.if_uuid,
2553 sizeof(uuid_t));
2554 }
2555 break;
2556
2557 default:
2558 ASSERT(0);
2559 break;
2560 }
2561}
2562
2563STATIC int 1724STATIC int
2564xfs_iflush_cluster( 1725xfs_iflush_cluster(
2565 xfs_inode_t *ip, 1726 xfs_inode_t *ip,
@@ -3006,1038 +2167,6 @@ corrupt_out:
3006} 2167}
3007 2168
3008/* 2169/*
3009 * Return a pointer to the extent record at file index idx.
3010 */
3011xfs_bmbt_rec_host_t *
3012xfs_iext_get_ext(
3013 xfs_ifork_t *ifp, /* inode fork pointer */
3014 xfs_extnum_t idx) /* index of target extent */
3015{
3016 ASSERT(idx >= 0);
3017 ASSERT(idx < ifp->if_bytes / sizeof(xfs_bmbt_rec_t));
3018
3019 if ((ifp->if_flags & XFS_IFEXTIREC) && (idx == 0)) {
3020 return ifp->if_u1.if_ext_irec->er_extbuf;
3021 } else if (ifp->if_flags & XFS_IFEXTIREC) {
3022 xfs_ext_irec_t *erp; /* irec pointer */
3023 int erp_idx = 0; /* irec index */
3024 xfs_extnum_t page_idx = idx; /* ext index in target list */
3025
3026 erp = xfs_iext_idx_to_irec(ifp, &page_idx, &erp_idx, 0);
3027 return &erp->er_extbuf[page_idx];
3028 } else if (ifp->if_bytes) {
3029 return &ifp->if_u1.if_extents[idx];
3030 } else {
3031 return NULL;
3032 }
3033}
3034
3035/*
3036 * Insert new item(s) into the extent records for incore inode
3037 * fork 'ifp'. 'count' new items are inserted at index 'idx'.
3038 */
3039void
3040xfs_iext_insert(
3041 xfs_inode_t *ip, /* incore inode pointer */
3042 xfs_extnum_t idx, /* starting index of new items */
3043 xfs_extnum_t count, /* number of inserted items */
3044 xfs_bmbt_irec_t *new, /* items to insert */
3045 int state) /* type of extent conversion */
3046{
3047 xfs_ifork_t *ifp = (state & BMAP_ATTRFORK) ? ip->i_afp : &ip->i_df;
3048 xfs_extnum_t i; /* extent record index */
3049
3050 trace_xfs_iext_insert(ip, idx, new, state, _RET_IP_);
3051
3052 ASSERT(ifp->if_flags & XFS_IFEXTENTS);
3053 xfs_iext_add(ifp, idx, count);
3054 for (i = idx; i < idx + count; i++, new++)
3055 xfs_bmbt_set_all(xfs_iext_get_ext(ifp, i), new);
3056}
3057
3058/*
3059 * This is called when the amount of space required for incore file
3060 * extents needs to be increased. The ext_diff parameter stores the
3061 * number of new extents being added and the idx parameter contains
3062 * the extent index where the new extents will be added. If the new
3063 * extents are being appended, then we just need to (re)allocate and
3064 * initialize the space. Otherwise, if the new extents are being
3065 * inserted into the middle of the existing entries, a bit more work
3066 * is required to make room for the new extents to be inserted. The
3067 * caller is responsible for filling in the new extent entries upon
3068 * return.
3069 */
3070void
3071xfs_iext_add(
3072 xfs_ifork_t *ifp, /* inode fork pointer */
3073 xfs_extnum_t idx, /* index to begin adding exts */
3074 int ext_diff) /* number of extents to add */
3075{
3076 int byte_diff; /* new bytes being added */
3077 int new_size; /* size of extents after adding */
3078 xfs_extnum_t nextents; /* number of extents in file */
3079
3080 nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
3081 ASSERT((idx >= 0) && (idx <= nextents));
3082 byte_diff = ext_diff * sizeof(xfs_bmbt_rec_t);
3083 new_size = ifp->if_bytes + byte_diff;
3084 /*
3085 * If the new number of extents (nextents + ext_diff)
3086 * fits inside the inode, then continue to use the inline
3087 * extent buffer.
3088 */
3089 if (nextents + ext_diff <= XFS_INLINE_EXTS) {
3090 if (idx < nextents) {
3091 memmove(&ifp->if_u2.if_inline_ext[idx + ext_diff],
3092 &ifp->if_u2.if_inline_ext[idx],
3093 (nextents - idx) * sizeof(xfs_bmbt_rec_t));
3094 memset(&ifp->if_u2.if_inline_ext[idx], 0, byte_diff);
3095 }
3096 ifp->if_u1.if_extents = ifp->if_u2.if_inline_ext;
3097 ifp->if_real_bytes = 0;
3098 }
3099 /*
3100 * Otherwise use a linear (direct) extent list.
3101 * If the extents are currently inside the inode,
3102 * xfs_iext_realloc_direct will switch us from
3103 * inline to direct extent allocation mode.
3104 */
3105 else if (nextents + ext_diff <= XFS_LINEAR_EXTS) {
3106 xfs_iext_realloc_direct(ifp, new_size);
3107 if (idx < nextents) {
3108 memmove(&ifp->if_u1.if_extents[idx + ext_diff],
3109 &ifp->if_u1.if_extents[idx],
3110 (nextents - idx) * sizeof(xfs_bmbt_rec_t));
3111 memset(&ifp->if_u1.if_extents[idx], 0, byte_diff);
3112 }
3113 }
3114 /* Indirection array */
3115 else {
3116 xfs_ext_irec_t *erp;
3117 int erp_idx = 0;
3118 int page_idx = idx;
3119
3120 ASSERT(nextents + ext_diff > XFS_LINEAR_EXTS);
3121 if (ifp->if_flags & XFS_IFEXTIREC) {
3122 erp = xfs_iext_idx_to_irec(ifp, &page_idx, &erp_idx, 1);
3123 } else {
3124 xfs_iext_irec_init(ifp);
3125 ASSERT(ifp->if_flags & XFS_IFEXTIREC);
3126 erp = ifp->if_u1.if_ext_irec;
3127 }
3128 /* Extents fit in target extent page */
3129 if (erp && erp->er_extcount + ext_diff <= XFS_LINEAR_EXTS) {
3130 if (page_idx < erp->er_extcount) {
3131 memmove(&erp->er_extbuf[page_idx + ext_diff],
3132 &erp->er_extbuf[page_idx],
3133 (erp->er_extcount - page_idx) *
3134 sizeof(xfs_bmbt_rec_t));
3135 memset(&erp->er_extbuf[page_idx], 0, byte_diff);
3136 }
3137 erp->er_extcount += ext_diff;
3138 xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, ext_diff);
3139 }
3140 /* Insert a new extent page */
3141 else if (erp) {
3142 xfs_iext_add_indirect_multi(ifp,
3143 erp_idx, page_idx, ext_diff);
3144 }
3145 /*
3146 * If extent(s) are being appended to the last page in
3147 * the indirection array and the new extent(s) don't fit
3148 * in the page, then erp is NULL and erp_idx is set to
3149 * the next index needed in the indirection array.
3150 */
3151 else {
3152 int count = ext_diff;
3153
3154 while (count) {
3155 erp = xfs_iext_irec_new(ifp, erp_idx);
3156 erp->er_extcount = count;
3157 count -= MIN(count, (int)XFS_LINEAR_EXTS);
3158 if (count) {
3159 erp_idx++;
3160 }
3161 }
3162 }
3163 }
3164 ifp->if_bytes = new_size;
3165}
3166
3167/*
3168 * This is called when incore extents are being added to the indirection
3169 * array and the new extents do not fit in the target extent list. The
3170 * erp_idx parameter contains the irec index for the target extent list
3171 * in the indirection array, and the idx parameter contains the extent
3172 * index within the list. The number of extents being added is stored
3173 * in the count parameter.
3174 *
3175 * |-------| |-------|
3176 * | | | | idx - number of extents before idx
3177 * | idx | | count |
3178 * | | | | count - number of extents being inserted at idx
3179 * |-------| |-------|
3180 * | count | | nex2 | nex2 - number of extents after idx + count
3181 * |-------| |-------|
3182 */
3183void
3184xfs_iext_add_indirect_multi(
3185 xfs_ifork_t *ifp, /* inode fork pointer */
3186 int erp_idx, /* target extent irec index */
3187 xfs_extnum_t idx, /* index within target list */
3188 int count) /* new extents being added */
3189{
3190 int byte_diff; /* new bytes being added */
3191 xfs_ext_irec_t *erp; /* pointer to irec entry */
3192 xfs_extnum_t ext_diff; /* number of extents to add */
3193 xfs_extnum_t ext_cnt; /* new extents still needed */
3194 xfs_extnum_t nex2; /* extents after idx + count */
3195 xfs_bmbt_rec_t *nex2_ep = NULL; /* temp list for nex2 extents */
3196 int nlists; /* number of irec's (lists) */
3197
3198 ASSERT(ifp->if_flags & XFS_IFEXTIREC);
3199 erp = &ifp->if_u1.if_ext_irec[erp_idx];
3200 nex2 = erp->er_extcount - idx;
3201 nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
3202
3203 /*
3204 * Save second part of target extent list
3205 * (all extents past */
3206 if (nex2) {
3207 byte_diff = nex2 * sizeof(xfs_bmbt_rec_t);
3208 nex2_ep = (xfs_bmbt_rec_t *) kmem_alloc(byte_diff, KM_NOFS);
3209 memmove(nex2_ep, &erp->er_extbuf[idx], byte_diff);
3210 erp->er_extcount -= nex2;
3211 xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, -nex2);
3212 memset(&erp->er_extbuf[idx], 0, byte_diff);
3213 }
3214
3215 /*
3216 * Add the new extents to the end of the target
3217 * list, then allocate new irec record(s) and
3218 * extent buffer(s) as needed to store the rest
3219 * of the new extents.
3220 */
3221 ext_cnt = count;
3222 ext_diff = MIN(ext_cnt, (int)XFS_LINEAR_EXTS - erp->er_extcount);
3223 if (ext_diff) {
3224 erp->er_extcount += ext_diff;
3225 xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, ext_diff);
3226 ext_cnt -= ext_diff;
3227 }
3228 while (ext_cnt) {
3229 erp_idx++;
3230 erp = xfs_iext_irec_new(ifp, erp_idx);
3231 ext_diff = MIN(ext_cnt, (int)XFS_LINEAR_EXTS);
3232 erp->er_extcount = ext_diff;
3233 xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, ext_diff);
3234 ext_cnt -= ext_diff;
3235 }
3236
3237 /* Add nex2 extents back to indirection array */
3238 if (nex2) {
3239 xfs_extnum_t ext_avail;
3240 int i;
3241
3242 byte_diff = nex2 * sizeof(xfs_bmbt_rec_t);
3243 ext_avail = XFS_LINEAR_EXTS - erp->er_extcount;
3244 i = 0;
3245 /*
3246 * If nex2 extents fit in the current page, append
3247 * nex2_ep after the new extents.
3248 */
3249 if (nex2 <= ext_avail) {
3250 i = erp->er_extcount;
3251 }
3252 /*
3253 * Otherwise, check if space is available in the
3254 * next page.
3255 */
3256 else if ((erp_idx < nlists - 1) &&
3257 (nex2 <= (ext_avail = XFS_LINEAR_EXTS -
3258 ifp->if_u1.if_ext_irec[erp_idx+1].er_extcount))) {
3259 erp_idx++;
3260 erp++;
3261 /* Create a hole for nex2 extents */
3262 memmove(&erp->er_extbuf[nex2], erp->er_extbuf,
3263 erp->er_extcount * sizeof(xfs_bmbt_rec_t));
3264 }
3265 /*
3266 * Final choice, create a new extent page for
3267 * nex2 extents.
3268 */
3269 else {
3270 erp_idx++;
3271 erp = xfs_iext_irec_new(ifp, erp_idx);
3272 }
3273 memmove(&erp->er_extbuf[i], nex2_ep, byte_diff);
3274 kmem_free(nex2_ep);
3275 erp->er_extcount += nex2;
3276 xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, nex2);
3277 }
3278}
3279
3280/*
3281 * This is called when the amount of space required for incore file
3282 * extents needs to be decreased. The ext_diff parameter stores the
3283 * number of extents to be removed and the idx parameter contains
3284 * the extent index where the extents will be removed from.
3285 *
3286 * If the amount of space needed has decreased below the linear
3287 * limit, XFS_IEXT_BUFSZ, then switch to using the contiguous
3288 * extent array. Otherwise, use kmem_realloc() to adjust the
3289 * size to what is needed.
3290 */
3291void
3292xfs_iext_remove(
3293 xfs_inode_t *ip, /* incore inode pointer */
3294 xfs_extnum_t idx, /* index to begin removing exts */
3295 int ext_diff, /* number of extents to remove */
3296 int state) /* type of extent conversion */
3297{
3298 xfs_ifork_t *ifp = (state & BMAP_ATTRFORK) ? ip->i_afp : &ip->i_df;
3299 xfs_extnum_t nextents; /* number of extents in file */
3300 int new_size; /* size of extents after removal */
3301
3302 trace_xfs_iext_remove(ip, idx, state, _RET_IP_);
3303
3304 ASSERT(ext_diff > 0);
3305 nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
3306 new_size = (nextents - ext_diff) * sizeof(xfs_bmbt_rec_t);
3307
3308 if (new_size == 0) {
3309 xfs_iext_destroy(ifp);
3310 } else if (ifp->if_flags & XFS_IFEXTIREC) {
3311 xfs_iext_remove_indirect(ifp, idx, ext_diff);
3312 } else if (ifp->if_real_bytes) {
3313 xfs_iext_remove_direct(ifp, idx, ext_diff);
3314 } else {
3315 xfs_iext_remove_inline(ifp, idx, ext_diff);
3316 }
3317 ifp->if_bytes = new_size;
3318}
3319
3320/*
3321 * This removes ext_diff extents from the inline buffer, beginning
3322 * at extent index idx.
3323 */
3324void
3325xfs_iext_remove_inline(
3326 xfs_ifork_t *ifp, /* inode fork pointer */
3327 xfs_extnum_t idx, /* index to begin removing exts */
3328 int ext_diff) /* number of extents to remove */
3329{
3330 int nextents; /* number of extents in file */
3331
3332 ASSERT(!(ifp->if_flags & XFS_IFEXTIREC));
3333 ASSERT(idx < XFS_INLINE_EXTS);
3334 nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
3335 ASSERT(((nextents - ext_diff) > 0) &&
3336 (nextents - ext_diff) < XFS_INLINE_EXTS);
3337
3338 if (idx + ext_diff < nextents) {
3339 memmove(&ifp->if_u2.if_inline_ext[idx],
3340 &ifp->if_u2.if_inline_ext[idx + ext_diff],
3341 (nextents - (idx + ext_diff)) *
3342 sizeof(xfs_bmbt_rec_t));
3343 memset(&ifp->if_u2.if_inline_ext[nextents - ext_diff],
3344 0, ext_diff * sizeof(xfs_bmbt_rec_t));
3345 } else {
3346 memset(&ifp->if_u2.if_inline_ext[idx], 0,
3347 ext_diff * sizeof(xfs_bmbt_rec_t));
3348 }
3349}
3350
3351/*
3352 * This removes ext_diff extents from a linear (direct) extent list,
3353 * beginning at extent index idx. If the extents are being removed
3354 * from the end of the list (ie. truncate) then we just need to re-
3355 * allocate the list to remove the extra space. Otherwise, if the
3356 * extents are being removed from the middle of the existing extent
3357 * entries, then we first need to move the extent records beginning
3358 * at idx + ext_diff up in the list to overwrite the records being
3359 * removed, then remove the extra space via kmem_realloc.
3360 */
3361void
3362xfs_iext_remove_direct(
3363 xfs_ifork_t *ifp, /* inode fork pointer */
3364 xfs_extnum_t idx, /* index to begin removing exts */
3365 int ext_diff) /* number of extents to remove */
3366{
3367 xfs_extnum_t nextents; /* number of extents in file */
3368 int new_size; /* size of extents after removal */
3369
3370 ASSERT(!(ifp->if_flags & XFS_IFEXTIREC));
3371 new_size = ifp->if_bytes -
3372 (ext_diff * sizeof(xfs_bmbt_rec_t));
3373 nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
3374
3375 if (new_size == 0) {
3376 xfs_iext_destroy(ifp);
3377 return;
3378 }
3379 /* Move extents up in the list (if needed) */
3380 if (idx + ext_diff < nextents) {
3381 memmove(&ifp->if_u1.if_extents[idx],
3382 &ifp->if_u1.if_extents[idx + ext_diff],
3383 (nextents - (idx + ext_diff)) *
3384 sizeof(xfs_bmbt_rec_t));
3385 }
3386 memset(&ifp->if_u1.if_extents[nextents - ext_diff],
3387 0, ext_diff * sizeof(xfs_bmbt_rec_t));
3388 /*
3389 * Reallocate the direct extent list. If the extents
3390 * will fit inside the inode then xfs_iext_realloc_direct
3391 * will switch from direct to inline extent allocation
3392 * mode for us.
3393 */
3394 xfs_iext_realloc_direct(ifp, new_size);
3395 ifp->if_bytes = new_size;
3396}
3397
3398/*
3399 * This is called when incore extents are being removed from the
3400 * indirection array and the extents being removed span multiple extent
3401 * buffers. The idx parameter contains the file extent index where we
3402 * want to begin removing extents, and the count parameter contains
3403 * how many extents need to be removed.
3404 *
3405 * |-------| |-------|
3406 * | nex1 | | | nex1 - number of extents before idx
3407 * |-------| | count |
3408 * | | | | count - number of extents being removed at idx
3409 * | count | |-------|
3410 * | | | nex2 | nex2 - number of extents after idx + count
3411 * |-------| |-------|
3412 */
3413void
3414xfs_iext_remove_indirect(
3415 xfs_ifork_t *ifp, /* inode fork pointer */
3416 xfs_extnum_t idx, /* index to begin removing extents */
3417 int count) /* number of extents to remove */
3418{
3419 xfs_ext_irec_t *erp; /* indirection array pointer */
3420 int erp_idx = 0; /* indirection array index */
3421 xfs_extnum_t ext_cnt; /* extents left to remove */
3422 xfs_extnum_t ext_diff; /* extents to remove in current list */
3423 xfs_extnum_t nex1; /* number of extents before idx */
3424 xfs_extnum_t nex2; /* extents after idx + count */
3425 int page_idx = idx; /* index in target extent list */
3426
3427 ASSERT(ifp->if_flags & XFS_IFEXTIREC);
3428 erp = xfs_iext_idx_to_irec(ifp, &page_idx, &erp_idx, 0);
3429 ASSERT(erp != NULL);
3430 nex1 = page_idx;
3431 ext_cnt = count;
3432 while (ext_cnt) {
3433 nex2 = MAX((erp->er_extcount - (nex1 + ext_cnt)), 0);
3434 ext_diff = MIN(ext_cnt, (erp->er_extcount - nex1));
3435 /*
3436 * Check for deletion of entire list;
3437 * xfs_iext_irec_remove() updates extent offsets.
3438 */
3439 if (ext_diff == erp->er_extcount) {
3440 xfs_iext_irec_remove(ifp, erp_idx);
3441 ext_cnt -= ext_diff;
3442 nex1 = 0;
3443 if (ext_cnt) {
3444 ASSERT(erp_idx < ifp->if_real_bytes /
3445 XFS_IEXT_BUFSZ);
3446 erp = &ifp->if_u1.if_ext_irec[erp_idx];
3447 nex1 = 0;
3448 continue;
3449 } else {
3450 break;
3451 }
3452 }
3453 /* Move extents up (if needed) */
3454 if (nex2) {
3455 memmove(&erp->er_extbuf[nex1],
3456 &erp->er_extbuf[nex1 + ext_diff],
3457 nex2 * sizeof(xfs_bmbt_rec_t));
3458 }
3459 /* Zero out rest of page */
3460 memset(&erp->er_extbuf[nex1 + nex2], 0, (XFS_IEXT_BUFSZ -
3461 ((nex1 + nex2) * sizeof(xfs_bmbt_rec_t))));
3462 /* Update remaining counters */
3463 erp->er_extcount -= ext_diff;
3464 xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, -ext_diff);
3465 ext_cnt -= ext_diff;
3466 nex1 = 0;
3467 erp_idx++;
3468 erp++;
3469 }
3470 ifp->if_bytes -= count * sizeof(xfs_bmbt_rec_t);
3471 xfs_iext_irec_compact(ifp);
3472}
3473
3474/*
3475 * Create, destroy, or resize a linear (direct) block of extents.
3476 */
3477void
3478xfs_iext_realloc_direct(
3479 xfs_ifork_t *ifp, /* inode fork pointer */
3480 int new_size) /* new size of extents */
3481{
3482 int rnew_size; /* real new size of extents */
3483
3484 rnew_size = new_size;
3485
3486 ASSERT(!(ifp->if_flags & XFS_IFEXTIREC) ||
3487 ((new_size >= 0) && (new_size <= XFS_IEXT_BUFSZ) &&
3488 (new_size != ifp->if_real_bytes)));
3489
3490 /* Free extent records */
3491 if (new_size == 0) {
3492 xfs_iext_destroy(ifp);
3493 }
3494 /* Resize direct extent list and zero any new bytes */
3495 else if (ifp->if_real_bytes) {
3496 /* Check if extents will fit inside the inode */
3497 if (new_size <= XFS_INLINE_EXTS * sizeof(xfs_bmbt_rec_t)) {
3498 xfs_iext_direct_to_inline(ifp, new_size /
3499 (uint)sizeof(xfs_bmbt_rec_t));
3500 ifp->if_bytes = new_size;
3501 return;
3502 }
3503 if (!is_power_of_2(new_size)){
3504 rnew_size = roundup_pow_of_two(new_size);
3505 }
3506 if (rnew_size != ifp->if_real_bytes) {
3507 ifp->if_u1.if_extents =
3508 kmem_realloc(ifp->if_u1.if_extents,
3509 rnew_size,
3510 ifp->if_real_bytes, KM_NOFS);
3511 }
3512 if (rnew_size > ifp->if_real_bytes) {
3513 memset(&ifp->if_u1.if_extents[ifp->if_bytes /
3514 (uint)sizeof(xfs_bmbt_rec_t)], 0,
3515 rnew_size - ifp->if_real_bytes);
3516 }
3517 }
3518 /*
3519 * Switch from the inline extent buffer to a direct
3520 * extent list. Be sure to include the inline extent
3521 * bytes in new_size.
3522 */
3523 else {
3524 new_size += ifp->if_bytes;
3525 if (!is_power_of_2(new_size)) {
3526 rnew_size = roundup_pow_of_two(new_size);
3527 }
3528 xfs_iext_inline_to_direct(ifp, rnew_size);
3529 }
3530 ifp->if_real_bytes = rnew_size;
3531 ifp->if_bytes = new_size;
3532}
3533
3534/*
3535 * Switch from linear (direct) extent records to inline buffer.
3536 */
3537void
3538xfs_iext_direct_to_inline(
3539 xfs_ifork_t *ifp, /* inode fork pointer */
3540 xfs_extnum_t nextents) /* number of extents in file */
3541{
3542 ASSERT(ifp->if_flags & XFS_IFEXTENTS);
3543 ASSERT(nextents <= XFS_INLINE_EXTS);
3544 /*
3545 * The inline buffer was zeroed when we switched
3546 * from inline to direct extent allocation mode,
3547 * so we don't need to clear it here.
3548 */
3549 memcpy(ifp->if_u2.if_inline_ext, ifp->if_u1.if_extents,
3550 nextents * sizeof(xfs_bmbt_rec_t));
3551 kmem_free(ifp->if_u1.if_extents);
3552 ifp->if_u1.if_extents = ifp->if_u2.if_inline_ext;
3553 ifp->if_real_bytes = 0;
3554}
3555
3556/*
3557 * Switch from inline buffer to linear (direct) extent records.
3558 * new_size should already be rounded up to the next power of 2
3559 * by the caller (when appropriate), so use new_size as it is.
3560 * However, since new_size may be rounded up, we can't update
3561 * if_bytes here. It is the caller's responsibility to update
3562 * if_bytes upon return.
3563 */
3564void
3565xfs_iext_inline_to_direct(
3566 xfs_ifork_t *ifp, /* inode fork pointer */
3567 int new_size) /* number of extents in file */
3568{
3569 ifp->if_u1.if_extents = kmem_alloc(new_size, KM_NOFS);
3570 memset(ifp->if_u1.if_extents, 0, new_size);
3571 if (ifp->if_bytes) {
3572 memcpy(ifp->if_u1.if_extents, ifp->if_u2.if_inline_ext,
3573 ifp->if_bytes);
3574 memset(ifp->if_u2.if_inline_ext, 0, XFS_INLINE_EXTS *
3575 sizeof(xfs_bmbt_rec_t));
3576 }
3577 ifp->if_real_bytes = new_size;
3578}
3579
3580/*
3581 * Resize an extent indirection array to new_size bytes.
3582 */
3583STATIC void
3584xfs_iext_realloc_indirect(
3585 xfs_ifork_t *ifp, /* inode fork pointer */
3586 int new_size) /* new indirection array size */
3587{
3588 int nlists; /* number of irec's (ex lists) */
3589 int size; /* current indirection array size */
3590
3591 ASSERT(ifp->if_flags & XFS_IFEXTIREC);
3592 nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
3593 size = nlists * sizeof(xfs_ext_irec_t);
3594 ASSERT(ifp->if_real_bytes);
3595 ASSERT((new_size >= 0) && (new_size != size));
3596 if (new_size == 0) {
3597 xfs_iext_destroy(ifp);
3598 } else {
3599 ifp->if_u1.if_ext_irec = (xfs_ext_irec_t *)
3600 kmem_realloc(ifp->if_u1.if_ext_irec,
3601 new_size, size, KM_NOFS);
3602 }
3603}
3604
3605/*
3606 * Switch from indirection array to linear (direct) extent allocations.
3607 */
3608STATIC void
3609xfs_iext_indirect_to_direct(
3610 xfs_ifork_t *ifp) /* inode fork pointer */
3611{
3612 xfs_bmbt_rec_host_t *ep; /* extent record pointer */
3613 xfs_extnum_t nextents; /* number of extents in file */
3614 int size; /* size of file extents */
3615
3616 ASSERT(ifp->if_flags & XFS_IFEXTIREC);
3617 nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
3618 ASSERT(nextents <= XFS_LINEAR_EXTS);
3619 size = nextents * sizeof(xfs_bmbt_rec_t);
3620
3621 xfs_iext_irec_compact_pages(ifp);
3622 ASSERT(ifp->if_real_bytes == XFS_IEXT_BUFSZ);
3623
3624 ep = ifp->if_u1.if_ext_irec->er_extbuf;
3625 kmem_free(ifp->if_u1.if_ext_irec);
3626 ifp->if_flags &= ~XFS_IFEXTIREC;
3627 ifp->if_u1.if_extents = ep;
3628 ifp->if_bytes = size;
3629 if (nextents < XFS_LINEAR_EXTS) {
3630 xfs_iext_realloc_direct(ifp, size);
3631 }
3632}
3633
3634/*
3635 * Free incore file extents.
3636 */
3637void
3638xfs_iext_destroy(
3639 xfs_ifork_t *ifp) /* inode fork pointer */
3640{
3641 if (ifp->if_flags & XFS_IFEXTIREC) {
3642 int erp_idx;
3643 int nlists;
3644
3645 nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
3646 for (erp_idx = nlists - 1; erp_idx >= 0 ; erp_idx--) {
3647 xfs_iext_irec_remove(ifp, erp_idx);
3648 }
3649 ifp->if_flags &= ~XFS_IFEXTIREC;
3650 } else if (ifp->if_real_bytes) {
3651 kmem_free(ifp->if_u1.if_extents);
3652 } else if (ifp->if_bytes) {
3653 memset(ifp->if_u2.if_inline_ext, 0, XFS_INLINE_EXTS *
3654 sizeof(xfs_bmbt_rec_t));
3655 }
3656 ifp->if_u1.if_extents = NULL;
3657 ifp->if_real_bytes = 0;
3658 ifp->if_bytes = 0;
3659}
3660
3661/*
3662 * Return a pointer to the extent record for file system block bno.
3663 */
3664xfs_bmbt_rec_host_t * /* pointer to found extent record */
3665xfs_iext_bno_to_ext(
3666 xfs_ifork_t *ifp, /* inode fork pointer */
3667 xfs_fileoff_t bno, /* block number to search for */
3668 xfs_extnum_t *idxp) /* index of target extent */
3669{
3670 xfs_bmbt_rec_host_t *base; /* pointer to first extent */
3671 xfs_filblks_t blockcount = 0; /* number of blocks in extent */
3672 xfs_bmbt_rec_host_t *ep = NULL; /* pointer to target extent */
3673 xfs_ext_irec_t *erp = NULL; /* indirection array pointer */
3674 int high; /* upper boundary in search */
3675 xfs_extnum_t idx = 0; /* index of target extent */
3676 int low; /* lower boundary in search */
3677 xfs_extnum_t nextents; /* number of file extents */
3678 xfs_fileoff_t startoff = 0; /* start offset of extent */
3679
3680 nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
3681 if (nextents == 0) {
3682 *idxp = 0;
3683 return NULL;
3684 }
3685 low = 0;
3686 if (ifp->if_flags & XFS_IFEXTIREC) {
3687 /* Find target extent list */
3688 int erp_idx = 0;
3689 erp = xfs_iext_bno_to_irec(ifp, bno, &erp_idx);
3690 base = erp->er_extbuf;
3691 high = erp->er_extcount - 1;
3692 } else {
3693 base = ifp->if_u1.if_extents;
3694 high = nextents - 1;
3695 }
3696 /* Binary search extent records */
3697 while (low <= high) {
3698 idx = (low + high) >> 1;
3699 ep = base + idx;
3700 startoff = xfs_bmbt_get_startoff(ep);
3701 blockcount = xfs_bmbt_get_blockcount(ep);
3702 if (bno < startoff) {
3703 high = idx - 1;
3704 } else if (bno >= startoff + blockcount) {
3705 low = idx + 1;
3706 } else {
3707 /* Convert back to file-based extent index */
3708 if (ifp->if_flags & XFS_IFEXTIREC) {
3709 idx += erp->er_extoff;
3710 }
3711 *idxp = idx;
3712 return ep;
3713 }
3714 }
3715 /* Convert back to file-based extent index */
3716 if (ifp->if_flags & XFS_IFEXTIREC) {
3717 idx += erp->er_extoff;
3718 }
3719 if (bno >= startoff + blockcount) {
3720 if (++idx == nextents) {
3721 ep = NULL;
3722 } else {
3723 ep = xfs_iext_get_ext(ifp, idx);
3724 }
3725 }
3726 *idxp = idx;
3727 return ep;
3728}
3729
3730/*
3731 * Return a pointer to the indirection array entry containing the
3732 * extent record for filesystem block bno. Store the index of the
3733 * target irec in *erp_idxp.
3734 */
3735xfs_ext_irec_t * /* pointer to found extent record */
3736xfs_iext_bno_to_irec(
3737 xfs_ifork_t *ifp, /* inode fork pointer */
3738 xfs_fileoff_t bno, /* block number to search for */
3739 int *erp_idxp) /* irec index of target ext list */
3740{
3741 xfs_ext_irec_t *erp = NULL; /* indirection array pointer */
3742 xfs_ext_irec_t *erp_next; /* next indirection array entry */
3743 int erp_idx; /* indirection array index */
3744 int nlists; /* number of extent irec's (lists) */
3745 int high; /* binary search upper limit */
3746 int low; /* binary search lower limit */
3747
3748 ASSERT(ifp->if_flags & XFS_IFEXTIREC);
3749 nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
3750 erp_idx = 0;
3751 low = 0;
3752 high = nlists - 1;
3753 while (low <= high) {
3754 erp_idx = (low + high) >> 1;
3755 erp = &ifp->if_u1.if_ext_irec[erp_idx];
3756 erp_next = erp_idx < nlists - 1 ? erp + 1 : NULL;
3757 if (bno < xfs_bmbt_get_startoff(erp->er_extbuf)) {
3758 high = erp_idx - 1;
3759 } else if (erp_next && bno >=
3760 xfs_bmbt_get_startoff(erp_next->er_extbuf)) {
3761 low = erp_idx + 1;
3762 } else {
3763 break;
3764 }
3765 }
3766 *erp_idxp = erp_idx;
3767 return erp;
3768}
3769
3770/*
3771 * Return a pointer to the indirection array entry containing the
3772 * extent record at file extent index *idxp. Store the index of the
3773 * target irec in *erp_idxp and store the page index of the target
3774 * extent record in *idxp.
3775 */
3776xfs_ext_irec_t *
3777xfs_iext_idx_to_irec(
3778 xfs_ifork_t *ifp, /* inode fork pointer */
3779 xfs_extnum_t *idxp, /* extent index (file -> page) */
3780 int *erp_idxp, /* pointer to target irec */
3781 int realloc) /* new bytes were just added */
3782{
3783 xfs_ext_irec_t *prev; /* pointer to previous irec */
3784 xfs_ext_irec_t *erp = NULL; /* pointer to current irec */
3785 int erp_idx; /* indirection array index */
3786 int nlists; /* number of irec's (ex lists) */
3787 int high; /* binary search upper limit */
3788 int low; /* binary search lower limit */
3789 xfs_extnum_t page_idx = *idxp; /* extent index in target list */
3790
3791 ASSERT(ifp->if_flags & XFS_IFEXTIREC);
3792 ASSERT(page_idx >= 0);
3793 ASSERT(page_idx <= ifp->if_bytes / sizeof(xfs_bmbt_rec_t));
3794 ASSERT(page_idx < ifp->if_bytes / sizeof(xfs_bmbt_rec_t) || realloc);
3795
3796 nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
3797 erp_idx = 0;
3798 low = 0;
3799 high = nlists - 1;
3800
3801 /* Binary search extent irec's */
3802 while (low <= high) {
3803 erp_idx = (low + high) >> 1;
3804 erp = &ifp->if_u1.if_ext_irec[erp_idx];
3805 prev = erp_idx > 0 ? erp - 1 : NULL;
3806 if (page_idx < erp->er_extoff || (page_idx == erp->er_extoff &&
3807 realloc && prev && prev->er_extcount < XFS_LINEAR_EXTS)) {
3808 high = erp_idx - 1;
3809 } else if (page_idx > erp->er_extoff + erp->er_extcount ||
3810 (page_idx == erp->er_extoff + erp->er_extcount &&
3811 !realloc)) {
3812 low = erp_idx + 1;
3813 } else if (page_idx == erp->er_extoff + erp->er_extcount &&
3814 erp->er_extcount == XFS_LINEAR_EXTS) {
3815 ASSERT(realloc);
3816 page_idx = 0;
3817 erp_idx++;
3818 erp = erp_idx < nlists ? erp + 1 : NULL;
3819 break;
3820 } else {
3821 page_idx -= erp->er_extoff;
3822 break;
3823 }
3824 }
3825 *idxp = page_idx;
3826 *erp_idxp = erp_idx;
3827 return(erp);
3828}
3829
3830/*
3831 * Allocate and initialize an indirection array once the space needed
3832 * for incore extents increases above XFS_IEXT_BUFSZ.
3833 */
3834void
3835xfs_iext_irec_init(
3836 xfs_ifork_t *ifp) /* inode fork pointer */
3837{
3838 xfs_ext_irec_t *erp; /* indirection array pointer */
3839 xfs_extnum_t nextents; /* number of extents in file */
3840
3841 ASSERT(!(ifp->if_flags & XFS_IFEXTIREC));
3842 nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
3843 ASSERT(nextents <= XFS_LINEAR_EXTS);
3844
3845 erp = kmem_alloc(sizeof(xfs_ext_irec_t), KM_NOFS);
3846
3847 if (nextents == 0) {
3848 ifp->if_u1.if_extents = kmem_alloc(XFS_IEXT_BUFSZ, KM_NOFS);
3849 } else if (!ifp->if_real_bytes) {
3850 xfs_iext_inline_to_direct(ifp, XFS_IEXT_BUFSZ);
3851 } else if (ifp->if_real_bytes < XFS_IEXT_BUFSZ) {
3852 xfs_iext_realloc_direct(ifp, XFS_IEXT_BUFSZ);
3853 }
3854 erp->er_extbuf = ifp->if_u1.if_extents;
3855 erp->er_extcount = nextents;
3856 erp->er_extoff = 0;
3857
3858 ifp->if_flags |= XFS_IFEXTIREC;
3859 ifp->if_real_bytes = XFS_IEXT_BUFSZ;
3860 ifp->if_bytes = nextents * sizeof(xfs_bmbt_rec_t);
3861 ifp->if_u1.if_ext_irec = erp;
3862
3863 return;
3864}
3865
3866/*
3867 * Allocate and initialize a new entry in the indirection array.
3868 */
3869xfs_ext_irec_t *
3870xfs_iext_irec_new(
3871 xfs_ifork_t *ifp, /* inode fork pointer */
3872 int erp_idx) /* index for new irec */
3873{
3874 xfs_ext_irec_t *erp; /* indirection array pointer */
3875 int i; /* loop counter */
3876 int nlists; /* number of irec's (ex lists) */
3877
3878 ASSERT(ifp->if_flags & XFS_IFEXTIREC);
3879 nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
3880
3881 /* Resize indirection array */
3882 xfs_iext_realloc_indirect(ifp, ++nlists *
3883 sizeof(xfs_ext_irec_t));
3884 /*
3885 * Move records down in the array so the
3886 * new page can use erp_idx.
3887 */
3888 erp = ifp->if_u1.if_ext_irec;
3889 for (i = nlists - 1; i > erp_idx; i--) {
3890 memmove(&erp[i], &erp[i-1], sizeof(xfs_ext_irec_t));
3891 }
3892 ASSERT(i == erp_idx);
3893
3894 /* Initialize new extent record */
3895 erp = ifp->if_u1.if_ext_irec;
3896 erp[erp_idx].er_extbuf = kmem_alloc(XFS_IEXT_BUFSZ, KM_NOFS);
3897 ifp->if_real_bytes = nlists * XFS_IEXT_BUFSZ;
3898 memset(erp[erp_idx].er_extbuf, 0, XFS_IEXT_BUFSZ);
3899 erp[erp_idx].er_extcount = 0;
3900 erp[erp_idx].er_extoff = erp_idx > 0 ?
3901 erp[erp_idx-1].er_extoff + erp[erp_idx-1].er_extcount : 0;
3902 return (&erp[erp_idx]);
3903}
3904
3905/*
3906 * Remove a record from the indirection array.
3907 */
3908void
3909xfs_iext_irec_remove(
3910 xfs_ifork_t *ifp, /* inode fork pointer */
3911 int erp_idx) /* irec index to remove */
3912{
3913 xfs_ext_irec_t *erp; /* indirection array pointer */
3914 int i; /* loop counter */
3915 int nlists; /* number of irec's (ex lists) */
3916
3917 ASSERT(ifp->if_flags & XFS_IFEXTIREC);
3918 nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
3919 erp = &ifp->if_u1.if_ext_irec[erp_idx];
3920 if (erp->er_extbuf) {
3921 xfs_iext_irec_update_extoffs(ifp, erp_idx + 1,
3922 -erp->er_extcount);
3923 kmem_free(erp->er_extbuf);
3924 }
3925 /* Compact extent records */
3926 erp = ifp->if_u1.if_ext_irec;
3927 for (i = erp_idx; i < nlists - 1; i++) {
3928 memmove(&erp[i], &erp[i+1], sizeof(xfs_ext_irec_t));
3929 }
3930 /*
3931 * Manually free the last extent record from the indirection
3932 * array. A call to xfs_iext_realloc_indirect() with a size
3933 * of zero would result in a call to xfs_iext_destroy() which
3934 * would in turn call this function again, creating a nasty
3935 * infinite loop.
3936 */
3937 if (--nlists) {
3938 xfs_iext_realloc_indirect(ifp,
3939 nlists * sizeof(xfs_ext_irec_t));
3940 } else {
3941 kmem_free(ifp->if_u1.if_ext_irec);
3942 }
3943 ifp->if_real_bytes = nlists * XFS_IEXT_BUFSZ;
3944}
3945
3946/*
3947 * This is called to clean up large amounts of unused memory allocated
3948 * by the indirection array. Before compacting anything though, verify
3949 * that the indirection array is still needed and switch back to the
3950 * linear extent list (or even the inline buffer) if possible. The
3951 * compaction policy is as follows:
3952 *
3953 * Full Compaction: Extents fit into a single page (or inline buffer)
3954 * Partial Compaction: Extents occupy less than 50% of allocated space
3955 * No Compaction: Extents occupy at least 50% of allocated space
3956 */
3957void
3958xfs_iext_irec_compact(
3959 xfs_ifork_t *ifp) /* inode fork pointer */
3960{
3961 xfs_extnum_t nextents; /* number of extents in file */
3962 int nlists; /* number of irec's (ex lists) */
3963
3964 ASSERT(ifp->if_flags & XFS_IFEXTIREC);
3965 nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
3966 nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
3967
3968 if (nextents == 0) {
3969 xfs_iext_destroy(ifp);
3970 } else if (nextents <= XFS_INLINE_EXTS) {
3971 xfs_iext_indirect_to_direct(ifp);
3972 xfs_iext_direct_to_inline(ifp, nextents);
3973 } else if (nextents <= XFS_LINEAR_EXTS) {
3974 xfs_iext_indirect_to_direct(ifp);
3975 } else if (nextents < (nlists * XFS_LINEAR_EXTS) >> 1) {
3976 xfs_iext_irec_compact_pages(ifp);
3977 }
3978}
3979
3980/*
3981 * Combine extents from neighboring extent pages.
3982 */
3983void
3984xfs_iext_irec_compact_pages(
3985 xfs_ifork_t *ifp) /* inode fork pointer */
3986{
3987 xfs_ext_irec_t *erp, *erp_next;/* pointers to irec entries */
3988 int erp_idx = 0; /* indirection array index */
3989 int nlists; /* number of irec's (ex lists) */
3990
3991 ASSERT(ifp->if_flags & XFS_IFEXTIREC);
3992 nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
3993 while (erp_idx < nlists - 1) {
3994 erp = &ifp->if_u1.if_ext_irec[erp_idx];
3995 erp_next = erp + 1;
3996 if (erp_next->er_extcount <=
3997 (XFS_LINEAR_EXTS - erp->er_extcount)) {
3998 memcpy(&erp->er_extbuf[erp->er_extcount],
3999 erp_next->er_extbuf, erp_next->er_extcount *
4000 sizeof(xfs_bmbt_rec_t));
4001 erp->er_extcount += erp_next->er_extcount;
4002 /*
4003 * Free page before removing extent record
4004 * so er_extoffs don't get modified in
4005 * xfs_iext_irec_remove.
4006 */
4007 kmem_free(erp_next->er_extbuf);
4008 erp_next->er_extbuf = NULL;
4009 xfs_iext_irec_remove(ifp, erp_idx + 1);
4010 nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
4011 } else {
4012 erp_idx++;
4013 }
4014 }
4015}
4016
4017/*
4018 * This is called to update the er_extoff field in the indirection
4019 * array when extents have been added or removed from one of the
4020 * extent lists. erp_idx contains the irec index to begin updating
4021 * at and ext_diff contains the number of extents that were added
4022 * or removed.
4023 */
4024void
4025xfs_iext_irec_update_extoffs(
4026 xfs_ifork_t *ifp, /* inode fork pointer */
4027 int erp_idx, /* irec index to update */
4028 int ext_diff) /* number of new extents */
4029{
4030 int i; /* loop counter */
4031 int nlists; /* number of irec's (ex lists */
4032
4033 ASSERT(ifp->if_flags & XFS_IFEXTIREC);
4034 nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
4035 for (i = erp_idx; i < nlists; i++) {
4036 ifp->if_u1.if_ext_irec[i].er_extoff += ext_diff;
4037 }
4038}
4039
4040/*
4041 * Test whether it is appropriate to check an inode for and free post EOF 2170 * Test whether it is appropriate to check an inode for and free post EOF
4042 * blocks. The 'force' parameter determines whether we should also consider 2171 * blocks. The 'force' parameter determines whether we should also consider
4043 * regular files that are marked preallocated or append-only. 2172 * regular files that are marked preallocated or append-only.
@@ -4072,4 +2201,3 @@ xfs_can_free_eofblocks(struct xfs_inode *ip, bool force)
4072 2201
4073 return true; 2202 return true;
4074} 2203}
4075