summaryrefslogtreecommitdiffstats
path: root/fs/bcachefs/dirent.c
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2021-03-16 00:46:26 -0400
committerKent Overstreet <kent.overstreet@linux.dev>2023-10-22 17:09:12 -0400
commitb9e1adf57988fb4632b86c43fde1551a24299b86 (patch)
tree3f6d8942ede2c864a84cb66501bf80d7682c60a7 /fs/bcachefs/dirent.c
parent14b393ee768e8339b9c64f82df24e8c081bdbff9 (diff)
downloadlinux-b9e1adf57988fb4632b86c43fde1551a24299b86.tar.gz
linux-b9e1adf57988fb4632b86c43fde1551a24299b86.tar.bz2
linux-b9e1adf57988fb4632b86c43fde1551a24299b86.zip
bcachefs: Add support for dirents that point to subvolumes
Dirents currently always point to inodes. Subvolumes add a new type of dirent, with d_type DT_SUBVOL, that instead points to an entry in the subvolumes btree, and the subvolume has a pointer to the root inode. This patch adds bch2_dirent_read_target() to get the inode (and potentially subvolume) a dirent points to, and changes existing code to use that instead of reading from d_inum directly. Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
Diffstat (limited to 'fs/bcachefs/dirent.c')
-rw-r--r--fs/bcachefs/dirent.c105
1 files changed, 87 insertions, 18 deletions
diff --git a/fs/bcachefs/dirent.c b/fs/bcachefs/dirent.c
index 53c7687a9ca8..f3aef0686928 100644
--- a/fs/bcachefs/dirent.c
+++ b/fs/bcachefs/dirent.c
@@ -177,6 +177,61 @@ static void dirent_copy_target(struct bkey_i_dirent *dst,
dst->v.d_type = src.v->d_type;
}
+int __bch2_dirent_read_target(struct btree_trans *trans,
+ struct bkey_s_c_dirent d,
+ u32 *subvol, u32 *snapshot, u64 *inum,
+ bool is_fsck)
+{
+ int ret = 0;
+
+ *subvol = 0;
+ *snapshot = d.k->p.snapshot;
+
+ if (likely(d.v->d_type != DT_SUBVOL)) {
+ *inum = le64_to_cpu(d.v->d_inum);
+ } else {
+ struct btree_iter iter;
+ struct bkey_s_c k;
+ struct bkey_s_c_subvolume s;
+ int ret;
+
+ *subvol = le64_to_cpu(d.v->d_inum);
+ bch2_trans_iter_init(trans, &iter, BTREE_ID_subvolumes,
+ POS(0, *subvol),
+ BTREE_ITER_CACHED);
+ k = bch2_btree_iter_peek_slot(&iter);
+ ret = bkey_err(k);
+ if (ret)
+ goto err;
+
+ if (k.k->type != KEY_TYPE_subvolume) {
+ ret = -ENOENT;
+ goto err;
+ }
+
+ s = bkey_s_c_to_subvolume(k);
+ *snapshot = le32_to_cpu(s.v->snapshot);
+ *inum = le64_to_cpu(s.v->inode);
+err:
+ if (ret == -ENOENT && !is_fsck)
+ bch2_fs_inconsistent(trans->c, "pointer to missing subvolume %u",
+ *subvol);
+
+ bch2_trans_iter_exit(trans, &iter);
+ }
+
+ return ret;
+}
+
+int bch2_dirent_read_target(struct btree_trans *trans,
+ struct bkey_s_c_dirent d, u64 *target)
+{
+ u32 subvol, snapshot;
+
+ return __bch2_dirent_read_target(trans, d, &subvol,
+ &snapshot, target, false);
+}
+
int bch2_dirent_rename(struct btree_trans *trans,
u64 src_dir, struct bch_hash_info *src_hash,
u64 dst_dir, struct bch_hash_info *dst_hash,
@@ -323,10 +378,32 @@ int __bch2_dirent_lookup_trans(struct btree_trans *trans,
struct btree_iter *iter,
u64 dir_inum,
const struct bch_hash_info *hash_info,
- const struct qstr *name, unsigned flags)
+ const struct qstr *name, u64 *inum,
+ unsigned flags)
{
- return bch2_hash_lookup(trans, iter, bch2_dirent_hash_desc,
- hash_info, dir_inum, name, flags);
+ struct bkey_s_c k;
+ struct bkey_s_c_dirent d;
+ int ret;
+
+ ret = bch2_hash_lookup(trans, iter, bch2_dirent_hash_desc,
+ hash_info, dir_inum, name, flags);
+ if (ret)
+ return ret;
+
+ k = bch2_btree_iter_peek_slot(iter);
+ ret = bkey_err(k);
+ if (ret) {
+ bch2_trans_iter_exit(trans, iter);
+ return ret;
+ }
+
+ d = bkey_s_c_to_dirent(k);
+
+ ret = bch2_dirent_read_target(trans, d, inum);
+ if (ret)
+ bch2_trans_iter_exit(trans, iter);
+
+ return ret;
}
u64 bch2_dirent_lookup(struct bch_fs *c, u64 dir_inum,
@@ -335,26 +412,18 @@ u64 bch2_dirent_lookup(struct bch_fs *c, u64 dir_inum,
{
struct btree_trans trans;
struct btree_iter iter;
- struct bkey_s_c k;
u64 inum = 0;
int ret = 0;
bch2_trans_init(&trans, c, 0, 0);
+retry:
+ bch2_trans_begin(&trans);
+ ret = __bch2_dirent_lookup_trans(&trans, &iter, dir_inum, hash_info,
+ name, &inum, 0);
- ret = __bch2_dirent_lookup_trans(&trans, &iter, dir_inum,
- hash_info, name, 0);
- if (ret)
- goto out;
-
- k = bch2_btree_iter_peek_slot(&iter);
- ret = bkey_err(k);
- if (ret)
- goto out;
-
- inum = le64_to_cpu(bkey_s_c_to_dirent(k).v->d_inum);
bch2_trans_iter_exit(&trans, &iter);
-out:
- BUG_ON(ret == -EINTR);
+ if (ret == -EINTR)
+ goto retry;
bch2_trans_exit(&trans);
return inum;
}
@@ -408,7 +477,7 @@ int bch2_readdir(struct bch_fs *c, u64 inum, struct dir_context *ctx)
if (!dir_emit(ctx, dirent.v->d_name,
bch2_dirent_name_bytes(dirent),
le64_to_cpu(dirent.v->d_inum),
- dirent.v->d_type))
+ vfs_d_type(dirent.v->d_type)))
break;
ctx->pos = dirent.k->p.offset + 1;
}