|
@@ -1110,70 +1110,6 @@ static inline struct hlist_head *d_hash(struct dentry *parent,
|
|
|
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
|
|
@@ -1194,19 +1130,50 @@ struct dentry * d_alloc_anon(struct inode *inode)
|
|
|
*/
|
|
|
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);
|
|
|
|
|
@@ -2379,7 +2346,6 @@ void __init vfs_caches_init(unsigned long mempages)
|
|
|
}
|
|
|
|
|
|
EXPORT_SYMBOL(d_alloc);
|
|
|
-EXPORT_SYMBOL(d_alloc_anon);
|
|
|
EXPORT_SYMBOL(d_alloc_root);
|
|
|
EXPORT_SYMBOL(d_delete);
|
|
|
EXPORT_SYMBOL(d_find_alias);
|