replace d_add_unique() with saner primitive
new primitive: d_exact_alias(dentry, inode). If there is an unhashed dentry with the same name/parent and given inode, rehash, grab and return it. Otherwise, return NULL. The only caller of d_add_unique() switched to d_exact_alias() + d_splice_alias(). Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
Родитель
e12a4e8a04
Коммит
668d0cd56e
125
fs/dcache.c
125
fs/dcache.c
|
@ -1781,81 +1781,6 @@ void d_instantiate(struct dentry *entry, struct inode * inode)
|
|||
}
|
||||
EXPORT_SYMBOL(d_instantiate);
|
||||
|
||||
/**
|
||||
* d_instantiate_unique - instantiate a non-aliased dentry
|
||||
* @entry: dentry to instantiate
|
||||
* @inode: inode to attach to this dentry
|
||||
*
|
||||
* Fill in inode information in the entry. On success, it returns NULL.
|
||||
* If an unhashed alias of "entry" already exists, then we return the
|
||||
* aliased dentry instead and drop one reference to inode.
|
||||
*
|
||||
* Note that in order to avoid conflicts with rename() etc, the caller
|
||||
* had better be holding the parent directory semaphore.
|
||||
*
|
||||
* This also assumes that the inode count has been incremented
|
||||
* (or otherwise set) by the caller to indicate that it is now
|
||||
* in use by the dcache.
|
||||
*/
|
||||
static struct dentry *__d_instantiate_unique(struct dentry *entry,
|
||||
struct inode *inode)
|
||||
{
|
||||
struct dentry *alias;
|
||||
int len = entry->d_name.len;
|
||||
const char *name = entry->d_name.name;
|
||||
unsigned int hash = entry->d_name.hash;
|
||||
|
||||
if (!inode) {
|
||||
__d_instantiate(entry, NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) {
|
||||
/*
|
||||
* Don't need alias->d_lock here, because aliases with
|
||||
* d_parent == entry->d_parent are not subject to name or
|
||||
* parent changes, because the parent inode i_mutex is held.
|
||||
*/
|
||||
if (alias->d_name.hash != hash)
|
||||
continue;
|
||||
if (alias->d_parent != entry->d_parent)
|
||||
continue;
|
||||
if (alias->d_name.len != len)
|
||||
continue;
|
||||
if (dentry_cmp(alias, name, len))
|
||||
continue;
|
||||
__dget(alias);
|
||||
return alias;
|
||||
}
|
||||
|
||||
__d_instantiate(entry, inode);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct dentry *d_instantiate_unique(struct dentry *entry, struct inode *inode)
|
||||
{
|
||||
struct dentry *result;
|
||||
|
||||
BUG_ON(!hlist_unhashed(&entry->d_u.d_alias));
|
||||
|
||||
if (inode)
|
||||
spin_lock(&inode->i_lock);
|
||||
result = __d_instantiate_unique(entry, inode);
|
||||
if (inode)
|
||||
spin_unlock(&inode->i_lock);
|
||||
|
||||
if (!result) {
|
||||
security_d_instantiate(entry, inode);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BUG_ON(!d_unhashed(result));
|
||||
iput(inode);
|
||||
return result;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(d_instantiate_unique);
|
||||
|
||||
/**
|
||||
* d_instantiate_no_diralias - instantiate a non-aliased dentry
|
||||
* @entry: dentry to complete
|
||||
|
@ -2436,6 +2361,56 @@ void d_rehash(struct dentry * entry)
|
|||
}
|
||||
EXPORT_SYMBOL(d_rehash);
|
||||
|
||||
/**
|
||||
* d_exact_alias - find and hash an exact unhashed alias
|
||||
* @entry: dentry to add
|
||||
* @inode: The inode to go with this dentry
|
||||
*
|
||||
* If an unhashed dentry with the same name/parent and desired
|
||||
* inode already exists, hash and return it. Otherwise, return
|
||||
* NULL.
|
||||
*
|
||||
* Parent directory should be locked.
|
||||
*/
|
||||
struct dentry *d_exact_alias(struct dentry *entry, struct inode *inode)
|
||||
{
|
||||
struct dentry *alias;
|
||||
int len = entry->d_name.len;
|
||||
const char *name = entry->d_name.name;
|
||||
unsigned int hash = entry->d_name.hash;
|
||||
|
||||
spin_lock(&inode->i_lock);
|
||||
hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) {
|
||||
/*
|
||||
* Don't need alias->d_lock here, because aliases with
|
||||
* d_parent == entry->d_parent are not subject to name or
|
||||
* parent changes, because the parent inode i_mutex is held.
|
||||
*/
|
||||
if (alias->d_name.hash != hash)
|
||||
continue;
|
||||
if (alias->d_parent != entry->d_parent)
|
||||
continue;
|
||||
if (alias->d_name.len != len)
|
||||
continue;
|
||||
if (dentry_cmp(alias, name, len))
|
||||
continue;
|
||||
spin_lock(&alias->d_lock);
|
||||
if (!d_unhashed(alias)) {
|
||||
spin_unlock(&alias->d_lock);
|
||||
alias = NULL;
|
||||
} else {
|
||||
__dget_dlock(alias);
|
||||
_d_rehash(alias);
|
||||
spin_unlock(&alias->d_lock);
|
||||
}
|
||||
spin_unlock(&inode->i_lock);
|
||||
return alias;
|
||||
}
|
||||
spin_unlock(&inode->i_lock);
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(d_exact_alias);
|
||||
|
||||
/**
|
||||
* dentry_update_name_case - update case insensitive dentry with a new name
|
||||
* @dentry: dentry to be updated
|
||||
|
|
|
@ -2461,14 +2461,15 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata,
|
|||
|
||||
dentry = opendata->dentry;
|
||||
if (d_really_is_negative(dentry)) {
|
||||
/* FIXME: Is this d_drop() ever needed? */
|
||||
struct dentry *alias;
|
||||
d_drop(dentry);
|
||||
dentry = d_add_unique(dentry, igrab(state->inode));
|
||||
if (dentry == NULL) {
|
||||
dentry = opendata->dentry;
|
||||
} else if (dentry != ctx->dentry) {
|
||||
alias = d_exact_alias(dentry, state->inode);
|
||||
if (!alias)
|
||||
alias = d_splice_alias(igrab(state->inode), dentry);
|
||||
/* d_splice_alias() can't fail here - it's a non-directory */
|
||||
if (alias) {
|
||||
dput(ctx->dentry);
|
||||
ctx->dentry = dget(dentry);
|
||||
ctx->dentry = dentry = alias;
|
||||
}
|
||||
nfs_set_verifier(dentry,
|
||||
nfs_save_change_attribute(d_inode(opendata->dir)));
|
||||
|
|
|
@ -246,6 +246,7 @@ extern struct dentry * d_alloc(struct dentry *, const struct qstr *);
|
|||
extern struct dentry * d_alloc_pseudo(struct super_block *, const struct qstr *);
|
||||
extern struct dentry * d_splice_alias(struct inode *, struct dentry *);
|
||||
extern struct dentry * d_add_ci(struct dentry *, struct inode *, struct qstr *);
|
||||
extern struct dentry * d_exact_alias(struct dentry *, struct inode *);
|
||||
extern struct dentry *d_find_any_alias(struct inode *inode);
|
||||
extern struct dentry * d_obtain_alias(struct inode *);
|
||||
extern struct dentry * d_obtain_root(struct inode *);
|
||||
|
@ -288,23 +289,6 @@ static inline void d_add(struct dentry *entry, struct inode *inode)
|
|||
d_rehash(entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* d_add_unique - add dentry to hash queues without aliasing
|
||||
* @entry: dentry to add
|
||||
* @inode: The inode to attach to this dentry
|
||||
*
|
||||
* This adds the entry to the hash queues and initializes @inode.
|
||||
* The entry was actually filled in earlier during d_alloc().
|
||||
*/
|
||||
static inline struct dentry *d_add_unique(struct dentry *entry, struct inode *inode)
|
||||
{
|
||||
struct dentry *res;
|
||||
|
||||
res = d_instantiate_unique(entry, inode);
|
||||
d_rehash(res != NULL ? res : entry);
|
||||
return res;
|
||||
}
|
||||
|
||||
extern void dentry_update_name_case(struct dentry *, struct qstr *);
|
||||
|
||||
/* used for rename() and baskets */
|
||||
|
|
Загрузка…
Ссылка в новой задаче