diff options
Diffstat (limited to 'fs/ocfs2/xattr.c')
| -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; |
