Commit 5e98d492 authored by Goldwyn Rodrigues's avatar Goldwyn Rodrigues Committed by Joel Becker

Track negative entries v3

Track negative dentries by recording the generation number of the parent
directory in d_fsdata. The generation number for the parent directory is
recorded in the inode_info, which increments every time the lock on the
directory is dropped.

If the generation number of the parent directory and the negative dentry
matches, there is no need to perform the revalidate, else a revalidate
is forced. This improves performance in situations where nodes look for
the same non-existent file multiple times.

Thanks Mark for explaining the DLM sequence.
Signed-off-by: default avatarGoldwyn Rodrigues <rgoldwyn@suse.de>
Signed-off-by: default avatarJoel Becker <joel.becker@oracle.com>
parent b4d693fc
...@@ -40,6 +40,14 @@ ...@@ -40,6 +40,14 @@
#include "inode.h" #include "inode.h"
#include "super.h" #include "super.h"
void ocfs2_dentry_attach_gen(struct dentry *dentry)
{
unsigned long gen =
OCFS2_I(dentry->d_parent->d_inode)->ip_dir_lock_gen;
BUG_ON(dentry->d_inode);
dentry->d_fsdata = (void *)gen;
}
static int ocfs2_dentry_revalidate(struct dentry *dentry, static int ocfs2_dentry_revalidate(struct dentry *dentry,
struct nameidata *nd) struct nameidata *nd)
...@@ -51,11 +59,20 @@ static int ocfs2_dentry_revalidate(struct dentry *dentry, ...@@ -51,11 +59,20 @@ static int ocfs2_dentry_revalidate(struct dentry *dentry,
mlog_entry("(0x%p, '%.*s')\n", dentry, mlog_entry("(0x%p, '%.*s')\n", dentry,
dentry->d_name.len, dentry->d_name.name); dentry->d_name.len, dentry->d_name.name);
/* Never trust a negative dentry - force a new lookup. */ /* For a negative dentry -
* check the generation number of the parent and compare with the
* one stored in the inode.
*/
if (inode == NULL) { if (inode == NULL) {
mlog(0, "negative dentry: %.*s\n", dentry->d_name.len, unsigned long gen = (unsigned long) dentry->d_fsdata;
dentry->d_name.name); unsigned long pgen =
goto bail; OCFS2_I(dentry->d_parent->d_inode)->ip_dir_lock_gen;
mlog(0, "negative dentry: %.*s parent gen: %lu "
"dentry gen: %lu\n",
dentry->d_name.len, dentry->d_name.name, pgen, gen);
if (gen != pgen)
goto bail;
goto valid;
} }
BUG_ON(!osb); BUG_ON(!osb);
...@@ -96,6 +113,7 @@ static int ocfs2_dentry_revalidate(struct dentry *dentry, ...@@ -96,6 +113,7 @@ static int ocfs2_dentry_revalidate(struct dentry *dentry,
goto bail; goto bail;
} }
valid:
ret = 1; ret = 1;
bail: bail:
...@@ -227,6 +245,12 @@ int ocfs2_dentry_attach_lock(struct dentry *dentry, ...@@ -227,6 +245,12 @@ int ocfs2_dentry_attach_lock(struct dentry *dentry,
if (!inode) if (!inode)
return 0; return 0;
if (!dentry->d_inode && dentry->d_fsdata) {
/* Converting a negative dentry to positive
Clear dentry->d_fsdata */
dentry->d_fsdata = dl = NULL;
}
if (dl) { if (dl) {
mlog_bug_on_msg(dl->dl_parent_blkno != parent_blkno, mlog_bug_on_msg(dl->dl_parent_blkno != parent_blkno,
" \"%.*s\": old parent: %llu, new: %llu\n", " \"%.*s\": old parent: %llu, new: %llu\n",
...@@ -452,6 +476,7 @@ static void ocfs2_dentry_iput(struct dentry *dentry, struct inode *inode) ...@@ -452,6 +476,7 @@ static void ocfs2_dentry_iput(struct dentry *dentry, struct inode *inode)
out: out:
iput(inode); iput(inode);
ocfs2_dentry_attach_gen(dentry);
} }
/* /*
......
...@@ -64,5 +64,6 @@ void ocfs2_dentry_move(struct dentry *dentry, struct dentry *target, ...@@ -64,5 +64,6 @@ void ocfs2_dentry_move(struct dentry *dentry, struct dentry *target,
struct inode *old_dir, struct inode *new_dir); struct inode *old_dir, struct inode *new_dir);
extern spinlock_t dentry_attach_lock; extern spinlock_t dentry_attach_lock;
void ocfs2_dentry_attach_gen(struct dentry *dentry);
#endif /* OCFS2_DCACHE_H */ #endif /* OCFS2_DCACHE_H */
...@@ -3635,10 +3635,18 @@ static int ocfs2_data_convert_worker(struct ocfs2_lock_res *lockres, ...@@ -3635,10 +3635,18 @@ static int ocfs2_data_convert_worker(struct ocfs2_lock_res *lockres,
{ {
struct inode *inode; struct inode *inode;
struct address_space *mapping; struct address_space *mapping;
struct ocfs2_inode_info *oi;
inode = ocfs2_lock_res_inode(lockres); inode = ocfs2_lock_res_inode(lockres);
mapping = inode->i_mapping; mapping = inode->i_mapping;
if (S_ISDIR(inode->i_mode)) {
oi = OCFS2_I(inode);
oi->ip_dir_lock_gen++;
mlog(0, "generation: %u\n", oi->ip_dir_lock_gen);
goto out;
}
if (!S_ISREG(inode->i_mode)) if (!S_ISREG(inode->i_mode))
goto out; goto out;
......
...@@ -335,6 +335,7 @@ void ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe, ...@@ -335,6 +335,7 @@ void ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe,
else else
inode->i_fop = &ocfs2_dops_no_plocks; inode->i_fop = &ocfs2_dops_no_plocks;
i_size_write(inode, le64_to_cpu(fe->i_size)); i_size_write(inode, le64_to_cpu(fe->i_size));
OCFS2_I(inode)->ip_dir_lock_gen = 1;
break; break;
case S_IFLNK: case S_IFLNK:
if (ocfs2_inode_is_fast_symlink(inode)) if (ocfs2_inode_is_fast_symlink(inode))
......
...@@ -67,6 +67,7 @@ struct ocfs2_inode_info ...@@ -67,6 +67,7 @@ struct ocfs2_inode_info
/* Only valid if the inode is the dir. */ /* Only valid if the inode is the dir. */
u32 ip_last_used_slot; u32 ip_last_used_slot;
u64 ip_last_used_group; u64 ip_last_used_group;
u32 ip_dir_lock_gen;
struct ocfs2_alloc_reservation ip_la_data_resv; struct ocfs2_alloc_reservation ip_la_data_resv;
}; };
......
...@@ -171,7 +171,8 @@ static struct dentry *ocfs2_lookup(struct inode *dir, struct dentry *dentry, ...@@ -171,7 +171,8 @@ static struct dentry *ocfs2_lookup(struct inode *dir, struct dentry *dentry,
ret = ERR_PTR(status); ret = ERR_PTR(status);
goto bail_unlock; goto bail_unlock;
} }
} } else
ocfs2_dentry_attach_gen(dentry);
bail_unlock: bail_unlock:
/* Don't drop the cluster lock until *after* the d_add -- /* Don't drop the cluster lock until *after* the d_add --
......
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