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. ...@@ -198,3 +198,20 @@ e.g.
->revalidate() is gone. If your filesystem had it - provide ->getattr() ->revalidate() is gone. If your filesystem had it - provide ->getattr()
and let it call whatever you had as ->revlidate() + (for symlinks that and let it call whatever you had as ->revlidate() + (for symlinks that
had ->revalidate()) add calls in ->follow_link()/->readlink(). 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 @@ ...@@ -32,9 +32,6 @@
spinlock_t dcache_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; spinlock_t dcache_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
rwlock_t dparent_lock __cacheline_aligned_in_smp = RW_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; static kmem_cache_t *dentry_cache;
/* /*
...@@ -812,7 +809,6 @@ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry) ...@@ -812,7 +809,6 @@ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry)
struct dentry *new = NULL; struct dentry *new = NULL;
if (inode && S_ISDIR(inode->i_mode)) { if (inode && S_ISDIR(inode->i_mode)) {
lock_kernel(); /* for d_move */
spin_lock(&dcache_lock); spin_lock(&dcache_lock);
if (!list_empty(&inode->i_dentry)) { if (!list_empty(&inode->i_dentry)) {
new = list_entry(inode->i_dentry.next, struct dentry, d_alias); 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) ...@@ -828,7 +824,6 @@ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry)
spin_unlock(&dcache_lock); spin_unlock(&dcache_lock);
d_rehash(dentry); d_rehash(dentry);
} }
unlock_kernel();
} else } else
d_add(dentry, inode); d_add(dentry, inode);
return new; return new;
...@@ -1012,7 +1007,6 @@ static inline void switch_names(struct dentry * dentry, struct dentry * target) ...@@ -1012,7 +1007,6 @@ static inline void switch_names(struct dentry * dentry, struct dentry * target)
{ {
const unsigned char *old_name, *new_name; const unsigned char *old_name, *new_name;
check_lock();
memcpy(dentry->d_iname, target->d_iname, DNAME_INLINE_LEN); memcpy(dentry->d_iname, target->d_iname, DNAME_INLINE_LEN);
old_name = target->d_name.name; old_name = target->d_name.name;
new_name = dentry->d_name.name; new_name = dentry->d_name.name;
...@@ -1051,8 +1045,6 @@ static inline void switch_names(struct dentry * dentry, struct dentry * target) ...@@ -1051,8 +1045,6 @@ static inline void switch_names(struct dentry * dentry, struct dentry * target)
void d_move(struct dentry * dentry, struct dentry * target) void d_move(struct dentry * dentry, struct dentry * target)
{ {
check_lock();
if (!dentry->d_inode) if (!dentry->d_inode)
printk(KERN_WARNING "VFS: moving negative dcache entry\n"); 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, ...@@ -1866,11 +1866,8 @@ int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
d_rehash(new_dentry); d_rehash(new_dentry);
dput(new_dentry); dput(new_dentry);
} }
if (!error) { if (!error)
lock_kernel();
d_move(old_dentry,new_dentry); d_move(old_dentry,new_dentry);
unlock_kernel();
}
return error; return error;
} }
...@@ -1890,11 +1887,8 @@ int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry, ...@@ -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); error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
if (!error) { if (!error) {
/* The following d_move() should become unconditional */ /* The following d_move() should become unconditional */
if (!(old_dir->i_sb->s_type->fs_flags & FS_ODD_RENAME)) { if (!(old_dir->i_sb->s_type->fs_flags & FS_ODD_RENAME))
lock_kernel();
d_move(old_dentry, new_dentry); d_move(old_dentry, new_dentry);
unlock_kernel();
}
} }
if (target) if (target)
up(&target->i_sem); 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