1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Code for moving data off a device. 4 */ 5 6 #include "bcachefs.h" 7 #include "backpointers.h" 8 #include "bkey_buf.h" 9 #include "btree_update.h" 10 #include "btree_update_interior.h" 11 #include "btree_write_buffer.h" 12 #include "buckets.h" 13 #include "ec.h" 14 #include "errcode.h" 15 #include "extents.h" 16 #include "io_write.h" 17 #include "journal.h" 18 #include "keylist.h" 19 #include "migrate.h" 20 #include "move.h" 21 #include "progress.h" 22 #include "replicas.h" 23 #include "super-io.h" 24 25 static int drop_dev_ptrs(struct bch_fs *c, struct bkey_s k, 26 unsigned dev_idx, unsigned flags, bool metadata) 27 { 28 unsigned replicas = metadata ? c->opts.metadata_replicas : c->opts.data_replicas; 29 unsigned lost = metadata ? BCH_FORCE_IF_METADATA_LOST : BCH_FORCE_IF_DATA_LOST; 30 unsigned degraded = metadata ? BCH_FORCE_IF_METADATA_DEGRADED : BCH_FORCE_IF_DATA_DEGRADED; 31 unsigned nr_good; 32 33 bch2_bkey_drop_device(k, dev_idx); 34 35 nr_good = bch2_bkey_durability(c, k.s_c); 36 if ((!nr_good && !(flags & lost)) || 37 (nr_good < replicas && !(flags & degraded))) 38 return bch_err_throw(c, remove_would_lose_data); 39 40 return 0; 41 } 42 43 static int drop_btree_ptrs(struct btree_trans *trans, struct btree_iter *iter, 44 struct btree *b, unsigned dev_idx, unsigned flags) 45 { 46 struct bch_fs *c = trans->c; 47 struct bkey_buf k; 48 49 bch2_bkey_buf_init(&k); 50 bch2_bkey_buf_copy(&k, c, &b->key); 51 52 int ret = drop_dev_ptrs(c, bkey_i_to_s(k.k), dev_idx, flags, true) ?: 53 bch2_btree_node_update_key(trans, iter, b, k.k, 0, false); 54 55 bch_err_fn(c, ret); 56 bch2_bkey_buf_exit(&k, c); 57 return ret; 58 } 59 60 static int bch2_dev_usrdata_drop_key(struct btree_trans *trans, 61 struct btree_iter *iter, 62 struct bkey_s_c k, 63 unsigned dev_idx, 64 unsigned flags) 65 { 66 struct bch_fs *c = trans->c; 67 struct bkey_i *n; 68 int ret; 69 70 if (!bch2_bkey_has_device_c(k, dev_idx)) 71 return 0; 72 73 n = bch2_bkey_make_mut(trans, iter, &k, BTREE_UPDATE_internal_snapshot_node); 74 ret = PTR_ERR_OR_ZERO(n); 75 if (ret) 76 return ret; 77 78 ret = drop_dev_ptrs(c, bkey_i_to_s(n), dev_idx, flags, false); 79 if (ret) 80 return ret; 81 82 /* 83 * If the new extent no longer has any pointers, bch2_extent_normalize() 84 * will do the appropriate thing with it (turning it into a 85 * KEY_TYPE_error key, or just a discard if it was a cached extent) 86 */ 87 bch2_extent_normalize(c, bkey_i_to_s(n)); 88 89 /* 90 * Since we're not inserting through an extent iterator 91 * (BTREE_ITER_all_snapshots iterators aren't extent iterators), 92 * we aren't using the extent overwrite path to delete, we're 93 * just using the normal key deletion path: 94 */ 95 if (bkey_deleted(&n->k)) 96 n->k.size = 0; 97 return 0; 98 } 99 100 static int bch2_dev_btree_drop_key(struct btree_trans *trans, 101 struct bkey_s_c_backpointer bp, 102 unsigned dev_idx, 103 struct bkey_buf *last_flushed, 104 unsigned flags) 105 { 106 struct btree_iter iter; 107 struct btree *b = bch2_backpointer_get_node(trans, bp, &iter, last_flushed); 108 int ret = PTR_ERR_OR_ZERO(b); 109 if (ret) 110 return ret == -BCH_ERR_backpointer_to_overwritten_btree_node ? 0 : ret; 111 112 ret = drop_btree_ptrs(trans, &iter, b, dev_idx, flags); 113 114 bch2_trans_iter_exit(trans, &iter); 115 return ret; 116 } 117 118 static int bch2_dev_usrdata_drop(struct bch_fs *c, 119 struct progress_indicator_state *progress, 120 unsigned dev_idx, unsigned flags) 121 { 122 struct btree_trans *trans = bch2_trans_get(c); 123 enum btree_id id; 124 int ret = 0; 125 126 for (id = 0; id < BTREE_ID_NR; id++) { 127 if (!btree_type_has_ptrs(id)) 128 continue; 129 130 ret = for_each_btree_key_commit(trans, iter, id, POS_MIN, 131 BTREE_ITER_prefetch|BTREE_ITER_all_snapshots, k, 132 NULL, NULL, BCH_TRANS_COMMIT_no_enospc, ({ 133 bch2_progress_update_iter(trans, progress, &iter, "dropping user data"); 134 bch2_dev_usrdata_drop_key(trans, &iter, k, dev_idx, flags); 135 })); 136 if (ret) 137 break; 138 } 139 140 bch2_trans_put(trans); 141 142 return ret; 143 } 144 145 static int bch2_dev_metadata_drop(struct bch_fs *c, 146 struct progress_indicator_state *progress, 147 unsigned dev_idx, unsigned flags) 148 { 149 struct btree_trans *trans; 150 struct btree_iter iter; 151 struct closure cl; 152 struct btree *b; 153 struct bkey_buf k; 154 unsigned id; 155 int ret; 156 157 /* don't handle this yet: */ 158 if (flags & BCH_FORCE_IF_METADATA_LOST) 159 return bch_err_throw(c, remove_with_metadata_missing_unimplemented); 160 161 trans = bch2_trans_get(c); 162 bch2_bkey_buf_init(&k); 163 closure_init_stack(&cl); 164 165 for (id = 0; id < BTREE_ID_NR; id++) { 166 bch2_trans_node_iter_init(trans, &iter, id, POS_MIN, 0, 0, 167 BTREE_ITER_prefetch); 168 retry: 169 ret = 0; 170 while (bch2_trans_begin(trans), 171 (b = bch2_btree_iter_peek_node(trans, &iter)) && 172 !(ret = PTR_ERR_OR_ZERO(b))) { 173 bch2_progress_update_iter(trans, progress, &iter, "dropping metadata"); 174 175 if (!bch2_bkey_has_device_c(bkey_i_to_s_c(&b->key), dev_idx)) 176 goto next; 177 178 ret = drop_btree_ptrs(trans, &iter, b, dev_idx, flags); 179 if (bch2_err_matches(ret, BCH_ERR_transaction_restart)) { 180 ret = 0; 181 continue; 182 } 183 184 if (ret) 185 break; 186 next: 187 bch2_btree_iter_next_node(trans, &iter); 188 } 189 if (bch2_err_matches(ret, BCH_ERR_transaction_restart)) 190 goto retry; 191 192 bch2_trans_iter_exit(trans, &iter); 193 194 if (ret) 195 goto err; 196 } 197 198 bch2_btree_interior_updates_flush(c); 199 ret = 0; 200 err: 201 bch2_bkey_buf_exit(&k, c); 202 bch2_trans_put(trans); 203 204 BUG_ON(bch2_err_matches(ret, BCH_ERR_transaction_restart)); 205 206 return ret; 207 } 208 209 static int data_drop_bp(struct btree_trans *trans, unsigned dev_idx, 210 struct bkey_s_c_backpointer bp, struct bkey_buf *last_flushed, 211 unsigned flags) 212 { 213 struct btree_iter iter; 214 struct bkey_s_c k = bch2_backpointer_get_key(trans, bp, &iter, BTREE_ITER_intent, 215 last_flushed); 216 int ret = bkey_err(k); 217 if (ret == -BCH_ERR_backpointer_to_overwritten_btree_node) 218 return 0; 219 if (ret) 220 return ret; 221 222 if (!k.k || !bch2_bkey_has_device_c(k, dev_idx)) 223 goto out; 224 225 /* 226 * XXX: pass flags arg to invalidate_stripe_to_dev and handle it 227 * properly 228 */ 229 230 if (bkey_is_btree_ptr(k.k)) 231 ret = bch2_dev_btree_drop_key(trans, bp, dev_idx, last_flushed, flags); 232 else if (k.k->type == KEY_TYPE_stripe) 233 ret = bch2_invalidate_stripe_to_dev(trans, &iter, k, dev_idx, flags); 234 else 235 ret = bch2_dev_usrdata_drop_key(trans, &iter, k, dev_idx, flags); 236 out: 237 bch2_trans_iter_exit(trans, &iter); 238 return ret; 239 } 240 241 int bch2_dev_data_drop_by_backpointers(struct bch_fs *c, unsigned dev_idx, unsigned flags) 242 { 243 struct btree_trans *trans = bch2_trans_get(c); 244 245 struct bkey_buf last_flushed; 246 bch2_bkey_buf_init(&last_flushed); 247 bkey_init(&last_flushed.k->k); 248 249 int ret = bch2_btree_write_buffer_flush_sync(trans) ?: 250 for_each_btree_key_max_commit(trans, iter, BTREE_ID_backpointers, 251 POS(dev_idx, 0), 252 POS(dev_idx, U64_MAX), 0, k, 253 NULL, NULL, BCH_TRANS_COMMIT_no_enospc, ({ 254 if (k.k->type != KEY_TYPE_backpointer) 255 continue; 256 257 data_drop_bp(trans, dev_idx, bkey_s_c_to_backpointer(k), 258 &last_flushed, flags); 259 260 })); 261 262 bch2_bkey_buf_exit(&last_flushed, trans->c); 263 bch2_trans_put(trans); 264 bch_err_fn(c, ret); 265 return ret; 266 } 267 268 int bch2_dev_data_drop(struct bch_fs *c, unsigned dev_idx, unsigned flags) 269 { 270 struct progress_indicator_state progress; 271 bch2_progress_init(&progress, c, 272 BIT_ULL(BTREE_ID_extents)| 273 BIT_ULL(BTREE_ID_reflink)); 274 275 return bch2_dev_usrdata_drop(c, &progress, dev_idx, flags) ?: 276 bch2_dev_metadata_drop(c, &progress, dev_idx, flags); 277 } 278