aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ocfs2
diff options
context:
space:
mode:
authorTao Ma <tao.ma@oracle.com>2009-08-17 23:24:49 -0400
committerJoel Becker <joel.becker@oracle.com>2009-09-22 23:09:33 -0400
commit1823cb0b9fe5e6d48017ee3f92428f69c0235d87 (patch)
tree461e5d6cc255c400acac69dd968fae935a9c073f /fs/ocfs2
parente73a819db9c2d6c4065b7cab7374709b6939e8f1 (diff)
ocfs2: Add support of decrementing refcount for delete.
Given a physical cpos and length, decrement the refcount in the tree. If the refcount for any portion of the extent goes to zero, that portion is queued for freeing. Signed-off-by: Tao Ma <tao.ma@oracle.com>
Diffstat (limited to 'fs/ocfs2')
-rw-r--r--fs/ocfs2/alloc.c6
-rw-r--r--fs/ocfs2/alloc.h3
-rw-r--r--fs/ocfs2/refcounttree.c256
-rw-r--r--fs/ocfs2/refcounttree.h5
4 files changed, 265 insertions, 5 deletions
diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c
index 2c8ce32adf01..9dd68cd7b0ad 100644
--- a/fs/ocfs2/alloc.c
+++ b/fs/ocfs2/alloc.c
@@ -6522,9 +6522,9 @@ ocfs2_find_per_slot_free_list(int type,
6522 return fl; 6522 return fl;
6523} 6523}
6524 6524
6525static int ocfs2_cache_block_dealloc(struct ocfs2_cached_dealloc_ctxt *ctxt, 6525int ocfs2_cache_block_dealloc(struct ocfs2_cached_dealloc_ctxt *ctxt,
6526 int type, int slot, u64 blkno, 6526 int type, int slot, u64 blkno,
6527 unsigned int bit) 6527 unsigned int bit)
6528{ 6528{
6529 int ret; 6529 int ret;
6530 struct ocfs2_per_slot_free_list *fl; 6530 struct ocfs2_per_slot_free_list *fl;
diff --git a/fs/ocfs2/alloc.h b/fs/ocfs2/alloc.h
index 3f4348923b73..0610ba148ea0 100644
--- a/fs/ocfs2/alloc.h
+++ b/fs/ocfs2/alloc.h
@@ -202,6 +202,9 @@ static inline void ocfs2_init_dealloc_ctxt(struct ocfs2_cached_dealloc_ctxt *c)
202} 202}
203int ocfs2_cache_cluster_dealloc(struct ocfs2_cached_dealloc_ctxt *ctxt, 203int ocfs2_cache_cluster_dealloc(struct ocfs2_cached_dealloc_ctxt *ctxt,
204 u64 blkno, unsigned int bit); 204 u64 blkno, unsigned int bit);
205int ocfs2_cache_block_dealloc(struct ocfs2_cached_dealloc_ctxt *ctxt,
206 int type, int slot, u64 blkno,
207 unsigned int bit);
205static inline int ocfs2_dealloc_has_cluster(struct ocfs2_cached_dealloc_ctxt *c) 208static inline int ocfs2_dealloc_has_cluster(struct ocfs2_cached_dealloc_ctxt *c)
206{ 209{
207 return c->c_global_allocator != NULL; 210 return c->c_global_allocator != NULL;
diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c
index ee0422ce72c4..2c7974cccaf8 100644
--- a/fs/ocfs2/refcounttree.c
+++ b/fs/ocfs2/refcounttree.c
@@ -1071,6 +1071,10 @@ static void ocfs2_refcount_rec_merge(struct ocfs2_refcount_block *rb,
1071 ocfs2_rotate_refcount_rec_left(rb, index); 1071 ocfs2_rotate_refcount_rec_left(rb, index);
1072} 1072}
1073 1073
1074/*
1075 * Change the refcount indexed by "index" in ref_bh.
1076 * If refcount reaches 0, remove it.
1077 */
1074static int ocfs2_change_refcount_rec(handle_t *handle, 1078static int ocfs2_change_refcount_rec(handle_t *handle,
1075 struct ocfs2_caching_info *ci, 1079 struct ocfs2_caching_info *ci,
1076 struct buffer_head *ref_leaf_bh, 1080 struct buffer_head *ref_leaf_bh,
@@ -1079,7 +1083,8 @@ static int ocfs2_change_refcount_rec(handle_t *handle,
1079 int ret; 1083 int ret;
1080 struct ocfs2_refcount_block *rb = 1084 struct ocfs2_refcount_block *rb =
1081 (struct ocfs2_refcount_block *)ref_leaf_bh->b_data; 1085 (struct ocfs2_refcount_block *)ref_leaf_bh->b_data;
1082 struct ocfs2_refcount_rec *rec = &rb->rf_records.rl_recs[index]; 1086 struct ocfs2_refcount_list *rl = &rb->rf_records;
1087 struct ocfs2_refcount_rec *rec = &rl->rl_recs[index];
1083 1088
1084 ret = ocfs2_journal_access_rb(handle, ci, ref_leaf_bh, 1089 ret = ocfs2_journal_access_rb(handle, ci, ref_leaf_bh,
1085 OCFS2_JOURNAL_ACCESS_WRITE); 1090 OCFS2_JOURNAL_ACCESS_WRITE);
@@ -1092,7 +1097,18 @@ static int ocfs2_change_refcount_rec(handle_t *handle,
1092 le32_to_cpu(rec->r_refcount), change); 1097 le32_to_cpu(rec->r_refcount), change);
1093 le32_add_cpu(&rec->r_refcount, change); 1098 le32_add_cpu(&rec->r_refcount, change);
1094 1099
1095 ocfs2_refcount_rec_merge(rb, index); 1100 if (!rec->r_refcount) {
1101 if (index != le16_to_cpu(rl->rl_used) - 1) {
1102 memmove(rec, rec + 1,
1103 (le16_to_cpu(rl->rl_used) - index - 1) *
1104 sizeof(struct ocfs2_refcount_rec));
1105 memset(&rl->rl_recs[le16_to_cpu(rl->rl_used) - 1],
1106 0, sizeof(struct ocfs2_refcount_rec));
1107 }
1108
1109 le16_add_cpu(&rl->rl_used, -1);
1110 } else
1111 ocfs2_refcount_rec_merge(rb, index);
1096 1112
1097 ret = ocfs2_journal_dirty(handle, ref_leaf_bh); 1113 ret = ocfs2_journal_dirty(handle, ref_leaf_bh);
1098 if (ret) 1114 if (ret)
@@ -1901,3 +1917,239 @@ out:
1901 brelse(ref_leaf_bh); 1917 brelse(ref_leaf_bh);
1902 return ret; 1918 return ret;
1903} 1919}
1920
1921static int ocfs2_remove_refcount_extent(handle_t *handle,
1922 struct ocfs2_caching_info *ci,
1923 struct buffer_head *ref_root_bh,
1924 struct buffer_head *ref_leaf_bh,
1925 struct ocfs2_alloc_context *meta_ac,
1926 struct ocfs2_cached_dealloc_ctxt *dealloc)
1927{
1928 int ret;
1929 struct super_block *sb = ocfs2_metadata_cache_get_super(ci);
1930 struct ocfs2_refcount_block *rb =
1931 (struct ocfs2_refcount_block *)ref_leaf_bh->b_data;
1932 struct ocfs2_extent_tree et;
1933
1934 BUG_ON(rb->rf_records.rl_used);
1935
1936 ocfs2_init_refcount_extent_tree(&et, ci, ref_root_bh);
1937 ret = ocfs2_remove_extent(handle, &et, le32_to_cpu(rb->rf_cpos),
1938 1, meta_ac, dealloc);
1939 if (ret) {
1940 mlog_errno(ret);
1941 goto out;
1942 }
1943
1944 ocfs2_remove_from_cache(ci, ref_leaf_bh);
1945
1946 /*
1947 * add the freed block to the dealloc so that it will be freed
1948 * when we run dealloc.
1949 */
1950 ret = ocfs2_cache_block_dealloc(dealloc, EXTENT_ALLOC_SYSTEM_INODE,
1951 le16_to_cpu(rb->rf_suballoc_slot),
1952 le64_to_cpu(rb->rf_blkno),
1953 le16_to_cpu(rb->rf_suballoc_bit));
1954 if (ret) {
1955 mlog_errno(ret);
1956 goto out;
1957 }
1958
1959 ret = ocfs2_journal_access_rb(handle, ci, ref_root_bh,
1960 OCFS2_JOURNAL_ACCESS_WRITE);
1961 if (ret) {
1962 mlog_errno(ret);
1963 goto out;
1964 }
1965
1966 rb = (struct ocfs2_refcount_block *)ref_root_bh->b_data;
1967
1968 le32_add_cpu(&rb->rf_clusters, -1);
1969
1970 /*
1971 * check whether we need to restore the root refcount block if
1972 * there is no leaf extent block at atll.
1973 */
1974 if (!rb->rf_list.l_next_free_rec) {
1975 BUG_ON(rb->rf_clusters);
1976
1977 mlog(0, "reset refcount tree root %llu to be a record block.\n",
1978 (unsigned long long)ref_root_bh->b_blocknr);
1979
1980 rb->rf_flags = 0;
1981 rb->rf_parent = 0;
1982 rb->rf_cpos = 0;
1983 memset(&rb->rf_records, 0, sb->s_blocksize -
1984 offsetof(struct ocfs2_refcount_block, rf_records));
1985 rb->rf_records.rl_count =
1986 cpu_to_le16(ocfs2_refcount_recs_per_rb(sb));
1987 }
1988
1989 ocfs2_journal_dirty(handle, ref_root_bh);
1990
1991out:
1992 return ret;
1993}
1994
1995static int ocfs2_decrease_refcount_rec(handle_t *handle,
1996 struct ocfs2_caching_info *ci,
1997 struct buffer_head *ref_root_bh,
1998 struct buffer_head *ref_leaf_bh,
1999 int index, u64 cpos, unsigned int len,
2000 struct ocfs2_alloc_context *meta_ac,
2001 struct ocfs2_cached_dealloc_ctxt *dealloc)
2002{
2003 int ret;
2004 struct ocfs2_refcount_block *rb =
2005 (struct ocfs2_refcount_block *)ref_leaf_bh->b_data;
2006 struct ocfs2_refcount_rec *rec = &rb->rf_records.rl_recs[index];
2007
2008 BUG_ON(cpos < le64_to_cpu(rec->r_cpos));
2009 BUG_ON(cpos + len >
2010 le64_to_cpu(rec->r_cpos) + le32_to_cpu(rec->r_clusters));
2011
2012 if (cpos == le64_to_cpu(rec->r_cpos) &&
2013 len == le32_to_cpu(rec->r_clusters))
2014 ret = ocfs2_change_refcount_rec(handle, ci,
2015 ref_leaf_bh, index, -1);
2016 else {
2017 struct ocfs2_refcount_rec split = *rec;
2018 split.r_cpos = cpu_to_le64(cpos);
2019 split.r_clusters = cpu_to_le32(len);
2020
2021 le32_add_cpu(&split.r_refcount, -1);
2022
2023 mlog(0, "split refcount rec, start %llu, "
2024 "len %u, count %u, original start %llu, len %u\n",
2025 (unsigned long long)le64_to_cpu(split.r_cpos),
2026 len, le32_to_cpu(split.r_refcount),
2027 (unsigned long long)le64_to_cpu(rec->r_cpos),
2028 le32_to_cpu(rec->r_clusters));
2029 ret = ocfs2_split_refcount_rec(handle, ci,
2030 ref_root_bh, ref_leaf_bh,
2031 &split, index,
2032 meta_ac, dealloc);
2033 }
2034
2035 if (ret) {
2036 mlog_errno(ret);
2037 goto out;
2038 }
2039
2040 /* Remove the leaf refcount block if it contains no refcount record. */
2041 if (!rb->rf_records.rl_used && ref_leaf_bh != ref_root_bh) {
2042 ret = ocfs2_remove_refcount_extent(handle, ci, ref_root_bh,
2043 ref_leaf_bh, meta_ac,
2044 dealloc);
2045 if (ret)
2046 mlog_errno(ret);
2047 }
2048
2049out:
2050 return ret;
2051}
2052
2053static int __ocfs2_decrease_refcount(handle_t *handle,
2054 struct ocfs2_caching_info *ci,
2055 struct buffer_head *ref_root_bh,
2056 u64 cpos, u32 len,
2057 struct ocfs2_alloc_context *meta_ac,
2058 struct ocfs2_cached_dealloc_ctxt *dealloc)
2059{
2060 int ret = 0, index = 0;
2061 struct ocfs2_refcount_rec rec;
2062 unsigned int r_count = 0, r_len;
2063 struct super_block *sb = ocfs2_metadata_cache_get_super(ci);
2064 struct buffer_head *ref_leaf_bh = NULL;
2065
2066 mlog(0, "Tree owner %llu, decrease refcount start %llu, len %u\n",
2067 (unsigned long long)ocfs2_metadata_cache_owner(ci),
2068 (unsigned long long)cpos, len);
2069
2070 while (len) {
2071 ret = ocfs2_get_refcount_rec(ci, ref_root_bh,
2072 cpos, len, &rec, &index,
2073 &ref_leaf_bh);
2074 if (ret) {
2075 mlog_errno(ret);
2076 goto out;
2077 }
2078
2079 r_count = le32_to_cpu(rec.r_refcount);
2080 BUG_ON(r_count == 0);
2081
2082 r_len = min((u64)(cpos + len), le64_to_cpu(rec.r_cpos) +
2083 le32_to_cpu(rec.r_clusters)) - cpos;
2084
2085 ret = ocfs2_decrease_refcount_rec(handle, ci, ref_root_bh,
2086 ref_leaf_bh, index,
2087 cpos, r_len,
2088 meta_ac, dealloc);
2089 if (ret) {
2090 mlog_errno(ret);
2091 goto out;
2092 }
2093
2094 if (le32_to_cpu(rec.r_refcount) == 1) {
2095 ret = ocfs2_cache_cluster_dealloc(dealloc,
2096 ocfs2_clusters_to_blocks(sb, cpos),
2097 r_len);
2098 if (ret) {
2099 mlog_errno(ret);
2100 goto out;
2101 }
2102 }
2103
2104 cpos += r_len;
2105 len -= r_len;
2106 brelse(ref_leaf_bh);
2107 ref_leaf_bh = NULL;
2108 }
2109
2110out:
2111 brelse(ref_leaf_bh);
2112 return ret;
2113}
2114
2115/* Caller must hold refcount tree lock. */
2116int ocfs2_decrease_refcount(struct inode *inode,
2117 handle_t *handle, u32 cpos, u32 len,
2118 struct ocfs2_alloc_context *meta_ac,
2119 struct ocfs2_cached_dealloc_ctxt *dealloc)
2120{
2121 int ret;
2122 u64 ref_blkno;
2123 struct ocfs2_inode_info *oi = OCFS2_I(inode);
2124 struct buffer_head *ref_root_bh = NULL;
2125 struct ocfs2_refcount_tree *tree;
2126
2127 BUG_ON(!(oi->ip_dyn_features & OCFS2_HAS_REFCOUNT_FL));
2128
2129 ret = ocfs2_get_refcount_block(inode, &ref_blkno);
2130 if (ret) {
2131 mlog_errno(ret);
2132 goto out;
2133 }
2134
2135 ret = ocfs2_get_refcount_tree(OCFS2_SB(inode->i_sb), ref_blkno, &tree);
2136 if (ret) {
2137 mlog_errno(ret);
2138 goto out;
2139 }
2140
2141 ret = ocfs2_read_refcount_block(&tree->rf_ci, tree->rf_blkno,
2142 &ref_root_bh);
2143 if (ret) {
2144 mlog_errno(ret);
2145 goto out;
2146 }
2147
2148 ret = __ocfs2_decrease_refcount(handle, &tree->rf_ci, ref_root_bh,
2149 cpos, len, meta_ac, dealloc);
2150 if (ret)
2151 mlog_errno(ret);
2152out:
2153 brelse(ref_root_bh);
2154 return ret;
2155}
diff --git a/fs/ocfs2/refcounttree.h b/fs/ocfs2/refcounttree.h
index 2ea7fc52c23c..ad4b483ec5c7 100644
--- a/fs/ocfs2/refcounttree.h
+++ b/fs/ocfs2/refcounttree.h
@@ -40,4 +40,9 @@ int ocfs2_lock_refcount_tree(struct ocfs2_super *osb, u64 ref_blkno, int rw,
40void ocfs2_unlock_refcount_tree(struct ocfs2_super *osb, 40void ocfs2_unlock_refcount_tree(struct ocfs2_super *osb,
41 struct ocfs2_refcount_tree *tree, 41 struct ocfs2_refcount_tree *tree,
42 int rw); 42 int rw);
43
44int ocfs2_decrease_refcount(struct inode *inode,
45 handle_t *handle, u32 cpos, u32 len,
46 struct ocfs2_alloc_context *meta_ac,
47 struct ocfs2_cached_dealloc_ctxt *dealloc);
43#endif /* OCFS2_REFCOUNTTREE_H */ 48#endif /* OCFS2_REFCOUNTTREE_H */