mirror of
https://github.com/torvalds/linux.git
synced 2026-03-08 04:04:43 +01:00
make it easier to catch those who try to modify ->d_name
Turn d_name into an anon union of const struct qstr d_name with struct qstr __d_name. Very few places need to modify it (all in fs/dcache.c); those are switched to use of ->__d_name. Note that ->d_name can actually change under you unless you have the right locking environment; this const just prohibits accidentally doing stores without being easily spotted. Reviewed-by: Christian Brauner <brauner@kernel.org> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
ca97d6c60b
commit
180a9cc3fd
2 changed files with 17 additions and 14 deletions
26
fs/dcache.c
26
fs/dcache.c
|
|
@ -1717,13 +1717,13 @@ static struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name)
|
|||
dname = dentry->d_shortname.string;
|
||||
}
|
||||
|
||||
dentry->d_name.len = name->len;
|
||||
dentry->d_name.hash = name->hash;
|
||||
dentry->__d_name.len = name->len;
|
||||
dentry->__d_name.hash = name->hash;
|
||||
memcpy(dname, name->name, name->len);
|
||||
dname[name->len] = 0;
|
||||
|
||||
/* Make sure we always see the terminating NUL character */
|
||||
smp_store_release(&dentry->d_name.name, dname); /* ^^^ */
|
||||
smp_store_release(&dentry->__d_name.name, dname); /* ^^^ */
|
||||
|
||||
dentry->d_flags = 0;
|
||||
lockref_init(&dentry->d_lockref);
|
||||
|
|
@ -2743,15 +2743,15 @@ static void swap_names(struct dentry *dentry, struct dentry *target)
|
|||
/*
|
||||
* Both external: swap the pointers
|
||||
*/
|
||||
swap(target->d_name.name, dentry->d_name.name);
|
||||
swap(target->__d_name.name, dentry->__d_name.name);
|
||||
} else {
|
||||
/*
|
||||
* dentry:internal, target:external. Steal target's
|
||||
* storage and make target internal.
|
||||
*/
|
||||
dentry->d_name.name = target->d_name.name;
|
||||
dentry->__d_name.name = target->__d_name.name;
|
||||
target->d_shortname = dentry->d_shortname;
|
||||
target->d_name.name = target->d_shortname.string;
|
||||
target->__d_name.name = target->d_shortname.string;
|
||||
}
|
||||
} else {
|
||||
if (unlikely(dname_external(dentry))) {
|
||||
|
|
@ -2759,9 +2759,9 @@ static void swap_names(struct dentry *dentry, struct dentry *target)
|
|||
* dentry:external, target:internal. Give dentry's
|
||||
* storage to target and make dentry internal
|
||||
*/
|
||||
target->d_name.name = dentry->d_name.name;
|
||||
target->__d_name.name = dentry->__d_name.name;
|
||||
dentry->d_shortname = target->d_shortname;
|
||||
dentry->d_name.name = dentry->d_shortname.string;
|
||||
dentry->__d_name.name = dentry->d_shortname.string;
|
||||
} else {
|
||||
/*
|
||||
* Both are internal.
|
||||
|
|
@ -2771,7 +2771,7 @@ static void swap_names(struct dentry *dentry, struct dentry *target)
|
|||
target->d_shortname.words[i]);
|
||||
}
|
||||
}
|
||||
swap(dentry->d_name.hash_len, target->d_name.hash_len);
|
||||
swap(dentry->__d_name.hash_len, target->__d_name.hash_len);
|
||||
}
|
||||
|
||||
static void copy_name(struct dentry *dentry, struct dentry *target)
|
||||
|
|
@ -2781,11 +2781,11 @@ static void copy_name(struct dentry *dentry, struct dentry *target)
|
|||
old_name = external_name(dentry);
|
||||
if (unlikely(dname_external(target))) {
|
||||
atomic_inc(&external_name(target)->count);
|
||||
dentry->d_name = target->d_name;
|
||||
dentry->__d_name = target->__d_name;
|
||||
} else {
|
||||
dentry->d_shortname = target->d_shortname;
|
||||
dentry->d_name.name = dentry->d_shortname.string;
|
||||
dentry->d_name.hash_len = target->d_name.hash_len;
|
||||
dentry->__d_name.name = dentry->d_shortname.string;
|
||||
dentry->__d_name.hash_len = target->__d_name.hash_len;
|
||||
}
|
||||
if (old_name && likely(atomic_dec_and_test(&old_name->count)))
|
||||
kfree_rcu(old_name, head);
|
||||
|
|
@ -3133,7 +3133,7 @@ void d_mark_tmpfile(struct file *file, struct inode *inode)
|
|||
!d_unlinked(dentry));
|
||||
spin_lock(&dentry->d_parent->d_lock);
|
||||
spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
|
||||
dentry->d_name.len = sprintf(dentry->d_shortname.string, "#%llu",
|
||||
dentry->__d_name.len = sprintf(dentry->d_shortname.string, "#%llu",
|
||||
(unsigned long long)inode->i_ino);
|
||||
spin_unlock(&dentry->d_lock);
|
||||
spin_unlock(&dentry->d_parent->d_lock);
|
||||
|
|
|
|||
|
|
@ -95,7 +95,10 @@ struct dentry {
|
|||
seqcount_spinlock_t d_seq; /* per dentry seqlock */
|
||||
struct hlist_bl_node d_hash; /* lookup hash list */
|
||||
struct dentry *d_parent; /* parent directory */
|
||||
struct qstr d_name;
|
||||
union {
|
||||
struct qstr __d_name; /* for use ONLY in fs/dcache.c */
|
||||
const struct qstr d_name;
|
||||
};
|
||||
struct inode *d_inode; /* Where the name belongs to - NULL is
|
||||
* negative */
|
||||
union shortname_store d_shortname;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue