Commit 726761cc authored by Alexander Viro's avatar Alexander Viro Committed by Linus Torvalds

[PATCH] (4/) BKL removal in d_move()

	... is finally done.
parent c7dbd2e1
......@@ -198,3 +198,20 @@ e.g.
->revalidate() is gone. If your filesystem had it - provide ->getattr()
and let it call whatever you had as ->revlidate() + (for symlinks that
had ->revalidate()) add calls in ->follow_link()/->readlink().
---
[mandatory]
->d_parent changes are not protected by BKL anymore. Read access is safe
if at least one of the following is true:
* filesystem has no cross-directory rename()
* dcache_lock is held
* dparent_lock is held (shared)
* we know that parent had been locked (e.g. we are looking at
->d_parent of ->lookup() argument).
* we are called from ->rename().
Audit your code and add locking if needed. Notice that any place that is
not protected by the conditions above is risky even in the old tree - you
had been relying on BKL and that's prone to screwups. Old tree had quite
a few holes of that kind - unprotected access to ->d_parent leading to
anything from oops to silent memory corruption.
......@@ -32,9 +32,6 @@
spinlock_t dcache_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
rwlock_t dparent_lock __cacheline_aligned_in_smp = RW_LOCK_UNLOCKED;
/* Right now the dcache depends on the kernel lock */
#define check_lock() if (!kernel_locked()) BUG()
static kmem_cache_t *dentry_cache;
/*
......@@ -812,7 +809,6 @@ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry)
struct dentry *new = NULL;
if (inode && S_ISDIR(inode->i_mode)) {
lock_kernel(); /* for d_move */
spin_lock(&dcache_lock);
if (!list_empty(&inode->i_dentry)) {
new = list_entry(inode->i_dentry.next, struct dentry, d_alias);
......@@ -828,7 +824,6 @@ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry)
spin_unlock(&dcache_lock);
d_rehash(dentry);
}
unlock_kernel();
} else
d_add(dentry, inode);
return new;
......@@ -1012,7 +1007,6 @@ static inline void switch_names(struct dentry * dentry, struct dentry * target)
{
const unsigned char *old_name, *new_name;
check_lock();
memcpy(dentry->d_iname, target->d_iname, DNAME_INLINE_LEN);
old_name = target->d_name.name;
new_name = dentry->d_name.name;
......@@ -1051,8 +1045,6 @@ static inline void switch_names(struct dentry * dentry, struct dentry * target)
void d_move(struct dentry * dentry, struct dentry * target)
{
check_lock();
if (!dentry->d_inode)
printk(KERN_WARNING "VFS: moving negative dcache entry\n");
......
......@@ -1866,11 +1866,8 @@ int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
d_rehash(new_dentry);
dput(new_dentry);
}
if (!error) {
lock_kernel();
if (!error)
d_move(old_dentry,new_dentry);
unlock_kernel();
}
return error;
}
......@@ -1890,11 +1887,8 @@ int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry,
error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
if (!error) {
/* The following d_move() should become unconditional */
if (!(old_dir->i_sb->s_type->fs_flags & FS_ODD_RENAME)) {
lock_kernel();
if (!(old_dir->i_sb->s_type->fs_flags & FS_ODD_RENAME))
d_move(old_dentry, new_dentry);
unlock_kernel();
}
}
if (target)
up(&target->i_sem);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment