Skip to content

Commit f4e4c4e

Browse files
author
Andreas Gruenbacher
committed
gfs2: fix address space truncation during withdraw
When a withdrawn filesystem's inodes are being evicted, the address spaces of those inodes still need to be truncated but we can no longer start new transactions. We still don't want gfs2_invalidate_folio() to race with gfs2_log_flush(), so take a read lock on sdp->sd_log_flush_lock in that case. (It may not be obvious, but gfs2_invalidate_folio() is a jdata-only address space operation.) Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
1 parent 7d2da6e commit f4e4c4e

2 files changed

Lines changed: 39 additions & 19 deletions

File tree

fs/gfs2/log.c

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1024,17 +1024,22 @@ void gfs2_remove_from_journal(struct buffer_head *bh, int meta)
10241024
trace_gfs2_pin(bd, 0);
10251025
atomic_dec(&sdp->sd_log_pinned);
10261026
list_del_init(&bd->bd_list);
1027-
if (meta == REMOVE_META)
1028-
tr->tr_num_buf_rm++;
1029-
else
1030-
tr->tr_num_databuf_rm++;
1031-
set_bit(TR_TOUCHED, &tr->tr_flags);
1027+
if (tr) {
1028+
if (meta == REMOVE_META)
1029+
tr->tr_num_buf_rm++;
1030+
else
1031+
tr->tr_num_databuf_rm++;
1032+
set_bit(TR_TOUCHED, &tr->tr_flags);
1033+
}
10321034
was_pinned = 1;
10331035
brelse(bh);
10341036
}
10351037
if (bd) {
10361038
if (bd->bd_tr) {
1037-
gfs2_trans_add_revoke(sdp, bd);
1039+
if (tr)
1040+
gfs2_trans_add_revoke(sdp, bd);
1041+
else
1042+
gfs2_remove_from_ail(bd);
10381043
} else if (was_pinned) {
10391044
bh->b_private = NULL;
10401045
kmem_cache_free(gfs2_bufdata_cachep, bd);

fs/gfs2/super.c

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1339,27 +1339,44 @@ static int gfs2_truncate_inode_pages(struct inode *inode)
13391339
struct gfs2_sbd *sdp = GFS2_SB(inode);
13401340
struct address_space *mapping = &inode->i_data;
13411341
bool need_trans = gfs2_is_jdata(ip) && mapping->nrpages;
1342-
int ret;
1342+
int ret = 0;
13431343

13441344
/*
13451345
* Truncating a jdata inode address space may create revokes in
13461346
* truncate_inode_pages() -> gfs2_invalidate_folio() -> ... ->
13471347
* gfs2_remove_from_journal(), so we need a transaction here.
13481348
*
1349-
* FIXME: During a withdraw, no new transactions can be created.
1350-
* In that case, we skip the truncate, but that doesn't help because
1351-
* truncate_inode_pages_final() will then call gfs2_invalidate_folio()
1352-
* again, and outside of a transaction.
1349+
* During a withdraw, no new transactions can be created. We still
1350+
* take the log flush lock to prevent truncate from racing with
1351+
* gfs2_log_flush().
13531352
*/
13541353
if (need_trans) {
13551354
ret = gfs2_trans_begin(sdp, 0, sdp->sd_jdesc->jd_blocks);
13561355
if (ret)
1357-
return ret;
1356+
down_read(&sdp->sd_log_flush_lock);
13581357
}
13591358
truncate_inode_pages(mapping, 0);
1360-
if (need_trans)
1361-
gfs2_trans_end(sdp);
1362-
return 0;
1359+
if (need_trans) {
1360+
if (ret)
1361+
up_read(&sdp->sd_log_flush_lock);
1362+
else
1363+
gfs2_trans_end(sdp);
1364+
}
1365+
return ret;
1366+
}
1367+
1368+
static void gfs2_truncate_inode_pages_final(struct inode *inode)
1369+
{
1370+
struct gfs2_inode *ip = GFS2_I(inode);
1371+
struct gfs2_sbd *sdp = GFS2_SB(inode);
1372+
struct address_space *mapping = &inode->i_data;
1373+
bool need_lock = gfs2_is_jdata(ip) && mapping->nrpages;
1374+
1375+
if (need_lock)
1376+
down_read(&sdp->sd_log_flush_lock);
1377+
truncate_inode_pages_final(mapping);
1378+
if (need_lock)
1379+
up_read(&sdp->sd_log_flush_lock);
13631380
}
13641381

13651382
/*
@@ -1398,10 +1415,8 @@ static int evict_linked_inode(struct inode *inode, struct gfs2_holder *gh)
13981415

13991416
clean:
14001417
ret = gfs2_truncate_inode_pages(inode);
1401-
if (ret)
1402-
return ret;
14031418
truncate_inode_pages(metamapping, 0);
1404-
return 0;
1419+
return ret;
14051420
}
14061421

14071422
/**
@@ -1472,7 +1487,7 @@ static void gfs2_evict_inode(struct inode *inode)
14721487
out:
14731488
if (gfs2_holder_initialized(&gh))
14741489
gfs2_glock_dq_uninit(&gh);
1475-
truncate_inode_pages_final(&inode->i_data);
1490+
gfs2_truncate_inode_pages_final(inode);
14761491
if (ip->i_qadata)
14771492
gfs2_assert_warn(sdp, ip->i_qadata->qa_ref == 0);
14781493
gfs2_rs_deltree(&ip->i_res);

0 commit comments

Comments
 (0)