Update bcachefs sources to 938f680845d1 fixup! rename and export __kern_path_locked()

This commit is contained in:
Kent Overstreet 2023-11-16 15:47:11 -05:00
parent 9776f9f362
commit 689b4dd4f0
17 changed files with 162 additions and 267 deletions

View File

@ -1 +1 @@
3ca08ab51ec996180c20105489176b8c4327240c 938f680845d1be28979e23aee972dba010c464ba

View File

@ -457,25 +457,18 @@ missing:
} }
static int check_extent_to_backpointers(struct btree_trans *trans, 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_start,
struct bpos bucket_end, 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 bch_fs *c = trans->c;
struct bkey_ptrs_c ptrs; struct bkey_ptrs_c ptrs;
const union bch_extent_entry *entry; const union bch_extent_entry *entry;
struct extent_ptr_decoded p; struct extent_ptr_decoded p;
struct bkey_s_c k;
int ret; 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); ptrs = bch2_bkey_ptrs_c(k);
bkey_for_each_ptr_decode(k.k, ptrs, p, entry) { bkey_for_each_ptr_decode(k.k, ptrs, p, entry) {
struct bpos bucket_pos; struct bpos bucket_pos;
@ -484,7 +477,7 @@ static int check_extent_to_backpointers(struct btree_trans *trans,
if (p.ptr.cached) if (p.ptr.cached)
continue; 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); k, p, &bucket_pos, &bp);
ret = check_bp_exists(trans, bucket_pos, bp, k, 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, enum btree_id btree_id,
struct bpos bucket_start, struct bpos bucket_start,
struct bpos bucket_end, struct bpos bucket_end,
struct bpos_level *last_flushed) struct bpos_level *last_flushed,
int *level)
{ {
struct bch_fs *c = trans->c; struct bch_fs *c = trans->c;
struct btree_root *r = bch2_btree_id_root(c, btree_id);
struct btree_iter iter; struct btree_iter iter;
struct btree *b; struct btree *b;
struct bkey_s_c k; struct bkey_s_c k;
struct bkey_ptrs_c ptrs;
struct extent_ptr_decoded p;
const union bch_extent_entry *entry;
int ret; int ret;
retry:
bch2_trans_node_iter_init(trans, &iter, btree_id, POS_MIN, 0, r->level, 0); 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); b = bch2_btree_iter_peek_node(&iter);
ret = PTR_ERR_OR_ZERO(b); ret = PTR_ERR_OR_ZERO(b);
if (ret) if (ret)
goto err; 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); k = bkey_i_to_s_c(&b->key);
ptrs = bch2_bkey_ptrs_c(k); ret = check_extent_to_backpointers(trans, btree_id, b->c.level + 1,
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,
bucket_start, bucket_end, bucket_start, bucket_end,
last_flushed); last_flushed, k);
if (ret)
goto err;
}
err: err:
bch2_trans_iter_exit(trans, &iter); bch2_trans_iter_exit(trans, &iter);
return ret; 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 bch_fs *c = trans->c;
struct btree_iter iter; struct btree_iter iter;
enum btree_id btree_id; enum btree_id btree_id;
struct bkey_s_c k;
struct bpos_level last_flushed = { UINT_MAX, POS_MIN }; struct bpos_level last_flushed = { UINT_MAX, POS_MIN };
int ret = 0; int ret = 0;
for (btree_id = 0; btree_id < btree_id_nr_alive(c); btree_id++) { for (btree_id = 0; btree_id < btree_id_nr_alive(c); btree_id++) {
unsigned depth = btree_type_has_ptrs(btree_id) ? 0 : 1; int level, 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;
ret = commit_do(trans, NULL, NULL, ret = commit_do(trans, NULL, NULL,
BCH_TRANS_COMMIT_lazy_rw| BCH_TRANS_COMMIT_lazy_rw|
BCH_TRANS_COMMIT_no_enospc, BCH_TRANS_COMMIT_no_enospc,
check_btree_root_to_backpointers(trans, btree_id, check_btree_root_to_backpointers(trans, btree_id,
bucket_start, bucket_end, bucket_start, bucket_end,
&last_flushed)); &last_flushed, &level));
if (ret) 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, static struct bpos bucket_pos_to_bp_safe(const struct bch_fs *c,

View File

@ -1797,23 +1797,15 @@ err:
inline bool bch2_btree_iter_advance(struct btree_iter *iter) inline bool bch2_btree_iter_advance(struct btree_iter *iter)
{ {
if (likely(!(iter->flags & BTREE_ITER_ALL_LEVELS))) { struct bpos pos = iter->k.p;
struct bpos pos = iter->k.p; bool ret = !(iter->flags & BTREE_ITER_ALL_SNAPSHOTS
bool ret = !(iter->flags & BTREE_ITER_ALL_SNAPSHOTS ? bpos_eq(pos, SPOS_MAX)
? bpos_eq(pos, SPOS_MAX) : bkey_eq(pos, SPOS_MAX));
: bkey_eq(pos, SPOS_MAX));
if (ret && !(iter->flags & BTREE_ITER_IS_EXTENTS)) if (ret && !(iter->flags & BTREE_ITER_IS_EXTENTS))
pos = bkey_successor(iter, pos); pos = bkey_successor(iter, pos);
bch2_btree_iter_set_pos(iter, pos); bch2_btree_iter_set_pos(iter, pos);
return ret; return ret;
} else {
if (!btree_path_node(iter->path, iter->path->level))
return true;
iter->advanced = true;
return false;
}
} }
inline bool bch2_btree_iter_rewind(struct btree_iter *iter) 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; struct bpos iter_pos;
int ret; int ret;
EBUG_ON(iter->flags & BTREE_ITER_ALL_LEVELS);
EBUG_ON((iter->flags & BTREE_ITER_FILTER_SNAPSHOTS) && bkey_eq(end, POS_MAX)); EBUG_ON((iter->flags & BTREE_ITER_FILTER_SNAPSHOTS) && bkey_eq(end, POS_MAX));
if (iter->update_path) { if (iter->update_path) {
@ -2190,103 +2181,6 @@ end:
goto out_no_locked; 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 * bch2_btree_iter_next() - returns first key greater than iterator's current
* position * 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(iter);
bch2_btree_iter_verify_entry_exit(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)); EBUG_ON(iter->path->level && (iter->flags & BTREE_ITER_WITH_KEY_CACHE));
/* extents can't span inode numbers: */ /* extents can't span inode numbers: */

View File

@ -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_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_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) static inline struct bkey_s_c bch2_btree_iter_peek(struct btree_iter *iter)
{ {
return bch2_btree_iter_peek_upto(iter, SPOS_MAX); 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 btree_id,
unsigned flags) 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)) && if (!(flags & (BTREE_ITER_ALL_SNAPSHOTS|BTREE_ITER_NOT_EXTENTS)) &&
btree_id_is_extents(btree_id)) btree_id_is_extents(btree_id))
flags |= BTREE_ITER_IS_EXTENTS; 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, static inline struct bkey_s_c bch2_btree_iter_peek_prev_type(struct btree_iter *iter,
unsigned flags) unsigned flags)
{ {
BUG_ON(flags & BTREE_ITER_ALL_LEVELS);
return 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_prev(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, static inline struct bkey_s_c bch2_btree_iter_peek_type(struct btree_iter *iter,
unsigned flags) unsigned flags)
{ {
return flags & BTREE_ITER_ALL_LEVELS ? bch2_btree_iter_peek_all_levels(iter) : return flags & BTREE_ITER_SLOTS ? bch2_btree_iter_peek_slot(iter) :
flags & BTREE_ITER_SLOTS ? bch2_btree_iter_peek_slot(iter) :
bch2_btree_iter_peek(iter); bch2_btree_iter_peek(iter);
} }

View File

@ -664,7 +664,7 @@ void __bch2_btree_path_downgrade(struct btree_trans *trans,
struct btree_path *path, struct btree_path *path,
unsigned new_locks_want) unsigned new_locks_want)
{ {
unsigned l; unsigned l, old_locks_want = path->locks_want;
if (trans->restarted) if (trans->restarted)
return; return;
@ -689,7 +689,7 @@ void __bch2_btree_path_downgrade(struct btree_trans *trans,
bch2_btree_path_verify_locks(path); bch2_btree_path_verify_locks(path);
path->downgrade_seq++; path->downgrade_seq++;
trace_path_downgrade(trans, _RET_IP_, path); trace_path_downgrade(trans, _RET_IP_, path, old_locks_want);
} }
/* Btree transaction locking: */ /* Btree transaction locking: */

View File

@ -195,33 +195,32 @@ struct btree_node_iter {
* Iterate over all possible positions, synthesizing deleted keys for holes: * 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_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 * Indicates that intent locks should be taken on leaf nodes, because we expect
* to be doing updates: * 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: * 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 * Used in bch2_btree_iter_traverse(), to indicate whether we're searching for
* @pos or the first key strictly greater than @pos * @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_IS_EXTENTS = 1 << 3;
static const __maybe_unused u16 BTREE_ITER_NOT_EXTENTS = 1 << 5; static const __maybe_unused u16 BTREE_ITER_NOT_EXTENTS = 1 << 4;
static const __maybe_unused u16 BTREE_ITER_CACHED = 1 << 6; static const __maybe_unused u16 BTREE_ITER_CACHED = 1 << 5;
static const __maybe_unused u16 BTREE_ITER_WITH_KEY_CACHE = 1 << 7; static const __maybe_unused u16 BTREE_ITER_WITH_KEY_CACHE = 1 << 6;
static const __maybe_unused u16 BTREE_ITER_WITH_UPDATES = 1 << 8; static const __maybe_unused u16 BTREE_ITER_WITH_UPDATES = 1 << 7;
static const __maybe_unused u16 BTREE_ITER_WITH_JOURNAL = 1 << 9; static const __maybe_unused u16 BTREE_ITER_WITH_JOURNAL = 1 << 8;
static const __maybe_unused u16 __BTREE_ITER_ALL_SNAPSHOTS = 1 << 10; static const __maybe_unused u16 __BTREE_ITER_ALL_SNAPSHOTS = 1 << 9;
static const __maybe_unused u16 BTREE_ITER_ALL_SNAPSHOTS = 1 << 11; static const __maybe_unused u16 BTREE_ITER_ALL_SNAPSHOTS = 1 << 10;
static const __maybe_unused u16 BTREE_ITER_FILTER_SNAPSHOTS = 1 << 12; static const __maybe_unused u16 BTREE_ITER_FILTER_SNAPSHOTS = 1 << 11;
static const __maybe_unused u16 BTREE_ITER_NOPRESERVE = 1 << 13; static const __maybe_unused u16 BTREE_ITER_NOPRESERVE = 1 << 12;
static const __maybe_unused u16 BTREE_ITER_CACHED_NOFILL = 1 << 14; static const __maybe_unused u16 BTREE_ITER_CACHED_NOFILL = 1 << 13;
static const __maybe_unused u16 BTREE_ITER_KEY_CACHE_FILL = 1 << 15; static const __maybe_unused u16 BTREE_ITER_KEY_CACHE_FILL = 1 << 14;
#define __BTREE_ITER_FLAGS_END 16 #define __BTREE_ITER_FLAGS_END 15
enum btree_path_uptodate { enum btree_path_uptodate {
BTREE_ITER_UPTODATE = 0, BTREE_ITER_UPTODATE = 0,

View File

@ -1054,7 +1054,6 @@ bch2_btree_update_start(struct btree_trans *trans, struct btree_path *path,
unsigned nr_nodes[2] = { 0, 0 }; unsigned nr_nodes[2] = { 0, 0 };
unsigned update_level = level; unsigned update_level = level;
enum bch_watermark watermark = flags & BCH_WATERMARK_MASK; enum bch_watermark watermark = flags & BCH_WATERMARK_MASK;
unsigned journal_flags = 0;
int ret = 0; int ret = 0;
u32 restart_count = trans->restart_count; 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 &= ~BCH_WATERMARK_MASK;
flags |= watermark; flags |= watermark;
if (flags & BCH_TRANS_COMMIT_journal_reclaim)
journal_flags |= JOURNAL_RES_GET_NONBLOCK;
journal_flags |= watermark;
while (1) { while (1) {
nr_nodes[!!update_level] += 1 + split; nr_nodes[!!update_level] += 1 + split;
update_level++; update_level++;

View File

@ -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, static long bch2_ioctl_subvolume_destroy(struct bch_fs *c, struct file *filp,
struct bch_ioctl_subvolume arg) struct bch_ioctl_subvolume arg)
{ {
struct filename *name;
struct path path; struct path path;
struct inode *dir; struct inode *dir;
struct dentry *victim;
int ret = 0; int ret = 0;
if (arg.flags) if (arg.flags)
return -EINVAL; return -EINVAL;
ret = user_path_at(arg.dirfd, name = getname((const char __user *)(unsigned long)arg.dst_ptr);
(const char __user *)(unsigned long)arg.dst_ptr, victim = filename_path_locked(arg.dirfd, name, &path);
LOOKUP_FOLLOW, &path); putname(name);
if (ret) if (IS_ERR(victim))
return ret; return PTR_ERR(victim);
if (path.dentry->d_sb->s_fs_info != c) { if (victim->d_sb->s_fs_info != c) {
ret = -EXDEV; ret = -EXDEV;
goto err; goto err;
} }
dir = path.dentry->d_parent->d_inode; dir = d_inode(path.dentry);
ret = __bch2_unlink(dir, victim, true);
ret = __bch2_unlink(dir, path.dentry, true); if (!ret) {
if (ret) fsnotify_rmdir(dir, victim);
goto err; d_delete(victim);
}
fsnotify_rmdir(dir, path.dentry); inode_unlock(dir);
d_delete(path.dentry);
err: err:
dput(victim);
path_put(&path); path_put(&path);
return ret; return ret;
} }

View File

@ -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; : 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) static int check_i_sectors(struct btree_trans *trans, struct inode_walker *w)
{ {
struct bch_fs *c = trans->c; 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 bch_fs *c = trans->c;
struct bkey_i_dirent *n; struct bkey_i_dirent *n;
bool backpointer_exists = true;
struct printbuf buf = PRINTBUF; struct printbuf buf = PRINTBUF;
struct btree_iter bp_iter = { NULL };
int ret = 0; int ret = 0;
if (!target->bi_dir && if (!target->bi_dir &&
@ -1568,25 +1549,37 @@ static int check_dirent_target(struct btree_trans *trans,
} }
if (!inode_points_to_dirent(target, d)) { if (!inode_points_to_dirent(target, d)) {
ret = inode_backpointer_exists(trans, target, d.k->p.snapshot); struct bkey_s_c_dirent bp_dirent = dirent_get_by_pos(trans, &bp_iter,
if (ret < 0) SPOS(target->bi_dir, target->bi_dir_offset, target_snapshot));
ret = bkey_err(bp_dirent);
if (ret && !bch2_err_matches(ret, ENOENT))
goto err; goto err;
backpointer_exists = ret; bool backpointer_exists = !ret;
ret = 0; 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, if (fsck_err_on(S_ISDIR(target->bi_mode) && backpointer_exists,
c, inode_dir_multiple_links, c, inode_dir_multiple_links,
"directory %llu with multiple links", "directory %llu:%u with multiple links\n%s",
target->bi_inum)) { target->bi_inum, target_snapshot, buf.buf)) {
ret = __remove_dirent(trans, d.k->p); ret = __remove_dirent(trans, d.k->p);
goto out; 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, if (fsck_err_on(backpointer_exists && !target->bi_nlink,
c, inode_multiple_links_but_nlink_0, c, inode_multiple_links_but_nlink_0,
"inode %llu type %s has multiple links but i_nlink 0", "inode %llu:%u type %s has multiple links but i_nlink 0\n%s",
target->bi_inum, bch2_d_types[d.v->d_type])) { target->bi_inum, target_snapshot, bch2_d_types[d.v->d_type], buf.buf)) {
target->bi_nlink++; target->bi_nlink++;
target->bi_flags &= ~BCH_INODE_unlinked; target->bi_flags &= ~BCH_INODE_unlinked;
@ -1660,6 +1653,7 @@ static int check_dirent_target(struct btree_trans *trans,
out: out:
err: err:
fsck_err: fsck_err:
bch2_trans_iter_exit(trans, &bp_iter);
printbuf_exit(&buf); printbuf_exit(&buf);
bch_err_fn(c, ret); bch_err_fn(c, ret);
return 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 *l = _l;
const struct nlink *r = _r; 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, 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, NULL, NULL, BCH_TRANS_COMMIT_lazy_rw|BCH_TRANS_COMMIT_no_enospc,
check_nlinks_update_inode(trans, &iter, k, links, &idx, range_end))); check_nlinks_update_inode(trans, &iter, k, links, &idx, range_end)));
if (ret < 0) { 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; return ret;
} }

View File

@ -1124,10 +1124,7 @@ static int may_delete_deleted_inode(struct btree_trans *trans,
inode.bi_flags &= ~BCH_INODE_unlinked; inode.bi_flags &= ~BCH_INODE_unlinked;
ret = bch2_inode_write_flags(trans, &inode_iter, &inode, ret = bch2_inode_write_flags(trans, &inode_iter, &inode,
BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE) ?: BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE);
bch2_trans_commit(trans, NULL, NULL,
BCH_TRANS_COMMIT_no_enospc|
BCH_TRANS_COMMIT_lazy_rw);
bch_err_msg(c, ret, "clearing inode unlinked flag"); bch_err_msg(c, ret, "clearing inode unlinked flag");
if (ret) if (ret)
goto out; goto out;
@ -1172,8 +1169,10 @@ again:
*/ */
for_each_btree_key(trans, iter, BTREE_ID_deleted_inodes, POS_MIN, for_each_btree_key(trans, iter, BTREE_ID_deleted_inodes, POS_MIN,
BTREE_ITER_PREFETCH|BTREE_ITER_ALL_SNAPSHOTS, k, ret) { BTREE_ITER_PREFETCH|BTREE_ITER_ALL_SNAPSHOTS, k, ret) {
ret = lockrestart_do(trans, may_delete_deleted_inode(trans, &iter, k.k->p, ret = commit_do(trans, NULL, NULL,
&need_another_pass)); 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) if (ret < 0)
break; break;

View File

@ -795,7 +795,7 @@ static int bch2_write_decrypt(struct bch_write_op *op)
* checksum: * checksum:
*/ */
csum = bch2_checksum_bio(c, op->crc.csum_type, nonce, &op->wbio.bio); 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; return -EIO;
ret = bch2_encrypt_bio(c, op->crc.csum_type, nonce, &op->wbio.bio); ret = bch2_encrypt_bio(c, op->crc.csum_type, nonce, &op->wbio.bio);

View File

@ -161,8 +161,8 @@ static int bch2_journal_replay(struct bch_fs *c)
/* /*
* First, attempt to replay keys in sorted order. This is more * First, attempt to replay keys in sorted order. This is more
* efficient, but some might fail if that would cause a journal * efficient - better locality of btree access - but some might fail if
* deadlock. * that would cause a journal deadlock.
*/ */
for (size_t i = 0; i < keys->nr; i++) { for (size_t i = 0; i < keys->nr; i++) {
cond_resched(); cond_resched();
@ -211,6 +211,10 @@ static int bch2_journal_replay(struct bch_fs *c)
BUG_ON(!k->overwritten); 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); bch2_trans_put(trans);
trans = NULL; trans = NULL;
@ -874,6 +878,8 @@ use_clean:
test_bit(BCH_FS_ERRORS_FIXED, &c->flags) && test_bit(BCH_FS_ERRORS_FIXED, &c->flags) &&
!test_bit(BCH_FS_ERRORS_NOT_FIXED, &c->flags) && !test_bit(BCH_FS_ERRORS_NOT_FIXED, &c->flags) &&
!test_bit(BCH_FS_ERROR, &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"); bch_info(c, "Fixed errors, running fsck a second time to verify fs is clean");
clear_bit(BCH_FS_ERRORS_FIXED, &c->flags); clear_bit(BCH_FS_ERRORS_FIXED, &c->flags);

View File

@ -163,8 +163,11 @@ static int __do_six_trylock(struct six_lock *lock, enum six_lock_type type,
this_cpu_sub(*lock->readers, !ret); this_cpu_sub(*lock->readers, !ret);
preempt_enable(); preempt_enable();
if (!ret && (old & SIX_LOCK_WAITING_write)) if (!ret) {
ret = -1 - SIX_LOCK_write; smp_mb();
if (atomic_read(&lock->state) & SIX_LOCK_WAITING_write)
ret = -1 - SIX_LOCK_write;
}
} else if (type == SIX_LOCK_write && lock->readers) { } else if (type == SIX_LOCK_write && lock->readers) {
if (try) { if (try) {
atomic_add(SIX_LOCK_HELD_write, &lock->state); atomic_add(SIX_LOCK_HELD_write, &lock->state);

View File

@ -1252,22 +1252,37 @@ TRACE_EVENT(trans_restart_key_cache_key_realloced,
TRACE_EVENT(path_downgrade, TRACE_EVENT(path_downgrade,
TP_PROTO(struct btree_trans *trans, TP_PROTO(struct btree_trans *trans,
unsigned long caller_ip, unsigned long caller_ip,
struct btree_path *path), struct btree_path *path,
TP_ARGS(trans, caller_ip, path), unsigned old_locks_want),
TP_ARGS(trans, caller_ip, path, old_locks_want),
TP_STRUCT__entry( TP_STRUCT__entry(
__array(char, trans_fn, 32 ) __array(char, trans_fn, 32 )
__field(unsigned long, caller_ip ) __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( TP_fast_assign(
strscpy(__entry->trans_fn, trans->fn, sizeof(__entry->trans_fn)); strscpy(__entry->trans_fn, trans->fn, sizeof(__entry->trans_fn));
__entry->caller_ip = caller_ip; __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, __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, DEFINE_EVENT(transaction_event, trans_restart_write_buffer_flush,

View File

@ -322,6 +322,7 @@ void bch2_prt_datetime(struct printbuf *out, time64_t sec)
time_t t = sec; time_t t = sec;
char buf[64]; char buf[64];
ctime_r(&t, buf); ctime_r(&t, buf);
strim(buf);
prt_str(out, buf); prt_str(out, buf);
} }
#else #else

View File

@ -552,6 +552,14 @@ static int bch2_xattr_bcachefs_set(const struct xattr_handler *handler,
s.v = v + 1; s.v = v + 1;
s.defined = true; s.defined = true;
} else { } 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)) { if (!IS_ROOT(dentry)) {
struct bch_inode_info *dir = struct bch_inode_info *dir =
to_bch_ei(d_inode(dentry->d_parent)); to_bch_ei(d_inode(dentry->d_parent));
@ -560,6 +568,7 @@ static int bch2_xattr_bcachefs_set(const struct xattr_handler *handler,
} else { } else {
s.v = 0; s.v = 0;
} }
spin_unlock(&dentry->d_lock);
s.defined = false; s.defined = false;
} }

View File

@ -32,7 +32,6 @@ impl<'f> Drop for BtreeTrans<'f> {
bitflags! { bitflags! {
pub struct BtreeIterFlags: u16 { pub struct BtreeIterFlags: u16 {
const SLOTS = c::BTREE_ITER_SLOTS as 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 INTENT = c::BTREE_ITER_INTENT as u16;
const PREFETCH = c::BTREE_ITER_PREFETCH as u16; const PREFETCH = c::BTREE_ITER_PREFETCH as u16;
const IS_EXTENTS = c::BTREE_ITER_IS_EXTENTS as u16; const IS_EXTENTS = c::BTREE_ITER_IS_EXTENTS as u16;