aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorMark Fasheh <mfasheh@suse.com>2009-02-17 18:29:35 -0500
committerMark Fasheh <mfasheh@suse.com>2009-04-03 14:39:16 -0400
commite3a93c2db6410822aa24295c3874b44ba21730a8 (patch)
tree8de41a37abc6497745d07506a0fb5174da61d7c1 /fs
parent198a1ca3b735986542c538e38b9499ffcaed7005 (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')
-rw-r--r--fs/ocfs2/dir.c162
-rw-r--r--fs/ocfs2/ocfs2_fs.h6
2 files changed, 124 insertions, 44 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
1375out: 1375out:
@@ -1508,13 +1508,20 @@ out:
1508 return ret; 1508 return ret;
1509} 1509}
1510 1510
1511static int ocfs2_dx_inline_root_insert(struct inode *dir, handle_t *handle, 1511static 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
1519static 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
1530out: 1550out:
1531 return ret; 1551 return ret;
1532} 1552}
1533 1553
1534static 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
1551static void ocfs2_remove_block_from_free_list(struct inode *dir, 1554static 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};
2125static int ocfs2_empty_dir_filldir(void *priv, const char *name, int name_len, 2129static 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
2164static 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
2192out:
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 */
2155int ocfs2_empty_dir(struct inode *inode) 2205int 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
2667inc: 2731inc:
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);
2710inc: 2776inc:
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
diff --git a/fs/ocfs2/ocfs2_fs.h b/fs/ocfs2/ocfs2_fs.h
index 43da76eff9ae..f7a5201410c8 100644
--- a/fs/ocfs2/ocfs2_fs.h
+++ b/fs/ocfs2/ocfs2_fs.h
@@ -421,6 +421,7 @@ static struct ocfs2_system_inode_info ocfs2_system_inodes[NUM_SYSTEM_INODES] = {
421#define OCFS2_LINK_MAX 32000 421#define OCFS2_LINK_MAX 32000
422#define OCFS2_DX_LINK_MAX ((1U << 31) - 1U) 422#define OCFS2_DX_LINK_MAX ((1U << 31) - 1U)
423#define OCFS2_LINKS_HI_SHIFT 16 423#define OCFS2_LINKS_HI_SHIFT 16
424#define OCFS2_DX_ENTRIES_MAX (0xffffffffU)
424 425
425#define S_SHIFT 12 426#define S_SHIFT 12
426static unsigned char ocfs2_type_by_mode[S_IFMT >> S_SHIFT] = { 427static unsigned char ocfs2_type_by_mode[S_IFMT >> S_SHIFT] = {
@@ -844,7 +845,10 @@ struct ocfs2_dx_root_block {
844 __u8 dr_reserved0; 845 __u8 dr_reserved0;
845 __le16 dr_reserved1; 846 __le16 dr_reserved1;
846 __le64 dr_dir_blkno; /* Pointer to parent inode */ 847 __le64 dr_dir_blkno; /* Pointer to parent inode */
847 __le64 dr_reserved2; 848 __le32 dr_num_entries; /* Total number of
849 * names stored in
850 * this directory.*/
851 __le32 dr_reserved2;
848 __le64 dr_free_blk; /* Pointer to head of free 852 __le64 dr_free_blk; /* Pointer to head of free
849 * unindexed block list. */ 853 * unindexed block list. */
850 __le64 dr_reserved3[15]; 854 __le64 dr_reserved3[15];