Skip to content

Commit 46bf2e9

Browse files
author
Kent Overstreet
committed
bcachefs: Fix excess transaction restarts in __bchfs_fallocate()
drop_locks_do() should not be used in a fastpath without first trying the do in nonblocking mode - the unlock and relock will cause excessive transaction restarts and potentially livelocking with other threads that are contending for the same locks. Signed-off-by: Kent Overstreet <[email protected]>
1 parent 1a50390 commit 46bf2e9

File tree

4 files changed

+35
-16
lines changed

4 files changed

+35
-16
lines changed

fs/bcachefs/btree_iter.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -819,6 +819,11 @@ __bch2_btree_iter_peek_and_restart(struct btree_trans *trans,
819819
#define for_each_btree_key_continue_norestart(_iter, _flags, _k, _ret) \
820820
for_each_btree_key_upto_continue_norestart(_iter, SPOS_MAX, _flags, _k, _ret)
821821

822+
/*
823+
* This should not be used in a fastpath, without first trying _do in
824+
* nonblocking mode - it will cause excessive transaction restarts and
825+
* potentially livelocking:
826+
*/
822827
#define drop_locks_do(_trans, _do) \
823828
({ \
824829
bch2_trans_unlock(_trans); \

fs/bcachefs/fs-io-pagecache.c

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -309,39 +309,49 @@ void bch2_mark_pagecache_unallocated(struct bch_inode_info *inode,
309309
}
310310
}
311311

312-
void bch2_mark_pagecache_reserved(struct bch_inode_info *inode,
313-
u64 start, u64 end)
312+
int bch2_mark_pagecache_reserved(struct bch_inode_info *inode,
313+
u64 *start, u64 end,
314+
bool nonblocking)
314315
{
315316
struct bch_fs *c = inode->v.i_sb->s_fs_info;
316-
pgoff_t index = start >> PAGE_SECTORS_SHIFT;
317+
pgoff_t index = *start >> PAGE_SECTORS_SHIFT;
317318
pgoff_t end_index = (end - 1) >> PAGE_SECTORS_SHIFT;
318319
struct folio_batch fbatch;
319320
s64 i_sectors_delta = 0;
320-
unsigned i, j;
321+
int ret = 0;
321322

322-
if (end <= start)
323-
return;
323+
if (end <= *start)
324+
return 0;
324325

325326
folio_batch_init(&fbatch);
326327

327328
while (filemap_get_folios(inode->v.i_mapping,
328329
&index, end_index, &fbatch)) {
329-
for (i = 0; i < folio_batch_count(&fbatch); i++) {
330+
for (unsigned i = 0; i < folio_batch_count(&fbatch); i++) {
330331
struct folio *folio = fbatch.folios[i];
332+
333+
if (!nonblocking)
334+
folio_lock(folio);
335+
else if (!folio_trylock(folio)) {
336+
folio_batch_release(&fbatch);
337+
ret = -EAGAIN;
338+
break;
339+
}
340+
331341
u64 folio_start = folio_sector(folio);
332342
u64 folio_end = folio_end_sector(folio);
333-
unsigned folio_offset = max(start, folio_start) - folio_start;
334-
unsigned folio_len = min(end, folio_end) - folio_offset - folio_start;
335-
struct bch_folio *s;
336343

337344
BUG_ON(end <= folio_start);
338345

339-
folio_lock(folio);
340-
s = bch2_folio(folio);
346+
*start = min(end, folio_end);
341347

348+
struct bch_folio *s = bch2_folio(folio);
342349
if (s) {
350+
unsigned folio_offset = max(*start, folio_start) - folio_start;
351+
unsigned folio_len = min(end, folio_end) - folio_offset - folio_start;
352+
343353
spin_lock(&s->lock);
344-
for (j = folio_offset; j < folio_offset + folio_len; j++) {
354+
for (unsigned j = folio_offset; j < folio_offset + folio_len; j++) {
345355
i_sectors_delta -= s->s[j].state == SECTOR_dirty;
346356
bch2_folio_sector_set(folio, s, j,
347357
folio_sector_reserve(s->s[j].state));
@@ -356,6 +366,7 @@ void bch2_mark_pagecache_reserved(struct bch_inode_info *inode,
356366
}
357367

358368
bch2_i_sectors_acct(c, inode, NULL, i_sectors_delta);
369+
return ret;
359370
}
360371

361372
static inline unsigned sectors_to_reserve(struct bch_folio_sector *s,

fs/bcachefs/fs-io-pagecache.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ int bch2_folio_set(struct bch_fs *, subvol_inum, struct folio **, unsigned);
143143
void bch2_bio_page_state_set(struct bio *, struct bkey_s_c);
144144

145145
void bch2_mark_pagecache_unallocated(struct bch_inode_info *, u64, u64);
146-
void bch2_mark_pagecache_reserved(struct bch_inode_info *, u64, u64);
146+
int bch2_mark_pagecache_reserved(struct bch_inode_info *, u64 *, u64, bool);
147147

148148
int bch2_get_folio_disk_reservation(struct bch_fs *,
149149
struct bch_inode_info *,

fs/bcachefs/fs-io.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -675,8 +675,11 @@ static int __bchfs_fallocate(struct bch_inode_info *inode, int mode,
675675

676676
bch2_i_sectors_acct(c, inode, &quota_res, i_sectors_delta);
677677

678-
drop_locks_do(trans,
679-
(bch2_mark_pagecache_reserved(inode, hole_start, iter.pos.offset), 0));
678+
if (bch2_mark_pagecache_reserved(inode, &hole_start,
679+
iter.pos.offset, true))
680+
drop_locks_do(trans,
681+
bch2_mark_pagecache_reserved(inode, &hole_start,
682+
iter.pos.offset, false));
680683
bkey_err:
681684
bch2_quota_reservation_put(c, inode, &quota_res);
682685
if (bch2_err_matches(ret, BCH_ERR_transaction_restart))

0 commit comments

Comments
 (0)