From a2b02395933ea8da3121b1c76d9774b8585d1313 Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Thu, 21 Oct 2021 13:09:39 -0400 Subject: [PATCH] Update bcachefs sources to 718df3f7c2 bcachefs: Fix restart handling in for_each_btree_key() --- .bcachefs_revision | 2 +- libbcachefs/bcachefs_format.h | 2 - libbcachefs/btree_iter.c | 14 +--- libbcachefs/btree_iter.h | 134 ++++++++++++++++++++------------ libbcachefs/btree_update_leaf.c | 2 +- libbcachefs/dirent.c | 4 +- libbcachefs/extent_update.c | 4 +- libbcachefs/fs-io.c | 8 +- libbcachefs/fs-ioctl.c | 9 ++- libbcachefs/fsck.c | 64 ++++++++++----- libbcachefs/io.c | 3 +- libbcachefs/reflink.c | 4 +- libbcachefs/replicas.c | 3 + libbcachefs/str_hash.h | 8 +- libbcachefs/xattr.c | 2 +- 15 files changed, 158 insertions(+), 105 deletions(-) diff --git a/.bcachefs_revision b/.bcachefs_revision index 43da7f3f..9cb57dcd 100644 --- a/.bcachefs_revision +++ b/.bcachefs_revision @@ -1 +1 @@ -4dd9a5a488857137ce6eecadddd9304440fb03e9 +718df3f7c266f8385fa8bef9ce4c5e9266aa8970 diff --git a/libbcachefs/bcachefs_format.h b/libbcachefs/bcachefs_format.h index e268125b..296166fa 100644 --- a/libbcachefs/bcachefs_format.h +++ b/libbcachefs/bcachefs_format.h @@ -1037,8 +1037,6 @@ LE64_BITMASK(BCH_MEMBER_DATA_ALLOWED, struct bch_member, flags[0], 15, 20) LE64_BITMASK(BCH_MEMBER_GROUP, struct bch_member, flags[0], 20, 28) LE64_BITMASK(BCH_MEMBER_DURABILITY, struct bch_member, flags[0], 28, 30) -#define BCH_TIER_MAX 4U - #if 0 LE64_BITMASK(BCH_MEMBER_NR_READ_ERRORS, struct bch_member, flags[1], 0, 20); LE64_BITMASK(BCH_MEMBER_NR_WRITE_ERRORS,struct bch_member, flags[1], 20, 40); diff --git a/libbcachefs/btree_iter.c b/libbcachefs/btree_iter.c index 343587e8..47c10886 100644 --- a/libbcachefs/btree_iter.c +++ b/libbcachefs/btree_iter.c @@ -1508,19 +1508,11 @@ static int __btree_path_traverse_all(struct btree_trans *, int, unsigned long); int __must_check bch2_btree_path_traverse(struct btree_trans *trans, struct btree_path *path, unsigned flags) { - int ret; - if (path->uptodate < BTREE_ITER_NEED_RELOCK) return 0; - ret = bch2_trans_cond_resched(trans) ?: + return bch2_trans_cond_resched(trans) ?: btree_path_traverse_one(trans, path, flags, _RET_IP_); - if (unlikely(ret) && hweight64(trans->paths_allocated) == 1) { - ret = __btree_path_traverse_all(trans, ret, _RET_IP_); - BUG_ON(ret == -EINTR); - } - - return ret; } static void btree_path_copy(struct btree_trans *trans, struct btree_path *dst, @@ -1928,10 +1920,6 @@ struct btree *bch2_btree_iter_next_node(struct btree_iter *iter) if (!btree_path_node(path, path->level)) goto out; - ret = bch2_trans_cond_resched(trans); - if (ret) - goto err; - btree_node_unlock(path, path->level); path->l[path->level].b = BTREE_ITER_NO_NODE_UP; path->level++; diff --git a/libbcachefs/btree_iter.h b/libbcachefs/btree_iter.h index 72aff955..eaf432aa 100644 --- a/libbcachefs/btree_iter.h +++ b/libbcachefs/btree_iter.h @@ -258,57 +258,6 @@ static inline int bch2_trans_cond_resched(struct btree_trans *trans) } } -#define __for_each_btree_node(_trans, _iter, _btree_id, _start, \ - _locks_want, _depth, _flags, _b, _ret) \ - for (bch2_trans_node_iter_init((_trans), &(_iter), (_btree_id), \ - _start, _locks_want, _depth, _flags), \ - _b = bch2_btree_iter_peek_node(&(_iter)); \ - !((_ret) = PTR_ERR_OR_ZERO(_b)) && (_b); \ - (_b) = bch2_btree_iter_next_node(&(_iter))) - -#define for_each_btree_node(_trans, _iter, _btree_id, _start, \ - _flags, _b, _ret) \ - __for_each_btree_node(_trans, _iter, _btree_id, _start, \ - 0, 0, _flags, _b, _ret) - -static inline struct bkey_s_c __bch2_btree_iter_peek(struct btree_iter *iter, - unsigned flags) -{ - return flags & BTREE_ITER_SLOTS - ? bch2_btree_iter_peek_slot(iter) - : bch2_btree_iter_peek(iter); -} - -static inline struct bkey_s_c __bch2_btree_iter_next(struct btree_iter *iter, - unsigned flags) -{ - return flags & BTREE_ITER_SLOTS - ? bch2_btree_iter_next_slot(iter) - : bch2_btree_iter_next(iter); -} - -static inline int bkey_err(struct bkey_s_c k) -{ - return PTR_ERR_OR_ZERO(k.k); -} - -#define for_each_btree_key(_trans, _iter, _btree_id, \ - _start, _flags, _k, _ret) \ - for (bch2_trans_iter_init((_trans), &(_iter), (_btree_id), \ - (_start), (_flags)), \ - (_k) = __bch2_btree_iter_peek(&(_iter), _flags); \ - !((_ret) = bkey_err(_k)) && (_k).k; \ - (_k) = __bch2_btree_iter_next(&(_iter), _flags)) - -#define for_each_btree_key_continue(_iter, _flags, _k, _ret) \ - for ((_k) = __bch2_btree_iter_peek(&(_iter), _flags); \ - !((_ret) = bkey_err(_k)) && (_k).k; \ - (_k) = __bch2_btree_iter_next(&(_iter), _flags)) - -/* new multiple iterator interface: */ - -void bch2_dump_trans_paths_updates(struct btree_trans *); - void bch2_trans_iter_exit(struct btree_trans *, struct btree_iter *); void bch2_trans_iter_init(struct btree_trans *, struct btree_iter *, unsigned, struct bpos, unsigned); @@ -324,6 +273,89 @@ static inline void set_btree_iter_dontneed(struct btree_iter *iter) void *bch2_trans_kmalloc(struct btree_trans *, size_t); void bch2_trans_begin(struct btree_trans *); + +static inline struct btree * +__btree_iter_peek_node_and_restart(struct btree_trans *trans, struct btree_iter *iter) +{ + struct btree *b; + + while (b = bch2_btree_iter_peek_node(iter), + PTR_ERR_OR_ZERO(b) == -EINTR) + bch2_trans_begin(trans); + + return b; +} + +#define __for_each_btree_node(_trans, _iter, _btree_id, _start, \ + _locks_want, _depth, _flags, _b, _ret) \ + for (bch2_trans_node_iter_init((_trans), &(_iter), (_btree_id), \ + _start, _locks_want, _depth, _flags); \ + (_b) = __btree_iter_peek_node_and_restart((_trans), &(_iter)),\ + !((_ret) = PTR_ERR_OR_ZERO(_b)) && (_b); \ + (_b) = bch2_btree_iter_next_node(&(_iter))) + +#define for_each_btree_node(_trans, _iter, _btree_id, _start, \ + _flags, _b, _ret) \ + __for_each_btree_node(_trans, _iter, _btree_id, _start, \ + 0, 0, _flags, _b, _ret) + +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(struct btree_iter *iter, + unsigned flags) +{ + return flags & BTREE_ITER_SLOTS + ? bch2_btree_iter_peek_slot(iter) + : bch2_btree_iter_peek(iter); +} + +static inline struct bkey_s_c +__bch2_btree_iter_peek_and_restart(struct btree_trans *trans, + struct btree_iter *iter, unsigned flags) +{ + struct bkey_s_c k; + + while (k = __bch2_btree_iter_peek(iter, flags), + bkey_err(k) == -EINTR) + bch2_trans_begin(trans); + + return k; +} + +#define for_each_btree_key(_trans, _iter, _btree_id, \ + _start, _flags, _k, _ret) \ + for (bch2_trans_iter_init((_trans), &(_iter), (_btree_id), \ + (_start), (_flags)); \ + (_k) = __bch2_btree_iter_peek_and_restart((_trans), &(_iter), _flags),\ + !((_ret) = bkey_err(_k)) && (_k).k; \ + bch2_btree_iter_advance(&(_iter))) + +#define for_each_btree_key_norestart(_trans, _iter, _btree_id, \ + _start, _flags, _k, _ret) \ + for (bch2_trans_iter_init((_trans), &(_iter), (_btree_id), \ + (_start), (_flags)); \ + (_k) = __bch2_btree_iter_peek(&(_iter), _flags), \ + !((_ret) = bkey_err(_k)) && (_k).k; \ + bch2_btree_iter_advance(&(_iter))) + +#define for_each_btree_key_continue(_trans, _iter, _flags, _k, _ret) \ + for (; \ + (_k) = __bch2_btree_iter_peek_and_restart((_trans), &(_iter), _flags),\ + !((_ret) = bkey_err(_k)) && (_k).k; \ + bch2_btree_iter_advance(&(_iter))) + +#define for_each_btree_key_continue_norestart(_iter, _flags, _k, _ret) \ + for (; \ + (_k) = __bch2_btree_iter_peek(&(_iter), _flags), \ + !((_ret) = bkey_err(_k)) && (_k).k; \ + bch2_btree_iter_advance(&(_iter))) + +/* new multiple iterator interface: */ + +void bch2_dump_trans_paths_updates(struct btree_trans *); void bch2_trans_init(struct btree_trans *, struct bch_fs *, unsigned, size_t); void bch2_trans_exit(struct btree_trans *); diff --git a/libbcachefs/btree_update_leaf.c b/libbcachefs/btree_update_leaf.c index f69f919d..762a9773 100644 --- a/libbcachefs/btree_update_leaf.c +++ b/libbcachefs/btree_update_leaf.c @@ -1210,7 +1210,7 @@ static int need_whiteout_for_snapshot(struct btree_trans *trans, pos.snapshot++; - for_each_btree_key(trans, iter, btree_id, pos, + for_each_btree_key_norestart(trans, iter, btree_id, pos, BTREE_ITER_ALL_SNAPSHOTS, k, ret) { if (bkey_cmp(k.k->p, pos)) break; diff --git a/libbcachefs/dirent.c b/libbcachefs/dirent.c index 26df20ad..00dac687 100644 --- a/libbcachefs/dirent.c +++ b/libbcachefs/dirent.c @@ -432,7 +432,7 @@ int bch2_empty_dir_trans(struct btree_trans *trans, subvol_inum dir) if (ret) return ret; - for_each_btree_key(trans, iter, BTREE_ID_dirents, + for_each_btree_key_norestart(trans, iter, BTREE_ID_dirents, SPOS(dir.inum, 0, snapshot), 0, k, ret) { if (k.k->p.inode > dir.inum) break; @@ -464,7 +464,7 @@ retry: if (ret) goto err; - for_each_btree_key(&trans, iter, BTREE_ID_dirents, + for_each_btree_key_norestart(&trans, iter, BTREE_ID_dirents, SPOS(inum.inum, ctx->pos, snapshot), 0, k, ret) { if (k.k->p.inode > inum.inum) break; diff --git a/libbcachefs/extent_update.c b/libbcachefs/extent_update.c index 9d959b05..58b2c96f 100644 --- a/libbcachefs/extent_update.c +++ b/libbcachefs/extent_update.c @@ -61,7 +61,7 @@ static int count_iters_for_insert(struct btree_trans *trans, struct btree_iter iter; struct bkey_s_c r_k; - for_each_btree_key(trans, iter, + for_each_btree_key_norestart(trans, iter, BTREE_ID_reflink, POS(0, idx + offset), BTREE_ITER_SLOTS, r_k, ret2) { if (bkey_cmp(bkey_start_pos(r_k.k), @@ -120,7 +120,7 @@ int bch2_extent_atomic_end(struct btree_trans *trans, bch2_trans_copy_iter(©, iter); - for_each_btree_key_continue(copy, 0, k, ret) { + for_each_btree_key_continue_norestart(copy, 0, k, ret) { unsigned offset = 0; if (bkey_cmp(bkey_start_pos(k.k), *end) >= 0) diff --git a/libbcachefs/fs-io.c b/libbcachefs/fs-io.c index 900a0c3e..3a3f6c7d 100644 --- a/libbcachefs/fs-io.c +++ b/libbcachefs/fs-io.c @@ -1838,7 +1838,7 @@ retry: if (err) goto err; - for_each_btree_key(&trans, iter, BTREE_ID_extents, + for_each_btree_key_norestart(&trans, iter, BTREE_ID_extents, SPOS(inum.inum, offset, snapshot), BTREE_ITER_SLOTS, k, err) { if (bkey_cmp(bkey_start_pos(k.k), POS(inum.inum, end)) >= 0) @@ -2213,7 +2213,7 @@ retry: if (ret) goto err; - for_each_btree_key(&trans, iter, BTREE_ID_extents, start, 0, k, ret) { + for_each_btree_key_norestart(&trans, iter, BTREE_ID_extents, start, 0, k, ret) { if (bkey_cmp(bkey_start_pos(k.k), end) >= 0) break; @@ -3118,7 +3118,7 @@ retry: if (ret) goto err; - for_each_btree_key(&trans, iter, BTREE_ID_extents, + for_each_btree_key_norestart(&trans, iter, BTREE_ID_extents, SPOS(inode->v.i_ino, offset >> 9, snapshot), 0, k, ret) { if (k.k->p.inode != inode->v.i_ino) { break; @@ -3225,7 +3225,7 @@ retry: if (ret) goto err; - for_each_btree_key(&trans, iter, BTREE_ID_extents, + for_each_btree_key_norestart(&trans, iter, BTREE_ID_extents, SPOS(inode->v.i_ino, offset >> 9, snapshot), BTREE_ITER_SLOTS, k, ret) { if (k.k->p.inode != inode->v.i_ino) { diff --git a/libbcachefs/fs-ioctl.c b/libbcachefs/fs-ioctl.c index 3ed53f42..513f7a7a 100644 --- a/libbcachefs/fs-ioctl.c +++ b/libbcachefs/fs-ioctl.c @@ -422,6 +422,7 @@ static long bch2_ioctl_subvolume_destroy(struct bch_fs *c, struct file *filp, struct bch_ioctl_subvolume arg) { struct path path; + struct inode *dir; int ret = 0; if (arg.flags) @@ -438,7 +439,13 @@ static long bch2_ioctl_subvolume_destroy(struct bch_fs *c, struct file *filp, return -EXDEV; } - ret = __bch2_unlink(path.dentry->d_parent->d_inode, path.dentry, 1); + dir = path.dentry->d_parent->d_inode; + + ret = __bch2_unlink(dir, path.dentry, 1); + if (!ret) { + fsnotify_rmdir(dir, path.dentry); + d_delete(path.dentry); + } path_put(&path); return ret; diff --git a/libbcachefs/fsck.c b/libbcachefs/fsck.c index c99e1514..d6f37b9e 100644 --- a/libbcachefs/fsck.c +++ b/libbcachefs/fsck.c @@ -1357,10 +1357,10 @@ static int check_dirent_target(struct btree_trans *trans, } if (fsck_err_on(!backpointer_exists, c, - "inode %llu has wrong backpointer:\n" + "inode %llu:%u has wrong backpointer:\n" "got %llu:%llu\n" "should be %llu:%llu", - target->bi_inum, + target->bi_inum, target_snapshot, target->bi_dir, target->bi_dir_offset, d.k->p.inode, @@ -1730,10 +1730,23 @@ struct pathbuf { struct pathbuf_entry { u64 inum; + u32 snapshot; } *entries; }; -static int path_down(struct pathbuf *p, u64 inum) +static bool path_is_dup(struct pathbuf *p, u64 inum, u32 snapshot) +{ + struct pathbuf_entry *i; + + for (i = p->entries; i < p->entries + p->nr; i++) + if (i->inum == inum && + i->snapshot == snapshot) + return true; + + return false; +} + +static int path_down(struct pathbuf *p, u64 inum, u32 snapshot) { if (p->nr == p->size) { size_t new_size = max_t(size_t, 256UL, p->size * 2); @@ -1749,18 +1762,23 @@ static int path_down(struct pathbuf *p, u64 inum) }; p->entries[p->nr++] = (struct pathbuf_entry) { - .inum = inum, + .inum = inum, + .snapshot = snapshot, }; return 0; } +/* + * Check that a given inode is reachable from the root: + * + * XXX: we should also be verifying that inodes are in the right subvolumes + */ static int check_path(struct btree_trans *trans, struct pathbuf *p, struct bch_inode_unpacked *inode, u32 snapshot) { struct bch_fs *c = trans->c; - size_t i; int ret = 0; snapshot = snapshot_t(c, snapshot)->equiv; @@ -1768,17 +1786,19 @@ static int check_path(struct btree_trans *trans, while (!(inode->bi_inum == BCACHEFS_ROOT_INO && inode->bi_subvol == BCACHEFS_ROOT_SUBVOL)) { + u32 parent_snapshot = snapshot; + if (inode->bi_parent_subvol) { u64 inum; ret = subvol_lookup(trans, inode->bi_parent_subvol, - &snapshot, &inum); + &parent_snapshot, &inum); if (ret) break; } ret = lockrestart_do(trans, - inode_backpointer_exists(trans, inode, snapshot)); + inode_backpointer_exists(trans, inode, parent_snapshot)); if (ret < 0) break; @@ -1797,17 +1817,31 @@ static int check_path(struct btree_trans *trans, if (!S_ISDIR(inode->bi_mode)) break; - ret = path_down(p, inode->bi_inum); + ret = path_down(p, inode->bi_inum, snapshot); if (ret) { bch_err(c, "memory allocation failure"); return ret; } - for (i = 0; i < p->nr; i++) { - if (inode->bi_dir != p->entries[i].inum) - continue; + snapshot = parent_snapshot; + + ret = lookup_inode(trans, inode->bi_dir, inode, &snapshot); + if (ret) { + /* Should have been caught in dirents pass */ + bch_err(c, "error looking up parent directory: %i", ret); + break; + } + + if (path_is_dup(p, inode->bi_inum, snapshot)) { + struct pathbuf_entry *i; /* XXX print path */ + bch_err(c, "directory structure loop"); + + for (i = p->entries; i < p->entries + p->nr; i++) + pr_err("%llu:%u", i->inum, i->snapshot); + pr_err("%llu:%u", inode->bi_inum, snapshot); + if (!fsck_err(c, "directory structure loop")) return 0; @@ -1819,14 +1853,6 @@ static int check_path(struct btree_trans *trans, } ret = reattach_inode(trans, inode, snapshot); - break; - } - - ret = lookup_inode(trans, inode->bi_dir, inode, &snapshot); - if (ret) { - /* Should have been caught in dirents pass */ - bch_err(c, "error looking up parent directory: %i", ret); - break; } } fsck_err: diff --git a/libbcachefs/io.c b/libbcachefs/io.c index 65f8645c..c4c28559 100644 --- a/libbcachefs/io.c +++ b/libbcachefs/io.c @@ -206,7 +206,7 @@ int bch2_sum_sector_overwrites(struct btree_trans *trans, bch2_trans_copy_iter(&iter, extent_iter); - for_each_btree_key_continue(iter, BTREE_ITER_SLOTS, old, ret) { + for_each_btree_key_continue_norestart(iter, BTREE_ITER_SLOTS, old, ret) { s64 sectors = min(new->k.p.offset, old.k->p.offset) - max(bkey_start_offset(&new->k), bkey_start_offset(old.k)); @@ -966,7 +966,6 @@ static int bch2_write_extent(struct bch_write_op *op, struct write_point *wp, ret = -EIO; goto err; case PREP_ENCODED_CHECKSUM_ERR: - BUG(); goto csum_err; case PREP_ENCODED_DO_WRITE: /* XXX look for bug here */ diff --git a/libbcachefs/reflink.c b/libbcachefs/reflink.c index 2827d0ef..8e66e639 100644 --- a/libbcachefs/reflink.c +++ b/libbcachefs/reflink.c @@ -131,7 +131,7 @@ static int bch2_make_extent_indirect(struct btree_trans *trans, if (orig->k.type == KEY_TYPE_inline_data) bch2_check_set_feature(c, BCH_FEATURE_reflink_inline_data); - for_each_btree_key(trans, reflink_iter, BTREE_ID_reflink, + for_each_btree_key_norestart(trans, reflink_iter, BTREE_ID_reflink, POS(0, c->reflink_hint), BTREE_ITER_INTENT|BTREE_ITER_SLOTS, k, ret) { if (reflink_iter.pos.inode) { @@ -194,7 +194,7 @@ static struct bkey_s_c get_next_src(struct btree_iter *iter, struct bpos end) struct bkey_s_c k; int ret; - for_each_btree_key_continue(*iter, 0, k, ret) { + for_each_btree_key_continue_norestart(*iter, 0, k, ret) { if (bkey_cmp(iter->pos, end) >= 0) break; diff --git a/libbcachefs/replicas.c b/libbcachefs/replicas.c index dbbbcc6d..00200659 100644 --- a/libbcachefs/replicas.c +++ b/libbcachefs/replicas.c @@ -1010,6 +1010,9 @@ bool bch2_have_enough_devs(struct bch_fs *c, struct bch_devs_mask devs, unsigned i, nr_online = 0, nr_failed = 0, dflags = 0; bool metadata = e->data_type < BCH_DATA_user; + if (e->data_type == BCH_DATA_cached) + continue; + for (i = 0; i < e->nr_devs; i++) { struct bch_dev *ca = bch_dev_bkey_exists(c, e->devs[i]); diff --git a/libbcachefs/str_hash.h b/libbcachefs/str_hash.h index 6486e709..3e54d0b0 100644 --- a/libbcachefs/str_hash.h +++ b/libbcachefs/str_hash.h @@ -156,7 +156,7 @@ bch2_hash_lookup(struct btree_trans *trans, if (ret) return ret; - for_each_btree_key(trans, *iter, desc.btree_id, + for_each_btree_key_norestart(trans, *iter, desc.btree_id, SPOS(inum.inum, desc.hash_key(info, key), snapshot), BTREE_ITER_SLOTS|flags, k, ret) { if (iter->pos.inode != inum.inum) @@ -192,7 +192,7 @@ bch2_hash_hole(struct btree_trans *trans, if (ret) return ret; - for_each_btree_key(trans, *iter, desc.btree_id, + for_each_btree_key_norestart(trans, *iter, desc.btree_id, SPOS(inum.inum, desc.hash_key(info, key), snapshot), BTREE_ITER_SLOTS|BTREE_ITER_INTENT, k, ret) { if (iter->pos.inode != inum.inum) @@ -220,7 +220,7 @@ int bch2_hash_needs_whiteout(struct btree_trans *trans, bch2_btree_iter_advance(&iter); - for_each_btree_key_continue(iter, BTREE_ITER_SLOTS, k, ret) { + for_each_btree_key_continue_norestart(iter, BTREE_ITER_SLOTS, k, ret) { if (k.k->type != desc.key_type && k.k->type != KEY_TYPE_hash_whiteout) break; @@ -253,7 +253,7 @@ int bch2_hash_set(struct btree_trans *trans, if (ret) return ret; - for_each_btree_key(trans, iter, desc.btree_id, + for_each_btree_key_norestart(trans, iter, desc.btree_id, SPOS(inum.inum, desc.hash_bkey(info, bkey_i_to_s_c(insert)), snapshot), diff --git a/libbcachefs/xattr.c b/libbcachefs/xattr.c index fe572b23..bb5da310 100644 --- a/libbcachefs/xattr.c +++ b/libbcachefs/xattr.c @@ -295,7 +295,7 @@ retry: if (ret) goto err; - for_each_btree_key(&trans, iter, BTREE_ID_xattrs, + for_each_btree_key_norestart(&trans, iter, BTREE_ID_xattrs, SPOS(inum, offset, snapshot), 0, k, ret) { BUG_ON(k.k->p.inode < inum);