aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/xfs/xfs_inode.c70
1 files changed, 47 insertions, 23 deletions
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index fcb1dcc6f036..bedc66163176 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -4532,39 +4532,63 @@ xfs_iext_irec_compact_full(
4532 int nlists; /* number of irec's (ex lists) */ 4532 int nlists; /* number of irec's (ex lists) */
4533 4533
4534 ASSERT(ifp->if_flags & XFS_IFEXTIREC); 4534 ASSERT(ifp->if_flags & XFS_IFEXTIREC);
4535
4535 nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; 4536 nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
4536 erp = ifp->if_u1.if_ext_irec; 4537 erp = ifp->if_u1.if_ext_irec;
4537 ep = &erp->er_extbuf[erp->er_extcount]; 4538 ep = &erp->er_extbuf[erp->er_extcount];
4538 erp_next = erp + 1; 4539 erp_next = erp + 1;
4539 ep_next = erp_next->er_extbuf; 4540 ep_next = erp_next->er_extbuf;
4541
4540 while (erp_idx < nlists - 1) { 4542 while (erp_idx < nlists - 1) {
4543 /*
4544 * Check how many extent records are available in this irec.
4545 * If there is none skip the whole exercise.
4546 */
4541 ext_avail = XFS_LINEAR_EXTS - erp->er_extcount; 4547 ext_avail = XFS_LINEAR_EXTS - erp->er_extcount;
4542 ext_diff = MIN(ext_avail, erp_next->er_extcount); 4548 if (ext_avail) {
4543 memcpy(ep, ep_next, ext_diff * sizeof(xfs_bmbt_rec_t)); 4549
4544 erp->er_extcount += ext_diff;
4545 erp_next->er_extcount -= ext_diff;
4546 /* Remove next page */
4547 if (erp_next->er_extcount == 0) {
4548 /* 4550 /*
4549 * Free page before removing extent record 4551 * Copy over as many as possible extent records into
4550 * so er_extoffs don't get modified in 4552 * the previous page.
4551 * xfs_iext_irec_remove.
4552 */ 4553 */
4553 kmem_free(erp_next->er_extbuf); 4554 ext_diff = MIN(ext_avail, erp_next->er_extcount);
4554 erp_next->er_extbuf = NULL; 4555 memcpy(ep, ep_next, ext_diff * sizeof(xfs_bmbt_rec_t));
4555 xfs_iext_irec_remove(ifp, erp_idx + 1); 4556 erp->er_extcount += ext_diff;
4556 erp = &ifp->if_u1.if_ext_irec[erp_idx]; 4557 erp_next->er_extcount -= ext_diff;
4557 nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; 4558
4558 /* Update next page */ 4559 /*
4559 } else { 4560 * If the next irec is empty now we can simply
4560 /* Move rest of page up to become next new page */ 4561 * remove it.
4561 memmove(erp_next->er_extbuf, ep_next, 4562 */
4562 erp_next->er_extcount * sizeof(xfs_bmbt_rec_t)); 4563 if (erp_next->er_extcount == 0) {
4563 ep_next = erp_next->er_extbuf; 4564 /*
4564 memset(&ep_next[erp_next->er_extcount], 0, 4565 * Free page before removing extent record
4565 (XFS_LINEAR_EXTS - erp_next->er_extcount) * 4566 * so er_extoffs don't get modified in
4566 sizeof(xfs_bmbt_rec_t)); 4567 * xfs_iext_irec_remove.
4568 */
4569 kmem_free(erp_next->er_extbuf);
4570 erp_next->er_extbuf = NULL;
4571 xfs_iext_irec_remove(ifp, erp_idx + 1);
4572 erp = &ifp->if_u1.if_ext_irec[erp_idx];
4573 nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
4574
4575 /*
4576 * If the next irec is not empty move up the content
4577 * that has not been copied to the previous page to
4578 * the beggining of this one.
4579 */
4580 } else {
4581 memmove(erp_next->er_extbuf, &ep_next[ext_diff],
4582 erp_next->er_extcount *
4583 sizeof(xfs_bmbt_rec_t));
4584 ep_next = erp_next->er_extbuf;
4585 memset(&ep_next[erp_next->er_extcount], 0,
4586 (XFS_LINEAR_EXTS -
4587 erp_next->er_extcount) *
4588 sizeof(xfs_bmbt_rec_t));
4589 }
4567 } 4590 }
4591
4568 if (erp->er_extcount == XFS_LINEAR_EXTS) { 4592 if (erp->er_extcount == XFS_LINEAR_EXTS) {
4569 erp_idx++; 4593 erp_idx++;
4570 if (erp_idx < nlists) 4594 if (erp_idx < nlists)