ret = bch2_subvolume_get_snapshot(trans, dir.subvol, &snapshot); if (ret) goto err;
ret = bch2_inode_peek(trans, &dir_iter, dir_u, dir,
BTREE_ITER_intent|BTREE_ITER_with_updates); if (ret) goto err;
if (!(flags & BCH_CREATE_SNAPSHOT)) { /* Normal create path - allocate a new inode: */
bch2_inode_init_late(c, new_inode, now, uid, gid, mode, rdev, dir_u);
if (flags & BCH_CREATE_TMPFILE)
new_inode->bi_flags |= BCH_INODE_unlinked;
ret = bch2_inode_create(trans, &inode_iter, new_inode, snapshot, cpu); if (ret) goto err;
snapshot_src = (subvol_inum) { 0 };
} else { /* * Creating a snapshot - we're not allocating a new inode, but * we do have to lookup the root inode of the subvolume we're * snapshotting and update it (in the new snapshot):
*/
if (!snapshot_src.inum) { /* Inode wasn't specified, just snapshot: */ struct bch_subvolume s;
ret = bch2_subvolume_get(trans, snapshot_src.subvol, true, &s); if (ret) goto err;
snapshot_src.inum = le64_to_cpu(s.inode);
}
ret = bch2_inode_peek(trans, &inode_iter, new_inode, snapshot_src,
BTREE_ITER_intent); if (ret) goto err;
if (new_inode->bi_subvol != snapshot_src.subvol) { /* Not a subvolume root: */
ret = -EINVAL; goto err;
}
/* * If we're not root, we have to own the subvolume being * snapshotted:
*/ if (uid && new_inode->bi_uid != uid) {
ret = -EPERM; goto err;
}
ret = bch2_subvolume_get_snapshot(trans, dir.subvol, &dir_snapshot); if (ret) goto err;
bch2_btree_iter_set_snapshot(trans, &dir_iter, dir_snapshot);
ret = bch2_btree_iter_traverse(trans, &dir_iter); if (ret) goto err;
}
if (!(flags & BCH_CREATE_SNAPSHOT)) { if (default_acl) {
ret = bch2_set_acl_trans(trans, new_inum, new_inode,
default_acl, ACL_TYPE_DEFAULT); if (ret) goto err;
}
if (acl) {
ret = bch2_set_acl_trans(trans, new_inum, new_inode,
acl, ACL_TYPE_ACCESS); if (ret) goto err;
}
}
ret = bch2_inode_peek(trans, &dir_iter, dir_u, dir, BTREE_ITER_intent); if (ret) goto err;
dir_hash = bch2_hash_info_init(c, dir_u);
ret = bch2_dirent_lookup_trans(trans, &dirent_iter, dir, &dir_hash,
name, &inum, BTREE_ITER_intent); if (ret) goto err;
ret = bch2_inode_peek(trans, &inode_iter, inode_u, inum,
BTREE_ITER_intent); if (ret) goto err;
if (!deleting_subvol && S_ISDIR(inode_u->bi_mode)) {
ret = bch2_empty_dir_trans(trans, inum); if (ret) goto err;
}
if (deleting_subvol && !inode_u->bi_subvol) {
ret = bch_err_throw(c, ENOENT_not_subvol); goto err;
}
if (inode_u->bi_subvol) { /* Recursive subvolume destroy not allowed (yet?) */
ret = bch2_subvol_has_children(trans, inode_u->bi_subvol); if (ret) goto err;
}
if (deleting_subvol || inode_u->bi_subvol) {
ret = bch2_subvolume_unlink(trans, inode_u->bi_subvol); if (ret) goto err;
k = bch2_btree_iter_peek_slot(trans, &dirent_iter);
ret = bkey_err(k); if (ret) goto err;
/* * If we're deleting a subvolume, we need to really delete the * dirent, not just emit a whiteout in the current snapshot:
*/
bch2_btree_iter_set_snapshot(trans, &dirent_iter, k.k->p.snapshot);
ret = bch2_btree_iter_traverse(trans, &dirent_iter); if (ret) goto err;
} else {
bch2_inode_nlink_dec(trans, inode_u);
}
if (!backpointer_exists) { if (fsck_err(trans, inode_wrong_backpointer, "inode %llu:%u has wrong backpointer:\n" "got %llu:%llu\n" "should be %llu:%llu",
target->bi_inum, target->bi_snapshot,
target->bi_dir,
target->bi_dir_offset,
d.k->p.inode,
d.k->p.offset)) {
target->bi_dir = d.k->p.inode;
target->bi_dir_offset = d.k->p.offset;
ret = __bch2_fsck_write_inode(trans, target);
}
} else {
printbuf_reset(&buf);
bch2_bkey_val_to_text(&buf, c, d.s_c);
prt_newline(&buf);
bch2_bkey_val_to_text(&buf, c, bp_dirent.s_c);
if (S_ISDIR(target->bi_mode) || target->bi_subvol) { /* * XXX: verify connectivity of the other dirent * up to the root before removing this one * * Additionally, bch2_lookup would need to cope with the * dirent it found being removed - or should we remove * the other one, even though the inode points to it?
*/ if (in_fsck) { if (fsck_err(trans, inode_dir_multiple_links, "%s %llu:%u with multiple links\n%s",
S_ISDIR(target->bi_mode) ? "directory" : "subvolume",
target->bi_inum, target->bi_snapshot, buf.buf))
ret = bch2_fsck_remove_dirent(trans, d.k->p);
} else {
bch2_fs_inconsistent(c, "%s %llu:%u with multiple links\n%s",
S_ISDIR(target->bi_mode) ? "directory" : "subvolume",
target->bi_inum, target->bi_snapshot, buf.buf);
}
goto out;
} else { /* * hardlinked file with nlink 0: * We're just adjusting nlink here so check_nlinks() will pick * it up, it ignores inodes with nlink 0
*/ if (fsck_err_on(!target->bi_nlink,
trans, inode_multiple_links_but_nlink_0, "inode %llu:%u type %s has multiple links but i_nlink 0\n%s",
target->bi_inum, target->bi_snapshot, bch2_d_types[d.v->d_type], buf.buf)) {
target->bi_nlink++;
target->bi_flags &= ~BCH_INODE_unlinked;
ret = __bch2_fsck_write_inode(trans, target); if (ret) goto err;
}
}
}
out:
err:
fsck_err:
bch2_trans_iter_exit(trans, &bp_iter);
printbuf_exit(&buf);
bch_err_fn(c, ret); return ret;
}
int __bch2_check_dirent_target(struct btree_trans *trans, struct btree_iter *dirent_iter, struct bkey_s_c_dirent d, struct bch_inode_unpacked *target, bool in_fsck)
{ struct bch_fs *c = trans->c; struct printbuf buf = PRINTBUF; int ret = 0;
ret = bch2_check_dirent_inode_dirent(trans, d, target, in_fsck); if (ret) goto err;
if (fsck_err_on(d.v->d_type != inode_d_type(target),
trans, dirent_d_type_wrong, "incorrect d_type: got %s, should be %s:\n%s",
bch2_d_type_str(d.v->d_type),
bch2_d_type_str(inode_d_type(target)),
(printbuf_reset(&buf),
bch2_bkey_val_to_text(&buf, c, d.s_c), buf.buf))) { struct bkey_i_dirent *n = bch2_trans_kmalloc(trans, bkey_bytes(d.k));
ret = PTR_ERR_OR_ZERO(n); if (ret) goto err;
int bch2_check_inode_has_case_insensitive(struct btree_trans *trans, struct bch_inode_unpacked *inode,
snapshot_id_list *snapshot_overwrites, bool *do_update)
{ struct printbuf buf = PRINTBUF; bool repairing_parents = false; int ret = 0;
if (!S_ISDIR(inode->bi_mode)) { /* * Old versions set bi_casefold for non dirs, but that's * unnecessary and wasteful
*/ if (inode->bi_casefold) {
inode->bi_casefold = 0;
*do_update = true;
} return 0;
}
if (trans->c->sb.version < bcachefs_metadata_version_inode_has_case_insensitive) return 0;
if (bch2_inode_casefold(trans->c, inode) &&
!(inode->bi_flags & BCH_INODE_has_case_insensitive)) {
prt_printf(&buf, "casefolded dir with has_case_insensitive not set\ninum %llu:%u ",
inode->bi_inum, inode->bi_snapshot);
ret = bch2_inum_snapshot_to_path(trans, inode->bi_inum, inode->bi_snapshot,
snapshot_overwrites, &buf); if (ret) goto err;
if (!(inode->bi_flags & BCH_INODE_has_case_insensitive)) goto out;
struct bch_inode_unpacked dir = *inode;
u32 snapshot = dir.bi_snapshot;
while (!(dir.bi_inum == BCACHEFS_ROOT_INO &&
dir.bi_subvol == BCACHEFS_ROOT_SUBVOL)) { if (dir.bi_parent_subvol) {
ret = bch2_subvolume_get_snapshot(trans, dir.bi_parent_subvol, &snapshot); if (ret) goto err;
snapshot_overwrites = NULL;
}
ret = bch2_inode_find_by_inum_snapshot(trans, dir.bi_dir, snapshot, &dir, 0); if (ret) goto err;
if (!(dir.bi_flags & BCH_INODE_has_case_insensitive)) {
prt_printf(&buf, "parent of casefolded dir with has_case_insensitive not set\n");
ret = bch2_inum_snapshot_to_path(trans, dir.bi_inum, dir.bi_snapshot,
snapshot_overwrites, &buf); if (ret) goto err;
if (fsck_err(trans, inode_parent_has_case_insensitive_not_set, "%s", buf.buf)) {
dir.bi_flags |= BCH_INODE_has_case_insensitive;
ret = __bch2_fsck_write_inode(trans, &dir); if (ret) goto err;
}
}
/* * We only need to check the first parent, unless we find an * inconsistency
*/ if (!repairing_parents) break;
}
out:
err:
fsck_err:
printbuf_exit(&buf); if (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.