1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Code for moving data off a device. 4 */ 5 6 #include "bcachefs.h" 7 #include "bkey_buf.h" 8 #include "btree_update.h" 9 #include "btree_update_interior.h" 10 #include "buckets.h" 11 #include "errcode.h" 12 #include "extents.h" 13 #include "io_write.h" 14 #include "journal.h" 15 #include "keylist.h" 16 #include "migrate.h" 17 #include "move.h" 18 #include "progress.h" 19 #include "replicas.h" 20 #include "super-io.h" 21 22 static int drop_dev_ptrs(struct bch_fs *c, struct bkey_s k, 23 unsigned dev_idx, int flags, bool metadata) 24 { 25 unsigned replicas = metadata ? c->opts.metadata_replicas : c->opts.data_replicas; 26 unsigned lost = metadata ? BCH_FORCE_IF_METADATA_LOST : BCH_FORCE_IF_DATA_LOST; 27 unsigned degraded = metadata ? BCH_FORCE_IF_METADATA_DEGRADED : BCH_FORCE_IF_DATA_DEGRADED; 28 unsigned nr_good; 29 30 bch2_bkey_drop_device(k, dev_idx); 31 32 nr_good = bch2_bkey_durability(c, k.s_c); 33 if ((!nr_good && !(flags & lost)) || 34 (nr_good < replicas && !(flags & degraded))) 35 return -BCH_ERR_remove_would_lose_data; 36 37 return 0; 38 } 39 40 static int bch2_dev_usrdata_drop_key(struct btree_trans *trans, 41 struct btree_iter *iter, 42 struct bkey_s_c k, 43 unsigned dev_idx, 44 int flags) 45 { 46 struct bch_fs *c = trans->c; 47 struct bkey_i *n; 48 int ret; 49 50 if (!bch2_bkey_has_device_c(k, dev_idx)) 51 return 0; 52 53 n = bch2_bkey_make_mut(trans, iter, &k, BTREE_UPDATE_internal_snapshot_node); 54 ret = PTR_ERR_OR_ZERO(n); 55 if (ret) 56 return ret; 57 58 ret = drop_dev_ptrs(c, bkey_i_to_s(n), dev_idx, flags, false); 59 if (ret) 60 return ret; 61 62 /* 63 * If the new extent no longer has any pointers, bch2_extent_normalize() 64 * will do the appropriate thing with it (turning it into a 65 * KEY_TYPE_error key, or just a discard if it was a cached extent) 66 */ 67 bch2_extent_normalize(c, bkey_i_to_s(n)); 68 69 /* 70 * Since we're not inserting through an extent iterator 71 * (BTREE_ITER_all_snapshots iterators aren't extent iterators), 72 * we aren't using the extent overwrite path to delete, we're 73 * just using the normal key deletion path: 74 */ 75 if (bkey_deleted(&n->k)) 76 n->k.size = 0; 77 return 0; 78 } 79 80 static int bch2_dev_usrdata_drop(struct bch_fs *c, 81 struct progress_indicator_state *progress, 82 unsigned dev_idx, int flags) 83 { 84 struct btree_trans *trans = bch2_trans_get(c); 85 enum btree_id id; 86 int ret = 0; 87 88 for (id = 0; id < BTREE_ID_NR; id++) { 89 if (!btree_type_has_ptrs(id)) 90 continue; 91 92 ret = for_each_btree_key_commit(trans, iter, id, POS_MIN, 93 BTREE_ITER_prefetch|BTREE_ITER_all_snapshots, k, 94 NULL, NULL, BCH_TRANS_COMMIT_no_enospc, ({ 95 bch2_progress_update_iter(trans, progress, &iter, "dropping user data"); 96 bch2_dev_usrdata_drop_key(trans, &iter, k, dev_idx, flags); 97 })); 98 if (ret) 99 break; 100 } 101 102 bch2_trans_put(trans); 103 104 return ret; 105 } 106 107 static int bch2_dev_metadata_drop(struct bch_fs *c, 108 struct progress_indicator_state *progress, 109 unsigned dev_idx, int flags) 110 { 111 struct btree_trans *trans; 112 struct btree_iter iter; 113 struct closure cl; 114 struct btree *b; 115 struct bkey_buf k; 116 unsigned id; 117 int ret; 118 119 /* don't handle this yet: */ 120 if (flags & BCH_FORCE_IF_METADATA_LOST) 121 return -BCH_ERR_remove_with_metadata_missing_unimplemented; 122 123 trans = bch2_trans_get(c); 124 bch2_bkey_buf_init(&k); 125 closure_init_stack(&cl); 126 127 for (id = 0; id < BTREE_ID_NR; id++) { 128 bch2_trans_node_iter_init(trans, &iter, id, POS_MIN, 0, 0, 129 BTREE_ITER_prefetch); 130 retry: 131 ret = 0; 132 while (bch2_trans_begin(trans), 133 (b = bch2_btree_iter_peek_node(trans, &iter)) && 134 !(ret = PTR_ERR_OR_ZERO(b))) { 135 bch2_progress_update_iter(trans, progress, &iter, "dropping metadata"); 136 137 if (!bch2_bkey_has_device_c(bkey_i_to_s_c(&b->key), dev_idx)) 138 goto next; 139 140 bch2_bkey_buf_copy(&k, c, &b->key); 141 142 ret = drop_dev_ptrs(c, bkey_i_to_s(k.k), 143 dev_idx, flags, true); 144 if (ret) 145 break; 146 147 ret = bch2_btree_node_update_key(trans, &iter, b, k.k, 0, false); 148 if (bch2_err_matches(ret, BCH_ERR_transaction_restart)) { 149 ret = 0; 150 continue; 151 } 152 153 bch_err_msg(c, ret, "updating btree node key"); 154 if (ret) 155 break; 156 next: 157 bch2_btree_iter_next_node(trans, &iter); 158 } 159 if (bch2_err_matches(ret, BCH_ERR_transaction_restart)) 160 goto retry; 161 162 bch2_trans_iter_exit(trans, &iter); 163 164 if (ret) 165 goto err; 166 } 167 168 bch2_btree_interior_updates_flush(c); 169 ret = 0; 170 err: 171 bch2_bkey_buf_exit(&k, c); 172 bch2_trans_put(trans); 173 174 BUG_ON(bch2_err_matches(ret, BCH_ERR_transaction_restart)); 175 176 return ret; 177 } 178 179 int bch2_dev_data_drop(struct bch_fs *c, unsigned dev_idx, int flags) 180 { 181 struct progress_indicator_state progress; 182 bch2_progress_init(&progress, c, 183 BIT_ULL(BTREE_ID_extents)| 184 BIT_ULL(BTREE_ID_reflink)); 185 186 return bch2_dev_usrdata_drop(c, &progress, dev_idx, flags) ?: 187 bch2_dev_metadata_drop(c, &progress, dev_idx, flags); 188 } 189