dentry_stat.nr_dentry--; /* For d_free, below */
/*drops the locks, at that point nobody can reach this dentry */
dentry_iput(dentry);
- parent = dentry->d_parent;
+ if (IS_ROOT(dentry))
+ parent = NULL;
+ else
+ parent = dentry->d_parent;
d_free(dentry);
- return dentry == parent ? NULL : parent;
+ return parent;
}
/*
BUG();
}
- parent = dentry->d_parent;
- if (parent == dentry)
+ if (IS_ROOT(dentry))
parent = NULL;
- else
+ else {
+ parent = dentry->d_parent;
atomic_dec(&parent->d_count);
+ }
list_del(&dentry->d_u.d_child);
detached++;
return dentry_hashtable + (hash & D_HASHMASK);
}
-/**
- * d_alloc_anon - allocate an anonymous dentry
- * @inode: inode to allocate the dentry for
- *
- * This is similar to d_alloc_root. It is used by filesystems when
- * creating a dentry for a given inode, often in the process of
- * mapping a filehandle to a dentry. The returned dentry may be
- * anonymous, or may have a full name (if the inode was already
- * in the cache). The file system may need to make further
- * efforts to connect this dentry into the dcache properly.
- *
- * When called on a directory inode, we must ensure that
- * the inode only ever has one dentry. If a dentry is
- * found, that is returned instead of allocating a new one.
- *
- * On successful return, the reference to the inode has been transferred
- * to the dentry. If %NULL is returned (indicating kmalloc failure),
- * the reference on the inode has not been released.
- */
-
-struct dentry * d_alloc_anon(struct inode *inode)
-{
- static const struct qstr anonstring = { .name = "" };
- struct dentry *tmp;
- struct dentry *res;
-
- if ((res = d_find_alias(inode))) {
- iput(inode);
- return res;
- }
-
- tmp = d_alloc(NULL, &anonstring);
- if (!tmp)
- return NULL;
-
- tmp->d_parent = tmp; /* make sure dput doesn't croak */
-
- spin_lock(&dcache_lock);
- res = __d_find_alias(inode, 0);
- if (!res) {
- /* attach a disconnected dentry */
- res = tmp;
- tmp = NULL;
- spin_lock(&res->d_lock);
- res->d_sb = inode->i_sb;
- res->d_parent = res;
- res->d_inode = inode;
- res->d_flags |= DCACHE_DISCONNECTED;
- res->d_flags &= ~DCACHE_UNHASHED;
- list_add(&res->d_alias, &inode->i_dentry);
- hlist_add_head(&res->d_hash, &inode->i_sb->s_anon);
- spin_unlock(&res->d_lock);
-
- inode = NULL; /* don't drop reference */
- }
- spin_unlock(&dcache_lock);
-
- if (inode)
- iput(inode);
- if (tmp)
- dput(tmp);
- return res;
-}
-
/**
* d_obtain_alias - find or allocate a dentry for a given inode
* @inode: inode to allocate the dentry for
*/
struct dentry *d_obtain_alias(struct inode *inode)
{
- struct dentry *dentry;
+ static const struct qstr anonstring = { .name = "" };
+ struct dentry *tmp;
+ struct dentry *res;
if (!inode)
return ERR_PTR(-ESTALE);
if (IS_ERR(inode))
return ERR_CAST(inode);
- dentry = d_alloc_anon(inode);
- if (!dentry) {
- iput(inode);
- dentry = ERR_PTR(-ENOMEM);
+ res = d_find_alias(inode);
+ if (res)
+ goto out_iput;
+
+ tmp = d_alloc(NULL, &anonstring);
+ if (!tmp) {
+ res = ERR_PTR(-ENOMEM);
+ goto out_iput;
}
- return dentry;
+ tmp->d_parent = tmp; /* make sure dput doesn't croak */
+
+ spin_lock(&dcache_lock);
+ res = __d_find_alias(inode, 0);
+ if (res) {
+ spin_unlock(&dcache_lock);
+ dput(tmp);
+ goto out_iput;
+ }
+
+ /* attach a disconnected dentry */
+ spin_lock(&tmp->d_lock);
+ tmp->d_sb = inode->i_sb;
+ tmp->d_inode = inode;
+ tmp->d_flags |= DCACHE_DISCONNECTED;
+ tmp->d_flags &= ~DCACHE_UNHASHED;
+ list_add(&tmp->d_alias, &inode->i_dentry);
+ hlist_add_head(&tmp->d_hash, &inode->i_sb->s_anon);
+ spin_unlock(&tmp->d_lock);
+
+ spin_unlock(&dcache_lock);
+ return tmp;
+
+ out_iput:
+ iput(inode);
+ return res;
}
EXPORT_SYMBOL_GPL(d_obtain_alias);
{
struct dentry *p;
- for (p = p2; p->d_parent != p; p = p->d_parent) {
+ for (p = p2; !IS_ROOT(p); p = p->d_parent) {
if (p->d_parent == p1)
return 1;
}
seq = read_seqbegin(&rename_lock);
for (;;) {
if (new_dentry != old_dentry) {
- struct dentry * parent = new_dentry->d_parent;
- if (parent == new_dentry)
+ if (IS_ROOT(new_dentry))
break;
- new_dentry = parent;
+ new_dentry = new_dentry->d_parent;
continue;
}
result = 1;
}
EXPORT_SYMBOL(d_alloc);
-EXPORT_SYMBOL(d_alloc_anon);
EXPORT_SYMBOL(d_alloc_root);
EXPORT_SYMBOL(d_delete);
EXPORT_SYMBOL(d_find_alias);