reiserfs: Protect dquot_writeback_dquots() by s_umount semaphore
dquot_writeback_dquots() expects s_umount semaphore to be held to
protect it from other concurrent quota operations. reiserfs_sync_fs()
can call dquot_writeback_dquots() without holding s_umount semaphore
when called from flush_old_commits().
Fix the problem by grabbing s_umount in flush_old_commits(). However we
have to be careful and use only trylock since reiserfs_cancel_old_sync()
can be waiting for flush_old_commits() to complete while holding
s_umount semaphore. Possible postponing of sync work is not a big deal
though as that is only an opportunistic flush.
Fixes: 9d1ccbe70e
Reported-by: Jan Beulich <jbeulich@suse.com>
Signed-off-by: Jan Kara <jack@suse.cz>
This commit is contained in:
parent
71b0576bdb
commit
1e0e653f11
1 changed files with 14 additions and 0 deletions
|
@ -89,6 +89,19 @@ static void flush_old_commits(struct work_struct *work)
|
||||||
sbi = container_of(work, struct reiserfs_sb_info, old_work.work);
|
sbi = container_of(work, struct reiserfs_sb_info, old_work.work);
|
||||||
s = sbi->s_journal->j_work_sb;
|
s = sbi->s_journal->j_work_sb;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We need s_umount for protecting quota writeback. We have to use
|
||||||
|
* trylock as reiserfs_cancel_old_flush() may be waiting for this work
|
||||||
|
* to complete with s_umount held.
|
||||||
|
*/
|
||||||
|
if (!down_read_trylock(&s->s_umount)) {
|
||||||
|
/* Requeue work if we are not cancelling it */
|
||||||
|
spin_lock(&sbi->old_work_lock);
|
||||||
|
if (sbi->work_queued == 1)
|
||||||
|
queue_delayed_work(system_long_wq, &sbi->old_work, HZ);
|
||||||
|
spin_unlock(&sbi->old_work_lock);
|
||||||
|
return;
|
||||||
|
}
|
||||||
spin_lock(&sbi->old_work_lock);
|
spin_lock(&sbi->old_work_lock);
|
||||||
/* Avoid clobbering the cancel state... */
|
/* Avoid clobbering the cancel state... */
|
||||||
if (sbi->work_queued == 1)
|
if (sbi->work_queued == 1)
|
||||||
|
@ -96,6 +109,7 @@ static void flush_old_commits(struct work_struct *work)
|
||||||
spin_unlock(&sbi->old_work_lock);
|
spin_unlock(&sbi->old_work_lock);
|
||||||
|
|
||||||
reiserfs_sync_fs(s, 1);
|
reiserfs_sync_fs(s, 1);
|
||||||
|
up_read(&s->s_umount);
|
||||||
}
|
}
|
||||||
|
|
||||||
void reiserfs_schedule_old_flush(struct super_block *s)
|
void reiserfs_schedule_old_flush(struct super_block *s)
|
||||||
|
|
Loading…
Reference in a new issue