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.c1303
1 files changed, 1161 insertions, 142 deletions
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 1d7f5a7e063e..88a517fad07b 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/*
@@ -252,7 +253,8 @@ xfs_itobp(
252 xfs_inode_t *ip, 253 xfs_inode_t *ip,
253 xfs_dinode_t **dipp, 254 xfs_dinode_t **dipp,
254 xfs_buf_t **bpp, 255 xfs_buf_t **bpp,
255 xfs_daddr_t bno) 256 xfs_daddr_t bno,
257 uint imap_flags)
256{ 258{
257 xfs_buf_t *bp; 259 xfs_buf_t *bp;
258 int error; 260 int error;
@@ -268,10 +270,9 @@ xfs_itobp(
268 * inode on disk. 270 * inode on disk.
269 */ 271 */
270 imap.im_blkno = bno; 272 imap.im_blkno = bno;
271 error = xfs_imap(mp, tp, ip->i_ino, &imap, XFS_IMAP_LOOKUP); 273 if ((error = xfs_imap(mp, tp, ip->i_ino, &imap,
272 if (error != 0) { 274 XFS_IMAP_LOOKUP | imap_flags)))
273 return error; 275 return error;
274 }
275 276
276 /* 277 /*
277 * If the inode number maps to a block outside the bounds 278 * If the inode number maps to a block outside the bounds
@@ -335,9 +336,10 @@ xfs_itobp(
335 * (if DEBUG kernel) or the first inode in the buffer, otherwise. 336 * (if DEBUG kernel) or the first inode in the buffer, otherwise.
336 */ 337 */
337#ifdef DEBUG 338#ifdef DEBUG
338 ni = BBTOB(imap.im_len) >> mp->m_sb.sb_inodelog; 339 ni = (imap_flags & XFS_IMAP_BULKSTAT) ? 0 :
340 (BBTOB(imap.im_len) >> mp->m_sb.sb_inodelog);
339#else 341#else
340 ni = 1; 342 ni = (imap_flags & XFS_IMAP_BULKSTAT) ? 0 : 1;
341#endif 343#endif
342 for (i = 0; i < ni; i++) { 344 for (i = 0; i < ni; i++) {
343 int di_ok; 345 int di_ok;
@@ -504,7 +506,7 @@ xfs_iformat(
504 switch (INT_GET(dip->di_core.di_aformat, ARCH_CONVERT)) { 506 switch (INT_GET(dip->di_core.di_aformat, ARCH_CONVERT)) {
505 case XFS_DINODE_FMT_LOCAL: 507 case XFS_DINODE_FMT_LOCAL:
506 atp = (xfs_attr_shortform_t *)XFS_DFORK_APTR(dip); 508 atp = (xfs_attr_shortform_t *)XFS_DFORK_APTR(dip);
507 size = (int)INT_GET(atp->hdr.totsize, ARCH_CONVERT); 509 size = be16_to_cpu(atp->hdr.totsize);
508 error = xfs_iformat_local(ip, dip, XFS_ATTR_FORK, size); 510 error = xfs_iformat_local(ip, dip, XFS_ATTR_FORK, size);
509 break; 511 break;
510 case XFS_DINODE_FMT_EXTENTS: 512 case XFS_DINODE_FMT_EXTENTS:
@@ -597,7 +599,6 @@ xfs_iformat_extents(
597 xfs_bmbt_rec_t *ep, *dp; 599 xfs_bmbt_rec_t *ep, *dp;
598 xfs_ifork_t *ifp; 600 xfs_ifork_t *ifp;
599 int nex; 601 int nex;
600 int real_size;
601 int size; 602 int size;
602 int i; 603 int i;
603 604
@@ -619,23 +620,20 @@ xfs_iformat_extents(
619 return XFS_ERROR(EFSCORRUPTED); 620 return XFS_ERROR(EFSCORRUPTED);
620 } 621 }
621 622
622 real_size = 0; 623 ifp->if_real_bytes = 0;
623 if (nex == 0) 624 if (nex == 0)
624 ifp->if_u1.if_extents = NULL; 625 ifp->if_u1.if_extents = NULL;
625 else if (nex <= XFS_INLINE_EXTS) 626 else if (nex <= XFS_INLINE_EXTS)
626 ifp->if_u1.if_extents = ifp->if_u2.if_inline_ext; 627 ifp->if_u1.if_extents = ifp->if_u2.if_inline_ext;
627 else { 628 else
628 ifp->if_u1.if_extents = kmem_alloc(size, KM_SLEEP); 629 xfs_iext_add(ifp, 0, nex);
629 ASSERT(ifp->if_u1.if_extents != NULL); 630
630 real_size = size;
631 }
632 ifp->if_bytes = size; 631 ifp->if_bytes = size;
633 ifp->if_real_bytes = real_size;
634 if (size) { 632 if (size) {
635 dp = (xfs_bmbt_rec_t *) XFS_DFORK_PTR(dip, whichfork); 633 dp = (xfs_bmbt_rec_t *) XFS_DFORK_PTR(dip, whichfork);
636 xfs_validate_extents(dp, nex, 1, XFS_EXTFMT_INODE(ip)); 634 xfs_validate_extents(ifp, nex, 1, XFS_EXTFMT_INODE(ip));
637 ep = ifp->if_u1.if_extents; 635 for (i = 0; i < nex; i++, dp++) {
638 for (i = 0; i < nex; i++, ep++, dp++) { 636 ep = xfs_iext_get_ext(ifp, i);
639 ep->l0 = INT_GET(get_unaligned((__uint64_t*)&dp->l0), 637 ep->l0 = INT_GET(get_unaligned((__uint64_t*)&dp->l0),
640 ARCH_CONVERT); 638 ARCH_CONVERT);
641 ep->l1 = INT_GET(get_unaligned((__uint64_t*)&dp->l1), 639 ep->l1 = INT_GET(get_unaligned((__uint64_t*)&dp->l1),
@@ -646,7 +644,7 @@ xfs_iformat_extents(
646 if (whichfork != XFS_DATA_FORK || 644 if (whichfork != XFS_DATA_FORK ||
647 XFS_EXTFMT_INODE(ip) == XFS_EXTFMT_NOSTATE) 645 XFS_EXTFMT_INODE(ip) == XFS_EXTFMT_NOSTATE)
648 if (unlikely(xfs_check_nostate_extents( 646 if (unlikely(xfs_check_nostate_extents(
649 ifp->if_u1.if_extents, nex))) { 647 ifp, 0, nex))) {
650 XFS_ERROR_REPORT("xfs_iformat_extents(2)", 648 XFS_ERROR_REPORT("xfs_iformat_extents(2)",
651 XFS_ERRLEVEL_LOW, 649 XFS_ERRLEVEL_LOW,
652 ip->i_mount); 650 ip->i_mount);
@@ -871,9 +869,8 @@ xfs_iread(
871 * return NULL as well. Set i_blkno to 0 so that xfs_itobp() will 869 * return NULL as well. Set i_blkno to 0 so that xfs_itobp() will
872 * know that this is a new incore inode. 870 * know that this is a new incore inode.
873 */ 871 */
874 error = xfs_itobp(mp, tp, ip, &dip, &bp, bno); 872 error = xfs_itobp(mp, tp, ip, &dip, &bp, bno, 0);
875 873 if (error) {
876 if (error != 0) {
877 kmem_zone_free(xfs_inode_zone, ip); 874 kmem_zone_free(xfs_inode_zone, ip);
878 return error; 875 return error;
879 } 876 }
@@ -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
@@ -1376,10 +1372,10 @@ xfs_itrunc_trace(
1376 (void*)(unsigned long)((toss_finish >> 32) & 0xffffffff), 1372 (void*)(unsigned long)((toss_finish >> 32) & 0xffffffff),
1377 (void*)(unsigned long)(toss_finish & 0xffffffff), 1373 (void*)(unsigned long)(toss_finish & 0xffffffff),
1378 (void*)(unsigned long)current_cpu(), 1374 (void*)(unsigned long)current_cpu(),
1379 (void*)0, 1375 (void*)(unsigned long)current_pid(),
1380 (void*)0, 1376 (void*)NULL,
1381 (void*)0, 1377 (void*)NULL,
1382 (void*)0); 1378 (void*)NULL);
1383} 1379}
1384#else 1380#else
1385#define xfs_itrunc_trace(tag, ip, flag, new_size, toss_start, toss_finish) 1381#define xfs_itrunc_trace(tag, ip, flag, new_size, toss_start, toss_finish)
@@ -1397,6 +1393,16 @@ xfs_itrunc_trace(
1397 * calling into the buffer/page cache code and we can't hold the 1393 * calling into the buffer/page cache code and we can't hold the
1398 * inode lock when we do so. 1394 * inode lock when we do so.
1399 * 1395 *
1396 * We need to wait for any direct I/Os in flight to complete before we
1397 * proceed with the truncate. This is needed to prevent the extents
1398 * being read or written by the direct I/Os from being removed while the
1399 * I/O is in flight as there is no other method of synchronising
1400 * direct I/O with the truncate operation. Also, because we hold
1401 * the IOLOCK in exclusive mode, we prevent new direct I/Os from being
1402 * started until the truncate completes and drops the lock. Essentially,
1403 * the vn_iowait() call forms an I/O barrier that provides strict ordering
1404 * between direct I/Os and the truncate operation.
1405 *
1400 * The flags parameter can have either the value XFS_ITRUNC_DEFINITE 1406 * The flags parameter can have either the value XFS_ITRUNC_DEFINITE
1401 * or XFS_ITRUNC_MAYBE. The XFS_ITRUNC_MAYBE value should be used 1407 * or XFS_ITRUNC_MAYBE. The XFS_ITRUNC_MAYBE value should be used
1402 * in the case that the caller is locking things out of order and 1408 * in the case that the caller is locking things out of order and
@@ -1424,6 +1430,9 @@ xfs_itruncate_start(
1424 1430
1425 mp = ip->i_mount; 1431 mp = ip->i_mount;
1426 vp = XFS_ITOV(ip); 1432 vp = XFS_ITOV(ip);
1433
1434 vn_iowait(vp); /* wait for the completion of any pending DIOs */
1435
1427 /* 1436 /*
1428 * Call VOP_TOSS_PAGES() or VOP_FLUSHINVAL_PAGES() to get rid of pages and buffers 1437 * Call VOP_TOSS_PAGES() or VOP_FLUSHINVAL_PAGES() to get rid of pages and buffers
1429 * overlapping the region being removed. We have to use 1438 * overlapping the region being removed. We have to use
@@ -1899,7 +1908,7 @@ xfs_iunlink(
1899 * Here we put the head pointer into our next pointer, 1908 * Here we put the head pointer into our next pointer,
1900 * and then we fall through to point the head at us. 1909 * and then we fall through to point the head at us.
1901 */ 1910 */
1902 error = xfs_itobp(mp, tp, ip, &dip, &ibp, 0); 1911 error = xfs_itobp(mp, tp, ip, &dip, &ibp, 0, 0);
1903 if (error) { 1912 if (error) {
1904 return error; 1913 return error;
1905 } 1914 }
@@ -2008,7 +2017,7 @@ xfs_iunlink_remove(
2008 * of dealing with the buffer when there is no need to 2017 * of dealing with the buffer when there is no need to
2009 * change it. 2018 * change it.
2010 */ 2019 */
2011 error = xfs_itobp(mp, tp, ip, &dip, &ibp, 0); 2020 error = xfs_itobp(mp, tp, ip, &dip, &ibp, 0, 0);
2012 if (error) { 2021 if (error) {
2013 cmn_err(CE_WARN, 2022 cmn_err(CE_WARN,
2014 "xfs_iunlink_remove: xfs_itobp() returned an error %d on %s. Returning error.", 2023 "xfs_iunlink_remove: xfs_itobp() returned an error %d on %s. Returning error.",
@@ -2070,7 +2079,7 @@ xfs_iunlink_remove(
2070 * Now last_ibp points to the buffer previous to us on 2079 * Now last_ibp points to the buffer previous to us on
2071 * the unlinked list. Pull us from the list. 2080 * the unlinked list. Pull us from the list.
2072 */ 2081 */
2073 error = xfs_itobp(mp, tp, ip, &dip, &ibp, 0); 2082 error = xfs_itobp(mp, tp, ip, &dip, &ibp, 0, 0);
2074 if (error) { 2083 if (error) {
2075 cmn_err(CE_WARN, 2084 cmn_err(CE_WARN,
2076 "xfs_iunlink_remove: xfs_itobp() returned an error %d on %s. Returning error.", 2085 "xfs_iunlink_remove: xfs_itobp() returned an error %d on %s. Returning error.",
@@ -2476,92 +2485,6 @@ xfs_iroot_realloc(
2476 2485
2477 2486
2478/* 2487/*
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 2488 * This is called when the amount of space needed for if_data
2566 * is increased or decreased. The change in size is indicated by 2489 * 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 2490 * the number of bytes that need to be added or deleted in the
@@ -2720,12 +2643,11 @@ xfs_idestroy_fork(
2720 ifp->if_real_bytes = 0; 2643 ifp->if_real_bytes = 0;
2721 } 2644 }
2722 } else if ((ifp->if_flags & XFS_IFEXTENTS) && 2645 } else if ((ifp->if_flags & XFS_IFEXTENTS) &&
2723 (ifp->if_u1.if_extents != NULL) && 2646 ((ifp->if_flags & XFS_IFEXTIREC) ||
2724 (ifp->if_u1.if_extents != ifp->if_u2.if_inline_ext)) { 2647 ((ifp->if_u1.if_extents != NULL) &&
2648 (ifp->if_u1.if_extents != ifp->if_u2.if_inline_ext)))) {
2725 ASSERT(ifp->if_real_bytes != 0); 2649 ASSERT(ifp->if_real_bytes != 0);
2726 kmem_free(ifp->if_u1.if_extents, ifp->if_real_bytes); 2650 xfs_iext_destroy(ifp);
2727 ifp->if_u1.if_extents = NULL;
2728 ifp->if_real_bytes = 0;
2729 } 2651 }
2730 ASSERT(ifp->if_u1.if_extents == NULL || 2652 ASSERT(ifp->if_u1.if_extents == NULL ||
2731 ifp->if_u1.if_extents == ifp->if_u2.if_inline_ext); 2653 ifp->if_u1.if_extents == ifp->if_u2.if_inline_ext);
@@ -2814,7 +2736,7 @@ xfs_iunpin(
2814 2736
2815 /* make sync come back and flush this inode */ 2737 /* make sync come back and flush this inode */
2816 if (vp) { 2738 if (vp) {
2817 struct inode *inode = LINVFS_GET_IP(vp); 2739 struct inode *inode = vn_to_inode(vp);
2818 2740
2819 if (!(inode->i_state & I_NEW)) 2741 if (!(inode->i_state & I_NEW))
2820 mark_inode_dirty_sync(inode); 2742 mark_inode_dirty_sync(inode);
@@ -2902,16 +2824,15 @@ xfs_iextents_copy(
2902 * the delayed ones. There must be at least one 2824 * the delayed ones. There must be at least one
2903 * non-delayed extent. 2825 * non-delayed extent.
2904 */ 2826 */
2905 ep = ifp->if_u1.if_extents;
2906 dest_ep = buffer; 2827 dest_ep = buffer;
2907 copied = 0; 2828 copied = 0;
2908 for (i = 0; i < nrecs; i++) { 2829 for (i = 0; i < nrecs; i++) {
2830 ep = xfs_iext_get_ext(ifp, i);
2909 start_block = xfs_bmbt_get_startblock(ep); 2831 start_block = xfs_bmbt_get_startblock(ep);
2910 if (ISNULLSTARTBLOCK(start_block)) { 2832 if (ISNULLSTARTBLOCK(start_block)) {
2911 /* 2833 /*
2912 * It's a delayed allocation extent, so skip it. 2834 * It's a delayed allocation extent, so skip it.
2913 */ 2835 */
2914 ep++;
2915 continue; 2836 continue;
2916 } 2837 }
2917 2838
@@ -2921,11 +2842,10 @@ xfs_iextents_copy(
2921 put_unaligned(INT_GET(ep->l1, ARCH_CONVERT), 2842 put_unaligned(INT_GET(ep->l1, ARCH_CONVERT),
2922 (__uint64_t*)&dest_ep->l1); 2843 (__uint64_t*)&dest_ep->l1);
2923 dest_ep++; 2844 dest_ep++;
2924 ep++;
2925 copied++; 2845 copied++;
2926 } 2846 }
2927 ASSERT(copied != 0); 2847 ASSERT(copied != 0);
2928 xfs_validate_extents(buffer, copied, 1, XFS_EXTFMT_INODE(ip)); 2848 xfs_validate_extents(ifp, copied, 1, XFS_EXTFMT_INODE(ip));
2929 2849
2930 return (copied * (uint)sizeof(xfs_bmbt_rec_t)); 2850 return (copied * (uint)sizeof(xfs_bmbt_rec_t));
2931} 2851}
@@ -2995,8 +2915,10 @@ xfs_iflush_fork(
2995 case XFS_DINODE_FMT_EXTENTS: 2915 case XFS_DINODE_FMT_EXTENTS:
2996 ASSERT((ifp->if_flags & XFS_IFEXTENTS) || 2916 ASSERT((ifp->if_flags & XFS_IFEXTENTS) ||
2997 !(iip->ili_format.ilf_fields & extflag[whichfork])); 2917 !(iip->ili_format.ilf_fields & extflag[whichfork]));
2998 ASSERT((ifp->if_u1.if_extents != NULL) || (ifp->if_bytes == 0)); 2918 ASSERT((xfs_iext_get_ext(ifp, 0) != NULL) ||
2999 ASSERT((ifp->if_u1.if_extents == NULL) || (ifp->if_bytes > 0)); 2919 (ifp->if_bytes == 0));
2920 ASSERT((xfs_iext_get_ext(ifp, 0) == NULL) ||
2921 (ifp->if_bytes > 0));
3000 if ((iip->ili_format.ilf_fields & extflag[whichfork]) && 2922 if ((iip->ili_format.ilf_fields & extflag[whichfork]) &&
3001 (ifp->if_bytes > 0)) { 2923 (ifp->if_bytes > 0)) {
3002 ASSERT(XFS_IFORK_NEXTENTS(ip, whichfork) > 0); 2924 ASSERT(XFS_IFORK_NEXTENTS(ip, whichfork) > 0);
@@ -3114,8 +3036,8 @@ xfs_iflush(
3114 /* 3036 /*
3115 * Get the buffer containing the on-disk inode. 3037 * Get the buffer containing the on-disk inode.
3116 */ 3038 */
3117 error = xfs_itobp(mp, NULL, ip, &dip, &bp, 0); 3039 error = xfs_itobp(mp, NULL, ip, &dip, &bp, 0, 0);
3118 if (error != 0) { 3040 if (error) {
3119 xfs_ifunlock(ip); 3041 xfs_ifunlock(ip);
3120 return error; 3042 return error;
3121 } 3043 }
@@ -3610,7 +3532,7 @@ xfs_iaccess(
3610{ 3532{
3611 int error; 3533 int error;
3612 mode_t orgmode = mode; 3534 mode_t orgmode = mode;
3613 struct inode *inode = LINVFS_GET_IP(XFS_ITOV(ip)); 3535 struct inode *inode = vn_to_inode(XFS_ITOV(ip));
3614 3536
3615 if (mode & S_IWUSR) { 3537 if (mode & S_IWUSR) {
3616 umode_t imode = inode->i_mode; 3538 umode_t imode = inode->i_mode;
@@ -3704,3 +3626,1100 @@ 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); 3626 NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
3705} 3627}
3706#endif 3628#endif
3629
3630/*
3631 * Return a pointer to the extent record at file index idx.
3632 */
3633xfs_bmbt_rec_t *
3634xfs_iext_get_ext(
3635 xfs_ifork_t *ifp, /* inode fork pointer */
3636 xfs_extnum_t idx) /* index of target extent */
3637{
3638 ASSERT(idx >= 0);
3639 if ((ifp->if_flags & XFS_IFEXTIREC) && (idx == 0)) {
3640 return ifp->if_u1.if_ext_irec->er_extbuf;
3641 } else if (ifp->if_flags & XFS_IFEXTIREC) {
3642 xfs_ext_irec_t *erp; /* irec pointer */
3643 int erp_idx = 0; /* irec index */
3644 xfs_extnum_t page_idx = idx; /* ext index in target list */
3645
3646 erp = xfs_iext_idx_to_irec(ifp, &page_idx, &erp_idx, 0);
3647 return &erp->er_extbuf[page_idx];
3648 } else if (ifp->if_bytes) {
3649 return &ifp->if_u1.if_extents[idx];
3650 } else {
3651 return NULL;
3652 }
3653}
3654
3655/*
3656 * Insert new item(s) into the extent records for incore inode
3657 * fork 'ifp'. 'count' new items are inserted at index 'idx'.
3658 */
3659void
3660xfs_iext_insert(
3661 xfs_ifork_t *ifp, /* inode fork pointer */
3662 xfs_extnum_t idx, /* starting index of new items */
3663 xfs_extnum_t count, /* number of inserted items */
3664 xfs_bmbt_irec_t *new) /* items to insert */
3665{
3666 xfs_bmbt_rec_t *ep; /* extent record pointer */
3667 xfs_extnum_t i; /* extent record index */
3668
3669 ASSERT(ifp->if_flags & XFS_IFEXTENTS);
3670 xfs_iext_add(ifp, idx, count);
3671 for (i = idx; i < idx + count; i++, new++) {
3672 ep = xfs_iext_get_ext(ifp, i);
3673 xfs_bmbt_set_all(ep, new);
3674 }
3675}
3676
3677/*
3678 * This is called when the amount of space required for incore file
3679 * extents needs to be increased. The ext_diff parameter stores the
3680 * number of new extents being added and the idx parameter contains
3681 * the extent index where the new extents will be added. If the new
3682 * extents are being appended, then we just need to (re)allocate and
3683 * initialize the space. Otherwise, if the new extents are being
3684 * inserted into the middle of the existing entries, a bit more work
3685 * is required to make room for the new extents to be inserted. The
3686 * caller is responsible for filling in the new extent entries upon
3687 * return.
3688 */
3689void
3690xfs_iext_add(
3691 xfs_ifork_t *ifp, /* inode fork pointer */
3692 xfs_extnum_t idx, /* index to begin adding exts */
3693 int ext_diff) /* nubmer of extents to add */
3694{
3695 int byte_diff; /* new bytes being added */
3696 int new_size; /* size of extents after adding */
3697 xfs_extnum_t nextents; /* number of extents in file */
3698
3699 nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
3700 ASSERT((idx >= 0) && (idx <= nextents));
3701 byte_diff = ext_diff * sizeof(xfs_bmbt_rec_t);
3702 new_size = ifp->if_bytes + byte_diff;
3703 /*
3704 * If the new number of extents (nextents + ext_diff)
3705 * fits inside the inode, then continue to use the inline
3706 * extent buffer.
3707 */
3708 if (nextents + ext_diff <= XFS_INLINE_EXTS) {
3709 if (idx < nextents) {
3710 memmove(&ifp->if_u2.if_inline_ext[idx + ext_diff],
3711 &ifp->if_u2.if_inline_ext[idx],
3712 (nextents - idx) * sizeof(xfs_bmbt_rec_t));
3713 memset(&ifp->if_u2.if_inline_ext[idx], 0, byte_diff);
3714 }
3715 ifp->if_u1.if_extents = ifp->if_u2.if_inline_ext;
3716 ifp->if_real_bytes = 0;
3717 ifp->if_lastex = nextents + ext_diff;
3718 }
3719 /*
3720 * Otherwise use a linear (direct) extent list.
3721 * If the extents are currently inside the inode,
3722 * xfs_iext_realloc_direct will switch us from
3723 * inline to direct extent allocation mode.
3724 */
3725 else if (nextents + ext_diff <= XFS_LINEAR_EXTS) {
3726 xfs_iext_realloc_direct(ifp, new_size);
3727 if (idx < nextents) {
3728 memmove(&ifp->if_u1.if_extents[idx + ext_diff],
3729 &ifp->if_u1.if_extents[idx],
3730 (nextents - idx) * sizeof(xfs_bmbt_rec_t));
3731 memset(&ifp->if_u1.if_extents[idx], 0, byte_diff);
3732 }
3733 }
3734 /* Indirection array */
3735 else {
3736 xfs_ext_irec_t *erp;
3737 int erp_idx = 0;
3738 int page_idx = idx;
3739
3740 ASSERT(nextents + ext_diff > XFS_LINEAR_EXTS);
3741 if (ifp->if_flags & XFS_IFEXTIREC) {
3742 erp = xfs_iext_idx_to_irec(ifp, &page_idx, &erp_idx, 1);
3743 } else {
3744 xfs_iext_irec_init(ifp);
3745 ASSERT(ifp->if_flags & XFS_IFEXTIREC);
3746 erp = ifp->if_u1.if_ext_irec;
3747 }
3748 /* Extents fit in target extent page */
3749 if (erp && erp->er_extcount + ext_diff <= XFS_LINEAR_EXTS) {
3750 if (page_idx < erp->er_extcount) {
3751 memmove(&erp->er_extbuf[page_idx + ext_diff],
3752 &erp->er_extbuf[page_idx],
3753 (erp->er_extcount - page_idx) *
3754 sizeof(xfs_bmbt_rec_t));
3755 memset(&erp->er_extbuf[page_idx], 0, byte_diff);
3756 }
3757 erp->er_extcount += ext_diff;
3758 xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, ext_diff);
3759 }
3760 /* Insert a new extent page */
3761 else if (erp) {
3762 xfs_iext_add_indirect_multi(ifp,
3763 erp_idx, page_idx, ext_diff);
3764 }
3765 /*
3766 * If extent(s) are being appended to the last page in
3767 * the indirection array and the new extent(s) don't fit
3768 * in the page, then erp is NULL and erp_idx is set to
3769 * the next index needed in the indirection array.
3770 */
3771 else {
3772 int count = ext_diff;
3773
3774 while (count) {
3775 erp = xfs_iext_irec_new(ifp, erp_idx);
3776 erp->er_extcount = count;
3777 count -= MIN(count, (int)XFS_LINEAR_EXTS);
3778 if (count) {
3779 erp_idx++;
3780 }
3781 }
3782 }
3783 }
3784 ifp->if_bytes = new_size;
3785}
3786
3787/*
3788 * This is called when incore extents are being added to the indirection
3789 * array and the new extents do not fit in the target extent list. The
3790 * erp_idx parameter contains the irec index for the target extent list
3791 * in the indirection array, and the idx parameter contains the extent
3792 * index within the list. The number of extents being added is stored
3793 * in the count parameter.
3794 *
3795 * |-------| |-------|
3796 * | | | | idx - number of extents before idx
3797 * | idx | | count |
3798 * | | | | count - number of extents being inserted at idx
3799 * |-------| |-------|
3800 * | count | | nex2 | nex2 - number of extents after idx + count
3801 * |-------| |-------|
3802 */
3803void
3804xfs_iext_add_indirect_multi(
3805 xfs_ifork_t *ifp, /* inode fork pointer */
3806 int erp_idx, /* target extent irec index */
3807 xfs_extnum_t idx, /* index within target list */
3808 int count) /* new extents being added */
3809{
3810 int byte_diff; /* new bytes being added */
3811 xfs_ext_irec_t *erp; /* pointer to irec entry */
3812 xfs_extnum_t ext_diff; /* number of extents to add */
3813 xfs_extnum_t ext_cnt; /* new extents still needed */
3814 xfs_extnum_t nex2; /* extents after idx + count */
3815 xfs_bmbt_rec_t *nex2_ep = NULL; /* temp list for nex2 extents */
3816 int nlists; /* number of irec's (lists) */
3817
3818 ASSERT(ifp->if_flags & XFS_IFEXTIREC);
3819 erp = &ifp->if_u1.if_ext_irec[erp_idx];
3820 nex2 = erp->er_extcount - idx;
3821 nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
3822
3823 /*
3824 * Save second part of target extent list
3825 * (all extents past */
3826 if (nex2) {
3827 byte_diff = nex2 * sizeof(xfs_bmbt_rec_t);
3828 nex2_ep = (xfs_bmbt_rec_t *) kmem_alloc(byte_diff, KM_SLEEP);
3829 memmove(nex2_ep, &erp->er_extbuf[idx], byte_diff);
3830 erp->er_extcount -= nex2;
3831 xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, -nex2);
3832 memset(&erp->er_extbuf[idx], 0, byte_diff);
3833 }
3834
3835 /*
3836 * Add the new extents to the end of the target
3837 * list, then allocate new irec record(s) and
3838 * extent buffer(s) as needed to store the rest
3839 * of the new extents.
3840 */
3841 ext_cnt = count;
3842 ext_diff = MIN(ext_cnt, (int)XFS_LINEAR_EXTS - erp->er_extcount);
3843 if (ext_diff) {
3844 erp->er_extcount += ext_diff;
3845 xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, ext_diff);
3846 ext_cnt -= ext_diff;
3847 }
3848 while (ext_cnt) {
3849 erp_idx++;
3850 erp = xfs_iext_irec_new(ifp, erp_idx);
3851 ext_diff = MIN(ext_cnt, (int)XFS_LINEAR_EXTS);
3852 erp->er_extcount = ext_diff;
3853 xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, ext_diff);
3854 ext_cnt -= ext_diff;
3855 }
3856
3857 /* Add nex2 extents back to indirection array */
3858 if (nex2) {
3859 xfs_extnum_t ext_avail;
3860 int i;
3861
3862 byte_diff = nex2 * sizeof(xfs_bmbt_rec_t);
3863 ext_avail = XFS_LINEAR_EXTS - erp->er_extcount;
3864 i = 0;
3865 /*
3866 * If nex2 extents fit in the current page, append
3867 * nex2_ep after the new extents.
3868 */
3869 if (nex2 <= ext_avail) {
3870 i = erp->er_extcount;
3871 }
3872 /*
3873 * Otherwise, check if space is available in the
3874 * next page.
3875 */
3876 else if ((erp_idx < nlists - 1) &&
3877 (nex2 <= (ext_avail = XFS_LINEAR_EXTS -
3878 ifp->if_u1.if_ext_irec[erp_idx+1].er_extcount))) {
3879 erp_idx++;
3880 erp++;
3881 /* Create a hole for nex2 extents */
3882 memmove(&erp->er_extbuf[nex2], erp->er_extbuf,
3883 erp->er_extcount * sizeof(xfs_bmbt_rec_t));
3884 }
3885 /*
3886 * Final choice, create a new extent page for
3887 * nex2 extents.
3888 */
3889 else {
3890 erp_idx++;
3891 erp = xfs_iext_irec_new(ifp, erp_idx);
3892 }
3893 memmove(&erp->er_extbuf[i], nex2_ep, byte_diff);
3894 kmem_free(nex2_ep, byte_diff);
3895 erp->er_extcount += nex2;
3896 xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, nex2);
3897 }
3898}
3899
3900/*
3901 * This is called when the amount of space required for incore file
3902 * extents needs to be decreased. The ext_diff parameter stores the
3903 * number of extents to be removed and the idx parameter contains
3904 * the extent index where the extents will be removed from.
3905 *
3906 * If the amount of space needed has decreased below the linear
3907 * limit, XFS_IEXT_BUFSZ, then switch to using the contiguous
3908 * extent array. Otherwise, use kmem_realloc() to adjust the
3909 * size to what is needed.
3910 */
3911void
3912xfs_iext_remove(
3913 xfs_ifork_t *ifp, /* inode fork pointer */
3914 xfs_extnum_t idx, /* index to begin removing exts */
3915 int ext_diff) /* number of extents to remove */
3916{
3917 xfs_extnum_t nextents; /* number of extents in file */
3918 int new_size; /* size of extents after removal */
3919
3920 ASSERT(ext_diff > 0);
3921 nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
3922 new_size = (nextents - ext_diff) * sizeof(xfs_bmbt_rec_t);
3923
3924 if (new_size == 0) {
3925 xfs_iext_destroy(ifp);
3926 } else if (ifp->if_flags & XFS_IFEXTIREC) {
3927 xfs_iext_remove_indirect(ifp, idx, ext_diff);
3928 } else if (ifp->if_real_bytes) {
3929 xfs_iext_remove_direct(ifp, idx, ext_diff);
3930 } else {
3931 xfs_iext_remove_inline(ifp, idx, ext_diff);
3932 }
3933 ifp->if_bytes = new_size;
3934}
3935
3936/*
3937 * This removes ext_diff extents from the inline buffer, beginning
3938 * at extent index idx.
3939 */
3940void
3941xfs_iext_remove_inline(
3942 xfs_ifork_t *ifp, /* inode fork pointer */
3943 xfs_extnum_t idx, /* index to begin removing exts */
3944 int ext_diff) /* number of extents to remove */
3945{
3946 int nextents; /* number of extents in file */
3947
3948 ASSERT(!(ifp->if_flags & XFS_IFEXTIREC));
3949 ASSERT(idx < XFS_INLINE_EXTS);
3950 nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
3951 ASSERT(((nextents - ext_diff) > 0) &&
3952 (nextents - ext_diff) < XFS_INLINE_EXTS);
3953
3954 if (idx + ext_diff < nextents) {
3955 memmove(&ifp->if_u2.if_inline_ext[idx],
3956 &ifp->if_u2.if_inline_ext[idx + ext_diff],
3957 (nextents - (idx + ext_diff)) *
3958 sizeof(xfs_bmbt_rec_t));
3959 memset(&ifp->if_u2.if_inline_ext[nextents - ext_diff],
3960 0, ext_diff * sizeof(xfs_bmbt_rec_t));
3961 } else {
3962 memset(&ifp->if_u2.if_inline_ext[idx], 0,
3963 ext_diff * sizeof(xfs_bmbt_rec_t));
3964 }
3965}
3966
3967/*
3968 * This removes ext_diff extents from a linear (direct) extent list,
3969 * beginning at extent index idx. If the extents are being removed
3970 * from the end of the list (ie. truncate) then we just need to re-
3971 * allocate the list to remove the extra space. Otherwise, if the
3972 * extents are being removed from the middle of the existing extent
3973 * entries, then we first need to move the extent records beginning
3974 * at idx + ext_diff up in the list to overwrite the records being
3975 * removed, then remove the extra space via kmem_realloc.
3976 */
3977void
3978xfs_iext_remove_direct(
3979 xfs_ifork_t *ifp, /* inode fork pointer */
3980 xfs_extnum_t idx, /* index to begin removing exts */
3981 int ext_diff) /* number of extents to remove */
3982{
3983 xfs_extnum_t nextents; /* number of extents in file */
3984 int new_size; /* size of extents after removal */
3985
3986 ASSERT(!(ifp->if_flags & XFS_IFEXTIREC));
3987 new_size = ifp->if_bytes -
3988 (ext_diff * sizeof(xfs_bmbt_rec_t));
3989 nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
3990
3991 if (new_size == 0) {
3992 xfs_iext_destroy(ifp);
3993 return;
3994 }
3995 /* Move extents up in the list (if needed) */
3996 if (idx + ext_diff < nextents) {
3997 memmove(&ifp->if_u1.if_extents[idx],
3998 &ifp->if_u1.if_extents[idx + ext_diff],
3999 (nextents - (idx + ext_diff)) *
4000 sizeof(xfs_bmbt_rec_t));
4001 }
4002 memset(&ifp->if_u1.if_extents[nextents - ext_diff],
4003 0, ext_diff * sizeof(xfs_bmbt_rec_t));
4004 /*
4005 * Reallocate the direct extent list. If the extents
4006 * will fit inside the inode then xfs_iext_realloc_direct
4007 * will switch from direct to inline extent allocation
4008 * mode for us.
4009 */
4010 xfs_iext_realloc_direct(ifp, new_size);
4011 ifp->if_bytes = new_size;
4012}
4013
4014/*
4015 * This is called when incore extents are being removed from the
4016 * indirection array and the extents being removed span multiple extent
4017 * buffers. The idx parameter contains the file extent index where we
4018 * want to begin removing extents, and the count parameter contains
4019 * how many extents need to be removed.
4020 *
4021 * |-------| |-------|
4022 * | nex1 | | | nex1 - number of extents before idx
4023 * |-------| | count |
4024 * | | | | count - number of extents being removed at idx
4025 * | count | |-------|
4026 * | | | nex2 | nex2 - number of extents after idx + count
4027 * |-------| |-------|
4028 */
4029void
4030xfs_iext_remove_indirect(
4031 xfs_ifork_t *ifp, /* inode fork pointer */
4032 xfs_extnum_t idx, /* index to begin removing extents */
4033 int count) /* number of extents to remove */
4034{
4035 xfs_ext_irec_t *erp; /* indirection array pointer */
4036 int erp_idx = 0; /* indirection array index */
4037 xfs_extnum_t ext_cnt; /* extents left to remove */
4038 xfs_extnum_t ext_diff; /* extents to remove in current list */
4039 xfs_extnum_t nex1; /* number of extents before idx */
4040 xfs_extnum_t nex2; /* extents after idx + count */
4041 int nlists; /* entries in indirecton array */
4042 int page_idx = idx; /* index in target extent list */
4043
4044 ASSERT(ifp->if_flags & XFS_IFEXTIREC);
4045 erp = xfs_iext_idx_to_irec(ifp, &page_idx, &erp_idx, 0);
4046 ASSERT(erp != NULL);
4047 nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
4048 nex1 = page_idx;
4049 ext_cnt = count;
4050 while (ext_cnt) {
4051 nex2 = MAX((erp->er_extcount - (nex1 + ext_cnt)), 0);
4052 ext_diff = MIN(ext_cnt, (erp->er_extcount - nex1));
4053 /*
4054 * Check for deletion of entire list;
4055 * xfs_iext_irec_remove() updates extent offsets.
4056 */
4057 if (ext_diff == erp->er_extcount) {
4058 xfs_iext_irec_remove(ifp, erp_idx);
4059 ext_cnt -= ext_diff;
4060 nex1 = 0;
4061 if (ext_cnt) {
4062 ASSERT(erp_idx < ifp->if_real_bytes /
4063 XFS_IEXT_BUFSZ);
4064 erp = &ifp->if_u1.if_ext_irec[erp_idx];
4065 nex1 = 0;
4066 continue;
4067 } else {
4068 break;
4069 }
4070 }
4071 /* Move extents up (if needed) */
4072 if (nex2) {
4073 memmove(&erp->er_extbuf[nex1],
4074 &erp->er_extbuf[nex1 + ext_diff],
4075 nex2 * sizeof(xfs_bmbt_rec_t));
4076 }
4077 /* Zero out rest of page */
4078 memset(&erp->er_extbuf[nex1 + nex2], 0, (XFS_IEXT_BUFSZ -
4079 ((nex1 + nex2) * sizeof(xfs_bmbt_rec_t))));
4080 /* Update remaining counters */
4081 erp->er_extcount -= ext_diff;
4082 xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, -ext_diff);
4083 ext_cnt -= ext_diff;
4084 nex1 = 0;
4085 erp_idx++;
4086 erp++;
4087 }
4088 ifp->if_bytes -= count * sizeof(xfs_bmbt_rec_t);
4089 xfs_iext_irec_compact(ifp);
4090}
4091
4092/*
4093 * Create, destroy, or resize a linear (direct) block of extents.
4094 */
4095void
4096xfs_iext_realloc_direct(
4097 xfs_ifork_t *ifp, /* inode fork pointer */
4098 int new_size) /* new size of extents */
4099{
4100 int rnew_size; /* real new size of extents */
4101
4102 rnew_size = new_size;
4103
4104 ASSERT(!(ifp->if_flags & XFS_IFEXTIREC) ||
4105 ((new_size >= 0) && (new_size <= XFS_IEXT_BUFSZ) &&
4106 (new_size != ifp->if_real_bytes)));
4107
4108 /* Free extent records */
4109 if (new_size == 0) {
4110 xfs_iext_destroy(ifp);
4111 }
4112 /* Resize direct extent list and zero any new bytes */
4113 else if (ifp->if_real_bytes) {
4114 /* Check if extents will fit inside the inode */
4115 if (new_size <= XFS_INLINE_EXTS * sizeof(xfs_bmbt_rec_t)) {
4116 xfs_iext_direct_to_inline(ifp, new_size /
4117 (uint)sizeof(xfs_bmbt_rec_t));
4118 ifp->if_bytes = new_size;
4119 return;
4120 }
4121 if ((new_size & (new_size - 1)) != 0) {
4122 rnew_size = xfs_iroundup(new_size);
4123 }
4124 if (rnew_size != ifp->if_real_bytes) {
4125 ifp->if_u1.if_extents = (xfs_bmbt_rec_t *)
4126 kmem_realloc(ifp->if_u1.if_extents,
4127 rnew_size,
4128 ifp->if_real_bytes,
4129 KM_SLEEP);
4130 }
4131 if (rnew_size > ifp->if_real_bytes) {
4132 memset(&ifp->if_u1.if_extents[ifp->if_bytes /
4133 (uint)sizeof(xfs_bmbt_rec_t)], 0,
4134 rnew_size - ifp->if_real_bytes);
4135 }
4136 }
4137 /*
4138 * Switch from the inline extent buffer to a direct
4139 * extent list. Be sure to include the inline extent
4140 * bytes in new_size.
4141 */
4142 else {
4143 new_size += ifp->if_bytes;
4144 if ((new_size & (new_size - 1)) != 0) {
4145 rnew_size = xfs_iroundup(new_size);
4146 }
4147 xfs_iext_inline_to_direct(ifp, rnew_size);
4148 }
4149 ifp->if_real_bytes = rnew_size;
4150 ifp->if_bytes = new_size;
4151}
4152
4153/*
4154 * Switch from linear (direct) extent records to inline buffer.
4155 */
4156void
4157xfs_iext_direct_to_inline(
4158 xfs_ifork_t *ifp, /* inode fork pointer */
4159 xfs_extnum_t nextents) /* number of extents in file */
4160{
4161 ASSERT(ifp->if_flags & XFS_IFEXTENTS);
4162 ASSERT(nextents <= XFS_INLINE_EXTS);
4163 /*
4164 * The inline buffer was zeroed when we switched
4165 * from inline to direct extent allocation mode,
4166 * so we don't need to clear it here.
4167 */
4168 memcpy(ifp->if_u2.if_inline_ext, ifp->if_u1.if_extents,
4169 nextents * sizeof(xfs_bmbt_rec_t));
4170 kmem_free(ifp->if_u1.if_extents, KM_SLEEP);
4171 ifp->if_u1.if_extents = ifp->if_u2.if_inline_ext;
4172 ifp->if_real_bytes = 0;
4173}
4174
4175/*
4176 * Switch from inline buffer to linear (direct) extent records.
4177 * new_size should already be rounded up to the next power of 2
4178 * by the caller (when appropriate), so use new_size as it is.
4179 * However, since new_size may be rounded up, we can't update
4180 * if_bytes here. It is the caller's responsibility to update
4181 * if_bytes upon return.
4182 */
4183void
4184xfs_iext_inline_to_direct(
4185 xfs_ifork_t *ifp, /* inode fork pointer */
4186 int new_size) /* number of extents in file */
4187{
4188 ifp->if_u1.if_extents = (xfs_bmbt_rec_t *)
4189 kmem_alloc(new_size, KM_SLEEP);
4190 memset(ifp->if_u1.if_extents, 0, new_size);
4191 if (ifp->if_bytes) {
4192 memcpy(ifp->if_u1.if_extents, ifp->if_u2.if_inline_ext,
4193 ifp->if_bytes);
4194 memset(ifp->if_u2.if_inline_ext, 0, XFS_INLINE_EXTS *
4195 sizeof(xfs_bmbt_rec_t));
4196 }
4197 ifp->if_real_bytes = new_size;
4198}
4199
4200/*
4201 * Resize an extent indirection array to new_size bytes.
4202 */
4203void
4204xfs_iext_realloc_indirect(
4205 xfs_ifork_t *ifp, /* inode fork pointer */
4206 int new_size) /* new indirection array size */
4207{
4208 int nlists; /* number of irec's (ex lists) */
4209 int size; /* current indirection array size */
4210
4211 ASSERT(ifp->if_flags & XFS_IFEXTIREC);
4212 nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
4213 size = nlists * sizeof(xfs_ext_irec_t);
4214 ASSERT(ifp->if_real_bytes);
4215 ASSERT((new_size >= 0) && (new_size != size));
4216 if (new_size == 0) {
4217 xfs_iext_destroy(ifp);
4218 } else {
4219 ifp->if_u1.if_ext_irec = (xfs_ext_irec_t *)
4220 kmem_realloc(ifp->if_u1.if_ext_irec,
4221 new_size, size, KM_SLEEP);
4222 }
4223}
4224
4225/*
4226 * Switch from indirection array to linear (direct) extent allocations.
4227 */
4228void
4229xfs_iext_indirect_to_direct(
4230 xfs_ifork_t *ifp) /* inode fork pointer */
4231{
4232 xfs_bmbt_rec_t *ep; /* extent record pointer */
4233 xfs_extnum_t nextents; /* number of extents in file */
4234 int size; /* size of file extents */
4235
4236 ASSERT(ifp->if_flags & XFS_IFEXTIREC);
4237 nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
4238 ASSERT(nextents <= XFS_LINEAR_EXTS);
4239 size = nextents * sizeof(xfs_bmbt_rec_t);
4240
4241 xfs_iext_irec_compact_full(ifp);
4242 ASSERT(ifp->if_real_bytes == XFS_IEXT_BUFSZ);
4243
4244 ep = ifp->if_u1.if_ext_irec->er_extbuf;
4245 kmem_free(ifp->if_u1.if_ext_irec, sizeof(xfs_ext_irec_t));
4246 ifp->if_flags &= ~XFS_IFEXTIREC;
4247 ifp->if_u1.if_extents = ep;
4248 ifp->if_bytes = size;
4249 if (nextents < XFS_LINEAR_EXTS) {
4250 xfs_iext_realloc_direct(ifp, size);
4251 }
4252}
4253
4254/*
4255 * Free incore file extents.
4256 */
4257void
4258xfs_iext_destroy(
4259 xfs_ifork_t *ifp) /* inode fork pointer */
4260{
4261 if (ifp->if_flags & XFS_IFEXTIREC) {
4262 int erp_idx;
4263 int nlists;
4264
4265 nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
4266 for (erp_idx = nlists - 1; erp_idx >= 0 ; erp_idx--) {
4267 xfs_iext_irec_remove(ifp, erp_idx);
4268 }
4269 ifp->if_flags &= ~XFS_IFEXTIREC;
4270 } else if (ifp->if_real_bytes) {
4271 kmem_free(ifp->if_u1.if_extents, ifp->if_real_bytes);
4272 } else if (ifp->if_bytes) {
4273 memset(ifp->if_u2.if_inline_ext, 0, XFS_INLINE_EXTS *
4274 sizeof(xfs_bmbt_rec_t));
4275 }
4276 ifp->if_u1.if_extents = NULL;
4277 ifp->if_real_bytes = 0;
4278 ifp->if_bytes = 0;
4279}
4280
4281/*
4282 * Return a pointer to the extent record for file system block bno.
4283 */
4284xfs_bmbt_rec_t * /* pointer to found extent record */
4285xfs_iext_bno_to_ext(
4286 xfs_ifork_t *ifp, /* inode fork pointer */
4287 xfs_fileoff_t bno, /* block number to search for */
4288 xfs_extnum_t *idxp) /* index of target extent */
4289{
4290 xfs_bmbt_rec_t *base; /* pointer to first extent */
4291 xfs_filblks_t blockcount = 0; /* number of blocks in extent */
4292 xfs_bmbt_rec_t *ep = NULL; /* pointer to target extent */
4293 xfs_ext_irec_t *erp = NULL; /* indirection array pointer */
4294 int high; /* upper boundry in search */
4295 xfs_extnum_t idx = 0; /* index of target extent */
4296 int low; /* lower boundry in search */
4297 xfs_extnum_t nextents; /* number of file extents */
4298 xfs_fileoff_t startoff = 0; /* start offset of extent */
4299
4300 nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
4301 if (nextents == 0) {
4302 *idxp = 0;
4303 return NULL;
4304 }
4305 low = 0;
4306 if (ifp->if_flags & XFS_IFEXTIREC) {
4307 /* Find target extent list */
4308 int erp_idx = 0;
4309 erp = xfs_iext_bno_to_irec(ifp, bno, &erp_idx);
4310 base = erp->er_extbuf;
4311 high = erp->er_extcount - 1;
4312 } else {
4313 base = ifp->if_u1.if_extents;
4314 high = nextents - 1;
4315 }
4316 /* Binary search extent records */
4317 while (low <= high) {
4318 idx = (low + high) >> 1;
4319 ep = base + idx;
4320 startoff = xfs_bmbt_get_startoff(ep);
4321 blockcount = xfs_bmbt_get_blockcount(ep);
4322 if (bno < startoff) {
4323 high = idx - 1;
4324 } else if (bno >= startoff + blockcount) {
4325 low = idx + 1;
4326 } else {
4327 /* Convert back to file-based extent index */
4328 if (ifp->if_flags & XFS_IFEXTIREC) {
4329 idx += erp->er_extoff;
4330 }
4331 *idxp = idx;
4332 return ep;
4333 }
4334 }
4335 /* Convert back to file-based extent index */
4336 if (ifp->if_flags & XFS_IFEXTIREC) {
4337 idx += erp->er_extoff;
4338 }
4339 if (bno >= startoff + blockcount) {
4340 if (++idx == nextents) {
4341 ep = NULL;
4342 } else {
4343 ep = xfs_iext_get_ext(ifp, idx);
4344 }
4345 }
4346 *idxp = idx;
4347 return ep;
4348}
4349
4350/*
4351 * Return a pointer to the indirection array entry containing the
4352 * extent record for filesystem block bno. Store the index of the
4353 * target irec in *erp_idxp.
4354 */
4355xfs_ext_irec_t * /* pointer to found extent record */
4356xfs_iext_bno_to_irec(
4357 xfs_ifork_t *ifp, /* inode fork pointer */
4358 xfs_fileoff_t bno, /* block number to search for */
4359 int *erp_idxp) /* irec index of target ext list */
4360{
4361 xfs_ext_irec_t *erp = NULL; /* indirection array pointer */
4362 xfs_ext_irec_t *erp_next; /* next indirection array entry */
4363 int erp_idx; /* indirection array index */
4364 int nlists; /* number of extent irec's (lists) */
4365 int high; /* binary search upper limit */
4366 int low; /* binary search lower limit */
4367
4368 ASSERT(ifp->if_flags & XFS_IFEXTIREC);
4369 nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
4370 erp_idx = 0;
4371 low = 0;
4372 high = nlists - 1;
4373 while (low <= high) {
4374 erp_idx = (low + high) >> 1;
4375 erp = &ifp->if_u1.if_ext_irec[erp_idx];
4376 erp_next = erp_idx < nlists - 1 ? erp + 1 : NULL;
4377 if (bno < xfs_bmbt_get_startoff(erp->er_extbuf)) {
4378 high = erp_idx - 1;
4379 } else if (erp_next && bno >=
4380 xfs_bmbt_get_startoff(erp_next->er_extbuf)) {
4381 low = erp_idx + 1;
4382 } else {
4383 break;
4384 }
4385 }
4386 *erp_idxp = erp_idx;
4387 return erp;
4388}
4389
4390/*
4391 * Return a pointer to the indirection array entry containing the
4392 * extent record at file extent index *idxp. Store the index of the
4393 * target irec in *erp_idxp and store the page index of the target
4394 * extent record in *idxp.
4395 */
4396xfs_ext_irec_t *
4397xfs_iext_idx_to_irec(
4398 xfs_ifork_t *ifp, /* inode fork pointer */
4399 xfs_extnum_t *idxp, /* extent index (file -> page) */
4400 int *erp_idxp, /* pointer to target irec */
4401 int realloc) /* new bytes were just added */
4402{
4403 xfs_ext_irec_t *prev; /* pointer to previous irec */
4404 xfs_ext_irec_t *erp = NULL; /* pointer to current irec */
4405 int erp_idx; /* indirection array index */
4406 int nlists; /* number of irec's (ex lists) */
4407 int high; /* binary search upper limit */
4408 int low; /* binary search lower limit */
4409 xfs_extnum_t page_idx = *idxp; /* extent index in target list */
4410
4411 ASSERT(ifp->if_flags & XFS_IFEXTIREC);
4412 ASSERT(page_idx >= 0 && page_idx <=
4413 ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t));
4414 nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
4415 erp_idx = 0;
4416 low = 0;
4417 high = nlists - 1;
4418
4419 /* Binary search extent irec's */
4420 while (low <= high) {
4421 erp_idx = (low + high) >> 1;
4422 erp = &ifp->if_u1.if_ext_irec[erp_idx];
4423 prev = erp_idx > 0 ? erp - 1 : NULL;
4424 if (page_idx < erp->er_extoff || (page_idx == erp->er_extoff &&
4425 realloc && prev && prev->er_extcount < XFS_LINEAR_EXTS)) {
4426 high = erp_idx - 1;
4427 } else if (page_idx > erp->er_extoff + erp->er_extcount ||
4428 (page_idx == erp->er_extoff + erp->er_extcount &&
4429 !realloc)) {
4430 low = erp_idx + 1;
4431 } else if (page_idx == erp->er_extoff + erp->er_extcount &&
4432 erp->er_extcount == XFS_LINEAR_EXTS) {
4433 ASSERT(realloc);
4434 page_idx = 0;
4435 erp_idx++;
4436 erp = erp_idx < nlists ? erp + 1 : NULL;
4437 break;
4438 } else {
4439 page_idx -= erp->er_extoff;
4440 break;
4441 }
4442 }
4443 *idxp = page_idx;
4444 *erp_idxp = erp_idx;
4445 return(erp);
4446}
4447
4448/*
4449 * Allocate and initialize an indirection array once the space needed
4450 * for incore extents increases above XFS_IEXT_BUFSZ.
4451 */
4452void
4453xfs_iext_irec_init(
4454 xfs_ifork_t *ifp) /* inode fork pointer */
4455{
4456 xfs_ext_irec_t *erp; /* indirection array pointer */
4457 xfs_extnum_t nextents; /* number of extents in file */
4458
4459 ASSERT(!(ifp->if_flags & XFS_IFEXTIREC));
4460 nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
4461 ASSERT(nextents <= XFS_LINEAR_EXTS);
4462
4463 erp = (xfs_ext_irec_t *)
4464 kmem_alloc(sizeof(xfs_ext_irec_t), KM_SLEEP);
4465
4466 if (nextents == 0) {
4467 ifp->if_u1.if_extents = (xfs_bmbt_rec_t *)
4468 kmem_alloc(XFS_IEXT_BUFSZ, KM_SLEEP);
4469 } else if (!ifp->if_real_bytes) {
4470 xfs_iext_inline_to_direct(ifp, XFS_IEXT_BUFSZ);
4471 } else if (ifp->if_real_bytes < XFS_IEXT_BUFSZ) {
4472 xfs_iext_realloc_direct(ifp, XFS_IEXT_BUFSZ);
4473 }
4474 erp->er_extbuf = ifp->if_u1.if_extents;
4475 erp->er_extcount = nextents;
4476 erp->er_extoff = 0;
4477
4478 ifp->if_flags |= XFS_IFEXTIREC;
4479 ifp->if_real_bytes = XFS_IEXT_BUFSZ;
4480 ifp->if_bytes = nextents * sizeof(xfs_bmbt_rec_t);
4481 ifp->if_u1.if_ext_irec = erp;
4482
4483 return;
4484}
4485
4486/*
4487 * Allocate and initialize a new entry in the indirection array.
4488 */
4489xfs_ext_irec_t *
4490xfs_iext_irec_new(
4491 xfs_ifork_t *ifp, /* inode fork pointer */
4492 int erp_idx) /* index for new irec */
4493{
4494 xfs_ext_irec_t *erp; /* indirection array pointer */
4495 int i; /* loop counter */
4496 int nlists; /* number of irec's (ex lists) */
4497
4498 ASSERT(ifp->if_flags & XFS_IFEXTIREC);
4499 nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
4500
4501 /* Resize indirection array */
4502 xfs_iext_realloc_indirect(ifp, ++nlists *
4503 sizeof(xfs_ext_irec_t));
4504 /*
4505 * Move records down in the array so the
4506 * new page can use erp_idx.
4507 */
4508 erp = ifp->if_u1.if_ext_irec;
4509 for (i = nlists - 1; i > erp_idx; i--) {
4510 memmove(&erp[i], &erp[i-1], sizeof(xfs_ext_irec_t));
4511 }
4512 ASSERT(i == erp_idx);
4513
4514 /* Initialize new extent record */
4515 erp = ifp->if_u1.if_ext_irec;
4516 erp[erp_idx].er_extbuf = (xfs_bmbt_rec_t *)
4517 kmem_alloc(XFS_IEXT_BUFSZ, KM_SLEEP);
4518 ifp->if_real_bytes = nlists * XFS_IEXT_BUFSZ;
4519 memset(erp[erp_idx].er_extbuf, 0, XFS_IEXT_BUFSZ);
4520 erp[erp_idx].er_extcount = 0;
4521 erp[erp_idx].er_extoff = erp_idx > 0 ?
4522 erp[erp_idx-1].er_extoff + erp[erp_idx-1].er_extcount : 0;
4523 return (&erp[erp_idx]);
4524}
4525
4526/*
4527 * Remove a record from the indirection array.
4528 */
4529void
4530xfs_iext_irec_remove(
4531 xfs_ifork_t *ifp, /* inode fork pointer */
4532 int erp_idx) /* irec index to remove */
4533{
4534 xfs_ext_irec_t *erp; /* indirection array pointer */
4535 int i; /* loop counter */
4536 int nlists; /* number of irec's (ex lists) */
4537
4538 ASSERT(ifp->if_flags & XFS_IFEXTIREC);
4539 nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
4540 erp = &ifp->if_u1.if_ext_irec[erp_idx];
4541 if (erp->er_extbuf) {
4542 xfs_iext_irec_update_extoffs(ifp, erp_idx + 1,
4543 -erp->er_extcount);
4544 kmem_free(erp->er_extbuf, XFS_IEXT_BUFSZ);
4545 }
4546 /* Compact extent records */
4547 erp = ifp->if_u1.if_ext_irec;
4548 for (i = erp_idx; i < nlists - 1; i++) {
4549 memmove(&erp[i], &erp[i+1], sizeof(xfs_ext_irec_t));
4550 }
4551 /*
4552 * Manually free the last extent record from the indirection
4553 * array. A call to xfs_iext_realloc_indirect() with a size
4554 * of zero would result in a call to xfs_iext_destroy() which
4555 * would in turn call this function again, creating a nasty
4556 * infinite loop.
4557 */
4558 if (--nlists) {
4559 xfs_iext_realloc_indirect(ifp,
4560 nlists * sizeof(xfs_ext_irec_t));
4561 } else {
4562 kmem_free(ifp->if_u1.if_ext_irec,
4563 sizeof(xfs_ext_irec_t));
4564 }
4565 ifp->if_real_bytes = nlists * XFS_IEXT_BUFSZ;
4566}
4567
4568/*
4569 * This is called to clean up large amounts of unused memory allocated
4570 * by the indirection array. Before compacting anything though, verify
4571 * that the indirection array is still needed and switch back to the
4572 * linear extent list (or even the inline buffer) if possible. The
4573 * compaction policy is as follows:
4574 *
4575 * Full Compaction: Extents fit into a single page (or inline buffer)
4576 * Full Compaction: Extents occupy less than 10% of allocated space
4577 * Partial Compaction: Extents occupy > 10% and < 50% of allocated space
4578 * No Compaction: Extents occupy at least 50% of allocated space
4579 */
4580void
4581xfs_iext_irec_compact(
4582 xfs_ifork_t *ifp) /* inode fork pointer */
4583{
4584 xfs_extnum_t nextents; /* number of extents in file */
4585 int nlists; /* number of irec's (ex lists) */
4586
4587 ASSERT(ifp->if_flags & XFS_IFEXTIREC);
4588 nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
4589 nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
4590
4591 if (nextents == 0) {
4592 xfs_iext_destroy(ifp);
4593 } else if (nextents <= XFS_INLINE_EXTS) {
4594 xfs_iext_indirect_to_direct(ifp);
4595 xfs_iext_direct_to_inline(ifp, nextents);
4596 } else if (nextents <= XFS_LINEAR_EXTS) {
4597 xfs_iext_indirect_to_direct(ifp);
4598 } else if (nextents < (nlists * XFS_LINEAR_EXTS) >> 3) {
4599 xfs_iext_irec_compact_full(ifp);
4600 } else if (nextents < (nlists * XFS_LINEAR_EXTS) >> 1) {
4601 xfs_iext_irec_compact_pages(ifp);
4602 }
4603}
4604
4605/*
4606 * Combine extents from neighboring extent pages.
4607 */
4608void
4609xfs_iext_irec_compact_pages(
4610 xfs_ifork_t *ifp) /* inode fork pointer */
4611{
4612 xfs_ext_irec_t *erp, *erp_next;/* pointers to irec entries */
4613 int erp_idx = 0; /* indirection array index */
4614 int nlists; /* number of irec's (ex lists) */
4615
4616 ASSERT(ifp->if_flags & XFS_IFEXTIREC);
4617 nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
4618 while (erp_idx < nlists - 1) {
4619 erp = &ifp->if_u1.if_ext_irec[erp_idx];
4620 erp_next = erp + 1;
4621 if (erp_next->er_extcount <=
4622 (XFS_LINEAR_EXTS - erp->er_extcount)) {
4623 memmove(&erp->er_extbuf[erp->er_extcount],
4624 erp_next->er_extbuf, erp_next->er_extcount *
4625 sizeof(xfs_bmbt_rec_t));
4626 erp->er_extcount += erp_next->er_extcount;
4627 /*
4628 * Free page before removing extent record
4629 * so er_extoffs don't get modified in
4630 * xfs_iext_irec_remove.
4631 */
4632 kmem_free(erp_next->er_extbuf, XFS_IEXT_BUFSZ);
4633 erp_next->er_extbuf = NULL;
4634 xfs_iext_irec_remove(ifp, erp_idx + 1);
4635 nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
4636 } else {
4637 erp_idx++;
4638 }
4639 }
4640}
4641
4642/*
4643 * Fully compact the extent records managed by the indirection array.
4644 */
4645void
4646xfs_iext_irec_compact_full(
4647 xfs_ifork_t *ifp) /* inode fork pointer */
4648{
4649 xfs_bmbt_rec_t *ep, *ep_next; /* extent record pointers */
4650 xfs_ext_irec_t *erp, *erp_next; /* extent irec pointers */
4651 int erp_idx = 0; /* extent irec index */
4652 int ext_avail; /* empty entries in ex list */
4653 int ext_diff; /* number of exts to add */
4654 int nlists; /* number of irec's (ex lists) */
4655
4656 ASSERT(ifp->if_flags & XFS_IFEXTIREC);
4657 nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
4658 erp = ifp->if_u1.if_ext_irec;
4659 ep = &erp->er_extbuf[erp->er_extcount];
4660 erp_next = erp + 1;
4661 ep_next = erp_next->er_extbuf;
4662 while (erp_idx < nlists - 1) {
4663 ext_avail = XFS_LINEAR_EXTS - erp->er_extcount;
4664 ext_diff = MIN(ext_avail, erp_next->er_extcount);
4665 memcpy(ep, ep_next, ext_diff * sizeof(xfs_bmbt_rec_t));
4666 erp->er_extcount += ext_diff;
4667 erp_next->er_extcount -= ext_diff;
4668 /* Remove next page */
4669 if (erp_next->er_extcount == 0) {
4670 /*
4671 * Free page before removing extent record
4672 * so er_extoffs don't get modified in
4673 * xfs_iext_irec_remove.
4674 */
4675 kmem_free(erp_next->er_extbuf,
4676 erp_next->er_extcount * sizeof(xfs_bmbt_rec_t));
4677 erp_next->er_extbuf = NULL;
4678 xfs_iext_irec_remove(ifp, erp_idx + 1);
4679 erp = &ifp->if_u1.if_ext_irec[erp_idx];
4680 nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
4681 /* Update next page */
4682 } else {
4683 /* Move rest of page up to become next new page */
4684 memmove(erp_next->er_extbuf, ep_next,
4685 erp_next->er_extcount * sizeof(xfs_bmbt_rec_t));
4686 ep_next = erp_next->er_extbuf;
4687 memset(&ep_next[erp_next->er_extcount], 0,
4688 (XFS_LINEAR_EXTS - erp_next->er_extcount) *
4689 sizeof(xfs_bmbt_rec_t));
4690 }
4691 if (erp->er_extcount == XFS_LINEAR_EXTS) {
4692 erp_idx++;
4693 if (erp_idx < nlists)
4694 erp = &ifp->if_u1.if_ext_irec[erp_idx];
4695 else
4696 break;
4697 }
4698 ep = &erp->er_extbuf[erp->er_extcount];
4699 erp_next = erp + 1;
4700 ep_next = erp_next->er_extbuf;
4701 }
4702}
4703
4704/*
4705 * This is called to update the er_extoff field in the indirection
4706 * array when extents have been added or removed from one of the
4707 * extent lists. erp_idx contains the irec index to begin updating
4708 * at and ext_diff contains the number of extents that were added
4709 * or removed.
4710 */
4711void
4712xfs_iext_irec_update_extoffs(
4713 xfs_ifork_t *ifp, /* inode fork pointer */
4714 int erp_idx, /* irec index to update */
4715 int ext_diff) /* number of new extents */
4716{
4717 int i; /* loop counter */
4718 int nlists; /* number of irec's (ex lists */
4719
4720 ASSERT(ifp->if_flags & XFS_IFEXTIREC);
4721 nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
4722 for (i = erp_idx; i < nlists; i++) {
4723 ifp->if_u1.if_ext_irec[i].er_extoff += ext_diff;
4724 }
4725}