Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

quota: fix livelock in dquot_writeback_dquots

Write only quotas which are dirty at entry.

XFSTEST: https://github.com/dmonakhov/xfstests/commit/b10ad23566a5bf75832a6f500e1236084083cddc

Link: https://lore.kernel.org/r/20191031103920.3919-1-dmonakhov@openvz.org
CC: stable@vger.kernel.org
Signed-off-by: Konstantin Khlebnikov <khlebnikov@yandex-team.ru>
Signed-off-by: Dmitry Monakhov <dmtrmonakhov@yandex-team.ru>
Signed-off-by: Jan Kara <jack@suse.cz>

authored by

Dmitry Monakhov and committed by
Jan Kara
6ff33d99 30ef0e40

+5 -4
+5 -4
fs/quota/dquot.c
··· 622 622 /* Write all dquot structures to quota files */ 623 623 int dquot_writeback_dquots(struct super_block *sb, int type) 624 624 { 625 - struct list_head *dirty; 625 + struct list_head dirty; 626 626 struct dquot *dquot; 627 627 struct quota_info *dqopt = sb_dqopt(sb); 628 628 int cnt; ··· 636 636 if (!sb_has_quota_active(sb, cnt)) 637 637 continue; 638 638 spin_lock(&dq_list_lock); 639 - dirty = &dqopt->info[cnt].dqi_dirty_list; 640 - while (!list_empty(dirty)) { 641 - dquot = list_first_entry(dirty, struct dquot, 639 + /* Move list away to avoid livelock. */ 640 + list_replace_init(&dqopt->info[cnt].dqi_dirty_list, &dirty); 641 + while (!list_empty(&dirty)) { 642 + dquot = list_first_entry(&dirty, struct dquot, 642 643 dq_dirty); 643 644 644 645 WARN_ON(!test_bit(DQ_ACTIVE_B, &dquot->dq_flags));