summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2019-04-17 22:49:28 +0300
committerKent Overstreet <kent.overstreet@linux.dev>2023-10-23 00:08:20 +0300
commit94f651e2c7e2808e82673b46776f951a67da4a2d (patch)
tree18ae9ea3df4e9c5f2bfa491d3efe722e5443f5c5
parent201a4d4cbed532c73d83ea9ea8166f40e9faa1e1 (diff)
downloadlinux-94f651e2c7e2808e82673b46776f951a67da4a2d.tar.xz
bcachefs: Return errors from for_each_btree_key()
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
-rw-r--r--fs/bcachefs/alloc_background.c10
-rw-r--r--fs/bcachefs/btree_gc.c4
-rw-r--r--fs/bcachefs/btree_iter.h16
-rw-r--r--fs/bcachefs/buckets.c41
-rw-r--r--fs/bcachefs/buckets.h10
-rw-r--r--fs/bcachefs/dirent.c17
-rw-r--r--fs/bcachefs/ec.c19
-rw-r--r--fs/bcachefs/extents.c3
-rw-r--r--fs/bcachefs/fs-io.c10
-rw-r--r--fs/bcachefs/fs.c10
-rw-r--r--fs/bcachefs/fsck.c28
-rw-r--r--fs/bcachefs/io.c13
-rw-r--r--fs/bcachefs/move.c2
-rw-r--r--fs/bcachefs/quota.c4
-rw-r--r--fs/bcachefs/str_hash.h43
-rw-r--r--fs/bcachefs/sysfs.c8
-rw-r--r--fs/bcachefs/tests.c35
-rw-r--r--fs/bcachefs/xattr.c93
18 files changed, 182 insertions, 184 deletions
diff --git a/fs/bcachefs/alloc_background.c b/fs/bcachefs/alloc_background.c
index 4a8f6fa3db1e..a6d3417ac262 100644
--- a/fs/bcachefs/alloc_background.c
+++ b/fs/bcachefs/alloc_background.c
@@ -273,14 +273,14 @@ int bch2_alloc_read(struct bch_fs *c, struct journal_keys *journal_keys)
bch2_trans_init(&trans, c);
- for_each_btree_key(&trans, iter, BTREE_ID_ALLOC, POS_MIN, 0, k) {
+ for_each_btree_key(&trans, iter, BTREE_ID_ALLOC, POS_MIN, 0, k, ret)
bch2_alloc_read_key(c, k);
- bch2_trans_cond_resched(&trans);
- }
- ret = bch2_trans_exit(&trans);
- if (ret)
+ ret = bch2_trans_exit(&trans) ?: ret;
+ if (ret) {
+ bch_err(c, "error reading alloc info: %i", ret);
return ret;
+ }
for_each_journal_key(*journal_keys, j)
if (j->btree_id == BTREE_ID_ALLOC)
diff --git a/fs/bcachefs/btree_gc.c b/fs/bcachefs/btree_gc.c
index 2650f60b7cd7..3ba0910c2a47 100644
--- a/fs/bcachefs/btree_gc.c
+++ b/fs/bcachefs/btree_gc.c
@@ -289,7 +289,7 @@ static int mark_journal_key(struct bch_fs *c, enum btree_id id,
bch2_trans_init(&trans, c);
for_each_btree_key(&trans, iter, id, bkey_start_pos(&insert->k),
- BTREE_ITER_SLOTS, k) {
+ BTREE_ITER_SLOTS, k, ret) {
percpu_down_read(&c->mark_lock);
ret = bch2_mark_overwrite(&trans, iter, k, insert, NULL,
BCH_BUCKET_MARK_GC|
@@ -300,7 +300,7 @@ static int mark_journal_key(struct bch_fs *c, enum btree_id id,
break;
}
- return bch2_trans_exit(&trans);
+ return bch2_trans_exit(&trans) ?: ret;
}
static int bch2_gc_btrees(struct bch_fs *c, struct journal_keys *journal_keys,
diff --git a/fs/bcachefs/btree_iter.h b/fs/bcachefs/btree_iter.h
index 291c805e3cc5..0a4c6c76e43b 100644
--- a/fs/bcachefs/btree_iter.h
+++ b/fs/bcachefs/btree_iter.h
@@ -238,12 +238,16 @@ static inline struct bkey_s_c __bch2_btree_iter_next(struct btree_iter *iter,
: bch2_btree_iter_next(iter);
}
-#define for_each_btree_key(_trans, _iter, _btree_id, _start, _flags, _k)\
- for (iter = bch2_trans_get_iter((_trans), (_btree_id), \
- (_start), (_flags)), \
- (_k) = __bch2_btree_iter_peek(_iter, _flags); \
- !IS_ERR_OR_NULL((_k).k); \
- (_k) = __bch2_btree_iter_next(_iter, _flags))
+#define for_each_btree_key(_trans, _iter, _btree_id, \
+ _start, _flags, _k, _ret) \
+ for ((_ret) = PTR_ERR_OR_ZERO((_iter) = \
+ bch2_trans_get_iter((_trans), (_btree_id), \
+ (_start), (_flags))) ?: \
+ PTR_ERR_OR_ZERO(((_k) = \
+ __bch2_btree_iter_peek(_iter, _flags)).k); \
+ !ret && (_k).k; \
+ (_ret) = PTR_ERR_OR_ZERO(((_k) = \
+ __bch2_btree_iter_next(_iter, _flags)).k))
#define for_each_btree_key_continue(_iter, _flags, _k) \
for ((_k) = __bch2_btree_iter_peek(_iter, _flags); \
diff --git a/fs/bcachefs/buckets.c b/fs/bcachefs/buckets.c
index e9c5889b2c0f..ff4c61371830 100644
--- a/fs/bcachefs/buckets.c
+++ b/fs/bcachefs/buckets.c
@@ -1035,12 +1035,12 @@ int bch2_mark_key(struct bch_fs *c, struct bkey_s_c k,
return ret;
}
-inline bool bch2_mark_overwrite(struct btree_trans *trans,
- struct btree_iter *iter,
- struct bkey_s_c old,
- struct bkey_i *new,
- struct bch_fs_usage *fs_usage,
- unsigned flags)
+inline int bch2_mark_overwrite(struct btree_trans *trans,
+ struct btree_iter *iter,
+ struct bkey_s_c old,
+ struct bkey_i *new,
+ struct bch_fs_usage *fs_usage,
+ unsigned flags)
{
struct bch_fs *c = trans->c;
struct btree *b = iter->l[0].b;
@@ -1049,7 +1049,7 @@ inline bool bch2_mark_overwrite(struct btree_trans *trans,
if (btree_node_is_extents(b)
? bkey_cmp(new->k.p, bkey_start_pos(old.k)) <= 0
: bkey_cmp(new->k.p, old.k->p))
- return false;
+ return 0;
if (btree_node_is_extents(b)) {
switch (bch2_extent_overlap(&new->k, old.k)) {
@@ -1080,24 +1080,24 @@ inline bool bch2_mark_overwrite(struct btree_trans *trans,
BUG_ON(sectors >= 0);
}
- bch2_mark_key_locked(c, old, false, sectors,
- fs_usage, trans->journal_res.seq, flags);
- return true;
+ return bch2_mark_key_locked(c, old, false, sectors, fs_usage,
+ trans->journal_res.seq, flags) ?: 1;
}
-void bch2_mark_update(struct btree_trans *trans,
- struct btree_insert_entry *insert,
- struct bch_fs_usage *fs_usage,
- unsigned flags)
+int bch2_mark_update(struct btree_trans *trans,
+ struct btree_insert_entry *insert,
+ struct bch_fs_usage *fs_usage,
+ unsigned flags)
{
struct bch_fs *c = trans->c;
struct btree_iter *iter = insert->iter;
struct btree *b = iter->l[0].b;
struct btree_node_iter node_iter = iter->l[0].iter;
struct bkey_packed *_k;
+ int ret = 0;
if (!btree_node_type_needs_gc(iter->btree_id))
- return;
+ return 0;
bch2_mark_key_locked(c, bkey_i_to_s_c(insert->k), true,
bpos_min(insert->k->k.p, b->key.k.p).offset -
@@ -1105,7 +1105,7 @@ void bch2_mark_update(struct btree_trans *trans,
fs_usage, trans->journal_res.seq, flags);
if (unlikely(trans->flags & BTREE_INSERT_NOMARK_OVERWRITES))
- return;
+ return 0;
/*
* For non extents, we only mark the new key, not the key being
@@ -1114,19 +1114,22 @@ void bch2_mark_update(struct btree_trans *trans,
if ((iter->btree_id == BTREE_ID_ALLOC ||
iter->btree_id == BTREE_ID_EC) &&
!bkey_deleted(&insert->k->k))
- return;
+ return 0;
while ((_k = bch2_btree_node_iter_peek_filter(&node_iter, b,
KEY_TYPE_discard))) {
struct bkey unpacked;
struct bkey_s_c k = bkey_disassemble(b, _k, &unpacked);
- if (!bch2_mark_overwrite(trans, iter, k, insert->k,
- fs_usage, flags))
+ ret = bch2_mark_overwrite(trans, iter, k, insert->k,
+ fs_usage, flags);
+ if (ret <= 0)
break;
bch2_btree_node_iter_advance(&node_iter, b);
}
+
+ return ret;
}
void bch2_trans_fs_usage_apply(struct btree_trans *trans,
diff --git a/fs/bcachefs/buckets.h b/fs/bcachefs/buckets.h
index 90fffee1c289..c51192fae503 100644
--- a/fs/bcachefs/buckets.h
+++ b/fs/bcachefs/buckets.h
@@ -254,11 +254,11 @@ int bch2_mark_key(struct bch_fs *, struct bkey_s_c,
int bch2_fs_usage_apply(struct bch_fs *, struct bch_fs_usage *,
struct disk_reservation *);
-bool bch2_mark_overwrite(struct btree_trans *, struct btree_iter *,
- struct bkey_s_c, struct bkey_i *,
- struct bch_fs_usage *, unsigned);
-void bch2_mark_update(struct btree_trans *, struct btree_insert_entry *,
- struct bch_fs_usage *, unsigned);
+int bch2_mark_overwrite(struct btree_trans *, struct btree_iter *,
+ struct bkey_s_c, struct bkey_i *,
+ struct bch_fs_usage *, unsigned);
+int bch2_mark_update(struct btree_trans *, struct btree_insert_entry *,
+ struct bch_fs_usage *, unsigned);
void bch2_trans_fs_usage_apply(struct btree_trans *, struct bch_fs_usage *);
/* disk reservations: */
diff --git a/fs/bcachefs/dirent.c b/fs/bcachefs/dirent.c
index 4479a9f55ddf..71971b3cc851 100644
--- a/fs/bcachefs/dirent.c
+++ b/fs/bcachefs/dirent.c
@@ -333,14 +333,10 @@ int bch2_empty_dir_trans(struct btree_trans *trans, u64 dir_inum)
{
struct btree_iter *iter;
struct bkey_s_c k;
- int ret = 0;
-
- iter = bch2_trans_get_iter(trans, BTREE_ID_DIRENTS,
- POS(dir_inum, 0), 0);
- if (IS_ERR(iter))
- return PTR_ERR(iter);
+ int ret;
- for_each_btree_key_continue(iter, 0, k) {
+ for_each_btree_key(trans, iter, BTREE_ID_DIRENTS,
+ POS(dir_inum, 0), 0, k, ret) {
if (k.k->p.inode > dir_inum)
break;
@@ -369,6 +365,7 @@ int bch2_readdir(struct bch_fs *c, struct file *file,
struct bkey_s_c k;
struct bkey_s_c_dirent dirent;
unsigned len;
+ int ret;
if (!dir_emit_dots(file, ctx))
return 0;
@@ -376,7 +373,7 @@ int bch2_readdir(struct bch_fs *c, struct file *file,
bch2_trans_init(&trans, c);
for_each_btree_key(&trans, iter, BTREE_ID_DIRENTS,
- POS(inode->v.i_ino, ctx->pos), 0, k) {
+ POS(inode->v.i_ino, ctx->pos), 0, k, ret) {
if (k.k->type != KEY_TYPE_dirent)
continue;
@@ -401,7 +398,7 @@ int bch2_readdir(struct bch_fs *c, struct file *file,
ctx->pos = k.k->p.offset + 1;
}
- bch2_trans_exit(&trans);
+ ret = bch2_trans_exit(&trans) ?: ret;
- return 0;
+ return ret;
}
diff --git a/fs/bcachefs/ec.c b/fs/bcachefs/ec.c
index 47d197ed5c99..063f91fc1b09 100644
--- a/fs/bcachefs/ec.c
+++ b/fs/bcachefs/ec.c
@@ -679,10 +679,8 @@ retry:
bch2_trans_begin(&trans);
/* XXX: start pos hint */
- iter = bch2_trans_get_iter(&trans, BTREE_ID_EC, POS_MIN,
- BTREE_ITER_SLOTS|BTREE_ITER_INTENT);
-
- for_each_btree_key_continue(iter, BTREE_ITER_SLOTS|BTREE_ITER_INTENT, k) {
+ for_each_btree_key(&trans, iter, BTREE_ID_EC, POS_MIN,
+ BTREE_ITER_SLOTS|BTREE_ITER_INTENT, k, ret) {
if (bkey_cmp(k.k->p, POS(0, U32_MAX)) > 0)
break;
@@ -690,7 +688,8 @@ retry:
goto found_slot;
}
- ret = -ENOSPC;
+ if (!ret)
+ ret = -ENOSPC;
goto out;
found_slot:
ret = ec_stripe_mem_alloc(c, iter);
@@ -1249,14 +1248,14 @@ int bch2_stripes_read(struct bch_fs *c, struct journal_keys *journal_keys)
bch2_trans_init(&trans, c);
- for_each_btree_key(&trans, iter, BTREE_ID_EC, POS_MIN, 0, k) {
+ for_each_btree_key(&trans, iter, BTREE_ID_EC, POS_MIN, 0, k, ret)
bch2_stripe_read_key(c, k);
- bch2_trans_cond_resched(&trans);
- }
- ret = bch2_trans_exit(&trans);
- if (ret)
+ ret = bch2_trans_exit(&trans) ?: ret;
+ if (ret) {
+ bch_err(c, "error reading stripes: %i", ret);
return ret;
+ }
for_each_journal_key(*journal_keys, i)
if (i->btree_id == BTREE_ID_EC)
diff --git a/fs/bcachefs/extents.c b/fs/bcachefs/extents.c
index 2e7c3e82f03b..257c862c9856 100644
--- a/fs/bcachefs/extents.c
+++ b/fs/bcachefs/extents.c
@@ -1632,13 +1632,14 @@ bool bch2_check_range_allocated(struct bch_fs *c, struct bpos pos, u64 size,
struct bpos end = pos;
struct bkey_s_c k;
bool ret = true;
+ int err;
end.offset += size;
bch2_trans_init(&trans, c);
for_each_btree_key(&trans, iter, BTREE_ID_EXTENTS, pos,
- BTREE_ITER_SLOTS, k) {
+ BTREE_ITER_SLOTS, k, err) {
if (bkey_cmp(bkey_start_pos(k.k), end) >= 0)
break;
diff --git a/fs/bcachefs/fs-io.c b/fs/bcachefs/fs-io.c
index c8f6104553aa..f76dd4d89f25 100644
--- a/fs/bcachefs/fs-io.c
+++ b/fs/bcachefs/fs-io.c
@@ -2139,7 +2139,7 @@ static inline int range_has_data(struct bch_fs *c,
bch2_trans_init(&trans, c);
- for_each_btree_key(&trans, iter, BTREE_ID_EXTENTS, start, 0, k) {
+ for_each_btree_key(&trans, iter, BTREE_ID_EXTENTS, start, 0, k, ret) {
if (bkey_cmp(bkey_start_pos(k.k), end) >= 0)
break;
@@ -2732,7 +2732,7 @@ static loff_t bch2_seek_data(struct file *file, u64 offset)
bch2_trans_init(&trans, c);
for_each_btree_key(&trans, iter, BTREE_ID_EXTENTS,
- POS(inode->v.i_ino, offset >> 9), 0, k) {
+ POS(inode->v.i_ino, offset >> 9), 0, k, ret) {
if (k.k->p.inode != inode->v.i_ino) {
break;
} else if (bkey_extent_is_data(k.k)) {
@@ -2742,7 +2742,7 @@ static loff_t bch2_seek_data(struct file *file, u64 offset)
break;
}
- ret = bch2_trans_exit(&trans);
+ ret = bch2_trans_exit(&trans) ?: ret;
if (ret)
return ret;
@@ -2806,7 +2806,7 @@ static loff_t bch2_seek_hole(struct file *file, u64 offset)
for_each_btree_key(&trans, iter, BTREE_ID_EXTENTS,
POS(inode->v.i_ino, offset >> 9),
- BTREE_ITER_SLOTS, k) {
+ BTREE_ITER_SLOTS, k, ret) {
if (k.k->p.inode != inode->v.i_ino) {
next_hole = bch2_next_pagecache_hole(&inode->v,
offset, MAX_LFS_FILESIZE);
@@ -2823,7 +2823,7 @@ static loff_t bch2_seek_hole(struct file *file, u64 offset)
}
}
- ret = bch2_trans_exit(&trans);
+ ret = bch2_trans_exit(&trans) ?: ret;
if (ret)
return ret;
diff --git a/fs/bcachefs/fs.c b/fs/bcachefs/fs.c
index 6e377a0e176f..ba4b4e942f0c 100644
--- a/fs/bcachefs/fs.c
+++ b/fs/bcachefs/fs.c
@@ -1210,7 +1210,7 @@ static int bch2_fiemap(struct inode *vinode, struct fiemap_extent_info *info,
bch2_trans_init(&trans, c);
for_each_btree_key(&trans, iter, BTREE_ID_EXTENTS,
- POS(ei->v.i_ino, start >> 9), 0, k)
+ POS(ei->v.i_ino, start >> 9), 0, k, ret)
if (bkey_extent_is_data(k.k) ||
k.k->type == KEY_TYPE_reservation) {
if (bkey_cmp(bkey_start_pos(k.k),
@@ -1220,17 +1220,17 @@ static int bch2_fiemap(struct inode *vinode, struct fiemap_extent_info *info,
if (have_extent) {
ret = bch2_fill_extent(info, &tmp.k, 0);
if (ret)
- goto out;
+ break;
}
bkey_reassemble(&tmp.k, k);
have_extent = true;
}
- if (have_extent)
+ if (!ret && have_extent)
ret = bch2_fill_extent(info, &tmp.k, FIEMAP_EXTENT_LAST);
-out:
- bch2_trans_exit(&trans);
+
+ ret = bch2_trans_exit(&trans) ?: ret;
return ret < 0 ? ret : 0;
}
diff --git a/fs/bcachefs/fsck.c b/fs/bcachefs/fsck.c
index 9db01437315b..ade3446d8dc3 100644
--- a/fs/bcachefs/fsck.c
+++ b/fs/bcachefs/fsck.c
@@ -21,8 +21,10 @@ static s64 bch2_count_inode_sectors(struct btree_trans *trans, u64 inum)
struct btree_iter *iter;
struct bkey_s_c k;
u64 sectors = 0;
+ int ret;
- for_each_btree_key(trans, iter, BTREE_ID_EXTENTS, POS(inum, 0), 0, k) {
+ for_each_btree_key(trans, iter, BTREE_ID_EXTENTS,
+ POS(inum, 0), 0, k, ret) {
if (k.k->p.inode != inum)
break;
@@ -30,7 +32,9 @@ static s64 bch2_count_inode_sectors(struct btree_trans *trans, u64 inum)
sectors += k.k->size;
}
- return bch2_trans_iter_free(trans, iter) ?: sectors;
+ bch2_trans_iter_free(trans, iter);
+
+ return ret ?: sectors;
}
static int remove_dirent(struct btree_trans *trans,
@@ -942,7 +946,7 @@ next:
goto up;
for_each_btree_key(&trans, iter, BTREE_ID_DIRENTS,
- POS(e->inum, e->offset + 1), 0, k) {
+ POS(e->inum, e->offset + 1), 0, k, ret) {
if (k.k->p.inode != e->inum)
break;
@@ -985,7 +989,7 @@ next:
}
goto next;
}
- ret = bch2_trans_iter_free(&trans, iter);
+ ret = bch2_trans_iter_free(&trans, iter) ?: ret;
if (ret) {
bch_err(c, "btree error %i in fsck", ret);
goto err;
@@ -1087,7 +1091,7 @@ static int bch2_gc_walk_dirents(struct bch_fs *c, nlink_table *links,
inc_link(c, links, range_start, range_end, BCACHEFS_ROOT_INO, false);
- for_each_btree_key(&trans, iter, BTREE_ID_DIRENTS, POS_MIN, 0, k) {
+ for_each_btree_key(&trans, iter, BTREE_ID_DIRENTS, POS_MIN, 0, k, ret) {
switch (k.k->type) {
case KEY_TYPE_dirent:
d = bkey_s_c_to_dirent(k);
@@ -1105,7 +1109,7 @@ static int bch2_gc_walk_dirents(struct bch_fs *c, nlink_table *links,
bch2_trans_cond_resched(&trans);
}
- ret = bch2_trans_exit(&trans);
+ ret = bch2_trans_exit(&trans) ?: ret;
if (ret)
bch_err(c, "error in fs gc: btree error %i while walking dirents", ret);
@@ -1432,15 +1436,12 @@ static int check_inodes_fast(struct bch_fs *c)
struct btree_iter *iter;
struct bkey_s_c k;
struct bkey_s_c_inode inode;
- int ret = 0, ret2;
+ int ret;
bch2_trans_init(&trans, c);
bch2_trans_preload_iters(&trans);
- iter = bch2_trans_get_iter(&trans, BTREE_ID_INODES,
- POS_MIN, 0);
-
- for_each_btree_key_continue(iter, 0, k) {
+ for_each_btree_key(&trans, iter, BTREE_ID_INODES, POS_MIN, 0, k, ret) {
if (k.k->type != KEY_TYPE_inode)
continue;
@@ -1456,10 +1457,9 @@ static int check_inodes_fast(struct bch_fs *c)
break;
}
}
+ BUG_ON(ret == -EINTR);
- ret2 = bch2_trans_exit(&trans);
-
- return ret ?: ret2;
+ return bch2_trans_exit(&trans) ?: ret;
}
/*
diff --git a/fs/bcachefs/io.c b/fs/bcachefs/io.c
index 71481b9728f5..b07b0f92d4f9 100644
--- a/fs/bcachefs/io.c
+++ b/fs/bcachefs/io.c
@@ -1326,7 +1326,7 @@ static void bch2_read_retry(struct bch_fs *c, struct bch_read_bio *rbio,
retry:
for_each_btree_key(&trans, iter, BTREE_ID_EXTENTS,
POS(inode, bvec_iter.bi_sector),
- BTREE_ITER_SLOTS, k) {
+ BTREE_ITER_SLOTS, k, ret) {
BKEY_PADDED(k) tmp;
unsigned bytes;
@@ -1357,8 +1357,8 @@ retry:
* If we get here, it better have been because there was an error
* reading a btree node
*/
- BUG_ON(!btree_iter_err(iter));
- __bcache_io_error(c, "btree IO error");
+ BUG_ON(!ret);
+ __bcache_io_error(c, "btree IO error: %i", ret);
err:
rbio->bio.bi_status = BLK_STS_IOERR;
out:
@@ -1871,6 +1871,7 @@ void bch2_read(struct bch_fs *c, struct bch_read_bio *rbio, u64 inode)
unsigned flags = BCH_READ_RETRY_IF_STALE|
BCH_READ_MAY_PROMOTE|
BCH_READ_USER_MAPPED;
+ int ret;
bch2_trans_init(&trans, c);
@@ -1883,7 +1884,7 @@ void bch2_read(struct bch_fs *c, struct bch_read_bio *rbio, u64 inode)
for_each_btree_key(&trans, iter, BTREE_ID_EXTENTS,
POS(inode, rbio->bio.bi_iter.bi_sector),
- BTREE_ITER_SLOTS, k) {
+ BTREE_ITER_SLOTS, k, ret) {
BKEY_PADDED(k) tmp;
unsigned bytes;
@@ -1915,8 +1916,8 @@ void bch2_read(struct bch_fs *c, struct bch_read_bio *rbio, u64 inode)
* If we get here, it better have been because there was an error
* reading a btree node
*/
- BUG_ON(!btree_iter_err(iter));
- bcache_io_error(c, &rbio->bio, "btree IO error");
+ BUG_ON(!ret);
+ bcache_io_error(c, &rbio->bio, "btree IO error: %i", ret);
bch2_trans_exit(&trans);
bch2_rbio_done(rbio);
diff --git a/fs/bcachefs/move.c b/fs/bcachefs/move.c
index 9793896bee77..1ad585ee27ca 100644
--- a/fs/bcachefs/move.c
+++ b/fs/bcachefs/move.c
@@ -630,7 +630,7 @@ static int bch2_gc_data_replicas(struct bch_fs *c)
bch2_replicas_gc_start(c, (1 << BCH_DATA_USER)|(1 << BCH_DATA_CACHED));
for_each_btree_key(&trans, iter, BTREE_ID_EXTENTS, POS_MIN,
- BTREE_ITER_PREFETCH, k) {
+ BTREE_ITER_PREFETCH, k, ret) {
ret = bch2_mark_bkey_replicas(c, k);
if (ret)
break;
diff --git a/fs/bcachefs/quota.c b/fs/bcachefs/quota.c
index a4f75d53b42c..b78df735d94c 100644
--- a/fs/bcachefs/quota.c
+++ b/fs/bcachefs/quota.c
@@ -364,7 +364,7 @@ static int bch2_quota_init_type(struct bch_fs *c, enum quota_types type)
bch2_trans_init(&trans, c);
for_each_btree_key(&trans, iter, BTREE_ID_QUOTAS, POS(type, 0),
- BTREE_ITER_PREFETCH, k) {
+ BTREE_ITER_PREFETCH, k, ret) {
if (k.k->p.inode != type)
break;
@@ -436,7 +436,7 @@ int bch2_fs_quota_read(struct bch_fs *c)
bch2_trans_init(&trans, c);
for_each_btree_key(&trans, iter, BTREE_ID_INODES, POS_MIN,
- BTREE_ITER_PREFETCH, k) {
+ BTREE_ITER_PREFETCH, k, ret) {
switch (k.k->type) {
case KEY_TYPE_inode:
ret = bch2_inode_unpack(bkey_s_c_to_inode(k), &u);
diff --git a/fs/bcachefs/str_hash.h b/fs/bcachefs/str_hash.h
index 0ed28d7f074d..c47af32ce983 100644
--- a/fs/bcachefs/str_hash.h
+++ b/fs/bcachefs/str_hash.h
@@ -134,14 +134,11 @@ bch2_hash_lookup(struct btree_trans *trans,
{
struct btree_iter *iter;
struct bkey_s_c k;
+ int ret;
- iter = bch2_trans_get_iter(trans, desc.btree_id,
- POS(inode, desc.hash_key(info, key)),
- BTREE_ITER_SLOTS|flags);
- if (IS_ERR(iter))
- return iter;
-
- for_each_btree_key_continue(iter, BTREE_ITER_SLOTS, k) {
+ for_each_btree_key(trans, iter, desc.btree_id,
+ POS(inode, desc.hash_key(info, key)),
+ BTREE_ITER_SLOTS|flags, k, ret) {
if (iter->pos.inode != inode)
break;
@@ -156,7 +153,7 @@ bch2_hash_lookup(struct btree_trans *trans,
}
}
- return IS_ERR(k.k) ? ERR_CAST(k.k) : ERR_PTR(-ENOENT);
+ return ERR_PTR(ret ?: -ENOENT);
}
static __always_inline struct btree_iter *
@@ -167,14 +164,11 @@ bch2_hash_hole(struct btree_trans *trans,
{
struct btree_iter *iter;
struct bkey_s_c k;
+ int ret;
- iter = bch2_trans_get_iter(trans, desc.btree_id,
- POS(inode, desc.hash_key(info, key)),
- BTREE_ITER_SLOTS|BTREE_ITER_INTENT);
- if (IS_ERR(iter))
- return iter;
-
- for_each_btree_key_continue(iter, BTREE_ITER_SLOTS, k) {
+ for_each_btree_key(trans, iter, desc.btree_id,
+ POS(inode, desc.hash_key(info, key)),
+ BTREE_ITER_SLOTS|BTREE_ITER_INTENT, k, ret) {
if (iter->pos.inode != inode)
break;
@@ -182,7 +176,7 @@ bch2_hash_hole(struct btree_trans *trans,
return iter;
}
- return IS_ERR(k.k) ? ERR_CAST(k.k) : ERR_PTR(-ENOSPC);
+ return ERR_PTR(ret ?: -ENOSPC);
}
static __always_inline
@@ -224,15 +218,11 @@ int bch2_hash_set(struct btree_trans *trans,
struct btree_iter *iter, *slot = NULL;
struct bkey_s_c k;
bool found = false;
- int ret = 0;
-
- iter = bch2_trans_get_iter(trans, desc.btree_id,
- POS(inode, desc.hash_bkey(info, bkey_i_to_s_c(insert))),
- BTREE_ITER_SLOTS|BTREE_ITER_INTENT);
- if (IS_ERR(iter))
- return PTR_ERR(iter);
+ int ret;
- for_each_btree_key_continue(iter, BTREE_ITER_SLOTS, k) {
+ for_each_btree_key(trans, iter, desc.btree_id,
+ POS(inode, desc.hash_bkey(info, bkey_i_to_s_c(insert))),
+ BTREE_ITER_SLOTS|BTREE_ITER_INTENT, k, ret) {
if (iter->pos.inode != inode)
break;
@@ -256,9 +246,10 @@ int bch2_hash_set(struct btree_trans *trans,
}
if (slot)
- bch2_trans_iter_free(trans, iter);
+ bch2_trans_iter_free(trans, slot);
+ bch2_trans_iter_free(trans, iter);
- return bch2_trans_iter_free(trans, iter) ?: -ENOSPC;
+ return ret ?: -ENOSPC;
found:
found = true;
not_found:
diff --git a/fs/bcachefs/sysfs.c b/fs/bcachefs/sysfs.c
index f4b70f66d0ac..ee4c0764d4ad 100644
--- a/fs/bcachefs/sysfs.c
+++ b/fs/bcachefs/sysfs.c
@@ -289,13 +289,14 @@ static ssize_t bch2_compression_stats(struct bch_fs *c, char *buf)
nr_compressed_extents = 0,
compressed_sectors_compressed = 0,
compressed_sectors_uncompressed = 0;
+ int ret;
if (!test_bit(BCH_FS_STARTED, &c->flags))
return -EPERM;
bch2_trans_init(&trans, c);
- for_each_btree_key(&trans, iter, BTREE_ID_EXTENTS, POS_MIN, 0, k)
+ for_each_btree_key(&trans, iter, BTREE_ID_EXTENTS, POS_MIN, 0, k, ret)
if (k.k->type == KEY_TYPE_extent) {
struct bkey_s_c_extent e = bkey_s_c_to_extent(k);
const union bch_extent_entry *entry;
@@ -317,7 +318,10 @@ static ssize_t bch2_compression_stats(struct bch_fs *c, char *buf)
break;
}
}
- bch2_trans_exit(&trans);
+
+ ret = bch2_trans_exit(&trans) ?: ret;
+ if (ret)
+ return ret;
return scnprintf(buf, PAGE_SIZE,
"uncompressed data:\n"
diff --git a/fs/bcachefs/tests.c b/fs/bcachefs/tests.c
index c8682fe674f6..0f5a3ed13f3e 100644
--- a/fs/bcachefs/tests.c
+++ b/fs/bcachefs/tests.c
@@ -116,7 +116,8 @@ static void test_iterate(struct bch_fs *c, u64 nr)
i = 0;
- for_each_btree_key(&trans, iter, BTREE_ID_DIRENTS, POS(0, 0), 0, k)
+ for_each_btree_key(&trans, iter, BTREE_ID_DIRENTS,
+ POS_MIN, 0, k, ret)
BUG_ON(k.k->p.offset != i++);
BUG_ON(i != nr);
@@ -161,7 +162,8 @@ static void test_iterate_extents(struct bch_fs *c, u64 nr)
i = 0;
- for_each_btree_key(&trans, iter, BTREE_ID_EXTENTS, POS(0, 0), 0, k) {
+ for_each_btree_key(&trans, iter, BTREE_ID_EXTENTS,
+ POS_MIN, 0, k, ret) {
BUG_ON(bkey_start_offset(k.k) != i);
i = k.k->p.offset;
}
@@ -209,7 +211,8 @@ static void test_iterate_slots(struct bch_fs *c, u64 nr)
i = 0;
- for_each_btree_key(&trans, iter, BTREE_ID_DIRENTS, POS(0, 0), 0, k) {
+ for_each_btree_key(&trans, iter, BTREE_ID_DIRENTS, POS_MIN,
+ 0, k, ret) {
BUG_ON(k.k->p.offset != i);
i += 2;
}
@@ -221,8 +224,8 @@ static void test_iterate_slots(struct bch_fs *c, u64 nr)
i = 0;
- for_each_btree_key(&trans, iter, BTREE_ID_DIRENTS, POS(0, 0),
- BTREE_ITER_SLOTS, k) {
+ for_each_btree_key(&trans, iter, BTREE_ID_DIRENTS, POS_MIN,
+ BTREE_ITER_SLOTS, k, ret) {
BUG_ON(bkey_deleted(k.k) != (i & 1));
BUG_ON(k.k->p.offset != i++);
@@ -263,7 +266,8 @@ static void test_iterate_slots_extents(struct bch_fs *c, u64 nr)
i = 0;
- for_each_btree_key(&trans, iter, BTREE_ID_EXTENTS, POS(0, 0), 0, k) {
+ for_each_btree_key(&trans, iter, BTREE_ID_EXTENTS, POS_MIN,
+ 0, k, ret) {
BUG_ON(bkey_start_offset(k.k) != i + 8);
BUG_ON(k.k->size != 8);
i += 16;
@@ -276,8 +280,8 @@ static void test_iterate_slots_extents(struct bch_fs *c, u64 nr)
i = 0;
- for_each_btree_key(&trans, iter, BTREE_ID_EXTENTS, POS(0, 0),
- BTREE_ITER_SLOTS, k) {
+ for_each_btree_key(&trans, iter, BTREE_ID_EXTENTS, POS_MIN,
+ BTREE_ITER_SLOTS, k, ret) {
BUG_ON(bkey_deleted(k.k) != !(i % 16));
BUG_ON(bkey_start_offset(k.k) != i);
@@ -501,10 +505,8 @@ static void seq_insert(struct bch_fs *c, u64 nr)
bch2_trans_init(&trans, c);
- iter = bch2_trans_get_iter(&trans, BTREE_ID_DIRENTS, POS_MIN,
- BTREE_ITER_SLOTS|BTREE_ITER_INTENT);
-
- for_each_btree_key_continue(iter, BTREE_ITER_SLOTS, k) {
+ for_each_btree_key(&trans, iter, BTREE_ID_DIRENTS, POS_MIN,
+ BTREE_ITER_SLOTS|BTREE_ITER_INTENT, k, ret) {
insert.k.p = iter->pos;
bch2_trans_update(&trans, BTREE_INSERT_ENTRY(iter, &insert.k_i));
@@ -522,10 +524,11 @@ static void seq_lookup(struct bch_fs *c, u64 nr)
struct btree_trans trans;
struct btree_iter *iter;
struct bkey_s_c k;
+ int ret;
bch2_trans_init(&trans, c);
- for_each_btree_key(&trans, iter, BTREE_ID_DIRENTS, POS_MIN, 0, k)
+ for_each_btree_key(&trans, iter, BTREE_ID_DIRENTS, POS_MIN, 0, k, ret)
;
bch2_trans_exit(&trans);
}
@@ -539,10 +542,8 @@ static void seq_overwrite(struct bch_fs *c, u64 nr)
bch2_trans_init(&trans, c);
- iter = bch2_trans_get_iter(&trans, BTREE_ID_DIRENTS, POS_MIN,
- BTREE_ITER_INTENT);
-
- for_each_btree_key_continue(iter, 0, k) {
+ for_each_btree_key(&trans, iter, BTREE_ID_DIRENTS, POS_MIN,
+ BTREE_ITER_INTENT, k, ret) {
struct bkey_i_cookie u;
bkey_reassemble(&u.k_i, k);
diff --git a/fs/bcachefs/xattr.c b/fs/bcachefs/xattr.c
index 68ece7c0ee7a..99fb42225508 100644
--- a/fs/bcachefs/xattr.c
+++ b/fs/bcachefs/xattr.c
@@ -198,55 +198,54 @@ int bch2_xattr_set(struct btree_trans *trans, u64 inum,
return ret;
}
-static void __bch2_xattr_emit(const char *prefix,
- const char *name, size_t name_len,
- char **buffer, size_t *buffer_size,
- ssize_t *ret)
+struct xattr_buf {
+ char *buf;
+ size_t len;
+ size_t used;
+};
+
+static int __bch2_xattr_emit(const char *prefix,
+ const char *name, size_t name_len,
+ struct xattr_buf *buf)
{
const size_t prefix_len = strlen(prefix);
const size_t total_len = prefix_len + name_len + 1;
- if (*buffer) {
- if (total_len > *buffer_size) {
- *ret = -ERANGE;
- return;
- }
+ if (buf->buf) {
+ if (buf->used + total_len > buf->len)
+ return -ERANGE;
- memcpy(*buffer, prefix, prefix_len);
- memcpy(*buffer + prefix_len,
+ memcpy(buf->buf + buf->used, prefix, prefix_len);
+ memcpy(buf->buf + buf->used + prefix_len,
name, name_len);
- (*buffer)[prefix_len + name_len] = '\0';
-
- *buffer += total_len;
- *buffer_size -= total_len;
+ buf->buf[buf->used + prefix_len + name_len] = '\0';
}
- *ret += total_len;
+ buf->used += total_len;
+ return 0;
}
-static void bch2_xattr_emit(struct dentry *dentry,
+static int bch2_xattr_emit(struct dentry *dentry,
const struct bch_xattr *xattr,
- char **buffer, size_t *buffer_size,
- ssize_t *ret)
+ struct xattr_buf *buf)
{
const struct xattr_handler *handler =
bch2_xattr_type_to_handler(xattr->x_type);
- if (handler && (!handler->list || handler->list(dentry)))
- __bch2_xattr_emit(handler->prefix ?: handler->name,
- xattr->x_name, xattr->x_name_len,
- buffer, buffer_size, ret);
+ return handler && (!handler->list || handler->list(dentry))
+ ? __bch2_xattr_emit(handler->prefix ?: handler->name,
+ xattr->x_name, xattr->x_name_len, buf)
+ : 0;
}
-static void bch2_xattr_list_bcachefs(struct bch_fs *c,
- struct bch_inode_info *inode,
- char **buffer,
- size_t *buffer_size,
- ssize_t *ret,
- bool all)
+static int bch2_xattr_list_bcachefs(struct bch_fs *c,
+ struct bch_inode_info *inode,
+ struct xattr_buf *buf,
+ bool all)
{
const char *prefix = all ? "bcachefs_effective." : "bcachefs.";
unsigned id;
+ int ret = 0;
u64 v;
for (id = 0; id < Inode_opt_nr; id++) {
@@ -258,13 +257,13 @@ static void bch2_xattr_list_bcachefs(struct bch_fs *c,
!(inode->ei_inode.bi_fields_set & (1 << id)))
continue;
- __bch2_xattr_emit(prefix,
- bch2_inode_opts[id],
- strlen(bch2_inode_opts[id]),
- buffer, buffer_size, ret);
- if (*ret < 0)
+ ret = __bch2_xattr_emit(prefix, bch2_inode_opts[id],
+ strlen(bch2_inode_opts[id]), buf);
+ if (ret)
break;
}
+
+ return ret;
}
ssize_t bch2_xattr_list(struct dentry *dentry, char *buffer, size_t buffer_size)
@@ -274,13 +273,14 @@ ssize_t bch2_xattr_list(struct dentry *dentry, char *buffer, size_t buffer_size)
struct btree_trans trans;
struct btree_iter *iter;
struct bkey_s_c k;
+ struct xattr_buf buf = { .buf = buffer, .len = buffer_size };
u64 inum = dentry->d_inode->i_ino;
- ssize_t ret = 0;
+ int ret;
bch2_trans_init(&trans, c);
for_each_btree_key(&trans, iter, BTREE_ID_XATTRS,
- POS(inum, 0), 0, k) {
+ POS(inum, 0), 0, k, ret) {
BUG_ON(k.k->p.inode < inum);
if (k.k->p.inode > inum)
@@ -289,27 +289,24 @@ ssize_t bch2_xattr_list(struct dentry *dentry, char *buffer, size_t buffer_size)
if (k.k->type != KEY_TYPE_xattr)
continue;
- bch2_xattr_emit(dentry, bkey_s_c_to_xattr(k).v,
- &buffer, &buffer_size, &ret);
- if (ret < 0)
+ ret = bch2_xattr_emit(dentry, bkey_s_c_to_xattr(k).v, &buf);
+ if (ret)
break;
}
- bch2_trans_exit(&trans);
+ ret = bch2_trans_exit(&trans) ?: ret;
- if (ret < 0)
+ if (ret)
return ret;
- bch2_xattr_list_bcachefs(c, inode, &buffer,
- &buffer_size, &ret, false);
- if (ret < 0)
+ ret = bch2_xattr_list_bcachefs(c, inode, &buf, false);
+ if (ret)
return ret;
- bch2_xattr_list_bcachefs(c, inode, &buffer,
- &buffer_size, &ret, true);
- if (ret < 0)
+ ret = bch2_xattr_list_bcachefs(c, inode, &buf, true);
+ if (ret)
return ret;
- return ret;
+ return buf.used;
}
static int bch2_xattr_get_handler(const struct xattr_handler *handler,