-a5c0e1bb306e79b40b2432a22f164697c8b22110
+b6d54265513ceb7532e3983163338c1ad28a0284
ret = bch2_alloc_write_key(&trans, iter, flags);
if (ret) {
- percpu_ref_put(&ca->io_ref);
+ percpu_ref_put(&ca->ref);
goto err;
}
bch2_btree_iter_next_slot(iter);
static int bch2_gc_done(struct bch_fs *c,
bool initial, bool metadata_only)
{
- struct bch_dev *ca;
+ struct bch_dev *ca = NULL;
bool verify = !metadata_only && (!initial ||
(c->sb.compat & (1ULL << BCH_COMPAT_alloc_info)));
unsigned i, dev;
#undef copy_stripe_field
#undef copy_field
fsck_err:
+ if (ca)
+ percpu_ref_put(&ca->ref);
if (ret)
bch_err(c, "%s: ret %i", __func__, ret);
return ret;
static int bch2_gc_start(struct bch_fs *c,
bool metadata_only)
{
- struct bch_dev *ca;
+ struct bch_dev *ca = NULL;
unsigned i;
int ret;
/* bch2_varint_decode may read up to 7 bytes past the end of the buffer: */
bytes += 8;
+ /* buffer must be a multiple of the block size */
+ bytes = round_up(bytes, block_bytes(c));
+
data = btree_bounce_alloc(c, bytes, &used_mempool);
if (!b->written) {
static inline struct bkey_s_c __btree_iter_peek(struct btree_iter *iter, bool with_updates)
{
struct bpos search_key = btree_iter_search_key(iter);
- struct bkey_i *next_update = with_updates
- ? btree_trans_peek_updates(iter->trans, iter->btree_id, search_key)
- : NULL;
+ struct bkey_i *next_update;
struct bkey_s_c k;
int ret;
EBUG_ON(btree_iter_type(iter) != BTREE_ITER_KEYS);
bch2_btree_iter_verify(iter);
bch2_btree_iter_verify_entry_exit(iter);
-
+start:
+ next_update = with_updates
+ ? btree_trans_peek_updates(iter->trans, iter->btree_id, search_key)
+ : NULL;
btree_iter_set_search_pos(iter, search_key);
while (1) {
if (likely(k.k)) {
if (bkey_deleted(k.k)) {
- btree_iter_set_search_pos(iter,
- bkey_successor(iter, k.k->p));
- continue;
+ search_key = bkey_successor(iter, k.k->p);
+ goto start;
}
break;
}
}
+static bool reflink_p_frag_references(struct bkey_s_c_reflink_p p,
+ u64 start, u64 end,
+ struct bkey_s_c k)
+{
+ if (start == end)
+ return false;
+
+ start += le64_to_cpu(p.v->idx);
+ end += le64_to_cpu(p.v->idx);
+
+ if (end <= bkey_start_offset(k.k))
+ return false;
+ if (start >= k.k->p.offset)
+ return false;
+ return true;
+}
+
static int __bch2_trans_mark_reflink_p(struct btree_trans *trans,
struct bkey_s_c_reflink_p p,
u64 idx, unsigned sectors,
+ unsigned front_frag,
+ unsigned back_frag,
unsigned flags)
{
struct bch_fs *c = trans->c;
struct bkey_s_c k;
struct bkey_i *n;
__le64 *refcount;
+ int add = !(flags & BTREE_TRIGGER_OVERWRITE) ? 1 : -1;
s64 ret;
ret = trans_get_key(trans, BTREE_ID_reflink,
if (ret < 0)
return ret;
- if ((flags & BTREE_TRIGGER_OVERWRITE) &&
- (bkey_start_offset(k.k) < idx ||
- k.k->p.offset > idx + sectors))
+ if (reflink_p_frag_references(p, 0, front_frag, k) &&
+ reflink_p_frag_references(p, back_frag, p.k->size, k)) {
+ BUG_ON(!(flags & BTREE_TRIGGER_OVERWRITE_SPLIT));
+ add = -add;
+ } else if (reflink_p_frag_references(p, 0, front_frag, k) ||
+ reflink_p_frag_references(p, back_frag, p.k->size, k)) {
+ BUG_ON(!(flags & BTREE_TRIGGER_OVERWRITE));
goto out;
+ }
- sectors = k.k->p.offset - idx;
+ sectors = min_t(u64, sectors, k.k->p.offset - idx);
n = bch2_trans_kmalloc(trans, bkey_bytes(k.k));
ret = PTR_ERR_OR_ZERO(n);
goto err;
}
- le64_add_cpu(refcount, !(flags & BTREE_TRIGGER_OVERWRITE) ? 1 : -1);
+ BUG_ON(!*refcount && (flags & BTREE_TRIGGER_OVERWRITE));
+ le64_add_cpu(refcount, add);
if (!*refcount) {
n->k.type = KEY_TYPE_deleted;
s64 sectors, unsigned flags)
{
u64 idx = le64_to_cpu(p.v->idx) + offset;
+ unsigned front_frag, back_frag;
s64 ret = 0;
sectors = abs(sectors);
BUG_ON(offset + sectors > p.k->size);
+ front_frag = offset;
+ back_frag = offset + sectors;
+
while (sectors) {
- ret = __bch2_trans_mark_reflink_p(trans, p, idx, sectors, flags);
+ ret = __bch2_trans_mark_reflink_p(trans, p, idx, sectors,
+ front_frag, back_frag, flags);
if (ret < 0)
break;
int bch2_trans_mark_dev_sb(struct bch_fs *c, struct bch_dev *ca)
{
- return bch2_trans_do(c, NULL, NULL, 0,
+ return bch2_trans_do(c, NULL, NULL, BTREE_INSERT_LAZY_RW,
__bch2_trans_mark_dev_sb(&trans, ca));
}
if (k.k->type != KEY_TYPE_reflink_v &&
k.k->type != KEY_TYPE_indirect_inline_data) {
bch_err_inum_ratelimited(trans->c, orig_k->k->k.p.inode,
- "pointer to nonexistent indirect extent");
+ "%llu len %u points to nonexistent indirect extent %llu",
+ orig_k->k->k.p.offset,
+ orig_k->k->k.size,
+ reflink_offset);
bch2_inconsistent_error(trans->c);
ret = -EIO;
goto err;
* Hence, we want update/set last_seq on the current journal entry right
* before we open a new one:
*/
- buf->data->last_seq = cpu_to_le64(journal_last_seq(j));
+ buf->last_seq = journal_last_seq(j);
+ buf->data->last_seq = cpu_to_le64(buf->last_seq);
__bch2_journal_pin_put(j, le64_to_cpu(buf->data->seq));
bch2_bkey_devs(bkey_i_to_s_c(&w->key));
struct bch_replicas_padded replicas;
union journal_res_state old, new;
- u64 v, seq, last_seq;
+ u64 v, seq;
int err = 0;
bch2_time_stats_update(j->write_time, j->write_start_time);
spin_lock(&j->lock);
seq = le64_to_cpu(w->data->seq);
- last_seq = le64_to_cpu(w->data->last_seq);
if (seq >= j->pin.front)
journal_seq_pin(j, seq)->devs = devs;
if (!JSET_NO_FLUSH(w->data)) {
j->flushed_seq_ondisk = seq;
- j->last_seq_ondisk = last_seq;
+ j->last_seq_ondisk = w->last_seq;
}
/*
test_bit(JOURNAL_MAY_SKIP_FLUSH, &j->flags)) {
w->noflush = true;
SET_JSET_NO_FLUSH(jset, true);
- jset->last_seq = 0;
+ jset->last_seq = w->last_seq = 0;
j->nr_noflush_writes++;
} else {
__BKEY_PADDED(key, BCH_REPLICAS_MAX);
struct closure_waitlist wait;
+ u64 last_seq; /* copy of data->last_seq */
unsigned buf_size; /* size in bytes of @data */
unsigned sectors; /* maximum size for current entry */
err = "error marking superblock and journal";
for_each_member_device(ca, c, i) {
ret = bch2_trans_mark_dev_sb(c, ca);
- if (ret)
+ if (ret) {
+ percpu_ref_put(&ca->ref);
goto err;
+ }
}
bch2_inode_init(c, &root_inode, 0, 0,
+++ /dev/null
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _BCACHEFS_S128_H
-#define _BCACHEFS_S128_H
-
-#include <linux/math64.h>
-
-typedef struct {
- s64 lo;
- s64 hi;
-} s128;
-
-typedef struct {
- s64 lo;
- s32 hi;
-} s96;
-
-static inline s128 s128_mul(s128 a, s128 b)
-{
- return a.lo
-
-}
-
-static inline s96 s96_mul(s96 a, s96 b)
-{
- return a.lo
-
-}
-
-#endif /* _BCACHEFS_S128_H */
down_write(&c->state_lock);
err = "error creating sysfs objects";
- __for_each_member_device(ca, c, i, NULL)
- if (bch2_dev_sysfs_online(c, ca))
+ for_each_member_device(ca, c, i)
+ if (bch2_dev_sysfs_online(c, ca)) {
+ percpu_ref_put(&ca->ref);
goto err;
+ }
list_add(&c->list, &bch_fs_list);
err = NULL;
if (ret)
return ERR_PTR(ret);
- for_each_member_device(ca, c, i)
+ rcu_read_lock();
+ for_each_member_device_rcu(ca, c, i, NULL)
if (ca->disk_sb.bdev->bd_dev == dev)
goto found;
-
ca = ERR_PTR(-ENOENT);
found:
+ rcu_read_unlock();
+
return ca;
}
return ca;
}
-#define __for_each_member_device(ca, c, iter, mask) \
- for ((iter) = 0; ((ca) = __bch2_next_dev((c), &(iter), mask)); (iter)++)
-
#define for_each_member_device_rcu(ca, c, iter, mask) \
- __for_each_member_device(ca, c, iter, mask)
+ for ((iter) = 0; ((ca) = __bch2_next_dev((c), &(iter), mask)); (iter)++)
static inline struct bch_dev *bch2_get_next_dev(struct bch_fs *c, unsigned *iter)
{