mirror of
https://github.com/koverstreet/bcachefs-tools.git
synced 2025-02-22 00:00:03 +03:00
Update bcachefs sources to 938f680845d1 fixup! rename and export __kern_path_locked()
This commit is contained in:
parent
9776f9f362
commit
689b4dd4f0
@ -1 +1 @@
|
||||
3ca08ab51ec996180c20105489176b8c4327240c
|
||||
938f680845d1be28979e23aee972dba010c464ba
|
||||
|
@ -457,25 +457,18 @@ missing:
|
||||
}
|
||||
|
||||
static int check_extent_to_backpointers(struct btree_trans *trans,
|
||||
struct btree_iter *iter,
|
||||
enum btree_id btree, unsigned level,
|
||||
struct bpos bucket_start,
|
||||
struct bpos bucket_end,
|
||||
struct bpos_level *last_flushed)
|
||||
struct bpos_level *last_flushed,
|
||||
struct bkey_s_c k)
|
||||
{
|
||||
struct bch_fs *c = trans->c;
|
||||
struct bkey_ptrs_c ptrs;
|
||||
const union bch_extent_entry *entry;
|
||||
struct extent_ptr_decoded p;
|
||||
struct bkey_s_c k;
|
||||
int ret;
|
||||
|
||||
k = bch2_btree_iter_peek_all_levels(iter);
|
||||
ret = bkey_err(k);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (!k.k)
|
||||
return 0;
|
||||
|
||||
ptrs = bch2_bkey_ptrs_c(k);
|
||||
bkey_for_each_ptr_decode(k.k, ptrs, p, entry) {
|
||||
struct bpos bucket_pos;
|
||||
@ -484,7 +477,7 @@ static int check_extent_to_backpointers(struct btree_trans *trans,
|
||||
if (p.ptr.cached)
|
||||
continue;
|
||||
|
||||
bch2_extent_ptr_to_bp(c, iter->btree_id, iter->path->level,
|
||||
bch2_extent_ptr_to_bp(c, btree, level,
|
||||
k, p, &bucket_pos, &bp);
|
||||
|
||||
ret = check_bp_exists(trans, bucket_pos, bp, k,
|
||||
@ -501,44 +494,33 @@ static int check_btree_root_to_backpointers(struct btree_trans *trans,
|
||||
enum btree_id btree_id,
|
||||
struct bpos bucket_start,
|
||||
struct bpos bucket_end,
|
||||
struct bpos_level *last_flushed)
|
||||
struct bpos_level *last_flushed,
|
||||
int *level)
|
||||
{
|
||||
struct bch_fs *c = trans->c;
|
||||
struct btree_root *r = bch2_btree_id_root(c, btree_id);
|
||||
struct btree_iter iter;
|
||||
struct btree *b;
|
||||
struct bkey_s_c k;
|
||||
struct bkey_ptrs_c ptrs;
|
||||
struct extent_ptr_decoded p;
|
||||
const union bch_extent_entry *entry;
|
||||
int ret;
|
||||
|
||||
bch2_trans_node_iter_init(trans, &iter, btree_id, POS_MIN, 0, r->level, 0);
|
||||
retry:
|
||||
bch2_trans_node_iter_init(trans, &iter, btree_id, POS_MIN,
|
||||
0, bch2_btree_id_root(c, btree_id)->b->c.level, 0);
|
||||
b = bch2_btree_iter_peek_node(&iter);
|
||||
ret = PTR_ERR_OR_ZERO(b);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
BUG_ON(b != btree_node_root(c, b));
|
||||
if (b != btree_node_root(c, b)) {
|
||||
bch2_trans_iter_exit(trans, &iter);
|
||||
goto retry;
|
||||
}
|
||||
|
||||
*level = b->c.level;
|
||||
|
||||
k = bkey_i_to_s_c(&b->key);
|
||||
ptrs = bch2_bkey_ptrs_c(k);
|
||||
bkey_for_each_ptr_decode(k.k, ptrs, p, entry) {
|
||||
struct bpos bucket_pos;
|
||||
struct bch_backpointer bp;
|
||||
|
||||
if (p.ptr.cached)
|
||||
continue;
|
||||
|
||||
bch2_extent_ptr_to_bp(c, iter.btree_id, b->c.level + 1,
|
||||
k, p, &bucket_pos, &bp);
|
||||
|
||||
ret = check_bp_exists(trans, bucket_pos, bp, k,
|
||||
ret = check_extent_to_backpointers(trans, btree_id, b->c.level + 1,
|
||||
bucket_start, bucket_end,
|
||||
last_flushed);
|
||||
if (ret)
|
||||
goto err;
|
||||
}
|
||||
last_flushed, k);
|
||||
err:
|
||||
bch2_trans_iter_exit(trans, &iter);
|
||||
return ret;
|
||||
@ -616,43 +598,49 @@ static int bch2_check_extents_to_backpointers_pass(struct btree_trans *trans,
|
||||
struct bch_fs *c = trans->c;
|
||||
struct btree_iter iter;
|
||||
enum btree_id btree_id;
|
||||
struct bkey_s_c k;
|
||||
struct bpos_level last_flushed = { UINT_MAX, POS_MIN };
|
||||
int ret = 0;
|
||||
|
||||
for (btree_id = 0; btree_id < btree_id_nr_alive(c); btree_id++) {
|
||||
unsigned depth = btree_type_has_ptrs(btree_id) ? 0 : 1;
|
||||
|
||||
bch2_trans_node_iter_init(trans, &iter, btree_id, POS_MIN, 0,
|
||||
depth,
|
||||
BTREE_ITER_ALL_LEVELS|
|
||||
BTREE_ITER_PREFETCH);
|
||||
|
||||
do {
|
||||
ret = commit_do(trans, NULL, NULL,
|
||||
BCH_TRANS_COMMIT_lazy_rw|
|
||||
BCH_TRANS_COMMIT_no_enospc,
|
||||
check_extent_to_backpointers(trans, &iter,
|
||||
bucket_start, bucket_end,
|
||||
&last_flushed));
|
||||
if (ret)
|
||||
break;
|
||||
} while (!bch2_btree_iter_advance(&iter));
|
||||
|
||||
bch2_trans_iter_exit(trans, &iter);
|
||||
|
||||
if (ret)
|
||||
break;
|
||||
int level, depth = btree_type_has_ptrs(btree_id) ? 0 : 1;
|
||||
|
||||
ret = commit_do(trans, NULL, NULL,
|
||||
BCH_TRANS_COMMIT_lazy_rw|
|
||||
BCH_TRANS_COMMIT_no_enospc,
|
||||
check_btree_root_to_backpointers(trans, btree_id,
|
||||
bucket_start, bucket_end,
|
||||
&last_flushed));
|
||||
&last_flushed, &level));
|
||||
if (ret)
|
||||
break;
|
||||
return ret;
|
||||
|
||||
while (level >= depth) {
|
||||
bch2_trans_node_iter_init(trans, &iter, btree_id, POS_MIN, 0,
|
||||
level,
|
||||
BTREE_ITER_PREFETCH);
|
||||
for_each_btree_key_continue(trans, iter, BTREE_ITER_PREFETCH, k, ret) {
|
||||
ret = commit_do(trans, NULL, NULL,
|
||||
BCH_TRANS_COMMIT_lazy_rw|
|
||||
BCH_TRANS_COMMIT_no_enospc,
|
||||
check_extent_to_backpointers(trans, btree_id, level,
|
||||
bucket_start, bucket_end,
|
||||
&last_flushed, k));
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
if (bpos_eq(iter.pos, SPOS_MAX))
|
||||
break;
|
||||
}
|
||||
bch2_trans_iter_exit(trans, &iter);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
--level;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct bpos bucket_pos_to_bp_safe(const struct bch_fs *c,
|
||||
|
@ -1797,23 +1797,15 @@ err:
|
||||
|
||||
inline bool bch2_btree_iter_advance(struct btree_iter *iter)
|
||||
{
|
||||
if (likely(!(iter->flags & BTREE_ITER_ALL_LEVELS))) {
|
||||
struct bpos pos = iter->k.p;
|
||||
bool ret = !(iter->flags & BTREE_ITER_ALL_SNAPSHOTS
|
||||
? bpos_eq(pos, SPOS_MAX)
|
||||
: bkey_eq(pos, SPOS_MAX));
|
||||
struct bpos pos = iter->k.p;
|
||||
bool ret = !(iter->flags & BTREE_ITER_ALL_SNAPSHOTS
|
||||
? bpos_eq(pos, SPOS_MAX)
|
||||
: bkey_eq(pos, SPOS_MAX));
|
||||
|
||||
if (ret && !(iter->flags & BTREE_ITER_IS_EXTENTS))
|
||||
pos = bkey_successor(iter, pos);
|
||||
bch2_btree_iter_set_pos(iter, pos);
|
||||
return ret;
|
||||
} else {
|
||||
if (!btree_path_node(iter->path, iter->path->level))
|
||||
return true;
|
||||
|
||||
iter->advanced = true;
|
||||
return false;
|
||||
}
|
||||
if (ret && !(iter->flags & BTREE_ITER_IS_EXTENTS))
|
||||
pos = bkey_successor(iter, pos);
|
||||
bch2_btree_iter_set_pos(iter, pos);
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline bool bch2_btree_iter_rewind(struct btree_iter *iter)
|
||||
@ -2064,7 +2056,6 @@ struct bkey_s_c bch2_btree_iter_peek_upto(struct btree_iter *iter, struct bpos e
|
||||
struct bpos iter_pos;
|
||||
int ret;
|
||||
|
||||
EBUG_ON(iter->flags & BTREE_ITER_ALL_LEVELS);
|
||||
EBUG_ON((iter->flags & BTREE_ITER_FILTER_SNAPSHOTS) && bkey_eq(end, POS_MAX));
|
||||
|
||||
if (iter->update_path) {
|
||||
@ -2190,103 +2181,6 @@ end:
|
||||
goto out_no_locked;
|
||||
}
|
||||
|
||||
/**
|
||||
* bch2_btree_iter_peek_all_levels() - returns the first key greater than or
|
||||
* equal to iterator's current position, returning keys from every level of the
|
||||
* btree. For keys at different levels of the btree that compare equal, the key
|
||||
* from the lower level (leaf) is returned first.
|
||||
* @iter: iterator to peek from
|
||||
*
|
||||
* Returns: key if found, or an error extractable with bkey_err().
|
||||
*/
|
||||
struct bkey_s_c bch2_btree_iter_peek_all_levels(struct btree_iter *iter)
|
||||
{
|
||||
struct btree_trans *trans = iter->trans;
|
||||
struct bkey_s_c k;
|
||||
int ret;
|
||||
|
||||
EBUG_ON(iter->path->cached);
|
||||
bch2_btree_iter_verify(iter);
|
||||
BUG_ON(iter->path->level < iter->min_depth);
|
||||
BUG_ON(!(iter->flags & BTREE_ITER_ALL_SNAPSHOTS));
|
||||
EBUG_ON(!(iter->flags & BTREE_ITER_ALL_LEVELS));
|
||||
|
||||
while (1) {
|
||||
iter->path = bch2_btree_path_set_pos(trans, iter->path, iter->pos,
|
||||
iter->flags & BTREE_ITER_INTENT,
|
||||
btree_iter_ip_allocated(iter));
|
||||
|
||||
ret = bch2_btree_path_traverse(trans, iter->path, iter->flags);
|
||||
if (unlikely(ret)) {
|
||||
/* ensure that iter->k is consistent with iter->pos: */
|
||||
bch2_btree_iter_set_pos(iter, iter->pos);
|
||||
k = bkey_s_c_err(ret);
|
||||
goto out_no_locked;
|
||||
}
|
||||
|
||||
/* Already at end? */
|
||||
if (!btree_path_node(iter->path, iter->path->level)) {
|
||||
k = bkey_s_c_null;
|
||||
goto out_no_locked;
|
||||
}
|
||||
|
||||
k = btree_path_level_peek_all(trans->c,
|
||||
&iter->path->l[iter->path->level], &iter->k);
|
||||
|
||||
/* Check if we should go up to the parent node: */
|
||||
if (!k.k ||
|
||||
(iter->advanced &&
|
||||
bpos_eq(path_l(iter->path)->b->key.k.p, iter->pos))) {
|
||||
iter->pos = path_l(iter->path)->b->key.k.p;
|
||||
btree_path_set_level_up(trans, iter->path);
|
||||
iter->advanced = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if we should go back down to a leaf:
|
||||
* If we're not in a leaf node, we only return the current key
|
||||
* if it exactly matches iter->pos - otherwise we first have to
|
||||
* go back to the leaf:
|
||||
*/
|
||||
if (iter->path->level != iter->min_depth &&
|
||||
(iter->advanced ||
|
||||
!k.k ||
|
||||
!bpos_eq(iter->pos, k.k->p))) {
|
||||
btree_path_set_level_down(trans, iter->path, iter->min_depth);
|
||||
iter->pos = bpos_successor(iter->pos);
|
||||
iter->advanced = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check if we should go to the next key: */
|
||||
if (iter->path->level == iter->min_depth &&
|
||||
iter->advanced &&
|
||||
k.k &&
|
||||
bpos_eq(iter->pos, k.k->p)) {
|
||||
iter->pos = bpos_successor(iter->pos);
|
||||
iter->advanced = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (iter->advanced &&
|
||||
iter->path->level == iter->min_depth &&
|
||||
!bpos_eq(k.k->p, iter->pos))
|
||||
iter->advanced = false;
|
||||
|
||||
BUG_ON(iter->advanced);
|
||||
BUG_ON(!k.k);
|
||||
break;
|
||||
}
|
||||
|
||||
iter->pos = k.k->p;
|
||||
btree_path_set_should_be_locked(iter->path);
|
||||
out_no_locked:
|
||||
bch2_btree_iter_verify(iter);
|
||||
|
||||
return k;
|
||||
}
|
||||
|
||||
/**
|
||||
* bch2_btree_iter_next() - returns first key greater than iterator's current
|
||||
* position
|
||||
@ -2453,7 +2347,6 @@ struct bkey_s_c bch2_btree_iter_peek_slot(struct btree_iter *iter)
|
||||
|
||||
bch2_btree_iter_verify(iter);
|
||||
bch2_btree_iter_verify_entry_exit(iter);
|
||||
EBUG_ON(iter->flags & BTREE_ITER_ALL_LEVELS);
|
||||
EBUG_ON(iter->path->level && (iter->flags & BTREE_ITER_WITH_KEY_CACHE));
|
||||
|
||||
/* extents can't span inode numbers: */
|
||||
|
@ -348,8 +348,6 @@ struct btree *bch2_btree_iter_next_node(struct btree_iter *);
|
||||
struct bkey_s_c bch2_btree_iter_peek_upto(struct btree_iter *, struct bpos);
|
||||
struct bkey_s_c bch2_btree_iter_next(struct btree_iter *);
|
||||
|
||||
struct bkey_s_c bch2_btree_iter_peek_all_levels(struct btree_iter *);
|
||||
|
||||
static inline struct bkey_s_c bch2_btree_iter_peek(struct btree_iter *iter)
|
||||
{
|
||||
return bch2_btree_iter_peek_upto(iter, SPOS_MAX);
|
||||
@ -408,9 +406,6 @@ static inline unsigned __bch2_btree_iter_flags(struct btree_trans *trans,
|
||||
unsigned btree_id,
|
||||
unsigned flags)
|
||||
{
|
||||
if (flags & BTREE_ITER_ALL_LEVELS)
|
||||
flags |= BTREE_ITER_ALL_SNAPSHOTS|__BTREE_ITER_ALL_SNAPSHOTS;
|
||||
|
||||
if (!(flags & (BTREE_ITER_ALL_SNAPSHOTS|BTREE_ITER_NOT_EXTENTS)) &&
|
||||
btree_id_is_extents(btree_id))
|
||||
flags |= BTREE_ITER_IS_EXTENTS;
|
||||
@ -606,8 +601,6 @@ u32 bch2_trans_begin(struct btree_trans *);
|
||||
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);
|
||||
}
|
||||
@ -615,8 +608,7 @@ static inline struct bkey_s_c bch2_btree_iter_peek_prev_type(struct btree_iter *
|
||||
static inline struct bkey_s_c bch2_btree_iter_peek_type(struct btree_iter *iter,
|
||||
unsigned flags)
|
||||
{
|
||||
return flags & BTREE_ITER_ALL_LEVELS ? bch2_btree_iter_peek_all_levels(iter) :
|
||||
flags & BTREE_ITER_SLOTS ? bch2_btree_iter_peek_slot(iter) :
|
||||
return flags & BTREE_ITER_SLOTS ? bch2_btree_iter_peek_slot(iter) :
|
||||
bch2_btree_iter_peek(iter);
|
||||
}
|
||||
|
||||
|
@ -664,7 +664,7 @@ void __bch2_btree_path_downgrade(struct btree_trans *trans,
|
||||
struct btree_path *path,
|
||||
unsigned new_locks_want)
|
||||
{
|
||||
unsigned l;
|
||||
unsigned l, old_locks_want = path->locks_want;
|
||||
|
||||
if (trans->restarted)
|
||||
return;
|
||||
@ -689,7 +689,7 @@ void __bch2_btree_path_downgrade(struct btree_trans *trans,
|
||||
bch2_btree_path_verify_locks(path);
|
||||
|
||||
path->downgrade_seq++;
|
||||
trace_path_downgrade(trans, _RET_IP_, path);
|
||||
trace_path_downgrade(trans, _RET_IP_, path, old_locks_want);
|
||||
}
|
||||
|
||||
/* Btree transaction locking: */
|
||||
|
@ -195,33 +195,32 @@ struct btree_node_iter {
|
||||
* Iterate over all possible positions, synthesizing deleted keys for holes:
|
||||
*/
|
||||
static const __maybe_unused u16 BTREE_ITER_SLOTS = 1 << 0;
|
||||
static const __maybe_unused u16 BTREE_ITER_ALL_LEVELS = 1 << 1;
|
||||
/*
|
||||
* Indicates that intent locks should be taken on leaf nodes, because we expect
|
||||
* to be doing updates:
|
||||
*/
|
||||
static const __maybe_unused u16 BTREE_ITER_INTENT = 1 << 2;
|
||||
static const __maybe_unused u16 BTREE_ITER_INTENT = 1 << 1;
|
||||
/*
|
||||
* Causes the btree iterator code to prefetch additional btree nodes from disk:
|
||||
*/
|
||||
static const __maybe_unused u16 BTREE_ITER_PREFETCH = 1 << 3;
|
||||
static const __maybe_unused u16 BTREE_ITER_PREFETCH = 1 << 2;
|
||||
/*
|
||||
* Used in bch2_btree_iter_traverse(), to indicate whether we're searching for
|
||||
* @pos or the first key strictly greater than @pos
|
||||
*/
|
||||
static const __maybe_unused u16 BTREE_ITER_IS_EXTENTS = 1 << 4;
|
||||
static const __maybe_unused u16 BTREE_ITER_NOT_EXTENTS = 1 << 5;
|
||||
static const __maybe_unused u16 BTREE_ITER_CACHED = 1 << 6;
|
||||
static const __maybe_unused u16 BTREE_ITER_WITH_KEY_CACHE = 1 << 7;
|
||||
static const __maybe_unused u16 BTREE_ITER_WITH_UPDATES = 1 << 8;
|
||||
static const __maybe_unused u16 BTREE_ITER_WITH_JOURNAL = 1 << 9;
|
||||
static const __maybe_unused u16 __BTREE_ITER_ALL_SNAPSHOTS = 1 << 10;
|
||||
static const __maybe_unused u16 BTREE_ITER_ALL_SNAPSHOTS = 1 << 11;
|
||||
static const __maybe_unused u16 BTREE_ITER_FILTER_SNAPSHOTS = 1 << 12;
|
||||
static const __maybe_unused u16 BTREE_ITER_NOPRESERVE = 1 << 13;
|
||||
static const __maybe_unused u16 BTREE_ITER_CACHED_NOFILL = 1 << 14;
|
||||
static const __maybe_unused u16 BTREE_ITER_KEY_CACHE_FILL = 1 << 15;
|
||||
#define __BTREE_ITER_FLAGS_END 16
|
||||
static const __maybe_unused u16 BTREE_ITER_IS_EXTENTS = 1 << 3;
|
||||
static const __maybe_unused u16 BTREE_ITER_NOT_EXTENTS = 1 << 4;
|
||||
static const __maybe_unused u16 BTREE_ITER_CACHED = 1 << 5;
|
||||
static const __maybe_unused u16 BTREE_ITER_WITH_KEY_CACHE = 1 << 6;
|
||||
static const __maybe_unused u16 BTREE_ITER_WITH_UPDATES = 1 << 7;
|
||||
static const __maybe_unused u16 BTREE_ITER_WITH_JOURNAL = 1 << 8;
|
||||
static const __maybe_unused u16 __BTREE_ITER_ALL_SNAPSHOTS = 1 << 9;
|
||||
static const __maybe_unused u16 BTREE_ITER_ALL_SNAPSHOTS = 1 << 10;
|
||||
static const __maybe_unused u16 BTREE_ITER_FILTER_SNAPSHOTS = 1 << 11;
|
||||
static const __maybe_unused u16 BTREE_ITER_NOPRESERVE = 1 << 12;
|
||||
static const __maybe_unused u16 BTREE_ITER_CACHED_NOFILL = 1 << 13;
|
||||
static const __maybe_unused u16 BTREE_ITER_KEY_CACHE_FILL = 1 << 14;
|
||||
#define __BTREE_ITER_FLAGS_END 15
|
||||
|
||||
enum btree_path_uptodate {
|
||||
BTREE_ITER_UPTODATE = 0,
|
||||
|
@ -1054,7 +1054,6 @@ bch2_btree_update_start(struct btree_trans *trans, struct btree_path *path,
|
||||
unsigned nr_nodes[2] = { 0, 0 };
|
||||
unsigned update_level = level;
|
||||
enum bch_watermark watermark = flags & BCH_WATERMARK_MASK;
|
||||
unsigned journal_flags = 0;
|
||||
int ret = 0;
|
||||
u32 restart_count = trans->restart_count;
|
||||
|
||||
@ -1068,10 +1067,6 @@ bch2_btree_update_start(struct btree_trans *trans, struct btree_path *path,
|
||||
flags &= ~BCH_WATERMARK_MASK;
|
||||
flags |= watermark;
|
||||
|
||||
if (flags & BCH_TRANS_COMMIT_journal_reclaim)
|
||||
journal_flags |= JOURNAL_RES_GET_NONBLOCK;
|
||||
journal_flags |= watermark;
|
||||
|
||||
while (1) {
|
||||
nr_nodes[!!update_level] += 1 + split;
|
||||
update_level++;
|
||||
|
@ -453,33 +453,35 @@ static long bch2_ioctl_subvolume_create(struct bch_fs *c, struct file *filp,
|
||||
static long bch2_ioctl_subvolume_destroy(struct bch_fs *c, struct file *filp,
|
||||
struct bch_ioctl_subvolume arg)
|
||||
{
|
||||
struct filename *name;
|
||||
struct path path;
|
||||
struct inode *dir;
|
||||
struct dentry *victim;
|
||||
int ret = 0;
|
||||
|
||||
if (arg.flags)
|
||||
return -EINVAL;
|
||||
|
||||
ret = user_path_at(arg.dirfd,
|
||||
(const char __user *)(unsigned long)arg.dst_ptr,
|
||||
LOOKUP_FOLLOW, &path);
|
||||
if (ret)
|
||||
return ret;
|
||||
name = getname((const char __user *)(unsigned long)arg.dst_ptr);
|
||||
victim = filename_path_locked(arg.dirfd, name, &path);
|
||||
putname(name);
|
||||
if (IS_ERR(victim))
|
||||
return PTR_ERR(victim);
|
||||
|
||||
if (path.dentry->d_sb->s_fs_info != c) {
|
||||
if (victim->d_sb->s_fs_info != c) {
|
||||
ret = -EXDEV;
|
||||
goto err;
|
||||
}
|
||||
|
||||
dir = path.dentry->d_parent->d_inode;
|
||||
|
||||
ret = __bch2_unlink(dir, path.dentry, true);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
fsnotify_rmdir(dir, path.dentry);
|
||||
d_delete(path.dentry);
|
||||
dir = d_inode(path.dentry);
|
||||
ret = __bch2_unlink(dir, victim, true);
|
||||
if (!ret) {
|
||||
fsnotify_rmdir(dir, victim);
|
||||
d_delete(victim);
|
||||
}
|
||||
inode_unlock(dir);
|
||||
err:
|
||||
dput(victim);
|
||||
path_put(&path);
|
||||
return ret;
|
||||
}
|
||||
|
@ -1023,25 +1023,6 @@ static bool dirent_points_to_inode(struct bkey_s_c_dirent d,
|
||||
: le64_to_cpu(d.v->d_inum) == inode->bi_inum;
|
||||
}
|
||||
|
||||
static int inode_backpointer_exists(struct btree_trans *trans,
|
||||
struct bch_inode_unpacked *inode,
|
||||
u32 snapshot)
|
||||
{
|
||||
struct btree_iter iter;
|
||||
struct bkey_s_c_dirent d;
|
||||
int ret;
|
||||
|
||||
d = dirent_get_by_pos(trans, &iter,
|
||||
SPOS(inode->bi_dir, inode->bi_dir_offset, snapshot));
|
||||
ret = bkey_err(d);
|
||||
if (ret)
|
||||
return bch2_err_matches(ret, ENOENT) ? 0 : ret;
|
||||
|
||||
ret = dirent_points_to_inode(d, inode);
|
||||
bch2_trans_iter_exit(trans, &iter);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int check_i_sectors(struct btree_trans *trans, struct inode_walker *w)
|
||||
{
|
||||
struct bch_fs *c = trans->c;
|
||||
@ -1553,8 +1534,8 @@ static int check_dirent_target(struct btree_trans *trans,
|
||||
{
|
||||
struct bch_fs *c = trans->c;
|
||||
struct bkey_i_dirent *n;
|
||||
bool backpointer_exists = true;
|
||||
struct printbuf buf = PRINTBUF;
|
||||
struct btree_iter bp_iter = { NULL };
|
||||
int ret = 0;
|
||||
|
||||
if (!target->bi_dir &&
|
||||
@ -1568,25 +1549,37 @@ static int check_dirent_target(struct btree_trans *trans,
|
||||
}
|
||||
|
||||
if (!inode_points_to_dirent(target, d)) {
|
||||
ret = inode_backpointer_exists(trans, target, d.k->p.snapshot);
|
||||
if (ret < 0)
|
||||
struct bkey_s_c_dirent bp_dirent = dirent_get_by_pos(trans, &bp_iter,
|
||||
SPOS(target->bi_dir, target->bi_dir_offset, target_snapshot));
|
||||
ret = bkey_err(bp_dirent);
|
||||
if (ret && !bch2_err_matches(ret, ENOENT))
|
||||
goto err;
|
||||
|
||||
backpointer_exists = ret;
|
||||
bool backpointer_exists = !ret;
|
||||
ret = 0;
|
||||
|
||||
bch2_bkey_val_to_text(&buf, c, d.s_c);
|
||||
prt_newline(&buf);
|
||||
if (backpointer_exists)
|
||||
bch2_bkey_val_to_text(&buf, c, bp_dirent.s_c);
|
||||
|
||||
if (fsck_err_on(S_ISDIR(target->bi_mode) && backpointer_exists,
|
||||
c, inode_dir_multiple_links,
|
||||
"directory %llu with multiple links",
|
||||
target->bi_inum)) {
|
||||
"directory %llu:%u with multiple links\n%s",
|
||||
target->bi_inum, target_snapshot, buf.buf)) {
|
||||
ret = __remove_dirent(trans, d.k->p);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* hardlinked file with nlink 0:
|
||||
* We're just adjusting nlink here so check_nlinks() will pick
|
||||
* it up, it ignores inodes with nlink 0
|
||||
*/
|
||||
if (fsck_err_on(backpointer_exists && !target->bi_nlink,
|
||||
c, inode_multiple_links_but_nlink_0,
|
||||
"inode %llu type %s has multiple links but i_nlink 0",
|
||||
target->bi_inum, bch2_d_types[d.v->d_type])) {
|
||||
"inode %llu:%u type %s has multiple links but i_nlink 0\n%s",
|
||||
target->bi_inum, target_snapshot, bch2_d_types[d.v->d_type], buf.buf)) {
|
||||
target->bi_nlink++;
|
||||
target->bi_flags &= ~BCH_INODE_unlinked;
|
||||
|
||||
@ -1660,6 +1653,7 @@ static int check_dirent_target(struct btree_trans *trans,
|
||||
out:
|
||||
err:
|
||||
fsck_err:
|
||||
bch2_trans_iter_exit(trans, &bp_iter);
|
||||
printbuf_exit(&buf);
|
||||
bch_err_fn(c, ret);
|
||||
return ret;
|
||||
@ -2220,7 +2214,7 @@ static int nlink_cmp(const void *_l, const void *_r)
|
||||
const struct nlink *l = _l;
|
||||
const struct nlink *r = _r;
|
||||
|
||||
return cmp_int(l->inum, r->inum) ?: cmp_int(l->snapshot, r->snapshot);
|
||||
return cmp_int(l->inum, r->inum);
|
||||
}
|
||||
|
||||
static void inc_link(struct bch_fs *c, struct snapshots_seen *s,
|
||||
@ -2401,7 +2395,7 @@ static int check_nlinks_update_hardlinks(struct bch_fs *c,
|
||||
NULL, NULL, BCH_TRANS_COMMIT_lazy_rw|BCH_TRANS_COMMIT_no_enospc,
|
||||
check_nlinks_update_inode(trans, &iter, k, links, &idx, range_end)));
|
||||
if (ret < 0) {
|
||||
bch_err(c, "error in fsck: btree error %i while walking inodes", ret);
|
||||
bch_err(c, "error in fsck walking inodes: %s", bch2_err_str(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1124,10 +1124,7 @@ static int may_delete_deleted_inode(struct btree_trans *trans,
|
||||
inode.bi_flags &= ~BCH_INODE_unlinked;
|
||||
|
||||
ret = bch2_inode_write_flags(trans, &inode_iter, &inode,
|
||||
BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE) ?:
|
||||
bch2_trans_commit(trans, NULL, NULL,
|
||||
BCH_TRANS_COMMIT_no_enospc|
|
||||
BCH_TRANS_COMMIT_lazy_rw);
|
||||
BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE);
|
||||
bch_err_msg(c, ret, "clearing inode unlinked flag");
|
||||
if (ret)
|
||||
goto out;
|
||||
@ -1172,8 +1169,10 @@ again:
|
||||
*/
|
||||
for_each_btree_key(trans, iter, BTREE_ID_deleted_inodes, POS_MIN,
|
||||
BTREE_ITER_PREFETCH|BTREE_ITER_ALL_SNAPSHOTS, k, ret) {
|
||||
ret = lockrestart_do(trans, may_delete_deleted_inode(trans, &iter, k.k->p,
|
||||
&need_another_pass));
|
||||
ret = commit_do(trans, NULL, NULL,
|
||||
BCH_TRANS_COMMIT_no_enospc|
|
||||
BCH_TRANS_COMMIT_lazy_rw,
|
||||
may_delete_deleted_inode(trans, &iter, k.k->p, &need_another_pass));
|
||||
if (ret < 0)
|
||||
break;
|
||||
|
||||
|
@ -795,7 +795,7 @@ static int bch2_write_decrypt(struct bch_write_op *op)
|
||||
* checksum:
|
||||
*/
|
||||
csum = bch2_checksum_bio(c, op->crc.csum_type, nonce, &op->wbio.bio);
|
||||
if (bch2_crc_cmp(op->crc.csum, csum))
|
||||
if (bch2_crc_cmp(op->crc.csum, csum) && !c->opts.no_data_io)
|
||||
return -EIO;
|
||||
|
||||
ret = bch2_encrypt_bio(c, op->crc.csum_type, nonce, &op->wbio.bio);
|
||||
|
@ -161,8 +161,8 @@ static int bch2_journal_replay(struct bch_fs *c)
|
||||
|
||||
/*
|
||||
* First, attempt to replay keys in sorted order. This is more
|
||||
* efficient, but some might fail if that would cause a journal
|
||||
* deadlock.
|
||||
* efficient - better locality of btree access - but some might fail if
|
||||
* that would cause a journal deadlock.
|
||||
*/
|
||||
for (size_t i = 0; i < keys->nr; i++) {
|
||||
cond_resched();
|
||||
@ -211,6 +211,10 @@ static int bch2_journal_replay(struct bch_fs *c)
|
||||
BUG_ON(!k->overwritten);
|
||||
}
|
||||
|
||||
/*
|
||||
* We need to put our btree_trans before calling flush_all_pins(), since
|
||||
* that will use a btree_trans internally
|
||||
*/
|
||||
bch2_trans_put(trans);
|
||||
trans = NULL;
|
||||
|
||||
@ -874,6 +878,8 @@ use_clean:
|
||||
test_bit(BCH_FS_ERRORS_FIXED, &c->flags) &&
|
||||
!test_bit(BCH_FS_ERRORS_NOT_FIXED, &c->flags) &&
|
||||
!test_bit(BCH_FS_ERROR, &c->flags)) {
|
||||
bch2_flush_fsck_errs(c);
|
||||
|
||||
bch_info(c, "Fixed errors, running fsck a second time to verify fs is clean");
|
||||
clear_bit(BCH_FS_ERRORS_FIXED, &c->flags);
|
||||
|
||||
|
@ -163,8 +163,11 @@ static int __do_six_trylock(struct six_lock *lock, enum six_lock_type type,
|
||||
this_cpu_sub(*lock->readers, !ret);
|
||||
preempt_enable();
|
||||
|
||||
if (!ret && (old & SIX_LOCK_WAITING_write))
|
||||
ret = -1 - SIX_LOCK_write;
|
||||
if (!ret) {
|
||||
smp_mb();
|
||||
if (atomic_read(&lock->state) & SIX_LOCK_WAITING_write)
|
||||
ret = -1 - SIX_LOCK_write;
|
||||
}
|
||||
} else if (type == SIX_LOCK_write && lock->readers) {
|
||||
if (try) {
|
||||
atomic_add(SIX_LOCK_HELD_write, &lock->state);
|
||||
|
@ -1252,22 +1252,37 @@ TRACE_EVENT(trans_restart_key_cache_key_realloced,
|
||||
TRACE_EVENT(path_downgrade,
|
||||
TP_PROTO(struct btree_trans *trans,
|
||||
unsigned long caller_ip,
|
||||
struct btree_path *path),
|
||||
TP_ARGS(trans, caller_ip, path),
|
||||
struct btree_path *path,
|
||||
unsigned old_locks_want),
|
||||
TP_ARGS(trans, caller_ip, path, old_locks_want),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__array(char, trans_fn, 32 )
|
||||
__field(unsigned long, caller_ip )
|
||||
__field(unsigned, old_locks_want )
|
||||
__field(unsigned, new_locks_want )
|
||||
__field(unsigned, btree )
|
||||
TRACE_BPOS_entries(pos)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
strscpy(__entry->trans_fn, trans->fn, sizeof(__entry->trans_fn));
|
||||
__entry->caller_ip = caller_ip;
|
||||
__entry->old_locks_want = old_locks_want;
|
||||
__entry->new_locks_want = path->locks_want;
|
||||
__entry->btree = path->btree_id;
|
||||
TRACE_BPOS_assign(pos, path->pos);
|
||||
),
|
||||
|
||||
TP_printk("%s %pS",
|
||||
TP_printk("%s %pS locks_want %u -> %u %s %llu:%llu:%u",
|
||||
__entry->trans_fn,
|
||||
(void *) __entry->caller_ip)
|
||||
(void *) __entry->caller_ip,
|
||||
__entry->old_locks_want,
|
||||
__entry->new_locks_want,
|
||||
bch2_btree_id_str(__entry->btree),
|
||||
__entry->pos_inode,
|
||||
__entry->pos_offset,
|
||||
__entry->pos_snapshot)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(transaction_event, trans_restart_write_buffer_flush,
|
||||
|
@ -322,6 +322,7 @@ void bch2_prt_datetime(struct printbuf *out, time64_t sec)
|
||||
time_t t = sec;
|
||||
char buf[64];
|
||||
ctime_r(&t, buf);
|
||||
strim(buf);
|
||||
prt_str(out, buf);
|
||||
}
|
||||
#else
|
||||
|
@ -552,6 +552,14 @@ static int bch2_xattr_bcachefs_set(const struct xattr_handler *handler,
|
||||
s.v = v + 1;
|
||||
s.defined = true;
|
||||
} else {
|
||||
/*
|
||||
* Check if this option was set on the parent - if so, switched
|
||||
* back to inheriting from the parent:
|
||||
*
|
||||
* rename() also has to deal with keeping inherited options up
|
||||
* to date - see bch2_reinherit_attrs()
|
||||
*/
|
||||
spin_lock(&dentry->d_lock);
|
||||
if (!IS_ROOT(dentry)) {
|
||||
struct bch_inode_info *dir =
|
||||
to_bch_ei(d_inode(dentry->d_parent));
|
||||
@ -560,6 +568,7 @@ static int bch2_xattr_bcachefs_set(const struct xattr_handler *handler,
|
||||
} else {
|
||||
s.v = 0;
|
||||
}
|
||||
spin_unlock(&dentry->d_lock);
|
||||
|
||||
s.defined = false;
|
||||
}
|
||||
|
@ -32,7 +32,6 @@ impl<'f> Drop for BtreeTrans<'f> {
|
||||
bitflags! {
|
||||
pub struct BtreeIterFlags: u16 {
|
||||
const SLOTS = c::BTREE_ITER_SLOTS as u16;
|
||||
const ALL_LEVELS = c::BTREE_ITER_ALL_LEVELS as u16;
|
||||
const INTENT = c::BTREE_ITER_INTENT as u16;
|
||||
const PREFETCH = c::BTREE_ITER_PREFETCH as u16;
|
||||
const IS_EXTENTS = c::BTREE_ITER_IS_EXTENTS as u16;
|
||||
|
Loading…
Reference in New Issue
Block a user