]> git.sesse.net Git - bcachefs-tools-debian/blob - libbcachefs/migrate.c
Update bcachefs sources to 15f6e66e86 bcachefs: pass around bset_tree less
[bcachefs-tools-debian] / libbcachefs / migrate.c
1 /*
2  * Code for moving data off a device.
3  */
4
5 #include "bcachefs.h"
6 #include "btree_update.h"
7 #include "buckets.h"
8 #include "extents.h"
9 #include "io.h"
10 #include "journal.h"
11 #include "keylist.h"
12 #include "migrate.h"
13 #include "move.h"
14 #include "replicas.h"
15 #include "super-io.h"
16
17 static int drop_dev_ptrs(struct bch_fs *c, struct bkey_s_extent e,
18                          unsigned dev_idx, int flags, bool metadata)
19 {
20         unsigned replicas = metadata ? c->opts.metadata_replicas : c->opts.data_replicas;
21         unsigned lost = metadata ? BCH_FORCE_IF_METADATA_LOST : BCH_FORCE_IF_DATA_LOST;
22         unsigned degraded = metadata ? BCH_FORCE_IF_METADATA_DEGRADED : BCH_FORCE_IF_DATA_DEGRADED;
23         unsigned nr_good;
24
25         bch2_extent_drop_device(e, dev_idx);
26
27         nr_good = bch2_extent_durability(c, e.c);
28         if ((!nr_good && !(flags & lost)) ||
29             (nr_good < replicas && !(flags & degraded)))
30                 return -EINVAL;
31
32         return 0;
33 }
34
35 static int bch2_dev_usrdata_drop(struct bch_fs *c, unsigned dev_idx, int flags)
36 {
37         struct bkey_s_c k;
38         struct bkey_s_extent e;
39         BKEY_PADDED(key) tmp;
40         struct btree_iter iter;
41         int ret = 0;
42
43         mutex_lock(&c->replicas_gc_lock);
44         bch2_replicas_gc_start(c, (1 << BCH_DATA_USER)|(1 << BCH_DATA_CACHED));
45
46         bch2_btree_iter_init(&iter, c, BTREE_ID_EXTENTS,
47                              POS_MIN, BTREE_ITER_PREFETCH);
48
49         while ((k = bch2_btree_iter_peek(&iter)).k &&
50                !(ret = btree_iter_err(k))) {
51                 if (!bkey_extent_is_data(k.k) ||
52                     !bch2_extent_has_device(bkey_s_c_to_extent(k), dev_idx)) {
53                         ret = bch2_mark_bkey_replicas(c, BCH_DATA_USER, k);
54                         if (ret)
55                                 break;
56                         bch2_btree_iter_next(&iter);
57                         continue;
58                 }
59
60                 bkey_reassemble(&tmp.key, k);
61                 e = bkey_i_to_s_extent(&tmp.key);
62
63                 ret = drop_dev_ptrs(c, e, dev_idx, flags, false);
64                 if (ret)
65                         break;
66
67                 /*
68                  * If the new extent no longer has any pointers, bch2_extent_normalize()
69                  * will do the appropriate thing with it (turning it into a
70                  * KEY_TYPE_ERROR key, or just a discard if it was a cached extent)
71                  */
72                 bch2_extent_normalize(c, e.s);
73
74                 ret = bch2_mark_bkey_replicas(c, BCH_DATA_USER,
75                                               bkey_i_to_s_c(&tmp.key));
76                 if (ret)
77                         break;
78
79                 iter.pos = bkey_start_pos(&tmp.key.k);
80
81                 ret = bch2_btree_insert_at(c, NULL, NULL,
82                                            BTREE_INSERT_ATOMIC|
83                                            BTREE_INSERT_NOFAIL,
84                                            BTREE_INSERT_ENTRY(&iter, &tmp.key));
85
86                 /*
87                  * don't want to leave ret == -EINTR, since if we raced and
88                  * something else overwrote the key we could spuriously return
89                  * -EINTR below:
90                  */
91                 if (ret == -EINTR)
92                         ret = 0;
93                 if (ret)
94                         break;
95         }
96
97         bch2_btree_iter_unlock(&iter);
98
99         bch2_replicas_gc_end(c, ret);
100         mutex_unlock(&c->replicas_gc_lock);
101
102         return ret;
103 }
104
105 static int bch2_dev_metadata_drop(struct bch_fs *c, unsigned dev_idx, int flags)
106 {
107         struct btree_iter iter;
108         struct closure cl;
109         struct btree *b;
110         unsigned id;
111         int ret;
112
113         /* don't handle this yet: */
114         if (flags & BCH_FORCE_IF_METADATA_LOST)
115                 return -EINVAL;
116
117         closure_init_stack(&cl);
118
119         mutex_lock(&c->replicas_gc_lock);
120         bch2_replicas_gc_start(c, 1 << BCH_DATA_BTREE);
121
122         for (id = 0; id < BTREE_ID_NR; id++) {
123                 for_each_btree_node(&iter, c, id, POS_MIN, BTREE_ITER_PREFETCH, b) {
124                         __BKEY_PADDED(k, BKEY_BTREE_PTR_VAL_U64s_MAX) tmp;
125                         struct bkey_i_extent *new_key;
126 retry:
127                         if (!bch2_extent_has_device(bkey_i_to_s_c_extent(&b->key),
128                                                     dev_idx)) {
129                                 /*
130                                  * we might have found a btree node key we
131                                  * needed to update, and then tried to update it
132                                  * but got -EINTR after upgrading the iter, but
133                                  * then raced and the node is now gone:
134                                  */
135                                 bch2_btree_iter_downgrade(&iter);
136
137                                 ret = bch2_mark_bkey_replicas(c, BCH_DATA_BTREE,
138                                                               bkey_i_to_s_c(&b->key));
139                                 if (ret)
140                                         goto err;
141                         } else {
142                                 bkey_copy(&tmp.k, &b->key);
143                                 new_key = bkey_i_to_extent(&tmp.k);
144
145                                 ret = drop_dev_ptrs(c, extent_i_to_s(new_key),
146                                                     dev_idx, flags, true);
147                                 if (ret)
148                                         goto err;
149
150                                 ret = bch2_btree_node_update_key(c, &iter, b, new_key);
151                                 if (ret == -EINTR) {
152                                         b = bch2_btree_iter_peek_node(&iter);
153                                         goto retry;
154                                 }
155                                 if (ret)
156                                         goto err;
157                         }
158                 }
159                 bch2_btree_iter_unlock(&iter);
160         }
161
162         ret = 0;
163 out:
164         ret = bch2_replicas_gc_end(c, ret);
165         mutex_unlock(&c->replicas_gc_lock);
166
167         return ret;
168 err:
169         bch2_btree_iter_unlock(&iter);
170         goto out;
171 }
172
173 int bch2_dev_data_drop(struct bch_fs *c, unsigned dev_idx, int flags)
174 {
175         return bch2_dev_usrdata_drop(c, dev_idx, flags) ?:
176                 bch2_dev_metadata_drop(c, dev_idx, flags);
177 }