Commit e3a93c2d authored by Mark Fasheh's avatar Mark Fasheh

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: default avatarMark Fasheh <mfasheh@suse.com>
parent 198a1ca3
...@@ -1322,17 +1322,16 @@ static int ocfs2_delete_entry_dx(handle_t *handle, struct inode *dir, ...@@ -1322,17 +1322,16 @@ static int ocfs2_delete_entry_dx(handle_t *handle, struct inode *dir,
* entry yet. Likewise, successful return means we *must* * entry yet. Likewise, successful return means we *must*
* remove the indexed entry. * remove the indexed entry.
* *
* We're also careful to journal the root tree block here if * We're also careful to journal the root tree block here as
* we're going to be adding to the start of the free list. * the entry count needs to be updated. Also, we might be
* adding to the start of the free list.
*/ */
if (add_to_free_list || ocfs2_dx_root_inline(dx_root)) {
ret = ocfs2_journal_access_dr(handle, dir, dx_root_bh, ret = ocfs2_journal_access_dr(handle, dir, dx_root_bh,
OCFS2_JOURNAL_ACCESS_WRITE); OCFS2_JOURNAL_ACCESS_WRITE);
if (ret) { if (ret) {
mlog_errno(ret); mlog_errno(ret);
goto out; goto out;
} }
}
if (!ocfs2_dx_root_inline(dx_root)) { if (!ocfs2_dx_root_inline(dx_root)) {
ret = ocfs2_journal_access_dl(handle, dir, ret = ocfs2_journal_access_dl(handle, dir,
...@@ -1365,11 +1364,12 @@ static int ocfs2_delete_entry_dx(handle_t *handle, struct inode *dir, ...@@ -1365,11 +1364,12 @@ static int ocfs2_delete_entry_dx(handle_t *handle, struct inode *dir,
/* leaf_bh was journal_accessed for us in __ocfs2_delete_entry */ /* leaf_bh was journal_accessed for us in __ocfs2_delete_entry */
ocfs2_journal_dirty(handle, leaf_bh); ocfs2_journal_dirty(handle, leaf_bh);
le32_add_cpu(&dx_root->dr_num_entries, -1);
ocfs2_journal_dirty(handle, dx_root_bh);
ocfs2_dx_list_remove_entry(entry_list, index); ocfs2_dx_list_remove_entry(entry_list, index);
if (ocfs2_dx_root_inline(dx_root)) if (!ocfs2_dx_root_inline(dx_root))
ocfs2_journal_dirty(handle, dx_root_bh);
else
ocfs2_journal_dirty(handle, lookup->dl_dx_leaf_bh); ocfs2_journal_dirty(handle, lookup->dl_dx_leaf_bh);
out: out:
...@@ -1508,13 +1508,20 @@ static int __ocfs2_dx_dir_leaf_insert(struct inode *dir, handle_t *handle, ...@@ -1508,13 +1508,20 @@ static int __ocfs2_dx_dir_leaf_insert(struct inode *dir, handle_t *handle,
return ret; return ret;
} }
static int ocfs2_dx_inline_root_insert(struct inode *dir, handle_t *handle, static void ocfs2_dx_inline_root_insert(struct inode *dir, handle_t *handle,
struct ocfs2_dx_hinfo *hinfo, struct ocfs2_dx_hinfo *hinfo,
u64 dirent_blk, u64 dirent_blk,
struct buffer_head *dx_root_bh) struct ocfs2_dx_root_block *dx_root)
{ {
int ret; ocfs2_dx_entry_list_insert(&dx_root->dr_entries, hinfo, dirent_blk);
}
static int ocfs2_dx_dir_insert(struct inode *dir, handle_t *handle,
struct ocfs2_dir_lookup_result *lookup)
{
int ret = 0;
struct ocfs2_dx_root_block *dx_root; struct ocfs2_dx_root_block *dx_root;
struct buffer_head *dx_root_bh = lookup->dl_dx_root_bh;
ret = ocfs2_journal_access_dr(handle, dir, dx_root_bh, ret = ocfs2_journal_access_dr(handle, dir, dx_root_bh,
OCFS2_JOURNAL_ACCESS_WRITE); OCFS2_JOURNAL_ACCESS_WRITE);
...@@ -1523,29 +1530,25 @@ static int ocfs2_dx_inline_root_insert(struct inode *dir, handle_t *handle, ...@@ -1523,29 +1530,25 @@ static int ocfs2_dx_inline_root_insert(struct inode *dir, handle_t *handle,
goto out; goto out;
} }
dx_root = (struct ocfs2_dx_root_block *)dx_root_bh->b_data;
ocfs2_dx_entry_list_insert(&dx_root->dr_entries, hinfo, dirent_blk);
ocfs2_journal_dirty(handle, dx_root_bh);
out:
return ret;
}
static int ocfs2_dx_dir_insert(struct inode *dir, handle_t *handle,
struct ocfs2_dir_lookup_result *lookup)
{
struct ocfs2_dx_root_block *dx_root;
dx_root = (struct ocfs2_dx_root_block *)lookup->dl_dx_root_bh->b_data; dx_root = (struct ocfs2_dx_root_block *)lookup->dl_dx_root_bh->b_data;
if (ocfs2_dx_root_inline(dx_root)) if (ocfs2_dx_root_inline(dx_root)) {
return ocfs2_dx_inline_root_insert(dir, handle, ocfs2_dx_inline_root_insert(dir, handle,
&lookup->dl_hinfo, &lookup->dl_hinfo,
lookup->dl_leaf_bh->b_blocknr, lookup->dl_leaf_bh->b_blocknr,
lookup->dl_dx_root_bh); dx_root);
} else {
return __ocfs2_dx_dir_leaf_insert(dir, handle, &lookup->dl_hinfo, ret = __ocfs2_dx_dir_leaf_insert(dir, handle, &lookup->dl_hinfo,
lookup->dl_leaf_bh->b_blocknr, lookup->dl_leaf_bh->b_blocknr,
lookup->dl_dx_leaf_bh); lookup->dl_dx_leaf_bh);
if (ret)
goto out;
}
le32_add_cpu(&dx_root->dr_num_entries, 1);
ocfs2_journal_dirty(handle, dx_root_bh);
out:
return ret;
} }
static void ocfs2_remove_block_from_free_list(struct inode *dir, static void ocfs2_remove_block_from_free_list(struct inode *dir,
...@@ -2121,6 +2124,7 @@ struct ocfs2_empty_dir_priv { ...@@ -2121,6 +2124,7 @@ struct ocfs2_empty_dir_priv {
unsigned seen_dot; unsigned seen_dot;
unsigned seen_dot_dot; unsigned seen_dot_dot;
unsigned seen_other; unsigned seen_other;
unsigned dx_dir;
}; };
static int ocfs2_empty_dir_filldir(void *priv, const char *name, int name_len, static int ocfs2_empty_dir_filldir(void *priv, const char *name, int name_len,
loff_t pos, u64 ino, unsigned type) 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,6 +2134,13 @@ static int ocfs2_empty_dir_filldir(void *priv, const char *name, int name_len,
/* /*
* Check the positions of "." and ".." records to be sure * Check the positions of "." and ".." records to be sure
* they're in the correct place. * they're in the correct place.
*
* Indexed directories don't need to proceed past the first
* two entries, so we end the scan after seeing '..'. Despite
* that, we allow the scan to proceed In the event that we
* have a corrupted indexed directory (no dot or dot dot
* entries). This allows us to double check for existing
* entries which might not have been found in the index.
*/ */
if (name_len == 1 && !strncmp(".", name, 1) && pos == 0) { if (name_len == 1 && !strncmp(".", name, 1) && pos == 0) {
p->seen_dot = 1; p->seen_dot = 1;
...@@ -2139,18 +2150,57 @@ static int ocfs2_empty_dir_filldir(void *priv, const char *name, int name_len, ...@@ -2139,18 +2150,57 @@ static int ocfs2_empty_dir_filldir(void *priv, const char *name, int name_len,
if (name_len == 2 && !strncmp("..", name, 2) && if (name_len == 2 && !strncmp("..", name, 2) &&
pos == OCFS2_DIR_REC_LEN(1)) { pos == OCFS2_DIR_REC_LEN(1)) {
p->seen_dot_dot = 1; p->seen_dot_dot = 1;
if (p->dx_dir && p->seen_dot)
return 1;
return 0; return 0;
} }
p->seen_other = 1; p->seen_other = 1;
return 1; return 1;
} }
static int ocfs2_empty_dir_dx(struct inode *inode,
struct ocfs2_empty_dir_priv *priv)
{
int ret;
struct buffer_head *di_bh = NULL;
struct buffer_head *dx_root_bh = NULL;
struct ocfs2_dinode *di;
struct ocfs2_dx_root_block *dx_root;
priv->dx_dir = 1;
ret = ocfs2_read_inode_block(inode, &di_bh);
if (ret) {
mlog_errno(ret);
goto out;
}
di = (struct ocfs2_dinode *)di_bh->b_data;
ret = ocfs2_read_dx_root(inode, di, &dx_root_bh);
if (ret) {
mlog_errno(ret);
goto out;
}
dx_root = (struct ocfs2_dx_root_block *)dx_root_bh->b_data;
if (le32_to_cpu(dx_root->dr_num_entries) != 2)
priv->seen_other = 1;
out:
brelse(di_bh);
brelse(dx_root_bh);
return ret;
}
/* /*
* routine to check that the specified directory is empty (for rmdir) * routine to check that the specified directory is empty (for rmdir)
* *
* Returns 1 if dir is empty, zero otherwise. * Returns 1 if dir is empty, zero otherwise.
* *
* XXX: This is a performance problem * XXX: This is a performance problem for unindexed directories.
*/ */
int ocfs2_empty_dir(struct inode *inode) int ocfs2_empty_dir(struct inode *inode)
{ {
...@@ -2160,6 +2210,16 @@ int ocfs2_empty_dir(struct inode *inode) ...@@ -2160,6 +2210,16 @@ int ocfs2_empty_dir(struct inode *inode)
memset(&priv, 0, sizeof(priv)); memset(&priv, 0, sizeof(priv));
if (ocfs2_dir_indexed(inode)) {
ret = ocfs2_empty_dir_dx(inode, &priv);
if (ret)
mlog_errno(ret);
/*
* We still run ocfs2_dir_foreach to get the checks
* for "." and "..".
*/
}
ret = ocfs2_dir_foreach(inode, &start, &priv, ocfs2_empty_dir_filldir); ret = ocfs2_dir_foreach(inode, &start, &priv, ocfs2_empty_dir_filldir);
if (ret) if (ret)
mlog_errno(ret); mlog_errno(ret);
...@@ -2329,7 +2389,7 @@ static int ocfs2_dx_dir_attach_index(struct ocfs2_super *osb, ...@@ -2329,7 +2389,7 @@ static int ocfs2_dx_dir_attach_index(struct ocfs2_super *osb,
struct buffer_head *di_bh, struct buffer_head *di_bh,
struct buffer_head *dirdata_bh, struct buffer_head *dirdata_bh,
struct ocfs2_alloc_context *meta_ac, struct ocfs2_alloc_context *meta_ac,
int dx_inline, int dx_inline, u32 num_entries,
struct buffer_head **ret_dx_root_bh) struct buffer_head **ret_dx_root_bh)
{ {
int ret; int ret;
...@@ -2375,6 +2435,7 @@ static int ocfs2_dx_dir_attach_index(struct ocfs2_super *osb, ...@@ -2375,6 +2435,7 @@ static int ocfs2_dx_dir_attach_index(struct ocfs2_super *osb,
dx_root->dr_fs_generation = cpu_to_le32(osb->fs_generation); dx_root->dr_fs_generation = cpu_to_le32(osb->fs_generation);
dx_root->dr_blkno = cpu_to_le64(dr_blkno); dx_root->dr_blkno = cpu_to_le64(dr_blkno);
dx_root->dr_dir_blkno = cpu_to_le64(OCFS2_I(dir)->ip_blkno); dx_root->dr_dir_blkno = cpu_to_le64(OCFS2_I(dir)->ip_blkno);
dx_root->dr_num_entries = cpu_to_le32(num_entries);
if (le16_to_cpu(trailer->db_free_rec_len)) if (le16_to_cpu(trailer->db_free_rec_len))
dx_root->dr_free_blk = cpu_to_le64(dirdata_bh->b_blocknr); dx_root->dr_free_blk = cpu_to_le64(dirdata_bh->b_blocknr);
else else
...@@ -2586,7 +2647,7 @@ static int ocfs2_fill_new_dir_dx(struct ocfs2_super *osb, ...@@ -2586,7 +2647,7 @@ static int ocfs2_fill_new_dir_dx(struct ocfs2_super *osb,
} }
ret = ocfs2_dx_dir_attach_index(osb, handle, inode, di_bh, leaf_bh, ret = ocfs2_dx_dir_attach_index(osb, handle, inode, di_bh, leaf_bh,
meta_ac, 1, &dx_root_bh); meta_ac, 1, 2, &dx_root_bh);
if (ret) { if (ret) {
mlog_errno(ret); mlog_errno(ret);
goto out; goto out;
...@@ -2633,6 +2694,7 @@ static int ocfs2_dx_dir_index_block(struct inode *dir, ...@@ -2633,6 +2694,7 @@ static int ocfs2_dx_dir_index_block(struct inode *dir,
handle_t *handle, handle_t *handle,
struct buffer_head **dx_leaves, struct buffer_head **dx_leaves,
int num_dx_leaves, int num_dx_leaves,
u32 *num_dx_entries,
struct buffer_head *dirent_bh) struct buffer_head *dirent_bh)
{ {
int ret, namelen, i; int ret, namelen, i;
...@@ -2664,6 +2726,8 @@ static int ocfs2_dx_dir_index_block(struct inode *dir, ...@@ -2664,6 +2726,8 @@ static int ocfs2_dx_dir_index_block(struct inode *dir,
goto out; goto out;
} }
*num_dx_entries = *num_dx_entries + 1;
inc: inc:
de_buf += le16_to_cpu(de->rec_len); de_buf += le16_to_cpu(de->rec_len);
} }
...@@ -2707,6 +2771,8 @@ static void ocfs2_dx_dir_index_root_block(struct inode *dir, ...@@ -2707,6 +2771,8 @@ static void ocfs2_dx_dir_index_root_block(struct inode *dir,
ocfs2_dx_entry_list_insert(&dx_root->dr_entries, &hinfo, ocfs2_dx_entry_list_insert(&dx_root->dr_entries, &hinfo,
dirent_blk); dirent_blk);
le32_add_cpu(&dx_root->dr_num_entries, 1);
inc: inc:
de_buf += le16_to_cpu(de->rec_len); de_buf += le16_to_cpu(de->rec_len);
} }
...@@ -2810,7 +2876,7 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh, ...@@ -2810,7 +2876,7 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh,
struct ocfs2_dir_lookup_result *lookup, struct ocfs2_dir_lookup_result *lookup,
struct buffer_head **first_block_bh) struct buffer_head **first_block_bh)
{ {
u32 alloc, dx_alloc, bit_off, len; u32 alloc, dx_alloc, bit_off, len, num_dx_entries = 0;
struct super_block *sb = dir->i_sb; struct super_block *sb = dir->i_sb;
int ret, i, num_dx_leaves = 0, dx_inline = 0, int ret, i, num_dx_leaves = 0, dx_inline = 0,
credits = ocfs2_inline_to_extents_credits(sb); 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,10 +3038,14 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh,
/* /*
* Dx dirs with an external cluster need to do this up * Dx dirs with an external cluster need to do this up
* front. Inline dx root's get handled later, after * front. Inline dx root's get handled later, after
* we've allocated our root block. * we've allocated our root block. We get passed back
* a total number of items so that dr_num_entries can
* be correctly set once the dx_root has been
* allocated.
*/ */
ret = ocfs2_dx_dir_index_block(dir, handle, dx_leaves, ret = ocfs2_dx_dir_index_block(dir, handle, dx_leaves,
num_dx_leaves, dirdata_bh); num_dx_leaves, &num_dx_entries,
dirdata_bh);
if (ret) { if (ret) {
mlog_errno(ret); mlog_errno(ret);
goto out_commit; goto out_commit;
...@@ -3037,7 +3107,7 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh, ...@@ -3037,7 +3107,7 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh,
if (ocfs2_supports_indexed_dirs(osb)) { if (ocfs2_supports_indexed_dirs(osb)) {
ret = ocfs2_dx_dir_attach_index(osb, handle, dir, di_bh, ret = ocfs2_dx_dir_attach_index(osb, handle, dir, di_bh,
dirdata_bh, meta_ac, dx_inline, dirdata_bh, meta_ac, dx_inline,
&dx_root_bh); num_dx_entries, &dx_root_bh);
if (ret) { if (ret) {
mlog_errno(ret); mlog_errno(ret);
goto out_commit; goto out_commit;
...@@ -4202,6 +4272,12 @@ static int ocfs2_prepare_dx_dir_for_insert(struct inode *dir, ...@@ -4202,6 +4272,12 @@ static int ocfs2_prepare_dx_dir_for_insert(struct inode *dir,
} }
dx_root = (struct ocfs2_dx_root_block *)dx_root_bh->b_data; dx_root = (struct ocfs2_dx_root_block *)dx_root_bh->b_data;
if (le32_to_cpu(dx_root->dr_num_entries) == OCFS2_DX_ENTRIES_MAX) {
ret = -ENOSPC;
mlog_errno(ret);
goto out;
}
if (ocfs2_dx_root_inline(dx_root)) { if (ocfs2_dx_root_inline(dx_root)) {
ret = ocfs2_inline_dx_has_space(dx_root_bh); ret = ocfs2_inline_dx_has_space(dx_root_bh);
......
...@@ -421,6 +421,7 @@ static struct ocfs2_system_inode_info ocfs2_system_inodes[NUM_SYSTEM_INODES] = { ...@@ -421,6 +421,7 @@ static struct ocfs2_system_inode_info ocfs2_system_inodes[NUM_SYSTEM_INODES] = {
#define OCFS2_LINK_MAX 32000 #define OCFS2_LINK_MAX 32000
#define OCFS2_DX_LINK_MAX ((1U << 31) - 1U) #define OCFS2_DX_LINK_MAX ((1U << 31) - 1U)
#define OCFS2_LINKS_HI_SHIFT 16 #define OCFS2_LINKS_HI_SHIFT 16
#define OCFS2_DX_ENTRIES_MAX (0xffffffffU)
#define S_SHIFT 12 #define S_SHIFT 12
static unsigned char ocfs2_type_by_mode[S_IFMT >> S_SHIFT] = { static unsigned char ocfs2_type_by_mode[S_IFMT >> S_SHIFT] = {
...@@ -844,7 +845,10 @@ struct ocfs2_dx_root_block { ...@@ -844,7 +845,10 @@ struct ocfs2_dx_root_block {
__u8 dr_reserved0; __u8 dr_reserved0;
__le16 dr_reserved1; __le16 dr_reserved1;
__le64 dr_dir_blkno; /* Pointer to parent inode */ __le64 dr_dir_blkno; /* Pointer to parent inode */
__le64 dr_reserved2; __le32 dr_num_entries; /* Total number of
* names stored in
* this directory.*/
__le32 dr_reserved2;
__le64 dr_free_blk; /* Pointer to head of free __le64 dr_free_blk; /* Pointer to head of free
* unindexed block list. */ * unindexed block list. */
__le64 dr_reserved3[15]; __le64 dr_reserved3[15];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment