Skip to content

Commit 66782b2

Browse files
author
Kent Overstreet
committed
bcachefs: Fix btree_path_get_locks when not doing trans restart
btree_path_get_locks, on failure, shouldn't unlock if we're not issuing a transaction restart: we might drop locks we're not supposed to (if path->should_be_locked is set). Signed-off-by: Kent Overstreet <[email protected]>
1 parent 5b7b342 commit 66782b2

File tree

3 files changed

+72
-51
lines changed

3 files changed

+72
-51
lines changed

fs/bcachefs/btree_iter.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1799,7 +1799,7 @@ btree_path_idx_t bch2_path_get(struct btree_trans *trans,
17991799

18001800
locks_want = min(locks_want, BTREE_MAX_DEPTH);
18011801
if (locks_want > path->locks_want)
1802-
bch2_btree_path_upgrade_noupgrade_sibs(trans, path, locks_want, NULL);
1802+
bch2_btree_path_upgrade_norestart(trans, path, locks_want);
18031803

18041804
return path_idx;
18051805
}

fs/bcachefs/btree_locking.c

Lines changed: 61 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -451,53 +451,63 @@ void bch2_btree_node_lock_write_nofail(struct btree_trans *trans,
451451

452452
/* relock */
453453

454-
static inline bool btree_path_get_locks(struct btree_trans *trans,
455-
struct btree_path *path,
456-
bool upgrade,
457-
struct get_locks_fail *f)
454+
static int btree_path_get_locks(struct btree_trans *trans,
455+
struct btree_path *path,
456+
bool upgrade,
457+
struct get_locks_fail *f,
458+
int restart_err)
458459
{
459460
unsigned l = path->level;
460-
int fail_idx = -1;
461461

462462
do {
463463
if (!btree_path_node(path, l))
464464
break;
465465

466466
if (!(upgrade
467467
? bch2_btree_node_upgrade(trans, path, l)
468-
: bch2_btree_node_relock(trans, path, l))) {
469-
fail_idx = l;
470-
471-
if (f) {
472-
f->l = l;
473-
f->b = path->l[l].b;
474-
}
475-
}
468+
: bch2_btree_node_relock(trans, path, l)))
469+
goto err;
476470

477471
l++;
478472
} while (l < path->locks_want);
479473

474+
if (path->uptodate == BTREE_ITER_NEED_RELOCK)
475+
path->uptodate = BTREE_ITER_UPTODATE;
476+
477+
return path->uptodate < BTREE_ITER_NEED_RELOCK ? 0 : -1;
478+
err:
479+
if (f) {
480+
f->l = l;
481+
f->b = path->l[l].b;
482+
}
483+
484+
/*
485+
* Do transaction restart before unlocking, so we don't pop
486+
* should_be_locked asserts
487+
*/
488+
if (restart_err) {
489+
btree_trans_restart(trans, restart_err);
490+
} else if (path->should_be_locked && !trans->restarted) {
491+
if (upgrade)
492+
path->locks_want = l;
493+
return -1;
494+
}
495+
496+
__bch2_btree_path_unlock(trans, path);
497+
btree_path_set_dirty(path, BTREE_ITER_NEED_TRAVERSE);
498+
480499
/*
481500
* When we fail to get a lock, we have to ensure that any child nodes
482501
* can't be relocked so bch2_btree_path_traverse has to walk back up to
483502
* the node that we failed to relock:
484503
*/
485-
if (fail_idx >= 0) {
486-
__bch2_btree_path_unlock(trans, path);
487-
btree_path_set_dirty(path, BTREE_ITER_NEED_TRAVERSE);
488-
489-
do {
490-
path->l[fail_idx].b = upgrade
491-
? ERR_PTR(-BCH_ERR_no_btree_node_upgrade)
492-
: ERR_PTR(-BCH_ERR_no_btree_node_relock);
493-
--fail_idx;
494-
} while (fail_idx >= 0);
495-
}
496-
497-
if (path->uptodate == BTREE_ITER_NEED_RELOCK)
498-
path->uptodate = BTREE_ITER_UPTODATE;
504+
do {
505+
path->l[l].b = upgrade
506+
? ERR_PTR(-BCH_ERR_no_btree_node_upgrade)
507+
: ERR_PTR(-BCH_ERR_no_btree_node_relock);
508+
} while (l--);
499509

500-
return path->uptodate < BTREE_ITER_NEED_RELOCK;
510+
return -restart_err ?: -1;
501511
}
502512

