if (bch2_err_matches(ret, ENOENT)) return bch2_run_print_explicit_recovery_pass(c,
BCH_RECOVERY_PASS_reconstruct_snapshots) ?: ret; if (ret) return ret;
if (BCH_SUBVOLUME_UNLINKED(subvol.v)) {
ret = bch2_subvolume_delete(trans, iter->pos.offset);
bch_err_msg(c, ret, "deleting subvolume %llu", iter->pos.offset); return ret ?: -BCH_ERR_transaction_restart_nested;
}
if (fsck_err_on(subvol.k->p.offset == BCACHEFS_ROOT_SUBVOL &&
subvol.v->fs_path_parent,
trans, subvol_root_fs_path_parent_nonzero, "root subvolume has nonzero fs_path_parent\n%s",
(bch2_bkey_val_to_text(&buf, c, k), buf.buf))) { struct bkey_i_subvolume *n =
bch2_bkey_make_mut_typed(trans, iter, &subvol.s_c, 0, subvolume);
ret = PTR_ERR_OR_ZERO(n); if (ret) goto err;
n->v.fs_path_parent = 0;
}
if (subvol.v->fs_path_parent) { struct bpos pos = subvolume_children_pos(k);
struct bkey_s_c subvol_children_k =
bch2_bkey_get_iter(trans, &subvol_children_iter,
BTREE_ID_subvolume_children, pos, 0);
ret = bkey_err(subvol_children_k); if (ret) goto err;
if (fsck_err_on(subvol_children_k.k->type != KEY_TYPE_set,
trans, subvol_children_not_set, "subvolume not set in subvolume_children btree at %llu:%llu\n%s",
pos.inode, pos.offset,
(printbuf_reset(&buf),
bch2_bkey_val_to_text(&buf, c, k), buf.buf))) {
ret = bch2_btree_bit_mod(trans, BTREE_ID_subvolume_children, pos, true); if (ret) goto err;
}
}
struct bch_inode_unpacked inode;
ret = bch2_inode_find_by_inum_nowarn_trans(trans,
(subvol_inum) { k.k->p.offset, le64_to_cpu(subvol.v->inode) },
&inode); if (!ret) { if (fsck_err_on(inode.bi_subvol != subvol.k->p.offset,
trans, subvol_root_wrong_bi_subvol, "subvol root %llu:%u has wrong bi_subvol field: got %u, should be %llu",
inode.bi_inum, inode.bi_snapshot,
inode.bi_subvol, subvol.k->p.offset)) {
inode.bi_subvol = subvol.k->p.offset;
inode.bi_snapshot = le32_to_cpu(subvol.v->snapshot);
ret = __bch2_fsck_write_inode(trans, &inode); if (ret) goto err;
}
} elseif (bch2_err_matches(ret, ENOENT)) { if (fsck_err(trans, subvol_to_missing_root, "subvolume %llu points to missing subvolume root %llu:%u",
k.k->p.offset, le64_to_cpu(subvol.v->inode),
le32_to_cpu(subvol.v->snapshot))) { /* * Recreate - any contents that are still disconnected * will then get reattached under lost+found
*/
bch2_inode_init_early(c, &inode);
bch2_inode_init_late(c, &inode, bch2_current_time(c),
0, 0, S_IFDIR|0700, 0, NULL);
inode.bi_inum = le64_to_cpu(subvol.v->inode);
inode.bi_snapshot = le32_to_cpu(subvol.v->snapshot);
inode.bi_subvol = k.k->p.offset;
inode.bi_parent_subvol = le32_to_cpu(subvol.v->fs_path_parent);
ret = __bch2_fsck_write_inode(trans, &inode); if (ret) goto err;
}
} else { goto err;
}
struct bch_snapshot_tree st;
ret = bch2_snapshot_tree_lookup(trans, snapshot_tree, &st);
bch2_fs_inconsistent_on(bch2_err_matches(ret, ENOENT), c, "%s: snapshot tree %u not found", __func__, snapshot_tree);
if (ret) goto err;
if (fsck_err_on(le32_to_cpu(st.master_subvol) != subvol.k->p.offset,
trans, subvol_not_master_and_not_snapshot, "subvolume %llu is not set as snapshot but is not master subvolume",
k.k->p.offset)) { struct bkey_i_subvolume *s =
bch2_bkey_make_mut_typed(trans, iter, &subvol.s_c, 0, subvolume);
ret = PTR_ERR_OR_ZERO(s); if (ret) goto err;
if (!bpos_eq(children_pos_old, children_pos_new)) { int ret = subvolume_children_mod(trans, children_pos_old, false) ?:
subvolume_children_mod(trans, children_pos_new, true); if (ret) return ret;
}
}
return 0;
}
int bch2_subvol_has_children(struct btree_trans *trans, u32 subvol)
{ struct btree_iter iter;
/* * Separate from the snapshot tree in the snapshots btree, we record the tree * structure of how snapshot subvolumes were created - the parent subvolume of * each snapshot subvolume. * * When a subvolume is deleted, we scan for child subvolumes and reparant them, * to avoid dangling references:
*/ staticint bch2_subvolumes_reparent(struct btree_trans *trans, u32 subvolid_to_delete)
{ struct bch_subvolume s;
staticvoid bch2_subvolume_wait_for_pagecache_and_delete(struct work_struct *work)
{ struct bch_fs *c = container_of(work, struct bch_fs,
snapshot_wait_for_pagecache_and_delete_work); int ret = 0;
while (!ret) {
mutex_lock(&c->snapshots_unlinked_lock);
snapshot_id_list s = c->snapshots_unlinked;
darray_init(&c->snapshots_unlinked);
mutex_unlock(&c->snapshots_unlinked_lock);
if (!s.nr) break;
bch2_evict_subvolume_inodes(c, &s);
darray_for_each(s, id) {
ret = bch2_trans_run(c, bch2_subvolume_delete(trans, *id));
bch_err_msg(c, ret, "deleting subvolume %u", *id); if (ret) break;
}
mutex_lock(&c->snapshots_unlinked_lock); if (!snapshot_list_has_id(&c->snapshots_unlinked, h->subvol))
ret = snapshot_list_add(c, &c->snapshots_unlinked, h->subvol);
mutex_unlock(&c->snapshots_unlinked_lock);
if (ret) return ret;
if (!enumerated_ref_tryget(&c->writes, BCH_WRITE_REF_snapshot_delete_pagecache)) return -EROFS;
if (!queue_work(c->write_ref_wq, &c->snapshot_wait_for_pagecache_and_delete_work))
enumerated_ref_put(&c->writes, BCH_WRITE_REF_snapshot_delete_pagecache); return 0;
}
int bch2_subvolume_unlink(struct btree_trans *trans, u32 subvolid)
{ struct btree_iter iter; struct bkey_i_subvolume *n; struct subvolume_unlink_hook *h; int ret = 0;
h = bch2_trans_kmalloc(trans, sizeof(*h));
ret = PTR_ERR_OR_ZERO(h); if (ret) return ret;
n = bch2_bkey_get_mut_typed(trans, &iter,
BTREE_ID_subvolumes, POS(0, subvolid),
BTREE_ITER_cached, subvolume);
ret = PTR_ERR_OR_ZERO(n); if (bch2_err_matches(ret, ENOENT))
ret = bch2_subvolume_missing(trans->c, subvolid) ?: ret; if (unlikely(ret)) return ret;
ret = bch2_bkey_get_empty_slot(trans, &dst_iter,
BTREE_ID_subvolumes, POS(0, U32_MAX)); if (ret == -BCH_ERR_ENOSPC_btree_slot)
ret = bch_err_throw(c, ENOSPC_subvolume_create); if (ret) return ret;
/* set bi_subvol on root inode */ int bch2_fs_upgrade_for_subvolumes(struct bch_fs *c)
{ int ret = bch2_trans_commit_do(c, NULL, NULL, BCH_TRANS_COMMIT_no_enospc,
__bch2_fs_upgrade_for_subvolumes(trans));
bch_err_fn(c, ret); return ret;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.