unsigned, unsigned, unsigned, unsigned long);
struct bkey_s_c bch2_btree_path_peek_slot(struct btree_path *, struct bkey *);
+/*
+ * bch2_btree_path_peek_slot() for a cached iterator might return a key in a
+ * different snapshot:
+ */
+static inline struct bkey_s_c bch2_btree_path_peek_slot_exact(struct btree_path *path, struct bkey *u)
+{
+ struct bkey_s_c k = bch2_btree_path_peek_slot(path, u);
+
+ if (k.k && bpos_eq(path->pos, k.k->p))
+ return k;
+
+ bkey_init(u);
+ u->p = path->pos;
+ return (struct bkey_s_c) { u, NULL };
+}
+
struct bkey_i *bch2_btree_journal_peek_slot(struct btree_trans *,
struct btree_iter *, struct bpos);
void bch2_trans_unlock(struct btree_trans *);
bool bch2_trans_locked(struct btree_trans *);
-static inline bool trans_was_restarted(struct btree_trans *trans, u32 restart_count)
+static inline int trans_was_restarted(struct btree_trans *trans, u32 restart_count)
{
- return restart_count != trans->restart_count;
+ return restart_count != trans->restart_count
+ ? -BCH_ERR_transaction_restart_nested
+ : 0;
}
-void bch2_trans_restart_error(struct btree_trans *, u32);
+void __noreturn bch2_trans_restart_error(struct btree_trans *, u32);
static inline void bch2_trans_verify_not_restarted(struct btree_trans *trans,
u32 restart_count)
bch2_trans_restart_error(trans, restart_count);
}
-void bch2_trans_in_restart_error(struct btree_trans *);
+void __noreturn bch2_trans_in_restart_error(struct btree_trans *);
static inline void bch2_trans_verify_not_in_restart(struct btree_trans *trans)
{
}
__always_inline
-static inline int btree_trans_restart_nounlock(struct btree_trans *trans, int err)
+static int btree_trans_restart_nounlock(struct btree_trans *trans, int err)
{
BUG_ON(err <= 0);
BUG_ON(!bch2_err_matches(-err, BCH_ERR_transaction_restart));
}
__always_inline
-static inline int btree_trans_restart(struct btree_trans *trans, int err)
+static int btree_trans_restart(struct btree_trans *trans, int err)
{
btree_trans_restart_nounlock(trans, err);
return -err;
}
void bch2_trans_iter_init_outlined(struct btree_trans *, struct btree_iter *,
- unsigned, struct bpos, unsigned);
+ enum btree_id, struct bpos, unsigned);
static inline void bch2_trans_iter_init(struct btree_trans *trans,
struct btree_iter *iter,
#define lockrestart_do(_trans, _do) \
({ \
u32 _restart_count; \
- int _ret; \
+ int _ret2; \
\
do { \
_restart_count = bch2_trans_begin(_trans); \
- _ret = (_do); \
- } while (bch2_err_matches(_ret, BCH_ERR_transaction_restart)); \
+ _ret2 = (_do); \
+ } while (bch2_err_matches(_ret2, BCH_ERR_transaction_restart)); \
\
- if (!_ret) \
+ if (!_ret2) \
bch2_trans_verify_not_restarted(_trans, _restart_count);\
\
- _ret; \
+ _ret2; \
})
/*
#define nested_lockrestart_do(_trans, _do) \
({ \
u32 _restart_count, _orig_restart_count; \
- int _ret; \
+ int _ret2; \
\
_restart_count = _orig_restart_count = (_trans)->restart_count; \
\
- while (bch2_err_matches(_ret = (_do), BCH_ERR_transaction_restart))\
+ while (bch2_err_matches(_ret2 = (_do), BCH_ERR_transaction_restart))\
_restart_count = bch2_trans_begin(_trans); \
\
- if (!_ret) \
+ if (!_ret2) \
bch2_trans_verify_not_restarted(_trans, _restart_count);\
\
- if (!_ret && trans_was_restarted(_trans, _orig_restart_count)) \
- _ret = -BCH_ERR_transaction_restart_nested; \
- \
- _ret; \
+ _ret2 ?: trans_was_restarted(_trans, _restart_count); \
})
#define for_each_btree_key2(_trans, _iter, _btree_id, \
_start, _flags, _k, _do) \
({ \
- int _ret = 0; \
+ int _ret3 = 0; \
\
bch2_trans_iter_init((_trans), &(_iter), (_btree_id), \
(_start), (_flags)); \
while (1) { \
u32 _restart_count = bch2_trans_begin(_trans); \
\
- _ret = 0; \
+ _ret3 = 0; \
(_k) = bch2_btree_iter_peek_type(&(_iter), (_flags)); \
if (!(_k).k) \
break; \
\
- _ret = bkey_err(_k) ?: (_do); \
- if (bch2_err_matches(_ret, BCH_ERR_transaction_restart))\
+ _ret3 = bkey_err(_k) ?: (_do); \
+ if (bch2_err_matches(_ret3, BCH_ERR_transaction_restart))\
continue; \
- if (_ret) \
+ if (_ret3) \
break; \
bch2_trans_verify_not_restarted(_trans, _restart_count);\
if (!bch2_btree_iter_advance(&(_iter))) \
} \
\
bch2_trans_iter_exit((_trans), &(_iter)); \
- _ret; \
+ _ret3; \
})
#define for_each_btree_key2_upto(_trans, _iter, _btree_id, \
_start, _end, _flags, _k, _do) \
({ \
- int _ret = 0; \
+ int _ret3 = 0; \
\
bch2_trans_iter_init((_trans), &(_iter), (_btree_id), \
(_start), (_flags)); \
while (1) { \
u32 _restart_count = bch2_trans_begin(_trans); \
\
- _ret = 0; \
+ _ret3 = 0; \
(_k) = bch2_btree_iter_peek_upto_type(&(_iter), _end, (_flags));\
if (!(_k).k) \
break; \
\
- _ret = bkey_err(_k) ?: (_do); \
- if (bch2_err_matches(_ret, BCH_ERR_transaction_restart))\
+ _ret3 = bkey_err(_k) ?: (_do); \
+ if (bch2_err_matches(_ret3, BCH_ERR_transaction_restart))\
continue; \
- if (_ret) \
+ if (_ret3) \
break; \
bch2_trans_verify_not_restarted(_trans, _restart_count);\
if (!bch2_btree_iter_advance(&(_iter))) \
} \
\
bch2_trans_iter_exit((_trans), &(_iter)); \
- _ret; \
+ _ret3; \
})
#define for_each_btree_key_reverse(_trans, _iter, _btree_id, \
_start, _flags, _k, _do) \
({ \
- int _ret = 0; \
+ int _ret3 = 0; \
\
bch2_trans_iter_init((_trans), &(_iter), (_btree_id), \
(_start), (_flags)); \
u32 _restart_count = bch2_trans_begin(_trans); \
(_k) = bch2_btree_iter_peek_prev_type(&(_iter), (_flags));\
if (!(_k).k) { \
- _ret = 0; \
+ _ret3 = 0; \
break; \
} \
\
- _ret = bkey_err(_k) ?: (_do); \
- if (bch2_err_matches(_ret, BCH_ERR_transaction_restart))\
+ _ret3 = bkey_err(_k) ?: (_do); \
+ if (bch2_err_matches(_ret3, BCH_ERR_transaction_restart))\
continue; \
- if (_ret) \
+ if (_ret3) \
break; \
bch2_trans_verify_not_restarted(_trans, _restart_count);\
if (!bch2_btree_iter_rewind(&(_iter))) \
} \
\
bch2_trans_iter_exit((_trans), &(_iter)); \
- _ret; \
+ _ret3; \
})
#define for_each_btree_key_commit(_trans, _iter, _btree_id, \
(_do) ?: bch2_trans_commit(_trans, (_disk_res),\
(_journal_seq), (_commit_flags)))
+#define for_each_btree_key_reverse_commit(_trans, _iter, _btree_id, \
+ _start, _iter_flags, _k, \
+ _disk_res, _journal_seq, _commit_flags,\
+ _do) \
+ for_each_btree_key_reverse(_trans, _iter, _btree_id, _start, _iter_flags, _k,\
+ (_do) ?: bch2_trans_commit(_trans, (_disk_res),\
+ (_journal_seq), (_commit_flags)))
+
#define for_each_btree_key_upto_commit(_trans, _iter, _btree_id, \
_start, _end, _iter_flags, _k, \
_disk_res, _journal_seq, _commit_flags,\
void bch2_trans_paths_to_text(struct printbuf *, struct btree_trans *);
void bch2_dump_trans_updates(struct btree_trans *);
void bch2_dump_trans_paths_updates(struct btree_trans *);
-void __bch2_trans_init(struct btree_trans *, struct bch_fs *, unsigned);
-void bch2_trans_exit(struct btree_trans *);
+
+struct btree_trans *__bch2_trans_get(struct bch_fs *, unsigned);
+void bch2_trans_put(struct btree_trans *);
extern const char *bch2_btree_transaction_fns[BCH_TRANSACTIONS_NR];
unsigned bch2_trans_get_fn_idx(const char *);
-#define bch2_trans_init(_trans, _c, _nr_iters, _mem) \
-do { \
+#define bch2_trans_get(_c) \
+({ \
static unsigned trans_fn_idx; \
\
if (unlikely(!trans_fn_idx)) \
trans_fn_idx = bch2_trans_get_fn_idx(__func__); \
- \
- __bch2_trans_init(_trans, _c, trans_fn_idx); \
-} while (0)
+ __bch2_trans_get(_c, trans_fn_idx); \
+})
void bch2_btree_trans_to_text(struct printbuf *, struct btree_trans *);