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);
}
EXPORT_SYMBOL(d_alloc);
-EXPORT_SYMBOL(d_alloc_anon);
EXPORT_SYMBOL(d_alloc_root);
EXPORT_SYMBOL(d_delete);
EXPORT_SYMBOL(d_find_alias);