Skip to content

Commit 18443cb

Browse files
koverstreetKent Overstreet
authored andcommitted
bcachefs: Update data move path for snapshots
The data move path operates on existing extents, and not within a subvolume as the regular IO paths do. It needs to change because it may cause existing extents to be split, and when splitting an existing extent in an ancestor snapshot we need to make sure the new split has the same visibility in child snapshots as the existing extent. Signed-off-by: Kent Overstreet <[email protected]>
1 parent 7a7d17b commit 18443cb

File tree

6 files changed

+195
-49
lines changed

6 files changed

+195
-49
lines changed

fs/bcachefs/btree_update_leaf.c

Lines changed: 70 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -941,6 +941,43 @@ int __bch2_trans_commit(struct btree_trans *trans)
941941
goto retry;
942942
}
943943

944+
static int check_pos_snapshot_overwritten(struct btree_trans *trans,
945+
enum btree_id id,
946+
struct bpos pos)
947+
{
948+
struct bch_fs *c = trans->c;
949+
struct btree_iter iter;
950+
struct bkey_s_c k;
951+
int ret;
952+
953+
if (!snapshot_t(c, pos.snapshot)->children[0])
954+
return 0;
955+
956+
bch2_trans_iter_init(trans, &iter, id, pos,
957+
BTREE_ITER_NOT_EXTENTS|
958+
BTREE_ITER_ALL_SNAPSHOTS);
959+
while (1) {
960+
k = bch2_btree_iter_prev(&iter);
961+
ret = bkey_err(k);
962+
if (ret)
963+
break;
964+
965+
if (!k.k)
966+
break;
967+
968+
if (bkey_cmp(pos, k.k->p))
969+
break;
970+
971+
if (bch2_snapshot_is_ancestor(c, k.k->p.snapshot, pos.snapshot)) {
972+
ret = 1;
973+
break;
974+
}
975+
}
976+
bch2_trans_iter_exit(trans, &iter);
977+
978+
return ret;
979+
}
980+
944981
static noinline int extent_front_merge(struct btree_trans *trans,
945982
struct btree_iter *iter,
946983
struct bkey_s_c k,
@@ -958,14 +995,40 @@ static noinline int extent_front_merge(struct btree_trans *trans,
958995

959996
bkey_reassemble(update, k);
960997

961-
if (bch2_bkey_merge(c, bkey_i_to_s(update), bkey_i_to_s_c(*insert))) {
962-
ret = bch2_btree_delete_at(trans, iter, flags);
963-
if (ret)
964-
return ret;
998+
if (!bch2_bkey_merge(c, bkey_i_to_s(update), bkey_i_to_s_c(*insert)))
999+
return 0;
9651000

966-
*insert = update;
967-
}
1001+
ret = check_pos_snapshot_overwritten(trans, iter->btree_id, k.k->p) ?:
1002+
check_pos_snapshot_overwritten(trans, iter->btree_id, (*insert)->k.p);
1003+
if (ret < 0)
1004+
return ret;
1005+
if (ret)
1006+
return 0;
1007+
1008+
ret = bch2_btree_delete_at(trans, iter, flags);
1009+
if (ret)
1010+
return ret;
1011+
1012+
*insert = update;
1013+
return 0;
1014+
}
1015+
1016+
static noinline int extent_back_merge(struct btree_trans *trans,
1017+
struct btree_iter *iter,
1018+
struct bkey_i *insert,
1019+
struct bkey_s_c k)
1020+
{
1021+
struct bch_fs *c = trans->c;
1022+
int ret;
1023+
1024+
ret = check_pos_snapshot_overwritten(trans, iter->btree_id, insert->k.p) ?:
1025+
check_pos_snapshot_overwritten(trans, iter->btree_id, k.k->p);
1026+
if (ret < 0)
1027+
return ret;
1028+
if (ret)
1029+
return 0;
9681030

1031+
bch2_bkey_merge(c, bkey_i_to_s(insert), k);
9691032
return 0;
9701033
}
9711034

@@ -974,7 +1037,6 @@ static int bch2_trans_update_extent(struct btree_trans *trans,
9741037
struct bkey_i *insert,
9751038
enum btree_update_flags flags)
9761039
{
977-
struct bch_fs *c = trans->c;
9781040
struct btree_iter iter, update_iter;
9791041
struct bpos start = bkey_start_pos(&insert->k);
9801042
struct bkey_i *update;
@@ -1002,9 +1064,6 @@ static int bch2_trans_update_extent(struct btree_trans *trans,
10021064
goto next;
10031065
}
10041066

1005-
if (!bkey_cmp(k.k->p, start))
1006-
goto next;
1007-
10081067
while (bkey_cmp(insert->k.p, bkey_start_pos(k.k)) > 0) {
10091068
bool front_split = bkey_cmp(bkey_start_pos(k.k), start) < 0;
10101069
bool back_split = bkey_cmp(k.k->p, insert->k.p) > 0;
@@ -1120,7 +1179,7 @@ static int bch2_trans_update_extent(struct btree_trans *trans,
11201179
}
11211180

11221181
if (bch2_bkey_maybe_mergable(&insert->k, k.k))
1123-
bch2_bkey_merge(c, bkey_i_to_s(insert), k);
1182+
extent_back_merge(trans, &iter, insert, k);
11241183
out:
11251184
if (!bkey_deleted(&insert->k)) {
11261185
/*

fs/bcachefs/fsck.c

Lines changed: 1 addition & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -473,24 +473,6 @@ static int remove_backpointer(struct btree_trans *trans,
473473
return ret;
474474
}
475475

476-
struct snapshots_seen {
477-
struct bpos pos;
478-
size_t nr;
479-
size_t size;
480-
u32 *d;
481-
};
482-
483-
static void snapshots_seen_exit(struct snapshots_seen *s)
484-
{
485-
kfree(s->d);
486-
s->d = NULL;
487-
}
488-
489-
static void snapshots_seen_init(struct snapshots_seen *s)
490-
{
491-
memset(s, 0, sizeof(*s));
492-
}
493-
494476
static int snapshots_seen_update(struct bch_fs *c, struct snapshots_seen *s, struct bpos pos)
495477
{
496478
pos.snapshot = snapshot_t(c, pos.snapshot)->equiv;
@@ -499,26 +481,11 @@ static int snapshots_seen_update(struct bch_fs *c, struct snapshots_seen *s, str
499481
s->nr = 0;
500482
s->pos = pos;
501483

502-
if (s->nr == s->size) {
503-
size_t new_size = max(s->size, 128UL) * 2;
504-
u32 *d = krealloc(s->d, new_size * sizeof(s->d[0]), GFP_KERNEL);
505-
506-
if (!d) {
507-
bch_err(c, "error reallocating snapshots_seen table (new size %zu)",
508-
new_size);
509-
return -ENOMEM;
510-
}
511-
512-
s->size = new_size;
513-
s->d = d;
514-
}
515-
516484
/* Might get called multiple times due to lock restarts */
517485
if (s->nr && s->d[s->nr - 1] == pos.snapshot)
518486
return 0;
519487

520-
s->d[s->nr++] = pos.snapshot;
521-
return 0;
488+
return snapshots_seen_add(c, s, pos.snapshot);
522489
}
523490

524491
/**

fs/bcachefs/io.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1828,7 +1828,8 @@ static int __bch2_rbio_narrow_crcs(struct btree_trans *trans,
18281828
if (!bch2_bkey_narrow_crcs(new, new_crc))
18291829
goto out;
18301830

1831-
ret = bch2_trans_update(trans, &iter, new, 0);
1831+
ret = bch2_trans_update(trans, &iter, new,
1832+
BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE);
18321833
out:
18331834
bch2_trans_iter_exit(trans, &iter);
18341835
return ret;

fs/bcachefs/migrate.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ static int __bch2_dev_usrdata_drop(struct bch_fs *c, unsigned dev_idx, int flags
4848
bch2_trans_init(&trans, c, BTREE_ITER_MAX, 0);
4949

5050
bch2_trans_iter_init(&trans, &iter, btree_id, POS_MIN,
51-
BTREE_ITER_PREFETCH);
51+
BTREE_ITER_PREFETCH|
52+
BTREE_ITER_ALL_SNAPSHOTS);
5253

5354
while ((k = bch2_btree_iter_peek(&iter)).k &&
5455
!(ret = bkey_err(k))) {
@@ -74,7 +75,8 @@ static int __bch2_dev_usrdata_drop(struct bch_fs *c, unsigned dev_idx, int flags
7475
bch2_btree_iter_set_pos(&iter, bkey_start_pos(&sk.k->k));
7576

7677
ret = bch2_btree_iter_traverse(&iter) ?:
77-
bch2_trans_update(&trans, &iter, sk.k, 0) ?:
78+
bch2_trans_update(&trans, &iter, sk.k,
79+
BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE) ?:
7880
bch2_trans_commit(&trans, NULL, NULL,
7981
BTREE_INSERT_NOFAIL);
8082

fs/bcachefs/move.c

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "keylist.h"
1515
#include "move.h"
1616
#include "replicas.h"
17+
#include "subvolume.h"
1718
#include "super-io.h"
1819
#include "trace.h"
1920

@@ -52,6 +53,81 @@ struct moving_context {
5253
wait_queue_head_t wait;
5354
};
5455

56+
static int insert_snapshot_whiteouts(struct btree_trans *trans,
57+
enum btree_id id,
58+
struct bpos old_pos,
59+
struct bpos new_pos)
60+
{
61+
struct bch_fs *c = trans->c;
62+
struct btree_iter iter, update_iter;
63+
struct bkey_s_c k;
64+
struct snapshots_seen s;
65+
int ret;
66+
67+
if (!btree_type_has_snapshots(id))
68+
return 0;
69+
70+
snapshots_seen_init(&s);
71+
72+
if (!bkey_cmp(old_pos, new_pos))
73+
return 0;
74+
75+
if (!snapshot_t(c, old_pos.snapshot)->children[0])
76+
return 0;
77+
78+
bch2_trans_iter_init(trans, &iter, id, old_pos,
79+
BTREE_ITER_NOT_EXTENTS|
80+
BTREE_ITER_ALL_SNAPSHOTS);
81+
while (1) {
82+
next:
83+
k = bch2_btree_iter_prev(&iter);
84+
ret = bkey_err(k);
85+
if (ret)
86+
break;
87+
88+
if (bkey_cmp(old_pos, k.k->p))
89+
break;
90+
91+
if (bch2_snapshot_is_ancestor(c, k.k->p.snapshot, old_pos.snapshot)) {
92+
struct bkey_i *update;
93+
size_t i;
94+
95+
for (i = 0; i < s.nr; i++)
96+
if (bch2_snapshot_is_ancestor(c, k.k->p.snapshot, s.d[i]))
97+
goto next;
98+
99+
update = bch2_trans_kmalloc(trans, sizeof(struct bkey_i));
100+
101+
ret = PTR_ERR_OR_ZERO(update);
102+
if (ret)
103+
break;
104+
105+
bkey_init(&update->k);
106+
update->k.p = new_pos;
107+
update->k.p.snapshot = k.k->p.snapshot;
108+
109+
bch2_trans_iter_init(trans, &update_iter, id, update->k.p,
110+
BTREE_ITER_NOT_EXTENTS|
111+
BTREE_ITER_ALL_SNAPSHOTS|
112+
BTREE_ITER_INTENT);
113+
ret = bch2_btree_iter_traverse(&update_iter) ?:
114+
bch2_trans_update(trans, &update_iter, update,
115+
BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE);
116+
bch2_trans_iter_exit(trans, &update_iter);
117+
if (ret)
118+
break;
119+
120+
ret = snapshots_seen_add(c, &s, k.k->p.snapshot);
121+
if (ret)
122+
break;
123+
}
124+
}
125+
bch2_trans_iter_exit(trans, &iter);
126+
kfree(s.d);
127+
128+
return ret;
129+
}
130+
55131
int bch2_migrate_index_update(struct bch_write_op *op)
56132
{
57133
struct bch_fs *c = op->c;
@@ -165,7 +241,10 @@ int bch2_migrate_index_update(struct bch_write_op *op)
165241

166242
next_pos = insert->k.p;
167243

168-
ret = bch2_trans_update(&trans, &iter, insert, 0) ?:
244+
ret = insert_snapshot_whiteouts(&trans, m->btree_id,
245+
k.k->p, insert->k.p) ?:
246+
bch2_trans_update(&trans, &iter, insert,
247+
BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE) ?:
169248
bch2_trans_commit(&trans, &op->res,
170249
op_journal_seq(op),
171250
BTREE_INSERT_NOFAIL|

fs/bcachefs/subvolume.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,44 @@ static inline bool bch2_snapshot_is_ancestor(struct bch_fs *c, u32 id, u32 ances
5454
return id == ancestor;
5555
}
5656

57+
struct snapshots_seen {
58+
struct bpos pos;
59+
size_t nr;
60+
size_t size;
61+
u32 *d;
62+
};
63+
64+
static inline void snapshots_seen_exit(struct snapshots_seen *s)
65+
{
66+
kfree(s->d);
67+
s->d = NULL;
68+
}
69+
70+
static inline void snapshots_seen_init(struct snapshots_seen *s)
71+
{
72+
memset(s, 0, sizeof(*s));
73+
}
74+
75+
static inline int snapshots_seen_add(struct bch_fs *c, struct snapshots_seen *s, u32 id)
76+
{
77+
if (s->nr == s->size) {
78+
size_t new_size = max(s->size, 128UL) * 2;
79+
u32 *d = krealloc(s->d, new_size * sizeof(s->d[0]), GFP_KERNEL);
80+
81+
if (!d) {
82+
bch_err(c, "error reallocating snapshots_seen table (new size %zu)",
83+
new_size);
84+
return -ENOMEM;
85+
}
86+
87+
s->size = new_size;
88+
s->d = d;
89+
}
90+
91+
s->d[s->nr++] = id;
92+
return 0;
93+
}
94+
5795
int bch2_fs_snapshots_check(struct bch_fs *);
5896
void bch2_fs_snapshots_exit(struct bch_fs *);
5997
int bch2_fs_snapshots_start(struct bch_fs *);

0 commit comments

Comments
 (0)