diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2011-07-07 15:03:58 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2011-07-20 01:44:17 -0400 |
commit | a4464dbc0ca6a3ab8e9d1206bc05059dae2a559d (patch) | |
tree | d3c9332ab72cf5a4eba483ba1ff83c54ca4c42a0 /fs/dcache.c | |
parent | e3c3d9c838d48c0341c40ea45ee087e3d8c8ea39 (diff) | |
download | linux-a4464dbc0ca6a3ab8e9d1206bc05059dae2a559d.tar.gz linux-a4464dbc0ca6a3ab8e9d1206bc05059dae2a559d.tar.bz2 linux-a4464dbc0ca6a3ab8e9d1206bc05059dae2a559d.zip |
Make ->d_sb assign-once and always non-NULL
New helper (non-exported, fs/internal.h-only): __d_alloc(sb, name).
Allocates dentry, sets its ->d_sb to given superblock and sets
->d_op accordingly. Old d_alloc(NULL, name) callers are converted
to that (all of them know what superblock they want). d_alloc()
itself is left only for parent != NULl case; uses __d_alloc(),
inserts result into the list of parent's children.
Note that now ->d_sb is assign-once and never NULL *and*
->d_parent is never NULL either.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/dcache.c')
-rw-r--r-- | fs/dcache.c | 75 |
1 files changed, 39 insertions, 36 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index d3902139b533..c61edd0318c3 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -1275,8 +1275,8 @@ static struct shrinker dcache_shrinker = { }; /** - * d_alloc - allocate a dcache entry - * @parent: parent of entry to allocate + * __d_alloc - allocate a dcache entry + * @sb: filesystem it will belong to * @name: qstr of the name * * Allocates a dentry. It returns %NULL if there is insufficient memory @@ -1284,7 +1284,7 @@ static struct shrinker dcache_shrinker = { * copied and the copy passed in may be reused after this call. */ -struct dentry *d_alloc(struct dentry * parent, const struct qstr *name) +struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name) { struct dentry *dentry; char *dname; @@ -1314,8 +1314,8 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name) spin_lock_init(&dentry->d_lock); seqcount_init(&dentry->d_seq); dentry->d_inode = NULL; - dentry->d_parent = NULL; - dentry->d_sb = NULL; + dentry->d_parent = dentry; + dentry->d_sb = sb; dentry->d_op = NULL; dentry->d_fsdata = NULL; INIT_HLIST_BL_NODE(&dentry->d_hash); @@ -1323,36 +1323,47 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name) INIT_LIST_HEAD(&dentry->d_subdirs); INIT_LIST_HEAD(&dentry->d_alias); INIT_LIST_HEAD(&dentry->d_u.d_child); - - if (parent) { - spin_lock(&parent->d_lock); - /* - * don't need child lock because it is not subject - * to concurrency here - */ - __dget_dlock(parent); - dentry->d_parent = parent; - dentry->d_sb = parent->d_sb; - d_set_d_op(dentry, dentry->d_sb->s_d_op); - list_add(&dentry->d_u.d_child, &parent->d_subdirs); - spin_unlock(&parent->d_lock); - } + d_set_d_op(dentry, dentry->d_sb->s_d_op); this_cpu_inc(nr_dentry); return dentry; } + +/** + * d_alloc - allocate a dcache entry + * @parent: parent of entry to allocate + * @name: qstr of the name + * + * Allocates a dentry. It returns %NULL if there is insufficient memory + * available. On a success the dentry is returned. The name passed in is + * copied and the copy passed in may be reused after this call. + */ +struct dentry *d_alloc(struct dentry * parent, const struct qstr *name) +{ + struct dentry *dentry = __d_alloc(parent->d_sb, name); + if (!dentry) + return NULL; + + spin_lock(&parent->d_lock); + /* + * don't need child lock because it is not subject + * to concurrency here + */ + __dget_dlock(parent); + dentry->d_parent = parent; + list_add(&dentry->d_u.d_child, &parent->d_subdirs); + spin_unlock(&parent->d_lock); + + return dentry; +} EXPORT_SYMBOL(d_alloc); struct dentry *d_alloc_pseudo(struct super_block *sb, const struct qstr *name) { - struct dentry *dentry = d_alloc(NULL, name); - if (dentry) { - dentry->d_sb = sb; - d_set_d_op(dentry, dentry->d_sb->s_d_op); - dentry->d_parent = dentry; + struct dentry *dentry = __d_alloc(sb, name); + if (dentry) dentry->d_flags |= DCACHE_DISCONNECTED; - } return dentry; } EXPORT_SYMBOL(d_alloc_pseudo); @@ -1522,13 +1533,9 @@ struct dentry * d_alloc_root(struct inode * root_inode) if (root_inode) { static const struct qstr name = { .name = "/", .len = 1 }; - res = d_alloc(NULL, &name); - if (res) { - res->d_sb = root_inode->i_sb; - d_set_d_op(res, res->d_sb->s_d_op); - res->d_parent = res; + res = __d_alloc(root_inode->i_sb, &name); + if (res) d_instantiate(res, root_inode); - } } return res; } @@ -1589,13 +1596,11 @@ struct dentry *d_obtain_alias(struct inode *inode) if (res) goto out_iput; - tmp = d_alloc(NULL, &anonstring); + tmp = __d_alloc(inode->i_sb, &anonstring); if (!tmp) { res = ERR_PTR(-ENOMEM); goto out_iput; } - tmp->d_parent = tmp; /* make sure dput doesn't croak */ - spin_lock(&inode->i_lock); res = __d_find_any_alias(inode); @@ -1607,8 +1612,6 @@ struct dentry *d_obtain_alias(struct inode *inode) /* attach a disconnected dentry */ spin_lock(&tmp->d_lock); - tmp->d_sb = inode->i_sb; - d_set_d_op(tmp, tmp->d_sb->s_d_op); tmp->d_inode = inode; tmp->d_flags |= DCACHE_DISCONNECTED; list_add(&tmp->d_alias, &inode->i_dentry); |