summaryrefslogtreecommitdiff
path: root/fs/bcachefs/namei.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/bcachefs/namei.c')
-rw-r--r--fs/bcachefs/namei.c136
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;