diff options
Diffstat (limited to 'fs/ocfs2')
-rw-r--r-- | fs/ocfs2/xattr.c | 190 |
1 files changed, 154 insertions, 36 deletions
diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c index 661ed9b85dbf..8d1a0abc105c 100644 --- a/fs/ocfs2/xattr.c +++ b/fs/ocfs2/xattr.c | |||
@@ -199,6 +199,11 @@ static int ocfs2_prepare_refcount_xattr(struct inode *inode, | |||
199 | struct ocfs2_refcount_tree **ref_tree, | 199 | struct ocfs2_refcount_tree **ref_tree, |
200 | int *meta_need, | 200 | int *meta_need, |
201 | int *credits); | 201 | int *credits); |
202 | static int ocfs2_get_xattr_tree_value_root(struct super_block *sb, | ||
203 | struct ocfs2_xattr_bucket *bucket, | ||
204 | int offset, | ||
205 | struct ocfs2_xattr_value_root **xv, | ||
206 | struct buffer_head **bh); | ||
202 | 207 | ||
203 | static inline u16 ocfs2_xattr_buckets_per_cluster(struct ocfs2_super *osb) | 208 | static inline u16 ocfs2_xattr_buckets_per_cluster(struct ocfs2_super *osb) |
204 | { | 209 | { |
@@ -1752,51 +1757,112 @@ out: | |||
1752 | return ret; | 1757 | return ret; |
1753 | } | 1758 | } |
1754 | 1759 | ||
1760 | /* | ||
1761 | * In xattr remove, if it is stored outside and refcounted, we may have | ||
1762 | * the chance to split the refcount tree. So need the allocators. | ||
1763 | */ | ||
1764 | static int ocfs2_lock_xattr_remove_allocators(struct inode *inode, | ||
1765 | struct ocfs2_xattr_value_root *xv, | ||
1766 | struct ocfs2_caching_info *ref_ci, | ||
1767 | struct buffer_head *ref_root_bh, | ||
1768 | struct ocfs2_alloc_context **meta_ac, | ||
1769 | int *ref_credits) | ||
1770 | { | ||
1771 | int ret, meta_add = 0; | ||
1772 | u32 p_cluster, num_clusters; | ||
1773 | unsigned int ext_flags; | ||
1774 | |||
1775 | *ref_credits = 0; | ||
1776 | ret = ocfs2_xattr_get_clusters(inode, 0, &p_cluster, | ||
1777 | &num_clusters, | ||
1778 | &xv->xr_list, | ||
1779 | &ext_flags); | ||
1780 | if (ret) { | ||
1781 | mlog_errno(ret); | ||
1782 | goto out; | ||
1783 | } | ||
1784 | |||
1785 | if (!(ext_flags & OCFS2_EXT_REFCOUNTED)) | ||
1786 | goto out; | ||
1787 | |||
1788 | ret = ocfs2_refcounted_xattr_delete_need(inode, ref_ci, | ||
1789 | ref_root_bh, xv, | ||
1790 | &meta_add, ref_credits); | ||
1791 | if (ret) { | ||
1792 | mlog_errno(ret); | ||
1793 | goto out; | ||
1794 | } | ||
1795 | |||
1796 | ret = ocfs2_reserve_new_metadata_blocks(OCFS2_SB(inode->i_sb), | ||
1797 | meta_add, meta_ac); | ||
1798 | if (ret) | ||
1799 | mlog_errno(ret); | ||
1800 | |||
1801 | out: | ||
1802 | return ret; | ||
1803 | } | ||
1804 | |||
1755 | static int ocfs2_remove_value_outside(struct inode*inode, | 1805 | static int ocfs2_remove_value_outside(struct inode*inode, |
1756 | struct ocfs2_xattr_value_buf *vb, | 1806 | struct ocfs2_xattr_value_buf *vb, |
1757 | struct ocfs2_xattr_header *header) | 1807 | struct ocfs2_xattr_header *header, |
1808 | struct ocfs2_caching_info *ref_ci, | ||
1809 | struct buffer_head *ref_root_bh) | ||
1758 | { | 1810 | { |
1759 | int ret = 0, i; | 1811 | int ret = 0, i, ref_credits; |
1760 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | 1812 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); |
1761 | struct ocfs2_xattr_set_ctxt ctxt = { NULL, NULL, }; | 1813 | struct ocfs2_xattr_set_ctxt ctxt = { NULL, NULL, }; |
1814 | void *val; | ||
1762 | 1815 | ||
1763 | ocfs2_init_dealloc_ctxt(&ctxt.dealloc); | 1816 | ocfs2_init_dealloc_ctxt(&ctxt.dealloc); |
1764 | 1817 | ||
1765 | ctxt.handle = ocfs2_start_trans(osb, | ||
1766 | ocfs2_remove_extent_credits(osb->sb)); | ||
1767 | if (IS_ERR(ctxt.handle)) { | ||
1768 | ret = PTR_ERR(ctxt.handle); | ||
1769 | mlog_errno(ret); | ||
1770 | goto out; | ||
1771 | } | ||
1772 | |||
1773 | for (i = 0; i < le16_to_cpu(header->xh_count); i++) { | 1818 | for (i = 0; i < le16_to_cpu(header->xh_count); i++) { |
1774 | struct ocfs2_xattr_entry *entry = &header->xh_entries[i]; | 1819 | struct ocfs2_xattr_entry *entry = &header->xh_entries[i]; |
1775 | 1820 | ||
1776 | if (!ocfs2_xattr_is_local(entry)) { | 1821 | if (ocfs2_xattr_is_local(entry)) |
1777 | void *val; | 1822 | continue; |
1778 | 1823 | ||
1779 | val = (void *)header + | 1824 | val = (void *)header + |
1780 | le16_to_cpu(entry->xe_name_offset); | 1825 | le16_to_cpu(entry->xe_name_offset); |
1781 | vb->vb_xv = (struct ocfs2_xattr_value_root *) | 1826 | vb->vb_xv = (struct ocfs2_xattr_value_root *) |
1782 | (val + OCFS2_XATTR_SIZE(entry->xe_name_len)); | 1827 | (val + OCFS2_XATTR_SIZE(entry->xe_name_len)); |
1783 | ret = ocfs2_xattr_value_truncate(inode, vb, 0, &ctxt); | 1828 | |
1784 | if (ret < 0) { | 1829 | ret = ocfs2_lock_xattr_remove_allocators(inode, vb->vb_xv, |
1785 | mlog_errno(ret); | 1830 | ref_ci, ref_root_bh, |
1786 | break; | 1831 | &ctxt.meta_ac, |
1787 | } | 1832 | &ref_credits); |
1833 | |||
1834 | ctxt.handle = ocfs2_start_trans(osb, ref_credits + | ||
1835 | ocfs2_remove_extent_credits(osb->sb)); | ||
1836 | if (IS_ERR(ctxt.handle)) { | ||
1837 | ret = PTR_ERR(ctxt.handle); | ||
1838 | mlog_errno(ret); | ||
1839 | break; | ||
1840 | } | ||
1841 | |||
1842 | ret = ocfs2_xattr_value_truncate(inode, vb, 0, &ctxt); | ||
1843 | if (ret < 0) { | ||
1844 | mlog_errno(ret); | ||
1845 | break; | ||
1846 | } | ||
1847 | |||
1848 | ocfs2_commit_trans(osb, ctxt.handle); | ||
1849 | if (ctxt.meta_ac) { | ||
1850 | ocfs2_free_alloc_context(ctxt.meta_ac); | ||
1851 | ctxt.meta_ac = NULL; | ||
1788 | } | 1852 | } |
1789 | } | 1853 | } |
1790 | 1854 | ||
1791 | ocfs2_commit_trans(osb, ctxt.handle); | 1855 | if (ctxt.meta_ac) |
1856 | ocfs2_free_alloc_context(ctxt.meta_ac); | ||
1792 | ocfs2_schedule_truncate_log_flush(osb, 1); | 1857 | ocfs2_schedule_truncate_log_flush(osb, 1); |
1793 | ocfs2_run_deallocs(osb, &ctxt.dealloc); | 1858 | ocfs2_run_deallocs(osb, &ctxt.dealloc); |
1794 | out: | ||
1795 | return ret; | 1859 | return ret; |
1796 | } | 1860 | } |
1797 | 1861 | ||
1798 | static int ocfs2_xattr_ibody_remove(struct inode *inode, | 1862 | static int ocfs2_xattr_ibody_remove(struct inode *inode, |
1799 | struct buffer_head *di_bh) | 1863 | struct buffer_head *di_bh, |
1864 | struct ocfs2_caching_info *ref_ci, | ||
1865 | struct buffer_head *ref_root_bh) | ||
1800 | { | 1866 | { |
1801 | 1867 | ||
1802 | struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; | 1868 | struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; |
@@ -1811,13 +1877,21 @@ static int ocfs2_xattr_ibody_remove(struct inode *inode, | |||
1811 | ((void *)di + inode->i_sb->s_blocksize - | 1877 | ((void *)di + inode->i_sb->s_blocksize - |
1812 | le16_to_cpu(di->i_xattr_inline_size)); | 1878 | le16_to_cpu(di->i_xattr_inline_size)); |
1813 | 1879 | ||
1814 | ret = ocfs2_remove_value_outside(inode, &vb, header); | 1880 | ret = ocfs2_remove_value_outside(inode, &vb, header, |
1881 | ref_ci, ref_root_bh); | ||
1815 | 1882 | ||
1816 | return ret; | 1883 | return ret; |
1817 | } | 1884 | } |
1818 | 1885 | ||
1886 | struct ocfs2_rm_xattr_bucket_para { | ||
1887 | struct ocfs2_caching_info *ref_ci; | ||
1888 | struct buffer_head *ref_root_bh; | ||
1889 | }; | ||
1890 | |||
1819 | static int ocfs2_xattr_block_remove(struct inode *inode, | 1891 | static int ocfs2_xattr_block_remove(struct inode *inode, |
1820 | struct buffer_head *blk_bh) | 1892 | struct buffer_head *blk_bh, |
1893 | struct ocfs2_caching_info *ref_ci, | ||
1894 | struct buffer_head *ref_root_bh) | ||
1821 | { | 1895 | { |
1822 | struct ocfs2_xattr_block *xb; | 1896 | struct ocfs2_xattr_block *xb; |
1823 | int ret = 0; | 1897 | int ret = 0; |
@@ -1825,22 +1899,29 @@ static int ocfs2_xattr_block_remove(struct inode *inode, | |||
1825 | .vb_bh = blk_bh, | 1899 | .vb_bh = blk_bh, |
1826 | .vb_access = ocfs2_journal_access_xb, | 1900 | .vb_access = ocfs2_journal_access_xb, |
1827 | }; | 1901 | }; |
1902 | struct ocfs2_rm_xattr_bucket_para args = { | ||
1903 | .ref_ci = ref_ci, | ||
1904 | .ref_root_bh = ref_root_bh, | ||
1905 | }; | ||
1828 | 1906 | ||
1829 | xb = (struct ocfs2_xattr_block *)blk_bh->b_data; | 1907 | xb = (struct ocfs2_xattr_block *)blk_bh->b_data; |
1830 | if (!(le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED)) { | 1908 | if (!(le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED)) { |
1831 | struct ocfs2_xattr_header *header = &(xb->xb_attrs.xb_header); | 1909 | struct ocfs2_xattr_header *header = &(xb->xb_attrs.xb_header); |
1832 | ret = ocfs2_remove_value_outside(inode, &vb, header); | 1910 | ret = ocfs2_remove_value_outside(inode, &vb, header, |
1911 | ref_ci, ref_root_bh); | ||
1833 | } else | 1912 | } else |
1834 | ret = ocfs2_iterate_xattr_index_block(inode, | 1913 | ret = ocfs2_iterate_xattr_index_block(inode, |
1835 | blk_bh, | 1914 | blk_bh, |
1836 | ocfs2_rm_xattr_cluster, | 1915 | ocfs2_rm_xattr_cluster, |
1837 | NULL); | 1916 | &args); |
1838 | 1917 | ||
1839 | return ret; | 1918 | return ret; |
1840 | } | 1919 | } |
1841 | 1920 | ||
1842 | static int ocfs2_xattr_free_block(struct inode *inode, | 1921 | static int ocfs2_xattr_free_block(struct inode *inode, |
1843 | u64 block) | 1922 | u64 block, |
1923 | struct ocfs2_caching_info *ref_ci, | ||
1924 | struct buffer_head *ref_root_bh) | ||
1844 | { | 1925 | { |
1845 | struct inode *xb_alloc_inode; | 1926 | struct inode *xb_alloc_inode; |
1846 | struct buffer_head *xb_alloc_bh = NULL; | 1927 | struct buffer_head *xb_alloc_bh = NULL; |
@@ -1858,7 +1939,7 @@ static int ocfs2_xattr_free_block(struct inode *inode, | |||
1858 | goto out; | 1939 | goto out; |
1859 | } | 1940 | } |
1860 | 1941 | ||
1861 | ret = ocfs2_xattr_block_remove(inode, blk_bh); | 1942 | ret = ocfs2_xattr_block_remove(inode, blk_bh, ref_ci, ref_root_bh); |
1862 | if (ret < 0) { | 1943 | if (ret < 0) { |
1863 | mlog_errno(ret); | 1944 | mlog_errno(ret); |
1864 | goto out; | 1945 | goto out; |
@@ -1918,6 +1999,9 @@ int ocfs2_xattr_remove(struct inode *inode, struct buffer_head *di_bh) | |||
1918 | { | 1999 | { |
1919 | struct ocfs2_inode_info *oi = OCFS2_I(inode); | 2000 | struct ocfs2_inode_info *oi = OCFS2_I(inode); |
1920 | struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; | 2001 | struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; |
2002 | struct ocfs2_refcount_tree *ref_tree = NULL; | ||
2003 | struct buffer_head *ref_root_bh = NULL; | ||
2004 | struct ocfs2_caching_info *ref_ci = NULL; | ||
1921 | handle_t *handle; | 2005 | handle_t *handle; |
1922 | int ret; | 2006 | int ret; |
1923 | 2007 | ||
@@ -1927,8 +2011,21 @@ int ocfs2_xattr_remove(struct inode *inode, struct buffer_head *di_bh) | |||
1927 | if (!(oi->ip_dyn_features & OCFS2_HAS_XATTR_FL)) | 2011 | if (!(oi->ip_dyn_features & OCFS2_HAS_XATTR_FL)) |
1928 | return 0; | 2012 | return 0; |
1929 | 2013 | ||
2014 | if (OCFS2_I(inode)->ip_dyn_features & OCFS2_HAS_REFCOUNT_FL) { | ||
2015 | ret = ocfs2_lock_refcount_tree(OCFS2_SB(inode->i_sb), | ||
2016 | le64_to_cpu(di->i_refcount_loc), | ||
2017 | 1, &ref_tree, &ref_root_bh); | ||
2018 | if (ret) { | ||
2019 | mlog_errno(ret); | ||
2020 | goto out; | ||
2021 | } | ||
2022 | ref_ci = &ref_tree->rf_ci; | ||
2023 | |||
2024 | } | ||
2025 | |||
1930 | if (oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL) { | 2026 | if (oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL) { |
1931 | ret = ocfs2_xattr_ibody_remove(inode, di_bh); | 2027 | ret = ocfs2_xattr_ibody_remove(inode, di_bh, |
2028 | ref_ci, ref_root_bh); | ||
1932 | if (ret < 0) { | 2029 | if (ret < 0) { |
1933 | mlog_errno(ret); | 2030 | mlog_errno(ret); |
1934 | goto out; | 2031 | goto out; |
@@ -1937,7 +2034,8 @@ int ocfs2_xattr_remove(struct inode *inode, struct buffer_head *di_bh) | |||
1937 | 2034 | ||
1938 | if (di->i_xattr_loc) { | 2035 | if (di->i_xattr_loc) { |
1939 | ret = ocfs2_xattr_free_block(inode, | 2036 | ret = ocfs2_xattr_free_block(inode, |
1940 | le64_to_cpu(di->i_xattr_loc)); | 2037 | le64_to_cpu(di->i_xattr_loc), |
2038 | ref_ci, ref_root_bh); | ||
1941 | if (ret < 0) { | 2039 | if (ret < 0) { |
1942 | mlog_errno(ret); | 2040 | mlog_errno(ret); |
1943 | goto out; | 2041 | goto out; |
@@ -1971,6 +2069,9 @@ int ocfs2_xattr_remove(struct inode *inode, struct buffer_head *di_bh) | |||
1971 | out_commit: | 2069 | out_commit: |
1972 | ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle); | 2070 | ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle); |
1973 | out: | 2071 | out: |
2072 | if (ref_tree) | ||
2073 | ocfs2_unlock_refcount_tree(OCFS2_SB(inode->i_sb), ref_tree, 1); | ||
2074 | brelse(ref_root_bh); | ||
1974 | return ret; | 2075 | return ret; |
1975 | } | 2076 | } |
1976 | 2077 | ||
@@ -4989,7 +5090,7 @@ static int ocfs2_rm_xattr_cluster(struct inode *inode, | |||
4989 | struct ocfs2_extent_tree et; | 5090 | struct ocfs2_extent_tree et; |
4990 | 5091 | ||
4991 | ret = ocfs2_iterate_xattr_buckets(inode, blkno, len, | 5092 | ret = ocfs2_iterate_xattr_buckets(inode, blkno, len, |
4992 | ocfs2_delete_xattr_in_bucket, NULL); | 5093 | ocfs2_delete_xattr_in_bucket, para); |
4993 | if (ret) { | 5094 | if (ret) { |
4994 | mlog_errno(ret); | 5095 | mlog_errno(ret); |
4995 | return ret; | 5096 | return ret; |
@@ -5378,7 +5479,7 @@ static int ocfs2_delete_xattr_in_bucket(struct inode *inode, | |||
5378 | struct ocfs2_xattr_bucket *bucket, | 5479 | struct ocfs2_xattr_bucket *bucket, |
5379 | void *para) | 5480 | void *para) |
5380 | { | 5481 | { |
5381 | int ret = 0; | 5482 | int ret = 0, ref_credits; |
5382 | struct ocfs2_xattr_header *xh = bucket_xh(bucket); | 5483 | struct ocfs2_xattr_header *xh = bucket_xh(bucket); |
5383 | u16 i; | 5484 | u16 i; |
5384 | struct ocfs2_xattr_entry *xe; | 5485 | struct ocfs2_xattr_entry *xe; |
@@ -5386,7 +5487,9 @@ static int ocfs2_delete_xattr_in_bucket(struct inode *inode, | |||
5386 | struct ocfs2_xattr_set_ctxt ctxt = {NULL, NULL,}; | 5487 | struct ocfs2_xattr_set_ctxt ctxt = {NULL, NULL,}; |
5387 | int credits = ocfs2_remove_extent_credits(osb->sb) + | 5488 | int credits = ocfs2_remove_extent_credits(osb->sb) + |
5388 | ocfs2_blocks_per_xattr_bucket(inode->i_sb); | 5489 | ocfs2_blocks_per_xattr_bucket(inode->i_sb); |
5389 | 5490 | struct ocfs2_xattr_value_root *xv; | |
5491 | struct ocfs2_rm_xattr_bucket_para *args = | ||
5492 | (struct ocfs2_rm_xattr_bucket_para *)para; | ||
5390 | 5493 | ||
5391 | ocfs2_init_dealloc_ctxt(&ctxt.dealloc); | 5494 | ocfs2_init_dealloc_ctxt(&ctxt.dealloc); |
5392 | 5495 | ||
@@ -5395,7 +5498,16 @@ static int ocfs2_delete_xattr_in_bucket(struct inode *inode, | |||
5395 | if (ocfs2_xattr_is_local(xe)) | 5498 | if (ocfs2_xattr_is_local(xe)) |
5396 | continue; | 5499 | continue; |
5397 | 5500 | ||
5398 | ctxt.handle = ocfs2_start_trans(osb, credits); | 5501 | ret = ocfs2_get_xattr_tree_value_root(inode->i_sb, bucket, |
5502 | i, &xv, NULL); | ||
5503 | |||
5504 | ret = ocfs2_lock_xattr_remove_allocators(inode, xv, | ||
5505 | args->ref_ci, | ||
5506 | args->ref_root_bh, | ||
5507 | &ctxt.meta_ac, | ||
5508 | &ref_credits); | ||
5509 | |||
5510 | ctxt.handle = ocfs2_start_trans(osb, credits + ref_credits); | ||
5399 | if (IS_ERR(ctxt.handle)) { | 5511 | if (IS_ERR(ctxt.handle)) { |
5400 | ret = PTR_ERR(ctxt.handle); | 5512 | ret = PTR_ERR(ctxt.handle); |
5401 | mlog_errno(ret); | 5513 | mlog_errno(ret); |
@@ -5406,12 +5518,18 @@ static int ocfs2_delete_xattr_in_bucket(struct inode *inode, | |||
5406 | i, 0, &ctxt); | 5518 | i, 0, &ctxt); |
5407 | 5519 | ||
5408 | ocfs2_commit_trans(osb, ctxt.handle); | 5520 | ocfs2_commit_trans(osb, ctxt.handle); |
5521 | if (ctxt.meta_ac) { | ||
5522 | ocfs2_free_alloc_context(ctxt.meta_ac); | ||
5523 | ctxt.meta_ac = NULL; | ||
5524 | } | ||
5409 | if (ret) { | 5525 | if (ret) { |
5410 | mlog_errno(ret); | 5526 | mlog_errno(ret); |
5411 | break; | 5527 | break; |
5412 | } | 5528 | } |
5413 | } | 5529 | } |
5414 | 5530 | ||
5531 | if (ctxt.meta_ac) | ||
5532 | ocfs2_free_alloc_context(ctxt.meta_ac); | ||
5415 | ocfs2_schedule_truncate_log_flush(osb, 1); | 5533 | ocfs2_schedule_truncate_log_flush(osb, 1); |
5416 | ocfs2_run_deallocs(osb, &ctxt.dealloc); | 5534 | ocfs2_run_deallocs(osb, &ctxt.dealloc); |
5417 | return ret; | 5535 | return ret; |