Commit 668d0cd5 authored by Al Viro's avatar Al Viro

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: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent e12a4e8a
...@@ -1781,81 +1781,6 @@ void d_instantiate(struct dentry *entry, struct inode * inode) ...@@ -1781,81 +1781,6 @@ void d_instantiate(struct dentry *entry, struct inode * inode)
} }
EXPORT_SYMBOL(d_instantiate); 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 * d_instantiate_no_diralias - instantiate a non-aliased dentry
* @entry: dentry to complete * @entry: dentry to complete
...@@ -2436,6 +2361,56 @@ void d_rehash(struct dentry * entry) ...@@ -2436,6 +2361,56 @@ void d_rehash(struct dentry * entry)
} }
EXPORT_SYMBOL(d_rehash); 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_update_name_case - update case insensitive dentry with a new name
* @dentry: dentry to be updated * @dentry: dentry to be updated
......
...@@ -2461,14 +2461,15 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata, ...@@ -2461,14 +2461,15 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata,
dentry = opendata->dentry; dentry = opendata->dentry;
if (d_really_is_negative(dentry)) { if (d_really_is_negative(dentry)) {
/* FIXME: Is this d_drop() ever needed? */ struct dentry *alias;
d_drop(dentry); d_drop(dentry);
dentry = d_add_unique(dentry, igrab(state->inode)); alias = d_exact_alias(dentry, state->inode);
if (dentry == NULL) { if (!alias)
dentry = opendata->dentry; alias = d_splice_alias(igrab(state->inode), dentry);
} else if (dentry != ctx->dentry) { /* d_splice_alias() can't fail here - it's a non-directory */
if (alias) {
dput(ctx->dentry); dput(ctx->dentry);
ctx->dentry = dget(dentry); ctx->dentry = dentry = alias;
} }
nfs_set_verifier(dentry, nfs_set_verifier(dentry,
nfs_save_change_attribute(d_inode(opendata->dir))); nfs_save_change_attribute(d_inode(opendata->dir)));
......
...@@ -246,6 +246,7 @@ extern struct dentry * d_alloc(struct dentry *, const struct qstr *); ...@@ -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_alloc_pseudo(struct super_block *, const struct qstr *);
extern struct dentry * d_splice_alias(struct inode *, struct dentry *); 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_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_find_any_alias(struct inode *inode);
extern struct dentry * d_obtain_alias(struct inode *); extern struct dentry * d_obtain_alias(struct inode *);
extern struct dentry * d_obtain_root(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) ...@@ -288,23 +289,6 @@ static inline void d_add(struct dentry *entry, struct inode *inode)
d_rehash(entry); 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 *); extern void dentry_update_name_case(struct dentry *, struct qstr *);
/* used for rename() and baskets */ /* used for rename() and baskets */
......
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