Commit 3bb3e1fc authored by Jan Kara's avatar Jan Kara
Browse files

reiserfs: Fix lock ordering during remount



When remounting reiserfs dquot_suspend() or dquot_resume() can be called.
These functions take dqonoff_mutex which ranks above write lock so we have
to drop it before calling into quota code.

CC: stable@vger.kernel.org # >= 3.0
Signed-off-by: default avatarJan Kara <jack@suse.cz>
parent 77b67063
Loading
Loading
Loading
Loading
+20 −7
Original line number Original line Diff line number Diff line
@@ -1335,7 +1335,7 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)
				kfree(qf_names[i]);
				kfree(qf_names[i]);
#endif
#endif
		err = -EINVAL;
		err = -EINVAL;
		goto out_err;
		goto out_unlock;
	}
	}
#ifdef CONFIG_QUOTA
#ifdef CONFIG_QUOTA
	handle_quota_files(s, qf_names, &qfmt);
	handle_quota_files(s, qf_names, &qfmt);
@@ -1379,7 +1379,7 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)
	if (blocks) {
	if (blocks) {
		err = reiserfs_resize(s, blocks);
		err = reiserfs_resize(s, blocks);
		if (err != 0)
		if (err != 0)
			goto out_err;
			goto out_unlock;
	}
	}


	if (*mount_flags & MS_RDONLY) {
	if (*mount_flags & MS_RDONLY) {
@@ -1389,9 +1389,15 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)
			/* it is read-only already */
			/* it is read-only already */
			goto out_ok;
			goto out_ok;


		/*
		 * Drop write lock. Quota will retake it when needed and lock
		 * ordering requires calling dquot_suspend() without it.
		 */
		reiserfs_write_unlock(s);
		err = dquot_suspend(s, -1);
		err = dquot_suspend(s, -1);
		if (err < 0)
		if (err < 0)
			goto out_err;
			goto out_err;
		reiserfs_write_lock(s);


		/* try to remount file system with read-only permissions */
		/* try to remount file system with read-only permissions */
		if (sb_umount_state(rs) == REISERFS_VALID_FS
		if (sb_umount_state(rs) == REISERFS_VALID_FS
@@ -1401,7 +1407,7 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)


		err = journal_begin(&th, s, 10);
		err = journal_begin(&th, s, 10);
		if (err)
		if (err)
			goto out_err;
			goto out_unlock;


		/* Mounting a rw partition read-only. */
		/* Mounting a rw partition read-only. */
		reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1);
		reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1);
@@ -1416,7 +1422,7 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)


		if (reiserfs_is_journal_aborted(journal)) {
		if (reiserfs_is_journal_aborted(journal)) {
			err = journal->j_errno;
			err = journal->j_errno;
			goto out_err;
			goto out_unlock;
		}
		}


		handle_data_mode(s, mount_options);
		handle_data_mode(s, mount_options);
@@ -1425,7 +1431,7 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)
		s->s_flags &= ~MS_RDONLY;	/* now it is safe to call journal_begin */
		s->s_flags &= ~MS_RDONLY;	/* now it is safe to call journal_begin */
		err = journal_begin(&th, s, 10);
		err = journal_begin(&th, s, 10);
		if (err)
		if (err)
			goto out_err;
			goto out_unlock;


		/* Mount a partition which is read-only, read-write */
		/* Mount a partition which is read-only, read-write */
		reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1);
		reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1);
@@ -1442,10 +1448,16 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)
	SB_JOURNAL(s)->j_must_wait = 1;
	SB_JOURNAL(s)->j_must_wait = 1;
	err = journal_end(&th, s, 10);
	err = journal_end(&th, s, 10);
	if (err)
	if (err)
		goto out_err;
		goto out_unlock;


	if (!(*mount_flags & MS_RDONLY)) {
	if (!(*mount_flags & MS_RDONLY)) {
		/*
		 * Drop write lock. Quota will retake it when needed and lock
		 * ordering requires calling dquot_resume() without it.
		 */
		reiserfs_write_unlock(s);
		dquot_resume(s, -1);
		dquot_resume(s, -1);
		reiserfs_write_lock(s);
		finish_unfinished(s);
		finish_unfinished(s);
		reiserfs_xattr_init(s, *mount_flags);
		reiserfs_xattr_init(s, *mount_flags);
	}
	}
@@ -1455,9 +1467,10 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)
	reiserfs_write_unlock(s);
	reiserfs_write_unlock(s);
	return 0;
	return 0;


out_unlock:
	reiserfs_write_unlock(s);
out_err:
out_err:
	kfree(new_opts);
	kfree(new_opts);
	reiserfs_write_unlock(s);
	return err;
	return err;
}
}