diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/dcache.c | 108 |
1 files changed, 37 insertions, 71 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index d45ff7f5ecc..1710d2484fd 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -1111,70 +1111,6 @@ static inline struct hlist_head *d_hash(struct dentry *parent, } /** - * 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); |