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>
This commit is contained in:
Al Viro 2011-07-07 15:03:58 -04:00
parent e3c3d9c838
commit a4464dbc0c
3 changed files with 47 additions and 39 deletions

View file

@ -1275,8 +1275,8 @@ static struct shrinker dcache_shrinker = {
}; };
/** /**
* d_alloc - allocate a dcache entry * __d_alloc - allocate a dcache entry
* @parent: parent of entry to allocate * @sb: filesystem it will belong to
* @name: qstr of the name * @name: qstr of the name
* *
* Allocates a dentry. It returns %NULL if there is insufficient memory * 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. * 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; struct dentry *dentry;
char *dname; char *dname;
@ -1314,8 +1314,8 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name)
spin_lock_init(&dentry->d_lock); spin_lock_init(&dentry->d_lock);
seqcount_init(&dentry->d_seq); seqcount_init(&dentry->d_seq);
dentry->d_inode = NULL; dentry->d_inode = NULL;
dentry->d_parent = NULL; dentry->d_parent = dentry;
dentry->d_sb = NULL; dentry->d_sb = sb;
dentry->d_op = NULL; dentry->d_op = NULL;
dentry->d_fsdata = NULL; dentry->d_fsdata = NULL;
INIT_HLIST_BL_NODE(&dentry->d_hash); 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_subdirs);
INIT_LIST_HEAD(&dentry->d_alias); INIT_LIST_HEAD(&dentry->d_alias);
INIT_LIST_HEAD(&dentry->d_u.d_child); INIT_LIST_HEAD(&dentry->d_u.d_child);
d_set_d_op(dentry, dentry->d_sb->s_d_op);
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);
}
this_cpu_inc(nr_dentry); this_cpu_inc(nr_dentry);
return 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); EXPORT_SYMBOL(d_alloc);
struct dentry *d_alloc_pseudo(struct super_block *sb, const struct qstr *name) struct dentry *d_alloc_pseudo(struct super_block *sb, const struct qstr *name)
{ {
struct dentry *dentry = d_alloc(NULL, name); struct dentry *dentry = __d_alloc(sb, name);
if (dentry) { if (dentry)
dentry->d_sb = sb;
d_set_d_op(dentry, dentry->d_sb->s_d_op);
dentry->d_parent = dentry;
dentry->d_flags |= DCACHE_DISCONNECTED; dentry->d_flags |= DCACHE_DISCONNECTED;
}
return dentry; return dentry;
} }
EXPORT_SYMBOL(d_alloc_pseudo); EXPORT_SYMBOL(d_alloc_pseudo);
@ -1522,13 +1533,9 @@ struct dentry * d_alloc_root(struct inode * root_inode)
if (root_inode) { if (root_inode) {
static const struct qstr name = { .name = "/", .len = 1 }; static const struct qstr name = { .name = "/", .len = 1 };
res = d_alloc(NULL, &name); res = __d_alloc(root_inode->i_sb, &name);
if (res) { if (res)
res->d_sb = root_inode->i_sb;
d_set_d_op(res, res->d_sb->s_d_op);
res->d_parent = res;
d_instantiate(res, root_inode); d_instantiate(res, root_inode);
}
} }
return res; return res;
} }
@ -1589,13 +1596,11 @@ struct dentry *d_obtain_alias(struct inode *inode)
if (res) if (res)
goto out_iput; goto out_iput;
tmp = d_alloc(NULL, &anonstring); tmp = __d_alloc(inode->i_sb, &anonstring);
if (!tmp) { if (!tmp) {
res = ERR_PTR(-ENOMEM); res = ERR_PTR(-ENOMEM);
goto out_iput; goto out_iput;
} }
tmp->d_parent = tmp; /* make sure dput doesn't croak */
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
res = __d_find_any_alias(inode); res = __d_find_any_alias(inode);
@ -1607,8 +1612,6 @@ struct dentry *d_obtain_alias(struct inode *inode)
/* attach a disconnected dentry */ /* attach a disconnected dentry */
spin_lock(&tmp->d_lock); 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_inode = inode;
tmp->d_flags |= DCACHE_DISCONNECTED; tmp->d_flags |= DCACHE_DISCONNECTED;
list_add(&tmp->d_alias, &inode->i_dentry); list_add(&tmp->d_alias, &inode->i_dentry);

View file

@ -135,3 +135,8 @@ extern void inode_wb_list_del(struct inode *inode);
extern int get_nr_dirty_inodes(void); extern int get_nr_dirty_inodes(void);
extern void evict_inodes(struct super_block *); extern void evict_inodes(struct super_block *);
extern int invalidate_inodes(struct super_block *, bool); extern int invalidate_inodes(struct super_block *, bool);
/*
* dcache.c
*/
extern struct dentry *__d_alloc(struct super_block *, const struct qstr *);

View file

@ -16,6 +16,8 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include "internal.h"
static inline int simple_positive(struct dentry *dentry) static inline int simple_positive(struct dentry *dentry)
{ {
return dentry->d_inode && !d_unhashed(dentry); return dentry->d_inode && !d_unhashed(dentry);
@ -246,13 +248,11 @@ struct dentry *mount_pseudo(struct file_system_type *fs_type, char *name,
root->i_ino = 1; root->i_ino = 1;
root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR; root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR;
root->i_atime = root->i_mtime = root->i_ctime = CURRENT_TIME; root->i_atime = root->i_mtime = root->i_ctime = CURRENT_TIME;
dentry = d_alloc(NULL, &d_name); dentry = __d_alloc(s, &d_name);
if (!dentry) { if (!dentry) {
iput(root); iput(root);
goto Enomem; goto Enomem;
} }
dentry->d_sb = s;
dentry->d_parent = dentry;
d_instantiate(dentry, root); d_instantiate(dentry, root);
s->s_root = dentry; s->s_root = dentry;
s->s_d_op = dops; s->s_d_op = dops;