unify dentry_iput() and dentry_unlink_inode()
There is a lot of duplication between dentry_unlink_inode() and dentry_iput(). The only real difference is that dentry_unlink_inode() bumps ->d_seq and dentry_iput() doesn't. The argument of the latter is known to have been unhashed, so anybody who might've found it in RCU lookup would already be doomed to a ->d_seq mismatch. And we want to avoid pointless smp_rmb() there. This patch makes dentry_unlink_inode() bump ->d_seq only for hashed dentries. It's safe (d_delete() calls that sucker only if we are holding the only reference to dentry, so rehash is not going to happen) and it allows to use dentry_unlink_inode() in __dentry_kill() and get rid of dentry_iput(). The interesting question here is profiling; it *is* a hot path, and extra conditional jumps in there might or might not be painful. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
ea7d4c046b
commit
550dce01dd
41
fs/dcache.c
41
fs/dcache.c
|
@ -335,43 +335,20 @@ static inline void dentry_rcuwalk_invalidate(struct dentry *dentry)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Release the dentry's inode, using the filesystem
|
* Release the dentry's inode, using the filesystem
|
||||||
* d_iput() operation if defined. Dentry has no refcount
|
* d_iput() operation if defined.
|
||||||
* and is unhashed.
|
|
||||||
*/
|
|
||||||
static void dentry_iput(struct dentry * dentry)
|
|
||||||
__releases(dentry->d_lock)
|
|
||||||
__releases(dentry->d_inode->i_lock)
|
|
||||||
{
|
|
||||||
struct inode *inode = dentry->d_inode;
|
|
||||||
if (inode) {
|
|
||||||
__d_clear_type_and_inode(dentry);
|
|
||||||
hlist_del_init(&dentry->d_u.d_alias);
|
|
||||||
spin_unlock(&dentry->d_lock);
|
|
||||||
spin_unlock(&inode->i_lock);
|
|
||||||
if (!inode->i_nlink)
|
|
||||||
fsnotify_inoderemove(inode);
|
|
||||||
if (dentry->d_op && dentry->d_op->d_iput)
|
|
||||||
dentry->d_op->d_iput(dentry, inode);
|
|
||||||
else
|
|
||||||
iput(inode);
|
|
||||||
} else {
|
|
||||||
spin_unlock(&dentry->d_lock);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Release the dentry's inode, using the filesystem
|
|
||||||
* d_iput() operation if defined. dentry remains in-use.
|
|
||||||
*/
|
*/
|
||||||
static void dentry_unlink_inode(struct dentry * dentry)
|
static void dentry_unlink_inode(struct dentry * dentry)
|
||||||
__releases(dentry->d_lock)
|
__releases(dentry->d_lock)
|
||||||
__releases(dentry->d_inode->i_lock)
|
__releases(dentry->d_inode->i_lock)
|
||||||
{
|
{
|
||||||
struct inode *inode = dentry->d_inode;
|
struct inode *inode = dentry->d_inode;
|
||||||
|
bool hashed = !d_unhashed(dentry);
|
||||||
|
|
||||||
|
if (hashed)
|
||||||
raw_write_seqcount_begin(&dentry->d_seq);
|
raw_write_seqcount_begin(&dentry->d_seq);
|
||||||
__d_clear_type_and_inode(dentry);
|
__d_clear_type_and_inode(dentry);
|
||||||
hlist_del_init(&dentry->d_u.d_alias);
|
hlist_del_init(&dentry->d_u.d_alias);
|
||||||
|
if (hashed)
|
||||||
raw_write_seqcount_end(&dentry->d_seq);
|
raw_write_seqcount_end(&dentry->d_seq);
|
||||||
spin_unlock(&dentry->d_lock);
|
spin_unlock(&dentry->d_lock);
|
||||||
spin_unlock(&inode->i_lock);
|
spin_unlock(&inode->i_lock);
|
||||||
|
@ -540,12 +517,10 @@ static void __dentry_kill(struct dentry *dentry)
|
||||||
dentry->d_flags |= DCACHE_DENTRY_KILLED;
|
dentry->d_flags |= DCACHE_DENTRY_KILLED;
|
||||||
if (parent)
|
if (parent)
|
||||||
spin_unlock(&parent->d_lock);
|
spin_unlock(&parent->d_lock);
|
||||||
dentry_iput(dentry);
|
if (dentry->d_inode)
|
||||||
/*
|
dentry_unlink_inode(dentry);
|
||||||
* dentry_iput drops the locks, at which point nobody (except
|
else
|
||||||
* transient RCU lookups) can reach this dentry.
|
spin_unlock(&dentry->d_lock);
|
||||||
*/
|
|
||||||
BUG_ON(dentry->d_lockref.count > 0);
|
|
||||||
this_cpu_dec(nr_dentry);
|
this_cpu_dec(nr_dentry);
|
||||||
if (dentry->d_op && dentry->d_op->d_release)
|
if (dentry->d_op && dentry->d_op->d_release)
|
||||||
dentry->d_op->d_release(dentry);
|
dentry->d_op->d_release(dentry);
|
||||||
|
|
Loading…
Reference in New Issue