503513
bool __bch2_btree_node_relock(struct btree_trans *trans,
@@ -596,9 +606,7 @@ int bch2_btree_path_relock_intent(struct btree_trans *trans,
596606
__flatten
597607
bool bch2_btree_path_relock_norestart(struct btree_trans *trans, struct btree_path *path)
598608
{
599-
struct get_locks_fail f;
600-
601-
bool ret = btree_path_get_locks(trans, path, false, &f);
609+
bool ret = !btree_path_get_locks(trans, path, false, NULL, 0);
602610
bch2_trans_verify_locks(trans);
603611
return ret;
604612
}
@@ -614,28 +622,32 @@ int __bch2_btree_path_relock(struct btree_trans *trans,
614622
return 0;
615623
}
616624

617-
bool bch2_btree_path_upgrade_noupgrade_sibs(struct btree_trans *trans,
618-
struct btree_path *path,
619-
unsigned new_locks_want,
620-
struct get_locks_fail *f)
625+
bool __bch2_btree_path_upgrade_norestart(struct btree_trans *trans,
626+
struct btree_path *path,
627+
unsigned new_locks_want)
621628
{
622-
path->locks_want = max_t(unsigned, path->locks_want, new_locks_want);
629+
path->locks_want = new_locks_want;
623630

624-
bool ret = btree_path_get_locks(trans, path, true, f);
625-
bch2_trans_verify_locks(trans);
631+
struct get_locks_fail f = {};
632+
bool ret = !btree_path_get_locks(trans, path, true, &f, 0);
633+
634+
bch2_btree_path_verify_locks(path);
626635
return ret;
627636
}
628637

629638
int __bch2_btree_path_upgrade(struct btree_trans *trans,
630639
struct btree_path *path,
631640
unsigned new_locks_want)
632641
{
633-
struct get_locks_fail f = {};
634642
unsigned old_locks = path->nodes_locked;
635643
unsigned old_locks_want = path->locks_want;
636-
int ret = 0;
637644

638-
if (bch2_btree_path_upgrade_noupgrade_sibs(trans, path, new_locks_want, &f))
645+
path->locks_want = max_t(unsigned, path->locks_want, new_locks_want);
646+
647+
struct get_locks_fail f = {};
648+
int ret = btree_path_get_locks(trans, path, true, &f,
649+
BCH_ERR_transaction_restart_upgrade);
650+
if (!ret)
639651
goto out;
640652

641653
/*
@@ -667,7 +679,7 @@ int __bch2_btree_path_upgrade(struct btree_trans *trans,
667679
linked->btree_id == path->btree_id &&
668680
linked->locks_want < new_locks_want) {
669681
linked->locks_want = new_locks_want;
670-
btree_path_get_locks(trans, linked, true, NULL);
682+
btree_path_get_locks(trans, linked, true, NULL, 0);
671683
}
672684
}
673685

@@ -691,7 +703,6 @@ int __bch2_btree_path_upgrade(struct btree_trans *trans,
691703
trace_trans_restart_upgrade(trans->c, buf.buf);
692704
printbuf_exit(&buf);
693705
}
694-
ret = btree_trans_restart(trans, BCH_ERR_transaction_restart_upgrade);
695706
out:
696707
bch2_trans_verify_locks(trans);
697708
return ret;
@@ -752,7 +763,7 @@ static inline void __bch2_trans_unlock(struct btree_trans *trans)
752763
__bch2_btree_path_unlock(trans, path);
753764
}
754765

755-
static noinline __cold int bch2_trans_relock_fail(struct btree_trans *trans, struct btree_path *path,
766+
static noinline __cold void bch2_trans_relock_fail(struct btree_trans *trans, struct btree_path *path,
756767
struct get_locks_fail *f, bool trace)
757768
{
758769
if (!trace)
@@ -786,7 +797,6 @@ static noinline __cold int bch2_trans_relock_fail(struct btree_trans *trans, str
786797
out:
787798
__bch2_trans_unlock(trans);
788799
bch2_trans_verify_locks(trans);
789-
return btree_trans_restart(trans, BCH_ERR_transaction_restart_relock);
790800
}
791801

792802
static inline int __bch2_trans_relock(struct btree_trans *trans, bool trace)
@@ -803,10 +813,14 @@ static inline int __bch2_trans_relock(struct btree_trans *trans, bool trace)
803813

804814
trans_for_each_path(trans, path, i) {
805815
struct get_locks_fail f;
816+
int ret;
806817

807818
if (path->should_be_locked &&
808-
!btree_path_get_locks(trans, path, false, &f))
809-
return bch2_trans_relock_fail(trans, path, &f, trace);
819+
(ret = btree_path_get_locks(trans, path, false, &f,
820+
BCH_ERR_transaction_restart_relock))) {
821+
bch2_trans_relock_fail(trans, path, &f, trace);
822+
return ret;
823+
}
810824
}
811825

812826
trans_set_locked(trans, true);

fs/bcachefs/btree_locking.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -385,9 +385,16 @@ static inline bool bch2_btree_node_relock_notrace(struct btree_trans *trans,
385385

386386
/* upgrade */
387387

388-
bool bch2_btree_path_upgrade_noupgrade_sibs(struct btree_trans *,
389-
struct btree_path *, unsigned,
390-
struct get_locks_fail *);
388+
bool __bch2_btree_path_upgrade_norestart(struct btree_trans *, struct btree_path *, unsigned);
389+
390+
static inline bool bch2_btree_path_upgrade_norestart(struct btree_trans *trans,
391+
struct btree_path *path,
392+
unsigned new_locks_want)
393+
{
394+
return new_locks_want > path->locks_want
395+
? __bch2_btree_path_upgrade_norestart(trans, path, new_locks_want)
396+
: true;
397+
}
391398

392399
int __bch2_btree_path_upgrade(struct btree_trans *,
393400
struct btree_path *, unsigned);

0 commit comments

Comments
 (0)