beginning of transition to parallel lookups - marking in-lookup dentries
marked as such when (would be) parallel lookup is about to pass them to actual ->lookup(); unmarked when * __d_add() is about to make it hashed, positive or not. * __d_move() (from d_splice_alias(), directly or via __d_unalias()) puts a preexisting dentry in its place * in caller of ->lookup() if it has escaped all of the above. Bug (WARN_ON, actually) if it reaches the final dput() or d_instantiate() while still marked such. As the result, we are guaranteed that for as long as the flag is set, dentry will * remain negative unhashed with positive refcount * never have its ->d_alias looked at * never have its ->d_lru looked at * never have its ->d_parent and ->d_name changed Right now we have at most one such for any given parent directory. With parallel lookups that restriction will weaken to * only exist when parent is locked shared * at most one with given (parent,name) pair (comparison of names is according to ->d_compare()) * only exist when there's no hashed dentry with the same (parent,name) Transition will take the next several commits; unfortunately, we'll only be able to switch to rwsem at the end of this series. The reason for not making it a single patch is to simplify review. New primitives: d_in_lookup() (a predicate checking if dentry is in the in-lookup state) and d_lookup_done() (tells the system that we are done with lookup and if it's still marked as in-lookup, it should cease to be such). Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
0568d705b0
commit
85c7f81041
13
fs/dcache.c
13
fs/dcache.c
|
@ -761,6 +761,8 @@ void dput(struct dentry *dentry)
|
|||
/* Slow case: now with the dentry lock held */
|
||||
rcu_read_unlock();
|
||||
|
||||
WARN_ON(d_in_lookup(dentry));
|
||||
|
||||
/* Unreachable? Get rid of it */
|
||||
if (unlikely(d_unhashed(dentry)))
|
||||
goto kill_it;
|
||||
|
@ -1746,6 +1748,7 @@ static unsigned d_flags_for_inode(struct inode *inode)
|
|||
static void __d_instantiate(struct dentry *dentry, struct inode *inode)
|
||||
{
|
||||
unsigned add_flags = d_flags_for_inode(inode);
|
||||
WARN_ON(d_in_lookup(dentry));
|
||||
|
||||
spin_lock(&dentry->d_lock);
|
||||
hlist_add_head(&dentry->d_u.d_alias, &inode->i_dentry);
|
||||
|
@ -2361,12 +2364,20 @@ void d_rehash(struct dentry * entry)
|
|||
}
|
||||
EXPORT_SYMBOL(d_rehash);
|
||||
|
||||
void __d_lookup_done(struct dentry *dentry)
|
||||
{
|
||||
dentry->d_flags &= ~DCACHE_PAR_LOOKUP;
|
||||
/* more stuff will land here */
|
||||
}
|
||||
EXPORT_SYMBOL(__d_lookup_done);
|
||||
|
||||
/* inode->i_lock held if inode is non-NULL */
|
||||
|
||||
static inline void __d_add(struct dentry *dentry, struct inode *inode)
|
||||
{
|
||||
spin_lock(&dentry->d_lock);
|
||||
if (unlikely(d_in_lookup(dentry)))
|
||||
__d_lookup_done(dentry);
|
||||
if (inode) {
|
||||
unsigned add_flags = d_flags_for_inode(inode);
|
||||
hlist_add_head(&dentry->d_u.d_alias, &inode->i_dentry);
|
||||
|
@ -2612,6 +2623,8 @@ static void __d_move(struct dentry *dentry, struct dentry *target,
|
|||
BUG_ON(d_ancestor(target, dentry));
|
||||
|
||||
dentry_lock_for_move(dentry, target);
|
||||
if (unlikely(d_in_lookup(target)))
|
||||
__d_lookup_done(target);
|
||||
|
||||
write_seqcount_begin(&dentry->d_seq);
|
||||
write_seqcount_begin_nested(&target->d_seq, DENTRY_D_LOCK_NESTED);
|
||||
|
|
|
@ -1634,7 +1634,11 @@ static struct dentry *lookup_slow(const struct qstr *name,
|
|||
inode_unlock(inode);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
spin_lock(&dentry->d_lock);
|
||||
dentry->d_flags |= DCACHE_PAR_LOOKUP;
|
||||
spin_unlock(&dentry->d_lock);
|
||||
old = inode->i_op->lookup(inode, dentry, flags);
|
||||
d_lookup_done(dentry);
|
||||
if (unlikely(old)) {
|
||||
dput(dentry);
|
||||
dentry = old;
|
||||
|
|
|
@ -232,6 +232,8 @@ struct dentry_operations {
|
|||
#define DCACHE_ENCRYPTED_WITH_KEY 0x04000000 /* dir is encrypted with a valid key */
|
||||
#define DCACHE_OP_REAL 0x08000000
|
||||
|
||||
#define DCACHE_PAR_LOOKUP 0x10000000 /* being looked up (with parent locked shared) */
|
||||
|
||||
extern seqlock_t rename_lock;
|
||||
|
||||
/*
|
||||
|
@ -367,6 +369,22 @@ static inline void dont_mount(struct dentry *dentry)
|
|||
spin_unlock(&dentry->d_lock);
|
||||
}
|
||||
|
||||
extern void __d_lookup_done(struct dentry *);
|
||||
|
||||
static inline int d_in_lookup(struct dentry *dentry)
|
||||
{
|
||||
return dentry->d_flags & DCACHE_PAR_LOOKUP;
|
||||
}
|
||||
|
||||
static inline void d_lookup_done(struct dentry *dentry)
|
||||
{
|
||||
if (unlikely(d_in_lookup(dentry))) {
|
||||
spin_lock(&dentry->d_lock);
|
||||
__d_lookup_done(dentry);
|
||||
spin_unlock(&dentry->d_lock);
|
||||
}
|
||||
}
|
||||
|
||||
extern void dput(struct dentry *);
|
||||
|
||||
static inline bool d_managed(const struct dentry *dentry)
|
||||
|
|
Loading…
Reference in New Issue