Skip to content

Commit de0d95c

Browse files
author
Andreas Gruenbacher
committed
gfs2: Check quota consistency on mount
In gfs2_quota_init(), make sure that the per-node "quota_change%u" file doesn't contain duplicate uids/gids. Those duplicates would cause us to acquire the glock corresponding to those ids repeatedly, which the glock code doesn't allow. When finding inconsistencies, we wipe them out and ignore them. The resulting quotas will likely be inconsistent, and running quotacheck(1) is advised. Signed-off-by: Andreas Gruenbacher <[email protected]>
1 parent 5131652 commit de0d95c

File tree

1 file changed

+31
-6
lines changed

1 file changed

+31
-6
lines changed

fs/gfs2/quota.c

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1427,7 +1427,7 @@ int gfs2_quota_init(struct gfs2_sbd *sdp)
14271427
return error;
14281428

14291429
for (x = 0; x < blocks; x++) {
1430-
const struct gfs2_quota_change *qc;
1430+
struct gfs2_quota_change *qc;
14311431
unsigned int y;
14321432

14331433
if (!extlen) {
@@ -1443,10 +1443,10 @@ int gfs2_quota_init(struct gfs2_sbd *sdp)
14431443
if (gfs2_metatype_check(sdp, bh, GFS2_METATYPE_QC))
14441444
goto fail_brelse;
14451445

1446-
qc = (const struct gfs2_quota_change *)(bh->b_data + sizeof(struct gfs2_meta_header));
1446+
qc = (struct gfs2_quota_change *)(bh->b_data + sizeof(struct gfs2_meta_header));
14471447
for (y = 0; y < sdp->sd_qc_per_block && slot < sdp->sd_quota_slots;
14481448
y++, slot++) {
1449-
struct gfs2_quota_data *qd;
1449+
struct gfs2_quota_data *old_qd, *qd;
14501450
s64 qc_change = be64_to_cpu(qc->qc_change);
14511451
u32 qc_flags = be32_to_cpu(qc->qc_flags);
14521452
enum quota_type qtype = (qc_flags & GFS2_QCF_USER) ?
@@ -1468,18 +1468,41 @@ int gfs2_quota_init(struct gfs2_sbd *sdp)
14681468
qd->qd_slot_ref = 1;
14691469

14701470
spin_lock(&qd_lock);
1471+
spin_lock_bucket(hash);
1472+
old_qd = gfs2_qd_search_bucket(hash, sdp, qc_id);
1473+
if (old_qd) {
1474+
fs_err(sdp, "Corruption found in quota_change%u"
1475+
"file: duplicate identifier in "
1476+
"slot %u\n",
1477+
sdp->sd_jdesc->jd_jid, slot);
1478+
1479+
spin_unlock_bucket(hash);
1480+
spin_unlock(&qd_lock);
1481+
qd_put(old_qd);
1482+
1483+
gfs2_glock_put(qd->qd_gl);
1484+
kmem_cache_free(gfs2_quotad_cachep, qd);
1485+
1486+
/* zero out the duplicate slot */
1487+
lock_buffer(bh);
1488+
memset(qc, 0, sizeof(*qc));
1489+
mark_buffer_dirty(bh);
1490+
unlock_buffer(bh);
1491+
1492+
continue;
1493+
}
14711494
BUG_ON(test_and_set_bit(slot, sdp->sd_quota_bitmap));
14721495
list_add(&qd->qd_list, &sdp->sd_quota_list);
14731496
atomic_inc(&sdp->sd_quota_count);
1474-
spin_unlock(&qd_lock);
1475-
1476-
spin_lock_bucket(hash);
14771497
hlist_bl_add_head_rcu(&qd->qd_hlist, &qd_hash_table[hash]);
14781498
spin_unlock_bucket(hash);
1499+
spin_unlock(&qd_lock);
14791500

14801501
found++;
14811502
}
14821503

1504+
if (buffer_dirty(bh))
1505+
sync_dirty_buffer(bh);
14831506
brelse(bh);
14841507
dblock++;
14851508
extlen--;
@@ -1491,6 +1514,8 @@ int gfs2_quota_init(struct gfs2_sbd *sdp)
14911514
return 0;
14921515

14931516
fail_brelse:
1517+
if (buffer_dirty(bh))
1518+
sync_dirty_buffer(bh);
14941519
brelse(bh);
14951520
fail:
14961521
gfs2_quota_cleanup(sdp);

0 commit comments

Comments
 (0)