Commit a4464dbc authored by Al Viro's avatar Al Viro
Browse files

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: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent e3c3d9c8
Loading
Loading
Loading
Loading
+39 −36
Original line number Diff line number Diff line
@@ -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,8 +1323,28 @@ 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);
	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;

	if (parent) {
	spin_lock(&parent->d_lock);
	/*
	 * don't need child lock because it is not subject
@@ -1332,13 +1352,8 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name)
	 */
	__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);

	return dentry;
}
@@ -1346,13 +1361,9 @@ 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,14 +1533,10 @@ 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;
}
EXPORT_SYMBOL(d_alloc_root);
@@ -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);
+5 −0
Original line number Diff line number Diff line
@@ -135,3 +135,8 @@ extern void inode_wb_list_del(struct inode *inode);
extern int get_nr_dirty_inodes(void);
extern void evict_inodes(struct super_block *);
extern int invalidate_inodes(struct super_block *, bool);

/*
 * dcache.c
 */
extern struct dentry *__d_alloc(struct super_block *, const struct qstr *);
+3 −3
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

#include <asm/uaccess.h>

#include "internal.h"

static inline int simple_positive(struct dentry *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_mode = S_IFDIR | S_IRUSR | S_IWUSR;
	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) {
		iput(root);
		goto Enomem;
	}
	dentry->d_sb = s;
	dentry->d_parent = dentry;
	d_instantiate(dentry, root);
	s->s_root = dentry;
	s->s_d_op = dops;