-242d37cbd0abfa575ebf816c715e5bb9513c90a0
+0a9f0fc68a3cfaaee05a0848673fdb3de3108982
}
xattr = bkey_s_c_to_xattr(bch2_btree_iter_peek_slot(iter));
-
acl = bch2_acl_from_disk(xattr_val(xattr.v),
le16_to_cpu(xattr.v->x_val_len));
if (!IS_ERR(acl))
set_cached_acl(&inode->v, type, acl);
+ bch2_trans_iter_put(&trans, iter);
out:
bch2_trans_exit(&trans);
return acl;
if (type == ACL_TYPE_ACCESS) {
ret = posix_acl_update_mode(&inode->v, &mode, &acl);
if (ret)
- goto err;
+ goto btree_err;
}
hash_info = bch2_hash_info_init(c, &inode_u);
&inode->ei_journal_seq,
BTREE_INSERT_NOUNLOCK);
btree_err:
+ bch2_trans_iter_put(&trans, inode_iter);
+
if (ret == -EINTR)
goto retry;
if (unlikely(ret))
struct bkey_s_c_xattr xattr;
struct bkey_i_xattr *new;
struct posix_acl *acl;
- int ret = 0;
+ int ret;
iter = bch2_hash_lookup(trans, bch2_xattr_hash_desc,
&hash_info, inode->bi_inum,
&X_SEARCH(KEY_TYPE_XATTR_INDEX_POSIX_ACL_ACCESS, "", 0),
BTREE_ITER_INTENT);
- if (IS_ERR(iter))
- return PTR_ERR(iter) != -ENOENT ? PTR_ERR(iter) : 0;
+ ret = PTR_ERR_OR_ZERO(iter);
+ if (ret)
+ return ret == -ENOENT ? 0 : ret;
xattr = bkey_s_c_to_xattr(bch2_btree_iter_peek_slot(iter));
-
acl = bch2_acl_from_disk(xattr_val(xattr.v),
le16_to_cpu(xattr.v->x_val_len));
- if (IS_ERR_OR_NULL(acl))
- return PTR_ERR(acl);
+ ret = PTR_ERR_OR_ZERO(acl);
+ if (ret || !acl)
+ goto err;
ret = __posix_acl_chmod(&acl, GFP_KERNEL, mode);
if (ret)
*new_acl = acl;
acl = NULL;
err:
+ bch2_trans_iter_put(trans, iter);
kfree(acl);
return ret;
}
#undef x
}
-static void bch2_alloc_pack_v1(struct bkey_alloc_buf *dst,
- const struct bkey_alloc_unpacked src)
-{
- struct bkey_i_alloc *a = bkey_alloc_init(&dst->k);
- void *d = a->v.data;
- unsigned bytes, idx = 0;
-
- a->k.p = POS(src.dev, src.bucket);
- a->v.fields = 0;
- a->v.gen = src.gen;
-
-#define x(_name, _bits) alloc_field_v1_put(a, &d, idx++, src._name);
- BCH_ALLOC_FIELDS_V1()
-#undef x
- bytes = (void *) d - (void *) &a->v;
- set_bkey_val_bytes(&a->k, bytes);
- memset_u64s_tail(&a->v, 0, bytes);
-}
-
static int bch2_alloc_unpack_v2(struct bkey_alloc_unpacked *out,
struct bkey_s_c k)
{
struct bkey_alloc_buf *dst,
const struct bkey_alloc_unpacked src)
{
- if (c->sb.features & (1ULL << BCH_FEATURE_alloc_v2))
- bch2_alloc_pack_v2(dst, src);
- else
- bch2_alloc_pack_v1(dst, src);
+ bch2_alloc_pack_v2(dst, src);
}
static unsigned bch_alloc_val_u64s(const struct bch_alloc *a)
int ret = 0;
bch2_trans_init(&trans, c, BTREE_ITER_MAX, 0);
-
iter = bch2_trans_get_iter(&trans, BTREE_ID_alloc, POS_MIN,
BTREE_ITER_SLOTS|BTREE_ITER_INTENT);
}
}
err:
+ bch2_trans_iter_put(&trans, iter);
bch2_trans_exit(&trans);
return ret;
}
int ret = 0;
bch2_trans_init(&trans, c, 0, 0);
-
iter = bch2_trans_get_iter(&trans, BTREE_ID_alloc,
POS(ca->dev_idx, 0),
BTREE_ITER_CACHED|
(!fifo_empty(&ca->free_inc)
? BTREE_INSERT_NOWAIT : 0));
+ bch2_trans_iter_put(&trans, iter);
bch2_trans_exit(&trans);
/* If we used NOWAIT, don't return the error: */
uuid_le user_uuid;
u16 version;
+ u16 version_min;
u16 encoded_extent_max;
u8 nr_devices;
((1ULL << BCH_FEATURE_new_extent_overwrite)| \
(1ULL << BCH_FEATURE_extents_above_btree_updates)|\
(1ULL << BCH_FEATURE_btree_updates_journalled)|\
+ (1ULL << BCH_FEATURE_alloc_v2)|\
(1ULL << BCH_FEATURE_extents_across_btree_nodes))
#define BCH_SB_FEATURES_ALL \
(1ULL << BCH_FEATURE_new_siphash)| \
(1ULL << BCH_FEATURE_btree_ptr_v2)| \
(1ULL << BCH_FEATURE_new_varint)| \
- (1ULL << BCH_FEATURE_journal_no_flush)| \
- (1ULL << BCH_FEATURE_alloc_v2))
+ (1ULL << BCH_FEATURE_journal_no_flush))
enum bch_sb_feature {
#define x(f, n) BCH_FEATURE_##f,
void bch2_bkey_debugcheck(struct bch_fs *c, struct btree *b, struct bkey_s_c k)
{
- const struct bkey_ops *ops = &bch2_bkey_ops[k.k->type];
const char *invalid;
BUG_ON(!k.k->u64s);
bch2_bkey_val_to_text(&PBUF(buf), c, k);
bch2_fs_inconsistent(c, "invalid bkey %s: %s", buf, invalid);
- return;
}
-
- if (ops->key_debugcheck)
- ops->key_debugcheck(c, k);
}
void bch2_bpos_to_text(struct printbuf *out, struct bpos pos)
/* Returns reason for being invalid if invalid, else NULL: */
const char * (*key_invalid)(const struct bch_fs *,
struct bkey_s_c);
- void (*key_debugcheck)(struct bch_fs *, struct bkey_s_c);
void (*val_to_text)(struct printbuf *, struct bch_fs *,
struct bkey_s_c);
void (*swab)(struct bkey_s);
bkey_init(&prev.k->k);
while ((k = bch2_btree_node_iter_peek_unpack(&iter, b, &unpacked)).k) {
- bch2_bkey_debugcheck(c, b, k);
-
ret = bch2_gc_mark_key(c, b->c.btree_id, b->c.level, false,
k, max_stale, initial);
if (ret)
bch2_trans_cond_resched(&trans);
}
+ bch2_trans_iter_put(&trans, iter);
+
ret = bch2_trans_exit(&trans) ?: ret;
if (ret)
return ret;
bkey_init(&prev.k->k);
while ((k = bch2_btree_and_journal_iter_peek(&iter)).k) {
- bch2_bkey_debugcheck(c, b, k);
-
BUG_ON(bkey_cmp(k.k->p, b->data->min_key) < 0);
BUG_ON(bkey_cmp(k.k->p, b->data->max_key) > 0);
struct btree *b;
bool kthread = (current->flags & PF_KTHREAD) != 0;
unsigned i;
+ int ret = 0;
/* Sliding window of adjacent btree nodes */
struct btree *merge[GC_MERGE_NODES];
lock_seq[0] = merge[0]->c.lock.state.seq;
if (kthread && kthread_should_stop()) {
- bch2_trans_exit(&trans);
- return -ESHUTDOWN;
+ ret = -ESHUTDOWN;
+ break;
}
bch2_trans_cond_resched(&trans);
memset(merge + 1, 0,
(GC_MERGE_NODES - 1) * sizeof(merge[0]));
}
- return bch2_trans_exit(&trans);
+ bch2_trans_iter_put(&trans, iter);
+
+ return bch2_trans_exit(&trans) ?: ret;
}
/**
BTREE_ERR_FATAL, c, ca, b, i,
"unsupported bset version");
+ if (btree_err_on(version < c->sb.version_min,
+ BTREE_ERR_FIXABLE, c, NULL, b, i,
+ "bset version %u older than superblock version_min %u",
+ version, c->sb.version_min)) {
+ mutex_lock(&c->sb_lock);
+ c->disk_sb.sb->version_min = cpu_to_le16(version);
+ bch2_write_super(c);
+ mutex_unlock(&c->sb_lock);
+ }
+
+ if (btree_err_on(version > c->sb.version,
+ BTREE_ERR_FIXABLE, c, NULL, b, i,
+ "bset version %u newer than superblock version %u",
+ version, c->sb.version)) {
+ mutex_lock(&c->sb_lock);
+ c->disk_sb.sb->version = cpu_to_le16(version);
+ bch2_write_super(c);
+ mutex_unlock(&c->sb_lock);
+ }
+
if (btree_err_on(b->written + sectors > c->opts.btree_node_size,
BTREE_ERR_FIXABLE, c, ca, b, i,
"bset past end of btree node")) {
unsigned u64s;
int ret, retry_read = 0, write = READ;
+ b->version_ondisk = U16_MAX;
+
iter = mempool_alloc(&c->fill_iter, GFP_NOIO);
sort_iter_init(iter, b);
iter->size = (btree_blocks(c) + 1) * 2;
sectors = vstruct_sectors(bne, c->block_bits);
}
+ b->version_ondisk = min(b->version_ondisk,
+ le16_to_cpu(i->version));
+
ret = validate_bset(c, ca, b, i, sectors,
READ, have_retry);
if (ret)
if (ret)
goto err;
out:
+ bch2_trans_iter_put(&trans, iter);
bch2_trans_exit(&trans);
bch2_bkey_buf_exit(&k, c);
bio_put(&wbio->wbio.bio);
#include "btree_locking.h"
#include "btree_update.h"
#include "debug.h"
+#include "error.h"
#include "extents.h"
#include "journal.h"
if (btree_node_read_locked(iter, iter->level))
btree_node_unlock(iter, iter->level);
- iter->pos = bkey_successor(iter->pos);
+ iter->pos = iter->real_pos = bkey_successor(iter->pos);
iter->level = iter->min_depth;
btree_iter_set_dirty(iter, BTREE_ITER_NEED_TRAVERSE);
btree_iter_set_search_pos(iter, btree_iter_search_key(iter));
}
-static inline bool bch2_btree_iter_advance_pos(struct btree_iter *iter)
+inline bool bch2_btree_iter_advance_pos(struct btree_iter *iter)
{
struct bpos pos = iter->k.p;
bool ret = bkey_cmp(pos, POS_MAX) != 0;
return ret;
}
-static inline bool bch2_btree_iter_rewind_pos(struct btree_iter *iter)
+inline bool bch2_btree_iter_rewind_pos(struct btree_iter *iter)
{
struct bpos pos = bkey_start_pos(&iter->k);
bool ret = bkey_cmp(pos, POS_MIN) != 0;
return 0;
BUG_ON(trans->iters + iter->idx != iter);
+ BUG_ON(!btree_iter_live(trans, iter));
ret = btree_iter_err(iter);
if (IS_ERR_OR_NULL(iter))
return 0;
- trans->iters_touched &= ~(1ULL << iter->idx);
+ set_btree_iter_dontneed(trans, iter);
return bch2_trans_iter_put(trans, iter);
}
for (i = 0; i < ARRAY_SIZE(iter->l); i++)
iter->l[i].b = NULL;
iter->l[iter->level].b = BTREE_ITER_NO_NODE_INIT;
+ iter->ip_allocated = _RET_IP_;
return iter;
}
* We don't need to preserve this iter since it's cheap to copy it
* again - this will cause trans_iter_put() to free it right away:
*/
- trans->iters_touched &= ~(1ULL << iter->idx);
+ set_btree_iter_dontneed(trans, iter);
return iter;
}
(void *) &trans->fs_usage_deltas->memset_start);
}
+ bch2_trans_cond_resched(trans);
+
if (!(flags & TRANS_RESET_NOTRAVERSE))
bch2_btree_iter_traverse_all(trans);
}
bch2_trans_unlock(trans);
#ifdef CONFIG_BCACHEFS_DEBUG
+ if (trans->iters_live) {
+ struct btree_iter *iter;
+
+ bch_err(c, "btree iterators leaked!");
+ trans_for_each_iter(trans, iter)
+ if (btree_iter_live(trans, iter))
+ printk(KERN_ERR " btree %s allocated at %pS\n",
+ bch2_btree_ids[iter->btree_id],
+ (void *) iter->ip_allocated);
+ /* Be noisy about this: */
+ bch2_fatal_error(c);
+ }
+
mutex_lock(&trans->c->btree_trans_lock);
list_del(&trans->list);
mutex_unlock(&trans->c->btree_trans_lock);
struct bkey_s_c bch2_btree_iter_peek_cached(struct btree_iter *);
+bool bch2_btree_iter_advance_pos(struct btree_iter *);
+bool bch2_btree_iter_rewind_pos(struct btree_iter *);
void bch2_btree_iter_set_pos(struct btree_iter *, struct bpos);
/* Sort order for locking btree iterators: */
(iter->flags & BTREE_ITER_KEEP_UNTIL_COMMIT);
}
+static inline void set_btree_iter_dontneed(struct btree_trans *trans, struct btree_iter *iter)
+{
+ trans->iters_touched &= ~(1ULL << iter->idx);
+}
+
#define TRANS_RESET_NOTRAVERSE (1 << 0)
void bch2_trans_reset(struct btree_trans *, unsigned);
ck->key.pos, BTREE_ITER_SLOTS);
k = bch2_btree_iter_peek_slot(iter);
ret = bkey_err(k);
- if (ret) {
- bch2_trans_iter_put(trans, iter);
- return ret;
- }
+ if (ret)
+ goto err;
if (!bch2_btree_node_relock(ck_iter, 0)) {
- bch2_trans_iter_put(trans, iter);
trace_transaction_restart_ip(trans->ip, _THIS_IP_);
- return -EINTR;
+ ret = -EINTR;
+ goto err;
}
if (k.k->u64s > ck->u64s) {
new_u64s = roundup_pow_of_two(k.k->u64s);
new_k = kmalloc(new_u64s * sizeof(u64), GFP_NOFS);
if (!new_k) {
- bch2_trans_iter_put(trans, iter);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto err;
}
}
bch2_btree_node_unlock_write(ck_iter->l[0].b, ck_iter);
/* We're not likely to need this iterator again: */
- bch2_trans_iter_free(trans, iter);
-
- return 0;
+ set_btree_iter_dontneed(trans, iter);
+err:
+ bch2_trans_iter_put(trans, iter);
+ return ret;
}
static int bkey_cached_check_fn(struct six_lock *lock, void *p)
u16 written;
u8 nsets;
u8 nr_key_bits;
+ u16 version_ondisk;
struct bkey_format format;
bch2_bset_init_first(b, &b->data->keys);
b->c.level = level;
b->c.btree_id = as->btree_id;
+ b->version_ondisk = c->sb.version;
memset(&b->nr, 0, sizeof(b->nr));
b->data->magic = cpu_to_le64(bset_magic(c));
enum btree_id btree_id,
struct bpos start, struct bpos end)
{
- struct btree_iter *iter = NULL, *update_iter;
+ struct btree_iter *iter, *update_iter;
struct bkey_i *update;
struct bkey_s_c k;
int ret = 0;
break;
if (bkey_cmp(bkey_start_pos(k.k), start) < 0) {
- update_iter = bch2_trans_copy_iter(trans, iter);
-
update = bch2_trans_kmalloc(trans, bkey_bytes(k.k));
if ((ret = PTR_ERR_OR_ZERO(update)))
goto err;
bkey_reassemble(update, k);
bch2_cut_back(start, update);
+ update_iter = bch2_trans_copy_iter(trans, iter);
update_iter->flags &= ~BTREE_ITER_IS_EXTENTS;
bch2_btree_iter_set_pos(update_iter, update->k.p);
ret = bch2_trans_update2(trans, update_iter, update);
}
if (bkey_cmp(k.k->p, end) > 0) {
- update_iter = bch2_trans_copy_iter(trans, iter);
-
update = bch2_trans_kmalloc(trans, bkey_bytes(k.k));
if ((ret = PTR_ERR_OR_ZERO(update)))
goto err;
bkey_reassemble(update, k);
bch2_cut_front(end, update);
+ update_iter = bch2_trans_copy_iter(trans, iter);
update_iter->flags &= ~BTREE_ITER_IS_EXTENTS;
bch2_btree_iter_set_pos(update_iter, update->k.p);
ret = bch2_trans_update2(trans, update_iter, update);
if (ret)
goto err;
} else {
- update_iter = bch2_trans_copy_iter(trans, iter);
-
update = bch2_trans_kmalloc(trans, sizeof(struct bkey));
if ((ret = PTR_ERR_OR_ZERO(update)))
goto err;
update->k.type = KEY_TYPE_deleted;
update->k.size = 0;
+ update_iter = bch2_trans_copy_iter(trans, iter);
update_iter->flags &= ~BTREE_ITER_IS_EXTENTS;
bch2_btree_iter_set_pos(update_iter, update->k.p);
ret = bch2_trans_update2(trans, update_iter, update);
k = bch2_btree_iter_next_with_updates(iter);
}
err:
- if (!IS_ERR_OR_NULL(iter))
- bch2_trans_iter_put(trans, iter);
+ bch2_trans_iter_put(trans, iter);
return ret;
}
bkey_cmp(pos, i->k->k.p) < 0
: !bkey_cmp(pos, i->iter->pos))) {
*k = bkey_i_to_s_c(i->k);
+
+ /* ugly hack.. */
+ BUG_ON(btree_iter_live(trans, i->iter));
+ trans->iters_live |= 1ULL << i->iter->idx;
return i->iter;
}
if (!i->size)
break;
}
+ bch2_trans_iter_put(&trans, iter);
+
bch2_trans_exit(&trans);
return err < 0 ? err : i->ret;
if (!i->size)
break;
}
+ bch2_trans_iter_put(&trans, iter);
+
bch2_trans_exit(&trans);
return err < 0 ? err : i->ret;
k = bch2_btree_iter_peek_slot(iter);
inum = le64_to_cpu(bkey_s_c_to_dirent(k).v->d_inum);
+ bch2_trans_iter_put(&trans, iter);
out:
bch2_trans_exit(&trans);
return inum;
break;
ctx->pos = dirent.k->p.offset + 1;
}
+ bch2_trans_iter_put(&trans, iter);
+
ret = bch2_trans_exit(&trans) ?: ret;
return ret;
int ret = 0;
bch2_trans_init(&trans, c, 0, 0);
-
iter = bch2_trans_get_iter(&trans, BTREE_ID_stripes, POS(0, U64_MAX), 0);
k = bch2_btree_iter_prev(iter);
if (!IS_ERR_OR_NULL(k.k))
idx = k.k->p.offset + 1;
+
+ bch2_trans_iter_put(&trans, iter);
ret = bch2_trans_exit(&trans);
if (ret)
return ret;
return bch2_bkey_ptrs_invalid(c, k);
}
-void bch2_btree_ptr_debugcheck(struct bch_fs *c, struct bkey_s_c k)
-{
- struct bkey_ptrs_c ptrs = bch2_bkey_ptrs_c(k);
- const struct bch_extent_ptr *ptr;
- const char *err;
- char buf[160];
- struct bucket_mark mark;
- struct bch_dev *ca;
-
- if (!test_bit(BCH_FS_INITIAL_GC_DONE, &c->flags))
- return;
-
- if (!percpu_down_read_trylock(&c->mark_lock))
- return;
-
- bkey_for_each_ptr(ptrs, ptr) {
- ca = bch_dev_bkey_exists(c, ptr->dev);
-
- mark = ptr_bucket_mark(ca, ptr);
-
- err = "stale";
- if (gen_after(mark.gen, ptr->gen))
- goto err;
-
- err = "inconsistent";
- if (mark.data_type != BCH_DATA_btree ||
- mark.dirty_sectors < c->opts.btree_node_size)
- goto err;
- }
-out:
- percpu_up_read(&c->mark_lock);
- return;
-err:
- bch2_fs_inconsistent(c, "%s btree pointer %s: bucket %zi gen %i mark %08x",
- err, (bch2_bkey_val_to_text(&PBUF(buf), c, k), buf),
- PTR_BUCKET_NR(ca, ptr),
- mark.gen, (unsigned) mark.v.counter);
- goto out;
-}
-
void bch2_btree_ptr_to_text(struct printbuf *out, struct bch_fs *c,
struct bkey_s_c k)
{
return bch2_bkey_ptrs_invalid(c, k);
}
-void bch2_extent_debugcheck(struct bch_fs *c, struct bkey_s_c k)
-{
- struct bkey_s_c_extent e = bkey_s_c_to_extent(k);
- const union bch_extent_entry *entry;
- struct extent_ptr_decoded p;
- char buf[160];
-
- if (!test_bit(JOURNAL_REPLAY_DONE, &c->journal.flags) ||
- !test_bit(BCH_FS_INITIAL_GC_DONE, &c->flags))
- return;
-
- if (!percpu_down_read_trylock(&c->mark_lock))
- return;
-
- extent_for_each_ptr_decode(e, p, entry) {
- struct bch_dev *ca = bch_dev_bkey_exists(c, p.ptr.dev);
- struct bucket_mark mark = ptr_bucket_mark(ca, &p.ptr);
- unsigned stale = gen_after(mark.gen, p.ptr.gen);
- unsigned disk_sectors = ptr_disk_sectors(p);
- unsigned mark_sectors = p.ptr.cached
- ? mark.cached_sectors
- : mark.dirty_sectors;
-
- bch2_fs_inconsistent_on(stale && !p.ptr.cached, c,
- "stale dirty pointer (ptr gen %u bucket %u",
- p.ptr.gen, mark.gen);
-
- bch2_fs_inconsistent_on(stale > 96, c,
- "key too stale: %i", stale);
-
- bch2_fs_inconsistent_on(!stale &&
- (mark.data_type != BCH_DATA_user ||
- mark_sectors < disk_sectors), c,
- "extent pointer not marked: %s:\n"
- "type %u sectors %u < %u",
- (bch2_bkey_val_to_text(&PBUF(buf), c, e.s_c), buf),
- mark.data_type,
- mark_sectors, disk_sectors);
- }
-
- percpu_up_read(&c->mark_lock);
-}
-
void bch2_extent_to_text(struct printbuf *out, struct bch_fs *c,
struct bkey_s_c k)
{
break;
}
}
+ bch2_trans_iter_put(&trans, iter);
+
bch2_trans_exit(&trans);
return ret;
len = where.offset - bkey_start_offset(k.k);
- k.k->p = where;
+ k.k->p.offset = where.offset;
k.k->size = len;
if (!len) {
/* KEY_TYPE_btree_ptr: */
const char *bch2_btree_ptr_invalid(const struct bch_fs *, struct bkey_s_c);
-void bch2_btree_ptr_debugcheck(struct bch_fs *, struct bkey_s_c);
void bch2_btree_ptr_to_text(struct printbuf *, struct bch_fs *,
struct bkey_s_c);
#define bch2_bkey_ops_btree_ptr (struct bkey_ops) { \
.key_invalid = bch2_btree_ptr_invalid, \
- .key_debugcheck = bch2_btree_ptr_debugcheck, \
.val_to_text = bch2_btree_ptr_to_text, \
.swab = bch2_ptr_swab, \
}
#define bch2_bkey_ops_btree_ptr_v2 (struct bkey_ops) { \
.key_invalid = bch2_btree_ptr_invalid, \
- .key_debugcheck = bch2_btree_ptr_debugcheck, \
.val_to_text = bch2_btree_ptr_v2_to_text, \
.swab = bch2_ptr_swab, \
.compat = bch2_btree_ptr_v2_compat, \
/* KEY_TYPE_extent: */
const char *bch2_extent_invalid(const struct bch_fs *, struct bkey_s_c);
-void bch2_extent_debugcheck(struct bch_fs *, struct bkey_s_c);
void bch2_extent_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
enum merge_result bch2_extent_merge(struct bch_fs *,
struct bkey_s, struct bkey_s);
#define bch2_bkey_ops_extent (struct bkey_ops) { \
.key_invalid = bch2_extent_invalid, \
- .key_debugcheck = bch2_extent_debugcheck, \
.val_to_text = bch2_extent_to_text, \
.swab = bch2_ptr_swab, \
.key_normalize = bch2_extent_normalize, \
BUG_ON(ret);
bch2_trans_init(&trans, c, 0, 0);
-
iter = bch2_trans_get_iter(&trans, BTREE_ID_extents, POS_MIN,
BTREE_ITER_SLOTS);
bch2_pagecache_add_put(&inode->ei_pagecache_lock);
+ bch2_trans_iter_put(&trans, iter);
bch2_trans_exit(&trans);
kfree(readpages_iter.pages);
}
bchfs_read(&trans, iter, rbio, inum, NULL);
+ bch2_trans_iter_put(&trans, iter);
bch2_trans_exit(&trans);
}
break;
}
}
+ bch2_trans_iter_put(&trans, iter);
return bch2_trans_exit(&trans) ?: ret;
}
bch2_trans_init(&trans, c, 0, 0);
iter = bch2_inode_peek(&trans, &inode_u, inode->v.i_ino, 0);
ret = PTR_ERR_OR_ZERO(iter);
+ bch2_trans_iter_put(&trans, iter);
bch2_trans_exit(&trans);
if (ret)
struct btree_iter *src, *dst, *del;
loff_t shift, new_size;
u64 src_start;
- int ret;
+ int ret = 0;
if ((offset | len) & (block_bytes(c) - 1))
return -EINVAL;
- bch2_bkey_buf_init(©);
- bch2_trans_init(&trans, c, BTREE_ITER_MAX, 256);
-
/*
* We need i_mutex to keep the page cache consistent with the extents
* btree, and the btree consistent with i_size - we don't need outside
goto err;
}
+ bch2_bkey_buf_init(©);
+ bch2_trans_init(&trans, c, BTREE_ITER_MAX, 256);
src = bch2_trans_get_iter(&trans, BTREE_ID_extents,
POS(inode->v.i_ino, src_start >> 9),
BTREE_ITER_INTENT);
dst = bch2_trans_copy_iter(&trans, src);
del = bch2_trans_copy_iter(&trans, src);
- while (1) {
+ while (ret == 0 || ret == -EINTR) {
struct disk_reservation disk_res =
bch2_disk_reservation_init(c, 0);
struct bkey_i delete;
? bch2_btree_iter_peek_prev(src)
: bch2_btree_iter_peek(src);
if ((ret = bkey_err(k)))
- goto bkey_err;
+ continue;
if (!k.k || k.k->p.inode != inode->v.i_ino)
break;
ret = bch2_extent_atomic_end(dst, copy.k, &atomic_end);
if (ret)
- goto bkey_err;
+ continue;
if (bkey_cmp(atomic_end, copy.k->k.p)) {
if (insert) {
&inode->ei_journal_seq,
BTREE_INSERT_NOFAIL);
bch2_disk_reservation_put(c, &disk_res);
-bkey_err:
+
if (!ret)
bch2_btree_iter_set_pos(src, next_pos);
-
- if (ret == -EINTR)
- ret = 0;
- if (ret)
- goto err;
-
- bch2_trans_cond_resched(&trans);
}
- bch2_trans_unlock(&trans);
+ bch2_trans_iter_put(&trans, del);
+ bch2_trans_iter_put(&trans, dst);
+ bch2_trans_iter_put(&trans, src);
+ bch2_trans_exit(&trans);
+ bch2_bkey_buf_exit(©, c);
+
+ if (ret)
+ goto err;
if (!insert) {
i_size_write(&inode->v, new_size);
mutex_unlock(&inode->ei_update_lock);
}
err:
- bch2_trans_exit(&trans);
- bch2_bkey_buf_exit(©, c);
bch2_pagecache_block_put(&inode->ei_pagecache_lock);
inode_unlock(&inode->v);
return ret;
BTREE_ITER_SLOTS|BTREE_ITER_INTENT);
end_pos = POS(inode->v.i_ino, block_end >> 9);
- while (bkey_cmp(iter->pos, end_pos) < 0) {
+ while (!ret && bkey_cmp(iter->pos, end_pos) < 0) {
s64 i_sectors_delta = 0;
struct disk_reservation disk_res = { 0 };
struct quota_res quota_res = { 0 };
bch2_disk_reservation_put(c, &disk_res);
if (ret == -EINTR)
ret = 0;
- if (ret)
- goto err;
}
+ bch2_trans_iter_put(&trans, iter);
+
+ if (ret)
+ goto err;
/*
* Do we need to extend the file?
ret = PTR_ERR_OR_ZERO(inode_iter);
} while (ret == -EINTR);
+ bch2_trans_iter_put(&trans, inode_iter);
bch2_trans_unlock(&trans);
if (ret)
} else if (k.k->p.offset >> 9 > isize)
break;
}
+ bch2_trans_iter_put(&trans, iter);
ret = bch2_trans_exit(&trans) ?: ret;
if (ret)
offset = max(offset, bkey_start_offset(k.k) << 9);
}
}
+ bch2_trans_iter_put(&trans, iter);
ret = bch2_trans_exit(&trans) ?: ret;
if (ret)
BTREE_INSERT_NOUNLOCK|
BTREE_INSERT_NOFAIL);
btree_err:
+ bch2_trans_iter_put(&trans, inode_iter);
+
if (ret == -EINTR)
goto retry;
if (unlikely(ret))
ret = bch2_fill_extent(c, info, bkey_i_to_s_c(prev.k),
FIEMAP_EXTENT_LAST);
+ bch2_trans_iter_put(&trans, iter);
ret = bch2_trans_exit(&trans) ?: ret;
bch2_bkey_buf_exit(&cur, c);
bch2_bkey_buf_exit(&prev, c);
bch_err(c, "hash_redo_key err %i", ret);
return ret;
}
- return 1;
+ return -EINTR;
}
ret = hash_check_duplicates(trans, desc, h, k_iter, k);
goto err;
}
-static int bch2_inode_truncate(struct bch_fs *c, u64 inode_nr, u64 new_size)
-{
- return bch2_btree_delete_range(c, BTREE_ID_extents,
- POS(inode_nr, round_up(new_size, block_bytes(c)) >> 9),
- POS(inode_nr + 1, 0), NULL);
-}
-
-static int bch2_fix_overlapping_extent(struct btree_trans *trans,
- struct btree_iter *iter,
+static int fix_overlapping_extent(struct btree_trans *trans,
struct bkey_s_c k, struct bpos cut_at)
{
- struct btree_iter *u_iter;
+ struct btree_iter *iter;
struct bkey_i *u;
int ret;
bkey_reassemble(u, k);
bch2_cut_front(cut_at, u);
- u_iter = bch2_trans_copy_iter(trans, iter);
/*
- * We don't want to go through the
- * extent_handle_overwrites path:
+ * We don't want to go through the extent_handle_overwrites path:
+ *
+ * XXX: this is going to screw up disk accounting, extent triggers
+ * assume things about extent overwrites - we should be running the
+ * triggers manually here
*/
- u_iter->flags &= ~BTREE_ITER_IS_EXTENTS;
- bch2_btree_iter_set_pos(u_iter, u->k.p);
+ iter = bch2_trans_get_iter(trans, BTREE_ID_extents, u->k.p,
+ BTREE_ITER_INTENT|BTREE_ITER_NOT_EXTENTS);
- /*
- * XXX: this is going to leave disk space
- * accounting slightly wrong
- */
- ret = bch2_trans_update(trans, u_iter, u, 0);
- bch2_trans_iter_put(trans, u_iter);
- return ret;
+ BUG_ON(iter->flags & BTREE_ITER_IS_EXTENTS);
+ bch2_trans_update(trans, iter, u, BTREE_TRIGGER_NORUN);
+ bch2_trans_iter_put(trans, iter);
+
+ return bch2_trans_commit(trans, NULL, NULL,
+ BTREE_INSERT_NOFAIL|
+ BTREE_INSERT_LAZY_RW);
}
/*
struct btree_iter *iter;
struct bkey_s_c k;
struct bkey_buf prev;
- u64 i_sectors;
+ u64 i_sectors = 0;
int ret = 0;
bch2_bkey_buf_init(&prev);
POS(BCACHEFS_ROOT_INO, 0),
BTREE_ITER_INTENT);
retry:
- for_each_btree_key_continue(iter, 0, k, ret) {
- /*
- * due to retry errors we might see the same extent twice:
- */
- if (bkey_cmp(prev.k->k.p, k.k->p) &&
- bkey_cmp(prev.k->k.p, bkey_start_pos(k.k)) > 0) {
+ while ((k = bch2_btree_iter_peek(iter)).k &&
+ !(ret = bkey_err(k))) {
+ if (w.have_inode &&
+ w.cur_inum != k.k->p.inode &&
+ !(w.inode.bi_flags & BCH_INODE_I_SECTORS_DIRTY) &&
+ fsck_err_on(w.inode.bi_sectors != i_sectors, c,
+ "inode %llu has incorrect i_sectors: got %llu, should be %llu",
+ w.inode.bi_inum,
+ w.inode.bi_sectors, i_sectors)) {
+ struct btree_iter *inode_iter =
+ bch2_trans_get_iter(&trans, BTREE_ID_inodes,
+ POS(0, w.cur_inum),
+ BTREE_ITER_INTENT);
+
+ w.inode.bi_sectors = i_sectors;
+
+ ret = __bch2_trans_do(&trans, NULL, NULL,
+ BTREE_INSERT_NOFAIL|
+ BTREE_INSERT_LAZY_RW,
+ bch2_inode_write(&trans, inode_iter, &w.inode));
+ bch2_trans_iter_put(&trans, inode_iter);
+ if (ret)
+ break;
+ }
+
+ if (bkey_cmp(prev.k->k.p, bkey_start_pos(k.k)) > 0) {
char buf1[200];
char buf2[200];
bch2_bkey_val_to_text(&PBUF(buf1), c, bkey_i_to_s_c(prev.k));
bch2_bkey_val_to_text(&PBUF(buf2), c, k);
- if (fsck_err(c, "overlapping extents:\n%s\n%s", buf1, buf2)) {
- ret = __bch2_trans_do(&trans, NULL, NULL,
- BTREE_INSERT_NOFAIL|
- BTREE_INSERT_LAZY_RW,
- bch2_fix_overlapping_extent(&trans,
- iter, k, prev.k->k.p));
- if (ret)
- goto err;
- }
+ if (fsck_err(c, "overlapping extents:\n%s\n%s", buf1, buf2))
+ return fix_overlapping_extent(&trans, k, prev.k->k.p) ?: -EINTR;
}
- bch2_bkey_buf_reassemble(&prev, c, k);
ret = walk_inode(&trans, &w, k.k->p.inode);
if (ret)
break;
+ if (w.first_this_inode)
+ i_sectors = 0;
+
if (fsck_err_on(!w.have_inode, c,
- "extent type %u for missing inode %llu",
- k.k->type, k.k->p.inode) ||
+ "extent type %u for missing inode %llu",
+ k.k->type, k.k->p.inode) ||
fsck_err_on(w.have_inode &&
- !S_ISREG(w.inode.bi_mode) && !S_ISLNK(w.inode.bi_mode), c,
- "extent type %u for non regular file, inode %llu mode %o",
- k.k->type, k.k->p.inode, w.inode.bi_mode)) {
- bch2_trans_unlock(&trans);
-
- ret = bch2_inode_truncate(c, k.k->p.inode, 0);
- if (ret)
- goto err;
- continue;
+ !S_ISREG(w.inode.bi_mode) && !S_ISLNK(w.inode.bi_mode), c,
+ "extent type %u for non regular file, inode %llu mode %o",
+ k.k->type, k.k->p.inode, w.inode.bi_mode)) {
+ bch2_fs_lazy_rw(c);
+ return bch2_btree_delete_range_trans(&trans, BTREE_ID_extents,
+ POS(k.k->p.inode, 0),
+ POS(k.k->p.inode, U64_MAX),
+ NULL) ?: -EINTR;
}
- if (fsck_err_on(w.first_this_inode &&
- w.have_inode &&
- !(w.inode.bi_flags & BCH_INODE_I_SECTORS_DIRTY) &&
- w.inode.bi_sectors !=
- (i_sectors = bch2_count_inode_sectors(&trans, w.cur_inum)),
- c, "inode %llu has incorrect i_sectors: got %llu, should be %llu",
- w.inode.bi_inum,
- w.inode.bi_sectors, i_sectors)) {
- struct bkey_inode_buf p;
-
- w.inode.bi_sectors = i_sectors;
-
- bch2_trans_unlock(&trans);
-
- bch2_inode_pack(c, &p, &w.inode);
-
- ret = bch2_btree_insert(c, BTREE_ID_inodes,
- &p.inode.k_i, NULL, NULL,
- BTREE_INSERT_NOFAIL|
- BTREE_INSERT_LAZY_RW);
- if (ret) {
- bch_err(c, "error in fsck: error %i updating inode", ret);
- goto err;
- }
-
- /* revalidate iterator: */
- k = bch2_btree_iter_peek(iter);
+ if (fsck_err_on(w.have_inode &&
+ !(w.inode.bi_flags & BCH_INODE_I_SIZE_DIRTY) &&
+ k.k->type != KEY_TYPE_reservation &&
+ k.k->p.offset > round_up(w.inode.bi_size, block_bytes(c)) >> 9, c,
+ "extent type %u offset %llu past end of inode %llu, i_size %llu",
+ k.k->type, k.k->p.offset, k.k->p.inode, w.inode.bi_size)) {
+ bch2_fs_lazy_rw(c);
+ return bch2_btree_delete_range_trans(&trans, BTREE_ID_extents,
+ POS(k.k->p.inode, round_up(w.inode.bi_size, block_bytes(c))),
+ POS(k.k->p.inode, U64_MAX),
+ NULL) ?: -EINTR;
}
- if (fsck_err_on(w.have_inode &&
- !(w.inode.bi_flags & BCH_INODE_I_SIZE_DIRTY) &&
- k.k->type != KEY_TYPE_reservation &&
- k.k->p.offset > round_up(w.inode.bi_size, block_bytes(c)) >> 9, c,
- "extent type %u offset %llu past end of inode %llu, i_size %llu",
- k.k->type, k.k->p.offset, k.k->p.inode, w.inode.bi_size)) {
- bch2_trans_unlock(&trans);
+ if (bkey_extent_is_allocation(k.k))
+ i_sectors += k.k->size;
+ bch2_bkey_buf_reassemble(&prev, c, k);
- ret = bch2_inode_truncate(c, k.k->p.inode,
- w.inode.bi_size);
- if (ret)
- goto err;
- continue;
- }
+ bch2_btree_iter_advance_pos(iter);
}
-err:
fsck_err:
if (ret == -EINTR)
goto retry;
+ bch2_trans_iter_put(&trans, iter);
bch2_bkey_buf_exit(&prev, c);
return bch2_trans_exit(&trans) ?: ret;
}
iter = bch2_trans_get_iter(&trans, BTREE_ID_dirents,
POS(BCACHEFS_ROOT_INO, 0), 0);
retry:
- for_each_btree_key_continue(iter, 0, k, ret) {
+ while ((k = bch2_btree_iter_peek(iter)).k &&
+ !(ret = bkey_err(k))) {
struct bkey_s_c_dirent d;
struct bch_inode_unpacked target;
bool have_target;
goto err;
}
+
+ bch2_btree_iter_advance_pos(iter);
}
hash_stop_chain(&trans, &h);
if (ret == -EINTR)
goto retry;
+ bch2_trans_iter_put(&trans, h.chain);
+ bch2_trans_iter_put(&trans, iter);
return bch2_trans_exit(&trans) ?: ret;
}
iter = bch2_trans_get_iter(&trans, BTREE_ID_xattrs,
POS(BCACHEFS_ROOT_INO, 0), 0);
retry:
- for_each_btree_key_continue(iter, 0, k, ret) {
+ while ((k = bch2_btree_iter_peek(iter)).k &&
+ !(ret = bkey_err(k))) {
ret = walk_inode(&trans, &w, k.k->p.inode);
if (ret)
break;
k.k->p.inode)) {
ret = bch2_btree_delete_at(&trans, iter, 0);
if (ret)
- goto err;
+ break;
continue;
}
ret = hash_check_key(&trans, bch2_xattr_hash_desc,
&h, iter, k);
if (ret)
- goto fsck_err;
+ break;
+
+ bch2_btree_iter_advance_pos(iter);
}
-err:
fsck_err:
if (ret == -EINTR)
goto retry;
+
+ bch2_trans_iter_put(&trans, h.chain);
+ bch2_trans_iter_put(&trans, iter);
return bch2_trans_exit(&trans) ?: ret;
}
bch2_trans_cond_resched(&trans);
}
+ bch2_trans_iter_put(&trans, iter);
+
ret = bch2_trans_exit(&trans) ?: ret;
if (ret)
bch_err(c, "error in fsck: btree error %i while walking dirents", ret);
* XXX: need to truncate partial blocks too here - or ideally
* just switch units to bytes and that issue goes away
*/
-
- ret = bch2_inode_truncate(c, u.bi_inum, u.bi_size);
+ ret = bch2_btree_delete_range_trans(trans, BTREE_ID_extents,
+ POS(u.bi_inum, round_up(u.bi_size, block_bytes(c))),
+ POS(u.bi_inum, U64_MAX),
+ NULL);
if (ret) {
bch_err(c, "error in fsck: error %i truncating inode", ret);
return ret;
if (nlinks_pos == iter->pos.offset)
genradix_iter_advance(&nlinks_iter, links);
- bch2_btree_iter_next(iter);
+ bch2_btree_iter_advance_pos(iter);
bch2_trans_cond_resched(&trans);
}
fsck_err:
+ bch2_trans_iter_put(&trans, iter);
bch2_trans_exit(&trans);
if (ret2)
BCH_INODE_I_SECTORS_DIRTY|
BCH_INODE_UNLINKED)) {
ret = check_inode(&trans, NULL, iter, inode, NULL);
- BUG_ON(ret == -EINTR);
if (ret)
break;
}
}
+ bch2_trans_iter_put(&trans, iter);
+
BUG_ON(ret == -EINTR);
return bch2_trans_exit(&trans) ?: ret;
ret = bch2_trans_commit(&trans, NULL, NULL,
BTREE_INSERT_NOFAIL);
+ bch2_trans_iter_put(&trans, iter);
err:
if (ret == -EINTR)
goto retry;
ret = bch2_fpunch_at(&trans, iter, POS(inum, end),
journal_seq, i_sectors_delta);
+
+ bch2_trans_iter_put(&trans, iter);
bch2_trans_exit(&trans);
if (ret == -EINTR)
bch2_keylist_pop_front(keys);
} while (!bch2_keylist_empty(keys));
+ bch2_trans_iter_put(&trans, iter);
bch2_trans_exit(&trans);
bch2_bkey_buf_exit(&sk, c);
goto err;
out:
bch2_rbio_done(rbio);
+ bch2_trans_iter_put(&trans, iter);
bch2_trans_exit(&trans);
bch2_bkey_buf_exit(&sk, c);
return;
k = bch2_btree_iter_peek_slot(iter);
ret = bkey_err(k);
if (ret)
- goto err;
+ break;
offset_into_extent = iter->pos.offset -
bkey_start_offset(k.k);
ret = bch2_read_indirect_extent(&trans, &data_btree,
&offset_into_extent, &sk);
if (ret)
- goto err;
+ break;
k = bkey_i_to_s_c(sk.k);
ret = __bch2_read_extent(&trans, rbio, bvec_iter, iter->pos,
data_btree, k,
offset_into_extent, failed, flags);
- switch (ret) {
- case READ_RETRY:
- goto retry;
- case READ_ERR:
- goto err;
- };
+ if (ret)
+ break;
if (flags & BCH_READ_LAST_FRAGMENT)
break;
swap(bvec_iter.bi_size, bytes);
bio_advance_iter(&rbio->bio, &bvec_iter, bytes);
}
-out:
- bch2_trans_exit(&trans);
- bch2_bkey_buf_exit(&sk, c);
- return;
-err:
- if (ret == -EINTR)
+ bch2_trans_iter_put(&trans, iter);
+
+ if (ret == -EINTR || ret == READ_RETRY || ret == READ_RETRY_AVOID)
goto retry;
- bch_err_inum_ratelimited(c, inode,
- "read error %i from btree lookup", ret);
- rbio->bio.bi_status = BLK_STS_IOERR;
- bch2_rbio_done(rbio);
- goto out;
+ if (ret) {
+ bch_err_inum_ratelimited(c, inode,
+ "read error %i from btree lookup", ret);
+ rbio->bio.bi_status = BLK_STS_IOERR;
+ bch2_rbio_done(rbio);
+ }
+ bch2_trans_exit(&trans);
+ bch2_bkey_buf_exit(&sk, c);
}
void bch2_fs_io_exit(struct bch_fs *c)
&c->rw_devs[BCH_DATA_journal]) {
struct journal_device *ja = &ca->journal;
+ if (!test_bit(ca->dev_idx, c->rw_devs[BCH_DATA_journal].d))
+ continue;
+
if (!ja->nr)
continue;
goto next;
}
out:
+ bch2_trans_iter_put(&trans, iter);
bch2_trans_exit(&trans);
bch2_bkey_buf_exit(&_insert, c);
bch2_bkey_buf_exit(&_new, c);
bch2_trans_cond_resched(&trans);
}
out:
+
+ bch2_trans_iter_put(&trans, iter);
ret = bch2_trans_exit(&trans) ?: ret;
bch2_bkey_buf_exit(&sk, c);
for_each_btree_node(&trans, iter, id,
id == start_btree_id ? start_pos : POS_MIN,
BTREE_ITER_PREFETCH, b) {
- if (kthread && (ret = kthread_should_stop()))
+ if (kthread && kthread_should_stop())
goto out;
if ((cmp_int(id, end_btree_id) ?:
struct bch_io_opts *io_opts,
struct data_opts *data_opts)
{
- if (!btree_node_need_rewrite(b))
- return DATA_SKIP;
+ if (b->version_ondisk != c->sb.version ||
+ btree_node_need_rewrite(b)) {
+ data_opts->target = 0;
+ data_opts->nr_replicas = 1;
+ data_opts->btree_insert_flags = 0;
+ return DATA_REWRITE;
+ }
- data_opts->target = 0;
- data_opts->nr_replicas = 1;
- data_opts->btree_insert_flags = 0;
- return DATA_REWRITE;
+ return DATA_SKIP;
}
int bch2_data_job(struct bch_fs *c,
ret = bch2_replicas_gc2(c) ?: ret;
break;
case BCH_DATA_OP_REWRITE_OLD_NODES:
-
ret = bch2_move_btree(c,
op.start_btree, op.start_pos,
op.end_btree, op.end_pos,
rewrite_old_nodes_pred, &op, stats) ?: ret;
+
+ if (!ret) {
+ mutex_lock(&c->sb_lock);
+ c->disk_sb.sb->version_min = c->disk_sb.sb->version;
+ bch2_write_super(c);
+ mutex_unlock(&c->sb_lock);
+ }
break;
default:
ret = -EINVAL;
goto err;
}
+ if (!c->sb.clean &&
+ !(c->sb.features & (1ULL << BCH_FEATURE_extents_above_btree_updates))) {
+ bch_err(c, "filesystem needs recovery from older version; run fsck from older bcachefs-tools to fix");
+ ret = -EINVAL;
+ goto err;
+ }
+
if (!(c->sb.features & (1ULL << BCH_FEATURE_alloc_v2))) {
bch_info(c, "alloc_v2 feature bit not set, fsck required");
c->opts.fsck = true;
c->opts.fix_errors = FSCK_OPT_YES;
- c->disk_sb.sb->features[0] |= 1ULL << BCH_FEATURE_alloc_v2;
}
if (!c->replicas.entries ||
blacklist_seq = journal_seq = le64_to_cpu(clean->journal_seq) + 1;
}
- if (!c->sb.clean &&
- !(c->sb.features & (1ULL << BCH_FEATURE_extents_above_btree_updates))) {
- bch_err(c, "filesystem needs recovery from older version; run fsck from older bcachefs-tools to fix");
- ret = -EINVAL;
- goto err;
- }
-
if (c->opts.reconstruct_alloc) {
c->sb.compat &= ~(1ULL << BCH_COMPAT_FEAT_ALLOC_INFO);
drop_alloc_keys(&c->journal_keys);
}
mutex_lock(&c->sb_lock);
- if (c->opts.version_upgrade) {
- if (c->sb.version < bcachefs_metadata_version_new_versioning)
- c->disk_sb.sb->version_min =
- le16_to_cpu(bcachefs_metadata_version_min);
- c->disk_sb.sb->version = le16_to_cpu(bcachefs_metadata_version_current);
- c->disk_sb.sb->features[0] |= BCH_SB_FEATURES_ALL;
- write_sb = true;
- }
-
if (!test_bit(BCH_FS_ERROR, &c->flags)) {
c->disk_sb.sb->compat[0] |= 1ULL << BCH_COMPAT_FEAT_ALLOC_INFO;
write_sb = true;
bch2_mark_dev_superblock(c, ca, 0);
mutex_unlock(&c->sb_lock);
- mutex_lock(&c->sb_lock);
- c->disk_sb.sb->version = c->disk_sb.sb->version_min =
- le16_to_cpu(bcachefs_metadata_version_current);
- c->disk_sb.sb->features[0] |= 1ULL << BCH_FEATURE_atomic_nlink;
- c->disk_sb.sb->features[0] |= BCH_SB_FEATURES_ALL;
-
- bch2_write_super(c);
- mutex_unlock(&c->sb_lock);
-
set_bit(BCH_FS_ALLOC_READ_DONE, &c->flags);
set_bit(BCH_FS_INITIAL_GC_DONE, &c->flags);
dst_iter = bch2_trans_get_iter(&trans, BTREE_ID_extents, dst_start,
BTREE_ITER_INTENT);
- while (1) {
+ while (ret == 0 || ret == -EINTR) {
bch2_trans_begin(&trans);
- trans.mem_top = 0;
-
if (fatal_signal_pending(current)) {
ret = -EINTR;
- goto err;
+ break;
}
src_k = get_next_src(src_iter, src_end);
ret = bkey_err(src_k);
if (ret)
- goto btree_err;
+ continue;
src_done = bpos_min(src_iter->pos, src_end).offset -
src_start.offset;
if (bkey_cmp(dst_iter->pos, dst_want) < 0) {
ret = bch2_fpunch_at(&trans, dst_iter, dst_want,
journal_seq, i_sectors_delta);
- if (ret)
- goto btree_err;
continue;
}
ret = bch2_make_extent_indirect(&trans, src_iter,
new_src.k);
if (ret)
- goto btree_err;
+ continue;
BUG_ON(src_k.k->type != KEY_TYPE_reflink_p);
}
NULL, journal_seq,
new_i_size, i_sectors_delta);
if (ret)
- goto btree_err;
+ continue;
dst_done = dst_iter->pos.offset - dst_start.offset;
src_want = POS(src_start.inode, src_start.offset + dst_done);
bch2_btree_iter_set_pos(src_iter, src_want);
-btree_err:
- if (ret == -EINTR)
- ret = 0;
- if (ret)
- goto err;
}
+ bch2_trans_iter_put(&trans, dst_iter);
+ bch2_trans_iter_put(&trans, src_iter);
- BUG_ON(bkey_cmp(dst_iter->pos, dst_end));
-err:
+ BUG_ON(!ret && bkey_cmp(dst_iter->pos, dst_end));
BUG_ON(bkey_cmp(dst_iter->pos, dst_end) > 0);
dst_done = dst_iter->pos.offset - dst_start.offset;
ret2 = bch2_inode_write(&trans, inode_iter, &inode_u) ?:
bch2_trans_commit(&trans, NULL, journal_seq, 0);
}
+
+ bch2_trans_iter_put(&trans, inode_iter);
} while (ret2 == -EINTR);
ret = bch2_trans_exit(&trans) ?: ret;
c->sb.uuid = src->uuid;
c->sb.user_uuid = src->user_uuid;
c->sb.version = le16_to_cpu(src->version);
+ c->sb.version_min = le16_to_cpu(src->version_min);
c->sb.nr_devices = src->nr_devices;
c->sb.clean = BCH_SB_CLEAN(src);
c->sb.encryption_type = BCH_SB_ENCRYPTION_TYPE(src);
*/
mutex_lock(&c->sb_lock);
+ if (c->opts.version_upgrade) {
+ c->disk_sb.sb->version = le16_to_cpu(bcachefs_metadata_version_current);
+ c->disk_sb.sb->features[0] |= BCH_SB_FEATURES_ALL;
+ }
+
SET_BCH_SB_CLEAN(c->disk_sb.sb, false);
c->disk_sb.sb->features[0] |= BCH_SB_FEATURES_ALWAYS;
ret = bch2_write_super(c);
(!early || c->opts.read_only)))
return -EROFS;
+ bch_info(c, "going read-write");
+
ret = bch2_fs_mark_dirty(c);
if (ret)
goto err;
inode->v.i_ino,
&X_SEARCH(type, name, strlen(name)),
0);
- if (IS_ERR(iter)) {
- bch2_trans_exit(&trans);
- BUG_ON(PTR_ERR(iter) == -EINTR);
-
- return PTR_ERR(iter) == -ENOENT ? -ENODATA : PTR_ERR(iter);
- }
+ ret = PTR_ERR_OR_ZERO(iter);
+ if (ret)
+ goto err;
xattr = bkey_s_c_to_xattr(bch2_btree_iter_peek_slot(iter));
ret = le16_to_cpu(xattr.v->x_val_len);
else
memcpy(buffer, xattr_val(xattr.v), ret);
}
-
+ bch2_trans_iter_put(&trans, iter);
+err:
bch2_trans_exit(&trans);
- return ret;
+
+ BUG_ON(ret == -EINTR);
+ return ret == -ENOENT ? -ENODATA : ret;
}
int bch2_xattr_set(struct btree_trans *trans, u64 inum,
if (ret)
break;
}
+ bch2_trans_iter_put(&trans, iter);
+
ret = bch2_trans_exit(&trans) ?: ret;
if (ret)