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