diff options
author | Mark Fasheh <mfasheh@suse.com> | 2009-02-17 18:29:35 -0500 |
---|---|---|
committer | Mark Fasheh <mfasheh@suse.com> | 2009-04-03 14:39:16 -0400 |
commit | e3a93c2db6410822aa24295c3874b44ba21730a8 (patch) | |
tree | 8de41a37abc6497745d07506a0fb5174da61d7c1 /fs/ocfs2/dir.c | |
parent | 198a1ca3b735986542c538e38b9499ffcaed7005 (diff) |
ocfs2: Add total entry count to dx_root_block
This little bit of extra accounting speeds up ocfs2_empty_dir()
dramatically by allowing us to short-circuit the full directory scan.
Signed-off-by: Mark Fasheh <mfasheh@suse.com>
Diffstat (limited to 'fs/ocfs2/dir.c')
-rw-r--r-- | fs/ocfs2/dir.c | 162 |
1 files changed, 119 insertions, 43 deletions
diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c index 52df9125a79d..5e6aeb00cb43 100644 --- a/fs/ocfs2/dir.c +++ b/fs/ocfs2/dir.c | |||
@@ -1322,16 +1322,15 @@ static int ocfs2_delete_entry_dx(handle_t *handle, struct inode *dir, | |||
1322 | * entry yet. Likewise, successful return means we *must* | 1322 | * entry yet. Likewise, successful return means we *must* |
1323 | * remove the indexed entry. | 1323 | * remove the indexed entry. |
1324 | * | 1324 | * |
1325 | * We're also careful to journal the root tree block here if | 1325 | * We're also careful to journal the root tree block here as |
1326 | * we're going to be adding to the start of the free list. | 1326 | * the entry count needs to be updated. Also, we might be |
1327 | * adding to the start of the free list. | ||
1327 | */ | 1328 | */ |
1328 | if (add_to_free_list || ocfs2_dx_root_inline(dx_root)) { | 1329 | ret = ocfs2_journal_access_dr(handle, dir, dx_root_bh, |
1329 | ret = ocfs2_journal_access_dr(handle, dir, dx_root_bh, | 1330 | OCFS2_JOURNAL_ACCESS_WRITE); |
1330 | OCFS2_JOURNAL_ACCESS_WRITE); | 1331 | if (ret) { |
1331 | if (ret) { | 1332 | mlog_errno(ret); |
1332 | mlog_errno(ret); | 1333 | goto out; |
1333 | goto out; | ||
1334 | } | ||
1335 | } | 1334 | } |
1336 | 1335 | ||
1337 | if (!ocfs2_dx_root_inline(dx_root)) { | 1336 | if (!ocfs2_dx_root_inline(dx_root)) { |
@@ -1365,11 +1364,12 @@ static int ocfs2_delete_entry_dx(handle_t *handle, struct inode *dir, | |||
1365 | /* leaf_bh was journal_accessed for us in __ocfs2_delete_entry */ | 1364 | /* leaf_bh was journal_accessed for us in __ocfs2_delete_entry */ |
1366 | ocfs2_journal_dirty(handle, leaf_bh); | 1365 | ocfs2_journal_dirty(handle, leaf_bh); |
1367 | 1366 | ||
1367 | le32_add_cpu(&dx_root->dr_num_entries, -1); | ||
1368 | ocfs2_journal_dirty(handle, dx_root_bh); | ||
1369 | |||
1368 | ocfs2_dx_list_remove_entry(entry_list, index); | 1370 | ocfs2_dx_list_remove_entry(entry_list, index); |
1369 | 1371 | ||
1370 | if (ocfs2_dx_root_inline(dx_root)) | 1372 | if (!ocfs2_dx_root_inline(dx_root)) |
1371 | ocfs2_journal_dirty(handle, dx_root_bh); | ||
1372 | else | ||
1373 | ocfs2_journal_dirty(handle, lookup->dl_dx_leaf_bh); | 1373 | ocfs2_journal_dirty(handle, lookup->dl_dx_leaf_bh); |
1374 | 1374 | ||
1375 | out: | 1375 | out: |
@@ -1508,13 +1508,20 @@ out: | |||
1508 | return ret; | 1508 | return ret; |
1509 | } | 1509 | } |
1510 | 1510 | ||
1511 | static int ocfs2_dx_inline_root_insert(struct inode *dir, handle_t *handle, | 1511 | static void ocfs2_dx_inline_root_insert(struct inode *dir, handle_t *handle, |
1512 | struct ocfs2_dx_hinfo *hinfo, | 1512 | struct ocfs2_dx_hinfo *hinfo, |
1513 | u64 dirent_blk, | 1513 | u64 dirent_blk, |
1514 | struct buffer_head *dx_root_bh) | 1514 | struct ocfs2_dx_root_block *dx_root) |
1515 | { | 1515 | { |
1516 | int ret; | 1516 | ocfs2_dx_entry_list_insert(&dx_root->dr_entries, hinfo, dirent_blk); |
1517 | } | ||
1518 | |||
1519 | static int ocfs2_dx_dir_insert(struct inode *dir, handle_t *handle, | ||
1520 | struct ocfs2_dir_lookup_result *lookup) | ||
1521 | { | ||
1522 | int ret = 0; | ||
1517 | struct ocfs2_dx_root_block *dx_root; | 1523 | struct ocfs2_dx_root_block *dx_root; |
1524 | struct buffer_head *dx_root_bh = lookup->dl_dx_root_bh; | ||
1518 | 1525 | ||
1519 | ret = ocfs2_journal_access_dr(handle, dir, dx_root_bh, | 1526 | ret = ocfs2_journal_access_dr(handle, dir, dx_root_bh, |
1520 | OCFS2_JOURNAL_ACCESS_WRITE); | 1527 | OCFS2_JOURNAL_ACCESS_WRITE); |
@@ -1523,31 +1530,27 @@ static int ocfs2_dx_inline_root_insert(struct inode *dir, handle_t *handle, | |||
1523 | goto out; | 1530 | goto out; |
1524 | } | 1531 | } |
1525 | 1532 | ||
1526 | dx_root = (struct ocfs2_dx_root_block *)dx_root_bh->b_data; | 1533 | dx_root = (struct ocfs2_dx_root_block *)lookup->dl_dx_root_bh->b_data; |
1527 | ocfs2_dx_entry_list_insert(&dx_root->dr_entries, hinfo, dirent_blk); | 1534 | if (ocfs2_dx_root_inline(dx_root)) { |
1535 | ocfs2_dx_inline_root_insert(dir, handle, | ||
1536 | &lookup->dl_hinfo, | ||
1537 | lookup->dl_leaf_bh->b_blocknr, | ||
1538 | dx_root); | ||
1539 | } else { | ||
1540 | ret = __ocfs2_dx_dir_leaf_insert(dir, handle, &lookup->dl_hinfo, | ||
1541 | lookup->dl_leaf_bh->b_blocknr, | ||
1542 | lookup->dl_dx_leaf_bh); | ||
1543 | if (ret) | ||
1544 | goto out; | ||
1545 | } | ||
1546 | |||
1547 | le32_add_cpu(&dx_root->dr_num_entries, 1); | ||
1528 | ocfs2_journal_dirty(handle, dx_root_bh); | 1548 | ocfs2_journal_dirty(handle, dx_root_bh); |
1529 | 1549 | ||
1530 | out: | 1550 | out: |
1531 | return ret; | 1551 | return ret; |
1532 | } | 1552 | } |
1533 | 1553 | ||
1534 | static int ocfs2_dx_dir_insert(struct inode *dir, handle_t *handle, | ||
1535 | struct ocfs2_dir_lookup_result *lookup) | ||
1536 | { | ||
1537 | struct ocfs2_dx_root_block *dx_root; | ||
1538 | |||
1539 | dx_root = (struct ocfs2_dx_root_block *)lookup->dl_dx_root_bh->b_data; | ||
1540 | if (ocfs2_dx_root_inline(dx_root)) | ||
1541 | return ocfs2_dx_inline_root_insert(dir, handle, | ||
1542 | &lookup->dl_hinfo, | ||
1543 | lookup->dl_leaf_bh->b_blocknr, | ||
1544 | lookup->dl_dx_root_bh); | ||
1545 | |||
1546 | return __ocfs2_dx_dir_leaf_insert(dir, handle, &lookup->dl_hinfo, | ||
1547 | lookup->dl_leaf_bh->b_blocknr, | ||
1548 | lookup->dl_dx_leaf_bh); | ||
1549 | } | ||
1550 | |||
1551 | static void ocfs2_remove_block_from_free_list(struct inode *dir, | 1554 | static void ocfs2_remove_block_from_free_list(struct inode *dir, |
1552 | handle_t *handle, | 1555 | handle_t *handle, |
1553 | struct ocfs2_dir_lookup_result *lookup) | 1556 | struct ocfs2_dir_lookup_result *lookup) |
@@ -2121,6 +2124,7 @@ struct ocfs2_empty_dir_priv { | |||
2121 | unsigned seen_dot; | 2124 | unsigned seen_dot; |
2122 | unsigned seen_dot_dot; | 2125 | unsigned seen_dot_dot; |
2123 | unsigned seen_other; | 2126 | unsigned seen_other; |
2127 | unsigned dx_dir; | ||
2124 | }; | 2128 | }; |
2125 | static int ocfs2_empty_dir_filldir(void *priv, const char *name, int name_len, | 2129 | static int ocfs2_empty_dir_filldir(void *priv, const char *name, int name_len, |
2126 | loff_t pos, u64 ino, unsigned type) | 2130 | loff_t pos, u64 ino, unsigned type) |
@@ -2130,6 +2134,13 @@ static int ocfs2_empty_dir_filldir(void *priv, const char *name, int name_len, | |||
2130 | /* | 2134 | /* |
2131 | * Check the positions of "." and ".." records to be sure | 2135 | * Check the positions of "." and ".." records to be sure |
2132 | * they're in the correct place. | 2136 | * they're in the correct place. |
2137 | * | ||
2138 | * Indexed directories don't need to proceed past the first | ||
2139 | * two entries, so we end the scan after seeing '..'. Despite | ||
2140 | * that, we allow the scan to proceed In the event that we | ||
2141 | * have a corrupted indexed directory (no dot or dot dot | ||
2142 | * entries). This allows us to double check for existing | ||
2143 | * entries which might not have been found in the index. | ||
2133 | */ | 2144 | */ |
2134 | if (name_len == 1 && !strncmp(".", name, 1) && pos == 0) { | 2145 | if (name_len == 1 && !strncmp(".", name, 1) && pos == 0) { |
2135 | p->seen_dot = 1; | 2146 | p->seen_dot = 1; |
@@ -2139,18 +2150,57 @@ static int ocfs2_empty_dir_filldir(void *priv, const char *name, int name_len, | |||
2139 | if (name_len == 2 && !strncmp("..", name, 2) && | 2150 | if (name_len == 2 && !strncmp("..", name, 2) && |
2140 | pos == OCFS2_DIR_REC_LEN(1)) { | 2151 | pos == OCFS2_DIR_REC_LEN(1)) { |
2141 | p->seen_dot_dot = 1; | 2152 | p->seen_dot_dot = 1; |
2153 | |||
2154 | if (p->dx_dir && p->seen_dot) | ||
2155 | return 1; | ||
2156 | |||
2142 | return 0; | 2157 | return 0; |
2143 | } | 2158 | } |
2144 | 2159 | ||
2145 | p->seen_other = 1; | 2160 | p->seen_other = 1; |
2146 | return 1; | 2161 | return 1; |
2147 | } | 2162 | } |
2163 | |||
2164 | static int ocfs2_empty_dir_dx(struct inode *inode, | ||
2165 | struct ocfs2_empty_dir_priv *priv) | ||
2166 | { | ||
2167 | int ret; | ||
2168 | struct buffer_head *di_bh = NULL; | ||
2169 | struct buffer_head *dx_root_bh = NULL; | ||
2170 | struct ocfs2_dinode *di; | ||
2171 | struct ocfs2_dx_root_block *dx_root; | ||
2172 | |||
2173 | priv->dx_dir = 1; | ||
2174 | |||
2175 | ret = ocfs2_read_inode_block(inode, &di_bh); | ||
2176 | if (ret) { | ||
2177 | mlog_errno(ret); | ||
2178 | goto out; | ||
2179 | } | ||
2180 | di = (struct ocfs2_dinode *)di_bh->b_data; | ||
2181 | |||
2182 | ret = ocfs2_read_dx_root(inode, di, &dx_root_bh); | ||
2183 | if (ret) { | ||
2184 | mlog_errno(ret); | ||
2185 | goto out; | ||
2186 | } | ||
2187 | dx_root = (struct ocfs2_dx_root_block *)dx_root_bh->b_data; | ||
2188 | |||
2189 | if (le32_to_cpu(dx_root->dr_num_entries) != 2) | ||
2190 | priv->seen_other = 1; | ||
2191 | |||
2192 | out: | ||
2193 | brelse(di_bh); | ||
2194 | brelse(dx_root_bh); | ||
2195 | return ret; | ||
2196 | } | ||
2197 | |||
2148 | /* | 2198 | /* |
2149 | * routine to check that the specified directory is empty (for rmdir) | 2199 | * routine to check that the specified directory is empty (for rmdir) |
2150 | * | 2200 | * |
2151 | * Returns 1 if dir is empty, zero otherwise. | 2201 | * Returns 1 if dir is empty, zero otherwise. |
2152 | * | 2202 | * |
2153 | * XXX: This is a performance problem | 2203 | * XXX: This is a performance problem for unindexed directories. |
2154 | */ | 2204 | */ |
2155 | int ocfs2_empty_dir(struct inode *inode) | 2205 | int ocfs2_empty_dir(struct inode *inode) |
2156 | { | 2206 | { |
@@ -2160,6 +2210,16 @@ int ocfs2_empty_dir(struct inode *inode) | |||
2160 | 2210 | ||
2161 | memset(&priv, 0, sizeof(priv)); | 2211 | memset(&priv, 0, sizeof(priv)); |
2162 | 2212 | ||
2213 | if (ocfs2_dir_indexed(inode)) { | ||
2214 | ret = ocfs2_empty_dir_dx(inode, &priv); | ||
2215 | if (ret) | ||
2216 | mlog_errno(ret); | ||
2217 | /* | ||
2218 | * We still run ocfs2_dir_foreach to get the checks | ||
2219 | * for "." and "..". | ||
2220 | */ | ||
2221 | } | ||
2222 | |||
2163 | ret = ocfs2_dir_foreach(inode, &start, &priv, ocfs2_empty_dir_filldir); | 2223 | ret = ocfs2_dir_foreach(inode, &start, &priv, ocfs2_empty_dir_filldir); |
2164 | if (ret) | 2224 | if (ret) |
2165 | mlog_errno(ret); | 2225 | mlog_errno(ret); |
@@ -2329,7 +2389,7 @@ static int ocfs2_dx_dir_attach_index(struct ocfs2_super *osb, | |||
2329 | struct buffer_head *di_bh, | 2389 | struct buffer_head *di_bh, |
2330 | struct buffer_head *dirdata_bh, | 2390 | struct buffer_head *dirdata_bh, |
2331 | struct ocfs2_alloc_context *meta_ac, | 2391 | struct ocfs2_alloc_context *meta_ac, |
2332 | int dx_inline, | 2392 | int dx_inline, u32 num_entries, |
2333 | struct buffer_head **ret_dx_root_bh) | 2393 | struct buffer_head **ret_dx_root_bh) |
2334 | { | 2394 | { |
2335 | int ret; | 2395 | int ret; |
@@ -2375,6 +2435,7 @@ static int ocfs2_dx_dir_attach_index(struct ocfs2_super *osb, | |||
2375 | dx_root->dr_fs_generation = cpu_to_le32(osb->fs_generation); | 2435 | dx_root->dr_fs_generation = cpu_to_le32(osb->fs_generation); |
2376 | dx_root->dr_blkno = cpu_to_le64(dr_blkno); | 2436 | dx_root->dr_blkno = cpu_to_le64(dr_blkno); |
2377 | dx_root->dr_dir_blkno = cpu_to_le64(OCFS2_I(dir)->ip_blkno); | 2437 | dx_root->dr_dir_blkno = cpu_to_le64(OCFS2_I(dir)->ip_blkno); |
2438 | dx_root->dr_num_entries = cpu_to_le32(num_entries); | ||
2378 | if (le16_to_cpu(trailer->db_free_rec_len)) | 2439 | if (le16_to_cpu(trailer->db_free_rec_len)) |
2379 | dx_root->dr_free_blk = cpu_to_le64(dirdata_bh->b_blocknr); | 2440 | dx_root->dr_free_blk = cpu_to_le64(dirdata_bh->b_blocknr); |
2380 | else | 2441 | else |
@@ -2586,7 +2647,7 @@ static int ocfs2_fill_new_dir_dx(struct ocfs2_super *osb, | |||
2586 | } | 2647 | } |
2587 | 2648 | ||
2588 | ret = ocfs2_dx_dir_attach_index(osb, handle, inode, di_bh, leaf_bh, | 2649 | ret = ocfs2_dx_dir_attach_index(osb, handle, inode, di_bh, leaf_bh, |
2589 | meta_ac, 1, &dx_root_bh); | 2650 | meta_ac, 1, 2, &dx_root_bh); |
2590 | if (ret) { | 2651 | if (ret) { |
2591 | mlog_errno(ret); | 2652 | mlog_errno(ret); |
2592 | goto out; | 2653 | goto out; |
@@ -2633,6 +2694,7 @@ static int ocfs2_dx_dir_index_block(struct inode *dir, | |||
2633 | handle_t *handle, | 2694 | handle_t *handle, |
2634 | struct buffer_head **dx_leaves, | 2695 | struct buffer_head **dx_leaves, |
2635 | int num_dx_leaves, | 2696 | int num_dx_leaves, |
2697 | u32 *num_dx_entries, | ||
2636 | struct buffer_head *dirent_bh) | 2698 | struct buffer_head *dirent_bh) |
2637 | { | 2699 | { |
2638 | int ret, namelen, i; | 2700 | int ret, namelen, i; |
@@ -2664,6 +2726,8 @@ static int ocfs2_dx_dir_index_block(struct inode *dir, | |||
2664 | goto out; | 2726 | goto out; |
2665 | } | 2727 | } |
2666 | 2728 | ||
2729 | *num_dx_entries = *num_dx_entries + 1; | ||
2730 | |||
2667 | inc: | 2731 | inc: |
2668 | de_buf += le16_to_cpu(de->rec_len); | 2732 | de_buf += le16_to_cpu(de->rec_len); |
2669 | } | 2733 | } |
@@ -2707,6 +2771,8 @@ static void ocfs2_dx_dir_index_root_block(struct inode *dir, | |||
2707 | 2771 | ||
2708 | ocfs2_dx_entry_list_insert(&dx_root->dr_entries, &hinfo, | 2772 | ocfs2_dx_entry_list_insert(&dx_root->dr_entries, &hinfo, |
2709 | dirent_blk); | 2773 | dirent_blk); |
2774 | |||
2775 | le32_add_cpu(&dx_root->dr_num_entries, 1); | ||
2710 | inc: | 2776 | inc: |
2711 | de_buf += le16_to_cpu(de->rec_len); | 2777 | de_buf += le16_to_cpu(de->rec_len); |
2712 | } | 2778 | } |
@@ -2810,7 +2876,7 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh, | |||
2810 | struct ocfs2_dir_lookup_result *lookup, | 2876 | struct ocfs2_dir_lookup_result *lookup, |
2811 | struct buffer_head **first_block_bh) | 2877 | struct buffer_head **first_block_bh) |
2812 | { | 2878 | { |
2813 | u32 alloc, dx_alloc, bit_off, len; | 2879 | u32 alloc, dx_alloc, bit_off, len, num_dx_entries = 0; |
2814 | struct super_block *sb = dir->i_sb; | 2880 | struct super_block *sb = dir->i_sb; |
2815 | int ret, i, num_dx_leaves = 0, dx_inline = 0, | 2881 | int ret, i, num_dx_leaves = 0, dx_inline = 0, |
2816 | credits = ocfs2_inline_to_extents_credits(sb); | 2882 | credits = ocfs2_inline_to_extents_credits(sb); |
@@ -2972,10 +3038,14 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh, | |||
2972 | /* | 3038 | /* |
2973 | * Dx dirs with an external cluster need to do this up | 3039 | * Dx dirs with an external cluster need to do this up |
2974 | * front. Inline dx root's get handled later, after | 3040 | * front. Inline dx root's get handled later, after |
2975 | * we've allocated our root block. | 3041 | * we've allocated our root block. We get passed back |
3042 | * a total number of items so that dr_num_entries can | ||
3043 | * be correctly set once the dx_root has been | ||
3044 | * allocated. | ||
2976 | */ | 3045 | */ |
2977 | ret = ocfs2_dx_dir_index_block(dir, handle, dx_leaves, | 3046 | ret = ocfs2_dx_dir_index_block(dir, handle, dx_leaves, |
2978 | num_dx_leaves, dirdata_bh); | 3047 | num_dx_leaves, &num_dx_entries, |
3048 | dirdata_bh); | ||
2979 | if (ret) { | 3049 | if (ret) { |
2980 | mlog_errno(ret); | 3050 | mlog_errno(ret); |
2981 | goto out_commit; | 3051 | goto out_commit; |
@@ -3037,7 +3107,7 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh, | |||
3037 | if (ocfs2_supports_indexed_dirs(osb)) { | 3107 | if (ocfs2_supports_indexed_dirs(osb)) { |
3038 | ret = ocfs2_dx_dir_attach_index(osb, handle, dir, di_bh, | 3108 | ret = ocfs2_dx_dir_attach_index(osb, handle, dir, di_bh, |
3039 | dirdata_bh, meta_ac, dx_inline, | 3109 | dirdata_bh, meta_ac, dx_inline, |
3040 | &dx_root_bh); | 3110 | num_dx_entries, &dx_root_bh); |
3041 | if (ret) { | 3111 | if (ret) { |
3042 | mlog_errno(ret); | 3112 | mlog_errno(ret); |
3043 | goto out_commit; | 3113 | goto out_commit; |
@@ -4202,6 +4272,12 @@ static int ocfs2_prepare_dx_dir_for_insert(struct inode *dir, | |||
4202 | } | 4272 | } |
4203 | 4273 | ||
4204 | dx_root = (struct ocfs2_dx_root_block *)dx_root_bh->b_data; | 4274 | dx_root = (struct ocfs2_dx_root_block *)dx_root_bh->b_data; |
4275 | if (le32_to_cpu(dx_root->dr_num_entries) == OCFS2_DX_ENTRIES_MAX) { | ||
4276 | ret = -ENOSPC; | ||
4277 | mlog_errno(ret); | ||
4278 | goto out; | ||
4279 | } | ||
4280 | |||
4205 | if (ocfs2_dx_root_inline(dx_root)) { | 4281 | if (ocfs2_dx_root_inline(dx_root)) { |
4206 | ret = ocfs2_inline_dx_has_space(dx_root_bh); | 4282 | ret = ocfs2_inline_dx_has_space(dx_root_bh); |
4207 | 4283 | ||