diff options
author | Tao Ma <tao.ma@oracle.com> | 2009-08-17 23:29:12 -0400 |
---|---|---|
committer | Joel Becker <joel.becker@oracle.com> | 2009-09-22 23:09:35 -0400 |
commit | bcbbb24a6a5c5b3e7b8e5284e0bfa23f45c32377 (patch) | |
tree | e45a6cfd75cd8005fdf280c2f5f57c09186249dd /fs/ocfs2/refcounttree.c | |
parent | 1aa75fea64bc26bda9be9b1b20ae253d7a481877 (diff) |
ocfs2: Decrement refcount when truncating refcounted extents.
Add 'Decrement refcount for delete' in to the normal truncate
process. So for a refcounted extent record, call refcount rec
decrementation instead of cluster free.
Signed-off-by: Tao Ma <tao.ma@oracle.com>
Diffstat (limited to 'fs/ocfs2/refcounttree.c')
-rw-r--r-- | fs/ocfs2/refcounttree.c | 212 |
1 files changed, 212 insertions, 0 deletions
diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c index f7d19f4db897..e72dbdd3b6e8 100644 --- a/fs/ocfs2/refcounttree.c +++ b/fs/ocfs2/refcounttree.c | |||
@@ -2192,3 +2192,215 @@ static int ocfs2_mark_extent_refcounted(struct inode *inode, | |||
2192 | out: | 2192 | out: |
2193 | return ret; | 2193 | return ret; |
2194 | } | 2194 | } |
2195 | |||
2196 | /* | ||
2197 | * Given some contiguous physical clusters, calculate what we need | ||
2198 | * for modifying their refcount. | ||
2199 | */ | ||
2200 | static int ocfs2_calc_refcount_meta_credits(struct super_block *sb, | ||
2201 | struct ocfs2_caching_info *ci, | ||
2202 | struct buffer_head *ref_root_bh, | ||
2203 | u64 start_cpos, | ||
2204 | u32 clusters, | ||
2205 | int *meta_add, | ||
2206 | int *credits) | ||
2207 | { | ||
2208 | int ret = 0, index, ref_blocks = 0, recs_add = 0; | ||
2209 | u64 cpos = start_cpos; | ||
2210 | struct ocfs2_refcount_block *rb; | ||
2211 | struct ocfs2_refcount_rec rec; | ||
2212 | struct buffer_head *ref_leaf_bh = NULL, *prev_bh = NULL; | ||
2213 | u32 len; | ||
2214 | |||
2215 | mlog(0, "start_cpos %llu, clusters %u\n", | ||
2216 | (unsigned long long)start_cpos, clusters); | ||
2217 | while (clusters) { | ||
2218 | ret = ocfs2_get_refcount_rec(ci, ref_root_bh, | ||
2219 | cpos, clusters, &rec, | ||
2220 | &index, &ref_leaf_bh); | ||
2221 | if (ret) { | ||
2222 | mlog_errno(ret); | ||
2223 | goto out; | ||
2224 | } | ||
2225 | |||
2226 | if (ref_leaf_bh != prev_bh) { | ||
2227 | /* | ||
2228 | * Now we encounter a new leaf block, so calculate | ||
2229 | * whether we need to extend the old leaf. | ||
2230 | */ | ||
2231 | if (prev_bh) { | ||
2232 | rb = (struct ocfs2_refcount_block *) | ||
2233 | prev_bh->b_data; | ||
2234 | |||
2235 | if (le64_to_cpu(rb->rf_records.rl_used) + | ||
2236 | recs_add > | ||
2237 | le16_to_cpu(rb->rf_records.rl_count)) | ||
2238 | ref_blocks++; | ||
2239 | } | ||
2240 | |||
2241 | recs_add = 0; | ||
2242 | *credits += 1; | ||
2243 | brelse(prev_bh); | ||
2244 | prev_bh = ref_leaf_bh; | ||
2245 | get_bh(prev_bh); | ||
2246 | } | ||
2247 | |||
2248 | rb = (struct ocfs2_refcount_block *)ref_leaf_bh->b_data; | ||
2249 | |||
2250 | mlog(0, "recs_add %d,cpos %llu, clusters %u, rec->r_cpos %llu," | ||
2251 | "rec->r_clusters %u, rec->r_refcount %u, index %d\n", | ||
2252 | recs_add, (unsigned long long)cpos, clusters, | ||
2253 | (unsigned long long)le64_to_cpu(rec.r_cpos), | ||
2254 | le32_to_cpu(rec.r_clusters), | ||
2255 | le32_to_cpu(rec.r_refcount), index); | ||
2256 | |||
2257 | len = min((u64)cpos + clusters, le64_to_cpu(rec.r_cpos) + | ||
2258 | le32_to_cpu(rec.r_clusters)) - cpos; | ||
2259 | /* | ||
2260 | * If the refcount rec already exist, cool. We just need | ||
2261 | * to check whether there is a split. Otherwise we just need | ||
2262 | * to increase the refcount. | ||
2263 | * If we will insert one, increases recs_add. | ||
2264 | * | ||
2265 | * We record all the records which will be inserted to the | ||
2266 | * same refcount block, so that we can tell exactly whether | ||
2267 | * we need a new refcount block or not. | ||
2268 | */ | ||
2269 | if (rec.r_refcount) { | ||
2270 | /* Check whether we need a split at the beginning. */ | ||
2271 | if (cpos == start_cpos && | ||
2272 | cpos != le64_to_cpu(rec.r_cpos)) | ||
2273 | recs_add++; | ||
2274 | |||
2275 | /* Check whether we need a split in the end. */ | ||
2276 | if (cpos + clusters < le64_to_cpu(rec.r_cpos) + | ||
2277 | le32_to_cpu(rec.r_clusters)) | ||
2278 | recs_add++; | ||
2279 | } else | ||
2280 | recs_add++; | ||
2281 | |||
2282 | brelse(ref_leaf_bh); | ||
2283 | ref_leaf_bh = NULL; | ||
2284 | clusters -= len; | ||
2285 | cpos += len; | ||
2286 | } | ||
2287 | |||
2288 | if (prev_bh) { | ||
2289 | rb = (struct ocfs2_refcount_block *)prev_bh->b_data; | ||
2290 | |||
2291 | if (le64_to_cpu(rb->rf_records.rl_used) + recs_add > | ||
2292 | le16_to_cpu(rb->rf_records.rl_count)) | ||
2293 | ref_blocks++; | ||
2294 | |||
2295 | *credits += 1; | ||
2296 | } | ||
2297 | |||
2298 | if (!ref_blocks) | ||
2299 | goto out; | ||
2300 | |||
2301 | mlog(0, "we need ref_blocks %d\n", ref_blocks); | ||
2302 | *meta_add += ref_blocks; | ||
2303 | *credits += ref_blocks; | ||
2304 | |||
2305 | /* | ||
2306 | * So we may need ref_blocks to insert into the tree. | ||
2307 | * That also means we need to change the b-tree and add that number | ||
2308 | * of records since we never merge them. | ||
2309 | * We need one more block for expansion since the new created leaf | ||
2310 | * block is also full and needs split. | ||
2311 | */ | ||
2312 | rb = (struct ocfs2_refcount_block *)ref_root_bh->b_data; | ||
2313 | if (le32_to_cpu(rb->rf_flags) & OCFS2_REFCOUNT_TREE_FL) { | ||
2314 | struct ocfs2_extent_tree et; | ||
2315 | |||
2316 | ocfs2_init_refcount_extent_tree(&et, ci, ref_root_bh); | ||
2317 | *meta_add += ocfs2_extend_meta_needed(et.et_root_el); | ||
2318 | *credits += ocfs2_calc_extend_credits(sb, | ||
2319 | et.et_root_el, | ||
2320 | ref_blocks); | ||
2321 | } else { | ||
2322 | *credits += OCFS2_EXPAND_REFCOUNT_TREE_CREDITS; | ||
2323 | *meta_add += 1; | ||
2324 | } | ||
2325 | |||
2326 | out: | ||
2327 | brelse(ref_leaf_bh); | ||
2328 | brelse(prev_bh); | ||
2329 | return ret; | ||
2330 | } | ||
2331 | |||
2332 | /* | ||
2333 | * For refcount tree, we will decrease some contiguous clusters | ||
2334 | * refcount count, so just go through it to see how many blocks | ||
2335 | * we gonna touch and whether we need to create new blocks. | ||
2336 | * | ||
2337 | * Normally the refcount blocks store these refcount should be | ||
2338 | * continguous also, so that we can get the number easily. | ||
2339 | * As for meta_ac, we will at most add split 2 refcount record and | ||
2340 | * 2 more refcount block, so just check it in a rough way. | ||
2341 | * | ||
2342 | * Caller must hold refcount tree lock. | ||
2343 | */ | ||
2344 | int ocfs2_prepare_refcount_change_for_del(struct inode *inode, | ||
2345 | struct buffer_head *di_bh, | ||
2346 | u64 phys_blkno, | ||
2347 | u32 clusters, | ||
2348 | int *credits, | ||
2349 | struct ocfs2_alloc_context **meta_ac) | ||
2350 | { | ||
2351 | int ret, ref_blocks = 0; | ||
2352 | struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; | ||
2353 | struct ocfs2_inode_info *oi = OCFS2_I(inode); | ||
2354 | struct buffer_head *ref_root_bh = NULL; | ||
2355 | struct ocfs2_refcount_tree *tree; | ||
2356 | u64 start_cpos = ocfs2_blocks_to_clusters(inode->i_sb, phys_blkno); | ||
2357 | |||
2358 | if (!ocfs2_refcount_tree(OCFS2_SB(inode->i_sb))) { | ||
2359 | ocfs2_error(inode->i_sb, "Inode %lu want to use refcount " | ||
2360 | "tree, but the feature bit is not set in the " | ||
2361 | "super block.", inode->i_ino); | ||
2362 | ret = -EROFS; | ||
2363 | goto out; | ||
2364 | } | ||
2365 | |||
2366 | BUG_ON(!(oi->ip_dyn_features & OCFS2_HAS_REFCOUNT_FL)); | ||
2367 | |||
2368 | ret = ocfs2_get_refcount_tree(OCFS2_SB(inode->i_sb), | ||
2369 | le64_to_cpu(di->i_refcount_loc), &tree); | ||
2370 | if (ret) { | ||
2371 | mlog_errno(ret); | ||
2372 | goto out; | ||
2373 | } | ||
2374 | |||
2375 | ret = ocfs2_read_refcount_block(&tree->rf_ci, | ||
2376 | le64_to_cpu(di->i_refcount_loc), | ||
2377 | &ref_root_bh); | ||
2378 | if (ret) { | ||
2379 | mlog_errno(ret); | ||
2380 | goto out; | ||
2381 | } | ||
2382 | |||
2383 | ret = ocfs2_calc_refcount_meta_credits(inode->i_sb, | ||
2384 | &tree->rf_ci, | ||
2385 | ref_root_bh, | ||
2386 | start_cpos, clusters, | ||
2387 | &ref_blocks, credits); | ||
2388 | if (ret) { | ||
2389 | mlog_errno(ret); | ||
2390 | goto out; | ||
2391 | } | ||
2392 | |||
2393 | mlog(0, "reserve new metadata %d, credits = %d\n", | ||
2394 | ref_blocks, *credits); | ||
2395 | |||
2396 | if (ref_blocks) { | ||
2397 | ret = ocfs2_reserve_new_metadata_blocks(OCFS2_SB(inode->i_sb), | ||
2398 | ref_blocks, meta_ac); | ||
2399 | if (ret) | ||
2400 | mlog_errno(ret); | ||
2401 | } | ||
2402 | |||
2403 | out: | ||
2404 | brelse(ref_root_bh); | ||
2405 | return ret; | ||
2406 | } | ||