Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f1a96220 authored by Oleg Nesterov's avatar Oleg Nesterov Committed by Al Viro
Browse files

fs/super.c: don't fool lockdep in freeze_super() and thaw_super() paths



sb_wait_write()->percpu_rwsem_release() fools lockdep to avoid the
false-positives. Now that xfs was fixed by Dave's commit dbad7c99
("xfs: stop holding ILOCK over filldir callbacks") we can remove it and
change freeze_super() and thaw_super() to run with s_writers.rw_sem locks
held; we add two trivial helpers for that, lockdep_sb_freeze_release()
and lockdep_sb_freeze_acquire().

xfstests-dev/check `grep -il freeze tests/*/???` does not trigger any
warning from lockdep.

Signed-off-by: default avatarOleg Nesterov <oleg@redhat.com>
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 89f39af1
Loading
Loading
Loading
Loading
+25 −12
Original line number Original line Diff line number Diff line
@@ -1269,25 +1269,34 @@ EXPORT_SYMBOL(__sb_start_write);
static void sb_wait_write(struct super_block *sb, int level)
static void sb_wait_write(struct super_block *sb, int level)
{
{
	percpu_down_write(sb->s_writers.rw_sem + level-1);
	percpu_down_write(sb->s_writers.rw_sem + level-1);
}

/*
/*
	 * We are going to return to userspace and forget about this lock, the
 * We are going to return to userspace and forget about these locks, the
	 * ownership goes to the caller of thaw_super() which does unlock.
 * ownership goes to the caller of thaw_super() which does unlock().
	 *
	 * FIXME: we should do this before return from freeze_super() after we
	 * called sync_filesystem(sb) and s_op->freeze_fs(sb), and thaw_super()
	 * should re-acquire these locks before s_op->unfreeze_fs(sb). However
	 * this leads to lockdep false-positives, so currently we do the early
	 * release right after acquire.
 */
 */
	percpu_rwsem_release(sb->s_writers.rw_sem + level-1, 0, _THIS_IP_);
static void lockdep_sb_freeze_release(struct super_block *sb)
{
	int level;

	for (level = SB_FREEZE_LEVELS - 1; level >= 0; level--)
		percpu_rwsem_release(sb->s_writers.rw_sem + level, 0, _THIS_IP_);
}
}


static void sb_freeze_unlock(struct super_block *sb)
/*
 * Tell lockdep we are holding these locks before we call ->unfreeze_fs(sb).
 */
static void lockdep_sb_freeze_acquire(struct super_block *sb)
{
{
	int level;
	int level;


	for (level = 0; level < SB_FREEZE_LEVELS; ++level)
	for (level = 0; level < SB_FREEZE_LEVELS; ++level)
		percpu_rwsem_acquire(sb->s_writers.rw_sem + level, 0, _THIS_IP_);
		percpu_rwsem_acquire(sb->s_writers.rw_sem + level, 0, _THIS_IP_);
}

static void sb_freeze_unlock(struct super_block *sb)
{
	int level;


	for (level = SB_FREEZE_LEVELS - 1; level >= 0; level--)
	for (level = SB_FREEZE_LEVELS - 1; level >= 0; level--)
		percpu_up_write(sb->s_writers.rw_sem + level);
		percpu_up_write(sb->s_writers.rw_sem + level);
@@ -1383,6 +1392,7 @@ int freeze_super(struct super_block *sb)
	 * when frozen is set to SB_FREEZE_COMPLETE, and for thaw_super().
	 * when frozen is set to SB_FREEZE_COMPLETE, and for thaw_super().
	 */
	 */
	sb->s_writers.frozen = SB_FREEZE_COMPLETE;
	sb->s_writers.frozen = SB_FREEZE_COMPLETE;
	lockdep_sb_freeze_release(sb);
	up_write(&sb->s_umount);
	up_write(&sb->s_umount);
	return 0;
	return 0;
}
}
@@ -1409,11 +1419,14 @@ int thaw_super(struct super_block *sb)
		goto out;
		goto out;
	}
	}


	lockdep_sb_freeze_acquire(sb);

	if (sb->s_op->unfreeze_fs) {
	if (sb->s_op->unfreeze_fs) {
		error = sb->s_op->unfreeze_fs(sb);
		error = sb->s_op->unfreeze_fs(sb);
		if (error) {
		if (error) {
			printk(KERN_ERR
			printk(KERN_ERR
				"VFS:Filesystem thaw failed\n");
				"VFS:Filesystem thaw failed\n");
			lockdep_sb_freeze_release(sb);
			up_write(&sb->s_umount);
			up_write(&sb->s_umount);
			return error;
			return error;
		}
		}