From: Abhi Das Date: Wed, 8 Apr 2015 14:03:56 +0000 (-0500) Subject: gfs2: fix quota refresh race in do_glock() X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=30133177957dca9a3e2a37b720f891d3225a92a1;p=GitHub%2Fmoto-9609%2Fandroid_kernel_motorola_exynos9610.git gfs2: fix quota refresh race in do_glock() quotad periodically syncs in-memory quotas to the ondisk quota file and sets the QDF_REFRESH flag so that a subsequent read of a synced quota is re-read from disk. gfs2_quota_lock() checks for this flag and sets a 'force' bit to force re-read from disk if requested. However, there is a race condition here. It is possible for gfs2_quota_lock() to find the QDF_REFRESH flag unset (i.e force=0) and quotad comes in immediately after and syncs the relevant quota and sets the QDF_REFRESH flag. gfs2_quota_lock() resumes with force=0 and uses the stale in-memory quota usage values that result in miscalculations. This patch fixes this race by moving the check for the QDF_REFRESH flag check further out into the gfs2_quota_lock() process, i.e, in do_glock(), under the protection of the quota glock. Signed-off-by: Abhi Das Signed-off-by: Bob Peterson Acked-by: Steven Whitehouse --- diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 55614685a31c..5c27e48aa76f 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -923,6 +923,9 @@ restart: if (error) return error; + if (test_and_clear_bit(QDF_REFRESH, &qd->qd_flags)) + force_refresh = FORCE; + qd->qd_qb = *(struct gfs2_quota_lvb *)qd->qd_gl->gl_lksb.sb_lvbptr; if (force_refresh || qd->qd_qb.qb_magic != cpu_to_be32(GFS2_MAGIC)) { @@ -974,11 +977,8 @@ int gfs2_quota_lock(struct gfs2_inode *ip, kuid_t uid, kgid_t gid) sizeof(struct gfs2_quota_data *), sort_qd, NULL); for (x = 0; x < ip->i_res->rs_qa_qd_num; x++) { - int force = NO_FORCE; qd = ip->i_res->rs_qa_qd[x]; - if (test_and_clear_bit(QDF_REFRESH, &qd->qd_flags)) - force = FORCE; - error = do_glock(qd, force, &ip->i_res->rs_qa_qd_ghs[x]); + error = do_glock(qd, NO_FORCE, &ip->i_res->rs_qa_qd_ghs[x]); if (error) break; }