diff options
-rw-r--r-- | fs/xfs/xfs_bmap.c | 302 |
1 files changed, 162 insertions, 140 deletions
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c index c9492e23447c..311cbc1d64c5 100644 --- a/fs/xfs/xfs_bmap.c +++ b/fs/xfs/xfs_bmap.c | |||
@@ -4605,6 +4605,147 @@ xfs_bmapi_delay( | |||
4605 | } | 4605 | } |
4606 | 4606 | ||
4607 | 4607 | ||
4608 | STATIC int | ||
4609 | xfs_bmapi_allocate( | ||
4610 | struct xfs_bmalloca *bma, | ||
4611 | xfs_extnum_t *lastx, | ||
4612 | struct xfs_btree_cur **cur, | ||
4613 | xfs_fsblock_t *firstblock, | ||
4614 | struct xfs_bmap_free *flist, | ||
4615 | int flags, | ||
4616 | int *nallocs, | ||
4617 | int *logflags) | ||
4618 | { | ||
4619 | struct xfs_mount *mp = bma->ip->i_mount; | ||
4620 | int whichfork = (flags & XFS_BMAPI_ATTRFORK) ? | ||
4621 | XFS_ATTR_FORK : XFS_DATA_FORK; | ||
4622 | struct xfs_ifork *ifp = XFS_IFORK_PTR(bma->ip, whichfork); | ||
4623 | xfs_fsblock_t abno; | ||
4624 | xfs_extlen_t alen; | ||
4625 | xfs_fileoff_t aoff; | ||
4626 | int error; | ||
4627 | int rt; | ||
4628 | |||
4629 | rt = (whichfork == XFS_DATA_FORK) && XFS_IS_REALTIME_INODE(bma->ip); | ||
4630 | |||
4631 | /* | ||
4632 | * For the wasdelay case, we could also just allocate the stuff asked | ||
4633 | * for in this bmap call but that wouldn't be as good. | ||
4634 | */ | ||
4635 | if (bma->wasdel) { | ||
4636 | alen = (xfs_extlen_t)bma->gotp->br_blockcount; | ||
4637 | aoff = bma->gotp->br_startoff; | ||
4638 | if (*lastx != NULLEXTNUM && *lastx) { | ||
4639 | xfs_bmbt_get_all(xfs_iext_get_ext(ifp, *lastx - 1), | ||
4640 | bma->prevp); | ||
4641 | } | ||
4642 | } else { | ||
4643 | alen = (xfs_extlen_t)XFS_FILBLKS_MIN(bma->alen, MAXEXTLEN); | ||
4644 | if (!bma->eof) | ||
4645 | alen = (xfs_extlen_t)XFS_FILBLKS_MIN(alen, | ||
4646 | bma->gotp->br_startoff - bma->off); | ||
4647 | aoff = bma->off; | ||
4648 | } | ||
4649 | |||
4650 | /* | ||
4651 | * Indicate if this is the first user data in the file, or just any | ||
4652 | * user data. | ||
4653 | */ | ||
4654 | if (!(flags & XFS_BMAPI_METADATA)) { | ||
4655 | bma->userdata = (aoff == 0) ? | ||
4656 | XFS_ALLOC_INITIAL_USER_DATA : XFS_ALLOC_USERDATA; | ||
4657 | } | ||
4658 | |||
4659 | /* | ||
4660 | * Fill in changeable bma fields. | ||
4661 | */ | ||
4662 | bma->alen = alen; | ||
4663 | bma->off = aoff; | ||
4664 | bma->firstblock = *firstblock; | ||
4665 | bma->minlen = (flags & XFS_BMAPI_CONTIG) ? alen : 1; | ||
4666 | bma->low = flist->xbf_low; | ||
4667 | bma->aeof = 0; | ||
4668 | |||
4669 | /* | ||
4670 | * Only want to do the alignment at the eof if it is userdata and | ||
4671 | * allocation length is larger than a stripe unit. | ||
4672 | */ | ||
4673 | if (mp->m_dalign && alen >= mp->m_dalign && | ||
4674 | !(flags & XFS_BMAPI_METADATA) && whichfork == XFS_DATA_FORK) { | ||
4675 | error = xfs_bmap_isaeof(bma->ip, aoff, whichfork, &bma->aeof); | ||
4676 | if (error) | ||
4677 | return error; | ||
4678 | } | ||
4679 | |||
4680 | error = xfs_bmap_alloc(bma); | ||
4681 | if (error) | ||
4682 | return error; | ||
4683 | |||
4684 | /* | ||
4685 | * Copy out result fields. | ||
4686 | */ | ||
4687 | abno = bma->rval; | ||
4688 | flist->xbf_low = bma->low; | ||
4689 | alen = bma->alen; | ||
4690 | aoff = bma->off; | ||
4691 | ASSERT(*firstblock == NULLFSBLOCK || | ||
4692 | XFS_FSB_TO_AGNO(mp, *firstblock) == | ||
4693 | XFS_FSB_TO_AGNO(mp, bma->firstblock) || | ||
4694 | (flist->xbf_low && | ||
4695 | XFS_FSB_TO_AGNO(mp, *firstblock) < | ||
4696 | XFS_FSB_TO_AGNO(mp, bma->firstblock))); | ||
4697 | *firstblock = bma->firstblock; | ||
4698 | if (*cur) | ||
4699 | (*cur)->bc_private.b.firstblock = *firstblock; | ||
4700 | if (abno == NULLFSBLOCK) | ||
4701 | return 0; | ||
4702 | if ((ifp->if_flags & XFS_IFBROOT) && !*cur) { | ||
4703 | (*cur) = xfs_bmbt_init_cursor(mp, bma->tp, bma->ip, whichfork); | ||
4704 | (*cur)->bc_private.b.firstblock = *firstblock; | ||
4705 | (*cur)->bc_private.b.flist = flist; | ||
4706 | } | ||
4707 | /* | ||
4708 | * Bump the number of extents we've allocated | ||
4709 | * in this call. | ||
4710 | */ | ||
4711 | (*nallocs)++; | ||
4712 | |||
4713 | if (*cur) | ||
4714 | (*cur)->bc_private.b.flags = | ||
4715 | bma->wasdel ? XFS_BTCUR_BPRV_WASDEL : 0; | ||
4716 | |||
4717 | bma->gotp->br_startoff = aoff; | ||
4718 | bma->gotp->br_startblock = abno; | ||
4719 | bma->gotp->br_blockcount = alen; | ||
4720 | bma->gotp->br_state = XFS_EXT_NORM; | ||
4721 | |||
4722 | /* | ||
4723 | * A wasdelay extent has been initialized, so shouldn't be flagged | ||
4724 | * as unwritten. | ||
4725 | */ | ||
4726 | if (!bma->wasdel && (flags & XFS_BMAPI_PREALLOC) && | ||
4727 | xfs_sb_version_hasextflgbit(&mp->m_sb)) | ||
4728 | bma->gotp->br_state = XFS_EXT_UNWRITTEN; | ||
4729 | |||
4730 | error = xfs_bmap_add_extent(bma->tp, bma->ip, lastx, cur, bma->gotp, | ||
4731 | firstblock, flist, logflags, whichfork); | ||
4732 | if (error) | ||
4733 | return error; | ||
4734 | |||
4735 | /* | ||
4736 | * Update our extent pointer, given that xfs_bmap_add_extent might | ||
4737 | * have merged it into one of the neighbouring ones. | ||
4738 | */ | ||
4739 | xfs_bmbt_get_all(xfs_iext_get_ext(ifp, *lastx), bma->gotp); | ||
4740 | |||
4741 | ASSERT(bma->gotp->br_startoff <= aoff); | ||
4742 | ASSERT(bma->gotp->br_startoff + bma->gotp->br_blockcount >= | ||
4743 | aoff + alen); | ||
4744 | ASSERT(bma->gotp->br_state == XFS_EXT_NORM || | ||
4745 | bma->gotp->br_state == XFS_EXT_UNWRITTEN); | ||
4746 | return 0; | ||
4747 | } | ||
4748 | |||
4608 | /* | 4749 | /* |
4609 | * Map file blocks to filesystem blocks. | 4750 | * Map file blocks to filesystem blocks. |
4610 | * File range is given by the bno/len pair. | 4751 | * File range is given by the bno/len pair. |
@@ -4632,9 +4773,6 @@ xfs_bmapi( | |||
4632 | int *nmap, /* i/o: mval size/count */ | 4773 | int *nmap, /* i/o: mval size/count */ |
4633 | xfs_bmap_free_t *flist) /* i/o: list extents to free */ | 4774 | xfs_bmap_free_t *flist) /* i/o: list extents to free */ |
4634 | { | 4775 | { |
4635 | xfs_fsblock_t abno; /* allocated block number */ | ||
4636 | xfs_extlen_t alen; /* allocated extent length */ | ||
4637 | xfs_fileoff_t aoff; /* allocated file offset */ | ||
4638 | xfs_bmalloca_t bma = { 0 }; /* args for xfs_bmap_alloc */ | 4776 | xfs_bmalloca_t bma = { 0 }; /* args for xfs_bmap_alloc */ |
4639 | xfs_btree_cur_t *cur; /* bmap btree cursor */ | 4777 | xfs_btree_cur_t *cur; /* bmap btree cursor */ |
4640 | xfs_fileoff_t end; /* end of mapped file region */ | 4778 | xfs_fileoff_t end; /* end of mapped file region */ |
@@ -4646,7 +4784,6 @@ xfs_bmapi( | |||
4646 | xfs_extnum_t lastx; /* last useful extent number */ | 4784 | xfs_extnum_t lastx; /* last useful extent number */ |
4647 | int logflags; /* flags for transaction logging */ | 4785 | int logflags; /* flags for transaction logging */ |
4648 | xfs_extlen_t minleft; /* min blocks left after allocation */ | 4786 | xfs_extlen_t minleft; /* min blocks left after allocation */ |
4649 | xfs_extlen_t minlen; /* min allocation size */ | ||
4650 | xfs_mount_t *mp; /* xfs mount structure */ | 4787 | xfs_mount_t *mp; /* xfs mount structure */ |
4651 | int n; /* current extent index */ | 4788 | int n; /* current extent index */ |
4652 | int nallocs; /* number of extents alloc'd */ | 4789 | int nallocs; /* number of extents alloc'd */ |
@@ -4737,7 +4874,13 @@ xfs_bmapi( | |||
4737 | n = 0; | 4874 | n = 0; |
4738 | end = bno + len; | 4875 | end = bno + len; |
4739 | obno = bno; | 4876 | obno = bno; |
4740 | bma.ip = NULL; | 4877 | |
4878 | bma.tp = tp; | ||
4879 | bma.ip = ip; | ||
4880 | bma.prevp = &prev; | ||
4881 | bma.gotp = &got; | ||
4882 | bma.total = total; | ||
4883 | bma.userdata = 0; | ||
4741 | 4884 | ||
4742 | while (bno < end && n < *nmap) { | 4885 | while (bno < end && n < *nmap) { |
4743 | /* | 4886 | /* |
@@ -4753,144 +4896,23 @@ xfs_bmapi( | |||
4753 | * that we found, if any. | 4896 | * that we found, if any. |
4754 | */ | 4897 | */ |
4755 | if (wr && (inhole || wasdelay)) { | 4898 | if (wr && (inhole || wasdelay)) { |
4756 | /* | 4899 | bma.eof = eof; |
4757 | * For the wasdelay case, we could also just | 4900 | bma.conv = !!(flags & XFS_BMAPI_CONVERT); |
4758 | * allocate the stuff asked for in this bmap call | 4901 | bma.wasdel = wasdelay; |
4759 | * but that wouldn't be as good. | 4902 | bma.alen = len; |
4760 | */ | 4903 | bma.off = bno; |
4761 | if (wasdelay) { | 4904 | bma.minleft = minleft; |
4762 | alen = (xfs_extlen_t)got.br_blockcount; | 4905 | |
4763 | aoff = got.br_startoff; | 4906 | error = xfs_bmapi_allocate(&bma, &lastx, &cur, |
4764 | if (lastx != NULLEXTNUM && lastx) { | 4907 | firstblock, flist, flags, &nallocs, |
4765 | ep = xfs_iext_get_ext(ifp, lastx - 1); | 4908 | &tmp_logflags); |
4766 | xfs_bmbt_get_all(ep, &prev); | ||
4767 | } | ||
4768 | } else { | ||
4769 | alen = (xfs_extlen_t) | ||
4770 | XFS_FILBLKS_MIN(len, MAXEXTLEN); | ||
4771 | if (!eof) | ||
4772 | alen = (xfs_extlen_t) | ||
4773 | XFS_FILBLKS_MIN(alen, | ||
4774 | got.br_startoff - bno); | ||
4775 | aoff = bno; | ||
4776 | } | ||
4777 | minlen = (flags & XFS_BMAPI_CONTIG) ? alen : 1; | ||
4778 | { | ||
4779 | /* | ||
4780 | * If first time, allocate and fill in | ||
4781 | * once-only bma fields. | ||
4782 | */ | ||
4783 | if (bma.ip == NULL) { | ||
4784 | bma.tp = tp; | ||
4785 | bma.ip = ip; | ||
4786 | bma.prevp = &prev; | ||
4787 | bma.gotp = &got; | ||
4788 | bma.total = total; | ||
4789 | bma.userdata = 0; | ||
4790 | } | ||
4791 | /* Indicate if this is the first user data | ||
4792 | * in the file, or just any user data. | ||
4793 | */ | ||
4794 | if (!(flags & XFS_BMAPI_METADATA)) { | ||
4795 | bma.userdata = (aoff == 0) ? | ||
4796 | XFS_ALLOC_INITIAL_USER_DATA : | ||
4797 | XFS_ALLOC_USERDATA; | ||
4798 | } | ||
4799 | /* | ||
4800 | * Fill in changeable bma fields. | ||
4801 | */ | ||
4802 | bma.eof = eof; | ||
4803 | bma.firstblock = *firstblock; | ||
4804 | bma.alen = alen; | ||
4805 | bma.off = aoff; | ||
4806 | bma.conv = !!(flags & XFS_BMAPI_CONVERT); | ||
4807 | bma.wasdel = wasdelay; | ||
4808 | bma.minlen = minlen; | ||
4809 | bma.low = flist->xbf_low; | ||
4810 | bma.minleft = minleft; | ||
4811 | /* | ||
4812 | * Only want to do the alignment at the | ||
4813 | * eof if it is userdata and allocation length | ||
4814 | * is larger than a stripe unit. | ||
4815 | */ | ||
4816 | if (mp->m_dalign && alen >= mp->m_dalign && | ||
4817 | (!(flags & XFS_BMAPI_METADATA)) && | ||
4818 | (whichfork == XFS_DATA_FORK)) { | ||
4819 | if ((error = xfs_bmap_isaeof(ip, aoff, | ||
4820 | whichfork, &bma.aeof))) | ||
4821 | goto error0; | ||
4822 | } else | ||
4823 | bma.aeof = 0; | ||
4824 | /* | ||
4825 | * Call allocator. | ||
4826 | */ | ||
4827 | if ((error = xfs_bmap_alloc(&bma))) | ||
4828 | goto error0; | ||
4829 | /* | ||
4830 | * Copy out result fields. | ||
4831 | */ | ||
4832 | abno = bma.rval; | ||
4833 | if ((flist->xbf_low = bma.low)) | ||
4834 | minleft = 0; | ||
4835 | alen = bma.alen; | ||
4836 | aoff = bma.off; | ||
4837 | ASSERT(*firstblock == NULLFSBLOCK || | ||
4838 | XFS_FSB_TO_AGNO(mp, *firstblock) == | ||
4839 | XFS_FSB_TO_AGNO(mp, bma.firstblock) || | ||
4840 | (flist->xbf_low && | ||
4841 | XFS_FSB_TO_AGNO(mp, *firstblock) < | ||
4842 | XFS_FSB_TO_AGNO(mp, bma.firstblock))); | ||
4843 | *firstblock = bma.firstblock; | ||
4844 | if (cur) | ||
4845 | cur->bc_private.b.firstblock = | ||
4846 | *firstblock; | ||
4847 | if (abno == NULLFSBLOCK) | ||
4848 | break; | ||
4849 | if ((ifp->if_flags & XFS_IFBROOT) && !cur) { | ||
4850 | cur = xfs_bmbt_init_cursor(mp, tp, | ||
4851 | ip, whichfork); | ||
4852 | cur->bc_private.b.firstblock = | ||
4853 | *firstblock; | ||
4854 | cur->bc_private.b.flist = flist; | ||
4855 | } | ||
4856 | /* | ||
4857 | * Bump the number of extents we've allocated | ||
4858 | * in this call. | ||
4859 | */ | ||
4860 | nallocs++; | ||
4861 | } | ||
4862 | if (cur) | ||
4863 | cur->bc_private.b.flags = | ||
4864 | wasdelay ? XFS_BTCUR_BPRV_WASDEL : 0; | ||
4865 | got.br_startoff = aoff; | ||
4866 | got.br_startblock = abno; | ||
4867 | got.br_blockcount = alen; | ||
4868 | got.br_state = XFS_EXT_NORM; /* assume normal */ | ||
4869 | /* | ||
4870 | * Determine state of extent, and the filesystem. | ||
4871 | * A wasdelay extent has been initialized, so | ||
4872 | * shouldn't be flagged as unwritten. | ||
4873 | */ | ||
4874 | if (wr && xfs_sb_version_hasextflgbit(&mp->m_sb)) { | ||
4875 | if (!wasdelay && (flags & XFS_BMAPI_PREALLOC)) | ||
4876 | got.br_state = XFS_EXT_UNWRITTEN; | ||
4877 | } | ||
4878 | error = xfs_bmap_add_extent(tp, ip, &lastx, &cur, &got, | ||
4879 | firstblock, flist, &tmp_logflags, | ||
4880 | whichfork); | ||
4881 | logflags |= tmp_logflags; | 4909 | logflags |= tmp_logflags; |
4882 | if (error) | 4910 | if (error) |
4883 | goto error0; | 4911 | goto error0; |
4884 | ep = xfs_iext_get_ext(ifp, lastx); | 4912 | if (flist && flist->xbf_low) |
4885 | xfs_bmbt_get_all(ep, &got); | 4913 | minleft = 0; |
4886 | ASSERT(got.br_startoff <= aoff); | 4914 | if (bma.rval == NULLFSBLOCK) |
4887 | ASSERT(got.br_startoff + got.br_blockcount >= | 4915 | break; |
4888 | aoff + alen); | ||
4889 | ASSERT(got.br_state == XFS_EXT_NORM || | ||
4890 | got.br_state == XFS_EXT_UNWRITTEN); | ||
4891 | /* | ||
4892 | * Fall down into the found allocated space case. | ||
4893 | */ | ||
4894 | } else if (inhole) { | 4916 | } else if (inhole) { |
4895 | /* | 4917 | /* |
4896 | * Reading in a hole. | 4918 | * Reading in a hole. |