| From 08261673cb6dc638c39f44d69b76fffb57b92a8b Mon Sep 17 00:00:00 2001 |
| From: Andrew Perepechko <andrew.perepechko@sun.com> |
| Date: Mon, 12 Apr 2010 22:16:50 +0400 |
| Subject: quota: Fix possible dq_flags corruption |
| |
| From: Andrew Perepechko <andrew.perepechko@sun.com> |
| |
| commit 08261673cb6dc638c39f44d69b76fffb57b92a8b upstream. |
| |
| dq_flags are modified non-atomically in do_set_dqblk via __set_bit calls and |
| atomically for example in mark_dquot_dirty or clear_dquot_dirty. Hence a |
| change done by an atomic operation can be overwritten by a change done by a |
| non-atomic one. Fix the problem by using atomic bitops even in do_set_dqblk. |
| |
| Signed-off-by: Andrew Perepechko <andrew.perepechko@sun.com> |
| Signed-off-by: Jan Kara <jack@suse.cz> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| |
| --- |
| fs/quota/dquot.c | 12 ++++++------ |
| 1 file changed, 6 insertions(+), 6 deletions(-) |
| |
| --- a/fs/quota/dquot.c |
| +++ b/fs/quota/dquot.c |
| @@ -2389,34 +2389,34 @@ static int do_set_dqblk(struct dquot *dq |
| if (di->dqb_valid & QIF_SPACE) { |
| dm->dqb_curspace = di->dqb_curspace - dm->dqb_rsvspace; |
| check_blim = 1; |
| - __set_bit(DQ_LASTSET_B + QIF_SPACE_B, &dquot->dq_flags); |
| + set_bit(DQ_LASTSET_B + QIF_SPACE_B, &dquot->dq_flags); |
| } |
| if (di->dqb_valid & QIF_BLIMITS) { |
| dm->dqb_bsoftlimit = qbtos(di->dqb_bsoftlimit); |
| dm->dqb_bhardlimit = qbtos(di->dqb_bhardlimit); |
| check_blim = 1; |
| - __set_bit(DQ_LASTSET_B + QIF_BLIMITS_B, &dquot->dq_flags); |
| + set_bit(DQ_LASTSET_B + QIF_BLIMITS_B, &dquot->dq_flags); |
| } |
| if (di->dqb_valid & QIF_INODES) { |
| dm->dqb_curinodes = di->dqb_curinodes; |
| check_ilim = 1; |
| - __set_bit(DQ_LASTSET_B + QIF_INODES_B, &dquot->dq_flags); |
| + set_bit(DQ_LASTSET_B + QIF_INODES_B, &dquot->dq_flags); |
| } |
| if (di->dqb_valid & QIF_ILIMITS) { |
| dm->dqb_isoftlimit = di->dqb_isoftlimit; |
| dm->dqb_ihardlimit = di->dqb_ihardlimit; |
| check_ilim = 1; |
| - __set_bit(DQ_LASTSET_B + QIF_ILIMITS_B, &dquot->dq_flags); |
| + set_bit(DQ_LASTSET_B + QIF_ILIMITS_B, &dquot->dq_flags); |
| } |
| if (di->dqb_valid & QIF_BTIME) { |
| dm->dqb_btime = di->dqb_btime; |
| check_blim = 1; |
| - __set_bit(DQ_LASTSET_B + QIF_BTIME_B, &dquot->dq_flags); |
| + set_bit(DQ_LASTSET_B + QIF_BTIME_B, &dquot->dq_flags); |
| } |
| if (di->dqb_valid & QIF_ITIME) { |
| dm->dqb_itime = di->dqb_itime; |
| check_ilim = 1; |
| - __set_bit(DQ_LASTSET_B + QIF_ITIME_B, &dquot->dq_flags); |
| + set_bit(DQ_LASTSET_B + QIF_ITIME_B, &dquot->dq_flags); |
| } |
| |
| if (check_blim) { |