Re: [Cluster-devel] [GFS2] gfs2: fix quota refresh race in do_glock()
Hi, That makes sense to me. Acked-by: Steven Whitehouse swhit...@redhat.com Steve. On 07/04/15 18:48, Abhi Das wrote: 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. Resolves: rhbz#1174295 Signed-off-by: Abhi Das a...@redhat.com --- fs/gfs2/quota.c | 8 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 5561468..5c27e48 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; }
Re: [Cluster-devel] [GFS2] gfs2: fix quota refresh race in do_glock()
- Original Message - 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. Resolves: rhbz#1174295 Signed-off-by: Abhi Das a...@redhat.com --- Hi, ACK I pushed this patch to the for-next branch of the linux-gfs2 tree. Regards, Bob Peterson Red Hat File Systems
[Cluster-devel] [GFS2] 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. Resolves: rhbz#1174295 Signed-off-by: Abhi Das a...@redhat.com --- fs/gfs2/quota.c | 8 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 5561468..5c27e48 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; } -- 1.8.1.4