mirror of
https://github.com/koverstreet/bcachefs-tools.git
synced 2025-04-18 00:00:04 +03:00
Update bcachefs sources to 90a9c61e2b bcachefs: Switch bch2_btree_delete_range() to bch2_trans_run()
This commit is contained in:
parent
a6128b5335
commit
ddac1641ee
.bcachefs_revision
include
libbcachefs
acl.calloc_background.calloc_background.halloc_foreground.cbackpointers.cbcachefs.hbtree_cache.cbtree_gc.cbtree_io.cbtree_iter.cbtree_iter.hbtree_key_cache.cbtree_locking.hbtree_types.hbtree_update.hbtree_update_interior.cbtree_update_leaf.cbuckets.cchecksum.cdata_update.cdebug.cdirent.cec.cerrcode.cerrcode.herror.cerror.hfs-io.cfs-io.hfs.cfsck.cinode.cio.cjournal.cjournal_io.cjournal_reclaim.cjournal_seq_blacklist.clru.cmigrate.cmove.cmovinggc.cmovinggc.hopts.hquota.crebalance.crecovery.creflink.csubvolume.csuper-io.csuper.ctests.ctrace.cutil.cxattr.c
linux
@ -1 +1 @@
|
||||
1bda24d7cc91cb84fe5bcbc40c871e9d00542bd2
|
||||
90a9c61e2bcf20935aebda1c0c8078ad0fff2475
|
||||
|
@ -242,7 +242,7 @@ int bio_add_page(struct bio *, struct page *, unsigned, unsigned);
|
||||
struct bio *bio_alloc_clone(struct block_device *, struct bio *,
|
||||
gfp_t, struct bio_set *);
|
||||
|
||||
struct bio *bio_kmalloc(gfp_t, unsigned int);
|
||||
struct bio *bio_kmalloc(unsigned int, gfp_t);
|
||||
|
||||
extern void bio_endio(struct bio *);
|
||||
|
||||
|
@ -69,8 +69,7 @@ static inline void submit_bio(struct bio *bio)
|
||||
generic_make_request(bio);
|
||||
}
|
||||
|
||||
int blkdev_issue_discard(struct block_device *, sector_t,
|
||||
sector_t, gfp_t, unsigned long);
|
||||
int blkdev_issue_discard(struct block_device *, sector_t, sector_t, gfp_t);
|
||||
|
||||
#define bdev_get_queue(bdev) (&((bdev)->queue))
|
||||
|
||||
@ -85,7 +84,7 @@ int blkdev_issue_discard(struct block_device *, sector_t,
|
||||
#define PAGE_SECTORS (1 << PAGE_SECTORS_SHIFT)
|
||||
#define SECTOR_MASK (PAGE_SECTORS - 1)
|
||||
|
||||
#define blk_queue_discard(q) ((void) (q), 0)
|
||||
#define bdev_max_discard_sectors(bdev) ((void) (bdev), 0)
|
||||
#define blk_queue_nonrot(q) ((void) (q), 0)
|
||||
|
||||
unsigned bdev_logical_block_size(struct block_device *bdev);
|
||||
|
11
include/linux/errname.h
Normal file
11
include/linux/errname.h
Normal file
@ -0,0 +1,11 @@
|
||||
#ifndef _LINUX_ERRNAME_H
|
||||
#define _LINUX_ERRNAME_H
|
||||
|
||||
#include <string.h>
|
||||
|
||||
static inline const char *errname(int err)
|
||||
{
|
||||
return strerror(abs(err));
|
||||
}
|
||||
|
||||
#endif /* _LINUX_ERRNAME_H */
|
27
include/linux/prandom.h
Normal file
27
include/linux/prandom.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef _LINUX_PRANDOM_H
|
||||
#define _LINUX_PRANDOM_H
|
||||
|
||||
#include <linux/random.h>
|
||||
|
||||
static inline void prandom_bytes(void *buf, int nbytes)
|
||||
{
|
||||
return get_random_bytes(buf, nbytes);
|
||||
}
|
||||
|
||||
#define prandom_type(type) \
|
||||
static inline type prandom_##type(void) \
|
||||
{ \
|
||||
type v; \
|
||||
\
|
||||
prandom_bytes(&v, sizeof(v)); \
|
||||
return v; \
|
||||
}
|
||||
|
||||
prandom_type(int);
|
||||
prandom_type(long);
|
||||
prandom_type(u32);
|
||||
prandom_type(u64);
|
||||
#undef prandom_type
|
||||
|
||||
#endif /* _LINUX_PRANDOM_H */
|
||||
|
@ -29,11 +29,6 @@ static inline void get_random_bytes(void *buf, int nbytes)
|
||||
BUG_ON(getrandom(buf, nbytes, 0) != nbytes);
|
||||
}
|
||||
|
||||
static inline void prandom_bytes(void *buf, int nbytes)
|
||||
{
|
||||
return get_random_bytes(buf, nbytes);
|
||||
}
|
||||
|
||||
#define get_random_type(type) \
|
||||
static inline type get_random_##type(void) \
|
||||
{ \
|
||||
|
@ -200,4 +200,11 @@ void six_lock_pcpu_free_rcu(struct six_lock *);
|
||||
void six_lock_pcpu_free(struct six_lock *);
|
||||
void six_lock_pcpu_alloc(struct six_lock *);
|
||||
|
||||
struct six_lock_count {
|
||||
unsigned read;
|
||||
unsigned intent;
|
||||
};
|
||||
|
||||
struct six_lock_count six_lock_counts(struct six_lock *);
|
||||
|
||||
#endif /* _LINUX_SIX_H */
|
||||
|
@ -7,21 +7,29 @@
|
||||
|
||||
#include <linux/tracepoint.h>
|
||||
|
||||
#define TRACE_BPOS_entries(name) \
|
||||
__field(u64, name##_inode ) \
|
||||
__field(u64, name##_offset ) \
|
||||
__field(u32, name##_snapshot )
|
||||
|
||||
#define TRACE_BPOS_assign(dst, src) \
|
||||
__entry->dst##_inode = (src).inode; \
|
||||
__entry->dst##_offset = (src).offset; \
|
||||
__entry->dst##_snapshot = (src).snapshot
|
||||
|
||||
DECLARE_EVENT_CLASS(bpos,
|
||||
TP_PROTO(struct bpos *p),
|
||||
TP_ARGS(p),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field(u64, inode )
|
||||
__field(u64, offset )
|
||||
TRACE_BPOS_entries(p)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->inode = p->inode;
|
||||
__entry->offset = p->offset;
|
||||
TRACE_BPOS_assign(p, *p);
|
||||
),
|
||||
|
||||
TP_printk("%llu:%llu", __entry->inode, __entry->offset)
|
||||
TP_printk("%llu:%llu:%u", __entry->p_inode, __entry->p_offset, __entry->p_snapshot)
|
||||
);
|
||||
|
||||
DECLARE_EVENT_CLASS(bkey,
|
||||
@ -230,23 +238,22 @@ DECLARE_EVENT_CLASS(btree_node,
|
||||
TP_STRUCT__entry(
|
||||
__field(dev_t, dev )
|
||||
__field(u8, level )
|
||||
__field(u8, id )
|
||||
__field(u64, inode )
|
||||
__field(u64, offset )
|
||||
__field(u8, btree_id )
|
||||
TRACE_BPOS_entries(pos)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->dev = c->dev;
|
||||
__entry->level = b->c.level;
|
||||
__entry->id = b->c.btree_id;
|
||||
__entry->inode = b->key.k.p.inode;
|
||||
__entry->offset = b->key.k.p.offset;
|
||||
__entry->btree_id = b->c.btree_id;
|
||||
TRACE_BPOS_assign(pos, b->key.k.p);
|
||||
),
|
||||
|
||||
TP_printk("%d,%d %u id %u %llu:%llu",
|
||||
TP_printk("%d,%d %u %s %llu:%llu:%u",
|
||||
MAJOR(__entry->dev), MINOR(__entry->dev),
|
||||
__entry->level, __entry->id,
|
||||
__entry->inode, __entry->offset)
|
||||
__entry->level,
|
||||
bch2_btree_ids[__entry->btree_id],
|
||||
__entry->pos_inode, __entry->pos_offset, __entry->pos_snapshot)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(btree_node, btree_read,
|
||||
@ -376,43 +383,36 @@ TRACE_EVENT(btree_cache_scan,
|
||||
);
|
||||
|
||||
TRACE_EVENT(btree_node_relock_fail,
|
||||
TP_PROTO(const char *trans_fn,
|
||||
TP_PROTO(struct btree_trans *trans,
|
||||
unsigned long caller_ip,
|
||||
enum btree_id btree_id,
|
||||
struct bpos *pos,
|
||||
unsigned long node,
|
||||
u32 iter_lock_seq,
|
||||
u32 node_lock_seq),
|
||||
TP_ARGS(trans_fn, caller_ip, btree_id, pos, node, iter_lock_seq, node_lock_seq),
|
||||
struct btree_path *path,
|
||||
unsigned level),
|
||||
TP_ARGS(trans, caller_ip, path, level),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__array(char, trans_fn, 24 )
|
||||
__field(unsigned long, caller_ip )
|
||||
__field(u8, btree_id )
|
||||
__field(u64, pos_inode )
|
||||
__field(u64, pos_offset )
|
||||
__field(u32, pos_snapshot )
|
||||
TRACE_BPOS_entries(pos)
|
||||
__field(unsigned long, node )
|
||||
__field(u32, iter_lock_seq )
|
||||
__field(u32, node_lock_seq )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
strncpy(__entry->trans_fn, trans_fn, sizeof(__entry->trans_fn));
|
||||
strlcpy(__entry->trans_fn, trans->fn, sizeof(__entry->trans_fn));
|
||||
__entry->caller_ip = caller_ip;
|
||||
__entry->btree_id = btree_id;
|
||||
__entry->pos_inode = pos->inode;
|
||||
__entry->pos_offset = pos->offset;
|
||||
__entry->pos_snapshot = pos->snapshot;
|
||||
__entry->node = node;
|
||||
__entry->iter_lock_seq = iter_lock_seq;
|
||||
__entry->node_lock_seq = node_lock_seq;
|
||||
__entry->btree_id = path->btree_id;
|
||||
TRACE_BPOS_assign(pos, path->pos);
|
||||
__entry->node = (unsigned long) btree_path_node(path, level);
|
||||
__entry->iter_lock_seq = path->l[level].lock_seq;
|
||||
__entry->node_lock_seq = is_btree_node(path, level) ? path->l[level].b->c.lock.state.seq : 0;
|
||||
),
|
||||
|
||||
TP_printk("%s %pS btree %u pos %llu:%llu:%u, node %lu iter seq %u lock seq %u",
|
||||
TP_printk("%s %pS btree %s pos %llu:%llu:%u, node %lu iter seq %u lock seq %u",
|
||||
__entry->trans_fn,
|
||||
(void *) __entry->caller_ip,
|
||||
__entry->btree_id,
|
||||
bch2_btree_ids[__entry->btree_id],
|
||||
__entry->pos_inode,
|
||||
__entry->pos_offset,
|
||||
__entry->pos_snapshot,
|
||||
@ -421,6 +421,56 @@ TRACE_EVENT(btree_node_relock_fail,
|
||||
__entry->node_lock_seq)
|
||||
);
|
||||
|
||||
TRACE_EVENT(btree_node_upgrade_fail,
|
||||
TP_PROTO(struct btree_trans *trans,
|
||||
unsigned long caller_ip,
|
||||
struct btree_path *path,
|
||||
unsigned level),
|
||||
TP_ARGS(trans, caller_ip, path, level),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__array(char, trans_fn, 24 )
|
||||
__field(unsigned long, caller_ip )
|
||||
__field(u8, btree_id )
|
||||
TRACE_BPOS_entries(pos)
|
||||
__field(u8, locked )
|
||||
__field(u8, self_read_count )
|
||||
__field(u8, self_intent_count)
|
||||
__field(u8, read_count )
|
||||
__field(u8, intent_count )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
struct six_lock_count c;
|
||||
|
||||
strlcpy(__entry->trans_fn, trans->fn, sizeof(__entry->trans_fn));
|
||||
__entry->caller_ip = caller_ip;
|
||||
__entry->btree_id = path->btree_id;
|
||||
TRACE_BPOS_assign(pos, path->pos);
|
||||
__entry->locked = btree_node_locked(path, level);
|
||||
|
||||
c = bch2_btree_node_lock_counts(trans, NULL, path->l[level].b, level),
|
||||
__entry->self_read_count = c.read;
|
||||
__entry->self_intent_count = c.intent;
|
||||
c = six_lock_counts(&path->l[level].b->c.lock);
|
||||
__entry->read_count = c.read;
|
||||
__entry->intent_count = c.intent;
|
||||
),
|
||||
|
||||
TP_printk("%s %pS btree %s pos %llu:%llu:%u, locked %u held %u:%u lock count %u:%u",
|
||||
__entry->trans_fn,
|
||||
(void *) __entry->caller_ip,
|
||||
bch2_btree_ids[__entry->btree_id],
|
||||
__entry->pos_inode,
|
||||
__entry->pos_offset,
|
||||
__entry->pos_snapshot,
|
||||
__entry->locked,
|
||||
__entry->self_read_count,
|
||||
__entry->self_intent_count,
|
||||
__entry->read_count,
|
||||
__entry->intent_count)
|
||||
);
|
||||
|
||||
/* Garbage collection */
|
||||
|
||||
DEFINE_EVENT(bch_fs, gc_gens_start,
|
||||
@ -456,55 +506,68 @@ TRACE_EVENT(bucket_alloc,
|
||||
|
||||
TRACE_EVENT(bucket_alloc_fail,
|
||||
TP_PROTO(struct bch_dev *ca, const char *alloc_reserve,
|
||||
u64 free,
|
||||
u64 avail,
|
||||
u64 copygc_wait_amount,
|
||||
s64 copygc_waiting_for,
|
||||
u64 seen,
|
||||
u64 open,
|
||||
u64 need_journal_commit,
|
||||
u64 nouse,
|
||||
bool nonblocking,
|
||||
int ret),
|
||||
TP_ARGS(ca, alloc_reserve, avail, seen, open, need_journal_commit, nouse, nonblocking, ret),
|
||||
const char *err),
|
||||
TP_ARGS(ca, alloc_reserve, free, avail, copygc_wait_amount, copygc_waiting_for,
|
||||
seen, open, need_journal_commit, nouse, nonblocking, err),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field(dev_t, dev )
|
||||
__array(char, reserve, 16 )
|
||||
__field(u64, free )
|
||||
__field(u64, avail )
|
||||
__field(u64, copygc_wait_amount )
|
||||
__field(s64, copygc_waiting_for )
|
||||
__field(u64, seen )
|
||||
__field(u64, open )
|
||||
__field(u64, need_journal_commit )
|
||||
__field(u64, nouse )
|
||||
__field(bool, nonblocking )
|
||||
__field(int, ret )
|
||||
__array(char, err, 16 )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->dev = ca->dev;
|
||||
strlcpy(__entry->reserve, alloc_reserve, sizeof(__entry->reserve));
|
||||
__entry->free = free;
|
||||
__entry->avail = avail;
|
||||
__entry->copygc_wait_amount = copygc_wait_amount;
|
||||
__entry->copygc_waiting_for = copygc_waiting_for;
|
||||
__entry->seen = seen;
|
||||
__entry->open = open;
|
||||
__entry->need_journal_commit = need_journal_commit;
|
||||
__entry->nouse = nouse;
|
||||
__entry->nonblocking = nonblocking;
|
||||
__entry->ret = ret;
|
||||
strlcpy(__entry->err, err, sizeof(__entry->err));
|
||||
),
|
||||
|
||||
TP_printk("%d,%d reserve %s avail %llu seen %llu open %llu need_journal_commit %llu nouse %llu nonblocking %u ret %i",
|
||||
TP_printk("%d,%d reserve %s free %llu avail %llu copygc_wait %llu/%lli seen %llu open %llu need_journal_commit %llu nouse %llu nonblocking %u err %s",
|
||||
MAJOR(__entry->dev), MINOR(__entry->dev),
|
||||
__entry->reserve,
|
||||
__entry->free,
|
||||
__entry->avail,
|
||||
__entry->copygc_wait_amount,
|
||||
__entry->copygc_waiting_for,
|
||||
__entry->seen,
|
||||
__entry->open,
|
||||
__entry->need_journal_commit,
|
||||
__entry->nouse,
|
||||
__entry->nonblocking,
|
||||
__entry->ret)
|
||||
__entry->err)
|
||||
);
|
||||
|
||||
TRACE_EVENT(discard_buckets,
|
||||
TP_PROTO(struct bch_fs *c, u64 seen, u64 open,
|
||||
u64 need_journal_commit, u64 discarded, int ret),
|
||||
TP_ARGS(c, seen, open, need_journal_commit, discarded, ret),
|
||||
u64 need_journal_commit, u64 discarded, const char *err),
|
||||
TP_ARGS(c, seen, open, need_journal_commit, discarded, err),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field(dev_t, dev )
|
||||
@ -512,7 +575,7 @@ TRACE_EVENT(discard_buckets,
|
||||
__field(u64, open )
|
||||
__field(u64, need_journal_commit )
|
||||
__field(u64, discarded )
|
||||
__field(int, ret )
|
||||
__array(char, err, 16 )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
@ -521,16 +584,16 @@ TRACE_EVENT(discard_buckets,
|
||||
__entry->open = open;
|
||||
__entry->need_journal_commit = need_journal_commit;
|
||||
__entry->discarded = discarded;
|
||||
__entry->ret = ret;
|
||||
strlcpy(__entry->err, err, sizeof(__entry->err));
|
||||
),
|
||||
|
||||
TP_printk("%d%d seen %llu open %llu need_journal_commit %llu discarded %llu ret %i",
|
||||
TP_printk("%d%d seen %llu open %llu need_journal_commit %llu discarded %llu err %s",
|
||||
MAJOR(__entry->dev), MINOR(__entry->dev),
|
||||
__entry->seen,
|
||||
__entry->open,
|
||||
__entry->need_journal_commit,
|
||||
__entry->discarded,
|
||||
__entry->ret)
|
||||
__entry->err)
|
||||
);
|
||||
|
||||
TRACE_EVENT(invalidate_bucket,
|
||||
@ -649,9 +712,9 @@ TRACE_EVENT(copygc_wait,
|
||||
);
|
||||
|
||||
DECLARE_EVENT_CLASS(transaction_event,
|
||||
TP_PROTO(const char *trans_fn,
|
||||
TP_PROTO(struct btree_trans *trans,
|
||||
unsigned long caller_ip),
|
||||
TP_ARGS(trans_fn, caller_ip),
|
||||
TP_ARGS(trans, caller_ip),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__array(char, trans_fn, 24 )
|
||||
@ -659,7 +722,7 @@ DECLARE_EVENT_CLASS(transaction_event,
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
strncpy(__entry->trans_fn, trans_fn, sizeof(__entry->trans_fn));
|
||||
strlcpy(__entry->trans_fn, trans->fn, sizeof(__entry->trans_fn));
|
||||
__entry->caller_ip = caller_ip;
|
||||
),
|
||||
|
||||
@ -667,217 +730,206 @@ DECLARE_EVENT_CLASS(transaction_event,
|
||||
);
|
||||
|
||||
DEFINE_EVENT(transaction_event, transaction_commit,
|
||||
TP_PROTO(const char *trans_fn,
|
||||
TP_PROTO(struct btree_trans *trans,
|
||||
unsigned long caller_ip),
|
||||
TP_ARGS(trans_fn, caller_ip)
|
||||
TP_ARGS(trans, caller_ip)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(transaction_event, transaction_restart_ip,
|
||||
TP_PROTO(const char *trans_fn,
|
||||
DEFINE_EVENT(transaction_event, transaction_restart_injected,
|
||||
TP_PROTO(struct btree_trans *trans,
|
||||
unsigned long caller_ip),
|
||||
TP_ARGS(trans_fn, caller_ip)
|
||||
TP_ARGS(trans, caller_ip)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(transaction_event, trans_blocked_journal_reclaim,
|
||||
TP_PROTO(const char *trans_fn,
|
||||
TP_PROTO(struct btree_trans *trans,
|
||||
unsigned long caller_ip),
|
||||
TP_ARGS(trans_fn, caller_ip)
|
||||
TP_ARGS(trans, caller_ip)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(transaction_event, trans_restart_journal_res_get,
|
||||
TP_PROTO(const char *trans_fn,
|
||||
TP_PROTO(struct btree_trans *trans,
|
||||
unsigned long caller_ip),
|
||||
TP_ARGS(trans_fn, caller_ip)
|
||||
TP_ARGS(trans, caller_ip)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(transaction_event, trans_restart_journal_preres_get,
|
||||
TP_PROTO(const char *trans_fn,
|
||||
TP_PROTO(struct btree_trans *trans,
|
||||
unsigned long caller_ip),
|
||||
TP_ARGS(trans_fn, caller_ip)
|
||||
TP_ARGS(trans, caller_ip)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(transaction_event, trans_restart_journal_reclaim,
|
||||
TP_PROTO(const char *trans_fn,
|
||||
TP_PROTO(struct btree_trans *trans,
|
||||
unsigned long caller_ip),
|
||||
TP_ARGS(trans_fn, caller_ip)
|
||||
TP_ARGS(trans, caller_ip)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(transaction_event, trans_restart_fault_inject,
|
||||
TP_PROTO(const char *trans_fn,
|
||||
TP_PROTO(struct btree_trans *trans,
|
||||
unsigned long caller_ip),
|
||||
TP_ARGS(trans_fn, caller_ip)
|
||||
TP_ARGS(trans, caller_ip)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(transaction_event, trans_traverse_all,
|
||||
TP_PROTO(const char *trans_fn,
|
||||
TP_PROTO(struct btree_trans *trans,
|
||||
unsigned long caller_ip),
|
||||
TP_ARGS(trans_fn, caller_ip)
|
||||
TP_ARGS(trans, caller_ip)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(transaction_event, trans_restart_mark_replicas,
|
||||
TP_PROTO(const char *trans_fn,
|
||||
TP_PROTO(struct btree_trans *trans,
|
||||
unsigned long caller_ip),
|
||||
TP_ARGS(trans_fn, caller_ip)
|
||||
TP_ARGS(trans, caller_ip)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(transaction_event, trans_restart_key_cache_raced,
|
||||
TP_PROTO(const char *trans_fn,
|
||||
TP_PROTO(struct btree_trans *trans,
|
||||
unsigned long caller_ip),
|
||||
TP_ARGS(trans_fn, caller_ip)
|
||||
TP_ARGS(trans, caller_ip)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(transaction_event, trans_restart_too_many_iters,
|
||||
TP_PROTO(struct btree_trans *trans,
|
||||
unsigned long caller_ip),
|
||||
TP_ARGS(trans, caller_ip)
|
||||
);
|
||||
|
||||
DECLARE_EVENT_CLASS(transaction_restart_iter,
|
||||
TP_PROTO(const char *trans_fn,
|
||||
TP_PROTO(struct btree_trans *trans,
|
||||
unsigned long caller_ip,
|
||||
enum btree_id btree_id,
|
||||
struct bpos *pos),
|
||||
TP_ARGS(trans_fn, caller_ip, btree_id, pos),
|
||||
struct btree_path *path),
|
||||
TP_ARGS(trans, caller_ip, path),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__array(char, trans_fn, 24 )
|
||||
__field(unsigned long, caller_ip )
|
||||
__field(u8, btree_id )
|
||||
__field(u64, pos_inode )
|
||||
__field(u64, pos_offset )
|
||||
__field(u32, pos_snapshot )
|
||||
TRACE_BPOS_entries(pos)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
strncpy(__entry->trans_fn, trans_fn, sizeof(__entry->trans_fn));
|
||||
strlcpy(__entry->trans_fn, trans->fn, sizeof(__entry->trans_fn));
|
||||
__entry->caller_ip = caller_ip;
|
||||
__entry->btree_id = btree_id;
|
||||
__entry->pos_inode = pos->inode;
|
||||
__entry->pos_offset = pos->offset;
|
||||
__entry->pos_snapshot = pos->snapshot;
|
||||
__entry->btree_id = path->btree_id;
|
||||
TRACE_BPOS_assign(pos, path->pos)
|
||||
),
|
||||
|
||||
TP_printk("%s %pS btree %u pos %llu:%llu:%u",
|
||||
TP_printk("%s %pS btree %s pos %llu:%llu:%u",
|
||||
__entry->trans_fn,
|
||||
(void *) __entry->caller_ip,
|
||||
__entry->btree_id,
|
||||
bch2_btree_ids[__entry->btree_id],
|
||||
__entry->pos_inode,
|
||||
__entry->pos_offset,
|
||||
__entry->pos_snapshot)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(transaction_restart_iter, trans_restart_btree_node_reused,
|
||||
TP_PROTO(const char *trans_fn,
|
||||
TP_PROTO(struct btree_trans *trans,
|
||||
unsigned long caller_ip,
|
||||
enum btree_id btree_id,
|
||||
struct bpos *pos),
|
||||
TP_ARGS(trans_fn, caller_ip, btree_id, pos)
|
||||
struct btree_path *path),
|
||||
TP_ARGS(trans, caller_ip, path)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(transaction_restart_iter, trans_restart_btree_node_split,
|
||||
TP_PROTO(const char *trans_fn,
|
||||
TP_PROTO(struct btree_trans *trans,
|
||||
unsigned long caller_ip,
|
||||
enum btree_id btree_id,
|
||||
struct bpos *pos),
|
||||
TP_ARGS(trans_fn, caller_ip, btree_id, pos)
|
||||
struct btree_path *path),
|
||||
TP_ARGS(trans, caller_ip, path)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(transaction_restart_iter, trans_restart_upgrade,
|
||||
TP_PROTO(const char *trans_fn,
|
||||
TP_PROTO(struct btree_trans *trans,
|
||||
unsigned long caller_ip,
|
||||
enum btree_id btree_id,
|
||||
struct bpos *pos),
|
||||
TP_ARGS(trans_fn, caller_ip, btree_id, pos)
|
||||
struct btree_path *path),
|
||||
TP_ARGS(trans, caller_ip, path)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(transaction_restart_iter, trans_restart_iter_upgrade,
|
||||
TP_PROTO(const char *trans_fn,
|
||||
TP_PROTO(struct btree_trans *trans,
|
||||
unsigned long caller_ip,
|
||||
enum btree_id btree_id,
|
||||
struct bpos *pos),
|
||||
TP_ARGS(trans_fn, caller_ip, btree_id, pos)
|
||||
struct btree_path *path),
|
||||
TP_ARGS(trans, caller_ip, path)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(transaction_restart_iter, trans_restart_relock,
|
||||
TP_PROTO(const char *trans_fn,
|
||||
TP_PROTO(struct btree_trans *trans,
|
||||
unsigned long caller_ip,
|
||||
enum btree_id btree_id,
|
||||
struct bpos *pos),
|
||||
TP_ARGS(trans_fn, caller_ip, btree_id, pos)
|
||||
struct btree_path *path),
|
||||
TP_ARGS(trans, caller_ip, path)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(transaction_restart_iter, trans_restart_relock_next_node,
|
||||
TP_PROTO(const char *trans_fn,
|
||||
TP_PROTO(struct btree_trans *trans,
|
||||
unsigned long caller_ip,
|
||||
enum btree_id btree_id,
|
||||
struct bpos *pos),
|
||||
TP_ARGS(trans_fn, caller_ip, btree_id, pos)
|
||||
struct btree_path *path),
|
||||
TP_ARGS(trans, caller_ip, path)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(transaction_restart_iter, trans_restart_relock_parent_for_fill,
|
||||
TP_PROTO(const char *trans_fn,
|
||||
TP_PROTO(struct btree_trans *trans,
|
||||
unsigned long caller_ip,
|
||||
enum btree_id btree_id,
|
||||
struct bpos *pos),
|
||||
TP_ARGS(trans_fn, caller_ip, btree_id, pos)
|
||||
struct btree_path *path),
|
||||
TP_ARGS(trans, caller_ip, path)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(transaction_restart_iter, trans_restart_relock_after_fill,
|
||||
TP_PROTO(const char *trans_fn,
|
||||
TP_PROTO(struct btree_trans *trans,
|
||||
unsigned long caller_ip,
|
||||
enum btree_id btree_id,
|
||||
struct bpos *pos),
|
||||
TP_ARGS(trans_fn, caller_ip, btree_id, pos)
|
||||
struct btree_path *path),
|
||||
TP_ARGS(trans, caller_ip, path)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(transaction_event, transaction_restart_key_cache_upgrade,
|
||||
TP_PROTO(struct btree_trans *trans,
|
||||
unsigned long caller_ip),
|
||||
TP_ARGS(trans, caller_ip)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(transaction_restart_iter, trans_restart_relock_key_cache_fill,
|
||||
TP_PROTO(const char *trans_fn,
|
||||
TP_PROTO(struct btree_trans *trans,
|
||||
unsigned long caller_ip,
|
||||
enum btree_id btree_id,
|
||||
struct bpos *pos),
|
||||
TP_ARGS(trans_fn, caller_ip, btree_id, pos)
|
||||
struct btree_path *path),
|
||||
TP_ARGS(trans, caller_ip, path)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(transaction_restart_iter, trans_restart_relock_path,
|
||||
TP_PROTO(const char *trans_fn,
|
||||
TP_PROTO(struct btree_trans *trans,
|
||||
unsigned long caller_ip,
|
||||
enum btree_id btree_id,
|
||||
struct bpos *pos),
|
||||
TP_ARGS(trans_fn, caller_ip, btree_id, pos)
|
||||
struct btree_path *path),
|
||||
TP_ARGS(trans, caller_ip, path)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(transaction_restart_iter, trans_restart_relock_path_intent,
|
||||
TP_PROTO(const char *trans_fn,
|
||||
TP_PROTO(struct btree_trans *trans,
|
||||
unsigned long caller_ip,
|
||||
enum btree_id btree_id,
|
||||
struct bpos *pos),
|
||||
TP_ARGS(trans_fn, caller_ip, btree_id, pos)
|
||||
struct btree_path *path),
|
||||
TP_ARGS(trans, caller_ip, path)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(transaction_restart_iter, trans_restart_traverse,
|
||||
TP_PROTO(const char *trans_fn,
|
||||
TP_PROTO(struct btree_trans *trans,
|
||||
unsigned long caller_ip,
|
||||
enum btree_id btree_id,
|
||||
struct bpos *pos),
|
||||
TP_ARGS(trans_fn, caller_ip, btree_id, pos)
|
||||
struct btree_path *path),
|
||||
TP_ARGS(trans, caller_ip, path)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(transaction_restart_iter, trans_restart_memory_allocation_failure,
|
||||
TP_PROTO(const char *trans_fn,
|
||||
TP_PROTO(struct btree_trans *trans,
|
||||
unsigned long caller_ip,
|
||||
enum btree_id btree_id,
|
||||
struct bpos *pos),
|
||||
TP_ARGS(trans_fn, caller_ip, btree_id, pos)
|
||||
struct btree_path *path),
|
||||
TP_ARGS(trans, caller_ip, path)
|
||||
);
|
||||
|
||||
TRACE_EVENT(trans_restart_would_deadlock,
|
||||
TP_PROTO(const char *trans_fn,
|
||||
TP_PROTO(struct btree_trans *trans,
|
||||
unsigned long caller_ip,
|
||||
bool in_traverse_all,
|
||||
unsigned reason,
|
||||
enum btree_id have_btree_id,
|
||||
unsigned have_iter_type,
|
||||
struct bpos *have_pos,
|
||||
enum btree_id want_btree_id,
|
||||
unsigned want_iter_type,
|
||||
struct btree_path *have,
|
||||
struct btree_path *want,
|
||||
struct bpos *want_pos),
|
||||
TP_ARGS(trans_fn, caller_ip, in_traverse_all, reason,
|
||||
have_btree_id, have_iter_type, have_pos,
|
||||
want_btree_id, want_iter_type, want_pos),
|
||||
TP_ARGS(trans, caller_ip, reason,
|
||||
have, want, want_pos),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__array(char, trans_fn, 24 )
|
||||
@ -885,35 +937,24 @@ TRACE_EVENT(trans_restart_would_deadlock,
|
||||
__field(u8, in_traverse_all )
|
||||
__field(u8, reason )
|
||||
__field(u8, have_btree_id )
|
||||
__field(u8, have_iter_type )
|
||||
__field(u8, have_type )
|
||||
__field(u8, want_btree_id )
|
||||
__field(u8, want_iter_type )
|
||||
|
||||
__field(u64, have_pos_inode )
|
||||
__field(u64, have_pos_offset )
|
||||
__field(u32, have_pos_snapshot)
|
||||
__field(u32, want_pos_snapshot)
|
||||
__field(u64, want_pos_inode )
|
||||
__field(u64, want_pos_offset )
|
||||
__field(u8, want_type )
|
||||
TRACE_BPOS_entries(have_pos)
|
||||
TRACE_BPOS_entries(want_pos)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
strncpy(__entry->trans_fn, trans_fn, sizeof(__entry->trans_fn));
|
||||
strlcpy(__entry->trans_fn, trans->fn, sizeof(__entry->trans_fn));
|
||||
__entry->caller_ip = caller_ip;
|
||||
__entry->in_traverse_all = in_traverse_all;
|
||||
__entry->in_traverse_all = trans->in_traverse_all;
|
||||
__entry->reason = reason;
|
||||
__entry->have_btree_id = have_btree_id;
|
||||
__entry->have_iter_type = have_iter_type;
|
||||
__entry->want_btree_id = want_btree_id;
|
||||
__entry->want_iter_type = want_iter_type;
|
||||
|
||||
__entry->have_pos_inode = have_pos->inode;
|
||||
__entry->have_pos_offset = have_pos->offset;
|
||||
__entry->have_pos_snapshot = have_pos->snapshot;
|
||||
|
||||
__entry->want_pos_inode = want_pos->inode;
|
||||
__entry->want_pos_offset = want_pos->offset;
|
||||
__entry->want_pos_snapshot = want_pos->snapshot;
|
||||
__entry->have_btree_id = have->btree_id;
|
||||
__entry->have_type = have->cached;
|
||||
__entry->want_btree_id = want->btree_id;
|
||||
__entry->want_type = want->cached;
|
||||
TRACE_BPOS_assign(have_pos, have->pos);
|
||||
TRACE_BPOS_assign(want_pos, *want_pos);
|
||||
),
|
||||
|
||||
TP_printk("%s %pS traverse_all %u because %u have %u:%u %llu:%llu:%u want %u:%u %llu:%llu:%u",
|
||||
@ -922,37 +963,37 @@ TRACE_EVENT(trans_restart_would_deadlock,
|
||||
__entry->in_traverse_all,
|
||||
__entry->reason,
|
||||
__entry->have_btree_id,
|
||||
__entry->have_iter_type,
|
||||
__entry->have_type,
|
||||
__entry->have_pos_inode,
|
||||
__entry->have_pos_offset,
|
||||
__entry->have_pos_snapshot,
|
||||
__entry->want_btree_id,
|
||||
__entry->want_iter_type,
|
||||
__entry->want_type,
|
||||
__entry->want_pos_inode,
|
||||
__entry->want_pos_offset,
|
||||
__entry->want_pos_snapshot)
|
||||
);
|
||||
|
||||
TRACE_EVENT(trans_restart_would_deadlock_write,
|
||||
TP_PROTO(const char *trans_fn),
|
||||
TP_ARGS(trans_fn),
|
||||
TP_PROTO(struct btree_trans *trans),
|
||||
TP_ARGS(trans),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__array(char, trans_fn, 24 )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
strncpy(__entry->trans_fn, trans_fn, sizeof(__entry->trans_fn));
|
||||
strlcpy(__entry->trans_fn, trans->fn, sizeof(__entry->trans_fn));
|
||||
),
|
||||
|
||||
TP_printk("%s", __entry->trans_fn)
|
||||
);
|
||||
|
||||
TRACE_EVENT(trans_restart_mem_realloced,
|
||||
TP_PROTO(const char *trans_fn,
|
||||
TP_PROTO(struct btree_trans *trans,
|
||||
unsigned long caller_ip,
|
||||
unsigned long bytes),
|
||||
TP_ARGS(trans_fn, caller_ip, bytes),
|
||||
TP_ARGS(trans, caller_ip, bytes),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__array(char, trans_fn, 24 )
|
||||
@ -961,7 +1002,7 @@ TRACE_EVENT(trans_restart_mem_realloced,
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
strncpy(__entry->trans_fn, trans_fn, sizeof(__entry->trans_fn));
|
||||
strlcpy(__entry->trans_fn, trans->fn, sizeof(__entry->trans_fn));
|
||||
__entry->caller_ip = caller_ip;
|
||||
__entry->bytes = bytes;
|
||||
),
|
||||
@ -973,32 +1014,28 @@ TRACE_EVENT(trans_restart_mem_realloced,
|
||||
);
|
||||
|
||||
TRACE_EVENT(trans_restart_key_cache_key_realloced,
|
||||
TP_PROTO(const char *trans_fn,
|
||||
TP_PROTO(struct btree_trans *trans,
|
||||
unsigned long caller_ip,
|
||||
enum btree_id btree_id,
|
||||
struct bpos *pos,
|
||||
struct btree_path *path,
|
||||
unsigned old_u64s,
|
||||
unsigned new_u64s),
|
||||
TP_ARGS(trans_fn, caller_ip, btree_id, pos, old_u64s, new_u64s),
|
||||
TP_ARGS(trans, caller_ip, path, old_u64s, new_u64s),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__array(char, trans_fn, 24 )
|
||||
__field(unsigned long, caller_ip )
|
||||
__field(enum btree_id, btree_id )
|
||||
__field(u64, inode )
|
||||
__field(u64, offset )
|
||||
__field(u32, snapshot )
|
||||
TRACE_BPOS_entries(pos)
|
||||
__field(u32, old_u64s )
|
||||
__field(u32, new_u64s )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
strncpy(__entry->trans_fn, trans_fn, sizeof(__entry->trans_fn));
|
||||
__entry->caller_ip = caller_ip;
|
||||
__entry->btree_id = btree_id;
|
||||
__entry->inode = pos->inode;
|
||||
__entry->offset = pos->offset;
|
||||
__entry->snapshot = pos->snapshot;
|
||||
strlcpy(__entry->trans_fn, trans->fn, sizeof(__entry->trans_fn));
|
||||
__entry->caller_ip = caller_ip;
|
||||
|
||||
__entry->btree_id = path->btree_id;
|
||||
TRACE_BPOS_assign(pos, path->pos);
|
||||
__entry->old_u64s = old_u64s;
|
||||
__entry->new_u64s = new_u64s;
|
||||
),
|
||||
@ -1007,9 +1044,9 @@ TRACE_EVENT(trans_restart_key_cache_key_realloced,
|
||||
__entry->trans_fn,
|
||||
(void *) __entry->caller_ip,
|
||||
bch2_btree_ids[__entry->btree_id],
|
||||
__entry->inode,
|
||||
__entry->offset,
|
||||
__entry->snapshot,
|
||||
__entry->pos_inode,
|
||||
__entry->pos_offset,
|
||||
__entry->pos_snapshot,
|
||||
__entry->old_u64s,
|
||||
__entry->new_u64s)
|
||||
);
|
||||
|
@ -236,7 +236,7 @@ retry:
|
||||
&X_SEARCH(acl_to_xattr_type(type), "", 0),
|
||||
0);
|
||||
if (ret) {
|
||||
if (ret == -EINTR)
|
||||
if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
|
||||
goto retry;
|
||||
if (ret != -ENOENT)
|
||||
acl = ERR_PTR(ret);
|
||||
@ -335,7 +335,7 @@ retry:
|
||||
btree_err:
|
||||
bch2_trans_iter_exit(&trans, &inode_iter);
|
||||
|
||||
if (ret == -EINTR)
|
||||
if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
|
||||
goto retry;
|
||||
if (unlikely(ret))
|
||||
goto err;
|
||||
|
@ -543,7 +543,7 @@ int bch2_alloc_read(struct bch_fs *c)
|
||||
bch2_trans_exit(&trans);
|
||||
|
||||
if (ret)
|
||||
bch_err(c, "error reading alloc info: %i", ret);
|
||||
bch_err(c, "error reading alloc info: %s", bch2_err_str(ret));
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -794,7 +794,7 @@ static int bch2_check_discard_freespace_key(struct btree_trans *trans,
|
||||
{
|
||||
struct bch_fs *c = trans->c;
|
||||
struct btree_iter alloc_iter;
|
||||
struct bkey_s_c k, freespace_k;
|
||||
struct bkey_s_c alloc_k;
|
||||
struct bch_alloc_v4 a;
|
||||
u64 genbits;
|
||||
struct bpos pos;
|
||||
@ -804,14 +804,6 @@ static int bch2_check_discard_freespace_key(struct btree_trans *trans,
|
||||
struct printbuf buf = PRINTBUF;
|
||||
int ret;
|
||||
|
||||
freespace_k = bch2_btree_iter_peek(iter);
|
||||
if (!freespace_k.k)
|
||||
return 1;
|
||||
|
||||
ret = bkey_err(freespace_k);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pos = iter->pos;
|
||||
pos.offset &= ~(~0ULL << 56);
|
||||
genbits = iter->pos.offset & (~0ULL << 56);
|
||||
@ -823,18 +815,18 @@ static int bch2_check_discard_freespace_key(struct btree_trans *trans,
|
||||
bch2_btree_ids[iter->btree_id], pos.inode, pos.offset))
|
||||
goto delete;
|
||||
|
||||
k = bch2_btree_iter_peek_slot(&alloc_iter);
|
||||
ret = bkey_err(k);
|
||||
alloc_k = bch2_btree_iter_peek_slot(&alloc_iter);
|
||||
ret = bkey_err(alloc_k);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
bch2_alloc_to_v4(k, &a);
|
||||
bch2_alloc_to_v4(alloc_k, &a);
|
||||
|
||||
if (fsck_err_on(a.data_type != state ||
|
||||
(state == BCH_DATA_free &&
|
||||
genbits != alloc_freespace_genbits(a)), c,
|
||||
"%s\n incorrectly set in %s index (free %u, genbits %llu should be %llu)",
|
||||
(bch2_bkey_val_to_text(&buf, c, k), buf.buf),
|
||||
(bch2_bkey_val_to_text(&buf, c, alloc_k), buf.buf),
|
||||
bch2_btree_ids[iter->btree_id],
|
||||
a.data_type == state,
|
||||
genbits >> 56, alloc_freespace_genbits(a) >> 56))
|
||||
@ -855,6 +847,7 @@ int bch2_check_alloc_info(struct bch_fs *c)
|
||||
{
|
||||
struct btree_trans trans;
|
||||
struct btree_iter iter, discard_iter, freespace_iter;
|
||||
struct bkey_s_c k;
|
||||
int ret = 0;
|
||||
|
||||
bch2_trans_init(&trans, c, 0, 0);
|
||||
@ -884,36 +877,16 @@ int bch2_check_alloc_info(struct bch_fs *c)
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
bch2_trans_iter_init(&trans, &iter, BTREE_ID_need_discard, POS_MIN,
|
||||
BTREE_ITER_PREFETCH);
|
||||
while (1) {
|
||||
ret = commit_do(&trans, NULL, NULL,
|
||||
BTREE_INSERT_NOFAIL|
|
||||
BTREE_INSERT_LAZY_RW,
|
||||
bch2_check_discard_freespace_key(&trans, &iter));
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
bch2_btree_iter_advance(&iter);
|
||||
}
|
||||
bch2_trans_iter_exit(&trans, &iter);
|
||||
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
bch2_trans_iter_init(&trans, &iter, BTREE_ID_freespace, POS_MIN,
|
||||
BTREE_ITER_PREFETCH);
|
||||
while (1) {
|
||||
ret = commit_do(&trans, NULL, NULL,
|
||||
BTREE_INSERT_NOFAIL|
|
||||
BTREE_INSERT_LAZY_RW,
|
||||
bch2_check_discard_freespace_key(&trans, &iter));
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
bch2_btree_iter_advance(&iter);
|
||||
}
|
||||
bch2_trans_iter_exit(&trans, &iter);
|
||||
ret = for_each_btree_key_commit(&trans, iter,
|
||||
BTREE_ID_need_discard, POS_MIN,
|
||||
BTREE_ITER_PREFETCH, k,
|
||||
NULL, NULL, BTREE_INSERT_NOFAIL|BTREE_INSERT_LAZY_RW,
|
||||
bch2_check_discard_freespace_key(&trans, &iter)) ?:
|
||||
for_each_btree_key_commit(&trans, iter,
|
||||
BTREE_ID_freespace, POS_MIN,
|
||||
BTREE_ITER_PREFETCH, k,
|
||||
NULL, NULL, BTREE_INSERT_NOFAIL|BTREE_INSERT_LAZY_RW,
|
||||
bch2_check_discard_freespace_key(&trans, &iter));
|
||||
err:
|
||||
bch2_trans_exit(&trans);
|
||||
return ret < 0 ? ret : 0;
|
||||
@ -1016,17 +989,44 @@ int bch2_check_alloc_to_lru_refs(struct bch_fs *c)
|
||||
return ret < 0 ? ret : 0;
|
||||
}
|
||||
|
||||
static int bch2_clear_need_discard(struct btree_trans *trans, struct bpos pos,
|
||||
struct bch_dev *ca, bool *discard_done)
|
||||
static int bch2_discard_one_bucket(struct btree_trans *trans,
|
||||
struct btree_iter *need_discard_iter,
|
||||
struct bpos *discard_pos_done,
|
||||
u64 *seen,
|
||||
u64 *open,
|
||||
u64 *need_journal_commit,
|
||||
u64 *discarded)
|
||||
{
|
||||
struct bch_fs *c = trans->c;
|
||||
struct btree_iter iter;
|
||||
struct bpos pos = need_discard_iter->pos;
|
||||
struct btree_iter iter = { NULL };
|
||||
struct bkey_s_c k;
|
||||
struct bch_dev *ca;
|
||||
struct bkey_i_alloc_v4 *a;
|
||||
struct printbuf buf = PRINTBUF;
|
||||
int ret;
|
||||
bool did_discard = false;
|
||||
int ret = 0;
|
||||
|
||||
bch2_trans_iter_init(trans, &iter, BTREE_ID_alloc, pos,
|
||||
ca = bch_dev_bkey_exists(c, pos.inode);
|
||||
if (!percpu_ref_tryget(&ca->io_ref)) {
|
||||
bch2_btree_iter_set_pos(need_discard_iter, POS(pos.inode + 1, 0));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (bch2_bucket_is_open_safe(c, pos.inode, pos.offset)) {
|
||||
(*open)++;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (bch2_bucket_needs_journal_commit(&c->buckets_waiting_for_journal,
|
||||
c->journal.flushed_seq_ondisk,
|
||||
pos.inode, pos.offset)) {
|
||||
(*need_journal_commit)++;
|
||||
goto out;
|
||||
}
|
||||
|
||||
bch2_trans_iter_init(trans, &iter, BTREE_ID_alloc,
|
||||
need_discard_iter->pos,
|
||||
BTREE_ITER_CACHED);
|
||||
k = bch2_btree_iter_peek_slot(&iter);
|
||||
ret = bkey_err(k);
|
||||
@ -1062,7 +1062,8 @@ static int bch2_clear_need_discard(struct btree_trans *trans, struct bpos pos,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!*discard_done && ca->mi.discard && !c->opts.nochanges) {
|
||||
if (bkey_cmp(*discard_pos_done, iter.pos) &&
|
||||
ca->mi.discard && !c->opts.nochanges) {
|
||||
/*
|
||||
* This works without any other locks because this is the only
|
||||
* thread that removes items from the need_discard tree
|
||||
@ -1071,20 +1072,32 @@ static int bch2_clear_need_discard(struct btree_trans *trans, struct bpos pos,
|
||||
blkdev_issue_discard(ca->disk_sb.bdev,
|
||||
k.k->p.offset * ca->mi.bucket_size,
|
||||
ca->mi.bucket_size,
|
||||
GFP_KERNEL, 0);
|
||||
*discard_done = true;
|
||||
GFP_KERNEL);
|
||||
|
||||
ret = bch2_trans_relock(trans) ? 0 : -EINTR;
|
||||
ret = bch2_trans_relock(trans);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
*discard_pos_done = iter.pos;
|
||||
did_discard = true;
|
||||
|
||||
SET_BCH_ALLOC_V4_NEED_DISCARD(&a->v, false);
|
||||
a->v.data_type = alloc_data_type(a->v, a->v.data_type);
|
||||
write:
|
||||
ret = bch2_trans_update(trans, &iter, &a->k_i, 0);
|
||||
ret = bch2_trans_update(trans, &iter, &a->k_i, 0) ?:
|
||||
bch2_trans_commit(trans, NULL, NULL,
|
||||
BTREE_INSERT_USE_RESERVE|BTREE_INSERT_NOFAIL);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (did_discard) {
|
||||
this_cpu_inc(c->counters[BCH_COUNTER_bucket_discard]);
|
||||
(*discarded)++;
|
||||
}
|
||||
out:
|
||||
bch2_trans_iter_exit(trans, &iter);
|
||||
percpu_ref_put(&ca->io_ref);
|
||||
printbuf_exit(&buf);
|
||||
return ret;
|
||||
}
|
||||
@ -1092,61 +1105,27 @@ out:
|
||||
static void bch2_do_discards_work(struct work_struct *work)
|
||||
{
|
||||
struct bch_fs *c = container_of(work, struct bch_fs, discard_work);
|
||||
struct bch_dev *ca = NULL;
|
||||
struct btree_trans trans;
|
||||
struct btree_iter iter;
|
||||
struct bkey_s_c k;
|
||||
u64 seen = 0, open = 0, need_journal_commit = 0, discarded = 0;
|
||||
struct bpos discard_pos_done = POS_MAX;
|
||||
int ret;
|
||||
|
||||
bch2_trans_init(&trans, c, 0, 0);
|
||||
|
||||
for_each_btree_key(&trans, iter, BTREE_ID_need_discard,
|
||||
POS_MIN, 0, k, ret) {
|
||||
bool discard_done = false;
|
||||
|
||||
if (ca && k.k->p.inode != ca->dev_idx) {
|
||||
percpu_ref_put(&ca->io_ref);
|
||||
ca = NULL;
|
||||
}
|
||||
|
||||
if (!ca) {
|
||||
ca = bch_dev_bkey_exists(c, k.k->p.inode);
|
||||
if (!percpu_ref_tryget(&ca->io_ref)) {
|
||||
ca = NULL;
|
||||
bch2_btree_iter_set_pos(&iter, POS(k.k->p.inode + 1, 0));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
seen++;
|
||||
|
||||
if (bch2_bucket_is_open_safe(c, k.k->p.inode, k.k->p.offset)) {
|
||||
open++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bch2_bucket_needs_journal_commit(&c->buckets_waiting_for_journal,
|
||||
c->journal.flushed_seq_ondisk,
|
||||
k.k->p.inode, k.k->p.offset)) {
|
||||
need_journal_commit++;
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = commit_do(&trans, NULL, NULL,
|
||||
BTREE_INSERT_USE_RESERVE|
|
||||
BTREE_INSERT_NOFAIL,
|
||||
bch2_clear_need_discard(&trans, k.k->p, ca, &discard_done));
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
this_cpu_inc(c->counters[BCH_COUNTER_bucket_discard]);
|
||||
discarded++;
|
||||
}
|
||||
bch2_trans_iter_exit(&trans, &iter);
|
||||
|
||||
if (ca)
|
||||
percpu_ref_put(&ca->io_ref);
|
||||
/*
|
||||
* We're doing the commit in bch2_discard_one_bucket instead of using
|
||||
* for_each_btree_key_commit() so that we can increment counters after
|
||||
* successful commit:
|
||||
*/
|
||||
ret = for_each_btree_key2(&trans, iter,
|
||||
BTREE_ID_need_discard, POS_MIN, 0, k,
|
||||
bch2_discard_one_bucket(&trans, &iter, &discard_pos_done,
|
||||
&seen,
|
||||
&open,
|
||||
&need_journal_commit,
|
||||
&discarded));
|
||||
|
||||
bch2_trans_exit(&trans);
|
||||
|
||||
@ -1155,7 +1134,8 @@ static void bch2_do_discards_work(struct work_struct *work)
|
||||
|
||||
percpu_ref_put(&c->writes);
|
||||
|
||||
trace_discard_buckets(c, seen, open, need_journal_commit, discarded, ret);
|
||||
trace_discard_buckets(c, seen, open, need_journal_commit, discarded,
|
||||
bch2_err_str(ret));
|
||||
}
|
||||
|
||||
void bch2_do_discards(struct bch_fs *c)
|
||||
@ -1165,29 +1145,20 @@ void bch2_do_discards(struct bch_fs *c)
|
||||
percpu_ref_put(&c->writes);
|
||||
}
|
||||
|
||||
static int invalidate_one_bucket(struct btree_trans *trans, struct bch_dev *ca,
|
||||
struct bpos *bucket_pos, unsigned *cached_sectors)
|
||||
static int invalidate_one_bucket(struct btree_trans *trans,
|
||||
struct btree_iter *lru_iter, struct bkey_s_c k,
|
||||
unsigned dev_idx, s64 *nr_to_invalidate)
|
||||
{
|
||||
struct bch_fs *c = trans->c;
|
||||
struct btree_iter lru_iter, alloc_iter = { NULL };
|
||||
struct bkey_s_c k;
|
||||
struct btree_iter alloc_iter = { NULL };
|
||||
struct bkey_i_alloc_v4 *a;
|
||||
u64 bucket, idx;
|
||||
struct bpos bucket;
|
||||
struct printbuf buf = PRINTBUF;
|
||||
int ret;
|
||||
unsigned cached_sectors;
|
||||
int ret = 0;
|
||||
|
||||
bch2_trans_iter_init(trans, &lru_iter, BTREE_ID_lru,
|
||||
POS(ca->dev_idx, 0), 0);
|
||||
next_lru:
|
||||
k = bch2_btree_iter_peek(&lru_iter);
|
||||
ret = bkey_err(k);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (!k.k || k.k->p.inode != ca->dev_idx) {
|
||||
ret = 1;
|
||||
goto out;
|
||||
}
|
||||
if (*nr_to_invalidate <= 0 || k.k->p.inode != dev_idx)
|
||||
return 1;
|
||||
|
||||
if (k.k->type != KEY_TYPE_lru) {
|
||||
prt_printf(&buf, "non lru key in lru btree:\n ");
|
||||
@ -1195,26 +1166,22 @@ next_lru:
|
||||
|
||||
if (!test_bit(BCH_FS_CHECK_LRUS_DONE, &c->flags)) {
|
||||
bch_err(c, "%s", buf.buf);
|
||||
bch2_btree_iter_advance(&lru_iter);
|
||||
goto next_lru;
|
||||
} else {
|
||||
bch2_trans_inconsistent(trans, "%s", buf.buf);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
idx = k.k->p.offset;
|
||||
bucket = le64_to_cpu(bkey_s_c_to_lru(k).v->idx);
|
||||
bucket = POS(dev_idx, le64_to_cpu(bkey_s_c_to_lru(k).v->idx));
|
||||
|
||||
*bucket_pos = POS(ca->dev_idx, bucket);
|
||||
|
||||
a = bch2_trans_start_alloc_update(trans, &alloc_iter, *bucket_pos);
|
||||
a = bch2_trans_start_alloc_update(trans, &alloc_iter, bucket);
|
||||
ret = PTR_ERR_OR_ZERO(a);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (idx != alloc_lru_idx(a->v)) {
|
||||
if (k.k->p.offset != alloc_lru_idx(a->v)) {
|
||||
prt_printf(&buf, "alloc key does not point back to lru entry when invalidating bucket:\n ");
|
||||
bch2_bkey_val_to_text(&buf, c, bkey_i_to_s_c(&a->k_i));
|
||||
prt_printf(&buf, "\n ");
|
||||
@ -1222,19 +1189,18 @@ next_lru:
|
||||
|
||||
if (!test_bit(BCH_FS_CHECK_LRUS_DONE, &c->flags)) {
|
||||
bch_err(c, "%s", buf.buf);
|
||||
bch2_btree_iter_advance(&lru_iter);
|
||||
goto next_lru;
|
||||
} else {
|
||||
bch2_trans_inconsistent(trans, "%s", buf.buf);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!a->v.cached_sectors)
|
||||
bch_err(c, "invalidating empty bucket, confused");
|
||||
|
||||
*cached_sectors = a->v.cached_sectors;
|
||||
cached_sectors = a->v.cached_sectors;
|
||||
|
||||
SET_BCH_ALLOC_V4_NEED_INC_GEN(&a->v, false);
|
||||
a->v.gen++;
|
||||
@ -1244,13 +1210,18 @@ next_lru:
|
||||
a->v.io_time[READ] = atomic64_read(&c->io_clock[READ].now);
|
||||
a->v.io_time[WRITE] = atomic64_read(&c->io_clock[WRITE].now);
|
||||
|
||||
ret = bch2_trans_update(trans, &alloc_iter, &a->k_i,
|
||||
BTREE_TRIGGER_BUCKET_INVALIDATE);
|
||||
ret = bch2_trans_update(trans, &alloc_iter, &a->k_i,
|
||||
BTREE_TRIGGER_BUCKET_INVALIDATE) ?:
|
||||
bch2_trans_commit(trans, NULL, NULL,
|
||||
BTREE_INSERT_USE_RESERVE|BTREE_INSERT_NOFAIL);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
trace_invalidate_bucket(c, bucket.inode, bucket.offset, cached_sectors);
|
||||
this_cpu_inc(c->counters[BCH_COUNTER_bucket_invalidate]);
|
||||
--*nr_to_invalidate;
|
||||
out:
|
||||
bch2_trans_iter_exit(trans, &alloc_iter);
|
||||
bch2_trans_iter_exit(trans, &lru_iter);
|
||||
printbuf_exit(&buf);
|
||||
return ret;
|
||||
}
|
||||
@ -1260,8 +1231,9 @@ static void bch2_do_invalidates_work(struct work_struct *work)
|
||||
struct bch_fs *c = container_of(work, struct bch_fs, invalidate_work);
|
||||
struct bch_dev *ca;
|
||||
struct btree_trans trans;
|
||||
struct bpos bucket;
|
||||
unsigned i, sectors;
|
||||
struct btree_iter iter;
|
||||
struct bkey_s_c k;
|
||||
unsigned i;
|
||||
int ret = 0;
|
||||
|
||||
bch2_trans_init(&trans, c, 0, 0);
|
||||
@ -1270,17 +1242,13 @@ static void bch2_do_invalidates_work(struct work_struct *work)
|
||||
s64 nr_to_invalidate =
|
||||
should_invalidate_buckets(ca, bch2_dev_usage_read(ca));
|
||||
|
||||
while (nr_to_invalidate-- >= 0) {
|
||||
ret = commit_do(&trans, NULL, NULL,
|
||||
BTREE_INSERT_USE_RESERVE|
|
||||
BTREE_INSERT_NOFAIL,
|
||||
invalidate_one_bucket(&trans, ca, &bucket,
|
||||
§ors));
|
||||
if (ret)
|
||||
break;
|
||||
ret = for_each_btree_key2(&trans, iter, BTREE_ID_lru,
|
||||
POS(ca->dev_idx, 0), BTREE_ITER_INTENT, k,
|
||||
invalidate_one_bucket(&trans, &iter, k, ca->dev_idx, &nr_to_invalidate));
|
||||
|
||||
trace_invalidate_bucket(c, bucket.inode, bucket.offset, sectors);
|
||||
this_cpu_inc(c->counters[BCH_COUNTER_bucket_invalidate]);
|
||||
if (ret < 0) {
|
||||
percpu_ref_put(&ca->ref);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1295,16 +1263,13 @@ void bch2_do_invalidates(struct bch_fs *c)
|
||||
percpu_ref_put(&c->writes);
|
||||
}
|
||||
|
||||
static int bucket_freespace_init(struct btree_trans *trans, struct btree_iter *iter)
|
||||
static int bucket_freespace_init(struct btree_trans *trans, struct btree_iter *iter,
|
||||
struct bkey_s_c k, struct bch_dev *ca)
|
||||
{
|
||||
struct bch_alloc_v4 a;
|
||||
struct bkey_s_c k;
|
||||
int ret;
|
||||
|
||||
k = bch2_btree_iter_peek_slot(iter);
|
||||
ret = bkey_err(k);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (iter->pos.offset >= ca->mi.nbuckets)
|
||||
return 1;
|
||||
|
||||
bch2_alloc_to_v4(k, &a);
|
||||
return bch2_bucket_do_index(trans, k, &a, true);
|
||||
@ -1320,25 +1285,16 @@ static int bch2_dev_freespace_init(struct bch_fs *c, struct bch_dev *ca)
|
||||
|
||||
bch2_trans_init(&trans, c, 0, 0);
|
||||
|
||||
for_each_btree_key(&trans, iter, BTREE_ID_alloc,
|
||||
POS(ca->dev_idx, ca->mi.first_bucket),
|
||||
BTREE_ITER_SLOTS|
|
||||
BTREE_ITER_PREFETCH, k, ret) {
|
||||
if (iter.pos.offset >= ca->mi.nbuckets)
|
||||
break;
|
||||
|
||||
ret = commit_do(&trans, NULL, NULL,
|
||||
BTREE_INSERT_LAZY_RW,
|
||||
bucket_freespace_init(&trans, &iter));
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
bch2_trans_iter_exit(&trans, &iter);
|
||||
ret = for_each_btree_key_commit(&trans, iter, BTREE_ID_alloc,
|
||||
POS(ca->dev_idx, ca->mi.first_bucket),
|
||||
BTREE_ITER_SLOTS|BTREE_ITER_PREFETCH, k,
|
||||
NULL, NULL, BTREE_INSERT_LAZY_RW,
|
||||
bucket_freespace_init(&trans, &iter, k, ca));
|
||||
|
||||
bch2_trans_exit(&trans);
|
||||
|
||||
if (ret) {
|
||||
bch_err(ca, "error initializing free space: %i", ret);
|
||||
if (ret < 0) {
|
||||
bch_err(ca, "error initializing free space: %s", bch2_err_str(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1347,7 +1303,7 @@ static int bch2_dev_freespace_init(struct bch_fs *c, struct bch_dev *ca)
|
||||
SET_BCH_MEMBER_FREESPACE_INITIALIZED(m, true);
|
||||
mutex_unlock(&c->sb_lock);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bch2_fs_freespace_init(struct bch_fs *c)
|
||||
|
@ -150,11 +150,13 @@ void bch2_do_discards(struct bch_fs *);
|
||||
static inline u64 should_invalidate_buckets(struct bch_dev *ca,
|
||||
struct bch_dev_usage u)
|
||||
{
|
||||
u64 free = u.d[BCH_DATA_free].buckets +
|
||||
u.d[BCH_DATA_need_discard].buckets;
|
||||
u64 want_free = ca->mi.nbuckets >> 7;
|
||||
u64 free = max_t(s64, 0,
|
||||
u.d[BCH_DATA_free].buckets
|
||||
+ u.d[BCH_DATA_need_discard].buckets
|
||||
- bch2_dev_buckets_reserved(ca, RESERVE_none));
|
||||
|
||||
return clamp_t(s64, (ca->mi.nbuckets >> 7) - free,
|
||||
0, u.d[BCH_DATA_cached].buckets);
|
||||
return clamp_t(s64, want_free - free, 0, u.d[BCH_DATA_cached].buckets);
|
||||
}
|
||||
|
||||
void bch2_do_invalidates(struct bch_fs *);
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "error.h"
|
||||
#include "io.h"
|
||||
#include "journal.h"
|
||||
#include "movinggc.h"
|
||||
|
||||
#include <linux/math64.h>
|
||||
#include <linux/rculist.h>
|
||||
@ -226,7 +227,7 @@ static struct open_bucket *__try_alloc_bucket(struct bch_fs *c, struct bch_dev *
|
||||
c->blocked_allocate_open_bucket = local_clock();
|
||||
|
||||
spin_unlock(&c->freelist_lock);
|
||||
return ERR_PTR(-OPEN_BUCKETS_EMPTY);
|
||||
return ERR_PTR(-BCH_ERR_open_buckets_empty);
|
||||
}
|
||||
|
||||
/* Recheck under lock: */
|
||||
@ -339,6 +340,7 @@ static struct open_bucket *try_alloc_bucket(struct btree_trans *trans, struct bc
|
||||
skipped_nouse,
|
||||
cl);
|
||||
err:
|
||||
set_btree_iter_dontneed(&iter);
|
||||
bch2_trans_iter_exit(trans, &iter);
|
||||
printbuf_exit(&buf);
|
||||
return ob;
|
||||
@ -395,7 +397,7 @@ bch2_bucket_alloc_trans_early(struct btree_trans *trans,
|
||||
*cur_bucket = max_t(u64, *cur_bucket, ca->mi.first_bucket);
|
||||
*cur_bucket = max_t(u64, *cur_bucket, ca->new_fs_bucket_idx);
|
||||
|
||||
for_each_btree_key(trans, iter, BTREE_ID_alloc, POS(ca->dev_idx, *cur_bucket),
|
||||
for_each_btree_key_norestart(trans, iter, BTREE_ID_alloc, POS(ca->dev_idx, *cur_bucket),
|
||||
BTREE_ITER_SLOTS, k, ret) {
|
||||
struct bch_alloc_v4 a;
|
||||
|
||||
@ -425,7 +427,7 @@ bch2_bucket_alloc_trans_early(struct btree_trans *trans,
|
||||
|
||||
*cur_bucket = iter.pos.offset;
|
||||
|
||||
return ob ?: ERR_PTR(ret ?: -FREELIST_EMPTY);
|
||||
return ob ?: ERR_PTR(ret ?: -BCH_ERR_no_buckets_found);
|
||||
}
|
||||
|
||||
static struct open_bucket *bch2_bucket_alloc_trans(struct btree_trans *trans,
|
||||
@ -454,6 +456,11 @@ static struct open_bucket *bch2_bucket_alloc_trans(struct btree_trans *trans,
|
||||
|
||||
BUG_ON(ca->new_fs_bucket_idx);
|
||||
|
||||
/*
|
||||
* XXX:
|
||||
* On transaction restart, we'd like to restart from the bucket we were
|
||||
* at previously
|
||||
*/
|
||||
for_each_btree_key_norestart(trans, iter, BTREE_ID_freespace,
|
||||
POS(ca->dev_idx, *cur_bucket), 0, k, ret) {
|
||||
if (k.k->p.inode != ca->dev_idx)
|
||||
@ -462,10 +469,9 @@ static struct open_bucket *bch2_bucket_alloc_trans(struct btree_trans *trans,
|
||||
for (*cur_bucket = max(*cur_bucket, bkey_start_offset(k.k));
|
||||
*cur_bucket < k.k->p.offset && !ob;
|
||||
(*cur_bucket)++) {
|
||||
if (btree_trans_too_many_iters(trans)) {
|
||||
ob = ERR_PTR(-EINTR);
|
||||
ret = btree_trans_too_many_iters(trans);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
|
||||
(*buckets_seen)++;
|
||||
|
||||
@ -476,7 +482,8 @@ static struct open_bucket *bch2_bucket_alloc_trans(struct btree_trans *trans,
|
||||
skipped_nouse,
|
||||
k, cl);
|
||||
}
|
||||
if (ob)
|
||||
|
||||
if (ob || ret)
|
||||
break;
|
||||
}
|
||||
bch2_trans_iter_exit(trans, &iter);
|
||||
@ -496,8 +503,10 @@ struct open_bucket *bch2_bucket_alloc(struct bch_fs *c, struct bch_dev *ca,
|
||||
{
|
||||
struct open_bucket *ob = NULL;
|
||||
struct bch_dev_usage usage;
|
||||
bool freespace_initialized = READ_ONCE(ca->mi.freespace_initialized);
|
||||
u64 start = freespace_initialized ? 0 : ca->bucket_alloc_trans_early_cursor;
|
||||
u64 avail;
|
||||
u64 cur_bucket = 0;
|
||||
u64 cur_bucket = start;
|
||||
u64 buckets_seen = 0;
|
||||
u64 skipped_open = 0;
|
||||
u64 skipped_need_journal_commit = 0;
|
||||
@ -506,7 +515,7 @@ struct open_bucket *bch2_bucket_alloc(struct bch_fs *c, struct bch_dev *ca,
|
||||
int ret;
|
||||
again:
|
||||
usage = bch2_dev_usage_read(ca);
|
||||
avail = dev_buckets_free(ca, usage,reserve);
|
||||
avail = dev_buckets_free(ca, usage, reserve);
|
||||
|
||||
if (usage.d[BCH_DATA_need_discard].buckets > avail)
|
||||
bch2_do_discards(c);
|
||||
@ -527,7 +536,7 @@ again:
|
||||
if (!c->blocked_allocate)
|
||||
c->blocked_allocate = local_clock();
|
||||
|
||||
ob = ERR_PTR(-FREELIST_EMPTY);
|
||||
ob = ERR_PTR(-BCH_ERR_freelist_empty);
|
||||
goto err;
|
||||
}
|
||||
|
||||
@ -551,17 +560,30 @@ again:
|
||||
|
||||
if (skipped_need_journal_commit * 2 > avail)
|
||||
bch2_journal_flush_async(&c->journal, NULL);
|
||||
|
||||
if (!ob && !ret && !freespace_initialized && start) {
|
||||
start = cur_bucket = 0;
|
||||
goto again;
|
||||
}
|
||||
|
||||
if (!freespace_initialized)
|
||||
ca->bucket_alloc_trans_early_cursor = cur_bucket;
|
||||
err:
|
||||
if (!ob)
|
||||
ob = ERR_PTR(ret ?: -FREELIST_EMPTY);
|
||||
ob = ERR_PTR(ret ?: -BCH_ERR_no_buckets_found);
|
||||
|
||||
if (IS_ERR(ob)) {
|
||||
trace_bucket_alloc_fail(ca, bch2_alloc_reserves[reserve], avail,
|
||||
trace_bucket_alloc_fail(ca, bch2_alloc_reserves[reserve],
|
||||
usage.d[BCH_DATA_free].buckets,
|
||||
avail,
|
||||
bch2_copygc_wait_amount(c),
|
||||
c->copygc_wait - atomic64_read(&c->io_clock[WRITE].now),
|
||||
buckets_seen,
|
||||
skipped_open,
|
||||
skipped_need_journal_commit,
|
||||
skipped_nouse,
|
||||
cl == NULL, PTR_ERR(ob));
|
||||
cl == NULL,
|
||||
bch2_err_str(PTR_ERR(ob)));
|
||||
atomic_long_inc(&c->bucket_alloc_fail);
|
||||
}
|
||||
|
||||
@ -648,7 +670,7 @@ int bch2_bucket_alloc_set(struct bch_fs *c,
|
||||
bch2_dev_alloc_list(c, stripe, devs_may_alloc);
|
||||
unsigned dev;
|
||||
struct bch_dev *ca;
|
||||
int ret = -INSUFFICIENT_DEVICES;
|
||||
int ret = -BCH_ERR_insufficient_devices;
|
||||
unsigned i;
|
||||
|
||||
BUG_ON(*nr_effective >= nr_replicas);
|
||||
@ -846,8 +868,8 @@ static int open_bucket_add_buckets(struct bch_fs *c,
|
||||
target, erasure_code,
|
||||
nr_replicas, nr_effective,
|
||||
have_cache, flags, _cl);
|
||||
if (ret == -FREELIST_EMPTY ||
|
||||
ret == -OPEN_BUCKETS_EMPTY)
|
||||
if (bch2_err_matches(ret, BCH_ERR_freelist_empty) ||
|
||||
bch2_err_matches(ret, BCH_ERR_open_buckets_empty))
|
||||
return ret;
|
||||
if (*nr_effective >= nr_replicas)
|
||||
return 0;
|
||||
@ -868,7 +890,9 @@ retry_blocking:
|
||||
ret = bch2_bucket_alloc_set(c, ptrs, &wp->stripe, &devs,
|
||||
nr_replicas, nr_effective, have_cache,
|
||||
reserve, flags, cl);
|
||||
if (ret && ret != -INSUFFICIENT_DEVICES && !cl && _cl) {
|
||||
if (ret &&
|
||||
!bch2_err_matches(ret, BCH_ERR_insufficient_devices) &&
|
||||
!cl && _cl) {
|
||||
cl = _cl;
|
||||
goto retry_blocking;
|
||||
}
|
||||
@ -1111,7 +1135,7 @@ alloc_done:
|
||||
if (erasure_code && !ec_open_bucket(c, &ptrs))
|
||||
pr_debug("failed to get ec bucket: ret %u", ret);
|
||||
|
||||
if (ret == -INSUFFICIENT_DEVICES &&
|
||||
if (ret == -BCH_ERR_insufficient_devices &&
|
||||
nr_effective >= nr_replicas_required)
|
||||
ret = 0;
|
||||
|
||||
@ -1142,19 +1166,18 @@ err:
|
||||
|
||||
mutex_unlock(&wp->lock);
|
||||
|
||||
if (ret == -FREELIST_EMPTY &&
|
||||
if (bch2_err_matches(ret, BCH_ERR_freelist_empty) &&
|
||||
try_decrease_writepoints(c, write_points_nr))
|
||||
goto retry;
|
||||
|
||||
switch (ret) {
|
||||
case -OPEN_BUCKETS_EMPTY:
|
||||
case -FREELIST_EMPTY:
|
||||
if (bch2_err_matches(ret, BCH_ERR_open_buckets_empty) ||
|
||||
bch2_err_matches(ret, BCH_ERR_freelist_empty))
|
||||
return cl ? ERR_PTR(-EAGAIN) : ERR_PTR(-ENOSPC);
|
||||
case -INSUFFICIENT_DEVICES:
|
||||
|
||||
if (bch2_err_matches(ret, BCH_ERR_insufficient_devices))
|
||||
return ERR_PTR(-EROFS);
|
||||
default:
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
struct bch_extent_ptr bch2_ob_ptr(struct bch_fs *c, struct open_bucket *ob)
|
||||
|
@ -443,8 +443,8 @@ int bch2_get_next_backpointer(struct btree_trans *trans,
|
||||
goto out;
|
||||
}
|
||||
|
||||
for_each_btree_key(trans, bp_iter, BTREE_ID_backpointers,
|
||||
bp_pos, 0, k, ret) {
|
||||
for_each_btree_key_norestart(trans, bp_iter, BTREE_ID_backpointers,
|
||||
bp_pos, 0, k, ret) {
|
||||
if (bpos_cmp(k.k->p, bp_end_pos) >= 0)
|
||||
break;
|
||||
|
||||
@ -569,22 +569,16 @@ struct btree *bch2_backpointer_get_node(struct btree_trans *trans,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int bch2_check_btree_backpointer(struct btree_trans *trans, struct btree_iter *bp_iter)
|
||||
static int bch2_check_btree_backpointer(struct btree_trans *trans, struct btree_iter *bp_iter,
|
||||
struct bkey_s_c k)
|
||||
{
|
||||
struct bch_fs *c = trans->c;
|
||||
struct btree_iter alloc_iter = { NULL };
|
||||
struct bch_dev *ca;
|
||||
struct bkey_s_c k, alloc_k;
|
||||
struct bkey_s_c alloc_k;
|
||||
struct printbuf buf = PRINTBUF;
|
||||
int ret = 0;
|
||||
|
||||
k = bch2_btree_iter_peek(bp_iter);
|
||||
ret = bkey_err(k);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (!k.k)
|
||||
return 0;
|
||||
|
||||
if (fsck_err_on(!bch2_dev_exists2(c, k.k->p.inode), c,
|
||||
"backpointer for mising device:\n%s",
|
||||
(bch2_bkey_val_to_text(&buf, c, k), buf.buf))) {
|
||||
@ -619,25 +613,14 @@ fsck_err:
|
||||
/* verify that every backpointer has a corresponding alloc key */
|
||||
int bch2_check_btree_backpointers(struct bch_fs *c)
|
||||
{
|
||||
struct btree_trans trans;
|
||||
struct btree_iter iter;
|
||||
int ret = 0;
|
||||
struct bkey_s_c k;
|
||||
|
||||
bch2_trans_init(&trans, c, 0, 0);
|
||||
bch2_trans_iter_init(&trans, &iter, BTREE_ID_backpointers, POS_MIN, 0);
|
||||
|
||||
do {
|
||||
ret = commit_do(&trans, NULL, NULL,
|
||||
BTREE_INSERT_LAZY_RW|
|
||||
BTREE_INSERT_NOFAIL,
|
||||
bch2_check_btree_backpointer(&trans, &iter));
|
||||
if (ret)
|
||||
break;
|
||||
} while (bch2_btree_iter_advance(&iter));
|
||||
|
||||
bch2_trans_iter_exit(&trans, &iter);
|
||||
bch2_trans_exit(&trans);
|
||||
return ret;
|
||||
return bch2_trans_run(c,
|
||||
for_each_btree_key_commit(&trans, iter,
|
||||
BTREE_ID_backpointers, POS_MIN, 0, k,
|
||||
NULL, NULL, BTREE_INSERT_LAZY_RW|BTREE_INSERT_NOFAIL,
|
||||
bch2_check_btree_backpointer(&trans, &iter, k)));
|
||||
}
|
||||
|
||||
static int check_bp_exists(struct btree_trans *trans,
|
||||
|
@ -319,6 +319,8 @@ BCH_DEBUG_PARAMS_DEBUG()
|
||||
#undef BCH_DEBUG_PARAM
|
||||
#endif
|
||||
|
||||
#define BCH_LOCK_TIME_NR 128
|
||||
|
||||
#define BCH_TIME_STATS() \
|
||||
x(btree_node_mem_alloc) \
|
||||
x(btree_node_split) \
|
||||
@ -463,6 +465,7 @@ struct bch_dev {
|
||||
|
||||
/* Allocator: */
|
||||
u64 new_fs_bucket_idx;
|
||||
u64 bucket_alloc_trans_early_cursor;
|
||||
|
||||
unsigned nr_open_buckets;
|
||||
unsigned nr_btree_reserve;
|
||||
@ -528,6 +531,11 @@ struct btree_debug {
|
||||
unsigned id;
|
||||
};
|
||||
|
||||
struct lock_held_stats {
|
||||
struct time_stats times[BCH_LOCK_TIME_NR];
|
||||
const char *names[BCH_LOCK_TIME_NR];
|
||||
};
|
||||
|
||||
struct bch_fs_pcpu {
|
||||
u64 sectors_available;
|
||||
};
|
||||
@ -921,6 +929,8 @@ struct bch_fs {
|
||||
bool promote_whole_extents;
|
||||
|
||||
struct time_stats times[BCH_TIME_STAT_NR];
|
||||
|
||||
struct lock_held_stats lock_held_stats;
|
||||
};
|
||||
|
||||
static inline void bch2_set_ra_pages(struct bch_fs *c, unsigned ra_pages)
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "btree_iter.h"
|
||||
#include "btree_locking.h"
|
||||
#include "debug.h"
|
||||
#include "errcode.h"
|
||||
#include "error.h"
|
||||
|
||||
#include <linux/prefetch.h>
|
||||
@ -700,20 +701,16 @@ static noinline struct btree *bch2_btree_node_fill(struct bch_fs *c,
|
||||
* been freed:
|
||||
*/
|
||||
if (trans && !bch2_btree_node_relock(trans, path, level + 1)) {
|
||||
trace_trans_restart_relock_parent_for_fill(trans->fn,
|
||||
_THIS_IP_, btree_id, &path->pos);
|
||||
btree_trans_restart(trans);
|
||||
return ERR_PTR(-EINTR);
|
||||
trace_trans_restart_relock_parent_for_fill(trans, _THIS_IP_, path);
|
||||
return ERR_PTR(btree_trans_restart(trans, BCH_ERR_transaction_restart_fill_relock));
|
||||
}
|
||||
|
||||
b = bch2_btree_node_mem_alloc(c, level != 0);
|
||||
|
||||
if (trans && b == ERR_PTR(-ENOMEM)) {
|
||||
trans->memory_allocation_failure = true;
|
||||
trace_trans_restart_memory_allocation_failure(trans->fn,
|
||||
_THIS_IP_, btree_id, &path->pos);
|
||||
btree_trans_restart(trans);
|
||||
return ERR_PTR(-EINTR);
|
||||
trace_trans_restart_memory_allocation_failure(trans, _THIS_IP_, path);
|
||||
return ERR_PTR(btree_trans_restart(trans, BCH_ERR_transaction_restart_fill_mem_alloc_fail));
|
||||
}
|
||||
|
||||
if (IS_ERR(b))
|
||||
@ -750,18 +747,19 @@ static noinline struct btree *bch2_btree_node_fill(struct bch_fs *c,
|
||||
if (!sync)
|
||||
return NULL;
|
||||
|
||||
if (trans &&
|
||||
(!bch2_trans_relock(trans) ||
|
||||
!bch2_btree_path_relock_intent(trans, path))) {
|
||||
BUG_ON(!trans->restarted);
|
||||
return ERR_PTR(-EINTR);
|
||||
if (trans) {
|
||||
int ret = bch2_trans_relock(trans) ?:
|
||||
bch2_btree_path_relock_intent(trans, path);
|
||||
if (ret) {
|
||||
BUG_ON(!trans->restarted);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
}
|
||||
|
||||
if (!six_relock_type(&b->c.lock, lock_type, seq)) {
|
||||
trace_trans_restart_relock_after_fill(trans->fn, _THIS_IP_,
|
||||
btree_id, &path->pos);
|
||||
btree_trans_restart(trans);
|
||||
return ERR_PTR(-EINTR);
|
||||
if (trans)
|
||||
trace_trans_restart_relock_after_fill(trans, _THIS_IP_, path);
|
||||
return ERR_PTR(btree_trans_restart(trans, BCH_ERR_transaction_restart_relock_after_fill));
|
||||
}
|
||||
|
||||
return b;
|
||||
@ -772,7 +770,9 @@ static int lock_node_check_fn(struct six_lock *lock, void *p)
|
||||
struct btree *b = container_of(lock, struct btree, c.lock);
|
||||
const struct bkey_i *k = p;
|
||||
|
||||
return b->hash_val == btree_ptr_hash_val(k) ? 0 : -1;
|
||||
if (b->hash_val != btree_ptr_hash_val(k))
|
||||
return BCH_ERR_lock_fail_node_reused;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static noinline void btree_bad_header(struct bch_fs *c, struct btree *b)
|
||||
@ -831,6 +831,7 @@ struct btree *bch2_btree_node_get(struct btree_trans *trans, struct btree_path *
|
||||
struct btree_cache *bc = &c->btree_cache;
|
||||
struct btree *b;
|
||||
struct bset_tree *t;
|
||||
int ret;
|
||||
|
||||
EBUG_ON(level >= BTREE_MAX_DEPTH);
|
||||
|
||||
@ -893,13 +894,16 @@ lock_node:
|
||||
* was removed - and we'll bail out:
|
||||
*/
|
||||
if (btree_node_read_locked(path, level + 1))
|
||||
btree_node_unlock(path, level + 1);
|
||||
btree_node_unlock(trans, path, level + 1);
|
||||
|
||||
if (!btree_node_lock(trans, path, b, k->k.p, level, lock_type,
|
||||
lock_node_check_fn, (void *) k, trace_ip)) {
|
||||
if (!trans->restarted)
|
||||
ret = btree_node_lock(trans, path, b, k->k.p, level, lock_type,
|
||||
lock_node_check_fn, (void *) k, trace_ip);
|
||||
if (unlikely(ret)) {
|
||||
if (bch2_err_matches(ret, BCH_ERR_lock_fail_node_reused))
|
||||
goto retry;
|
||||
return ERR_PTR(-EINTR);
|
||||
if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
|
||||
return ERR_PTR(ret);
|
||||
BUG();
|
||||
}
|
||||
|
||||
if (unlikely(b->hash_val != btree_ptr_hash_val(k) ||
|
||||
@ -909,12 +913,8 @@ lock_node:
|
||||
if (bch2_btree_node_relock(trans, path, level + 1))
|
||||
goto retry;
|
||||
|
||||
trace_trans_restart_btree_node_reused(trans->fn,
|
||||
trace_ip,
|
||||
path->btree_id,
|
||||
&path->pos);
|
||||
btree_trans_restart(trans);
|
||||
return ERR_PTR(-EINTR);
|
||||
trace_trans_restart_btree_node_reused(trans, trace_ip, path);
|
||||
return ERR_PTR(btree_trans_restart(trans, BCH_ERR_transaction_restart_lock_node_reused));
|
||||
}
|
||||
}
|
||||
|
||||
@ -930,11 +930,13 @@ lock_node:
|
||||
* should_be_locked is not set on this path yet, so we need to
|
||||
* relock it specifically:
|
||||
*/
|
||||
if (trans &&
|
||||
(!bch2_trans_relock(trans) ||
|
||||
!bch2_btree_path_relock_intent(trans, path))) {
|
||||
BUG_ON(!trans->restarted);
|
||||
return ERR_PTR(-EINTR);
|
||||
if (trans) {
|
||||
int ret = bch2_trans_relock(trans) ?:
|
||||
bch2_btree_path_relock_intent(trans, path);
|
||||
if (ret) {
|
||||
BUG_ON(!trans->restarted);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
}
|
||||
|
||||
if (!six_relock_type(&b->c.lock, lock_type, seq))
|
||||
|
@ -98,7 +98,7 @@ static int bch2_gc_check_topology(struct bch_fs *c,
|
||||
buf1.buf, buf2.buf) &&
|
||||
!test_bit(BCH_FS_TOPOLOGY_REPAIR_DONE, &c->flags)) {
|
||||
bch_info(c, "Halting mark and sweep to start topology repair pass");
|
||||
ret = FSCK_ERR_START_TOPOLOGY_REPAIR;
|
||||
ret = -BCH_ERR_need_topology_repair;
|
||||
goto err;
|
||||
} else {
|
||||
set_bit(BCH_FS_INITIAL_GC_UNFIXED, &c->flags);
|
||||
@ -126,7 +126,7 @@ static int bch2_gc_check_topology(struct bch_fs *c,
|
||||
buf1.buf, buf2.buf) &&
|
||||
!test_bit(BCH_FS_TOPOLOGY_REPAIR_DONE, &c->flags)) {
|
||||
bch_info(c, "Halting mark and sweep to start topology repair pass");
|
||||
ret = FSCK_ERR_START_TOPOLOGY_REPAIR;
|
||||
ret = -BCH_ERR_need_topology_repair;
|
||||
goto err;
|
||||
} else {
|
||||
set_bit(BCH_FS_INITIAL_GC_UNFIXED, &c->flags);
|
||||
@ -402,8 +402,8 @@ again:
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
bch_err(c, "%s: error %i getting btree node",
|
||||
__func__, ret);
|
||||
bch_err(c, "%s: error getting btree node: %s",
|
||||
__func__, bch2_err_str(ret));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -471,8 +471,8 @@ again:
|
||||
ret = PTR_ERR_OR_ZERO(cur);
|
||||
|
||||
if (ret) {
|
||||
bch_err(c, "%s: error %i getting btree node",
|
||||
__func__, ret);
|
||||
bch_err(c, "%s: error getting btree node: %s",
|
||||
__func__, bch2_err_str(ret));
|
||||
goto err;
|
||||
}
|
||||
|
||||
@ -537,7 +537,7 @@ static int bch2_repair_topology(struct bch_fs *c)
|
||||
|
||||
if (ret == DROP_THIS_NODE) {
|
||||
bch_err(c, "empty btree root - repair unimplemented");
|
||||
ret = FSCK_ERR_EXIT;
|
||||
ret = -BCH_ERR_fsck_repair_unimplemented;
|
||||
}
|
||||
}
|
||||
|
||||
@ -804,7 +804,7 @@ static int bch2_gc_mark_key(struct btree_trans *trans, enum btree_id btree_id,
|
||||
fsck_err:
|
||||
err:
|
||||
if (ret)
|
||||
bch_err(c, "%s: ret %i", __func__, ret);
|
||||
bch_err(c, "error from %s(): %s", __func__, bch2_err_str(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -910,7 +910,8 @@ static int bch2_gc_btree_init_recurse(struct btree_trans *trans, struct btree *b
|
||||
ret = bch2_gc_mark_key(trans, b->c.btree_id, b->c.level,
|
||||
false, &k, true);
|
||||
if (ret) {
|
||||
bch_err(c, "%s: error %i from bch2_gc_mark_key", __func__, ret);
|
||||
bch_err(c, "%s: error from bch2_gc_mark_key: %s",
|
||||
__func__, bch2_err_str(ret));
|
||||
goto fsck_err;
|
||||
}
|
||||
|
||||
@ -959,7 +960,7 @@ static int bch2_gc_btree_init_recurse(struct btree_trans *trans, struct btree *b
|
||||
(printbuf_reset(&buf),
|
||||
bch2_bkey_val_to_text(&buf, c, bkey_i_to_s_c(cur.k)), buf.buf)) &&
|
||||
!test_bit(BCH_FS_TOPOLOGY_REPAIR_DONE, &c->flags)) {
|
||||
ret = FSCK_ERR_START_TOPOLOGY_REPAIR;
|
||||
ret = -BCH_ERR_need_topology_repair;
|
||||
bch_info(c, "Halting mark and sweep to start topology repair pass");
|
||||
goto fsck_err;
|
||||
} else {
|
||||
@ -970,8 +971,8 @@ static int bch2_gc_btree_init_recurse(struct btree_trans *trans, struct btree *b
|
||||
continue;
|
||||
}
|
||||
} else if (ret) {
|
||||
bch_err(c, "%s: error %i getting btree node",
|
||||
__func__, ret);
|
||||
bch_err(c, "%s: error getting btree node: %s",
|
||||
__func__, bch2_err_str(ret));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1012,7 +1013,7 @@ static int bch2_gc_btree_init(struct btree_trans *trans,
|
||||
if (mustfix_fsck_err_on(bpos_cmp(b->data->min_key, POS_MIN), c,
|
||||
"btree root with incorrect min_key: %s", buf.buf)) {
|
||||
bch_err(c, "repair unimplemented");
|
||||
ret = FSCK_ERR_EXIT;
|
||||
ret = -BCH_ERR_fsck_repair_unimplemented;
|
||||
goto fsck_err;
|
||||
}
|
||||
|
||||
@ -1021,7 +1022,7 @@ static int bch2_gc_btree_init(struct btree_trans *trans,
|
||||
if (mustfix_fsck_err_on(bpos_cmp(b->data->max_key, SPOS_MAX), c,
|
||||
"btree root with incorrect max_key: %s", buf.buf)) {
|
||||
bch_err(c, "repair unimplemented");
|
||||
ret = FSCK_ERR_EXIT;
|
||||
ret = -BCH_ERR_fsck_repair_unimplemented;
|
||||
goto fsck_err;
|
||||
}
|
||||
|
||||
@ -1038,7 +1039,7 @@ fsck_err:
|
||||
six_unlock_read(&b->c.lock);
|
||||
|
||||
if (ret < 0)
|
||||
bch_err(c, "%s: ret %i", __func__, ret);
|
||||
bch_err(c, "error from %s(): %s", __func__, bch2_err_str(ret));
|
||||
printbuf_exit(&buf);
|
||||
return ret;
|
||||
}
|
||||
@ -1071,7 +1072,7 @@ static int bch2_gc_btrees(struct bch_fs *c, bool initial, bool metadata_only)
|
||||
: bch2_gc_btree(&trans, ids[i], initial, metadata_only);
|
||||
|
||||
if (ret < 0)
|
||||
bch_err(c, "%s: ret %i", __func__, ret);
|
||||
bch_err(c, "error from %s(): %s", __func__, bch2_err_str(ret));
|
||||
|
||||
bch2_trans_exit(&trans);
|
||||
return ret;
|
||||
@ -1269,7 +1270,7 @@ fsck_err:
|
||||
if (ca)
|
||||
percpu_ref_put(&ca->ref);
|
||||
if (ret)
|
||||
bch_err(c, "%s: ret %i", __func__, ret);
|
||||
bch_err(c, "error from %s(): %s", __func__, bch2_err_str(ret));
|
||||
|
||||
percpu_up_write(&c->mark_lock);
|
||||
printbuf_exit(&buf);
|
||||
@ -1324,21 +1325,19 @@ static inline bool bch2_alloc_v4_cmp(struct bch_alloc_v4 l,
|
||||
|
||||
static int bch2_alloc_write_key(struct btree_trans *trans,
|
||||
struct btree_iter *iter,
|
||||
struct bkey_s_c k,
|
||||
bool metadata_only)
|
||||
{
|
||||
struct bch_fs *c = trans->c;
|
||||
struct bch_dev *ca = bch_dev_bkey_exists(c, iter->pos.inode);
|
||||
struct bucket gc, *b;
|
||||
struct bkey_s_c k;
|
||||
struct bkey_i_alloc_v4 *a;
|
||||
struct bch_alloc_v4 old, new;
|
||||
enum bch_data_type type;
|
||||
int ret;
|
||||
|
||||
k = bch2_btree_iter_peek_slot(iter);
|
||||
ret = bkey_err(k);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (bkey_cmp(iter->pos, POS(ca->dev_idx, ca->mi.nbuckets)) >= 0)
|
||||
return 1;
|
||||
|
||||
bch2_alloc_to_v4(k, &old);
|
||||
new = old;
|
||||
@ -1431,31 +1430,21 @@ static int bch2_gc_alloc_done(struct bch_fs *c, bool metadata_only)
|
||||
bch2_trans_init(&trans, c, 0, 0);
|
||||
|
||||
for_each_member_device(ca, c, i) {
|
||||
for_each_btree_key(&trans, iter, BTREE_ID_alloc,
|
||||
POS(ca->dev_idx, ca->mi.first_bucket),
|
||||
BTREE_ITER_SLOTS|
|
||||
BTREE_ITER_PREFETCH, k, ret) {
|
||||
if (bkey_cmp(iter.pos, POS(ca->dev_idx, ca->mi.nbuckets)) >= 0)
|
||||
break;
|
||||
ret = for_each_btree_key_commit(&trans, iter, BTREE_ID_alloc,
|
||||
POS(ca->dev_idx, ca->mi.first_bucket),
|
||||
BTREE_ITER_SLOTS|BTREE_ITER_PREFETCH, k,
|
||||
NULL, NULL, BTREE_INSERT_LAZY_RW,
|
||||
bch2_alloc_write_key(&trans, &iter, k, metadata_only));
|
||||
|
||||
ret = commit_do(&trans, NULL, NULL,
|
||||
BTREE_INSERT_LAZY_RW,
|
||||
bch2_alloc_write_key(&trans, &iter,
|
||||
metadata_only));
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
bch2_trans_iter_exit(&trans, &iter);
|
||||
|
||||
if (ret) {
|
||||
bch_err(c, "error writing alloc info: %i", ret);
|
||||
if (ret < 0) {
|
||||
bch_err(c, "error writing alloc info: %s", bch2_err_str(ret));
|
||||
percpu_ref_put(&ca->ref);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bch2_trans_exit(&trans);
|
||||
return ret;
|
||||
return ret < 0 ? ret : 0;
|
||||
}
|
||||
|
||||
static int bch2_gc_alloc_start(struct bch_fs *c, bool metadata_only)
|
||||
@ -1512,7 +1501,7 @@ static int bch2_gc_alloc_start(struct bch_fs *c, bool metadata_only)
|
||||
bch2_trans_exit(&trans);
|
||||
|
||||
if (ret)
|
||||
bch_err(c, "error reading alloc info at gc start: %i", ret);
|
||||
bch_err(c, "error reading alloc info at gc start: %s", bch2_err_str(ret));
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -1539,14 +1528,64 @@ static void bch2_gc_alloc_reset(struct bch_fs *c, bool metadata_only)
|
||||
};
|
||||
}
|
||||
|
||||
static int bch2_gc_write_reflink_key(struct btree_trans *trans,
|
||||
struct btree_iter *iter,
|
||||
struct bkey_s_c k,
|
||||
size_t *idx)
|
||||
{
|
||||
struct bch_fs *c = trans->c;
|
||||
const __le64 *refcount = bkey_refcount_c(k);
|
||||
struct printbuf buf = PRINTBUF;
|
||||
struct reflink_gc *r;
|
||||
int ret = 0;
|
||||
|
||||
if (!refcount)
|
||||
return 0;
|
||||
|
||||
while ((r = genradix_ptr(&c->reflink_gc_table, *idx)) &&
|
||||
r->offset < k.k->p.offset)
|
||||
++*idx;
|
||||
|
||||
if (!r ||
|
||||
r->offset != k.k->p.offset ||
|
||||
r->size != k.k->size) {
|
||||
bch_err(c, "unexpected inconsistency walking reflink table at gc finish");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (fsck_err_on(r->refcount != le64_to_cpu(*refcount), c,
|
||||
"reflink key has wrong refcount:\n"
|
||||
" %s\n"
|
||||
" should be %u",
|
||||
(bch2_bkey_val_to_text(&buf, c, k), buf.buf),
|
||||
r->refcount)) {
|
||||
struct bkey_i *new;
|
||||
|
||||
new = bch2_trans_kmalloc(trans, bkey_bytes(k.k));
|
||||
ret = PTR_ERR_OR_ZERO(new);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
bkey_reassemble(new, k);
|
||||
|
||||
if (!r->refcount)
|
||||
new->k.type = KEY_TYPE_deleted;
|
||||
else
|
||||
*bkey_refcount(new) = cpu_to_le64(r->refcount);
|
||||
|
||||
ret = bch2_trans_update(trans, iter, new, 0);
|
||||
}
|
||||
fsck_err:
|
||||
printbuf_exit(&buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bch2_gc_reflink_done(struct bch_fs *c, bool metadata_only)
|
||||
{
|
||||
struct btree_trans trans;
|
||||
struct btree_iter iter;
|
||||
struct bkey_s_c k;
|
||||
struct reflink_gc *r;
|
||||
size_t idx = 0;
|
||||
struct printbuf buf = PRINTBUF;
|
||||
int ret = 0;
|
||||
|
||||
if (metadata_only)
|
||||
@ -1554,57 +1593,14 @@ static int bch2_gc_reflink_done(struct bch_fs *c, bool metadata_only)
|
||||
|
||||
bch2_trans_init(&trans, c, 0, 0);
|
||||
|
||||
for_each_btree_key(&trans, iter, BTREE_ID_reflink, POS_MIN,
|
||||
BTREE_ITER_PREFETCH, k, ret) {
|
||||
const __le64 *refcount = bkey_refcount_c(k);
|
||||
ret = for_each_btree_key_commit(&trans, iter,
|
||||
BTREE_ID_reflink, POS_MIN,
|
||||
BTREE_ITER_PREFETCH, k,
|
||||
NULL, NULL, BTREE_INSERT_NOFAIL,
|
||||
bch2_gc_write_reflink_key(&trans, &iter, k, &idx));
|
||||
|
||||
if (!refcount)
|
||||
continue;
|
||||
|
||||
r = genradix_ptr(&c->reflink_gc_table, idx++);
|
||||
if (!r ||
|
||||
r->offset != k.k->p.offset ||
|
||||
r->size != k.k->size) {
|
||||
bch_err(c, "unexpected inconsistency walking reflink table at gc finish");
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (fsck_err_on(r->refcount != le64_to_cpu(*refcount), c,
|
||||
"reflink key has wrong refcount:\n"
|
||||
" %s\n"
|
||||
" should be %u",
|
||||
(printbuf_reset(&buf),
|
||||
bch2_bkey_val_to_text(&buf, c, k), buf.buf),
|
||||
r->refcount)) {
|
||||
struct bkey_i *new;
|
||||
|
||||
new = kmalloc(bkey_bytes(k.k), GFP_KERNEL);
|
||||
if (!new) {
|
||||
ret = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
|
||||
bkey_reassemble(new, k);
|
||||
|
||||
if (!r->refcount)
|
||||
new->k.type = KEY_TYPE_deleted;
|
||||
else
|
||||
*bkey_refcount(new) = cpu_to_le64(r->refcount);
|
||||
|
||||
ret = commit_do(&trans, NULL, NULL, 0,
|
||||
__bch2_btree_insert(&trans, BTREE_ID_reflink, new));
|
||||
kfree(new);
|
||||
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
}
|
||||
fsck_err:
|
||||
bch2_trans_iter_exit(&trans, &iter);
|
||||
c->reflink_gc_nr = 0;
|
||||
bch2_trans_exit(&trans);
|
||||
printbuf_exit(&buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1656,15 +1652,59 @@ static void bch2_gc_reflink_reset(struct bch_fs *c, bool metadata_only)
|
||||
r->refcount = 0;
|
||||
}
|
||||
|
||||
static int bch2_gc_write_stripes_key(struct btree_trans *trans,
|
||||
struct btree_iter *iter,
|
||||
struct bkey_s_c k)
|
||||
{
|
||||
struct bch_fs *c = trans->c;
|
||||
struct printbuf buf = PRINTBUF;
|
||||
const struct bch_stripe *s;
|
||||
struct gc_stripe *m;
|
||||
unsigned i;
|
||||
int ret = 0;
|
||||
|
||||
if (k.k->type != KEY_TYPE_stripe)
|
||||
return 0;
|
||||
|
||||
s = bkey_s_c_to_stripe(k).v;
|
||||
m = genradix_ptr(&c->gc_stripes, k.k->p.offset);
|
||||
|
||||
for (i = 0; i < s->nr_blocks; i++)
|
||||
if (stripe_blockcount_get(s, i) != (m ? m->block_sectors[i] : 0))
|
||||
goto inconsistent;
|
||||
return 0;
|
||||
inconsistent:
|
||||
if (fsck_err_on(true, c,
|
||||
"stripe has wrong block sector count %u:\n"
|
||||
" %s\n"
|
||||
" should be %u", i,
|
||||
(printbuf_reset(&buf),
|
||||
bch2_bkey_val_to_text(&buf, c, k), buf.buf),
|
||||
m ? m->block_sectors[i] : 0)) {
|
||||
struct bkey_i_stripe *new;
|
||||
|
||||
new = bch2_trans_kmalloc(trans, bkey_bytes(k.k));
|
||||
ret = PTR_ERR_OR_ZERO(new);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
bkey_reassemble(&new->k_i, k);
|
||||
|
||||
for (i = 0; i < new->v.nr_blocks; i++)
|
||||
stripe_blockcount_set(&new->v, i, m ? m->block_sectors[i] : 0);
|
||||
|
||||
ret = bch2_trans_update(trans, iter, &new->k_i, 0);
|
||||
}
|
||||
fsck_err:
|
||||
printbuf_exit(&buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bch2_gc_stripes_done(struct bch_fs *c, bool metadata_only)
|
||||
{
|
||||
struct btree_trans trans;
|
||||
struct btree_iter iter;
|
||||
struct bkey_s_c k;
|
||||
struct gc_stripe *m;
|
||||
const struct bch_stripe *s;
|
||||
struct printbuf buf = PRINTBUF;
|
||||
unsigned i;
|
||||
int ret = 0;
|
||||
|
||||
if (metadata_only)
|
||||
@ -1672,50 +1712,13 @@ static int bch2_gc_stripes_done(struct bch_fs *c, bool metadata_only)
|
||||
|
||||
bch2_trans_init(&trans, c, 0, 0);
|
||||
|
||||
for_each_btree_key(&trans, iter, BTREE_ID_stripes, POS_MIN,
|
||||
BTREE_ITER_PREFETCH, k, ret) {
|
||||
if (k.k->type != KEY_TYPE_stripe)
|
||||
continue;
|
||||
|
||||
s = bkey_s_c_to_stripe(k).v;
|
||||
m = genradix_ptr(&c->gc_stripes, k.k->p.offset);
|
||||
|
||||
for (i = 0; i < s->nr_blocks; i++)
|
||||
if (stripe_blockcount_get(s, i) != (m ? m->block_sectors[i] : 0))
|
||||
goto inconsistent;
|
||||
continue;
|
||||
inconsistent:
|
||||
if (fsck_err_on(true, c,
|
||||
"stripe has wrong block sector count %u:\n"
|
||||
" %s\n"
|
||||
" should be %u", i,
|
||||
(printbuf_reset(&buf),
|
||||
bch2_bkey_val_to_text(&buf, c, k), buf.buf),
|
||||
m ? m->block_sectors[i] : 0)) {
|
||||
struct bkey_i_stripe *new;
|
||||
|
||||
new = kmalloc(bkey_bytes(k.k), GFP_KERNEL);
|
||||
if (!new) {
|
||||
ret = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
|
||||
bkey_reassemble(&new->k_i, k);
|
||||
|
||||
for (i = 0; i < new->v.nr_blocks; i++)
|
||||
stripe_blockcount_set(&new->v, i, m ? m->block_sectors[i] : 0);
|
||||
|
||||
ret = commit_do(&trans, NULL, NULL, 0,
|
||||
__bch2_btree_insert(&trans, BTREE_ID_reflink, &new->k_i));
|
||||
kfree(new);
|
||||
}
|
||||
}
|
||||
fsck_err:
|
||||
bch2_trans_iter_exit(&trans, &iter);
|
||||
ret = for_each_btree_key_commit(&trans, iter,
|
||||
BTREE_ID_stripes, POS_MIN,
|
||||
BTREE_ITER_PREFETCH, k,
|
||||
NULL, NULL, BTREE_INSERT_NOFAIL,
|
||||
bch2_gc_write_stripes_key(&trans, &iter, k));
|
||||
|
||||
bch2_trans_exit(&trans);
|
||||
|
||||
printbuf_exit(&buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1777,7 +1780,7 @@ again:
|
||||
|
||||
ret = bch2_gc_btrees(c, initial, metadata_only);
|
||||
|
||||
if (ret == FSCK_ERR_START_TOPOLOGY_REPAIR &&
|
||||
if (ret == -BCH_ERR_need_topology_repair &&
|
||||
!test_bit(BCH_FS_TOPOLOGY_REPAIR_DONE, &c->flags) &&
|
||||
!test_bit(BCH_FS_INITIAL_GC_DONE, &c->flags)) {
|
||||
set_bit(BCH_FS_NEED_ANOTHER_GC, &c->flags);
|
||||
@ -1785,8 +1788,8 @@ again:
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
if (ret == FSCK_ERR_START_TOPOLOGY_REPAIR)
|
||||
ret = FSCK_ERR_EXIT;
|
||||
if (ret == -BCH_ERR_need_topology_repair)
|
||||
ret = -BCH_ERR_fsck_errors_not_fixed;
|
||||
|
||||
if (ret)
|
||||
goto out;
|
||||
@ -1969,7 +1972,7 @@ int bch2_gc_gens(struct bch_fs *c)
|
||||
BTREE_INSERT_NOFAIL,
|
||||
gc_btree_gens_key(&trans, &iter, k));
|
||||
if (ret) {
|
||||
bch_err(c, "error recalculating oldest_gen: %i", ret);
|
||||
bch_err(c, "error recalculating oldest_gen: %s", bch2_err_str(ret));
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
@ -1982,7 +1985,7 @@ int bch2_gc_gens(struct bch_fs *c)
|
||||
BTREE_INSERT_NOFAIL,
|
||||
bch2_alloc_write_oldest_gen(&trans, &iter, k));
|
||||
if (ret) {
|
||||
bch_err(c, "error writing oldest_gen: %i", ret);
|
||||
bch_err(c, "error writing oldest_gen: %s", bch2_err_str(ret));
|
||||
goto err;
|
||||
}
|
||||
|
||||
@ -2054,7 +2057,7 @@ static int bch2_gc_thread(void *arg)
|
||||
ret = bch2_gc_gens(c);
|
||||
#endif
|
||||
if (ret < 0)
|
||||
bch_err(c, "btree gc failed: %i", ret);
|
||||
bch_err(c, "btree gc failed: %s", bch2_err_str(ret));
|
||||
|
||||
debug_check_no_locks_held();
|
||||
}
|
||||
@ -2084,7 +2087,7 @@ int bch2_gc_thread_start(struct bch_fs *c)
|
||||
|
||||
p = kthread_create(bch2_gc_thread, c, "bch-gc/%s", c->name);
|
||||
if (IS_ERR(p)) {
|
||||
bch_err(c, "error creating gc thread: %li", PTR_ERR(p));
|
||||
bch_err(c, "error creating gc thread: %s", bch2_err_str(PTR_ERR(p)));
|
||||
return PTR_ERR(p);
|
||||
}
|
||||
|
||||
|
@ -543,7 +543,7 @@ enum btree_validate_ret {
|
||||
struct printbuf out = PRINTBUF; \
|
||||
\
|
||||
btree_err_msg(&out, c, ca, b, i, b->written, write); \
|
||||
prt_printf(&out, ": " msg, ##__VA_ARGS__); \
|
||||
prt_printf(&out, ": " msg, ##__VA_ARGS__); \
|
||||
\
|
||||
if (type == BTREE_ERR_FIXABLE && \
|
||||
write == READ && \
|
||||
@ -558,7 +558,7 @@ enum btree_validate_ret {
|
||||
\
|
||||
switch (type) { \
|
||||
case BTREE_ERR_FIXABLE: \
|
||||
ret = BCH_FSCK_ERRORS_NOT_FIXED; \
|
||||
ret = -BCH_ERR_fsck_errors_not_fixed; \
|
||||
goto fsck_err; \
|
||||
case BTREE_ERR_WANT_RETRY: \
|
||||
if (have_retry) { \
|
||||
@ -570,7 +570,7 @@ enum btree_validate_ret {
|
||||
ret = BTREE_RETRY_READ; \
|
||||
goto fsck_err; \
|
||||
case BTREE_ERR_FATAL: \
|
||||
ret = BCH_FSCK_ERRORS_NOT_FIXED; \
|
||||
ret = -BCH_ERR_fsck_errors_not_fixed; \
|
||||
goto fsck_err; \
|
||||
} \
|
||||
break; \
|
||||
@ -578,7 +578,7 @@ enum btree_validate_ret {
|
||||
bch_err(c, "corrupt metadata before write: %s", out.buf);\
|
||||
\
|
||||
if (bch2_fs_inconsistent(c)) { \
|
||||
ret = BCH_FSCK_ERRORS_NOT_FIXED; \
|
||||
ret = -BCH_ERR_fsck_errors_not_fixed; \
|
||||
goto fsck_err; \
|
||||
} \
|
||||
break; \
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -5,6 +5,8 @@
|
||||
#include "bset.h"
|
||||
#include "btree_types.h"
|
||||
|
||||
#include <trace/events/bcachefs.h>
|
||||
|
||||
static inline void __btree_path_get(struct btree_path *path, bool intent)
|
||||
{
|
||||
path->ref++;
|
||||
@ -159,19 +161,36 @@ void bch2_btree_node_iter_fix(struct btree_trans *trans, struct btree_path *,
|
||||
struct btree *, struct btree_node_iter *,
|
||||
struct bkey_packed *, unsigned, unsigned);
|
||||
|
||||
bool bch2_btree_path_relock_intent(struct btree_trans *, struct btree_path *);
|
||||
int bch2_btree_path_relock_intent(struct btree_trans *, struct btree_path *);
|
||||
|
||||
void bch2_path_put(struct btree_trans *, struct btree_path *, bool);
|
||||
|
||||
bool bch2_trans_relock(struct btree_trans *);
|
||||
int bch2_trans_relock(struct btree_trans *);
|
||||
void bch2_trans_unlock(struct btree_trans *);
|
||||
|
||||
__always_inline
|
||||
static inline int btree_trans_restart(struct btree_trans *trans)
|
||||
static inline bool trans_was_restarted(struct btree_trans *trans, u32 restart_count)
|
||||
{
|
||||
trans->restarted = true;
|
||||
bch2_trans_unlock(trans);
|
||||
return -EINTR;
|
||||
return restart_count != trans->restart_count;
|
||||
}
|
||||
|
||||
void bch2_trans_verify_not_restarted(struct btree_trans *, u32);
|
||||
|
||||
__always_inline
|
||||
static inline 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));
|
||||
|
||||
trans->restarted = err;
|
||||
trans->restart_count++;
|
||||
return -err;
|
||||
}
|
||||
|
||||
__always_inline
|
||||
static inline int btree_trans_restart(struct btree_trans *trans, int err)
|
||||
{
|
||||
btree_trans_restart_nounlock(trans, err);
|
||||
return -err;
|
||||
}
|
||||
|
||||
bool bch2_btree_node_upgrade(struct btree_trans *,
|
||||
@ -191,14 +210,15 @@ static inline bool bch2_btree_path_upgrade(struct btree_trans *trans,
|
||||
: path->uptodate == BTREE_ITER_UPTODATE;
|
||||
}
|
||||
|
||||
void __bch2_btree_path_downgrade(struct btree_path *, unsigned);
|
||||
void __bch2_btree_path_downgrade(struct btree_trans *, struct btree_path *, unsigned);
|
||||
|
||||
static inline void bch2_btree_path_downgrade(struct btree_path *path)
|
||||
static inline void bch2_btree_path_downgrade(struct btree_trans *trans,
|
||||
struct btree_path *path)
|
||||
{
|
||||
unsigned new_locks_want = path->level + !!path->intent_ref;
|
||||
|
||||
if (path->locks_want > new_locks_want)
|
||||
__bch2_btree_path_downgrade(path, new_locks_want);
|
||||
__bch2_btree_path_downgrade(trans, path, new_locks_want);
|
||||
}
|
||||
|
||||
void bch2_trans_downgrade(struct btree_trans *);
|
||||
@ -279,11 +299,12 @@ void bch2_trans_copy_iter(struct btree_iter *, struct btree_iter *);
|
||||
|
||||
static inline void set_btree_iter_dontneed(struct btree_iter *iter)
|
||||
{
|
||||
iter->path->preserve = false;
|
||||
if (!iter->trans->restarted)
|
||||
iter->path->preserve = false;
|
||||
}
|
||||
|
||||
void *bch2_trans_kmalloc(struct btree_trans *, size_t);
|
||||
void bch2_trans_begin(struct btree_trans *);
|
||||
u32 bch2_trans_begin(struct btree_trans *);
|
||||
|
||||
static inline struct btree *
|
||||
__btree_iter_peek_node_and_restart(struct btree_trans *trans, struct btree_iter *iter)
|
||||
@ -291,7 +312,7 @@ __btree_iter_peek_node_and_restart(struct btree_trans *trans, struct btree_iter
|
||||
struct btree *b;
|
||||
|
||||
while (b = bch2_btree_iter_peek_node(iter),
|
||||
PTR_ERR_OR_ZERO(b) == -EINTR)
|
||||
bch2_err_matches(PTR_ERR_OR_ZERO(b), BCH_ERR_transaction_restart))
|
||||
bch2_trans_begin(trans);
|
||||
|
||||
return b;
|
||||
@ -315,6 +336,15 @@ static inline int bkey_err(struct bkey_s_c k)
|
||||
return PTR_ERR_OR_ZERO(k.k);
|
||||
}
|
||||
|
||||
static inline struct bkey_s_c bch2_btree_iter_peek_prev_type(struct btree_iter *iter,
|
||||
unsigned flags)
|
||||
{
|
||||
BUG_ON(flags & BTREE_ITER_ALL_LEVELS);
|
||||
|
||||
return flags & BTREE_ITER_SLOTS ? bch2_btree_iter_peek_slot(iter) :
|
||||
bch2_btree_iter_peek_prev(iter);
|
||||
}
|
||||
|
||||
static inline struct bkey_s_c bch2_btree_iter_peek_type(struct btree_iter *iter,
|
||||
unsigned flags)
|
||||
{
|
||||
@ -338,8 +368,12 @@ static inline struct bkey_s_c bch2_btree_iter_peek_upto_type(struct btree_iter *
|
||||
|
||||
static inline int btree_trans_too_many_iters(struct btree_trans *trans)
|
||||
{
|
||||
return hweight64(trans->paths_allocated) > BTREE_ITER_MAX / 2
|
||||
? -EINTR : 0;
|
||||
if (hweight64(trans->paths_allocated) > BTREE_ITER_MAX) {
|
||||
trace_trans_restart_too_many_iters(trans, _THIS_IP_);
|
||||
return btree_trans_restart(trans, BCH_ERR_transaction_restart_too_many_iters);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline struct bkey_s_c
|
||||
@ -350,12 +384,52 @@ __bch2_btree_iter_peek_and_restart(struct btree_trans *trans,
|
||||
|
||||
while (btree_trans_too_many_iters(trans) ||
|
||||
(k = bch2_btree_iter_peek_type(iter, flags),
|
||||
bkey_err(k) == -EINTR))
|
||||
bch2_err_matches(bkey_err(k), BCH_ERR_transaction_restart)))
|
||||
bch2_trans_begin(trans);
|
||||
|
||||
return k;
|
||||
}
|
||||
|
||||
#define lockrestart_do(_trans, _do) \
|
||||
({ \
|
||||
int _ret; \
|
||||
\
|
||||
do { \
|
||||
bch2_trans_begin(_trans); \
|
||||
_ret = (_do); \
|
||||
} while (bch2_err_matches(_ret, BCH_ERR_transaction_restart)); \
|
||||
\
|
||||
_ret; \
|
||||
})
|
||||
|
||||
/*
|
||||
* nested_lockrestart_do(), nested_commit_do():
|
||||
*
|
||||
* These are like lockrestart_do() and commit_do(), with two differences:
|
||||
*
|
||||
* - We don't call bch2_trans_begin() unless we had a transaction restart
|
||||
* - We return -BCH_ERR_transaction_restart_nested if we succeeded after a
|
||||
* transaction restart
|
||||
*/
|
||||
#define nested_lockrestart_do(_trans, _do) \
|
||||
({ \
|
||||
u32 _restart_count, _orig_restart_count; \
|
||||
int _ret; \
|
||||
\
|
||||
_restart_count = _orig_restart_count = (_trans)->restart_count; \
|
||||
\
|
||||
while (bch2_err_matches(_ret = (_do), BCH_ERR_transaction_restart))\
|
||||
_restart_count = bch2_trans_begin(_trans); \
|
||||
\
|
||||
if (!_ret) \
|
||||
bch2_trans_verify_not_restarted(_trans, _restart_count);\
|
||||
\
|
||||
if (!_ret && trans_was_restarted(_trans, _orig_restart_count)) \
|
||||
_ret = -BCH_ERR_transaction_restart_nested; \
|
||||
\
|
||||
_ret; \
|
||||
})
|
||||
|
||||
#define for_each_btree_key2(_trans, _iter, _btree_id, \
|
||||
_start, _flags, _k, _do) \
|
||||
({ \
|
||||
@ -364,7 +438,7 @@ __bch2_btree_iter_peek_and_restart(struct btree_trans *trans,
|
||||
bch2_trans_iter_init((_trans), &(_iter), (_btree_id), \
|
||||
(_start), (_flags)); \
|
||||
\
|
||||
do { \
|
||||
while (1) { \
|
||||
bch2_trans_begin(_trans); \
|
||||
(_k) = bch2_btree_iter_peek_type(&(_iter), (_flags)); \
|
||||
if (!(_k).k) { \
|
||||
@ -373,9 +447,42 @@ __bch2_btree_iter_peek_and_restart(struct btree_trans *trans,
|
||||
} \
|
||||
\
|
||||
_ret = bkey_err(_k) ?: (_do); \
|
||||
if (!_ret) \
|
||||
bch2_btree_iter_advance(&(_iter)); \
|
||||
} while (_ret == 0 || _ret == -EINTR); \
|
||||
if (bch2_err_matches(_ret, BCH_ERR_transaction_restart))\
|
||||
continue; \
|
||||
if (_ret) \
|
||||
break; \
|
||||
if (!bch2_btree_iter_advance(&(_iter))) \
|
||||
break; \
|
||||
} \
|
||||
\
|
||||
bch2_trans_iter_exit((_trans), &(_iter)); \
|
||||
_ret; \
|
||||
})
|
||||
|
||||
#define for_each_btree_key_reverse(_trans, _iter, _btree_id, \
|
||||
_start, _flags, _k, _do) \
|
||||
({ \
|
||||
int _ret = 0; \
|
||||
\
|
||||
bch2_trans_iter_init((_trans), &(_iter), (_btree_id), \
|
||||
(_start), (_flags)); \
|
||||
\
|
||||
while (1) { \
|
||||
bch2_trans_begin(_trans); \
|
||||
(_k) = bch2_btree_iter_peek_prev_type(&(_iter), (_flags));\
|
||||
if (!(_k).k) { \
|
||||
_ret = 0; \
|
||||
break; \
|
||||
} \
|
||||
\
|
||||
_ret = bkey_err(_k) ?: (_do); \
|
||||
if (bch2_err_matches(_ret, BCH_ERR_transaction_restart))\
|
||||
continue; \
|
||||
if (_ret) \
|
||||
break; \
|
||||
if (!bch2_btree_iter_rewind(&(_iter))) \
|
||||
break; \
|
||||
} \
|
||||
\
|
||||
bch2_trans_iter_exit((_trans), &(_iter)); \
|
||||
_ret; \
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "btree_key_cache.h"
|
||||
#include "btree_locking.h"
|
||||
#include "btree_update.h"
|
||||
#include "errcode.h"
|
||||
#include "error.h"
|
||||
#include "journal.h"
|
||||
#include "journal_reclaim.h"
|
||||
@ -290,9 +291,8 @@ static int btree_key_cache_fill(struct btree_trans *trans,
|
||||
k = bch2_btree_path_peek_slot(path, &u);
|
||||
|
||||
if (!bch2_btree_node_relock(trans, ck_path, 0)) {
|
||||
trace_trans_restart_relock_key_cache_fill(trans->fn,
|
||||
_THIS_IP_, ck_path->btree_id, &ck_path->pos);
|
||||
ret = btree_trans_restart(trans);
|
||||
trace_trans_restart_relock_key_cache_fill(trans, _THIS_IP_, ck_path);
|
||||
ret = btree_trans_restart(trans, BCH_ERR_transaction_restart_key_cache_raced);
|
||||
goto err;
|
||||
}
|
||||
|
||||
@ -347,8 +347,10 @@ static int bkey_cached_check_fn(struct six_lock *lock, void *p)
|
||||
struct bkey_cached *ck = container_of(lock, struct bkey_cached, c.lock);
|
||||
const struct btree_path *path = p;
|
||||
|
||||
return ck->key.btree_id == path->btree_id &&
|
||||
!bpos_cmp(ck->key.pos, path->pos) ? 0 : -1;
|
||||
if (ck->key.btree_id != path->btree_id &&
|
||||
bpos_cmp(ck->key.pos, path->pos))
|
||||
return BCH_ERR_lock_fail_node_reused;
|
||||
return 0;
|
||||
}
|
||||
|
||||
__flatten
|
||||
@ -370,11 +372,6 @@ int bch2_btree_path_traverse_cached(struct btree_trans *trans, struct btree_path
|
||||
retry:
|
||||
ck = bch2_btree_key_cache_find(c, path->btree_id, path->pos);
|
||||
if (!ck) {
|
||||
if (flags & BTREE_ITER_CACHED_NOCREATE) {
|
||||
path->l[0].b = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ck = btree_key_cache_create(c, path->btree_id, path->pos);
|
||||
ret = PTR_ERR_OR_ZERO(ck);
|
||||
if (ret)
|
||||
@ -387,14 +384,15 @@ retry:
|
||||
} else {
|
||||
enum six_lock_type lock_want = __btree_lock_want(path, 0);
|
||||
|
||||
if (!btree_node_lock(trans, path, (void *) ck, path->pos, 0,
|
||||
lock_want,
|
||||
bkey_cached_check_fn, path, _THIS_IP_)) {
|
||||
if (!trans->restarted)
|
||||
ret = btree_node_lock(trans, path, (void *) ck, path->pos, 0,
|
||||
lock_want,
|
||||
bkey_cached_check_fn, path, _THIS_IP_);
|
||||
if (ret) {
|
||||
if (bch2_err_matches(ret, BCH_ERR_lock_fail_node_reused))
|
||||
goto retry;
|
||||
|
||||
ret = -EINTR;
|
||||
goto err;
|
||||
if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
|
||||
goto err;
|
||||
BUG();
|
||||
}
|
||||
|
||||
if (ck->key.btree_id != path->btree_id ||
|
||||
@ -409,11 +407,15 @@ retry:
|
||||
path->l[0].lock_seq = ck->c.lock.state.seq;
|
||||
path->l[0].b = (void *) ck;
|
||||
fill:
|
||||
if (!ck->valid && !(flags & BTREE_ITER_CACHED_NOFILL)) {
|
||||
if (!ck->valid) {
|
||||
/*
|
||||
* Using the underscore version because we haven't set
|
||||
* path->uptodate yet:
|
||||
*/
|
||||
if (!path->locks_want &&
|
||||
!__bch2_btree_path_upgrade(trans, path, 1)) {
|
||||
trace_transaction_restart_ip(trans->fn, _THIS_IP_);
|
||||
ret = btree_trans_restart(trans);
|
||||
trace_transaction_restart_key_cache_upgrade(trans, _THIS_IP_);
|
||||
ret = btree_trans_restart(trans, BCH_ERR_transaction_restart_key_cache_upgrade);
|
||||
goto err;
|
||||
}
|
||||
|
||||
@ -426,13 +428,14 @@ fill:
|
||||
set_bit(BKEY_CACHED_ACCESSED, &ck->flags);
|
||||
|
||||
path->uptodate = BTREE_ITER_UPTODATE;
|
||||
BUG_ON(!ck->valid);
|
||||
BUG_ON(btree_node_locked_type(path, 0) != btree_lock_want(path, 0));
|
||||
|
||||
return ret;
|
||||
err:
|
||||
if (ret != -EINTR) {
|
||||
btree_node_unlock(path, 0);
|
||||
path->l[0].b = BTREE_ITER_NO_NODE_ERROR;
|
||||
if (!bch2_err_matches(ret, BCH_ERR_transaction_restart)) {
|
||||
btree_node_unlock(trans, path, 0);
|
||||
path->l[0].b = ERR_PTR(ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@ -455,8 +458,6 @@ static int btree_key_cache_flush_pos(struct btree_trans *trans,
|
||||
BTREE_ITER_ALL_SNAPSHOTS);
|
||||
bch2_trans_iter_init(trans, &c_iter, key.btree_id, key.pos,
|
||||
BTREE_ITER_CACHED|
|
||||
BTREE_ITER_CACHED_NOFILL|
|
||||
BTREE_ITER_CACHED_NOCREATE|
|
||||
BTREE_ITER_INTENT);
|
||||
b_iter.flags &= ~BTREE_ITER_WITH_KEY_CACHE;
|
||||
|
||||
@ -497,13 +498,14 @@ static int btree_key_cache_flush_pos(struct btree_trans *trans,
|
||||
? JOURNAL_WATERMARK_reserved
|
||||
: 0)|
|
||||
commit_flags);
|
||||
if (ret) {
|
||||
bch2_fs_fatal_err_on(ret != -EINTR &&
|
||||
ret != -EAGAIN &&
|
||||
!bch2_journal_error(j), c,
|
||||
"error flushing key cache: %i", ret);
|
||||
|
||||
bch2_fs_fatal_err_on(ret &&
|
||||
!bch2_err_matches(ret, BCH_ERR_transaction_restart) &&
|
||||
!bch2_err_matches(ret, BCH_ERR_journal_reclaim_would_deadlock) &&
|
||||
!bch2_journal_error(j), c,
|
||||
"error flushing key cache: %s", bch2_err_str(ret));
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
bch2_journal_pin_drop(j, &ck->journal);
|
||||
bch2_journal_preres_put(j, &ck->res);
|
||||
|
@ -14,6 +14,11 @@
|
||||
|
||||
#include "btree_iter.h"
|
||||
|
||||
static inline bool is_btree_node(struct btree_path *path, unsigned l)
|
||||
{
|
||||
return l < BTREE_MAX_DEPTH && !IS_ERR_OR_NULL(path->l[l].b);
|
||||
}
|
||||
|
||||
/* matches six lock types */
|
||||
enum btree_node_locked_type {
|
||||
BTREE_NODE_UNLOCKED = -1,
|
||||
@ -58,7 +63,7 @@ static inline void mark_btree_node_unlocked(struct btree_path *path,
|
||||
path->nodes_intent_locked &= ~(1 << level);
|
||||
}
|
||||
|
||||
static inline void mark_btree_node_locked(struct btree_trans *trans,
|
||||
static inline void mark_btree_node_locked_noreset(struct btree_trans *trans,
|
||||
struct btree_path *path,
|
||||
unsigned level,
|
||||
enum six_lock_type type)
|
||||
@ -73,11 +78,22 @@ static inline void mark_btree_node_locked(struct btree_trans *trans,
|
||||
path->nodes_intent_locked |= type << level;
|
||||
}
|
||||
|
||||
static inline void mark_btree_node_locked(struct btree_trans *trans,
|
||||
struct btree_path *path,
|
||||
unsigned level,
|
||||
enum six_lock_type type)
|
||||
{
|
||||
mark_btree_node_locked_noreset(trans, path, level, type);
|
||||
#ifdef CONFIG_BCACHEFS_LOCK_TIME_STATS
|
||||
path->l[level].lock_taken_time = ktime_get_ns();
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void mark_btree_node_intent_locked(struct btree_trans *trans,
|
||||
struct btree_path *path,
|
||||
unsigned level)
|
||||
{
|
||||
mark_btree_node_locked(trans, path, level, SIX_LOCK_intent);
|
||||
mark_btree_node_locked_noreset(trans, path, level, SIX_LOCK_intent);
|
||||
}
|
||||
|
||||
static inline enum six_lock_type __btree_lock_want(struct btree_path *path, int level)
|
||||
@ -99,23 +115,35 @@ btree_lock_want(struct btree_path *path, int level)
|
||||
return BTREE_NODE_UNLOCKED;
|
||||
}
|
||||
|
||||
static inline void btree_node_unlock(struct btree_path *path, unsigned level)
|
||||
static inline void btree_node_unlock(struct btree_trans *trans,
|
||||
struct btree_path *path, unsigned level)
|
||||
{
|
||||
int lock_type = btree_node_locked_type(path, level);
|
||||
|
||||
EBUG_ON(level >= BTREE_MAX_DEPTH);
|
||||
|
||||
if (lock_type != BTREE_NODE_UNLOCKED)
|
||||
if (lock_type != BTREE_NODE_UNLOCKED) {
|
||||
six_unlock_type(&path->l[level].b->c.lock, lock_type);
|
||||
#ifdef CONFIG_BCACHEFS_LOCK_TIME_STATS
|
||||
if (trans->lock_name_idx < BCH_LOCK_TIME_NR) {
|
||||
struct bch_fs *c = trans->c;
|
||||
|
||||
__bch2_time_stats_update(&c->lock_held_stats.times[trans->lock_name_idx],
|
||||
path->l[level].lock_taken_time,
|
||||
ktime_get_ns());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
mark_btree_node_unlocked(path, level);
|
||||
}
|
||||
|
||||
static inline void __bch2_btree_path_unlock(struct btree_path *path)
|
||||
static inline void __bch2_btree_path_unlock(struct btree_trans *trans,
|
||||
struct btree_path *path)
|
||||
{
|
||||
btree_path_set_dirty(path, BTREE_ITER_NEED_RELOCK);
|
||||
|
||||
while (path->nodes_locked)
|
||||
btree_node_unlock(path, __ffs(path->nodes_locked));
|
||||
btree_node_unlock(trans, path, __ffs(path->nodes_locked));
|
||||
}
|
||||
|
||||
static inline enum bch_time_stats lock_to_time_stat(enum six_lock_type type)
|
||||
@ -132,7 +160,7 @@ static inline enum bch_time_stats lock_to_time_stat(enum six_lock_type type)
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool btree_node_lock_type(struct btree_trans *trans,
|
||||
static inline int btree_node_lock_type(struct btree_trans *trans,
|
||||
struct btree_path *path,
|
||||
struct btree *b,
|
||||
struct bpos pos, unsigned level,
|
||||
@ -141,10 +169,10 @@ static inline bool btree_node_lock_type(struct btree_trans *trans,
|
||||
{
|
||||
struct bch_fs *c = trans->c;
|
||||
u64 start_time;
|
||||
bool ret;
|
||||
int ret;
|
||||
|
||||
if (six_trylock_type(&b->c.lock, type))
|
||||
return true;
|
||||
return 0;
|
||||
|
||||
start_time = local_clock();
|
||||
|
||||
@ -153,14 +181,15 @@ static inline bool btree_node_lock_type(struct btree_trans *trans,
|
||||
trans->locking_btree_id = path->btree_id;
|
||||
trans->locking_level = level;
|
||||
trans->locking_lock_type = type;
|
||||
trans->locking = b;
|
||||
ret = six_lock_type(&b->c.lock, type, should_sleep_fn, p) == 0;
|
||||
trans->locking = &b->c;
|
||||
ret = six_lock_type(&b->c.lock, type, should_sleep_fn, p);
|
||||
trans->locking = NULL;
|
||||
|
||||
if (ret)
|
||||
bch2_time_stats_update(&c->times[lock_to_time_stat(type)], start_time);
|
||||
return ret;
|
||||
|
||||
return ret;
|
||||
bch2_time_stats_update(&c->times[lock_to_time_stat(type)], start_time);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -183,26 +212,34 @@ static inline bool btree_node_lock_increment(struct btree_trans *trans,
|
||||
return false;
|
||||
}
|
||||
|
||||
bool __bch2_btree_node_lock(struct btree_trans *, struct btree_path *,
|
||||
struct btree *, struct bpos, unsigned,
|
||||
enum six_lock_type,
|
||||
six_lock_should_sleep_fn, void *,
|
||||
unsigned long);
|
||||
int __bch2_btree_node_lock(struct btree_trans *, struct btree_path *,
|
||||
struct btree *, struct bpos, unsigned,
|
||||
enum six_lock_type,
|
||||
six_lock_should_sleep_fn, void *,
|
||||
unsigned long);
|
||||
|
||||
static inline bool btree_node_lock(struct btree_trans *trans,
|
||||
static inline int btree_node_lock(struct btree_trans *trans,
|
||||
struct btree_path *path,
|
||||
struct btree *b, struct bpos pos, unsigned level,
|
||||
enum six_lock_type type,
|
||||
six_lock_should_sleep_fn should_sleep_fn, void *p,
|
||||
unsigned long ip)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
EBUG_ON(level >= BTREE_MAX_DEPTH);
|
||||
EBUG_ON(!(trans->paths_allocated & (1ULL << path->idx)));
|
||||
|
||||
return likely(six_trylock_type(&b->c.lock, type)) ||
|
||||
btree_node_lock_increment(trans, b, level, type) ||
|
||||
__bch2_btree_node_lock(trans, path, b, pos, level, type,
|
||||
should_sleep_fn, p, ip);
|
||||
if (likely(six_trylock_type(&b->c.lock, type)) ||
|
||||
btree_node_lock_increment(trans, b, level, type) ||
|
||||
!(ret = __bch2_btree_node_lock(trans, path, b, pos, level, type,
|
||||
should_sleep_fn, p, ip))) {
|
||||
#ifdef CONFIG_BCACHEFS_LOCK_TIME_STATS
|
||||
path->l[b->c.level].lock_taken_time = ktime_get_ns();
|
||||
#endif
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool __bch2_btree_node_relock(struct btree_trans *, struct btree_path *, unsigned);
|
||||
@ -254,6 +291,30 @@ static inline void bch2_btree_node_lock_write(struct btree_trans *trans,
|
||||
__bch2_btree_node_lock_write(trans, b);
|
||||
}
|
||||
|
||||
static inline void btree_path_set_should_be_locked(struct btree_path *path)
|
||||
{
|
||||
EBUG_ON(!btree_node_locked(path, path->level));
|
||||
EBUG_ON(path->uptodate);
|
||||
|
||||
path->should_be_locked = true;
|
||||
}
|
||||
|
||||
static inline void __btree_path_set_level_up(struct btree_trans *trans,
|
||||
struct btree_path *path,
|
||||
unsigned l)
|
||||
{
|
||||
btree_node_unlock(trans, path, l);
|
||||
path->l[l].b = ERR_PTR(-BCH_ERR_no_btree_node_up);
|
||||
}
|
||||
|
||||
static inline void btree_path_set_level_up(struct btree_trans *trans,
|
||||
struct btree_path *path)
|
||||
{
|
||||
__btree_path_set_level_up(trans, path, path->level++);
|
||||
btree_path_set_dirty(path, BTREE_ITER_NEED_TRAVERSE);
|
||||
}
|
||||
|
||||
struct six_lock_count bch2_btree_node_lock_counts(struct btree_trans *,
|
||||
struct btree_path *, struct btree *, unsigned);
|
||||
|
||||
#endif /* _BCACHEFS_BTREE_LOCKING_H */
|
||||
|
||||
|
||||
|
@ -199,15 +199,13 @@ struct btree_node_iter {
|
||||
#define BTREE_ITER_IS_EXTENTS (1 << 4)
|
||||
#define BTREE_ITER_NOT_EXTENTS (1 << 5)
|
||||
#define BTREE_ITER_CACHED (1 << 6)
|
||||
#define BTREE_ITER_CACHED_NOFILL (1 << 7)
|
||||
#define BTREE_ITER_CACHED_NOCREATE (1 << 8)
|
||||
#define BTREE_ITER_WITH_KEY_CACHE (1 << 9)
|
||||
#define BTREE_ITER_WITH_UPDATES (1 << 10)
|
||||
#define BTREE_ITER_WITH_JOURNAL (1 << 11)
|
||||
#define __BTREE_ITER_ALL_SNAPSHOTS (1 << 12)
|
||||
#define BTREE_ITER_ALL_SNAPSHOTS (1 << 13)
|
||||
#define BTREE_ITER_FILTER_SNAPSHOTS (1 << 14)
|
||||
#define BTREE_ITER_NOPRESERVE (1 << 15)
|
||||
#define BTREE_ITER_WITH_KEY_CACHE (1 << 7)
|
||||
#define BTREE_ITER_WITH_UPDATES (1 << 8)
|
||||
#define BTREE_ITER_WITH_JOURNAL (1 << 9)
|
||||
#define __BTREE_ITER_ALL_SNAPSHOTS (1 << 10)
|
||||
#define BTREE_ITER_ALL_SNAPSHOTS (1 << 11)
|
||||
#define BTREE_ITER_FILTER_SNAPSHOTS (1 << 12)
|
||||
#define BTREE_ITER_NOPRESERVE (1 << 13)
|
||||
|
||||
enum btree_path_uptodate {
|
||||
BTREE_ITER_UPTODATE = 0,
|
||||
@ -215,15 +213,6 @@ enum btree_path_uptodate {
|
||||
BTREE_ITER_NEED_TRAVERSE = 2,
|
||||
};
|
||||
|
||||
#define BTREE_ITER_NO_NODE_GET_LOCKS ((struct btree *) 1)
|
||||
#define BTREE_ITER_NO_NODE_DROP ((struct btree *) 2)
|
||||
#define BTREE_ITER_NO_NODE_LOCK_ROOT ((struct btree *) 3)
|
||||
#define BTREE_ITER_NO_NODE_UP ((struct btree *) 4)
|
||||
#define BTREE_ITER_NO_NODE_DOWN ((struct btree *) 5)
|
||||
#define BTREE_ITER_NO_NODE_INIT ((struct btree *) 6)
|
||||
#define BTREE_ITER_NO_NODE_ERROR ((struct btree *) 7)
|
||||
#define BTREE_ITER_NO_NODE_CACHED ((struct btree *) 8)
|
||||
|
||||
struct btree_path {
|
||||
u8 idx;
|
||||
u8 sorted_idx;
|
||||
@ -251,6 +240,9 @@ struct btree_path {
|
||||
struct btree *b;
|
||||
struct btree_node_iter iter;
|
||||
u32 lock_seq;
|
||||
#ifdef CONFIG_BCACHEFS_LOCK_TIME_STATS
|
||||
u64 lock_taken_time;
|
||||
#endif
|
||||
} l[BTREE_MAX_DEPTH];
|
||||
#ifdef CONFIG_BCACHEFS_DEBUG
|
||||
unsigned long ip_allocated;
|
||||
@ -391,7 +383,7 @@ struct btree_trans {
|
||||
const char *fn;
|
||||
struct list_head list;
|
||||
u64 last_begin_time;
|
||||
struct btree *locking;
|
||||
struct btree_bkey_cached_common *locking;
|
||||
unsigned locking_path_idx;
|
||||
struct bpos locking_pos;
|
||||
u8 locking_btree_id;
|
||||
@ -405,9 +397,12 @@ struct btree_trans {
|
||||
u8 traverse_all_idx;
|
||||
bool used_mempool:1;
|
||||
bool in_traverse_all:1;
|
||||
bool restarted:1;
|
||||
bool memory_allocation_failure:1;
|
||||
bool is_initial_gc:1;
|
||||
enum bch_errcode restarted:16;
|
||||
u32 restart_count;
|
||||
unsigned long last_restarted_ip;
|
||||
|
||||
/*
|
||||
* For when bch2_trans_update notices we'll be splitting a compressed
|
||||
* extent:
|
||||
@ -437,6 +432,7 @@ struct btree_trans {
|
||||
unsigned journal_u64s;
|
||||
unsigned journal_preres_u64s;
|
||||
struct replicas_delta_list *fs_usage_deltas;
|
||||
int lock_name_idx;
|
||||
};
|
||||
|
||||
#define BTREE_FLAGS() \
|
||||
|
@ -90,7 +90,6 @@ int bch2_trans_log_msg(struct btree_trans *, const char *);
|
||||
* This is main entry point for btree updates.
|
||||
*
|
||||
* Return values:
|
||||
* -EINTR: locking changed, this function should be called again.
|
||||
* -EROFS: filesystem read only
|
||||
* -EIO: journal or btree node IO error
|
||||
*/
|
||||
@ -106,22 +105,14 @@ static inline int bch2_trans_commit(struct btree_trans *trans,
|
||||
return __bch2_trans_commit(trans);
|
||||
}
|
||||
|
||||
#define lockrestart_do(_trans, _do) \
|
||||
({ \
|
||||
int _ret; \
|
||||
\
|
||||
do { \
|
||||
bch2_trans_begin(_trans); \
|
||||
_ret = (_do); \
|
||||
} while (_ret == -EINTR); \
|
||||
\
|
||||
_ret; \
|
||||
})
|
||||
|
||||
#define commit_do(_trans, _disk_res, _journal_seq, _flags, _do) \
|
||||
lockrestart_do(_trans, _do ?: bch2_trans_commit(_trans, (_disk_res),\
|
||||
(_journal_seq), (_flags)))
|
||||
|
||||
#define nested_commit_do(_trans, _disk_res, _journal_seq, _flags, _do) \
|
||||
nested_lockrestart_do(_trans, _do ?: bch2_trans_commit(_trans, (_disk_res),\
|
||||
(_journal_seq), (_flags)))
|
||||
|
||||
#define bch2_trans_do(_c, _disk_res, _journal_seq, _flags, _do) \
|
||||
({ \
|
||||
struct btree_trans trans; \
|
||||
@ -134,6 +125,18 @@ static inline int bch2_trans_commit(struct btree_trans *trans,
|
||||
_ret; \
|
||||
})
|
||||
|
||||
#define bch2_trans_run(_c, _do) \
|
||||
({ \
|
||||
struct btree_trans trans; \
|
||||
int _ret; \
|
||||
\
|
||||
bch2_trans_init(&trans, (_c), 0, 0); \
|
||||
_ret = (_do); \
|
||||
bch2_trans_exit(&trans); \
|
||||
\
|
||||
_ret; \
|
||||
})
|
||||
|
||||
#define trans_for_each_update(_trans, _i) \
|
||||
for ((_i) = (_trans)->updates; \
|
||||
(_i) < (_trans)->updates + (_trans)->nr_updates; \
|
||||
|
@ -1005,9 +1005,8 @@ bch2_btree_update_start(struct btree_trans *trans, struct btree_path *path,
|
||||
nr_nodes[1] += 1;
|
||||
|
||||
if (!bch2_btree_path_upgrade(trans, path, U8_MAX)) {
|
||||
trace_trans_restart_iter_upgrade(trans->fn, _RET_IP_,
|
||||
path->btree_id, &path->pos);
|
||||
ret = btree_trans_restart(trans);
|
||||
trace_trans_restart_iter_upgrade(trans, _RET_IP_, path);
|
||||
ret = btree_trans_restart(trans, BCH_ERR_transaction_restart_upgrade);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
@ -1016,9 +1015,10 @@ bch2_btree_update_start(struct btree_trans *trans, struct btree_path *path,
|
||||
else if (!down_read_trylock(&c->gc_lock)) {
|
||||
bch2_trans_unlock(trans);
|
||||
down_read(&c->gc_lock);
|
||||
if (!bch2_trans_relock(trans)) {
|
||||
ret = bch2_trans_relock(trans);
|
||||
if (ret) {
|
||||
up_read(&c->gc_lock);
|
||||
return ERR_PTR(-EINTR);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1060,8 +1060,8 @@ bch2_btree_update_start(struct btree_trans *trans, struct btree_path *path,
|
||||
journal_flags);
|
||||
if (ret) {
|
||||
bch2_btree_update_free(as);
|
||||
trace_trans_restart_journal_preres_get(trans->fn, _RET_IP_);
|
||||
btree_trans_restart(trans);
|
||||
trace_trans_restart_journal_preres_get(trans, _RET_IP_);
|
||||
ret = btree_trans_restart(trans, BCH_ERR_transaction_restart_journal_preres_get);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
@ -1076,10 +1076,9 @@ bch2_btree_update_start(struct btree_trans *trans, struct btree_path *path,
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
if (!bch2_trans_relock(trans)) {
|
||||
ret = -EINTR;
|
||||
ret = bch2_trans_relock(trans);
|
||||
if (ret)
|
||||
goto err;
|
||||
}
|
||||
|
||||
return as;
|
||||
err:
|
||||
@ -1650,7 +1649,7 @@ int __bch2_foreground_maybe_merge(struct btree_trans *trans,
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
sib_path->should_be_locked = true;
|
||||
btree_path_set_should_be_locked(sib_path);
|
||||
|
||||
m = sib_path->l[level].b;
|
||||
|
||||
@ -1830,7 +1829,7 @@ int bch2_btree_node_rewrite(struct btree_trans *trans,
|
||||
|
||||
bch2_btree_update_done(as);
|
||||
out:
|
||||
bch2_btree_path_downgrade(iter->path);
|
||||
bch2_btree_path_downgrade(trans, iter->path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1943,10 +1942,7 @@ static int __bch2_btree_node_update_key(struct btree_trans *trans,
|
||||
BUG_ON(iter2.path->level != b->c.level);
|
||||
BUG_ON(bpos_cmp(iter2.path->pos, new_key->k.p));
|
||||
|
||||
btree_node_unlock(iter2.path, iter2.path->level);
|
||||
path_l(iter2.path)->b = BTREE_ITER_NO_NODE_UP;
|
||||
iter2.path->level++;
|
||||
btree_path_set_dirty(iter2.path, BTREE_ITER_NEED_TRAVERSE);
|
||||
btree_path_set_level_up(trans, iter2.path);
|
||||
|
||||
bch2_btree_path_check_sort(trans, iter2.path, 0);
|
||||
|
||||
@ -2017,10 +2013,8 @@ int bch2_btree_node_update_key(struct btree_trans *trans, struct btree_iter *ite
|
||||
int ret = 0;
|
||||
|
||||
if (!btree_node_intent_locked(path, b->c.level) &&
|
||||
!bch2_btree_path_upgrade(trans, path, b->c.level + 1)) {
|
||||
btree_trans_restart(trans);
|
||||
return -EINTR;
|
||||
}
|
||||
!bch2_btree_path_upgrade(trans, path, b->c.level + 1))
|
||||
return btree_trans_restart(trans, BCH_ERR_transaction_restart_upgrade);
|
||||
|
||||
closure_init_stack(&cl);
|
||||
|
||||
@ -2033,8 +2027,9 @@ int bch2_btree_node_update_key(struct btree_trans *trans, struct btree_iter *ite
|
||||
if (ret) {
|
||||
bch2_trans_unlock(trans);
|
||||
closure_sync(&cl);
|
||||
if (!bch2_trans_relock(trans))
|
||||
return -EINTR;
|
||||
ret = bch2_trans_relock(trans);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
new_hash = bch2_btree_node_mem_alloc(c, false);
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "btree_locking.h"
|
||||
#include "buckets.h"
|
||||
#include "debug.h"
|
||||
#include "errcode.h"
|
||||
#include "error.h"
|
||||
#include "extent_update.h"
|
||||
#include "journal.h"
|
||||
@ -282,9 +283,10 @@ bch2_trans_journal_preres_get_cold(struct btree_trans *trans, unsigned u64s,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!bch2_trans_relock(trans)) {
|
||||
trace_trans_restart_journal_preres_get(trans->fn, trace_ip);
|
||||
return -EINTR;
|
||||
ret = bch2_trans_relock(trans);
|
||||
if (ret) {
|
||||
trace_trans_restart_journal_preres_get(trans, trace_ip);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -373,15 +375,8 @@ btree_key_can_insert_cached(struct btree_trans *trans,
|
||||
* Keys returned by peek() are no longer valid pointers, so we need a
|
||||
* transaction restart:
|
||||
*/
|
||||
trace_trans_restart_key_cache_key_realloced(trans->fn, _RET_IP_,
|
||||
path->btree_id, &path->pos,
|
||||
old_u64s, new_u64s);
|
||||
/*
|
||||
* Not using btree_trans_restart() because we can't unlock here, we have
|
||||
* write locks held:
|
||||
*/
|
||||
trans->restarted = true;
|
||||
return -EINTR;
|
||||
trace_trans_restart_key_cache_key_realloced(trans, _RET_IP_, path, old_u64s, new_u64s);
|
||||
return btree_trans_restart_nounlock(trans, BCH_ERR_transaction_restart_key_cache_realloced);
|
||||
}
|
||||
|
||||
/* Triggers: */
|
||||
@ -572,9 +567,8 @@ bch2_trans_commit_write_locked(struct btree_trans *trans,
|
||||
int ret;
|
||||
|
||||
if (race_fault()) {
|
||||
trace_trans_restart_fault_inject(trans->fn, trace_ip);
|
||||
trans->restarted = true;
|
||||
return -EINTR;
|
||||
trace_trans_restart_fault_inject(trans, trace_ip);
|
||||
return btree_trans_restart_nounlock(trans, BCH_ERR_transaction_restart_fault_inject);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -726,8 +720,10 @@ bch2_trans_commit_write_locked(struct btree_trans *trans,
|
||||
btree_insert_key_leaf(trans, i);
|
||||
else if (!i->key_cache_already_flushed)
|
||||
bch2_btree_insert_key_cached(trans, i->path, i->k);
|
||||
else
|
||||
else {
|
||||
bch2_btree_key_cache_drop(trans, i->path);
|
||||
btree_path_set_dirty(i->path, BTREE_ITER_NEED_TRAVERSE);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
@ -806,6 +802,7 @@ static inline bool have_conflicting_read_lock(struct btree_trans *trans, struct
|
||||
static inline int trans_lock_write(struct btree_trans *trans)
|
||||
{
|
||||
struct btree_insert_entry *i;
|
||||
int ret;
|
||||
|
||||
trans_for_each_update(trans, i) {
|
||||
if (same_leaf_as_prev(trans, i))
|
||||
@ -815,10 +812,11 @@ static inline int trans_lock_write(struct btree_trans *trans)
|
||||
if (have_conflicting_read_lock(trans, i->path))
|
||||
goto fail;
|
||||
|
||||
btree_node_lock_type(trans, i->path,
|
||||
ret = btree_node_lock_type(trans, i->path,
|
||||
insert_l(i)->b,
|
||||
i->path->pos, i->level,
|
||||
SIX_LOCK_write, NULL, NULL);
|
||||
BUG_ON(ret);
|
||||
}
|
||||
|
||||
bch2_btree_node_prep_for_write(trans, i->path, insert_l(i)->b);
|
||||
@ -833,8 +831,8 @@ fail:
|
||||
bch2_btree_node_unlock_write_inlined(trans, i->path, insert_l(i)->b);
|
||||
}
|
||||
|
||||
trace_trans_restart_would_deadlock_write(trans->fn);
|
||||
return btree_trans_restart(trans);
|
||||
trace_trans_restart_would_deadlock_write(trans);
|
||||
return btree_trans_restart(trans, BCH_ERR_transaction_restart_would_deadlock_write);
|
||||
}
|
||||
|
||||
static noinline void bch2_drop_overwrites_from_journal(struct btree_trans *trans)
|
||||
@ -965,12 +963,8 @@ int bch2_trans_commit_error(struct btree_trans *trans,
|
||||
switch (ret) {
|
||||
case BTREE_INSERT_BTREE_NODE_FULL:
|
||||
ret = bch2_btree_split_leaf(trans, i->path, trans->flags);
|
||||
if (!ret)
|
||||
return 0;
|
||||
|
||||
if (ret == -EINTR)
|
||||
trace_trans_restart_btree_node_split(trans->fn, trace_ip,
|
||||
i->btree_id, &i->path->pos);
|
||||
if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
|
||||
trace_trans_restart_btree_node_split(trans, trace_ip, i->path);
|
||||
break;
|
||||
case BTREE_INSERT_NEED_MARK_REPLICAS:
|
||||
bch2_trans_unlock(trans);
|
||||
@ -979,19 +973,16 @@ int bch2_trans_commit_error(struct btree_trans *trans,
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
if (bch2_trans_relock(trans))
|
||||
return 0;
|
||||
|
||||
trace_trans_restart_mark_replicas(trans->fn, trace_ip);
|
||||
ret = -EINTR;
|
||||
ret = bch2_trans_relock(trans);
|
||||
if (ret)
|
||||
trace_trans_restart_mark_replicas(trans, trace_ip);
|
||||
break;
|
||||
case BTREE_INSERT_NEED_JOURNAL_RES:
|
||||
bch2_trans_unlock(trans);
|
||||
|
||||
if ((trans->flags & BTREE_INSERT_JOURNAL_RECLAIM) &&
|
||||
!(trans->flags & JOURNAL_WATERMARK_reserved)) {
|
||||
trans->restarted = true;
|
||||
ret = -EAGAIN;
|
||||
ret = -BCH_ERR_journal_reclaim_would_deadlock;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -999,34 +990,30 @@ int bch2_trans_commit_error(struct btree_trans *trans,
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
if (bch2_trans_relock(trans))
|
||||
return 0;
|
||||
|
||||
trace_trans_restart_journal_res_get(trans->fn, trace_ip);
|
||||
ret = -EINTR;
|
||||
ret = bch2_trans_relock(trans);
|
||||
if (ret)
|
||||
trace_trans_restart_journal_res_get(trans, trace_ip);
|
||||
break;
|
||||
case BTREE_INSERT_NEED_JOURNAL_RECLAIM:
|
||||
bch2_trans_unlock(trans);
|
||||
|
||||
trace_trans_blocked_journal_reclaim(trans->fn, trace_ip);
|
||||
trace_trans_blocked_journal_reclaim(trans, trace_ip);
|
||||
|
||||
wait_event_freezable(c->journal.reclaim_wait,
|
||||
(ret = journal_reclaim_wait_done(c)));
|
||||
if (ret < 0)
|
||||
break;
|
||||
|
||||
if (bch2_trans_relock(trans))
|
||||
return 0;
|
||||
|
||||
trace_trans_restart_journal_reclaim(trans->fn, trace_ip);
|
||||
ret = -EINTR;
|
||||
ret = bch2_trans_relock(trans);
|
||||
if (ret)
|
||||
trace_trans_restart_journal_reclaim(trans, trace_ip);
|
||||
break;
|
||||
default:
|
||||
BUG_ON(ret >= 0);
|
||||
break;
|
||||
}
|
||||
|
||||
BUG_ON((ret == EINTR || ret == -EAGAIN) && !trans->restarted);
|
||||
BUG_ON(bch2_err_matches(ret, BCH_ERR_transaction_restart) != !!trans->restarted);
|
||||
BUG_ON(ret == -ENOSPC &&
|
||||
!(trans->flags & BTREE_INSERT_NOWAIT) &&
|
||||
(trans->flags & BTREE_INSERT_NOFAIL));
|
||||
@ -1046,13 +1033,11 @@ bch2_trans_commit_get_rw_cold(struct btree_trans *trans)
|
||||
|
||||
bch2_trans_unlock(trans);
|
||||
|
||||
ret = bch2_fs_read_write_early(c);
|
||||
ret = bch2_fs_read_write_early(c) ?:
|
||||
bch2_trans_relock(trans);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!bch2_trans_relock(trans))
|
||||
return -EINTR;
|
||||
|
||||
percpu_ref_get(&c->writes);
|
||||
return 0;
|
||||
}
|
||||
@ -1122,9 +1107,8 @@ int __bch2_trans_commit(struct btree_trans *trans)
|
||||
BUG_ON(!i->path->should_be_locked);
|
||||
|
||||
if (unlikely(!bch2_btree_path_upgrade(trans, i->path, i->level + 1))) {
|
||||
trace_trans_restart_upgrade(trans->fn, _RET_IP_,
|
||||
i->btree_id, &i->path->pos);
|
||||
ret = btree_trans_restart(trans);
|
||||
trace_trans_restart_upgrade(trans, _RET_IP_, i->path);
|
||||
ret = btree_trans_restart(trans, BCH_ERR_transaction_restart_upgrade);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -1164,7 +1148,7 @@ retry:
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
trace_transaction_commit(trans->fn, _RET_IP_);
|
||||
trace_transaction_commit(trans, _RET_IP_);
|
||||
out:
|
||||
bch2_journal_preres_put(&c->journal, &trans->journal_preres);
|
||||
|
||||
@ -1567,7 +1551,7 @@ bch2_trans_update_by_path_trace(struct btree_trans *trans, struct btree_path *pa
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
btree_path->should_be_locked = true;
|
||||
btree_path_set_should_be_locked(btree_path);
|
||||
ret = bch2_trans_update_by_path_trace(trans, btree_path, k, flags, ip);
|
||||
err:
|
||||
bch2_path_put(trans, btree_path, true);
|
||||
@ -1633,12 +1617,11 @@ int __must_check bch2_trans_update(struct btree_trans *trans, struct btree_iter
|
||||
ck = (void *) iter->key_cache_path->l[0].b;
|
||||
|
||||
if (test_bit(BKEY_CACHED_DIRTY, &ck->flags)) {
|
||||
trace_trans_restart_key_cache_raced(trans->fn, _RET_IP_);
|
||||
btree_trans_restart(trans);
|
||||
return -EINTR;
|
||||
trace_trans_restart_key_cache_raced(trans, _RET_IP_);
|
||||
return btree_trans_restart(trans, BCH_ERR_transaction_restart_key_cache_raced);
|
||||
}
|
||||
|
||||
iter->key_cache_path->should_be_locked = true;
|
||||
btree_path_set_should_be_locked(iter->key_cache_path);
|
||||
}
|
||||
|
||||
path = iter->key_cache_path;
|
||||
@ -1763,7 +1746,7 @@ retry:
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret == -EINTR) {
|
||||
if (bch2_err_matches(ret, BCH_ERR_transaction_restart)) {
|
||||
ret = 0;
|
||||
goto retry;
|
||||
}
|
||||
@ -1782,9 +1765,8 @@ int bch2_btree_delete_range(struct bch_fs *c, enum btree_id id,
|
||||
unsigned update_flags,
|
||||
u64 *journal_seq)
|
||||
{
|
||||
return bch2_trans_do(c, NULL, journal_seq, 0,
|
||||
bch2_btree_delete_range_trans(&trans, id, start, end,
|
||||
update_flags, journal_seq));
|
||||
return bch2_trans_run(c,
|
||||
bch2_btree_delete_range_trans(&trans, id, start, end, update_flags, journal_seq));
|
||||
}
|
||||
|
||||
int bch2_trans_log_msg(struct btree_trans *trans, const char *msg)
|
||||
|
@ -544,22 +544,6 @@ int bch2_mark_alloc(struct btree_trans *trans,
|
||||
}
|
||||
}
|
||||
|
||||
if (new_a.data_type == BCH_DATA_free &&
|
||||
(!new_a.journal_seq || new_a.journal_seq < c->journal.flushed_seq_ondisk))
|
||||
closure_wake_up(&c->freelist_wait);
|
||||
|
||||
if (new_a.data_type == BCH_DATA_need_discard &&
|
||||
(!new_a.journal_seq || new_a.journal_seq < c->journal.flushed_seq_ondisk))
|
||||
bch2_do_discards(c);
|
||||
|
||||
if (old_a.data_type != BCH_DATA_cached &&
|
||||
new_a.data_type == BCH_DATA_cached &&
|
||||
should_invalidate_buckets(ca, bch2_dev_usage_read(ca)))
|
||||
bch2_do_invalidates(c);
|
||||
|
||||
if (new_a.data_type == BCH_DATA_need_gc_gens)
|
||||
bch2_do_gc_gens(c);
|
||||
|
||||
percpu_down_read(&c->mark_lock);
|
||||
if (!gc && new_a.gen != old_a.gen)
|
||||
*bucket_gen(ca, new.k->p.offset) = new_a.gen;
|
||||
@ -599,6 +583,22 @@ int bch2_mark_alloc(struct btree_trans *trans,
|
||||
}
|
||||
}
|
||||
|
||||
if (new_a.data_type == BCH_DATA_free &&
|
||||
(!new_a.journal_seq || new_a.journal_seq < c->journal.flushed_seq_ondisk))
|
||||
closure_wake_up(&c->freelist_wait);
|
||||
|
||||
if (new_a.data_type == BCH_DATA_need_discard &&
|
||||
(!new_a.journal_seq || new_a.journal_seq < c->journal.flushed_seq_ondisk))
|
||||
bch2_do_discards(c);
|
||||
|
||||
if (old_a.data_type != BCH_DATA_cached &&
|
||||
new_a.data_type == BCH_DATA_cached &&
|
||||
should_invalidate_buckets(ca, bch2_dev_usage_read(ca)))
|
||||
bch2_do_invalidates(c);
|
||||
|
||||
if (new_a.data_type == BCH_DATA_need_gc_gens)
|
||||
bch2_do_gc_gens(c);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1939,8 +1939,7 @@ static int __bch2_trans_mark_dev_sb(struct btree_trans *trans,
|
||||
|
||||
int bch2_trans_mark_dev_sb(struct bch_fs *c, struct bch_dev *ca)
|
||||
{
|
||||
return bch2_trans_do(c, NULL, NULL, BTREE_INSERT_LAZY_RW,
|
||||
__bch2_trans_mark_dev_sb(&trans, ca));
|
||||
return bch2_trans_run(c, __bch2_trans_mark_dev_sb(&trans, ca));
|
||||
}
|
||||
|
||||
/* Disk reservations: */
|
||||
|
@ -1,6 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include "bcachefs.h"
|
||||
#include "checksum.h"
|
||||
#include "errcode.h"
|
||||
#include "super.h"
|
||||
#include "super-io.h"
|
||||
|
||||
@ -527,7 +528,7 @@ int bch2_decrypt_sb_key(struct bch_fs *c,
|
||||
|
||||
ret = bch2_request_key(c->disk_sb.sb, &user_key);
|
||||
if (ret) {
|
||||
bch_err(c, "error requesting encryption key: %i", ret);
|
||||
bch_err(c, "error requesting encryption key: %s", bch2_err_str(ret));
|
||||
goto err;
|
||||
}
|
||||
|
||||
@ -552,20 +553,24 @@ err:
|
||||
|
||||
static int bch2_alloc_ciphers(struct bch_fs *c)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!c->chacha20)
|
||||
c->chacha20 = crypto_alloc_sync_skcipher("chacha20", 0, 0);
|
||||
if (IS_ERR(c->chacha20)) {
|
||||
bch_err(c, "error requesting chacha20 module: %li",
|
||||
PTR_ERR(c->chacha20));
|
||||
return PTR_ERR(c->chacha20);
|
||||
ret = PTR_ERR_OR_ZERO(c->chacha20);
|
||||
|
||||
if (ret) {
|
||||
bch_err(c, "error requesting chacha20 module: %s", bch2_err_str(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!c->poly1305)
|
||||
c->poly1305 = crypto_alloc_shash("poly1305", 0, 0);
|
||||
if (IS_ERR(c->poly1305)) {
|
||||
bch_err(c, "error requesting poly1305 module: %li",
|
||||
PTR_ERR(c->poly1305));
|
||||
return PTR_ERR(c->poly1305);
|
||||
ret = PTR_ERR_OR_ZERO(c->poly1305);
|
||||
|
||||
if (ret) {
|
||||
bch_err(c, "error requesting poly1305 module: %s", bch2_err_str(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -626,7 +631,7 @@ int bch2_enable_encryption(struct bch_fs *c, bool keyed)
|
||||
if (keyed) {
|
||||
ret = bch2_request_key(c->disk_sb.sb, &user_key);
|
||||
if (ret) {
|
||||
bch_err(c, "error requesting encryption key: %i", ret);
|
||||
bch_err(c, "error requesting encryption key: %s", bch2_err_str(ret));
|
||||
goto err;
|
||||
}
|
||||
|
||||
@ -678,9 +683,9 @@ int bch2_fs_encryption_init(struct bch_fs *c)
|
||||
pr_verbose_init(c->opts, "");
|
||||
|
||||
c->sha256 = crypto_alloc_shash("sha256", 0, 0);
|
||||
if (IS_ERR(c->sha256)) {
|
||||
bch_err(c, "error requesting sha256 module");
|
||||
ret = PTR_ERR(c->sha256);
|
||||
ret = PTR_ERR_OR_ZERO(c->sha256);
|
||||
if (ret) {
|
||||
bch_err(c, "error requesting sha256 module: %s", bch2_err_str(ret));
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -236,7 +236,7 @@ static int bch2_data_update_index_update(struct bch_write_op *op)
|
||||
bch2_ob_add_backpointer(c, ec_ob, &insert->k);
|
||||
}
|
||||
err:
|
||||
if (ret == -EINTR)
|
||||
if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
|
||||
ret = 0;
|
||||
if (ret)
|
||||
break;
|
||||
@ -272,7 +272,7 @@ out:
|
||||
bch2_trans_exit(&trans);
|
||||
bch2_bkey_buf_exit(&_insert, c);
|
||||
bch2_bkey_buf_exit(&_new, c);
|
||||
BUG_ON(ret == -EINTR);
|
||||
BUG_ON(bch2_err_matches(ret, BCH_ERR_transaction_restart));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -189,6 +189,7 @@ struct dump_iter {
|
||||
struct bch_fs *c;
|
||||
enum btree_id id;
|
||||
struct bpos from;
|
||||
struct bpos prev_node;
|
||||
u64 iter;
|
||||
|
||||
struct printbuf buf;
|
||||
@ -258,39 +259,30 @@ static ssize_t bch2_read_btree(struct file *file, char __user *buf,
|
||||
i->size = size;
|
||||
i->ret = 0;
|
||||
|
||||
err = flush_buf(i);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!i->size)
|
||||
return i->ret;
|
||||
|
||||
bch2_trans_init(&trans, i->c, 0, 0);
|
||||
|
||||
bch2_trans_iter_init(&trans, &iter, i->id, i->from,
|
||||
BTREE_ITER_PREFETCH|
|
||||
BTREE_ITER_ALL_SNAPSHOTS);
|
||||
k = bch2_btree_iter_peek(&iter);
|
||||
|
||||
while (k.k && !(err = bkey_err(k))) {
|
||||
bch2_bkey_val_to_text(&i->buf, i->c, k);
|
||||
prt_char(&i->buf, '\n');
|
||||
|
||||
k = bch2_btree_iter_next(&iter);
|
||||
i->from = iter.pos;
|
||||
|
||||
err = for_each_btree_key2(&trans, iter, i->id, i->from,
|
||||
BTREE_ITER_PREFETCH|
|
||||
BTREE_ITER_ALL_SNAPSHOTS, k, ({
|
||||
err = flush_buf(i);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
if (!i->size)
|
||||
break;
|
||||
}
|
||||
bch2_trans_iter_exit(&trans, &iter);
|
||||
|
||||
bch2_bkey_val_to_text(&i->buf, i->c, k);
|
||||
prt_newline(&i->buf);
|
||||
0;
|
||||
}));
|
||||
i->from = iter.pos;
|
||||
|
||||
if (!err)
|
||||
err = flush_buf(i);
|
||||
|
||||
bch2_trans_exit(&trans);
|
||||
|
||||
return err < 0 ? err : i->ret;
|
||||
return err ?: i->ret;
|
||||
}
|
||||
|
||||
static const struct file_operations btree_debug_ops = {
|
||||
@ -360,7 +352,6 @@ static ssize_t bch2_read_bfloat_failed(struct file *file, char __user *buf,
|
||||
struct btree_trans trans;
|
||||
struct btree_iter iter;
|
||||
struct bkey_s_c k;
|
||||
struct btree *prev_node = NULL;
|
||||
int err;
|
||||
|
||||
i->ubuf = buf;
|
||||
@ -376,44 +367,36 @@ static ssize_t bch2_read_bfloat_failed(struct file *file, char __user *buf,
|
||||
|
||||
bch2_trans_init(&trans, i->c, 0, 0);
|
||||
|
||||
bch2_trans_iter_init(&trans, &iter, i->id, i->from,
|
||||
BTREE_ITER_PREFETCH|
|
||||
BTREE_ITER_ALL_SNAPSHOTS);
|
||||
|
||||
while ((k = bch2_btree_iter_peek(&iter)).k &&
|
||||
!(err = bkey_err(k))) {
|
||||
err = for_each_btree_key2(&trans, iter, i->id, i->from,
|
||||
BTREE_ITER_PREFETCH|
|
||||
BTREE_ITER_ALL_SNAPSHOTS, k, ({
|
||||
struct btree_path_level *l = &iter.path->l[0];
|
||||
struct bkey_packed *_k =
|
||||
bch2_btree_node_iter_peek(&l->iter, l->b);
|
||||
|
||||
if (l->b != prev_node) {
|
||||
bch2_btree_node_to_text(&i->buf, i->c, l->b);
|
||||
err = flush_buf(i);
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
prev_node = l->b;
|
||||
|
||||
bch2_bfloat_to_text(&i->buf, l->b, _k);
|
||||
err = flush_buf(i);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
bch2_btree_iter_advance(&iter);
|
||||
i->from = iter.pos;
|
||||
|
||||
err = flush_buf(i);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
if (!i->size)
|
||||
break;
|
||||
}
|
||||
bch2_trans_iter_exit(&trans, &iter);
|
||||
|
||||
if (bpos_cmp(l->b->key.k.p, i->prev_node) > 0) {
|
||||
bch2_btree_node_to_text(&i->buf, i->c, l->b);
|
||||
i->prev_node = l->b->key.k.p;
|
||||
}
|
||||
|
||||
bch2_bfloat_to_text(&i->buf, l->b, _k);
|
||||
0;
|
||||
}));
|
||||
i->from = iter.pos;
|
||||
|
||||
if (!err)
|
||||
err = flush_buf(i);
|
||||
|
||||
bch2_trans_exit(&trans);
|
||||
|
||||
return err < 0 ? err : i->ret;
|
||||
return err ?: i->ret;
|
||||
}
|
||||
|
||||
static const struct file_operations bfloat_failed_debug_ops = {
|
||||
@ -636,6 +619,75 @@ static const struct file_operations journal_pins_ops = {
|
||||
.read = bch2_journal_pins_read,
|
||||
};
|
||||
|
||||
static int lock_held_stats_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct bch_fs *c = inode->i_private;
|
||||
struct dump_iter *i;
|
||||
|
||||
i = kzalloc(sizeof(struct dump_iter), GFP_KERNEL);
|
||||
|
||||
if (!i)
|
||||
return -ENOMEM;
|
||||
|
||||
i->iter = 0;
|
||||
i->c = c;
|
||||
i->buf = PRINTBUF;
|
||||
file->private_data = i;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lock_held_stats_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct dump_iter *i = file->private_data;
|
||||
|
||||
printbuf_exit(&i->buf);
|
||||
kfree(i);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t lock_held_stats_read(struct file *file, char __user *buf,
|
||||
size_t size, loff_t *ppos)
|
||||
{
|
||||
struct dump_iter *i = file->private_data;
|
||||
struct lock_held_stats *lhs = &i->c->lock_held_stats;
|
||||
int err;
|
||||
|
||||
i->ubuf = buf;
|
||||
i->size = size;
|
||||
i->ret = 0;
|
||||
|
||||
while (lhs->names[i->iter] != 0 && i->iter < BCH_LOCK_TIME_NR) {
|
||||
err = flush_buf(i);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!i->size)
|
||||
break;
|
||||
|
||||
prt_printf(&i->buf, "%s:", lhs->names[i->iter]);
|
||||
prt_newline(&i->buf);
|
||||
printbuf_indent_add(&i->buf, 8);
|
||||
bch2_time_stats_to_text(&i->buf, &lhs->times[i->iter]);
|
||||
printbuf_indent_sub(&i->buf, 8);
|
||||
prt_newline(&i->buf);
|
||||
i->iter++;
|
||||
}
|
||||
|
||||
if (i->buf.allocation_failure)
|
||||
return -ENOMEM;
|
||||
|
||||
return i->ret;
|
||||
}
|
||||
|
||||
static const struct file_operations lock_held_stats_op = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = lock_held_stats_open,
|
||||
.release = lock_held_stats_release,
|
||||
.read = lock_held_stats_read,
|
||||
};
|
||||
|
||||
void bch2_fs_debug_exit(struct bch_fs *c)
|
||||
{
|
||||
if (!IS_ERR_OR_NULL(c->fs_debug_dir))
|
||||
@ -664,6 +716,11 @@ void bch2_fs_debug_init(struct bch_fs *c)
|
||||
debugfs_create_file("journal_pins", 0400, c->fs_debug_dir,
|
||||
c->btree_debug, &journal_pins_ops);
|
||||
|
||||
if (IS_ENABLED(CONFIG_BCACHEFS_LOCK_TIME_STATS)) {
|
||||
debugfs_create_file("lock_held_stats", 0400, c->fs_debug_dir,
|
||||
c, &lock_held_stats_op);
|
||||
}
|
||||
|
||||
c->btree_debug_dir = debugfs_create_dir("btrees", c->fs_debug_dir);
|
||||
if (IS_ERR_OR_NULL(c->btree_debug_dir))
|
||||
return;
|
||||
|
@ -471,7 +471,7 @@ retry:
|
||||
|
||||
ret = __bch2_dirent_lookup_trans(&trans, &iter, dir, hash_info,
|
||||
name, inum, 0);
|
||||
if (ret == -EINTR)
|
||||
if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
|
||||
goto retry;
|
||||
if (!ret)
|
||||
bch2_trans_iter_exit(&trans, &iter);
|
||||
@ -556,7 +556,7 @@ retry:
|
||||
}
|
||||
bch2_trans_iter_exit(&trans, &iter);
|
||||
err:
|
||||
if (ret == -EINTR)
|
||||
if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
|
||||
goto retry;
|
||||
|
||||
bch2_trans_exit(&trans);
|
||||
|
146
libbcachefs/ec.c
146
libbcachefs/ec.c
@ -572,18 +572,14 @@ static int ec_stripe_mem_alloc(struct btree_trans *trans,
|
||||
struct btree_iter *iter)
|
||||
{
|
||||
size_t idx = iter->pos.offset;
|
||||
int ret = 0;
|
||||
|
||||
if (!__ec_stripe_mem_alloc(trans->c, idx, GFP_NOWAIT|__GFP_NOWARN))
|
||||
return ret;
|
||||
return 0;
|
||||
|
||||
bch2_trans_unlock(trans);
|
||||
ret = -EINTR;
|
||||
|
||||
if (!__ec_stripe_mem_alloc(trans->c, idx, GFP_KERNEL))
|
||||
return ret;
|
||||
|
||||
return -ENOMEM;
|
||||
return __ec_stripe_mem_alloc(trans->c, idx, GFP_KERNEL) ?:
|
||||
bch2_trans_relock(trans);
|
||||
}
|
||||
|
||||
static ssize_t stripe_idx_to_delete(struct bch_fs *c)
|
||||
@ -726,7 +722,7 @@ static int ec_stripe_bkey_insert(struct btree_trans *trans,
|
||||
struct bpos start_pos = bpos_max(min_pos, POS(0, c->ec_stripe_hint));
|
||||
int ret;
|
||||
|
||||
for_each_btree_key(trans, iter, BTREE_ID_stripes, start_pos,
|
||||
for_each_btree_key_norestart(trans, iter, BTREE_ID_stripes, start_pos,
|
||||
BTREE_ITER_SLOTS|BTREE_ITER_INTENT, k, ret) {
|
||||
if (bkey_cmp(k.k->p, POS(0, U32_MAX)) > 0) {
|
||||
if (start_pos.offset) {
|
||||
@ -740,12 +736,13 @@ static int ec_stripe_bkey_insert(struct btree_trans *trans,
|
||||
}
|
||||
|
||||
if (bkey_deleted(k.k))
|
||||
goto found_slot;
|
||||
break;
|
||||
}
|
||||
|
||||
goto err;
|
||||
found_slot:
|
||||
start_pos = iter.pos;
|
||||
c->ec_stripe_hint = iter.pos.offset;
|
||||
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = ec_stripe_mem_alloc(trans, &iter);
|
||||
if (ret)
|
||||
@ -754,8 +751,6 @@ found_slot:
|
||||
stripe->k.p = iter.pos;
|
||||
|
||||
ret = bch2_trans_update(trans, &iter, &stripe->k_i, 0);
|
||||
|
||||
c->ec_stripe_hint = start_pos.offset;
|
||||
err:
|
||||
bch2_trans_iter_exit(trans, &iter);
|
||||
|
||||
@ -822,80 +817,62 @@ static void extent_stripe_ptr_add(struct bkey_s_extent e,
|
||||
};
|
||||
}
|
||||
|
||||
static int ec_stripe_update_ptrs(struct bch_fs *c,
|
||||
static int ec_stripe_update_extent(struct btree_trans *trans,
|
||||
struct btree_iter *iter,
|
||||
struct bkey_s_c k,
|
||||
struct ec_stripe_buf *s,
|
||||
struct bpos end)
|
||||
{
|
||||
const struct bch_extent_ptr *ptr_c;
|
||||
struct bch_extent_ptr *ptr, *ec_ptr = NULL;
|
||||
struct bkey_i *n;
|
||||
int ret, dev, block;
|
||||
|
||||
if (bkey_cmp(bkey_start_pos(k.k), end) >= 0)
|
||||
return 1;
|
||||
|
||||
if (extent_has_stripe_ptr(k, s->key.k.p.offset))
|
||||
return 0;
|
||||
|
||||
ptr_c = bkey_matches_stripe(&s->key.v, k, &block);
|
||||
/*
|
||||
* It doesn't generally make sense to erasure code cached ptrs:
|
||||
* XXX: should we be incrementing a counter?
|
||||
*/
|
||||
if (!ptr_c || ptr_c->cached)
|
||||
return 0;
|
||||
|
||||
dev = s->key.v.ptrs[block].dev;
|
||||
|
||||
n = bch2_trans_kmalloc(trans, bkey_bytes(k.k));
|
||||
ret = PTR_ERR_OR_ZERO(n);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
bkey_reassemble(n, k);
|
||||
|
||||
bch2_bkey_drop_ptrs(bkey_i_to_s(n), ptr, ptr->dev != dev);
|
||||
ec_ptr = (void *) bch2_bkey_has_device(bkey_i_to_s_c(n), dev);
|
||||
BUG_ON(!ec_ptr);
|
||||
|
||||
extent_stripe_ptr_add(bkey_i_to_s_extent(n), s, ec_ptr, block);
|
||||
|
||||
return bch2_trans_update(trans, iter, n, 0);
|
||||
}
|
||||
|
||||
static int ec_stripe_update_extents(struct bch_fs *c,
|
||||
struct ec_stripe_buf *s,
|
||||
struct bkey *pos)
|
||||
{
|
||||
struct btree_trans trans;
|
||||
struct btree_iter iter;
|
||||
struct bkey_s_c k;
|
||||
struct bkey_s_extent e;
|
||||
struct bkey_buf sk;
|
||||
struct bpos next_pos;
|
||||
int ret = 0, dev, block;
|
||||
|
||||
bch2_bkey_buf_init(&sk);
|
||||
bch2_trans_init(&trans, c, BTREE_ITER_MAX, 0);
|
||||
|
||||
/* XXX this doesn't support the reflink btree */
|
||||
|
||||
bch2_trans_iter_init(&trans, &iter, BTREE_ID_extents,
|
||||
bkey_start_pos(pos),
|
||||
BTREE_ITER_INTENT);
|
||||
retry:
|
||||
while (bch2_trans_begin(&trans),
|
||||
(k = bch2_btree_iter_peek(&iter)).k &&
|
||||
!(ret = bkey_err(k)) &&
|
||||
bkey_cmp(bkey_start_pos(k.k), pos->p) < 0) {
|
||||
const struct bch_extent_ptr *ptr_c;
|
||||
struct bch_extent_ptr *ptr, *ec_ptr = NULL;
|
||||
|
||||
if (extent_has_stripe_ptr(k, s->key.k.p.offset)) {
|
||||
bch2_btree_iter_advance(&iter);
|
||||
continue;
|
||||
}
|
||||
|
||||
ptr_c = bkey_matches_stripe(&s->key.v, k, &block);
|
||||
/*
|
||||
* It doesn't generally make sense to erasure code cached ptrs:
|
||||
* XXX: should we be incrementing a counter?
|
||||
*/
|
||||
if (!ptr_c || ptr_c->cached) {
|
||||
bch2_btree_iter_advance(&iter);
|
||||
continue;
|
||||
}
|
||||
|
||||
dev = s->key.v.ptrs[block].dev;
|
||||
|
||||
bch2_bkey_buf_reassemble(&sk, c, k);
|
||||
e = bkey_i_to_s_extent(sk.k);
|
||||
|
||||
bch2_bkey_drop_ptrs(e.s, ptr, ptr->dev != dev);
|
||||
ec_ptr = (void *) bch2_bkey_has_device(e.s_c, dev);
|
||||
BUG_ON(!ec_ptr);
|
||||
|
||||
extent_stripe_ptr_add(e, s, ec_ptr, block);
|
||||
|
||||
bch2_btree_iter_set_pos(&iter, bkey_start_pos(&sk.k->k));
|
||||
next_pos = sk.k->k.p;
|
||||
|
||||
ret = bch2_btree_iter_traverse(&iter) ?:
|
||||
bch2_trans_update(&trans, &iter, sk.k, 0) ?:
|
||||
bch2_trans_commit(&trans, NULL, NULL,
|
||||
BTREE_INSERT_NOFAIL);
|
||||
if (!ret)
|
||||
bch2_btree_iter_set_pos(&iter, next_pos);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
if (ret == -EINTR)
|
||||
goto retry;
|
||||
bch2_trans_iter_exit(&trans, &iter);
|
||||
|
||||
bch2_trans_exit(&trans);
|
||||
bch2_bkey_buf_exit(&sk, c);
|
||||
|
||||
return ret;
|
||||
return bch2_trans_run(c,
|
||||
for_each_btree_key_commit(&trans, iter,
|
||||
BTREE_ID_extents, bkey_start_pos(pos),
|
||||
BTREE_ITER_NOT_EXTENTS|BTREE_ITER_INTENT, k,
|
||||
NULL, NULL, BTREE_INSERT_NOFAIL,
|
||||
ec_stripe_update_extent(&trans, &iter, k, s, pos->p)));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -966,9 +943,10 @@ static void ec_stripe_create(struct ec_stripe_new *s)
|
||||
}
|
||||
|
||||
for_each_keylist_key(&s->keys, k) {
|
||||
ret = ec_stripe_update_ptrs(c, &s->new_stripe, &k->k);
|
||||
ret = ec_stripe_update_extents(c, &s->new_stripe, &k->k);
|
||||
if (ret) {
|
||||
bch_err(c, "error creating stripe: error %i updating pointers", ret);
|
||||
bch_err(c, "error creating stripe: error updating pointers: %s",
|
||||
bch2_err_str(ret));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
51
libbcachefs/errcode.c
Normal file
51
libbcachefs/errcode.c
Normal file
@ -0,0 +1,51 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#include "bcachefs.h"
|
||||
#include "errcode.h"
|
||||
|
||||
#include <linux/errname.h>
|
||||
|
||||
static const char * const bch2_errcode_strs[] = {
|
||||
#define x(class, err) [BCH_ERR_##err - BCH_ERR_START] = #err,
|
||||
BCH_ERRCODES()
|
||||
#undef x
|
||||
NULL
|
||||
};
|
||||
|
||||
#define BCH_ERR_0 0
|
||||
|
||||
static unsigned bch2_errcode_parents[] = {
|
||||
#define x(class, err) [BCH_ERR_##err - BCH_ERR_START] = BCH_ERR_##class,
|
||||
BCH_ERRCODES()
|
||||
#undef x
|
||||
};
|
||||
|
||||
const char *bch2_err_str(int err)
|
||||
{
|
||||
const char *errstr;
|
||||
err = abs(err);
|
||||
|
||||
BUG_ON(err >= BCH_ERR_MAX);
|
||||
|
||||
if (err >= BCH_ERR_START)
|
||||
errstr = bch2_errcode_strs[err - BCH_ERR_START];
|
||||
else if (err)
|
||||
errstr = errname(err);
|
||||
else
|
||||
errstr = "(No error)";
|
||||
return errstr ?: "(Invalid error)";
|
||||
}
|
||||
|
||||
bool __bch2_err_matches(int err, int class)
|
||||
{
|
||||
err = abs(err);
|
||||
class = abs(class);
|
||||
|
||||
BUG_ON(err >= BCH_ERR_MAX);
|
||||
BUG_ON(class >= BCH_ERR_MAX);
|
||||
|
||||
while (err >= BCH_ERR_START && err != class)
|
||||
err = bch2_errcode_parents[err - BCH_ERR_START];
|
||||
|
||||
return err == class;
|
||||
}
|
@ -2,12 +2,73 @@
|
||||
#ifndef _BCACHEFS_ERRCODE_H
|
||||
#define _BCACHEFS_ERRCODE_H
|
||||
|
||||
enum {
|
||||
/* Bucket allocator: */
|
||||
OPEN_BUCKETS_EMPTY = 2048,
|
||||
FREELIST_EMPTY, /* Allocator thread not keeping up */
|
||||
INSUFFICIENT_DEVICES,
|
||||
NEED_SNAPSHOT_CLEANUP,
|
||||
#define BCH_ERRCODES() \
|
||||
x(0, open_buckets_empty) \
|
||||
x(0, freelist_empty) \
|
||||
x(freelist_empty, no_buckets_found) \
|
||||
x(0, insufficient_devices) \
|
||||
x(0, transaction_restart) \
|
||||
x(transaction_restart, transaction_restart_fault_inject) \
|
||||
x(transaction_restart, transaction_restart_relock) \
|
||||
x(transaction_restart, transaction_restart_relock_path) \
|
||||
x(transaction_restart, transaction_restart_relock_path_intent) \
|
||||
x(transaction_restart, transaction_restart_relock_after_fill) \
|
||||
x(transaction_restart, transaction_restart_too_many_iters) \
|
||||
x(transaction_restart, transaction_restart_lock_node_reused) \
|
||||
x(transaction_restart, transaction_restart_fill_relock) \
|
||||
x(transaction_restart, transaction_restart_fill_mem_alloc_fail)\
|
||||
x(transaction_restart, transaction_restart_mem_realloced) \
|
||||
x(transaction_restart, transaction_restart_in_traverse_all) \
|
||||
x(transaction_restart, transaction_restart_would_deadlock) \
|
||||
x(transaction_restart, transaction_restart_would_deadlock_write)\
|
||||
x(transaction_restart, transaction_restart_upgrade) \
|
||||
x(transaction_restart, transaction_restart_key_cache_upgrade) \
|
||||
x(transaction_restart, transaction_restart_key_cache_fill) \
|
||||
x(transaction_restart, transaction_restart_key_cache_raced) \
|
||||
x(transaction_restart, transaction_restart_key_cache_realloced)\
|
||||
x(transaction_restart, transaction_restart_journal_preres_get) \
|
||||
x(transaction_restart, transaction_restart_nested) \
|
||||
x(0, no_btree_node) \
|
||||
x(no_btree_node, no_btree_node_relock) \
|
||||
x(no_btree_node, no_btree_node_upgrade) \
|
||||
x(no_btree_node, no_btree_node_drop) \
|
||||
x(no_btree_node, no_btree_node_lock_root) \
|
||||
x(no_btree_node, no_btree_node_up) \
|
||||
x(no_btree_node, no_btree_node_down) \
|
||||
x(no_btree_node, no_btree_node_init) \
|
||||
x(no_btree_node, no_btree_node_cached) \
|
||||
x(0, lock_fail_node_reused) \
|
||||
x(0, lock_fail_root_changed) \
|
||||
x(0, journal_reclaim_would_deadlock) \
|
||||
x(0, fsck) \
|
||||
x(fsck, fsck_fix) \
|
||||
x(fsck, fsck_ignore) \
|
||||
x(fsck, fsck_errors_not_fixed) \
|
||||
x(fsck, fsck_repair_unimplemented) \
|
||||
x(fsck, fsck_repair_impossible) \
|
||||
x(0, need_snapshot_cleanup) \
|
||||
x(0, need_topology_repair)
|
||||
|
||||
enum bch_errcode {
|
||||
BCH_ERR_START = 2048,
|
||||
#define x(class, err) BCH_ERR_##err,
|
||||
BCH_ERRCODES()
|
||||
#undef x
|
||||
BCH_ERR_MAX
|
||||
};
|
||||
|
||||
const char *bch2_err_str(int);
|
||||
bool __bch2_err_matches(int, int);
|
||||
|
||||
static inline bool _bch2_err_matches(int err, int class)
|
||||
{
|
||||
return err && __bch2_err_matches(err, class);
|
||||
}
|
||||
|
||||
#define bch2_err_matches(_err, _class) \
|
||||
({ \
|
||||
BUILD_BUG_ON(!__builtin_constant_p(_class)); \
|
||||
_bch2_err_matches(_err, _class); \
|
||||
})
|
||||
|
||||
#endif /* _BCACHFES_ERRCODE_H */
|
||||
|
@ -68,8 +68,7 @@ void bch2_io_error(struct bch_dev *ca)
|
||||
#include "tools-util.h"
|
||||
#endif
|
||||
|
||||
enum fsck_err_ret bch2_fsck_err(struct bch_fs *c, unsigned flags,
|
||||
const char *fmt, ...)
|
||||
int bch2_fsck_err(struct bch_fs *c, unsigned flags, const char *fmt, ...)
|
||||
{
|
||||
struct fsck_err_state *s = NULL;
|
||||
va_list args;
|
||||
@ -83,10 +82,10 @@ enum fsck_err_ret bch2_fsck_err(struct bch_fs *c, unsigned flags,
|
||||
|
||||
if (c->opts.errors == BCH_ON_ERROR_continue) {
|
||||
bch_err(c, "fixing");
|
||||
return FSCK_ERR_FIX;
|
||||
return -BCH_ERR_fsck_fix;
|
||||
} else {
|
||||
bch2_inconsistent_error(c);
|
||||
return FSCK_ERR_EXIT;
|
||||
return -BCH_ERR_fsck_errors_not_fixed;
|
||||
}
|
||||
}
|
||||
|
||||
@ -156,14 +155,14 @@ print:
|
||||
|
||||
if (fix) {
|
||||
set_bit(BCH_FS_ERRORS_FIXED, &c->flags);
|
||||
return FSCK_ERR_FIX;
|
||||
return -BCH_ERR_fsck_fix;
|
||||
} else {
|
||||
set_bit(BCH_FS_ERRORS_NOT_FIXED, &c->flags);
|
||||
set_bit(BCH_FS_ERROR, &c->flags);
|
||||
return c->opts.fix_errors == FSCK_OPT_EXIT ||
|
||||
!(flags & FSCK_CAN_IGNORE)
|
||||
? FSCK_ERR_EXIT
|
||||
: FSCK_ERR_IGNORE;
|
||||
? -BCH_ERR_fsck_errors_not_fixed
|
||||
: -BCH_ERR_fsck_ignore;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -91,14 +91,6 @@ do { \
|
||||
* be able to repair:
|
||||
*/
|
||||
|
||||
enum {
|
||||
BCH_FSCK_OK = 0,
|
||||
BCH_FSCK_ERRORS_NOT_FIXED = 1,
|
||||
BCH_FSCK_REPAIR_UNIMPLEMENTED = 2,
|
||||
BCH_FSCK_REPAIR_IMPOSSIBLE = 3,
|
||||
BCH_FSCK_UNKNOWN_VERSION = 4,
|
||||
};
|
||||
|
||||
enum fsck_err_opts {
|
||||
FSCK_OPT_EXIT,
|
||||
FSCK_OPT_YES,
|
||||
@ -106,13 +98,6 @@ enum fsck_err_opts {
|
||||
FSCK_OPT_ASK,
|
||||
};
|
||||
|
||||
enum fsck_err_ret {
|
||||
FSCK_ERR_IGNORE = 0,
|
||||
FSCK_ERR_FIX = 1,
|
||||
FSCK_ERR_EXIT = 2,
|
||||
FSCK_ERR_START_TOPOLOGY_REPAIR = 3,
|
||||
};
|
||||
|
||||
struct fsck_err_state {
|
||||
struct list_head list;
|
||||
const char *fmt;
|
||||
@ -127,21 +112,21 @@ struct fsck_err_state {
|
||||
#define FSCK_NO_RATELIMIT (1 << 3)
|
||||
|
||||
__printf(3, 4) __cold
|
||||
enum fsck_err_ret bch2_fsck_err(struct bch_fs *,
|
||||
unsigned, const char *, ...);
|
||||
int bch2_fsck_err(struct bch_fs *, unsigned, const char *, ...);
|
||||
void bch2_flush_fsck_errs(struct bch_fs *);
|
||||
|
||||
#define __fsck_err(c, _flags, msg, ...) \
|
||||
({ \
|
||||
int _fix = bch2_fsck_err(c, _flags, msg, ##__VA_ARGS__);\
|
||||
int _ret = bch2_fsck_err(c, _flags, msg, ##__VA_ARGS__); \
|
||||
\
|
||||
if (_fix == FSCK_ERR_EXIT) { \
|
||||
if (_ret != -BCH_ERR_fsck_fix && \
|
||||
_ret != -BCH_ERR_fsck_ignore) { \
|
||||
bch_err(c, "Unable to continue, halting"); \
|
||||
ret = BCH_FSCK_ERRORS_NOT_FIXED; \
|
||||
ret = _ret; \
|
||||
goto fsck_err; \
|
||||
} \
|
||||
\
|
||||
_fix; \
|
||||
_ret == -BCH_ERR_fsck_fix; \
|
||||
})
|
||||
|
||||
/* These macros return true if error should be fixed: */
|
||||
|
@ -409,7 +409,7 @@ retry:
|
||||
offset = iter.pos.offset;
|
||||
bch2_trans_iter_exit(&trans, &iter);
|
||||
err:
|
||||
if (ret == -EINTR)
|
||||
if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
|
||||
goto retry;
|
||||
bch2_trans_exit(&trans);
|
||||
|
||||
@ -850,13 +850,13 @@ void bch2_invalidate_folio(struct folio *folio, size_t offset, size_t length)
|
||||
bch2_clear_page_bits(&folio->page);
|
||||
}
|
||||
|
||||
int bch2_releasepage(struct page *page, gfp_t gfp_mask)
|
||||
bool bch2_release_folio(struct folio *folio, gfp_t gfp_mask)
|
||||
{
|
||||
if (PageDirty(page))
|
||||
return 0;
|
||||
if (folio_test_dirty(folio) || folio_test_writeback(folio))
|
||||
return false;
|
||||
|
||||
bch2_clear_page_bits(page);
|
||||
return 1;
|
||||
bch2_clear_page_bits(&folio->page);
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MIGRATION
|
||||
@ -1045,10 +1045,9 @@ retry:
|
||||
* read_extent -> io_time_reset may cause a transaction restart
|
||||
* without returning an error, we need to check for that here:
|
||||
*/
|
||||
if (!bch2_trans_relock(trans)) {
|
||||
ret = -EINTR;
|
||||
ret = bch2_trans_relock(trans);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
|
||||
bch2_btree_iter_set_pos(&iter,
|
||||
POS(inum.inum, rbio->bio.bi_iter.bi_sector));
|
||||
@ -1101,7 +1100,7 @@ retry:
|
||||
err:
|
||||
bch2_trans_iter_exit(trans, &iter);
|
||||
|
||||
if (ret == -EINTR)
|
||||
if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
|
||||
goto retry;
|
||||
|
||||
if (ret) {
|
||||
@ -1175,20 +1174,6 @@ static void __bchfs_readpage(struct bch_fs *c, struct bch_read_bio *rbio,
|
||||
bch2_trans_exit(&trans);
|
||||
}
|
||||
|
||||
int bch2_readpage(struct file *file, struct page *page)
|
||||
{
|
||||
struct bch_inode_info *inode = to_bch_ei(page->mapping->host);
|
||||
struct bch_fs *c = inode->v.i_sb->s_fs_info;
|
||||
struct bch_io_opts opts = io_opts(c, &inode->ei_inode);
|
||||
struct bch_read_bio *rbio;
|
||||
|
||||
rbio = rbio_init(bio_alloc_bioset(NULL, 1, REQ_OP_READ, GFP_NOFS, &c->bio_read), opts);
|
||||
rbio->bio.bi_end_io = bch2_readpages_end_io;
|
||||
|
||||
__bchfs_readpage(c, rbio, inode_inum(inode), page);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bch2_read_single_page_end_io(struct bio *bio)
|
||||
{
|
||||
complete(bio->bi_private);
|
||||
@ -1221,6 +1206,16 @@ static int bch2_read_single_page(struct page *page,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bch2_read_folio(struct file *file, struct folio *folio)
|
||||
{
|
||||
struct page *page = &folio->page;
|
||||
int ret;
|
||||
|
||||
ret = bch2_read_single_page(page, page->mapping);
|
||||
folio_unlock(folio);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* writepages: */
|
||||
|
||||
struct bch_writepage_state {
|
||||
@ -1512,7 +1507,7 @@ int bch2_writepages(struct address_space *mapping, struct writeback_control *wbc
|
||||
/* buffered writes: */
|
||||
|
||||
int bch2_write_begin(struct file *file, struct address_space *mapping,
|
||||
loff_t pos, unsigned len, unsigned flags,
|
||||
loff_t pos, unsigned len,
|
||||
struct page **pagep, void **fsdata)
|
||||
{
|
||||
struct bch_inode_info *inode = to_bch_ei(mapping->host);
|
||||
@ -1532,7 +1527,7 @@ int bch2_write_begin(struct file *file, struct address_space *mapping,
|
||||
|
||||
bch2_pagecache_add_get(&inode->ei_pagecache_lock);
|
||||
|
||||
page = grab_cache_page_write_begin(mapping, index, flags);
|
||||
page = grab_cache_page_write_begin(mapping, index);
|
||||
if (!page)
|
||||
goto err_unlock;
|
||||
|
||||
@ -1663,7 +1658,7 @@ static int __bch2_buffered_write(struct bch_inode_info *inode,
|
||||
bch2_page_reservation_init(c, inode, &res);
|
||||
|
||||
for (i = 0; i < nr_pages; i++) {
|
||||
pages[i] = grab_cache_page_write_begin(mapping, index + i, 0);
|
||||
pages[i] = grab_cache_page_write_begin(mapping, index + i);
|
||||
if (!pages[i]) {
|
||||
nr_pages = i;
|
||||
if (!i) {
|
||||
@ -2073,7 +2068,7 @@ retry:
|
||||
offset = iter.pos.offset;
|
||||
bch2_trans_iter_exit(&trans, &iter);
|
||||
err:
|
||||
if (err == -EINTR)
|
||||
if (bch2_err_matches(err, BCH_ERR_transaction_restart))
|
||||
goto retry;
|
||||
bch2_trans_exit(&trans);
|
||||
|
||||
@ -2449,7 +2444,7 @@ retry:
|
||||
start = iter.pos;
|
||||
bch2_trans_iter_exit(&trans, &iter);
|
||||
err:
|
||||
if (ret == -EINTR)
|
||||
if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
|
||||
goto retry;
|
||||
|
||||
bch2_trans_exit(&trans);
|
||||
@ -2839,7 +2834,8 @@ static long bchfs_fcollapse_finsert(struct bch_inode_info *inode,
|
||||
bch2_trans_copy_iter(&dst, &src);
|
||||
bch2_trans_copy_iter(&del, &src);
|
||||
|
||||
while (ret == 0 || ret == -EINTR) {
|
||||
while (ret == 0 ||
|
||||
bch2_err_matches(ret, BCH_ERR_transaction_restart)) {
|
||||
struct disk_reservation disk_res =
|
||||
bch2_disk_reservation_init(c, 0);
|
||||
struct bkey_i delete;
|
||||
@ -3041,7 +3037,7 @@ static int __bchfs_fallocate(struct bch_inode_info *inode, int mode,
|
||||
bkey_err:
|
||||
bch2_quota_reservation_put(c, inode, "a_res);
|
||||
bch2_disk_reservation_put(c, &disk_res);
|
||||
if (ret == -EINTR)
|
||||
if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
@ -3321,7 +3317,7 @@ retry:
|
||||
}
|
||||
bch2_trans_iter_exit(&trans, &iter);
|
||||
err:
|
||||
if (ret == -EINTR)
|
||||
if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
|
||||
goto retry;
|
||||
|
||||
bch2_trans_exit(&trans);
|
||||
@ -3436,7 +3432,7 @@ retry:
|
||||
}
|
||||
bch2_trans_iter_exit(&trans, &iter);
|
||||
err:
|
||||
if (ret == -EINTR)
|
||||
if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
|
||||
goto retry;
|
||||
|
||||
bch2_trans_exit(&trans);
|
||||
|
@ -15,13 +15,13 @@ int __must_check bch2_write_inode_size(struct bch_fs *,
|
||||
struct bch_inode_info *,
|
||||
loff_t, unsigned);
|
||||
|
||||
int bch2_readpage(struct file *, struct page *);
|
||||
int bch2_read_folio(struct file *, struct folio *);
|
||||
|
||||
int bch2_writepages(struct address_space *, struct writeback_control *);
|
||||
void bch2_readahead(struct readahead_control *);
|
||||
|
||||
int bch2_write_begin(struct file *, struct address_space *, loff_t,
|
||||
unsigned, unsigned, struct page **, void **);
|
||||
unsigned, struct page **, void **);
|
||||
int bch2_write_end(struct file *, struct address_space *, loff_t,
|
||||
unsigned, unsigned, struct page *, void *);
|
||||
|
||||
@ -42,7 +42,7 @@ loff_t bch2_llseek(struct file *, loff_t, int);
|
||||
vm_fault_t bch2_page_fault(struct vm_fault *);
|
||||
vm_fault_t bch2_page_mkwrite(struct vm_fault *);
|
||||
void bch2_invalidate_folio(struct folio *, size_t, size_t);
|
||||
int bch2_releasepage(struct page *, gfp_t);
|
||||
bool bch2_release_folio(struct folio *, gfp_t);
|
||||
int bch2_migrate_page(struct address_space *, struct page *,
|
||||
struct page *, enum migrate_mode);
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "buckets.h"
|
||||
#include "chardev.h"
|
||||
#include "dirent.h"
|
||||
#include "errcode.h"
|
||||
#include "extents.h"
|
||||
#include "fs.h"
|
||||
#include "fs-common.h"
|
||||
@ -153,7 +154,7 @@ retry:
|
||||
|
||||
bch2_trans_iter_exit(&trans, &iter);
|
||||
|
||||
if (ret == -EINTR)
|
||||
if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
|
||||
goto retry;
|
||||
|
||||
bch2_trans_exit(&trans);
|
||||
@ -323,7 +324,7 @@ retry:
|
||||
bch2_quota_acct(c, bch_qid(&inode_u), Q_INO, -1,
|
||||
KEY_TYPE_QUOTA_WARN);
|
||||
err_before_quota:
|
||||
if (ret == -EINTR)
|
||||
if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
|
||||
goto retry;
|
||||
goto err_trans;
|
||||
}
|
||||
@ -754,7 +755,7 @@ retry:
|
||||
btree_err:
|
||||
bch2_trans_iter_exit(&trans, &inode_iter);
|
||||
|
||||
if (ret == -EINTR)
|
||||
if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
|
||||
goto retry;
|
||||
if (unlikely(ret))
|
||||
goto err_trans;
|
||||
@ -985,7 +986,7 @@ retry:
|
||||
start = iter.pos.offset;
|
||||
bch2_trans_iter_exit(&trans, &iter);
|
||||
err:
|
||||
if (ret == -EINTR)
|
||||
if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
|
||||
goto retry;
|
||||
|
||||
if (!ret && have_extent)
|
||||
@ -1112,14 +1113,14 @@ static const struct inode_operations bch_special_inode_operations = {
|
||||
};
|
||||
|
||||
static const struct address_space_operations bch_address_space_operations = {
|
||||
.readpage = bch2_readpage,
|
||||
.read_folio = bch2_read_folio,
|
||||
.writepages = bch2_writepages,
|
||||
.readahead = bch2_readahead,
|
||||
.dirty_folio = filemap_dirty_folio,
|
||||
.write_begin = bch2_write_begin,
|
||||
.write_end = bch2_write_end,
|
||||
.invalidate_folio = bch2_invalidate_folio,
|
||||
.releasepage = bch2_releasepage,
|
||||
.release_folio = bch2_release_folio,
|
||||
.direct_IO = noop_direct_IO,
|
||||
#ifdef CONFIG_MIGRATION
|
||||
.migratepage = bch2_migrate_page,
|
||||
@ -1335,7 +1336,7 @@ found:
|
||||
memcpy(name, d.v->d_name, name_len);
|
||||
name[name_len] = '\0';
|
||||
err:
|
||||
if (ret == -EINTR)
|
||||
if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
|
||||
goto retry;
|
||||
|
||||
bch2_trans_iter_exit(&trans, &iter1);
|
||||
@ -1870,10 +1871,9 @@ got_sb:
|
||||
sb->s_shrink.seeks = 0;
|
||||
|
||||
vinode = bch2_vfs_inode_get(c, BCACHEFS_ROOT_SUBVOL_INUM);
|
||||
if (IS_ERR(vinode)) {
|
||||
bch_err(c, "error mounting: error getting root inode %i",
|
||||
(int) PTR_ERR(vinode));
|
||||
ret = PTR_ERR(vinode);
|
||||
ret = PTR_ERR_OR_ZERO(vinode);
|
||||
if (ret) {
|
||||
bch_err(c, "error mounting: error getting root inode: %s", bch2_err_str(ret));
|
||||
goto err_put_super;
|
||||
}
|
||||
|
||||
|
@ -136,9 +136,9 @@ static int lookup_first_inode(struct btree_trans *trans, u64 inode_nr,
|
||||
|
||||
ret = bch2_inode_unpack(k, inode);
|
||||
err:
|
||||
if (ret && ret != -EINTR)
|
||||
bch_err(trans->c, "error %i fetching inode %llu",
|
||||
ret, inode_nr);
|
||||
if (ret && !bch2_err_matches(ret, BCH_ERR_transaction_restart))
|
||||
bch_err(trans->c, "error fetching inode %llu: %s",
|
||||
inode_nr, bch2_err_str(ret));
|
||||
bch2_trans_iter_exit(trans, &iter);
|
||||
return ret;
|
||||
}
|
||||
@ -164,9 +164,9 @@ static int __lookup_inode(struct btree_trans *trans, u64 inode_nr,
|
||||
if (!ret)
|
||||
*snapshot = iter.pos.snapshot;
|
||||
err:
|
||||
if (ret && ret != -EINTR)
|
||||
bch_err(trans->c, "error %i fetching inode %llu:%u",
|
||||
ret, inode_nr, *snapshot);
|
||||
if (ret && !bch2_err_matches(ret, BCH_ERR_transaction_restart))
|
||||
bch_err(trans->c, "error fetching inode %llu:%u: %s",
|
||||
inode_nr, *snapshot, bch2_err_str(ret));
|
||||
bch2_trans_iter_exit(trans, &iter);
|
||||
return ret;
|
||||
}
|
||||
@ -225,7 +225,8 @@ static int write_inode(struct btree_trans *trans,
|
||||
BTREE_INSERT_LAZY_RW,
|
||||
__write_inode(trans, inode, snapshot));
|
||||
if (ret)
|
||||
bch_err(trans->c, "error in fsck: error %i updating inode", ret);
|
||||
bch_err(trans->c, "error in fsck: error updating inode: %s",
|
||||
bch2_err_str(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -286,7 +287,7 @@ retry:
|
||||
BTREE_INSERT_NOFAIL);
|
||||
err:
|
||||
bch2_trans_iter_exit(trans, &iter);
|
||||
if (ret == -EINTR)
|
||||
if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
|
||||
goto retry;
|
||||
|
||||
return ret;
|
||||
@ -313,8 +314,8 @@ static int __remove_dirent(struct btree_trans *trans, struct bpos pos)
|
||||
BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE);
|
||||
bch2_trans_iter_exit(trans, &iter);
|
||||
err:
|
||||
if (ret && ret != -EINTR)
|
||||
bch_err(c, "error %i from __remove_dirent()", ret);
|
||||
if (ret && !bch2_err_matches(ret, BCH_ERR_transaction_restart))
|
||||
bch_err(c, "error from __remove_dirent(): %s", bch2_err_str(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -349,8 +350,8 @@ static int lookup_lostfound(struct btree_trans *trans, u32 subvol,
|
||||
goto create_lostfound;
|
||||
}
|
||||
|
||||
if (ret && ret != -EINTR)
|
||||
bch_err(c, "error looking up lost+found: %i", ret);
|
||||
if (ret && !bch2_err_matches(ret, BCH_ERR_transaction_restart))
|
||||
bch_err(c, "error looking up lost+found: %s", bch2_err_str(ret));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -372,8 +373,8 @@ create_lostfound:
|
||||
lostfound, &lostfound_str,
|
||||
0, 0, S_IFDIR|0700, 0, NULL, NULL,
|
||||
(subvol_inum) { }, 0);
|
||||
if (ret && ret != -EINTR)
|
||||
bch_err(c, "error creating lost+found: %i", ret);
|
||||
if (ret && !bch2_err_matches(ret, BCH_ERR_transaction_restart))
|
||||
bch_err(c, "error creating lost+found: %s", bch2_err_str(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -437,8 +438,8 @@ static int reattach_inode(struct btree_trans *trans,
|
||||
BTREE_INSERT_NOFAIL,
|
||||
__reattach_inode(trans, inode, inode_snapshot));
|
||||
if (ret) {
|
||||
bch_err(trans->c, "error %i reattaching inode %llu",
|
||||
ret, inode->bi_inum);
|
||||
bch_err(trans->c, "error reattaching inode %llu: %s",
|
||||
inode->bi_inum, bch2_err_str(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -518,7 +519,7 @@ static int snapshots_seen_update(struct bch_fs *c, struct snapshots_seen *s,
|
||||
.id = pos.snapshot,
|
||||
.equiv = bch2_snapshot_equiv(c, pos.snapshot),
|
||||
};
|
||||
int ret;
|
||||
int ret = 0;
|
||||
|
||||
if (bkey_cmp(s->pos, pos))
|
||||
s->ids.nr = 0;
|
||||
@ -528,14 +529,13 @@ static int snapshots_seen_update(struct bch_fs *c, struct snapshots_seen *s,
|
||||
|
||||
darray_for_each(s->ids, i)
|
||||
if (i->equiv == n.equiv) {
|
||||
if (i->id != n.id) {
|
||||
bch_err(c, "snapshot deletion did not run correctly:\n"
|
||||
if (fsck_err_on(i->id != n.id, c,
|
||||
"snapshot deletion did not run correctly:\n"
|
||||
" duplicate keys in btree %s at %llu:%llu snapshots %u, %u (equiv %u)\n",
|
||||
bch2_btree_ids[btree_id],
|
||||
pos.inode, pos.offset,
|
||||
i->id, n.id, n.equiv);
|
||||
return -NEED_SNAPSHOT_CLEANUP;
|
||||
}
|
||||
i->id, n.id, n.equiv))
|
||||
return -BCH_ERR_need_snapshot_cleanup;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -544,6 +544,7 @@ static int snapshots_seen_update(struct bch_fs *c, struct snapshots_seen *s,
|
||||
if (ret)
|
||||
bch_err(c, "error reallocating snapshots_seen table (size %zu)",
|
||||
s->ids.size);
|
||||
fsck_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -649,6 +650,7 @@ static int __walk_inode(struct btree_trans *trans,
|
||||
struct bch_fs *c = trans->c;
|
||||
struct btree_iter iter;
|
||||
struct bkey_s_c k;
|
||||
u32 restart_count = trans->restart_count;
|
||||
unsigned i;
|
||||
int ret;
|
||||
|
||||
@ -676,6 +678,10 @@ static int __walk_inode(struct btree_trans *trans,
|
||||
|
||||
w->cur_inum = pos.inode;
|
||||
w->first_this_inode = true;
|
||||
|
||||
if (trans_was_restarted(trans, restart_count))
|
||||
return -BCH_ERR_transaction_restart_nested;
|
||||
|
||||
lookup_snapshot:
|
||||
for (i = 0; i < w->inodes.nr; i++)
|
||||
if (bch2_snapshot_is_ancestor(c, pos.snapshot, w->inodes.data[i].snapshot))
|
||||
@ -837,15 +843,14 @@ bad_hash:
|
||||
"hashed to %llu\n%s",
|
||||
bch2_btree_ids[desc.btree_id], hash_k.k->p.inode, hash_k.k->p.offset, hash,
|
||||
(printbuf_reset(&buf),
|
||||
bch2_bkey_val_to_text(&buf, c, hash_k), buf.buf)) == FSCK_ERR_IGNORE)
|
||||
return 0;
|
||||
|
||||
ret = hash_redo_key(trans, desc, hash_info, k_iter, hash_k);
|
||||
if (ret) {
|
||||
bch_err(c, "hash_redo_key err %i", ret);
|
||||
return ret;
|
||||
bch2_bkey_val_to_text(&buf, c, hash_k), buf.buf))) {
|
||||
ret = hash_redo_key(trans, desc, hash_info, k_iter, hash_k);
|
||||
if (ret) {
|
||||
bch_err(c, "hash_redo_key err %s", bch2_err_str(ret));
|
||||
return ret;
|
||||
}
|
||||
ret = -BCH_ERR_transaction_restart_nested;
|
||||
}
|
||||
ret = -EINTR;
|
||||
fsck_err:
|
||||
goto out;
|
||||
}
|
||||
@ -910,7 +915,8 @@ static int check_inode(struct btree_trans *trans,
|
||||
|
||||
ret = fsck_inode_rm(trans, u.bi_inum, iter->pos.snapshot);
|
||||
if (ret)
|
||||
bch_err(c, "error in fsck: error %i while deleting inode", ret);
|
||||
bch_err(c, "error in fsck: error while deleting inode: %s",
|
||||
bch2_err_str(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -933,7 +939,8 @@ static int check_inode(struct btree_trans *trans,
|
||||
POS(u.bi_inum, U64_MAX),
|
||||
0, NULL);
|
||||
if (ret) {
|
||||
bch_err(c, "error in fsck: error %i truncating inode", ret);
|
||||
bch_err(c, "error in fsck: error truncating inode: %s",
|
||||
bch2_err_str(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -958,8 +965,8 @@ static int check_inode(struct btree_trans *trans,
|
||||
|
||||
sectors = bch2_count_inode_sectors(trans, u.bi_inum, iter->pos.snapshot);
|
||||
if (sectors < 0) {
|
||||
bch_err(c, "error in fsck: error %i recounting inode sectors",
|
||||
(int) sectors);
|
||||
bch_err(c, "error in fsck: error recounting inode sectors: %s",
|
||||
bch2_err_str(sectors));
|
||||
return sectors;
|
||||
}
|
||||
|
||||
@ -978,13 +985,13 @@ static int check_inode(struct btree_trans *trans,
|
||||
if (do_update) {
|
||||
ret = __write_inode(trans, &u, iter->pos.snapshot);
|
||||
if (ret)
|
||||
bch_err(c, "error in fsck: error %i "
|
||||
"updating inode", ret);
|
||||
bch_err(c, "error in fsck: error updating inode: %s",
|
||||
bch2_err_str(ret));
|
||||
}
|
||||
err:
|
||||
fsck_err:
|
||||
if (ret)
|
||||
bch_err(c, "error %i from check_inode()", ret);
|
||||
bch_err(c, "error from check_inode(): %s", bch2_err_str(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1003,16 +1010,14 @@ static int check_inodes(struct bch_fs *c, bool full)
|
||||
|
||||
ret = for_each_btree_key_commit(&trans, iter, BTREE_ID_inodes,
|
||||
POS_MIN,
|
||||
BTREE_ITER_PREFETCH|BTREE_ITER_ALL_SNAPSHOTS,
|
||||
k,
|
||||
NULL, NULL,
|
||||
BTREE_INSERT_LAZY_RW|BTREE_INSERT_NOFAIL,
|
||||
BTREE_ITER_PREFETCH|BTREE_ITER_ALL_SNAPSHOTS, k,
|
||||
NULL, NULL, BTREE_INSERT_LAZY_RW|BTREE_INSERT_NOFAIL,
|
||||
check_inode(&trans, &iter, k, &prev, &s, full));
|
||||
|
||||
bch2_trans_exit(&trans);
|
||||
snapshots_seen_exit(&s);
|
||||
if (ret)
|
||||
bch_err(c, "error %i from check_inodes()", ret);
|
||||
bch_err(c, "error from check_inodes(): %s", bch2_err_str(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1115,15 +1120,15 @@ static int check_i_sectors(struct btree_trans *trans, struct inode_walker *w)
|
||||
{
|
||||
struct bch_fs *c = trans->c;
|
||||
struct inode_walker_entry *i;
|
||||
int ret = 0, ret2 = 0;
|
||||
u32 restart_count = trans->restart_count;
|
||||
int ret = 0;
|
||||
s64 count2;
|
||||
|
||||
darray_for_each(w->inodes, i) {
|
||||
if (i->inode.bi_sectors == i->count)
|
||||
continue;
|
||||
|
||||
count2 = lockrestart_do(trans,
|
||||
bch2_count_inode_sectors(trans, w->cur_inum, i->snapshot));
|
||||
count2 = bch2_count_inode_sectors(trans, w->cur_inum, i->snapshot);
|
||||
|
||||
if (i->count != count2) {
|
||||
bch_err(c, "fsck counted i_sectors wrong: got %llu should be %llu",
|
||||
@ -1136,19 +1141,21 @@ static int check_i_sectors(struct btree_trans *trans, struct inode_walker *w)
|
||||
if (fsck_err_on(!(i->inode.bi_flags & BCH_INODE_I_SECTORS_DIRTY), c,
|
||||
"inode %llu:%u has incorrect i_sectors: got %llu, should be %llu",
|
||||
w->cur_inum, i->snapshot,
|
||||
i->inode.bi_sectors, i->count) == FSCK_ERR_IGNORE)
|
||||
continue;
|
||||
|
||||
i->inode.bi_sectors = i->count;
|
||||
ret = write_inode(trans, &i->inode, i->snapshot);
|
||||
if (ret)
|
||||
break;
|
||||
ret2 = -EINTR;
|
||||
i->inode.bi_sectors, i->count)) {
|
||||
i->inode.bi_sectors = i->count;
|
||||
ret = write_inode(trans, &i->inode, i->snapshot);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
}
|
||||
fsck_err:
|
||||
if (ret)
|
||||
bch_err(c, "error %i from check_i_sectors()", ret);
|
||||
return ret ?: ret2;
|
||||
if (ret) {
|
||||
bch_err(c, "error from check_i_sectors(): %s", bch2_err_str(ret));
|
||||
return ret;
|
||||
}
|
||||
if (trans_was_restarted(trans, restart_count))
|
||||
return -BCH_ERR_transaction_restart_nested;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int check_extent(struct btree_trans *trans, struct btree_iter *iter,
|
||||
@ -1184,14 +1191,7 @@ static int check_extent(struct btree_trans *trans, struct btree_iter *iter,
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!iter->path->should_be_locked) {
|
||||
/*
|
||||
* hack: check_i_sectors may have handled a transaction restart,
|
||||
* it shouldn't be but we need to fix the new i_sectors check
|
||||
* code and delete the old bch2_count_inode_sectors() first
|
||||
*/
|
||||
return -EINTR;
|
||||
}
|
||||
BUG_ON(!iter->path->should_be_locked);
|
||||
#if 0
|
||||
if (bkey_cmp(prev.k->k.p, bkey_start_pos(k.k)) > 0) {
|
||||
char buf1[200];
|
||||
@ -1201,7 +1201,8 @@ static int check_extent(struct btree_trans *trans, struct btree_iter *iter,
|
||||
bch2_bkey_val_to_text(&PBUF(buf2), c, k);
|
||||
|
||||
if (fsck_err(c, "overlapping extents:\n%s\n%s", buf1, buf2)) {
|
||||
ret = fix_overlapping_extent(trans, k, prev.k->k.p) ?: -EINTR;
|
||||
ret = fix_overlapping_extent(trans, k, prev.k->k.p)
|
||||
?: -BCH_ERR_transaction_restart_nested;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
@ -1286,8 +1287,8 @@ err:
|
||||
fsck_err:
|
||||
printbuf_exit(&buf);
|
||||
|
||||
if (ret && ret != -EINTR)
|
||||
bch_err(c, "error %i from check_extent()", ret);
|
||||
if (ret && !bch2_err_matches(ret, BCH_ERR_transaction_restart))
|
||||
bch_err(c, "error from check_extent(): %s", bch2_err_str(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1329,7 +1330,7 @@ static int check_extents(struct bch_fs *c)
|
||||
snapshots_seen_exit(&s);
|
||||
|
||||
if (ret)
|
||||
bch_err(c, "error %i from check_extents()", ret);
|
||||
bch_err(c, "error from check_extents(): %s", bch2_err_str(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1337,7 +1338,8 @@ static int check_subdir_count(struct btree_trans *trans, struct inode_walker *w)
|
||||
{
|
||||
struct bch_fs *c = trans->c;
|
||||
struct inode_walker_entry *i;
|
||||
int ret = 0, ret2 = 0;
|
||||
u32 restart_count = trans->restart_count;
|
||||
int ret = 0;
|
||||
s64 count2;
|
||||
|
||||
darray_for_each(w->inodes, i) {
|
||||
@ -1363,13 +1365,16 @@ static int check_subdir_count(struct btree_trans *trans, struct inode_walker *w)
|
||||
ret = write_inode(trans, &i->inode, i->snapshot);
|
||||
if (ret)
|
||||
break;
|
||||
ret2 = -EINTR;
|
||||
}
|
||||
}
|
||||
fsck_err:
|
||||
if (ret)
|
||||
bch_err(c, "error %i from check_subdir_count()", ret);
|
||||
return ret ?: ret2;
|
||||
if (ret) {
|
||||
bch_err(c, "error from check_subdir_count(): %s", bch2_err_str(ret));
|
||||
return ret;
|
||||
}
|
||||
if (trans_was_restarted(trans, restart_count))
|
||||
return -BCH_ERR_transaction_restart_nested;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int check_dirent_target(struct btree_trans *trans,
|
||||
@ -1486,8 +1491,8 @@ err:
|
||||
fsck_err:
|
||||
printbuf_exit(&buf);
|
||||
|
||||
if (ret && ret != -EINTR)
|
||||
bch_err(c, "error %i from check_target()", ret);
|
||||
if (ret && !bch2_err_matches(ret, BCH_ERR_transaction_restart))
|
||||
bch_err(c, "error from check_target(): %s", bch2_err_str(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1527,10 +1532,7 @@ static int check_dirent(struct btree_trans *trans, struct btree_iter *iter,
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!iter->path->should_be_locked) {
|
||||
/* hack: see check_extent() */
|
||||
return -EINTR;
|
||||
}
|
||||
BUG_ON(!iter->path->should_be_locked);
|
||||
|
||||
ret = __walk_inode(trans, dir, equiv);
|
||||
if (ret < 0)
|
||||
@ -1659,8 +1661,8 @@ err:
|
||||
fsck_err:
|
||||
printbuf_exit(&buf);
|
||||
|
||||
if (ret && ret != -EINTR)
|
||||
bch_err(c, "error %i from check_dirent()", ret);
|
||||
if (ret && !bch2_err_matches(ret, BCH_ERR_transaction_restart))
|
||||
bch_err(c, "error from check_dirent(): %s", bch2_err_str(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1699,7 +1701,7 @@ static int check_dirents(struct bch_fs *c)
|
||||
inode_walker_exit(&target);
|
||||
|
||||
if (ret)
|
||||
bch_err(c, "error %i from check_dirents()", ret);
|
||||
bch_err(c, "error from check_dirents(): %s", bch2_err_str(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1734,8 +1736,8 @@ static int check_xattr(struct btree_trans *trans, struct btree_iter *iter,
|
||||
|
||||
ret = hash_check_key(trans, bch2_xattr_hash_desc, hash_info, iter, k);
|
||||
fsck_err:
|
||||
if (ret && ret != -EINTR)
|
||||
bch_err(c, "error %i from check_xattr()", ret);
|
||||
if (ret && !bch2_err_matches(ret, BCH_ERR_transaction_restart))
|
||||
bch_err(c, "error from check_xattr(): %s", bch2_err_str(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1767,7 +1769,7 @@ static int check_xattrs(struct bch_fs *c)
|
||||
bch2_trans_exit(&trans);
|
||||
|
||||
if (ret)
|
||||
bch_err(c, "error %i from check_xattrs()", ret);
|
||||
bch_err(c, "error from check_xattrs(): %s", bch2_err_str(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1799,7 +1801,7 @@ static int check_root_trans(struct btree_trans *trans)
|
||||
BTREE_INSERT_LAZY_RW,
|
||||
__bch2_btree_insert(trans, BTREE_ID_subvolumes, &root_subvol.k_i));
|
||||
if (ret) {
|
||||
bch_err(c, "error writing root subvol: %i", ret);
|
||||
bch_err(c, "error writing root subvol: %s", bch2_err_str(ret));
|
||||
goto err;
|
||||
}
|
||||
|
||||
@ -1818,7 +1820,7 @@ static int check_root_trans(struct btree_trans *trans)
|
||||
|
||||
ret = __write_inode(trans, &root_inode, snapshot);
|
||||
if (ret)
|
||||
bch_err(c, "error writing root inode: %i", ret);
|
||||
bch_err(c, "error writing root inode: %s", bch2_err_str(ret));
|
||||
}
|
||||
err:
|
||||
fsck_err:
|
||||
@ -1971,7 +1973,7 @@ static int check_path(struct btree_trans *trans,
|
||||
}
|
||||
fsck_err:
|
||||
if (ret)
|
||||
bch_err(c, "%s: err %i", __func__, ret);
|
||||
bch_err(c, "%s: err %s", __func__, bch2_err_str(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -2015,8 +2017,6 @@ static int check_directory_structure(struct bch_fs *c)
|
||||
}
|
||||
bch2_trans_iter_exit(&trans, &iter);
|
||||
|
||||
BUG_ON(ret == -EINTR);
|
||||
|
||||
darray_exit(&path);
|
||||
|
||||
bch2_trans_exit(&trans);
|
||||
@ -2194,6 +2194,47 @@ static int check_nlinks_walk_dirents(struct bch_fs *c, struct nlink_table *links
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int check_nlinks_update_inode(struct btree_trans *trans, struct btree_iter *iter,
|
||||
struct bkey_s_c k,
|
||||
struct nlink_table *links,
|
||||
size_t *idx, u64 range_end)
|
||||
{
|
||||
struct bch_fs *c = trans->c;
|
||||
struct bch_inode_unpacked u;
|
||||
struct nlink *link = &links->d[*idx];
|
||||
int ret = 0;
|
||||
|
||||
if (k.k->p.offset >= range_end)
|
||||
return 1;
|
||||
|
||||
if (!bkey_is_inode(k.k))
|
||||
return 0;
|
||||
|
||||
BUG_ON(bch2_inode_unpack(k, &u));
|
||||
|
||||
if (S_ISDIR(le16_to_cpu(u.bi_mode)))
|
||||
return 0;
|
||||
|
||||
if (!u.bi_nlink)
|
||||
return 0;
|
||||
|
||||
while ((cmp_int(link->inum, k.k->p.offset) ?:
|
||||
cmp_int(link->snapshot, k.k->p.snapshot)) < 0) {
|
||||
BUG_ON(*idx == links->nr);
|
||||
link = &links->d[++*idx];
|
||||
}
|
||||
|
||||
if (fsck_err_on(bch2_inode_nlink_get(&u) != link->count, c,
|
||||
"inode %llu type %s has wrong i_nlink (%u, should be %u)",
|
||||
u.bi_inum, bch2_d_types[mode_to_type(u.bi_mode)],
|
||||
bch2_inode_nlink_get(&u), link->count)) {
|
||||
bch2_inode_nlink_set(&u, link->count);
|
||||
ret = __write_inode(trans, &u, k.k->p.snapshot);
|
||||
}
|
||||
fsck_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
noinline_for_stack
|
||||
static int check_nlinks_update_hardlinks(struct bch_fs *c,
|
||||
struct nlink_table *links,
|
||||
@ -2202,56 +2243,25 @@ static int check_nlinks_update_hardlinks(struct bch_fs *c,
|
||||
struct btree_trans trans;
|
||||
struct btree_iter iter;
|
||||
struct bkey_s_c k;
|
||||
struct bch_inode_unpacked u;
|
||||
struct nlink *link = links->d;
|
||||
size_t idx = 0;
|
||||
int ret = 0;
|
||||
|
||||
bch2_trans_init(&trans, c, BTREE_ITER_MAX, 0);
|
||||
|
||||
for_each_btree_key(&trans, iter, BTREE_ID_inodes,
|
||||
POS(0, range_start),
|
||||
BTREE_ITER_INTENT|
|
||||
BTREE_ITER_PREFETCH|
|
||||
BTREE_ITER_ALL_SNAPSHOTS, k, ret) {
|
||||
if (k.k->p.offset >= range_end)
|
||||
break;
|
||||
ret = for_each_btree_key_commit(&trans, iter, BTREE_ID_inodes,
|
||||
POS(0, range_start),
|
||||
BTREE_ITER_INTENT|BTREE_ITER_PREFETCH|BTREE_ITER_ALL_SNAPSHOTS, k,
|
||||
NULL, NULL, BTREE_INSERT_LAZY_RW|BTREE_INSERT_NOFAIL,
|
||||
check_nlinks_update_inode(&trans, &iter, k, links, &idx, range_end));
|
||||
|
||||
if (!bkey_is_inode(k.k))
|
||||
continue;
|
||||
|
||||
BUG_ON(bch2_inode_unpack(k, &u));
|
||||
|
||||
if (S_ISDIR(le16_to_cpu(u.bi_mode)))
|
||||
continue;
|
||||
|
||||
if (!u.bi_nlink)
|
||||
continue;
|
||||
|
||||
while ((cmp_int(link->inum, k.k->p.offset) ?:
|
||||
cmp_int(link->snapshot, k.k->p.snapshot)) < 0) {
|
||||
link++;
|
||||
BUG_ON(link >= links->d + links->nr);
|
||||
}
|
||||
|
||||
if (fsck_err_on(bch2_inode_nlink_get(&u) != link->count, c,
|
||||
"inode %llu type %s has wrong i_nlink (%u, should be %u)",
|
||||
u.bi_inum, bch2_d_types[mode_to_type(u.bi_mode)],
|
||||
bch2_inode_nlink_get(&u), link->count)) {
|
||||
bch2_inode_nlink_set(&u, link->count);
|
||||
|
||||
ret = write_inode(&trans, &u, k.k->p.snapshot);
|
||||
if (ret)
|
||||
bch_err(c, "error in fsck: error %i updating inode", ret);
|
||||
}
|
||||
}
|
||||
fsck_err:
|
||||
bch2_trans_iter_exit(&trans, &iter);
|
||||
bch2_trans_exit(&trans);
|
||||
|
||||
if (ret)
|
||||
if (ret < 0) {
|
||||
bch_err(c, "error in fsck: btree error %i while walking inodes", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
noinline_for_stack
|
||||
@ -2291,21 +2301,13 @@ static int check_nlinks(struct bch_fs *c)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fix_reflink_p_key(struct btree_trans *trans, struct btree_iter *iter)
|
||||
static int fix_reflink_p_key(struct btree_trans *trans, struct btree_iter *iter,
|
||||
struct bkey_s_c k)
|
||||
{
|
||||
struct bkey_s_c k;
|
||||
struct bkey_s_c_reflink_p p;
|
||||
struct bkey_i_reflink_p *u;
|
||||
int ret;
|
||||
|
||||
k = bch2_btree_iter_peek(iter);
|
||||
if (!k.k)
|
||||
return 0;
|
||||
|
||||
ret = bkey_err(k);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (k.k->type != KEY_TYPE_reflink_p)
|
||||
return 0;
|
||||
|
||||
@ -2341,20 +2343,11 @@ static int fix_reflink_p(struct bch_fs *c)
|
||||
|
||||
bch2_trans_init(&trans, c, BTREE_ITER_MAX, 0);
|
||||
|
||||
for_each_btree_key(&trans, iter, BTREE_ID_extents, POS_MIN,
|
||||
BTREE_ITER_INTENT|
|
||||
BTREE_ITER_PREFETCH|
|
||||
BTREE_ITER_ALL_SNAPSHOTS, k, ret) {
|
||||
if (k.k->type == KEY_TYPE_reflink_p) {
|
||||
ret = commit_do(&trans, NULL, NULL,
|
||||
BTREE_INSERT_NOFAIL|
|
||||
BTREE_INSERT_LAZY_RW,
|
||||
fix_reflink_p_key(&trans, &iter));
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
}
|
||||
bch2_trans_iter_exit(&trans, &iter);
|
||||
ret = for_each_btree_key_commit(&trans, iter,
|
||||
BTREE_ID_extents, POS_MIN,
|
||||
BTREE_ITER_INTENT|BTREE_ITER_PREFETCH|BTREE_ITER_ALL_SNAPSHOTS, k,
|
||||
NULL, NULL, BTREE_INSERT_NOFAIL|BTREE_INSERT_LAZY_RW,
|
||||
fix_reflink_p_key(&trans, &iter, k));
|
||||
|
||||
bch2_trans_exit(&trans);
|
||||
return ret;
|
||||
@ -2380,7 +2373,7 @@ again:
|
||||
check_nlinks(c) ?:
|
||||
fix_reflink_p(c);
|
||||
|
||||
if (ret == -NEED_SNAPSHOT_CLEANUP) {
|
||||
if (bch2_err_matches(ret, BCH_ERR_need_snapshot_cleanup)) {
|
||||
set_bit(BCH_FS_HAVE_DELETED_SNAPSHOTS, &c->flags);
|
||||
goto again;
|
||||
}
|
||||
|
@ -639,7 +639,7 @@ static int bch2_inode_delete_keys(struct btree_trans *trans,
|
||||
bch2_trans_commit(trans, NULL, NULL,
|
||||
BTREE_INSERT_NOFAIL);
|
||||
err:
|
||||
if (ret && ret != -EINTR)
|
||||
if (ret && !bch2_err_matches(ret, BCH_ERR_transaction_restart))
|
||||
break;
|
||||
}
|
||||
|
||||
@ -710,7 +710,7 @@ retry:
|
||||
BTREE_INSERT_NOFAIL);
|
||||
err:
|
||||
bch2_trans_iter_exit(&trans, &iter);
|
||||
if (ret == -EINTR)
|
||||
if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
|
||||
goto retry;
|
||||
|
||||
bch2_trans_exit(&trans);
|
||||
|
@ -312,7 +312,7 @@ int bch2_extent_update(struct btree_trans *trans,
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns -EINTR if we had to drop locks:
|
||||
* Returns -BCH_ERR_transacton_restart if we had to drop locks:
|
||||
*/
|
||||
int bch2_fpunch_at(struct btree_trans *trans, struct btree_iter *iter,
|
||||
subvol_inum inum, u64 end,
|
||||
@ -325,7 +325,8 @@ int bch2_fpunch_at(struct btree_trans *trans, struct btree_iter *iter,
|
||||
int ret = 0, ret2 = 0;
|
||||
u32 snapshot;
|
||||
|
||||
while (!ret || ret == -EINTR) {
|
||||
while (!ret ||
|
||||
bch2_err_matches(ret, BCH_ERR_transaction_restart)) {
|
||||
struct disk_reservation disk_res =
|
||||
bch2_disk_reservation_init(c, 0);
|
||||
struct bkey_i delete;
|
||||
@ -384,7 +385,10 @@ int bch2_fpunch(struct bch_fs *c, subvol_inum inum, u64 start, u64 end,
|
||||
bch2_trans_iter_exit(&trans, &iter);
|
||||
bch2_trans_exit(&trans);
|
||||
|
||||
return ret == -EINTR ? 0 : ret;
|
||||
if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
|
||||
ret = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int bch2_write_index_default(struct bch_write_op *op)
|
||||
@ -415,7 +419,7 @@ int bch2_write_index_default(struct bch_write_op *op)
|
||||
|
||||
ret = bch2_subvolume_get_snapshot(&trans, inum.subvol,
|
||||
&sk.k->k.p.snapshot);
|
||||
if (ret == -EINTR)
|
||||
if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
|
||||
continue;
|
||||
if (ret)
|
||||
break;
|
||||
@ -430,7 +434,7 @@ int bch2_write_index_default(struct bch_write_op *op)
|
||||
op->flags & BCH_WRITE_CHECK_ENOSPC);
|
||||
bch2_trans_iter_exit(&trans, &iter);
|
||||
|
||||
if (ret == -EINTR)
|
||||
if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
|
||||
continue;
|
||||
if (ret)
|
||||
break;
|
||||
@ -580,14 +584,14 @@ static void __bch2_write_index(struct bch_write_op *op)
|
||||
u64 sectors_start = keylist_sectors(keys);
|
||||
int ret = op->index_update_fn(op);
|
||||
|
||||
BUG_ON(ret == -EINTR);
|
||||
BUG_ON(bch2_err_matches(ret, BCH_ERR_transaction_restart));
|
||||
BUG_ON(keylist_sectors(keys) && !ret);
|
||||
|
||||
op->written += sectors_start - keylist_sectors(keys);
|
||||
|
||||
if (ret) {
|
||||
bch_err_inum_ratelimited(c, op->pos.inode,
|
||||
"write error %i from btree update", ret);
|
||||
"write error while doing btree update: %s", bch2_err_str(ret));
|
||||
op->error = ret;
|
||||
}
|
||||
}
|
||||
@ -1915,6 +1919,7 @@ static void bch2_read_endio(struct bio *bio)
|
||||
}
|
||||
|
||||
if (rbio->narrow_crcs ||
|
||||
rbio->promote ||
|
||||
crc_is_compressed(rbio->pick.crc) ||
|
||||
bch2_csum_type_is_encryption(rbio->pick.crc.csum_type))
|
||||
context = RBIO_CONTEXT_UNBOUND, wq = system_unbound_wq;
|
||||
@ -2316,10 +2321,9 @@ retry:
|
||||
* read_extent -> io_time_reset may cause a transaction restart
|
||||
* without returning an error, we need to check for that here:
|
||||
*/
|
||||
if (!bch2_trans_relock(&trans)) {
|
||||
ret = -EINTR;
|
||||
ret = bch2_trans_relock(&trans);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
|
||||
bch2_btree_iter_set_pos(&iter,
|
||||
POS(inum.inum, bvec_iter.bi_sector));
|
||||
@ -2373,7 +2377,9 @@ retry:
|
||||
err:
|
||||
bch2_trans_iter_exit(&trans, &iter);
|
||||
|
||||
if (ret == -EINTR || ret == READ_RETRY || ret == READ_RETRY_AVOID)
|
||||
if (bch2_err_matches(ret, BCH_ERR_transaction_restart) ||
|
||||
ret == READ_RETRY ||
|
||||
ret == READ_RETRY_AVOID)
|
||||
goto retry;
|
||||
|
||||
bch2_trans_exit(&trans);
|
||||
|
@ -883,7 +883,7 @@ static int __bch2_set_nr_journal_buckets(struct bch_dev *ca, unsigned nr,
|
||||
|
||||
if (!new_fs) {
|
||||
for (i = 0; i < nr_got; i++) {
|
||||
ret = bch2_trans_do(c, NULL, NULL, BTREE_INSERT_NOFAIL,
|
||||
ret = bch2_trans_run(c,
|
||||
bch2_trans_mark_metadata_bucket(&trans, ca,
|
||||
bu[i], BCH_DATA_journal,
|
||||
ca->mi.bucket_size));
|
||||
@ -1146,7 +1146,7 @@ int bch2_dev_journal_init(struct bch_dev *ca, struct bch_sb *sb)
|
||||
bch2_sb_get_journal(sb);
|
||||
struct bch_sb_field_journal_v2 *journal_buckets_v2 =
|
||||
bch2_sb_get_journal_v2(sb);
|
||||
unsigned i;
|
||||
unsigned i, nr_bvecs;
|
||||
|
||||
ja->nr = 0;
|
||||
|
||||
@ -1163,11 +1163,14 @@ int bch2_dev_journal_init(struct bch_dev *ca, struct bch_sb *sb)
|
||||
if (!ja->bucket_seq)
|
||||
return -ENOMEM;
|
||||
|
||||
ca->journal.bio = bio_kmalloc(GFP_KERNEL,
|
||||
DIV_ROUND_UP(JOURNAL_ENTRY_SIZE_MAX, PAGE_SIZE));
|
||||
nr_bvecs = DIV_ROUND_UP(JOURNAL_ENTRY_SIZE_MAX, PAGE_SIZE);
|
||||
|
||||
ca->journal.bio = bio_kmalloc(nr_bvecs, GFP_KERNEL);
|
||||
if (!ca->journal.bio)
|
||||
return -ENOMEM;
|
||||
|
||||
bio_init(ca->journal.bio, NULL, ca->journal.bio->bi_inline_vecs, nr_bvecs, 0);
|
||||
|
||||
ja->buckets = kcalloc(ja->nr, sizeof(u64), GFP_KERNEL);
|
||||
if (!ja->buckets)
|
||||
return -ENOMEM;
|
||||
|
@ -197,7 +197,7 @@ static void journal_entry_null_range(void *start, void *end)
|
||||
bch_err(c, "corrupt metadata before write:\n" \
|
||||
msg, ##__VA_ARGS__); \
|
||||
if (bch2_fs_inconsistent(c)) { \
|
||||
ret = BCH_FSCK_ERRORS_NOT_FIXED; \
|
||||
ret = -BCH_ERR_fsck_errors_not_fixed; \
|
||||
goto fsck_err; \
|
||||
} \
|
||||
break; \
|
||||
@ -823,20 +823,20 @@ static int journal_read_bucket(struct bch_dev *ca,
|
||||
while (offset < end) {
|
||||
if (!sectors_read) {
|
||||
struct bio *bio;
|
||||
unsigned nr_bvecs;
|
||||
reread:
|
||||
sectors_read = min_t(unsigned,
|
||||
end - offset, buf->size >> 9);
|
||||
nr_bvecs = buf_pages(buf->data, sectors_read << 9);
|
||||
|
||||
bio = bio_kmalloc(GFP_KERNEL,
|
||||
buf_pages(buf->data,
|
||||
sectors_read << 9));
|
||||
bio_set_dev(bio, ca->disk_sb.bdev);
|
||||
bio->bi_iter.bi_sector = offset;
|
||||
bio_set_op_attrs(bio, REQ_OP_READ, 0);
|
||||
bio = bio_kmalloc(nr_bvecs, GFP_KERNEL);
|
||||
bio_init(bio, ca->disk_sb.bdev, bio->bi_inline_vecs, nr_bvecs, REQ_OP_READ);
|
||||
|
||||
bio->bi_iter.bi_sector = offset;
|
||||
bch2_bio_map(bio, buf->data, sectors_read << 9);
|
||||
|
||||
ret = submit_bio_wait(bio);
|
||||
bio_put(bio);
|
||||
kfree(bio);
|
||||
|
||||
if (bch2_dev_io_err_on(ret, ca,
|
||||
"journal read error: sector %llu",
|
||||
@ -858,7 +858,7 @@ reread:
|
||||
end - offset, sectors_read,
|
||||
READ);
|
||||
switch (ret) {
|
||||
case BCH_FSCK_OK:
|
||||
case 0:
|
||||
sectors = vstruct_sectors(j, c->block_bits);
|
||||
break;
|
||||
case JOURNAL_ENTRY_REREAD:
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include "bcachefs.h"
|
||||
#include "btree_key_cache.h"
|
||||
#include "errcode.h"
|
||||
#include "error.h"
|
||||
#include "journal.h"
|
||||
#include "journal_io.h"
|
||||
@ -282,11 +283,11 @@ void bch2_journal_do_discards(struct journal *j)
|
||||
while (should_discard_bucket(j, ja)) {
|
||||
if (!c->opts.nochanges &&
|
||||
ca->mi.discard &&
|
||||
blk_queue_discard(bdev_get_queue(ca->disk_sb.bdev)))
|
||||
bdev_max_discard_sectors(ca->disk_sb.bdev))
|
||||
blkdev_issue_discard(ca->disk_sb.bdev,
|
||||
bucket_to_sector(ca,
|
||||
ja->buckets[ja->discard_idx]),
|
||||
ca->mi.bucket_size, GFP_NOIO, 0);
|
||||
ca->mi.bucket_size, GFP_NOIO);
|
||||
|
||||
spin_lock(&j->lock);
|
||||
ja->discard_idx = (ja->discard_idx + 1) % ja->nr;
|
||||
@ -740,15 +741,17 @@ int bch2_journal_reclaim_start(struct journal *j)
|
||||
{
|
||||
struct bch_fs *c = container_of(j, struct bch_fs, journal);
|
||||
struct task_struct *p;
|
||||
int ret;
|
||||
|
||||
if (j->reclaim_thread)
|
||||
return 0;
|
||||
|
||||
p = kthread_create(bch2_journal_reclaim_thread, j,
|
||||
"bch-reclaim/%s", c->name);
|
||||
if (IS_ERR(p)) {
|
||||
bch_err(c, "error creating journal reclaim thread: %li", PTR_ERR(p));
|
||||
return PTR_ERR(p);
|
||||
ret = PTR_ERR_OR_ZERO(p);
|
||||
if (ret) {
|
||||
bch_err(c, "error creating journal reclaim thread: %s", bch2_err_str(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
get_task_struct(p);
|
||||
|
@ -272,7 +272,7 @@ retry:
|
||||
!test_bit(BCH_FS_STOPPING, &c->flags))
|
||||
b = bch2_btree_iter_next_node(&iter);
|
||||
|
||||
if (ret == -EINTR)
|
||||
if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
|
||||
goto retry;
|
||||
|
||||
bch2_trans_iter_exit(&trans, &iter);
|
||||
|
@ -130,25 +130,18 @@ int bch2_lru_change(struct btree_trans *trans, u64 id, u64 idx,
|
||||
}
|
||||
|
||||
static int bch2_check_lru_key(struct btree_trans *trans,
|
||||
struct btree_iter *lru_iter)
|
||||
struct btree_iter *lru_iter,
|
||||
struct bkey_s_c lru_k)
|
||||
{
|
||||
struct bch_fs *c = trans->c;
|
||||
struct btree_iter iter;
|
||||
struct bkey_s_c lru_k, k;
|
||||
struct bkey_s_c k;
|
||||
struct bch_alloc_v4 a;
|
||||
struct printbuf buf1 = PRINTBUF;
|
||||
struct printbuf buf2 = PRINTBUF;
|
||||
struct bpos alloc_pos;
|
||||
int ret;
|
||||
|
||||
lru_k = bch2_btree_iter_peek(lru_iter);
|
||||
if (!lru_k.k)
|
||||
return 0;
|
||||
|
||||
ret = bkey_err(lru_k);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
alloc_pos = POS(lru_k.k->p.inode,
|
||||
le64_to_cpu(bkey_s_c_to_lru(lru_k).v->idx));
|
||||
|
||||
@ -202,16 +195,10 @@ int bch2_check_lrus(struct bch_fs *c)
|
||||
|
||||
bch2_trans_init(&trans, c, 0, 0);
|
||||
|
||||
for_each_btree_key(&trans, iter, BTREE_ID_lru, POS_MIN,
|
||||
BTREE_ITER_PREFETCH, k, ret) {
|
||||
ret = commit_do(&trans, NULL, NULL,
|
||||
BTREE_INSERT_NOFAIL|
|
||||
BTREE_INSERT_LAZY_RW,
|
||||
bch2_check_lru_key(&trans, &iter));
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
bch2_trans_iter_exit(&trans, &iter);
|
||||
ret = for_each_btree_key_commit(&trans, iter,
|
||||
BTREE_ID_lru, POS_MIN, BTREE_ITER_PREFETCH, k,
|
||||
NULL, NULL, BTREE_INSERT_NOFAIL|BTREE_INSERT_LAZY_RW,
|
||||
bch2_check_lru_key(&trans, &iter, k));
|
||||
|
||||
bch2_trans_exit(&trans);
|
||||
return ret;
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "btree_update.h"
|
||||
#include "btree_update_interior.h"
|
||||
#include "buckets.h"
|
||||
#include "errcode.h"
|
||||
#include "extents.h"
|
||||
#include "io.h"
|
||||
#include "journal.h"
|
||||
@ -35,83 +36,74 @@ static int drop_dev_ptrs(struct bch_fs *c, struct bkey_s k,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __bch2_dev_usrdata_drop(struct bch_fs *c, unsigned dev_idx, int flags,
|
||||
enum btree_id btree_id)
|
||||
static int bch2_dev_usrdata_drop_key(struct btree_trans *trans,
|
||||
struct btree_iter *iter,
|
||||
struct bkey_s_c k,
|
||||
unsigned dev_idx,
|
||||
int flags)
|
||||
{
|
||||
struct btree_trans trans;
|
||||
struct btree_iter iter;
|
||||
struct bkey_s_c k;
|
||||
struct bkey_buf sk;
|
||||
int ret = 0;
|
||||
struct bch_fs *c = trans->c;
|
||||
struct bkey_i *n;
|
||||
int ret;
|
||||
|
||||
bch2_bkey_buf_init(&sk);
|
||||
bch2_trans_init(&trans, c, BTREE_ITER_MAX, 0);
|
||||
if (!bch2_bkey_has_device(k, dev_idx))
|
||||
return 0;
|
||||
|
||||
bch2_trans_iter_init(&trans, &iter, btree_id, POS_MIN,
|
||||
BTREE_ITER_PREFETCH|
|
||||
BTREE_ITER_ALL_SNAPSHOTS);
|
||||
n = bch2_trans_kmalloc(trans, bkey_bytes(k.k));
|
||||
ret = PTR_ERR_OR_ZERO(n);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
while ((bch2_trans_begin(&trans),
|
||||
(k = bch2_btree_iter_peek(&iter)).k) &&
|
||||
!(ret = bkey_err(k))) {
|
||||
if (!bch2_bkey_has_device(k, dev_idx)) {
|
||||
bch2_btree_iter_advance(&iter);
|
||||
continue;
|
||||
}
|
||||
bkey_reassemble(n, k);
|
||||
|
||||
bch2_bkey_buf_reassemble(&sk, c, k);
|
||||
ret = drop_dev_ptrs(c, bkey_i_to_s(n), dev_idx, flags, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = drop_dev_ptrs(c, bkey_i_to_s(sk.k),
|
||||
dev_idx, flags, false);
|
||||
if (ret)
|
||||
break;
|
||||
/*
|
||||
* If the new extent no longer has any pointers, bch2_extent_normalize()
|
||||
* will do the appropriate thing with it (turning it into a
|
||||
* KEY_TYPE_error key, or just a discard if it was a cached extent)
|
||||
*/
|
||||
bch2_extent_normalize(c, bkey_i_to_s(n));
|
||||
|
||||
/*
|
||||
* If the new extent no longer has any pointers, bch2_extent_normalize()
|
||||
* will do the appropriate thing with it (turning it into a
|
||||
* KEY_TYPE_error key, or just a discard if it was a cached extent)
|
||||
*/
|
||||
bch2_extent_normalize(c, bkey_i_to_s(sk.k));
|
||||
/*
|
||||
* Since we're not inserting through an extent iterator
|
||||
* (BTREE_ITER_ALL_SNAPSHOTS iterators aren't extent iterators),
|
||||
* we aren't using the extent overwrite path to delete, we're
|
||||
* just using the normal key deletion path:
|
||||
*/
|
||||
if (bkey_deleted(&n->k))
|
||||
n->k.size = 0;
|
||||
|
||||
/*
|
||||
* Since we're not inserting through an extent iterator
|
||||
* (BTREE_ITER_ALL_SNAPSHOTS iterators aren't extent iterators),
|
||||
* we aren't using the extent overwrite path to delete, we're
|
||||
* just using the normal key deletion path:
|
||||
*/
|
||||
if (bkey_deleted(&sk.k->k))
|
||||
sk.k->k.size = 0;
|
||||
|
||||
ret = bch2_btree_iter_traverse(&iter) ?:
|
||||
bch2_trans_update(&trans, &iter, sk.k,
|
||||
BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE) ?:
|
||||
bch2_trans_commit(&trans, NULL, NULL,
|
||||
BTREE_INSERT_NOFAIL);
|
||||
|
||||
/*
|
||||
* don't want to leave ret == -EINTR, since if we raced and
|
||||
* something else overwrote the key we could spuriously return
|
||||
* -EINTR below:
|
||||
*/
|
||||
if (ret == -EINTR)
|
||||
ret = 0;
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
bch2_trans_iter_exit(&trans, &iter);
|
||||
|
||||
bch2_trans_exit(&trans);
|
||||
bch2_bkey_buf_exit(&sk, c);
|
||||
|
||||
BUG_ON(ret == -EINTR);
|
||||
|
||||
return ret;
|
||||
return bch2_trans_update(trans, iter, n, BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE);
|
||||
}
|
||||
|
||||
static int bch2_dev_usrdata_drop(struct bch_fs *c, unsigned dev_idx, int flags)
|
||||
{
|
||||
return __bch2_dev_usrdata_drop(c, dev_idx, flags, BTREE_ID_extents) ?:
|
||||
__bch2_dev_usrdata_drop(c, dev_idx, flags, BTREE_ID_reflink);
|
||||
struct btree_trans trans;
|
||||
struct btree_iter iter;
|
||||
struct bkey_s_c k;
|
||||
enum btree_id id;
|
||||
int ret = 0;
|
||||
|
||||
bch2_trans_init(&trans, c, BTREE_ITER_MAX, 0);
|
||||
|
||||
for (id = 0; id < BTREE_ID_NR; id++) {
|
||||
if (!btree_type_has_ptrs(id))
|
||||
continue;
|
||||
|
||||
ret = for_each_btree_key_commit(&trans, iter, id, POS_MIN,
|
||||
BTREE_ITER_PREFETCH|BTREE_ITER_ALL_SNAPSHOTS, k,
|
||||
NULL, NULL, BTREE_INSERT_NOFAIL,
|
||||
bch2_dev_usrdata_drop_key(&trans, &iter, k, dev_idx, flags));
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
|
||||
bch2_trans_exit(&trans);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bch2_dev_metadata_drop(struct bch_fs *c, unsigned dev_idx, int flags)
|
||||
@ -154,19 +146,20 @@ retry:
|
||||
}
|
||||
|
||||
ret = bch2_btree_node_update_key(&trans, &iter, b, k.k, false);
|
||||
if (ret == -EINTR) {
|
||||
if (bch2_err_matches(ret, BCH_ERR_transaction_restart)) {
|
||||
ret = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
bch_err(c, "Error updating btree node key: %i", ret);
|
||||
bch_err(c, "Error updating btree node key: %s",
|
||||
bch2_err_str(ret));
|
||||
break;
|
||||
}
|
||||
next:
|
||||
bch2_btree_iter_next_node(&iter);
|
||||
}
|
||||
if (ret == -EINTR)
|
||||
if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
|
||||
goto retry;
|
||||
|
||||
bch2_trans_iter_exit(&trans, &iter);
|
||||
@ -181,7 +174,7 @@ err:
|
||||
bch2_trans_exit(&trans);
|
||||
bch2_bkey_buf_exit(&k, c);
|
||||
|
||||
BUG_ON(ret == -EINTR);
|
||||
BUG_ON(bch2_err_matches(ret, BCH_ERR_transaction_restart));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "btree_update_interior.h"
|
||||
#include "disk_groups.h"
|
||||
#include "ec.h"
|
||||
#include "errcode.h"
|
||||
#include "error.h"
|
||||
#include "inode.h"
|
||||
#include "io.h"
|
||||
@ -370,7 +371,7 @@ static int move_get_io_opts(struct btree_trans *trans,
|
||||
ret = lookup_inode(trans,
|
||||
SPOS(0, k.k->p.inode, k.k->p.snapshot),
|
||||
&inode);
|
||||
if (ret == -EINTR)
|
||||
if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
|
||||
return ret;
|
||||
|
||||
if (!ret)
|
||||
@ -418,7 +419,7 @@ static int __bch2_move_data(struct moving_context *ctxt,
|
||||
break;
|
||||
|
||||
ret = bkey_err(k);
|
||||
if (ret == -EINTR)
|
||||
if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
|
||||
continue;
|
||||
if (ret)
|
||||
break;
|
||||
@ -449,7 +450,7 @@ static int __bch2_move_data(struct moving_context *ctxt,
|
||||
ret2 = bch2_move_extent(&trans, ctxt, io_opts,
|
||||
btree_id, k, data_opts);
|
||||
if (ret2) {
|
||||
if (ret2 == -EINTR)
|
||||
if (bch2_err_matches(ret2, BCH_ERR_transaction_restart))
|
||||
continue;
|
||||
|
||||
if (ret2 == -ENOMEM) {
|
||||
@ -574,7 +575,7 @@ int __bch2_evacuate_bucket(struct moving_context *ctxt,
|
||||
|
||||
ret = bch2_get_next_backpointer(&trans, bucket, gen,
|
||||
&bp_offset, &bp);
|
||||
if (ret == -EINTR)
|
||||
if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
|
||||
continue;
|
||||
if (ret)
|
||||
goto err;
|
||||
@ -589,7 +590,7 @@ int __bch2_evacuate_bucket(struct moving_context *ctxt,
|
||||
k = bch2_backpointer_get_key(&trans, &iter,
|
||||
bucket, bp_offset, bp);
|
||||
ret = bkey_err(k);
|
||||
if (ret == -EINTR)
|
||||
if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
|
||||
continue;
|
||||
if (ret)
|
||||
goto err;
|
||||
@ -616,7 +617,7 @@ int __bch2_evacuate_bucket(struct moving_context *ctxt,
|
||||
|
||||
ret = bch2_move_extent(&trans, ctxt, io_opts,
|
||||
bp.btree_id, k, data_opts);
|
||||
if (ret == -EINTR)
|
||||
if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
|
||||
continue;
|
||||
if (ret == -ENOMEM) {
|
||||
/* memory allocation failure, wait for some IO to finish */
|
||||
@ -635,7 +636,7 @@ int __bch2_evacuate_bucket(struct moving_context *ctxt,
|
||||
b = bch2_backpointer_get_node(&trans, &iter,
|
||||
bucket, bp_offset, bp);
|
||||
ret = PTR_ERR_OR_ZERO(b);
|
||||
if (ret == -EINTR)
|
||||
if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
|
||||
continue;
|
||||
if (ret)
|
||||
goto err;
|
||||
@ -645,7 +646,7 @@ int __bch2_evacuate_bucket(struct moving_context *ctxt,
|
||||
ret = bch2_btree_node_rewrite(&trans, &iter, b, 0);
|
||||
bch2_trans_iter_exit(&trans, &iter);
|
||||
|
||||
if (ret == -EINTR)
|
||||
if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
|
||||
continue;
|
||||
if (ret)
|
||||
goto err;
|
||||
@ -740,14 +741,14 @@ retry:
|
||||
goto next;
|
||||
|
||||
ret = bch2_btree_node_rewrite(&trans, &iter, b, 0) ?: ret;
|
||||
if (ret == -EINTR)
|
||||
if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
|
||||
continue;
|
||||
if (ret)
|
||||
break;
|
||||
next:
|
||||
bch2_btree_iter_next_node(&iter);
|
||||
}
|
||||
if (ret == -EINTR)
|
||||
if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
|
||||
goto retry;
|
||||
|
||||
bch2_trans_iter_exit(&trans, &iter);
|
||||
@ -759,7 +760,7 @@ next:
|
||||
bch2_trans_exit(&trans);
|
||||
|
||||
if (ret)
|
||||
bch_err(c, "error %i in bch2_move_btree", ret);
|
||||
bch_err(c, "error in %s(): %s", __func__, bch2_err_str(ret));
|
||||
|
||||
bch2_btree_interior_updates_flush(c);
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "buckets.h"
|
||||
#include "clock.h"
|
||||
#include "disk_groups.h"
|
||||
#include "errcode.h"
|
||||
#include "error.h"
|
||||
#include "extents.h"
|
||||
#include "eytzinger.h"
|
||||
@ -162,7 +163,7 @@ static int bch2_copygc(struct bch_fs *c)
|
||||
bch2_moving_ctxt_exit(&ctxt);
|
||||
|
||||
if (ret < 0)
|
||||
bch_err(c, "error %i from bch2_move_data() in copygc", ret);
|
||||
bch_err(c, "error from bch2_move_data() in copygc: %s", bch2_err_str(ret));
|
||||
|
||||
trace_copygc(c, atomic64_read(&move_stats.sectors_moved), 0, 0, 0);
|
||||
return ret;
|
||||
@ -251,6 +252,7 @@ void bch2_copygc_stop(struct bch_fs *c)
|
||||
int bch2_copygc_start(struct bch_fs *c)
|
||||
{
|
||||
struct task_struct *t;
|
||||
int ret;
|
||||
|
||||
if (c->copygc_thread)
|
||||
return 0;
|
||||
@ -262,9 +264,10 @@ int bch2_copygc_start(struct bch_fs *c)
|
||||
return -ENOMEM;
|
||||
|
||||
t = kthread_create(bch2_copygc_thread, c, "bch-copygc/%s", c->name);
|
||||
if (IS_ERR(t)) {
|
||||
bch_err(c, "error creating copygc thread: %li", PTR_ERR(t));
|
||||
return PTR_ERR(t);
|
||||
ret = PTR_ERR_OR_ZERO(t);
|
||||
if (ret) {
|
||||
bch_err(c, "error creating copygc thread: %s", bch2_err_str(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
get_task_struct(t);
|
||||
|
@ -2,6 +2,7 @@
|
||||
#ifndef _BCACHEFS_MOVINGGC_H
|
||||
#define _BCACHEFS_MOVINGGC_H
|
||||
|
||||
unsigned long bch2_copygc_wait_amount(struct bch_fs *);
|
||||
void bch2_copygc_stop(struct bch_fs *);
|
||||
int bch2_copygc_start(struct bch_fs *);
|
||||
void bch2_fs_copygc_init(struct bch_fs *);
|
||||
|
@ -341,6 +341,11 @@ enum opt_type {
|
||||
OPT_BOOL(), \
|
||||
BCH2_NO_SB_OPT, false, \
|
||||
NULL, "Don't open device in exclusive mode") \
|
||||
x(direct_io, u8, \
|
||||
OPT_FS|OPT_MOUNT, \
|
||||
OPT_BOOL(), \
|
||||
BCH2_NO_SB_OPT, true, \
|
||||
NULL, "Use O_DIRECT (userspace only)") \
|
||||
x(sb, u64, \
|
||||
OPT_MOUNT, \
|
||||
OPT_UINT(0, S64_MAX), \
|
||||
|
@ -1,6 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include "bcachefs.h"
|
||||
#include "btree_update.h"
|
||||
#include "errcode.h"
|
||||
#include "inode.h"
|
||||
#include "quota.h"
|
||||
#include "subvolume.h"
|
||||
@ -370,6 +371,9 @@ static int __bch2_quota_set(struct bch_fs *c, struct bkey_s_c k)
|
||||
|
||||
BUG_ON(k.k->p.inode >= QTYP_NR);
|
||||
|
||||
if (!((1U << k.k->p.inode) & enabled_qtypes(c)))
|
||||
return 0;
|
||||
|
||||
switch (k.k->type) {
|
||||
case KEY_TYPE_quota:
|
||||
dq = bkey_s_c_to_quota(k);
|
||||
@ -393,30 +397,6 @@ static int __bch2_quota_set(struct bch_fs *c, struct bkey_s_c k)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bch2_quota_init_type(struct bch_fs *c, enum quota_types type)
|
||||
{
|
||||
struct btree_trans trans;
|
||||
struct btree_iter iter;
|
||||
struct bkey_s_c k;
|
||||
int ret = 0;
|
||||
|
||||
bch2_trans_init(&trans, c, 0, 0);
|
||||
|
||||
for_each_btree_key(&trans, iter, BTREE_ID_quotas, POS(type, 0),
|
||||
BTREE_ITER_PREFETCH, k, ret) {
|
||||
if (k.k->p.inode != type)
|
||||
break;
|
||||
|
||||
ret = __bch2_quota_set(c, k);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
bch2_trans_iter_exit(&trans, &iter);
|
||||
|
||||
bch2_trans_exit(&trans);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void bch2_fs_quota_exit(struct bch_fs *c)
|
||||
{
|
||||
unsigned i;
|
||||
@ -491,8 +471,6 @@ advance:
|
||||
|
||||
int bch2_fs_quota_read(struct bch_fs *c)
|
||||
{
|
||||
unsigned i, qtypes = enabled_qtypes(c);
|
||||
struct bch_memquota_type *q;
|
||||
struct btree_trans trans;
|
||||
struct btree_iter iter;
|
||||
struct bkey_s_c k;
|
||||
@ -502,23 +480,16 @@ int bch2_fs_quota_read(struct bch_fs *c)
|
||||
bch2_sb_quota_read(c);
|
||||
mutex_unlock(&c->sb_lock);
|
||||
|
||||
for_each_set_qtype(c, i, q, qtypes) {
|
||||
ret = bch2_quota_init_type(c, i);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
bch2_trans_init(&trans, c, 0, 0);
|
||||
|
||||
ret = for_each_btree_key2(&trans, iter, BTREE_ID_inodes,
|
||||
POS_MIN,
|
||||
BTREE_ITER_INTENT|
|
||||
BTREE_ITER_PREFETCH|
|
||||
BTREE_ITER_ALL_SNAPSHOTS,
|
||||
k,
|
||||
ret = for_each_btree_key2(&trans, iter, BTREE_ID_quotas,
|
||||
POS_MIN, BTREE_ITER_PREFETCH, k,
|
||||
__bch2_quota_set(c, k)) ?:
|
||||
for_each_btree_key2(&trans, iter, BTREE_ID_inodes,
|
||||
POS_MIN, BTREE_ITER_PREFETCH|BTREE_ITER_ALL_SNAPSHOTS, k,
|
||||
bch2_fs_quota_read_inode(&trans, &iter, k));
|
||||
if (ret)
|
||||
bch_err(c, "err reading inodes in quota init: %i", ret);
|
||||
bch_err(c, "err in quota_read: %s", bch2_err_str(ret));
|
||||
|
||||
bch2_trans_exit(&trans);
|
||||
return ret;
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "buckets.h"
|
||||
#include "clock.h"
|
||||
#include "disk_groups.h"
|
||||
#include "errcode.h"
|
||||
#include "extents.h"
|
||||
#include "io.h"
|
||||
#include "move.h"
|
||||
@ -331,6 +332,7 @@ void bch2_rebalance_stop(struct bch_fs *c)
|
||||
int bch2_rebalance_start(struct bch_fs *c)
|
||||
{
|
||||
struct task_struct *p;
|
||||
int ret;
|
||||
|
||||
if (c->rebalance.thread)
|
||||
return 0;
|
||||
@ -339,9 +341,10 @@ int bch2_rebalance_start(struct bch_fs *c)
|
||||
return 0;
|
||||
|
||||
p = kthread_create(bch2_rebalance_thread, c, "bch-rebalance/%s", c->name);
|
||||
if (IS_ERR(p)) {
|
||||
bch_err(c, "error creating rebalance thread: %li", PTR_ERR(p));
|
||||
return PTR_ERR(p);
|
||||
ret = PTR_ERR_OR_ZERO(p);
|
||||
if (ret) {
|
||||
bch_err(c, "error creating rebalance thread: %s", bch2_err_str(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
get_task_struct(p);
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "buckets.h"
|
||||
#include "dirent.h"
|
||||
#include "ec.h"
|
||||
#include "errcode.h"
|
||||
#include "error.h"
|
||||
#include "fs-common.h"
|
||||
#include "fsck.h"
|
||||
@ -87,9 +88,9 @@ static inline struct journal_key *idx_to_key(struct journal_keys *keys, size_t i
|
||||
return keys->d + idx_to_pos(keys, idx);
|
||||
}
|
||||
|
||||
static size_t bch2_journal_key_search(struct journal_keys *keys,
|
||||
enum btree_id id, unsigned level,
|
||||
struct bpos pos)
|
||||
static size_t __bch2_journal_key_search(struct journal_keys *keys,
|
||||
enum btree_id id, unsigned level,
|
||||
struct bpos pos)
|
||||
{
|
||||
size_t l = 0, r = keys->nr, m;
|
||||
|
||||
@ -107,7 +108,14 @@ static size_t bch2_journal_key_search(struct journal_keys *keys,
|
||||
BUG_ON(l &&
|
||||
__journal_key_cmp(id, level, pos, idx_to_key(keys, l - 1)) <= 0);
|
||||
|
||||
return idx_to_pos(keys, l);
|
||||
return l;
|
||||
}
|
||||
|
||||
static size_t bch2_journal_key_search(struct journal_keys *keys,
|
||||
enum btree_id id, unsigned level,
|
||||
struct bpos pos)
|
||||
{
|
||||
return idx_to_pos(keys, __bch2_journal_key_search(keys, id, level, pos));
|
||||
}
|
||||
|
||||
struct bkey_i *bch2_journal_keys_peek_upto(struct bch_fs *c, enum btree_id btree_id,
|
||||
@ -116,22 +124,21 @@ struct bkey_i *bch2_journal_keys_peek_upto(struct bch_fs *c, enum btree_id btree
|
||||
{
|
||||
struct journal_keys *keys = &c->journal_keys;
|
||||
unsigned iters = 0;
|
||||
struct journal_key *k;
|
||||
search:
|
||||
if (!*idx)
|
||||
*idx = bch2_journal_key_search(keys, btree_id, level, pos);
|
||||
*idx = __bch2_journal_key_search(keys, btree_id, level, pos);
|
||||
|
||||
while (*idx < keys->size &&
|
||||
keys->d[*idx].btree_id == btree_id &&
|
||||
keys->d[*idx].level == level &&
|
||||
bpos_cmp(keys->d[*idx].k->k.p, end_pos) <= 0) {
|
||||
if (bpos_cmp(keys->d[*idx].k->k.p, pos) >= 0 &&
|
||||
!keys->d[*idx].overwritten)
|
||||
return keys->d[*idx].k;
|
||||
while (*idx < keys->nr &&
|
||||
(k = idx_to_key(keys, *idx),
|
||||
k->btree_id == btree_id &&
|
||||
k->level == level &&
|
||||
bpos_cmp(k->k->k.p, end_pos) <= 0)) {
|
||||
if (bpos_cmp(k->k->k.p, pos) >= 0 &&
|
||||
!k->overwritten)
|
||||
return k->k;
|
||||
|
||||
(*idx)++;
|
||||
if (*idx == keys->gap)
|
||||
*idx += keys->size - keys->nr;
|
||||
|
||||
iters++;
|
||||
if (iters == 10) {
|
||||
*idx = 0;
|
||||
@ -1153,7 +1160,7 @@ int bch2_fs_recovery(struct bch_fs *c)
|
||||
use_clean:
|
||||
if (!clean) {
|
||||
bch_err(c, "no superblock clean section found");
|
||||
ret = BCH_FSCK_REPAIR_IMPOSSIBLE;
|
||||
ret = -BCH_ERR_fsck_repair_impossible;
|
||||
goto err;
|
||||
|
||||
}
|
||||
@ -1435,9 +1442,9 @@ out:
|
||||
}
|
||||
|
||||
if (ret)
|
||||
bch_err(c, "Error in recovery: %s (%i)", err, ret);
|
||||
bch_err(c, "Error in recovery: %s (%s)", err, bch2_err_str(ret));
|
||||
else
|
||||
bch_verbose(c, "ret %i", ret);
|
||||
bch_verbose(c, "ret %s", bch2_err_str(ret));
|
||||
return ret;
|
||||
err:
|
||||
fsck_err:
|
||||
|
@ -299,7 +299,8 @@ s64 bch2_remap_range(struct bch_fs *c,
|
||||
bch2_trans_iter_init(&trans, &dst_iter, BTREE_ID_extents, dst_start,
|
||||
BTREE_ITER_INTENT);
|
||||
|
||||
while ((ret == 0 || ret == -EINTR) &&
|
||||
while ((ret == 0 ||
|
||||
bch2_err_matches(ret, BCH_ERR_transaction_restart)) &&
|
||||
bkey_cmp(dst_iter.pos, dst_end) < 0) {
|
||||
struct disk_reservation disk_res = { 0 };
|
||||
|
||||
@ -409,7 +410,7 @@ s64 bch2_remap_range(struct bch_fs *c,
|
||||
}
|
||||
|
||||
bch2_trans_iter_exit(&trans, &inode_iter);
|
||||
} while (ret2 == -EINTR);
|
||||
} while (bch2_err_matches(ret2, BCH_ERR_transaction_restart));
|
||||
|
||||
bch2_trans_exit(&trans);
|
||||
bch2_bkey_buf_exit(&new_src, c);
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include "bcachefs.h"
|
||||
#include "btree_key_cache.h"
|
||||
#include "btree_update.h"
|
||||
#include "errcode.h"
|
||||
#include "error.h"
|
||||
#include "fs.h"
|
||||
#include "subvolume.h"
|
||||
@ -291,22 +292,14 @@ int bch2_fs_check_snapshots(struct bch_fs *c)
|
||||
}
|
||||
|
||||
static int check_subvol(struct btree_trans *trans,
|
||||
struct btree_iter *iter)
|
||||
struct btree_iter *iter,
|
||||
struct bkey_s_c k)
|
||||
{
|
||||
struct bkey_s_c k;
|
||||
struct bkey_s_c_subvolume subvol;
|
||||
struct bch_snapshot snapshot;
|
||||
unsigned snapid;
|
||||
int ret;
|
||||
|
||||
k = bch2_btree_iter_peek(iter);
|
||||
if (!k.k)
|
||||
return 0;
|
||||
|
||||
ret = bkey_err(k);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (k.k->type != KEY_TYPE_subvolume)
|
||||
return 0;
|
||||
|
||||
@ -322,9 +315,9 @@ static int check_subvol(struct btree_trans *trans,
|
||||
|
||||
if (BCH_SUBVOLUME_UNLINKED(subvol.v)) {
|
||||
ret = bch2_subvolume_delete(trans, iter->pos.offset);
|
||||
if (ret && ret != -EINTR)
|
||||
bch_err(trans->c, "error deleting subvolume %llu: %i",
|
||||
iter->pos.offset, ret);
|
||||
if (ret && !bch2_err_matches(ret, BCH_ERR_transaction_restart))
|
||||
bch_err(trans->c, "error deleting subvolume %llu: %s",
|
||||
iter->pos.offset, bch2_err_str(ret));
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
@ -336,22 +329,15 @@ int bch2_fs_check_subvols(struct bch_fs *c)
|
||||
{
|
||||
struct btree_trans trans;
|
||||
struct btree_iter iter;
|
||||
struct bkey_s_c k;
|
||||
int ret;
|
||||
|
||||
bch2_trans_init(&trans, c, 0, 0);
|
||||
|
||||
bch2_trans_iter_init(&trans, &iter, BTREE_ID_subvolumes,
|
||||
POS_MIN, BTREE_ITER_PREFETCH);
|
||||
|
||||
do {
|
||||
ret = commit_do(&trans, NULL, NULL,
|
||||
BTREE_INSERT_LAZY_RW|
|
||||
BTREE_INSERT_NOFAIL,
|
||||
check_subvol(&trans, &iter));
|
||||
if (ret)
|
||||
break;
|
||||
} while (bch2_btree_iter_advance(&iter));
|
||||
bch2_trans_iter_exit(&trans, &iter);
|
||||
ret = for_each_btree_key_commit(&trans, iter,
|
||||
BTREE_ID_subvolumes, POS_MIN, BTREE_ITER_PREFETCH, k,
|
||||
NULL, NULL, BTREE_INSERT_LAZY_RW|BTREE_INSERT_NOFAIL,
|
||||
check_subvol(&trans, &iter, k));
|
||||
|
||||
bch2_trans_exit(&trans);
|
||||
|
||||
@ -380,7 +366,7 @@ int bch2_fs_snapshots_start(struct bch_fs *c)
|
||||
bch2_trans_exit(&trans);
|
||||
|
||||
if (ret)
|
||||
bch_err(c, "error starting snapshots: %i", ret);
|
||||
bch_err(c, "error starting snapshots: %s", bch2_err_str(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -595,59 +581,27 @@ err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bch2_snapshot_delete_keys_btree(struct btree_trans *trans,
|
||||
snapshot_id_list *deleted,
|
||||
enum btree_id btree_id)
|
||||
static int snapshot_delete_key(struct btree_trans *trans,
|
||||
struct btree_iter *iter,
|
||||
struct bkey_s_c k,
|
||||
snapshot_id_list *deleted,
|
||||
snapshot_id_list *equiv_seen,
|
||||
struct bpos *last_pos)
|
||||
{
|
||||
struct bch_fs *c = trans->c;
|
||||
struct btree_iter iter;
|
||||
struct bkey_s_c k;
|
||||
snapshot_id_list equiv_seen = { 0 };
|
||||
struct bpos last_pos = POS_MIN;
|
||||
int ret = 0;
|
||||
u32 equiv = snapshot_t(c, k.k->p.snapshot)->equiv;
|
||||
|
||||
/*
|
||||
* XXX: We should also delete whiteouts that no longer overwrite
|
||||
* anything
|
||||
*/
|
||||
if (bkey_cmp(k.k->p, *last_pos))
|
||||
equiv_seen->nr = 0;
|
||||
*last_pos = k.k->p;
|
||||
|
||||
bch2_trans_iter_init(trans, &iter, btree_id, POS_MIN,
|
||||
BTREE_ITER_INTENT|
|
||||
BTREE_ITER_PREFETCH|
|
||||
BTREE_ITER_NOT_EXTENTS|
|
||||
BTREE_ITER_ALL_SNAPSHOTS);
|
||||
|
||||
while ((bch2_trans_begin(trans),
|
||||
(k = bch2_btree_iter_peek(&iter)).k) &&
|
||||
!(ret = bkey_err(k))) {
|
||||
u32 equiv = snapshot_t(c, k.k->p.snapshot)->equiv;
|
||||
|
||||
if (bkey_cmp(k.k->p, last_pos))
|
||||
equiv_seen.nr = 0;
|
||||
last_pos = k.k->p;
|
||||
|
||||
if (snapshot_list_has_id(deleted, k.k->p.snapshot) ||
|
||||
snapshot_list_has_id(&equiv_seen, equiv)) {
|
||||
ret = commit_do(trans, NULL, NULL,
|
||||
BTREE_INSERT_NOFAIL,
|
||||
bch2_btree_iter_traverse(&iter) ?:
|
||||
bch2_btree_delete_at(trans, &iter,
|
||||
BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE));
|
||||
if (ret)
|
||||
break;
|
||||
} else {
|
||||
ret = snapshot_list_add(c, &equiv_seen, equiv);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
|
||||
bch2_btree_iter_advance(&iter);
|
||||
if (snapshot_list_has_id(deleted, k.k->p.snapshot) ||
|
||||
snapshot_list_has_id(equiv_seen, equiv)) {
|
||||
return bch2_btree_delete_at(trans, iter,
|
||||
BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE);
|
||||
} else {
|
||||
return snapshot_list_add(c, equiv_seen, equiv);
|
||||
}
|
||||
bch2_trans_iter_exit(trans, &iter);
|
||||
|
||||
darray_exit(&equiv_seen);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bch2_delete_redundant_snapshot(struct btree_trans *trans, struct btree_iter *iter,
|
||||
@ -694,7 +648,7 @@ int bch2_delete_dead_snapshots(struct bch_fs *c)
|
||||
if (!test_bit(BCH_FS_STARTED, &c->flags)) {
|
||||
ret = bch2_fs_read_write_early(c);
|
||||
if (ret) {
|
||||
bch_err(c, "error deleleting dead snapshots: error going rw: %i", ret);
|
||||
bch_err(c, "error deleleting dead snapshots: error going rw: %s", bch2_err_str(ret));
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@ -710,7 +664,7 @@ int bch2_delete_dead_snapshots(struct bch_fs *c)
|
||||
NULL, NULL, 0,
|
||||
bch2_delete_redundant_snapshot(&trans, &iter, k));
|
||||
if (ret) {
|
||||
bch_err(c, "error deleting redundant snapshots: %i", ret);
|
||||
bch_err(c, "error deleting redundant snapshots: %s", bch2_err_str(ret));
|
||||
goto err;
|
||||
}
|
||||
|
||||
@ -718,7 +672,7 @@ int bch2_delete_dead_snapshots(struct bch_fs *c)
|
||||
POS_MIN, 0, k,
|
||||
bch2_snapshot_set_equiv(&trans, k));
|
||||
if (ret) {
|
||||
bch_err(c, "error in bch2_snapshots_set_equiv: %i", ret);
|
||||
bch_err(c, "error in bch2_snapshots_set_equiv: %s", bch2_err_str(ret));
|
||||
goto err;
|
||||
}
|
||||
|
||||
@ -737,17 +691,27 @@ int bch2_delete_dead_snapshots(struct bch_fs *c)
|
||||
bch2_trans_iter_exit(&trans, &iter);
|
||||
|
||||
if (ret) {
|
||||
bch_err(c, "error walking snapshots: %i", ret);
|
||||
bch_err(c, "error walking snapshots: %s", bch2_err_str(ret));
|
||||
goto err;
|
||||
}
|
||||
|
||||
for (id = 0; id < BTREE_ID_NR; id++) {
|
||||
struct bpos last_pos = POS_MIN;
|
||||
snapshot_id_list equiv_seen = { 0 };
|
||||
|
||||
if (!btree_type_has_snapshots(id))
|
||||
continue;
|
||||
|
||||
ret = bch2_snapshot_delete_keys_btree(&trans, &deleted, id);
|
||||
ret = for_each_btree_key_commit(&trans, iter,
|
||||
id, POS_MIN,
|
||||
BTREE_ITER_PREFETCH|BTREE_ITER_ALL_SNAPSHOTS, k,
|
||||
NULL, NULL, BTREE_INSERT_NOFAIL,
|
||||
snapshot_delete_key(&trans, &iter, k, &deleted, &equiv_seen, &last_pos));
|
||||
|
||||
darray_exit(&equiv_seen);
|
||||
|
||||
if (ret) {
|
||||
bch_err(c, "error deleting snapshot keys: %i", ret);
|
||||
bch_err(c, "error deleting snapshot keys: %s", bch2_err_str(ret));
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
@ -756,8 +720,8 @@ int bch2_delete_dead_snapshots(struct bch_fs *c)
|
||||
ret = commit_do(&trans, NULL, NULL, 0,
|
||||
bch2_snapshot_node_delete(&trans, deleted.data[i]));
|
||||
if (ret) {
|
||||
bch_err(c, "error deleting snapshot %u: %i",
|
||||
deleted.data[i], ret);
|
||||
bch_err(c, "error deleting snapshot %u: %s",
|
||||
deleted.data[i], bch2_err_str(ret));
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
@ -913,6 +877,8 @@ int bch2_subvolume_delete(struct btree_trans *trans, u32 subvolid)
|
||||
goto err;
|
||||
|
||||
ret = bch2_snapshot_node_set_deleted(trans, snapid);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
h = bch2_trans_kmalloc(trans, sizeof(*h));
|
||||
ret = PTR_ERR_OR_ZERO(h);
|
||||
@ -949,7 +915,7 @@ void bch2_subvolume_wait_for_pagecache_and_delete(struct work_struct *work)
|
||||
ret = bch2_trans_do(c, NULL, NULL, BTREE_INSERT_NOFAIL,
|
||||
bch2_subvolume_delete(&trans, *id));
|
||||
if (ret) {
|
||||
bch_err(c, "error %i deleting subvolume %u", ret, *id);
|
||||
bch_err(c, "error deleting subvolume %u: %s", *id, bch2_err_str(ret));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ void bch2_sb_field_delete(struct bch_sb_handle *sb,
|
||||
void bch2_free_super(struct bch_sb_handle *sb)
|
||||
{
|
||||
if (sb->bio)
|
||||
bio_put(sb->bio);
|
||||
kfree(sb->bio);
|
||||
if (!IS_ERR_OR_NULL(sb->bdev))
|
||||
blkdev_put(sb->bdev, sb->mode);
|
||||
|
||||
@ -143,13 +143,16 @@ int bch2_sb_realloc(struct bch_sb_handle *sb, unsigned u64s)
|
||||
return -ENOMEM;
|
||||
|
||||
if (sb->have_bio) {
|
||||
bio = bio_kmalloc(GFP_KERNEL,
|
||||
DIV_ROUND_UP(new_buffer_size, PAGE_SIZE));
|
||||
unsigned nr_bvecs = DIV_ROUND_UP(new_buffer_size, PAGE_SIZE);
|
||||
|
||||
bio = bio_kmalloc(nr_bvecs, GFP_KERNEL);
|
||||
if (!bio)
|
||||
return -ENOMEM;
|
||||
|
||||
bio_init(bio, NULL, bio->bi_inline_vecs, nr_bvecs, 0);
|
||||
|
||||
if (sb->bio)
|
||||
bio_put(sb->bio);
|
||||
kfree(sb->bio);
|
||||
sb->bio = bio;
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "debug.h"
|
||||
#include "disk_groups.h"
|
||||
#include "ec.h"
|
||||
#include "errcode.h"
|
||||
#include "error.h"
|
||||
#include "fs.h"
|
||||
#include "fs-io.h"
|
||||
@ -930,31 +931,10 @@ out:
|
||||
up_write(&c->state_lock);
|
||||
return ret;
|
||||
err:
|
||||
switch (ret) {
|
||||
case BCH_FSCK_ERRORS_NOT_FIXED:
|
||||
bch_err(c, "filesystem contains errors: please report this to the developers");
|
||||
pr_cont("mount with -o fix_errors to repair\n");
|
||||
break;
|
||||
case BCH_FSCK_REPAIR_UNIMPLEMENTED:
|
||||
bch_err(c, "filesystem contains errors: please report this to the developers");
|
||||
pr_cont("repair unimplemented: inform the developers so that it can be added\n");
|
||||
break;
|
||||
case BCH_FSCK_REPAIR_IMPOSSIBLE:
|
||||
bch_err(c, "filesystem contains errors, but repair impossible");
|
||||
break;
|
||||
case BCH_FSCK_UNKNOWN_VERSION:
|
||||
bch_err(c, "unknown metadata version");
|
||||
break;
|
||||
case -ENOMEM:
|
||||
bch_err(c, "cannot allocate memory");
|
||||
break;
|
||||
case -EIO:
|
||||
bch_err(c, "IO error");
|
||||
break;
|
||||
}
|
||||
bch_err(c, "error starting filesystem: %s", bch2_err_str(ret));
|
||||
|
||||
if (ret >= 0)
|
||||
ret = -EIO;
|
||||
if (ret < -BCH_ERR_START)
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -1438,7 +1418,7 @@ static int bch2_dev_remove_alloc(struct bch_fs *c, struct bch_dev *ca)
|
||||
bch2_btree_delete_range(c, BTREE_ID_alloc, start, end,
|
||||
BTREE_TRIGGER_NORUN, NULL);
|
||||
if (ret)
|
||||
bch_err(c, "error %i removing dev alloc info", ret);
|
||||
bch_err(c, "error removing dev alloc info: %s", bch2_err_str(ret));
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -1466,7 +1446,7 @@ int bch2_dev_remove(struct bch_fs *c, struct bch_dev *ca, int flags)
|
||||
|
||||
ret = bch2_dev_data_drop(c, ca->dev_idx, flags);
|
||||
if (ret) {
|
||||
bch_err(ca, "Remove failed: error %i dropping data", ret);
|
||||
bch_err(ca, "Remove failed: error dropping data: %s", bch2_err_str(ret));
|
||||
goto err;
|
||||
}
|
||||
|
||||
@ -1478,7 +1458,7 @@ int bch2_dev_remove(struct bch_fs *c, struct bch_dev *ca, int flags)
|
||||
|
||||
ret = bch2_journal_flush_device_pins(&c->journal, ca->dev_idx);
|
||||
if (ret) {
|
||||
bch_err(ca, "Remove failed: error %i flushing journal", ret);
|
||||
bch_err(ca, "Remove failed: error flushing journal: %s", bch2_err_str(ret));
|
||||
goto err;
|
||||
}
|
||||
|
||||
@ -1490,7 +1470,7 @@ int bch2_dev_remove(struct bch_fs *c, struct bch_dev *ca, int flags)
|
||||
|
||||
ret = bch2_replicas_gc2(c);
|
||||
if (ret) {
|
||||
bch_err(ca, "Remove failed: error %i from replicas gc", ret);
|
||||
bch_err(ca, "Remove failed: error from replicas gc: %s", bch2_err_str(ret));
|
||||
goto err;
|
||||
}
|
||||
|
||||
@ -1554,7 +1534,7 @@ int bch2_dev_add(struct bch_fs *c, const char *path)
|
||||
|
||||
ret = bch2_read_super(path, &opts, &sb);
|
||||
if (ret) {
|
||||
bch_err(c, "device add error: error reading super: %i", ret);
|
||||
bch_err(c, "device add error: error reading super: %s", bch2_err_str(ret));
|
||||
goto err;
|
||||
}
|
||||
|
||||
@ -1647,13 +1627,13 @@ have_slot:
|
||||
|
||||
ret = bch2_trans_mark_dev_sb(c, ca);
|
||||
if (ret) {
|
||||
bch_err(c, "device add error: error marking new superblock: %i", ret);
|
||||
bch_err(c, "device add error: error marking new superblock: %s", bch2_err_str(ret));
|
||||
goto err_late;
|
||||
}
|
||||
|
||||
ret = bch2_fs_freespace_init(c);
|
||||
if (ret) {
|
||||
bch_err(c, "device add error: error initializing free space: %i", ret);
|
||||
bch_err(c, "device add error: error initializing free space: %s", bch2_err_str(ret));
|
||||
goto err_late;
|
||||
}
|
||||
|
||||
@ -1715,8 +1695,8 @@ int bch2_dev_online(struct bch_fs *c, const char *path)
|
||||
|
||||
ret = bch2_trans_mark_dev_sb(c, ca);
|
||||
if (ret) {
|
||||
bch_err(c, "error bringing %s online: error %i from bch2_trans_mark_dev_sb",
|
||||
path, ret);
|
||||
bch_err(c, "error bringing %s online: error from bch2_trans_mark_dev_sb: %s",
|
||||
path, bch2_err_str(ret));
|
||||
goto err;
|
||||
}
|
||||
|
||||
@ -1785,7 +1765,7 @@ int bch2_dev_resize(struct bch_fs *c, struct bch_dev *ca, u64 nbuckets)
|
||||
|
||||
ret = bch2_dev_buckets_resize(c, ca, nbuckets);
|
||||
if (ret) {
|
||||
bch_err(ca, "Resize error: %i", ret);
|
||||
bch_err(ca, "Resize error: %s", bch2_err_str(ret));
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
@ -46,7 +46,7 @@ static int test_delete(struct bch_fs *c, u64 nr)
|
||||
bch2_btree_iter_traverse(&iter) ?:
|
||||
bch2_trans_update(&trans, &iter, &k.k_i, 0));
|
||||
if (ret) {
|
||||
bch_err(c, "update error in test_delete: %i", ret);
|
||||
bch_err(c, "update error in test_delete: %s", bch2_err_str(ret));
|
||||
goto err;
|
||||
}
|
||||
|
||||
@ -55,7 +55,7 @@ static int test_delete(struct bch_fs *c, u64 nr)
|
||||
bch2_btree_iter_traverse(&iter) ?:
|
||||
bch2_btree_delete_at(&trans, &iter, 0));
|
||||
if (ret) {
|
||||
bch_err(c, "delete error (first) in test_delete: %i", ret);
|
||||
bch_err(c, "delete error (first) in test_delete: %s", bch2_err_str(ret));
|
||||
goto err;
|
||||
}
|
||||
|
||||
@ -64,7 +64,7 @@ static int test_delete(struct bch_fs *c, u64 nr)
|
||||
bch2_btree_iter_traverse(&iter) ?:
|
||||
bch2_btree_delete_at(&trans, &iter, 0));
|
||||
if (ret) {
|
||||
bch_err(c, "delete error (second) in test_delete: %i", ret);
|
||||
bch_err(c, "delete error (second) in test_delete: %s", bch2_err_str(ret));
|
||||
goto err;
|
||||
}
|
||||
err:
|
||||
@ -92,7 +92,7 @@ static int test_delete_written(struct bch_fs *c, u64 nr)
|
||||
bch2_btree_iter_traverse(&iter) ?:
|
||||
bch2_trans_update(&trans, &iter, &k.k_i, 0));
|
||||
if (ret) {
|
||||
bch_err(c, "update error in test_delete_written: %i", ret);
|
||||
bch_err(c, "update error in test_delete_written: %s", bch2_err_str(ret));
|
||||
goto err;
|
||||
}
|
||||
|
||||
@ -103,7 +103,7 @@ static int test_delete_written(struct bch_fs *c, u64 nr)
|
||||
bch2_btree_iter_traverse(&iter) ?:
|
||||
bch2_btree_delete_at(&trans, &iter, 0));
|
||||
if (ret) {
|
||||
bch_err(c, "delete error in test_delete_written: %i", ret);
|
||||
bch_err(c, "delete error in test_delete_written: %s", bch2_err_str(ret));
|
||||
goto err;
|
||||
}
|
||||
err:
|
||||
@ -136,7 +136,7 @@ static int test_iterate(struct bch_fs *c, u64 nr)
|
||||
ret = bch2_btree_insert(c, BTREE_ID_xattrs, &k.k_i,
|
||||
NULL, NULL, 0);
|
||||
if (ret) {
|
||||
bch_err(c, "insert error in test_iterate: %i", ret);
|
||||
bch_err(c, "insert error in test_iterate: %s", bch2_err_str(ret));
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
@ -145,20 +145,30 @@ static int test_iterate(struct bch_fs *c, u64 nr)
|
||||
|
||||
i = 0;
|
||||
|
||||
for_each_btree_key(&trans, iter, BTREE_ID_xattrs,
|
||||
SPOS(0, 0, U32_MAX), 0, k, ret) {
|
||||
if (k.k->p.inode)
|
||||
break;
|
||||
|
||||
ret = for_each_btree_key2(&trans, iter, BTREE_ID_xattrs,
|
||||
SPOS(0, 0, U32_MAX), 0, k, ({
|
||||
BUG_ON(k.k->p.offset != i++);
|
||||
0;
|
||||
}));
|
||||
if (ret) {
|
||||
bch_err(c, "%s(): error iterating forwards: %s", __func__, bch2_err_str(ret));
|
||||
goto err;
|
||||
}
|
||||
|
||||
BUG_ON(i != nr);
|
||||
|
||||
pr_info("iterating backwards");
|
||||
|
||||
while (!IS_ERR_OR_NULL((k = bch2_btree_iter_prev(&iter)).k))
|
||||
BUG_ON(k.k->p.offset != --i);
|
||||
ret = for_each_btree_key_reverse(&trans, iter, BTREE_ID_xattrs,
|
||||
SPOS(0, U64_MAX, U32_MAX), 0, k,
|
||||
({
|
||||
BUG_ON(k.k->p.offset != --i);
|
||||
0;
|
||||
}));
|
||||
if (ret) {
|
||||
bch_err(c, "%s(): error iterating backwards: %s", __func__, bch2_err_str(ret));
|
||||
goto err;
|
||||
}
|
||||
|
||||
BUG_ON(i);
|
||||
err:
|
||||
@ -192,7 +202,7 @@ static int test_iterate_extents(struct bch_fs *c, u64 nr)
|
||||
ret = bch2_btree_insert(c, BTREE_ID_extents, &k.k_i,
|
||||
NULL, NULL, 0);
|
||||
if (ret) {
|
||||
bch_err(c, "insert error in test_iterate_extents: %i", ret);
|
||||
bch_err(c, "insert error in test_iterate_extents: %s", bch2_err_str(ret));
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
@ -201,19 +211,31 @@ static int test_iterate_extents(struct bch_fs *c, u64 nr)
|
||||
|
||||
i = 0;
|
||||
|
||||
for_each_btree_key(&trans, iter, BTREE_ID_extents,
|
||||
SPOS(0, 0, U32_MAX), 0, k, ret) {
|
||||
ret = for_each_btree_key2(&trans, iter, BTREE_ID_extents,
|
||||
SPOS(0, 0, U32_MAX), 0, k, ({
|
||||
BUG_ON(bkey_start_offset(k.k) != i);
|
||||
i = k.k->p.offset;
|
||||
0;
|
||||
}));
|
||||
if (ret) {
|
||||
bch_err(c, "%s(): error iterating forwards: %s", __func__, bch2_err_str(ret));
|
||||
goto err;
|
||||
}
|
||||
|
||||
BUG_ON(i != nr);
|
||||
|
||||
pr_info("iterating backwards");
|
||||
|
||||
while (!IS_ERR_OR_NULL((k = bch2_btree_iter_prev(&iter)).k)) {
|
||||
BUG_ON(k.k->p.offset != i);
|
||||
i = bkey_start_offset(k.k);
|
||||
ret = for_each_btree_key_reverse(&trans, iter, BTREE_ID_extents,
|
||||
SPOS(0, U64_MAX, U32_MAX), 0, k,
|
||||
({
|
||||
BUG_ON(k.k->p.offset != i);
|
||||
i = bkey_start_offset(k.k);
|
||||
0;
|
||||
}));
|
||||
if (ret) {
|
||||
bch_err(c, "%s(): error iterating backwards: %s", __func__, bch2_err_str(ret));
|
||||
goto err;
|
||||
}
|
||||
|
||||
BUG_ON(i);
|
||||
@ -247,7 +269,7 @@ static int test_iterate_slots(struct bch_fs *c, u64 nr)
|
||||
ret = bch2_btree_insert(c, BTREE_ID_xattrs, &k.k_i,
|
||||
NULL, NULL, 0);
|
||||
if (ret) {
|
||||
bch_err(c, "insert error in test_iterate_slots: %i", ret);
|
||||
bch_err(c, "insert error in test_iterate_slots: %s", bch2_err_str(ret));
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
@ -256,15 +278,16 @@ static int test_iterate_slots(struct bch_fs *c, u64 nr)
|
||||
|
||||
i = 0;
|
||||
|
||||
for_each_btree_key(&trans, iter, BTREE_ID_xattrs,
|
||||
SPOS(0, 0, U32_MAX), 0, k, ret) {
|
||||
if (k.k->p.inode)
|
||||
break;
|
||||
|
||||
ret = for_each_btree_key2(&trans, iter, BTREE_ID_xattrs,
|
||||
SPOS(0, 0, U32_MAX), 0, k, ({
|
||||
BUG_ON(k.k->p.offset != i);
|
||||
i += 2;
|
||||
0;
|
||||
}));
|
||||
if (ret) {
|
||||
bch_err(c, "%s(): error iterating forwards: %s", __func__, bch2_err_str(ret));
|
||||
goto err;
|
||||
}
|
||||
bch2_trans_iter_exit(&trans, &iter);
|
||||
|
||||
BUG_ON(i != nr * 2);
|
||||
|
||||
@ -272,17 +295,23 @@ static int test_iterate_slots(struct bch_fs *c, u64 nr)
|
||||
|
||||
i = 0;
|
||||
|
||||
for_each_btree_key(&trans, iter, BTREE_ID_xattrs,
|
||||
SPOS(0, 0, U32_MAX),
|
||||
BTREE_ITER_SLOTS, k, ret) {
|
||||
ret = for_each_btree_key2(&trans, iter, BTREE_ID_xattrs,
|
||||
SPOS(0, 0, U32_MAX),
|
||||
BTREE_ITER_SLOTS, k, ({
|
||||
if (i >= nr * 2)
|
||||
break;
|
||||
|
||||
BUG_ON(k.k->p.offset != i);
|
||||
BUG_ON(bkey_deleted(k.k) != (i & 1));
|
||||
|
||||
i++;
|
||||
if (i == nr * 2)
|
||||
break;
|
||||
0;
|
||||
}));
|
||||
if (ret < 0) {
|
||||
bch_err(c, "%s(): error iterating forwards by slots: %s", __func__, bch2_err_str(ret));
|
||||
goto err;
|
||||
}
|
||||
bch2_trans_iter_exit(&trans, &iter);
|
||||
ret = 0;
|
||||
err:
|
||||
bch2_trans_exit(&trans);
|
||||
return ret;
|
||||
@ -313,7 +342,7 @@ static int test_iterate_slots_extents(struct bch_fs *c, u64 nr)
|
||||
ret = bch2_btree_insert(c, BTREE_ID_extents, &k.k_i,
|
||||
NULL, NULL, 0);
|
||||
if (ret) {
|
||||
bch_err(c, "insert error in test_iterate_slots_extents: %i", ret);
|
||||
bch_err(c, "insert error in test_iterate_slots_extents: %s", bch2_err_str(ret));
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
@ -322,13 +351,17 @@ static int test_iterate_slots_extents(struct bch_fs *c, u64 nr)
|
||||
|
||||
i = 0;
|
||||
|
||||
for_each_btree_key(&trans, iter, BTREE_ID_extents,
|
||||
SPOS(0, 0, U32_MAX), 0, k, ret) {
|
||||
ret = for_each_btree_key2(&trans, iter, BTREE_ID_extents,
|
||||
SPOS(0, 0, U32_MAX), 0, k, ({
|
||||
BUG_ON(bkey_start_offset(k.k) != i + 8);
|
||||
BUG_ON(k.k->size != 8);
|
||||
i += 16;
|
||||
0;
|
||||
}));
|
||||
if (ret) {
|
||||
bch_err(c, "%s(): error iterating forwards: %s", __func__, bch2_err_str(ret));
|
||||
goto err;
|
||||
}
|
||||
bch2_trans_iter_exit(&trans, &iter);
|
||||
|
||||
BUG_ON(i != nr);
|
||||
|
||||
@ -336,19 +369,23 @@ static int test_iterate_slots_extents(struct bch_fs *c, u64 nr)
|
||||
|
||||
i = 0;
|
||||
|
||||
for_each_btree_key(&trans, iter, BTREE_ID_extents,
|
||||
SPOS(0, 0, U32_MAX),
|
||||
BTREE_ITER_SLOTS, k, ret) {
|
||||
ret = for_each_btree_key2(&trans, iter, BTREE_ID_extents,
|
||||
SPOS(0, 0, U32_MAX),
|
||||
BTREE_ITER_SLOTS, k, ({
|
||||
if (i == nr)
|
||||
break;
|
||||
BUG_ON(bkey_deleted(k.k) != !(i % 16));
|
||||
|
||||
BUG_ON(bkey_start_offset(k.k) != i);
|
||||
BUG_ON(k.k->size != 8);
|
||||
i = k.k->p.offset;
|
||||
|
||||
if (i == nr)
|
||||
break;
|
||||
0;
|
||||
}));
|
||||
if (ret) {
|
||||
bch_err(c, "%s(): error iterating forwards by slots: %s", __func__, bch2_err_str(ret));
|
||||
goto err;
|
||||
}
|
||||
bch2_trans_iter_exit(&trans, &iter);
|
||||
ret = 0;
|
||||
err:
|
||||
bch2_trans_exit(&trans);
|
||||
return 0;
|
||||
@ -368,10 +405,10 @@ static int test_peek_end(struct bch_fs *c, u64 nr)
|
||||
bch2_trans_iter_init(&trans, &iter, BTREE_ID_xattrs,
|
||||
SPOS(0, 0, U32_MAX), 0);
|
||||
|
||||
k = bch2_btree_iter_peek(&iter);
|
||||
lockrestart_do(&trans, bkey_err(k = bch2_btree_iter_peek(&iter)));
|
||||
BUG_ON(k.k);
|
||||
|
||||
k = bch2_btree_iter_peek(&iter);
|
||||
lockrestart_do(&trans, bkey_err(k = bch2_btree_iter_peek(&iter)));
|
||||
BUG_ON(k.k);
|
||||
|
||||
bch2_trans_iter_exit(&trans, &iter);
|
||||
@ -389,10 +426,10 @@ static int test_peek_end_extents(struct bch_fs *c, u64 nr)
|
||||
bch2_trans_iter_init(&trans, &iter, BTREE_ID_extents,
|
||||
SPOS(0, 0, U32_MAX), 0);
|
||||
|
||||
k = bch2_btree_iter_peek(&iter);
|
||||
lockrestart_do(&trans, bkey_err(k = bch2_btree_iter_peek(&iter)));
|
||||
BUG_ON(k.k);
|
||||
|
||||
k = bch2_btree_iter_peek(&iter);
|
||||
lockrestart_do(&trans, bkey_err(k = bch2_btree_iter_peek(&iter)));
|
||||
BUG_ON(k.k);
|
||||
|
||||
bch2_trans_iter_exit(&trans, &iter);
|
||||
@ -419,7 +456,7 @@ static int insert_test_extent(struct bch_fs *c,
|
||||
ret = bch2_btree_insert(c, BTREE_ID_extents, &k.k_i,
|
||||
NULL, NULL, 0);
|
||||
if (ret)
|
||||
bch_err(c, "insert error in insert_test_extent: %i", ret);
|
||||
bch_err(c, "insert error in insert_test_extent: %s", bch2_err_str(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -482,7 +519,7 @@ static int test_snapshot_filter(struct bch_fs *c, u32 snapid_lo, u32 snapid_hi)
|
||||
bch2_trans_init(&trans, c, 0, 0);
|
||||
bch2_trans_iter_init(&trans, &iter, BTREE_ID_xattrs,
|
||||
SPOS(0, 0, snapid_lo), 0);
|
||||
k = bch2_btree_iter_peek(&iter);
|
||||
lockrestart_do(&trans, bkey_err(k = bch2_btree_iter_peek(&iter)));
|
||||
|
||||
BUG_ON(k.k->p.snapshot != U32_MAX);
|
||||
|
||||
@ -518,7 +555,7 @@ static int test_snapshots(struct bch_fs *c, u64 nr)
|
||||
|
||||
ret = test_snapshot_filter(c, snapids[0], snapids[1]);
|
||||
if (ret) {
|
||||
bch_err(c, "err %i from test_snapshot_filter", ret);
|
||||
bch_err(c, "err from test_snapshot_filter: %s", bch2_err_str(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -555,7 +592,7 @@ static int rand_insert(struct bch_fs *c, u64 nr)
|
||||
ret = commit_do(&trans, NULL, NULL, 0,
|
||||
__bch2_btree_insert(&trans, BTREE_ID_xattrs, &k.k_i));
|
||||
if (ret) {
|
||||
bch_err(c, "error in rand_insert: %i", ret);
|
||||
bch_err(c, "error in rand_insert: %s", bch2_err_str(ret));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -591,7 +628,7 @@ static int rand_insert_multi(struct bch_fs *c, u64 nr)
|
||||
__bch2_btree_insert(&trans, BTREE_ID_xattrs, &k[6].k_i) ?:
|
||||
__bch2_btree_insert(&trans, BTREE_ID_xattrs, &k[7].k_i));
|
||||
if (ret) {
|
||||
bch_err(c, "error in rand_insert_multi: %i", ret);
|
||||
bch_err(c, "error in rand_insert_multi: %s", bch2_err_str(ret));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -615,10 +652,10 @@ static int rand_lookup(struct bch_fs *c, u64 nr)
|
||||
for (i = 0; i < nr; i++) {
|
||||
bch2_btree_iter_set_pos(&iter, SPOS(0, test_rand(), U32_MAX));
|
||||
|
||||
k = bch2_btree_iter_peek(&iter);
|
||||
lockrestart_do(&trans, bkey_err(k = bch2_btree_iter_peek(&iter)));
|
||||
ret = bkey_err(k);
|
||||
if (ret) {
|
||||
bch_err(c, "error in rand_lookup: %i", ret);
|
||||
bch_err(c, "error in rand_lookup: %s", bch2_err_str(ret));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -638,10 +675,10 @@ static int rand_mixed_trans(struct btree_trans *trans,
|
||||
|
||||
bch2_btree_iter_set_pos(iter, SPOS(0, pos, U32_MAX));
|
||||
|
||||
k = bch2_btree_iter_peek(iter);
|
||||
lockrestart_do(trans, bkey_err(k = bch2_btree_iter_peek(iter)));
|
||||
ret = bkey_err(k);
|
||||
if (ret && ret != -EINTR)
|
||||
bch_err(trans->c, "lookup error in rand_mixed: %i", ret);
|
||||
if (ret && !bch2_err_matches(ret, BCH_ERR_transaction_restart))
|
||||
bch_err(trans->c, "lookup error in rand_mixed: %s", bch2_err_str(ret));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -671,7 +708,7 @@ static int rand_mixed(struct bch_fs *c, u64 nr)
|
||||
ret = commit_do(&trans, NULL, NULL, 0,
|
||||
rand_mixed_trans(&trans, &iter, &cookie, i, rand));
|
||||
if (ret) {
|
||||
bch_err(c, "update error in rand_mixed: %i", ret);
|
||||
bch_err(c, "update error in rand_mixed: %s", bch2_err_str(ret));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -689,7 +726,7 @@ static int __do_delete(struct btree_trans *trans, struct bpos pos)
|
||||
|
||||
bch2_trans_iter_init(trans, &iter, BTREE_ID_xattrs, pos,
|
||||
BTREE_ITER_INTENT);
|
||||
k = bch2_btree_iter_peek(&iter);
|
||||
lockrestart_do(trans, bkey_err(k = bch2_btree_iter_peek(&iter)));
|
||||
ret = bkey_err(k);
|
||||
if (ret)
|
||||
goto err;
|
||||
@ -717,7 +754,7 @@ static int rand_delete(struct bch_fs *c, u64 nr)
|
||||
ret = commit_do(&trans, NULL, NULL, 0,
|
||||
__do_delete(&trans, pos));
|
||||
if (ret) {
|
||||
bch_err(c, "error in rand_delete: %i", ret);
|
||||
bch_err(c, "error in rand_delete: %s", bch2_err_str(ret));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -733,28 +770,23 @@ static int seq_insert(struct bch_fs *c, u64 nr)
|
||||
struct bkey_s_c k;
|
||||
struct bkey_i_cookie insert;
|
||||
int ret = 0;
|
||||
u64 i = 0;
|
||||
|
||||
bkey_cookie_init(&insert.k_i);
|
||||
|
||||
bch2_trans_init(&trans, c, 0, 0);
|
||||
|
||||
for_each_btree_key(&trans, iter, BTREE_ID_xattrs, SPOS(0, 0, U32_MAX),
|
||||
BTREE_ITER_SLOTS|BTREE_ITER_INTENT, k, ret) {
|
||||
insert.k.p = iter.pos;
|
||||
|
||||
ret = commit_do(&trans, NULL, NULL, 0,
|
||||
bch2_btree_iter_traverse(&iter) ?:
|
||||
bch2_trans_update(&trans, &iter, &insert.k_i, 0));
|
||||
if (ret) {
|
||||
bch_err(c, "error in seq_insert: %i", ret);
|
||||
break;
|
||||
}
|
||||
|
||||
if (++i == nr)
|
||||
break;
|
||||
}
|
||||
bch2_trans_iter_exit(&trans, &iter);
|
||||
ret = for_each_btree_key_commit(&trans, iter, BTREE_ID_xattrs,
|
||||
SPOS(0, 0, U32_MAX),
|
||||
BTREE_ITER_SLOTS|BTREE_ITER_INTENT, k,
|
||||
NULL, NULL, 0,
|
||||
({
|
||||
if (iter.pos.offset >= nr)
|
||||
break;
|
||||
insert.k.p = iter.pos;
|
||||
bch2_trans_update(&trans, &iter, &insert.k_i, 0);
|
||||
}));
|
||||
if (ret)
|
||||
bch_err(c, "error in %s(): %s", __func__, bch2_err_str(ret));
|
||||
|
||||
bch2_trans_exit(&trans);
|
||||
return ret;
|
||||
@ -769,10 +801,11 @@ static int seq_lookup(struct bch_fs *c, u64 nr)
|
||||
|
||||
bch2_trans_init(&trans, c, 0, 0);
|
||||
|
||||
for_each_btree_key(&trans, iter, BTREE_ID_xattrs,
|
||||
SPOS(0, 0, U32_MAX), 0, k, ret)
|
||||
;
|
||||
bch2_trans_iter_exit(&trans, &iter);
|
||||
ret = for_each_btree_key2(&trans, iter, BTREE_ID_xattrs,
|
||||
SPOS(0, 0, U32_MAX), 0, k,
|
||||
0);
|
||||
if (ret)
|
||||
bch_err(c, "error in %s(): %s", __func__, bch2_err_str(ret));
|
||||
|
||||
bch2_trans_exit(&trans);
|
||||
return ret;
|
||||
@ -787,22 +820,18 @@ static int seq_overwrite(struct bch_fs *c, u64 nr)
|
||||
|
||||
bch2_trans_init(&trans, c, 0, 0);
|
||||
|
||||
for_each_btree_key(&trans, iter, BTREE_ID_xattrs,
|
||||
SPOS(0, 0, U32_MAX),
|
||||
BTREE_ITER_INTENT, k, ret) {
|
||||
struct bkey_i_cookie u;
|
||||
ret = for_each_btree_key_commit(&trans, iter, BTREE_ID_xattrs,
|
||||
SPOS(0, 0, U32_MAX),
|
||||
BTREE_ITER_INTENT, k,
|
||||
NULL, NULL, 0,
|
||||
({
|
||||
struct bkey_i_cookie u;
|
||||
|
||||
bkey_reassemble(&u.k_i, k);
|
||||
|
||||
ret = commit_do(&trans, NULL, NULL, 0,
|
||||
bch2_btree_iter_traverse(&iter) ?:
|
||||
bch2_trans_update(&trans, &iter, &u.k_i, 0));
|
||||
if (ret) {
|
||||
bch_err(c, "error in seq_overwrite: %i", ret);
|
||||
break;
|
||||
}
|
||||
}
|
||||
bch2_trans_iter_exit(&trans, &iter);
|
||||
bkey_reassemble(&u.k_i, k);
|
||||
bch2_trans_update(&trans, &iter, &u.k_i, 0);
|
||||
}));
|
||||
if (ret)
|
||||
bch_err(c, "error in %s(): %s", __func__, bch2_err_str(ret));
|
||||
|
||||
bch2_trans_exit(&trans);
|
||||
return ret;
|
||||
@ -816,7 +845,7 @@ static int seq_delete(struct bch_fs *c, u64 nr)
|
||||
SPOS(0, 0, U32_MAX), SPOS_MAX,
|
||||
0, NULL);
|
||||
if (ret)
|
||||
bch_err(c, "error in seq_delete: %i", ret);
|
||||
bch_err(c, "error in seq_delete: %s", bch2_err_str(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -853,7 +882,7 @@ static int btree_perf_test_thread(void *data)
|
||||
|
||||
ret = j->fn(j->c, div64_u64(j->nr, j->nr_threads));
|
||||
if (ret) {
|
||||
bch_err(j->c, "%ps: error %i", j->fn, ret);
|
||||
bch_err(j->c, "%ps: error %s", j->fn, bch2_err_str(ret));
|
||||
j->ret = ret;
|
||||
}
|
||||
|
||||
|
@ -2,11 +2,13 @@
|
||||
#include "bcachefs.h"
|
||||
#include "alloc_types.h"
|
||||
#include "buckets.h"
|
||||
#include "btree_types.h"
|
||||
#include "btree_iter.h"
|
||||
#include "btree_locking.h"
|
||||
#include "keylist.h"
|
||||
#include "opts.h"
|
||||
|
||||
#include <linux/blktrace_api.h>
|
||||
#include "keylist.h"
|
||||
#include <linux/six.h>
|
||||
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include <trace/events/bcachefs.h>
|
||||
|
@ -376,31 +376,37 @@ void bch2_time_stats_to_text(struct printbuf *out, struct time_stats *stats)
|
||||
u64 q, last_q = 0;
|
||||
int i;
|
||||
|
||||
prt_printf(out, "count:\t\t%llu\n",
|
||||
prt_printf(out, "count:\t\t%llu",
|
||||
stats->count);
|
||||
prt_printf(out, "rate:\t\t%llu/sec\n",
|
||||
prt_newline(out);
|
||||
prt_printf(out, "rate:\t\t%llu/sec",
|
||||
freq ? div64_u64(NSEC_PER_SEC, freq) : 0);
|
||||
prt_newline(out);
|
||||
|
||||
prt_printf(out, "frequency:\t");
|
||||
pr_time_units(out, freq);
|
||||
|
||||
prt_printf(out, "\navg duration:\t");
|
||||
prt_newline(out);
|
||||
prt_printf(out, "avg duration:\t");
|
||||
pr_time_units(out, stats->average_duration);
|
||||
|
||||
prt_printf(out, "\nmax duration:\t");
|
||||
prt_newline(out);
|
||||
prt_printf(out, "max duration:\t");
|
||||
pr_time_units(out, stats->max_duration);
|
||||
|
||||
i = eytzinger0_first(NR_QUANTILES);
|
||||
u = pick_time_units(stats->quantiles.entries[i].m);
|
||||
|
||||
prt_printf(out, "\nquantiles (%s):\t", u->name);
|
||||
prt_newline(out);
|
||||
prt_printf(out, "quantiles (%s):\t", u->name);
|
||||
eytzinger0_for_each(i, NR_QUANTILES) {
|
||||
bool is_last = eytzinger0_next(i, NR_QUANTILES) == -1;
|
||||
|
||||
q = max(stats->quantiles.entries[i].m, last_q);
|
||||
prt_printf(out, "%llu%s",
|
||||
div_u64(q, u->nsecs),
|
||||
is_last ? "\n" : " ");
|
||||
prt_printf(out, "%llu ",
|
||||
div_u64(q, u->nsecs));
|
||||
if (is_last)
|
||||
prt_newline(out);
|
||||
last_q = q;
|
||||
}
|
||||
}
|
||||
|
@ -344,7 +344,7 @@ retry:
|
||||
offset = iter.pos.offset;
|
||||
bch2_trans_iter_exit(&trans, &iter);
|
||||
err:
|
||||
if (ret == -EINTR)
|
||||
if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
|
||||
goto retry;
|
||||
|
||||
bch2_trans_exit(&trans);
|
||||
|
@ -293,7 +293,7 @@ void bio_reset(struct bio *bio, struct block_device *bdev, unsigned int opf)
|
||||
atomic_set(&bio->__bi_remaining, 1);
|
||||
}
|
||||
|
||||
struct bio *bio_kmalloc(gfp_t gfp_mask, unsigned int nr_iovecs)
|
||||
struct bio *bio_kmalloc(unsigned int nr_iovecs, gfp_t gfp_mask)
|
||||
{
|
||||
struct bio *bio;
|
||||
|
||||
|
@ -113,7 +113,7 @@ int submit_bio_wait(struct bio *bio)
|
||||
|
||||
int blkdev_issue_discard(struct block_device *bdev,
|
||||
sector_t sector, sector_t nr_sects,
|
||||
gfp_t gfp_mask, unsigned long flags)
|
||||
gfp_t gfp_mask)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
20
linux/six.c
20
linux/six.c
@ -757,3 +757,23 @@ void six_lock_pcpu_alloc(struct six_lock *lock)
|
||||
#endif
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(six_lock_pcpu_alloc);
|
||||
|
||||
/*
|
||||
* Returns lock held counts, for both read and intent
|
||||
*/
|
||||
struct six_lock_count six_lock_counts(struct six_lock *lock)
|
||||
{
|
||||
struct six_lock_count ret = { 0, lock->state.intent_lock };
|
||||
|
||||
if (!lock->readers)
|
||||
ret.read += lock->state.read_lock;
|
||||
else {
|
||||
int cpu;
|
||||
|
||||
for_each_possible_cpu(cpu)
|
||||
ret.read += *per_cpu_ptr(lock->readers, cpu);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(six_lock_counts);
|
||||
|
Loading…
Reference in New Issue
Block a user