diff options
Diffstat (limited to 'fs/bcachefs/namei.c')
-rw-r--r-- | fs/bcachefs/namei.c | 136 |
1 files changed, 76 insertions, 60 deletions
diff --git a/fs/bcachefs/namei.c b/fs/bcachefs/namei.c index 3e2b41babc26..cfed2041c2c3 100644 --- a/fs/bcachefs/namei.c +++ b/fs/bcachefs/namei.c @@ -36,8 +36,8 @@ int bch2_create_trans(struct btree_trans *trans, unsigned flags) { struct bch_fs *c = trans->c; - struct btree_iter dir_iter = {}; - struct btree_iter inode_iter = {}; + struct btree_iter dir_iter = { NULL }; + struct btree_iter inode_iter = { NULL }; subvol_inum new_inum = dir; u64 now = bch2_current_time(c); u64 cpu = raw_smp_processor_id(); @@ -99,7 +99,9 @@ int bch2_create_trans(struct btree_trans *trans, * If we're not root, we have to own the subvolume being * snapshotted: */ - if (uid && new_inode->bi_uid != uid) { + if (uid && + !capable(CAP_FOWNER) && + new_inode->bi_uid != uid) { ret = -EPERM; goto err; } @@ -131,8 +133,8 @@ int bch2_create_trans(struct btree_trans *trans, if (ret) goto err; - bch2_btree_iter_set_snapshot(trans, &dir_iter, dir_snapshot); - ret = bch2_btree_iter_traverse(trans, &dir_iter); + bch2_btree_iter_set_snapshot(&dir_iter, dir_snapshot); + ret = bch2_btree_iter_traverse(&dir_iter); if (ret) goto err; } @@ -190,13 +192,13 @@ int bch2_create_trans(struct btree_trans *trans, new_inode->bi_depth = dir_u->bi_depth + 1; inode_iter.flags &= ~BTREE_ITER_all_snapshots; - bch2_btree_iter_set_snapshot(trans, &inode_iter, snapshot); + bch2_btree_iter_set_snapshot(&inode_iter, snapshot); - ret = bch2_btree_iter_traverse(trans, &inode_iter) ?: + ret = bch2_btree_iter_traverse(&inode_iter) ?: bch2_inode_write(trans, &inode_iter, new_inode); err: - bch2_trans_iter_exit(trans, &inode_iter); - bch2_trans_iter_exit(trans, &dir_iter); + bch2_trans_iter_exit(&inode_iter); + bch2_trans_iter_exit(&dir_iter); return ret; } @@ -206,8 +208,8 @@ int bch2_link_trans(struct btree_trans *trans, const struct qstr *name) { struct bch_fs *c = trans->c; - struct btree_iter dir_iter = {}; - struct btree_iter inode_iter = {}; + struct btree_iter dir_iter = { NULL }; + struct btree_iter inode_iter = { NULL }; struct bch_hash_info dir_hash; u64 now = bch2_current_time(c); u64 dir_offset = 0; @@ -252,8 +254,8 @@ int bch2_link_trans(struct btree_trans *trans, ret = bch2_inode_write(trans, &dir_iter, dir_u) ?: bch2_inode_write(trans, &inode_iter, inode_u); err: - bch2_trans_iter_exit(trans, &dir_iter); - bch2_trans_iter_exit(trans, &inode_iter); + bch2_trans_iter_exit(&dir_iter); + bch2_trans_iter_exit(&inode_iter); return ret; } @@ -265,9 +267,9 @@ int bch2_unlink_trans(struct btree_trans *trans, bool deleting_subvol) { struct bch_fs *c = trans->c; - struct btree_iter dir_iter = {}; - struct btree_iter dirent_iter = {}; - struct btree_iter inode_iter = {}; + struct btree_iter dir_iter = { NULL }; + struct btree_iter dirent_iter = { NULL }; + struct btree_iter inode_iter = { NULL }; struct bch_hash_info dir_hash; subvol_inum inum; u64 now = bch2_current_time(c); @@ -313,7 +315,7 @@ int bch2_unlink_trans(struct btree_trans *trans, if (ret) goto err; - k = bch2_btree_iter_peek_slot(trans, &dirent_iter); + k = bch2_btree_iter_peek_slot(&dirent_iter); ret = bkey_err(k); if (ret) goto err; @@ -322,8 +324,8 @@ int bch2_unlink_trans(struct btree_trans *trans, * 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); + bch2_btree_iter_set_snapshot(&dirent_iter, k.k->p.snapshot); + ret = bch2_btree_iter_traverse(&dirent_iter); if (ret) goto err; } else { @@ -345,9 +347,9 @@ int bch2_unlink_trans(struct btree_trans *trans, bch2_inode_write(trans, &dir_iter, dir_u) ?: bch2_inode_write(trans, &inode_iter, inode_u); err: - bch2_trans_iter_exit(trans, &inode_iter); - bch2_trans_iter_exit(trans, &dirent_iter); - bch2_trans_iter_exit(trans, &dir_iter); + bch2_trans_iter_exit(&inode_iter); + bch2_trans_iter_exit(&dirent_iter); + bch2_trans_iter_exit(&dir_iter); return ret; } @@ -391,7 +393,7 @@ static int subvol_update_parent(struct btree_trans *trans, u32 subvol, u32 new_p return ret; s->v.fs_path_parent = cpu_to_le32(new_parent); - bch2_trans_iter_exit(trans, &iter); + bch2_trans_iter_exit(&iter); return 0; } @@ -405,10 +407,10 @@ int bch2_rename_trans(struct btree_trans *trans, enum bch_rename_mode mode) { struct bch_fs *c = trans->c; - struct btree_iter src_dir_iter = {}; - struct btree_iter dst_dir_iter = {}; - struct btree_iter src_inode_iter = {}; - struct btree_iter dst_inode_iter = {}; + struct btree_iter src_dir_iter = { NULL }; + struct btree_iter dst_dir_iter = { NULL }; + struct btree_iter src_inode_iter = { NULL }; + struct btree_iter dst_inode_iter = { NULL }; struct bch_hash_info src_hash, dst_hash; subvol_inum src_inum, dst_inum; u64 src_offset, dst_offset; @@ -580,15 +582,31 @@ int bch2_rename_trans(struct btree_trans *trans, ? bch2_inode_write(trans, &dst_inode_iter, dst_inode_u) : 0); err: - bch2_trans_iter_exit(trans, &dst_inode_iter); - bch2_trans_iter_exit(trans, &src_inode_iter); - bch2_trans_iter_exit(trans, &dst_dir_iter); - bch2_trans_iter_exit(trans, &src_dir_iter); + bch2_trans_iter_exit(&dst_inode_iter); + bch2_trans_iter_exit(&src_inode_iter); + bch2_trans_iter_exit(&dst_dir_iter); + bch2_trans_iter_exit(&src_dir_iter); return ret; } /* inum_to_path */ +static inline void reverse_bytes(void *b, size_t n) +{ + char *e = b + n, *s = b; + + while (s < e) { + --e; + swap(*s, *e); + s++; + } +} + +static inline void printbuf_reverse_from(struct printbuf *out, unsigned pos) +{ + reverse_bytes(out->buf + pos, out->pos - pos); +} + static inline void prt_bytes_reversed(struct printbuf *out, const void *b, unsigned n) { bch2_printbuf_make_room(out, n); @@ -608,15 +626,17 @@ static inline void prt_str_reversed(struct printbuf *out, const char *s) prt_bytes_reversed(out, s, strlen(s)); } -static inline void reverse_bytes(void *b, size_t n) +__printf(2, 3) +static inline void prt_printf_reversed(struct printbuf *out, const char *fmt, ...) { - char *e = b + n, *s = b; + unsigned orig_pos = out->pos; - while (s < e) { - --e; - swap(*s, *e); - s++; - } + va_list args; + va_start(args, fmt); + prt_vprintf(out, fmt, args); + va_end(args); + + printbuf_reverse_from(out, orig_pos); } static int __bch2_inum_to_path(struct btree_trans *trans, @@ -637,7 +657,7 @@ static int __bch2_inum_to_path(struct btree_trans *trans, subvol_inum n = (subvol_inum) { subvol ?: snapshot, inum }; if (darray_find_p(inums, i, i->subvol == n.subvol && i->inum == n.inum)) { - prt_str_reversed(path, "(loop)"); + prt_printf_reversed(path, "(loop at %llu:%u)", inum, snapshot); break; } @@ -681,27 +701,27 @@ static int __bch2_inum_to_path(struct btree_trans *trans, prt_char(path, '/'); - bch2_trans_iter_exit(trans, &d_iter); + bch2_trans_iter_exit(&d_iter); } if (orig_pos == path->pos) prt_char(path, '/'); out: + if (bch2_err_matches(ret, BCH_ERR_transaction_restart)) + goto err; + ret = path->allocation_failure ? -ENOMEM : 0; if (ret) goto err; - reverse_bytes(path->buf + orig_pos, path->pos - orig_pos); + printbuf_reverse_from(path, orig_pos); darray_exit(&inums); return 0; err: darray_exit(&inums); return ret; disconnected: - if (bch2_err_matches(ret, BCH_ERR_transaction_restart)) - goto err; - - prt_str_reversed(path, "(disconnected)"); + prt_printf_reversed(path, "(disconnected at %llu.%u)", inum, snapshot); goto out; } @@ -727,7 +747,7 @@ static int bch2_check_dirent_inode_dirent(struct btree_trans *trans, bool in_fsck) { struct bch_fs *c = trans->c; - struct printbuf buf = PRINTBUF; + CLASS(printbuf, buf)(); struct btree_iter bp_iter = {}; int ret = 0; @@ -834,8 +854,7 @@ static int bch2_check_dirent_inode_dirent(struct btree_trans *trans, out: err: fsck_err: - bch2_trans_iter_exit(trans, &bp_iter); - printbuf_exit(&buf); + bch2_trans_iter_exit(&bp_iter); bch_err_fn(c, ret); return ret; } @@ -847,7 +866,7 @@ int __bch2_check_dirent_target(struct btree_trans *trans, bool in_fsck) { struct bch_fs *c = trans->c; - struct printbuf buf = PRINTBUF; + CLASS(printbuf, buf)(); int ret = 0; ret = bch2_check_dirent_inode_dirent(trans, d, target, in_fsck); @@ -882,7 +901,6 @@ int __bch2_check_dirent_target(struct btree_trans *trans, } err: fsck_err: - printbuf_exit(&buf); bch_err_fn(c, ret); return ret; } @@ -913,14 +931,14 @@ static int bch2_propagate_has_case_insensitive(struct btree_trans *trans, subvol if (ret) break; - bch2_trans_iter_exit(trans, &iter); + bch2_trans_iter_exit(&iter); if (subvol_inum_eq(inum, BCACHEFS_ROOT_SUBVOL_INUM)) break; inum = parent_inum(inum, &inode); } - bch2_trans_iter_exit(trans, &iter); + bch2_trans_iter_exit(&iter); return ret; } @@ -940,7 +958,7 @@ int bch2_check_inode_has_case_insensitive(struct btree_trans *trans, snapshot_id_list *snapshot_overwrites, bool *do_update) { - struct printbuf buf = PRINTBUF; + CLASS(printbuf, buf)(); bool repairing_parents = false; int ret = 0; @@ -967,7 +985,7 @@ int bch2_check_inode_has_case_insensitive(struct btree_trans *trans, ret = bch2_inum_snapshot_to_path(trans, inode->bi_inum, inode->bi_snapshot, snapshot_overwrites, &buf); if (ret) - goto err; + return ret; if (fsck_err(trans, inode_has_case_insensitive_not_set, "%s", buf.buf)) { inode->bi_flags |= BCH_INODE_has_case_insensitive; @@ -986,14 +1004,14 @@ int bch2_check_inode_has_case_insensitive(struct btree_trans *trans, if (dir.bi_parent_subvol) { ret = bch2_subvolume_get_snapshot(trans, dir.bi_parent_subvol, &snapshot); if (ret) - goto err; + return ret; snapshot_overwrites = NULL; } ret = bch2_inode_find_by_inum_snapshot(trans, dir.bi_dir, snapshot, &dir, 0); if (ret) - goto err; + return ret; if (!(dir.bi_flags & BCH_INODE_has_case_insensitive)) { prt_printf(&buf, "parent of casefolded dir with has_case_insensitive not set\n"); @@ -1001,13 +1019,13 @@ int bch2_check_inode_has_case_insensitive(struct btree_trans *trans, ret = bch2_inum_snapshot_to_path(trans, dir.bi_inum, dir.bi_snapshot, snapshot_overwrites, &buf); if (ret) - goto err; + return ret; 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; + return ret; } } @@ -1019,9 +1037,7 @@ int bch2_check_inode_has_case_insensitive(struct btree_trans *trans, break; } out: -err: fsck_err: - printbuf_exit(&buf); if (ret) return ret; |