diff options
author | Dave Chinner <dchinner@redhat.com> | 2019-08-29 12:04:07 -0400 |
---|---|---|
committer | Darrick J. Wong <darrick.wong@oracle.com> | 2019-08-31 01:43:57 -0400 |
commit | 0e822255f95db400e56e19773e04755d79b50bda (patch) | |
tree | 4bf283a5959b9ce864a25d9725ca8fc7593a13e5 | |
parent | a07258a695281109422011182db069a0e6f8855e (diff) |
xfs: factor free block index lookup from xfs_dir2_node_addname_int()
Simplify the logic in xfs_dir2_node_addname_int() by factoring out
the free block index lookup code that finds a block with enough free
space for the entry to be added. The code that is moved gets a major
cleanup at the same time, but there is no algorithm change here.
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
-rw-r--r-- | fs/xfs/libxfs/xfs_dir2_node.c | 194 |
1 files changed, 102 insertions, 92 deletions
diff --git a/fs/xfs/libxfs/xfs_dir2_node.c b/fs/xfs/libxfs/xfs_dir2_node.c index cc1f1c505a2b..93254f45a5f9 100644 --- a/fs/xfs/libxfs/xfs_dir2_node.c +++ b/fs/xfs/libxfs/xfs_dir2_node.c | |||
@@ -1635,7 +1635,7 @@ xfs_dir2_node_add_datablk( | |||
1635 | int error; | 1635 | int error; |
1636 | 1636 | ||
1637 | /* Not allowed to allocate, return failure. */ | 1637 | /* Not allowed to allocate, return failure. */ |
1638 | if ((args->op_flags & XFS_DA_OP_JUSTCHECK) || args->total == 0) | 1638 | if (args->total == 0) |
1639 | return -ENOSPC; | 1639 | return -ENOSPC; |
1640 | 1640 | ||
1641 | /* Allocate and initialize the new data block. */ | 1641 | /* Allocate and initialize the new data block. */ |
@@ -1731,43 +1731,29 @@ xfs_dir2_node_add_datablk( | |||
1731 | return 0; | 1731 | return 0; |
1732 | } | 1732 | } |
1733 | 1733 | ||
1734 | /* | 1734 | static int |
1735 | * Add the data entry for a node-format directory name addition. | 1735 | xfs_dir2_node_find_freeblk( |
1736 | * The leaf entry is added in xfs_dir2_leafn_add. | 1736 | struct xfs_da_args *args, |
1737 | * We may enter with a freespace block that the lookup found. | 1737 | struct xfs_da_state_blk *fblk, |
1738 | */ | 1738 | xfs_dir2_db_t *dbnop, |
1739 | static int /* error */ | 1739 | struct xfs_buf **fbpp, |
1740 | xfs_dir2_node_addname_int( | 1740 | int *findexp, |
1741 | xfs_da_args_t *args, /* operation arguments */ | 1741 | int length) |
1742 | xfs_da_state_blk_t *fblk) /* optional freespace block */ | ||
1743 | { | 1742 | { |
1744 | xfs_dir2_data_hdr_t *hdr; /* data block header */ | ||
1745 | xfs_dir2_db_t dbno; /* data block number */ | ||
1746 | struct xfs_buf *dbp; /* data block buffer */ | ||
1747 | xfs_dir2_data_entry_t *dep; /* data entry pointer */ | ||
1748 | xfs_inode_t *dp; /* incore directory inode */ | ||
1749 | xfs_dir2_data_unused_t *dup; /* data unused entry pointer */ | ||
1750 | int error; /* error return value */ | ||
1751 | xfs_dir2_db_t fbno; /* freespace block number */ | ||
1752 | struct xfs_buf *fbp; /* freespace buffer */ | ||
1753 | int findex; /* freespace entry index */ | ||
1754 | xfs_dir2_free_t *free=NULL; /* freespace block structure */ | ||
1755 | xfs_dir2_db_t ifbno; /* initial freespace block no */ | ||
1756 | xfs_dir2_db_t lastfbno=0; /* highest freespace block no */ | ||
1757 | int length; /* length of the new entry */ | ||
1758 | int logfree = 0; /* need to log free entry */ | ||
1759 | int needlog = 0; /* need to log data header */ | ||
1760 | int needscan = 0; /* need to rescan data frees */ | ||
1761 | __be16 *tagp; /* data entry tag pointer */ | ||
1762 | xfs_trans_t *tp; /* transaction pointer */ | ||
1763 | __be16 *bests; | ||
1764 | struct xfs_dir3_icfree_hdr freehdr; | 1743 | struct xfs_dir3_icfree_hdr freehdr; |
1765 | struct xfs_dir2_data_free *bf; | 1744 | struct xfs_dir2_free *free = NULL; |
1766 | xfs_dir2_data_aoff_t aoff; | 1745 | struct xfs_inode *dp = args->dp; |
1746 | struct xfs_trans *tp = args->trans; | ||
1747 | struct xfs_buf *fbp = NULL; | ||
1748 | xfs_dir2_db_t lastfbno; | ||
1749 | xfs_dir2_db_t ifbno = -1; | ||
1750 | xfs_dir2_db_t dbno = -1; | ||
1751 | xfs_dir2_db_t fbno = -1; | ||
1752 | xfs_fileoff_t fo; | ||
1753 | __be16 *bests; | ||
1754 | int findex; | ||
1755 | int error; | ||
1767 | 1756 | ||
1768 | dp = args->dp; | ||
1769 | tp = args->trans; | ||
1770 | length = dp->d_ops->data_entsize(args->namelen); | ||
1771 | /* | 1757 | /* |
1772 | * If we came in with a freespace block that means that lookup | 1758 | * If we came in with a freespace block that means that lookup |
1773 | * found an entry with our hash value. This is the freespace | 1759 | * found an entry with our hash value. This is the freespace |
@@ -1775,56 +1761,44 @@ xfs_dir2_node_addname_int( | |||
1775 | */ | 1761 | */ |
1776 | if (fblk) { | 1762 | if (fblk) { |
1777 | fbp = fblk->bp; | 1763 | fbp = fblk->bp; |
1778 | /* | ||
1779 | * Remember initial freespace block number. | ||
1780 | */ | ||
1781 | ifbno = fblk->blkno; | ||
1782 | free = fbp->b_addr; | 1764 | free = fbp->b_addr; |
1783 | findex = fblk->index; | 1765 | findex = fblk->index; |
1784 | bests = dp->d_ops->free_bests_p(free); | ||
1785 | dp->d_ops->free_hdr_from_disk(&freehdr, free); | ||
1786 | |||
1787 | /* | ||
1788 | * This means the free entry showed that the data block had | ||
1789 | * space for our entry, so we remembered it. | ||
1790 | * Use that data block. | ||
1791 | */ | ||
1792 | if (findex >= 0) { | 1766 | if (findex >= 0) { |
1767 | /* caller already found the freespace for us. */ | ||
1768 | bests = dp->d_ops->free_bests_p(free); | ||
1769 | dp->d_ops->free_hdr_from_disk(&freehdr, free); | ||
1770 | |||
1793 | ASSERT(findex < freehdr.nvalid); | 1771 | ASSERT(findex < freehdr.nvalid); |
1794 | ASSERT(be16_to_cpu(bests[findex]) != NULLDATAOFF); | 1772 | ASSERT(be16_to_cpu(bests[findex]) != NULLDATAOFF); |
1795 | ASSERT(be16_to_cpu(bests[findex]) >= length); | 1773 | ASSERT(be16_to_cpu(bests[findex]) >= length); |
1796 | dbno = freehdr.firstdb + findex; | 1774 | dbno = freehdr.firstdb + findex; |
1797 | goto found_block; | 1775 | goto found_block; |
1798 | } else { | ||
1799 | /* | ||
1800 | * The data block looked at didn't have enough room. | ||
1801 | * We'll start at the beginning of the freespace entries. | ||
1802 | */ | ||
1803 | dbno = -1; | ||
1804 | findex = 0; | ||
1805 | } | 1776 | } |
1806 | } else { | 1777 | |
1807 | /* | 1778 | /* |
1808 | * Didn't come in with a freespace block, so no data block. | 1779 | * The data block looked at didn't have enough room. |
1780 | * We'll start at the beginning of the freespace entries. | ||
1809 | */ | 1781 | */ |
1810 | ifbno = dbno = -1; | 1782 | ifbno = fblk->blkno; |
1811 | fbp = NULL; | 1783 | fbno = ifbno; |
1812 | findex = 0; | ||
1813 | } | 1784 | } |
1785 | ASSERT(dbno == -1); | ||
1786 | findex = 0; | ||
1814 | 1787 | ||
1815 | /* | 1788 | /* |
1816 | * If we don't have a data block yet, we're going to scan the | 1789 | * If we don't have a data block yet, we're going to scan the freespace |
1817 | * freespace blocks looking for one. Figure out what the | 1790 | * blocks looking for one. Figure out what the highest freespace block |
1818 | * highest freespace block number is. | 1791 | * number is. |
1819 | */ | 1792 | */ |
1820 | if (dbno == -1) { | 1793 | error = xfs_bmap_last_offset(dp, &fo, XFS_DATA_FORK); |
1821 | xfs_fileoff_t fo; /* freespace block number */ | 1794 | if (error) |
1795 | return error; | ||
1796 | lastfbno = xfs_dir2_da_to_db(args->geo, (xfs_dablk_t)fo); | ||
1797 | |||
1798 | /* If we haven't get a search start block, set it now */ | ||
1799 | if (fbno == -1) | ||
1800 | fbno = xfs_dir2_byte_to_db(args->geo, XFS_DIR2_FREE_OFFSET); | ||
1822 | 1801 | ||
1823 | if ((error = xfs_bmap_last_offset(dp, &fo, XFS_DATA_FORK))) | ||
1824 | return error; | ||
1825 | lastfbno = xfs_dir2_da_to_db(args->geo, (xfs_dablk_t)fo); | ||
1826 | fbno = ifbno; | ||
1827 | } | ||
1828 | /* | 1802 | /* |
1829 | * While we haven't identified a data block, search the freeblock | 1803 | * While we haven't identified a data block, search the freeblock |
1830 | * data for a good data block. If we find a null freeblock entry, | 1804 | * data for a good data block. If we find a null freeblock entry, |
@@ -1836,16 +1810,9 @@ xfs_dir2_node_addname_int( | |||
1836 | */ | 1810 | */ |
1837 | if (fbp == NULL) { | 1811 | if (fbp == NULL) { |
1838 | /* | 1812 | /* |
1839 | * Happens the first time through unless lookup gave | ||
1840 | * us a freespace block to start with. | ||
1841 | */ | ||
1842 | if (++fbno == 0) | ||
1843 | fbno = xfs_dir2_byte_to_db(args->geo, | ||
1844 | XFS_DIR2_FREE_OFFSET); | ||
1845 | /* | ||
1846 | * If it's ifbno we already looked at it. | 1813 | * If it's ifbno we already looked at it. |
1847 | */ | 1814 | */ |
1848 | if (fbno == ifbno) | 1815 | if (++fbno == ifbno) |
1849 | fbno++; | 1816 | fbno++; |
1850 | /* | 1817 | /* |
1851 | * If it's off the end we're done. | 1818 | * If it's off the end we're done. |
@@ -1896,35 +1863,77 @@ xfs_dir2_node_addname_int( | |||
1896 | } | 1863 | } |
1897 | } | 1864 | } |
1898 | } | 1865 | } |
1866 | found_block: | ||
1867 | *dbnop = dbno; | ||
1868 | *fbpp = fbp; | ||
1869 | *findexp = findex; | ||
1870 | return 0; | ||
1871 | } | ||
1872 | |||
1873 | |||
1874 | /* | ||
1875 | * Add the data entry for a node-format directory name addition. | ||
1876 | * The leaf entry is added in xfs_dir2_leafn_add. | ||
1877 | * We may enter with a freespace block that the lookup found. | ||
1878 | */ | ||
1879 | static int | ||
1880 | xfs_dir2_node_addname_int( | ||
1881 | struct xfs_da_args *args, /* operation arguments */ | ||
1882 | struct xfs_da_state_blk *fblk) /* optional freespace block */ | ||
1883 | { | ||
1884 | struct xfs_dir2_data_unused *dup; /* data unused entry pointer */ | ||
1885 | struct xfs_dir2_data_entry *dep; /* data entry pointer */ | ||
1886 | struct xfs_dir2_data_hdr *hdr; /* data block header */ | ||
1887 | struct xfs_dir2_data_free *bf; | ||
1888 | struct xfs_dir2_free *free = NULL; /* freespace block structure */ | ||
1889 | struct xfs_trans *tp = args->trans; | ||
1890 | struct xfs_inode *dp = args->dp; | ||
1891 | struct xfs_buf *dbp; /* data block buffer */ | ||
1892 | struct xfs_buf *fbp; /* freespace buffer */ | ||
1893 | xfs_dir2_data_aoff_t aoff; | ||
1894 | xfs_dir2_db_t dbno; /* data block number */ | ||
1895 | int error; /* error return value */ | ||
1896 | int findex; /* freespace entry index */ | ||
1897 | int length; /* length of the new entry */ | ||
1898 | int logfree = 0; /* need to log free entry */ | ||
1899 | int needlog = 0; /* need to log data header */ | ||
1900 | int needscan = 0; /* need to rescan data frees */ | ||
1901 | __be16 *tagp; /* data entry tag pointer */ | ||
1902 | __be16 *bests; | ||
1903 | |||
1904 | length = dp->d_ops->data_entsize(args->namelen); | ||
1905 | error = xfs_dir2_node_find_freeblk(args, fblk, &dbno, &fbp, &findex, | ||
1906 | length); | ||
1907 | if (error) | ||
1908 | return error; | ||
1909 | |||
1910 | /* | ||
1911 | * Now we know if we must allocate blocks, so if we are checking whether | ||
1912 | * we can insert without allocation then we can return now. | ||
1913 | */ | ||
1914 | if (args->op_flags & XFS_DA_OP_JUSTCHECK) { | ||
1915 | if (dbno == -1) | ||
1916 | return -ENOSPC; | ||
1917 | return 0; | ||
1918 | } | ||
1899 | 1919 | ||
1900 | /* | 1920 | /* |
1901 | * If we don't have a data block, we need to allocate one and make | 1921 | * If we don't have a data block, we need to allocate one and make |
1902 | * the freespace entries refer to it. | 1922 | * the freespace entries refer to it. |
1903 | */ | 1923 | */ |
1904 | if (dbno == -1) { | 1924 | if (dbno == -1) { |
1905 | error = xfs_dir2_node_add_datablk(args, fblk, &dbno, &dbp, &fbp, | ||
1906 | &findex); | ||
1907 | if (error) | ||
1908 | return error; | ||
1909 | |||
1910 | /* setup current free block buffer */ | ||
1911 | free = fbp->b_addr; | ||
1912 | |||
1913 | /* we're going to have to log the free block index later */ | 1925 | /* we're going to have to log the free block index later */ |
1914 | logfree = 1; | 1926 | logfree = 1; |
1927 | error = xfs_dir2_node_add_datablk(args, fblk, &dbno, &dbp, &fbp, | ||
1928 | &findex); | ||
1915 | } else { | 1929 | } else { |
1916 | found_block: | ||
1917 | /* If just checking, we succeeded. */ | ||
1918 | if (args->op_flags & XFS_DA_OP_JUSTCHECK) | ||
1919 | return 0; | ||
1920 | |||
1921 | /* Read the data block in. */ | 1930 | /* Read the data block in. */ |
1922 | error = xfs_dir3_data_read(tp, dp, | 1931 | error = xfs_dir3_data_read(tp, dp, |
1923 | xfs_dir2_db_to_da(args->geo, dbno), | 1932 | xfs_dir2_db_to_da(args->geo, dbno), |
1924 | -1, &dbp); | 1933 | -1, &dbp); |
1925 | if (error) | ||
1926 | return error; | ||
1927 | } | 1934 | } |
1935 | if (error) | ||
1936 | return error; | ||
1928 | 1937 | ||
1929 | /* setup for data block up now */ | 1938 | /* setup for data block up now */ |
1930 | hdr = dbp->b_addr; | 1939 | hdr = dbp->b_addr; |
@@ -1961,6 +1970,7 @@ found_block: | |||
1961 | xfs_dir2_data_log_header(args, dbp); | 1970 | xfs_dir2_data_log_header(args, dbp); |
1962 | 1971 | ||
1963 | /* If the freespace block entry is now wrong, update it. */ | 1972 | /* If the freespace block entry is now wrong, update it. */ |
1973 | free = fbp->b_addr; | ||
1964 | bests = dp->d_ops->free_bests_p(free); | 1974 | bests = dp->d_ops->free_bests_p(free); |
1965 | if (bests[findex] != bf[0].length) { | 1975 | if (bests[findex] != bf[0].length) { |
1966 | bests[findex] = bf[0].length; | 1976 | bests[findex] = bf[0].length; |