... is finally done.
->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.
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;
/*
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);
spin_unlock(&dcache_lock);
d_rehash(dentry);
}
- unlock_kernel();
} else
d_add(dentry, inode);
return new;
{
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;
void d_move(struct dentry * dentry, struct dentry * target)
{
- check_lock();
-
if (!dentry->d_inode)
printk(KERN_WARNING "VFS: moving negative dcache entry\n");
d_rehash(new_dentry);
dput(new_dentry);
}
- if (!error) {
- lock_kernel();
+ if (!error)
d_move(old_dentry,new_dentry);
- unlock_kernel();
- }
return error;
}
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);