]> git.sesse.net Git - bcachefs-tools-debian/blob - libbcachefs/migrate.c
b21986514d66335f49791a3184bc7149c92e94f0
[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 k,
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_bkey_drop_device(k, dev_idx);
26
27         nr_good = bch2_bkey_durability(c, k.s_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         BKEY_PADDED(key) tmp;
39         struct btree_iter iter;
40         int ret = 0;
41
42         mutex_lock(&c->replicas_gc_lock);
43         bch2_replicas_gc_start(c, (1 << BCH_DATA_USER)|(1 << BCH_DATA_CACHED));
44
45         bch2_btree_iter_init(&iter, c, BTREE_ID_EXTENTS,
46                              POS_MIN, BTREE_ITER_PREFETCH);
47
48         while ((k = bch2_btree_iter_peek(&iter)).k &&
49                !(ret = btree_iter_err(k))) {
50                 if (!bkey_extent_is_data(k.k) ||
51                     !bch2_extent_has_device(bkey_s_c_to_extent(k), dev_idx)) {
52                         ret = bch2_mark_bkey_replicas(c, k);
53                         if (ret)
54                                 break;
55                         bch2_btree_iter_next(&iter);
56                         continue;
57                 }
58
59                 bkey_reassemble(&tmp.key, k);
60
61                 ret = drop_dev_ptrs(c, bkey_i_to_s(&tmp.key),
62                                     dev_idx, flags, false);
63                 if (ret)
64                         break;
65
66                 /*
67                  * If the new extent no longer has any pointers, bch2_extent_normalize()
68                  * will do the appropriate thing with it (turning it into a
69                  * KEY_TYPE_error key, or just a discard if it was a cached extent)
70                  */
71                 bch2_extent_normalize(c, bkey_i_to_s(&tmp.key));
72
73                 iter.pos = bkey_start_pos(&tmp.key.k);
74
75                 ret = bch2_btree_insert_at(c, NULL, NULL,
76                                            BTREE_INSERT_ATOMIC|
77                                            BTREE_INSERT_NOFAIL,
78                                            BTREE_INSERT_ENTRY(&iter, &tmp.key));
79
80                 /*
81                  * don't want to leave ret == -EINTR, since if we raced and
82                  * something else overwrote the key we could spuriously return
83                  * -EINTR below:
84                  */
85                 if (ret == -EINTR)
86                         ret = 0;
87                 if (ret)
88                         break;
89         }
90
91         bch2_btree_iter_unlock(&iter);
92
93         bch2_replicas_gc_end(c, ret);
94         mutex_unlock(&c->replicas_gc_lock);
95
96         return ret;
97 }
98
99 static int bch2_dev_metadata_drop(struct bch_fs *c, unsigned dev_idx, int flags)
100 {
101         struct btree_iter iter;
102         struct closure cl;
103         struct btree *b;
104         unsigned id;
105         int ret;
106
107         /* don't handle this yet: */
108         if (flags & BCH_FORCE_IF_METADATA_LOST)
109                 return -EINVAL;
110
111         closure_init_stack(&cl);
112
113         mutex_lock(&c->replicas_gc_lock);
114         bch2_replicas_gc_start(c, 1 << BCH_DATA_BTREE);
115
116         for (id = 0; id < BTREE_ID_NR; id++) {
117                 for_each_btree_node(&iter, c, id, POS_MIN, BTREE_ITER_PREFETCH, b) {
118                         __BKEY_PADDED(k, BKEY_BTREE_PTR_VAL_U64s_MAX) tmp;
119                         struct bkey_i_btree_ptr *new_key;
120 retry:
121                         if (!bch2_bkey_has_device(bkey_i_to_s_c(&b->key),
122                                                   dev_idx)) {
123                                 /*
124                                  * we might have found a btree node key we
125                                  * needed to update, and then tried to update it
126                                  * but got -EINTR after upgrading the iter, but
127                                  * then raced and the node is now gone:
128                                  */
129                                 bch2_btree_iter_downgrade(&iter);
130
131                                 ret = bch2_mark_bkey_replicas(c, bkey_i_to_s_c(&b->key));
132                                 if (ret)
133                                         goto err;
134                         } else {
135                                 bkey_copy(&tmp.k, &b->key);
136                                 new_key = bkey_i_to_btree_ptr(&tmp.k);
137
138                                 ret = drop_dev_ptrs(c, bkey_i_to_s(&new_key->k_i),
139                                                     dev_idx, flags, true);
140                                 if (ret)
141                                         goto err;
142
143                                 ret = bch2_btree_node_update_key(c, &iter, b, new_key);
144                                 if (ret == -EINTR) {
145                                         b = bch2_btree_iter_peek_node(&iter);
146                                         goto retry;
147                                 }
148                                 if (ret)
149                                         goto err;
150                         }
151                 }
152                 bch2_btree_iter_unlock(&iter);
153         }
154
155         ret = 0;
156 out:
157         ret = bch2_replicas_gc_end(c, ret);
158         mutex_unlock(&c->replicas_gc_lock);
159
160         return ret;
161 err:
162         bch2_btree_iter_unlock(&iter);
163         goto out;
164 }
165
166 int bch2_dev_data_drop(struct bch_fs *c, unsigned dev_idx, int flags)
167 {
168         return bch2_dev_usrdata_drop(c, dev_idx, flags) ?:
169                 bch2_dev_metadata_drop(c, dev_idx, flags);
170 }