summaryrefslogtreecommitdiff
path: root/fs/bcachefs/inode.c
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2019-06-30 16:28:01 -0400
committerKent Overstreet <kent.overstreet@gmail.com>2020-05-06 17:14:16 -0400
commitea5715a73506eb929e43b66eb3b87c94e2b44ab4 (patch)
treea145b47f47c831f20c6ee694995a5f9b7e2e6e31 /fs/bcachefs/inode.c
parent5f6131b81dfa624673447c41cfb69c151086b802 (diff)
Merge with 1f431b384d bcachefs: Refactor trans_(get|update)_key
Diffstat (limited to 'fs/bcachefs/inode.c')
-rw-r--r--fs/bcachefs/inode.c346
1 files changed, 168 insertions, 178 deletions
diff --git a/fs/bcachefs/inode.c b/fs/bcachefs/inode.c
index 81d040d46e41..05b7f6594113 100644
--- a/fs/bcachefs/inode.c
+++ b/fs/bcachefs/inode.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
#include "bcachefs.h"
#include "bkey_methods.h"
@@ -12,7 +13,12 @@
#include <asm/unaligned.h>
-#define FIELD_BYTES() \
+const char * const bch2_inode_opts[] = {
+#define x(name, ...) #name,
+ BCH_INODE_OPTS()
+#undef x
+ NULL,
+};
static const u8 byte_table[8] = { 1, 2, 3, 4, 6, 8, 10, 13 };
static const u8 bits_table[8] = {
@@ -97,7 +103,7 @@ void bch2_inode_pack(struct bkey_inode_buf *packed,
packed->inode.v.bi_flags = cpu_to_le32(inode->bi_flags);
packed->inode.v.bi_mode = cpu_to_le16(inode->bi_mode);
-#define BCH_INODE_FIELD(_name, _bits) \
+#define x(_name, _bits) \
out += inode_encode_field(out, end, 0, inode->_name); \
nr_fields++; \
\
@@ -107,7 +113,7 @@ void bch2_inode_pack(struct bkey_inode_buf *packed,
}
BCH_INODE_FIELDS()
-#undef BCH_INODE_FIELD
+#undef x
out = last_nonzero_field;
nr_fields = last_nonzero_fieldnr;
@@ -129,9 +135,9 @@ void bch2_inode_pack(struct bkey_inode_buf *packed,
BUG_ON(unpacked.bi_hash_seed != inode->bi_hash_seed);
BUG_ON(unpacked.bi_mode != inode->bi_mode);
-#define BCH_INODE_FIELD(_name, _bits) BUG_ON(unpacked._name != inode->_name);
+#define x(_name, _bits) BUG_ON(unpacked._name != inode->_name);
BCH_INODE_FIELDS()
-#undef BCH_INODE_FIELD
+#undef x
}
}
@@ -149,7 +155,7 @@ int bch2_inode_unpack(struct bkey_s_c_inode inode,
unpacked->bi_flags = le32_to_cpu(inode.v->bi_flags);
unpacked->bi_mode = le16_to_cpu(inode.v->bi_mode);
-#define BCH_INODE_FIELD(_name, _bits) \
+#define x(_name, _bits) \
if (fieldnr++ == INODE_NR_FIELDS(inode.v)) { \
memset(&unpacked->_name, 0, \
sizeof(*unpacked) - \
@@ -168,7 +174,7 @@ int bch2_inode_unpack(struct bkey_s_c_inode inode,
in += ret;
BCH_INODE_FIELDS()
-#undef BCH_INODE_FIELD
+#undef x
/* XXX: signal if there were more fields than expected? */
@@ -177,88 +183,86 @@ int bch2_inode_unpack(struct bkey_s_c_inode inode,
const char *bch2_inode_invalid(const struct bch_fs *c, struct bkey_s_c k)
{
- if (k.k->p.offset)
- return "nonzero offset";
-
- switch (k.k->type) {
- case BCH_INODE_FS: {
struct bkey_s_c_inode inode = bkey_s_c_to_inode(k);
struct bch_inode_unpacked unpacked;
- if (bkey_val_bytes(k.k) < sizeof(struct bch_inode))
- return "incorrect value size";
+ if (k.k->p.offset)
+ return "nonzero offset";
- if (k.k->p.inode < BLOCKDEV_INODE_MAX)
- return "fs inode in blockdev range";
+ if (bkey_val_bytes(k.k) < sizeof(struct bch_inode))
+ return "incorrect value size";
- if (INODE_STR_HASH(inode.v) >= BCH_STR_HASH_NR)
- return "invalid str hash type";
+ if (k.k->p.inode < BLOCKDEV_INODE_MAX)
+ return "fs inode in blockdev range";
- if (bch2_inode_unpack(inode, &unpacked))
- return "invalid variable length fields";
+ if (INODE_STR_HASH(inode.v) >= BCH_STR_HASH_NR)
+ return "invalid str hash type";
- if (unpacked.bi_data_checksum >= BCH_CSUM_OPT_NR + 1)
- return "invalid data checksum type";
+ if (bch2_inode_unpack(inode, &unpacked))
+ return "invalid variable length fields";
- if (unpacked.bi_compression >= BCH_COMPRESSION_OPT_NR + 1)
- return "invalid data checksum type";
+ if (unpacked.bi_data_checksum >= BCH_CSUM_OPT_NR + 1)
+ return "invalid data checksum type";
- return NULL;
- }
- case BCH_INODE_BLOCKDEV:
- if (bkey_val_bytes(k.k) != sizeof(struct bch_inode_blockdev))
- return "incorrect value size";
+ if (unpacked.bi_compression >= BCH_COMPRESSION_OPT_NR + 1)
+ return "invalid data checksum type";
- if (k.k->p.inode >= BLOCKDEV_INODE_MAX)
- return "blockdev inode in fs range";
+ if ((unpacked.bi_flags & BCH_INODE_UNLINKED) &&
+ unpacked.bi_nlink != 0)
+ return "flagged as unlinked but bi_nlink != 0";
- return NULL;
- case BCH_INODE_GENERATION:
- if (bkey_val_bytes(k.k) != sizeof(struct bch_inode_generation))
- return "incorrect value size";
+ return NULL;
+}
- return NULL;
- default:
- return "invalid type";
+void bch2_inode_to_text(struct printbuf *out, struct bch_fs *c,
+ struct bkey_s_c k)
+{
+ struct bkey_s_c_inode inode = bkey_s_c_to_inode(k);
+ struct bch_inode_unpacked unpacked;
+
+ if (bch2_inode_unpack(inode, &unpacked)) {
+ pr_buf(out, "(unpack error)");
+ return;
}
+
+#define x(_name, _bits) \
+ pr_buf(out, #_name ": %llu ", (u64) unpacked._name);
+ BCH_INODE_FIELDS()
+#undef x
}
-void bch2_inode_to_text(struct bch_fs *c, char *buf,
- size_t size, struct bkey_s_c k)
+const char *bch2_inode_generation_invalid(const struct bch_fs *c,
+ struct bkey_s_c k)
{
- char *out = buf, *end = out + size;
- struct bkey_s_c_inode inode;
- struct bch_inode_unpacked unpacked;
+ if (k.k->p.offset)
+ return "nonzero offset";
- switch (k.k->type) {
- case BCH_INODE_FS:
- inode = bkey_s_c_to_inode(k);
- if (bch2_inode_unpack(inode, &unpacked)) {
- out += scnprintf(out, end - out, "(unpack error)");
- break;
- }
+ if (bkey_val_bytes(k.k) != sizeof(struct bch_inode_generation))
+ return "incorrect value size";
-#define BCH_INODE_FIELD(_name, _bits) \
- out += scnprintf(out, end - out, #_name ": %llu ", (u64) unpacked._name);
- BCH_INODE_FIELDS()
-#undef BCH_INODE_FIELD
- break;
- }
+ return NULL;
+}
+
+void bch2_inode_generation_to_text(struct printbuf *out, struct bch_fs *c,
+ struct bkey_s_c k)
+{
+ struct bkey_s_c_inode_generation gen = bkey_s_c_to_inode_generation(k);
+
+ pr_buf(out, "generation: %u", le32_to_cpu(gen.v->bi_generation));
}
void bch2_inode_init(struct bch_fs *c, struct bch_inode_unpacked *inode_u,
uid_t uid, gid_t gid, umode_t mode, dev_t rdev,
struct bch_inode_unpacked *parent)
{
- s64 now = timespec_to_bch2_time(c,
- timespec64_trunc(current_kernel_time64(),
- c->sb.time_precision));
+ s64 now = bch2_current_time(c);
memset(inode_u, 0, sizeof(*inode_u));
/* ick */
inode_u->bi_flags |= c->opts.str_hash << INODE_STR_HASH_OFFSET;
- get_random_bytes(&inode_u->bi_hash_seed, sizeof(inode_u->bi_hash_seed));
+ get_random_bytes(&inode_u->bi_hash_seed,
+ sizeof(inode_u->bi_hash_seed));
inode_u->bi_mode = mode;
inode_u->bi_uid = uid;
@@ -270,18 +274,32 @@ void bch2_inode_init(struct bch_fs *c, struct bch_inode_unpacked *inode_u,
inode_u->bi_otime = now;
if (parent) {
-#define BCH_INODE_FIELD(_name) inode_u->_name = parent->_name;
- BCH_INODE_FIELDS_INHERIT()
-#undef BCH_INODE_FIELD
+#define x(_name, ...) inode_u->bi_##_name = parent->bi_##_name;
+ BCH_INODE_OPTS()
+#undef x
}
}
-int bch2_inode_create(struct bch_fs *c, struct bch_inode_unpacked *inode_u,
- u64 min, u64 max, u64 *hint)
+static inline u32 bkey_generation(struct bkey_s_c k)
{
- struct bkey_inode_buf inode_p;
- struct btree_iter iter;
- bool searched_from_start = false;
+ switch (k.k->type) {
+ case KEY_TYPE_inode:
+ BUG();
+ case KEY_TYPE_inode_generation:
+ return le32_to_cpu(bkey_s_c_to_inode_generation(k).v->bi_generation);
+ default:
+ return 0;
+ }
+}
+
+int __bch2_inode_create(struct btree_trans *trans,
+ struct bch_inode_unpacked *inode_u,
+ u64 min, u64 max, u64 *hint)
+{
+ struct bch_fs *c = trans->c;
+ struct bkey_inode_buf *inode_p;
+ struct btree_iter *iter;
+ u64 start;
int ret;
if (!max)
@@ -290,109 +308,75 @@ int bch2_inode_create(struct bch_fs *c, struct bch_inode_unpacked *inode_u,
if (c->opts.inodes_32bit)
max = min_t(u64, max, U32_MAX);
- if (*hint >= max || *hint < min)
- *hint = min;
+ start = READ_ONCE(*hint);
- if (*hint == min)
- searched_from_start = true;
-again:
- bch2_btree_iter_init(&iter, c, BTREE_ID_INODES, POS(*hint, 0),
- BTREE_ITER_SLOTS|BTREE_ITER_INTENT);
+ if (start >= max || start < min)
+ start = min;
+
+ inode_p = bch2_trans_kmalloc(trans, sizeof(*inode_p));
+ if (IS_ERR(inode_p))
+ return PTR_ERR(inode_p);
+ iter = bch2_trans_get_iter(trans,
+ BTREE_ID_INODES, POS(start, 0),
+ BTREE_ITER_SLOTS|BTREE_ITER_INTENT);
+ if (IS_ERR(iter))
+ return PTR_ERR(iter);
+again:
while (1) {
- struct bkey_s_c k = bch2_btree_iter_peek_slot(&iter);
- u32 bi_generation = 0;
+ struct bkey_s_c k = bch2_btree_iter_peek_slot(iter);
- ret = btree_iter_err(k);
- if (ret) {
- bch2_btree_iter_unlock(&iter);
+ ret = bkey_err(k);
+ if (ret)
return ret;
- }
switch (k.k->type) {
- case BCH_INODE_BLOCKDEV:
- case BCH_INODE_FS:
+ case KEY_TYPE_inode:
/* slot used */
- if (iter.pos.inode == max)
+ if (iter->pos.inode >= max)
goto out;
- bch2_btree_iter_next_slot(&iter);
+ bch2_btree_iter_next_slot(iter);
break;
- case BCH_INODE_GENERATION: {
- struct bkey_s_c_inode_generation g =
- bkey_s_c_to_inode_generation(k);
- bi_generation = le32_to_cpu(g.v->bi_generation);
- /* fallthrough: */
- }
default:
- inode_u->bi_generation = bi_generation;
-
- bch2_inode_pack(&inode_p, inode_u);
- inode_p.inode.k.p = k.k->p;
-
- ret = bch2_btree_insert_at(c, NULL, NULL, NULL,
- BTREE_INSERT_ATOMIC,
- BTREE_INSERT_ENTRY(&iter,
- &inode_p.inode.k_i));
-
- if (ret != -EINTR) {
- bch2_btree_iter_unlock(&iter);
-
- if (!ret) {
- inode_u->bi_inum =
- inode_p.inode.k.p.inode;
- *hint = inode_p.inode.k.p.inode + 1;
- }
-
- return ret;
- }
-
- if (ret == -EINTR)
- continue;
-
+ *hint = k.k->p.inode;
+ inode_u->bi_inum = k.k->p.inode;
+ inode_u->bi_generation = bkey_generation(k);
+
+ bch2_inode_pack(inode_p, inode_u);
+ bch2_trans_update(trans,
+ BTREE_INSERT_ENTRY(iter, &inode_p->inode.k_i));
+ return 0;
}
}
out:
- bch2_btree_iter_unlock(&iter);
-
- if (!searched_from_start) {
+ if (start != min) {
/* Retry from start */
- *hint = min;
- searched_from_start = true;
+ start = min;
+ bch2_btree_iter_set_pos(iter, POS(start, 0));
goto again;
}
return -ENOSPC;
}
-int bch2_inode_truncate(struct bch_fs *c, u64 inode_nr, u64 new_size,
- struct extent_insert_hook *hook, u64 *journal_seq)
+int bch2_inode_create(struct bch_fs *c, struct bch_inode_unpacked *inode_u,
+ u64 min, u64 max, u64 *hint)
{
- return bch2_btree_delete_range(c, BTREE_ID_EXTENTS,
- POS(inode_nr, new_size),
- POS(inode_nr + 1, 0),
- ZERO_VERSION, NULL, hook,
- journal_seq);
+ return bch2_trans_do(c, NULL, BTREE_INSERT_ATOMIC,
+ __bch2_inode_create(&trans, inode_u, min, max, hint));
}
int bch2_inode_rm(struct bch_fs *c, u64 inode_nr)
{
- struct btree_iter iter;
+ struct btree_trans trans;
+ struct btree_iter *iter;
struct bkey_i_inode_generation delete;
+ struct bpos start = POS(inode_nr, 0);
+ struct bpos end = POS(inode_nr + 1, 0);
int ret;
- ret = bch2_inode_truncate(c, inode_nr, 0, NULL, NULL);
- if (ret < 0)
- return ret;
-
- ret = bch2_btree_delete_range(c, BTREE_ID_XATTRS,
- POS(inode_nr, 0),
- POS(inode_nr + 1, 0),
- ZERO_VERSION, NULL, NULL, NULL);
- if (ret < 0)
- return ret;
-
/*
* If this was a directory, there shouldn't be any real dirents left -
* but there could be whiteouts (from hash collisions) that we should
@@ -401,38 +385,40 @@ int bch2_inode_rm(struct bch_fs *c, u64 inode_nr)
* XXX: the dirent could ideally would delete whiteouts when they're no
* longer needed
*/
- ret = bch2_btree_delete_range(c, BTREE_ID_DIRENTS,
- POS(inode_nr, 0),
- POS(inode_nr + 1, 0),
- ZERO_VERSION, NULL, NULL, NULL);
- if (ret < 0)
+ ret = bch2_btree_delete_range(c, BTREE_ID_EXTENTS,
+ start, end, NULL) ?:
+ bch2_btree_delete_range(c, BTREE_ID_XATTRS,
+ start, end, NULL) ?:
+ bch2_btree_delete_range(c, BTREE_ID_DIRENTS,
+ start, end, NULL);
+ if (ret)
return ret;
- bch2_btree_iter_init(&iter, c, BTREE_ID_INODES, POS(inode_nr, 0),
- BTREE_ITER_SLOTS|BTREE_ITER_INTENT);
+ bch2_trans_init(&trans, c, 0, 0);
+
+ iter = bch2_trans_get_iter(&trans, BTREE_ID_INODES, POS(inode_nr, 0),
+ BTREE_ITER_SLOTS|BTREE_ITER_INTENT);
do {
- struct bkey_s_c k = bch2_btree_iter_peek_slot(&iter);
+ struct bkey_s_c k = bch2_btree_iter_peek_slot(iter);
u32 bi_generation = 0;
- ret = btree_iter_err(k);
- if (ret) {
- bch2_btree_iter_unlock(&iter);
- return ret;
- }
+ ret = bkey_err(k);
+ if (ret)
+ break;
- bch2_fs_inconsistent_on(k.k->type != BCH_INODE_FS, c,
+ bch2_fs_inconsistent_on(k.k->type != KEY_TYPE_inode, c,
"inode %llu not found when deleting",
inode_nr);
switch (k.k->type) {
- case BCH_INODE_FS: {
+ case KEY_TYPE_inode: {
struct bch_inode_unpacked inode_u;
if (!bch2_inode_unpack(bkey_s_c_to_inode(k), &inode_u))
bi_generation = inode_u.bi_generation + 1;
break;
}
- case BCH_INODE_GENERATION: {
+ case KEY_TYPE_inode_generation: {
struct bkey_s_c_inode_generation g =
bkey_s_c_to_inode_generation(k);
bi_generation = le32_to_cpu(g.v->bi_generation);
@@ -449,40 +435,44 @@ int bch2_inode_rm(struct bch_fs *c, u64 inode_nr)
delete.v.bi_generation = cpu_to_le32(bi_generation);
}
- ret = bch2_btree_insert_at(c, NULL, NULL, NULL,
- BTREE_INSERT_ATOMIC|
- BTREE_INSERT_NOFAIL,
- BTREE_INSERT_ENTRY(&iter, &delete.k_i));
+ bch2_trans_update(&trans,
+ BTREE_INSERT_ENTRY(iter, &delete.k_i));
+
+ ret = bch2_trans_commit(&trans, NULL, NULL,
+ BTREE_INSERT_ATOMIC|
+ BTREE_INSERT_NOFAIL);
} while (ret == -EINTR);
- bch2_btree_iter_unlock(&iter);
+ bch2_trans_exit(&trans);
return ret;
}
-int bch2_inode_find_by_inum(struct bch_fs *c, u64 inode_nr,
- struct bch_inode_unpacked *inode)
+int bch2_inode_find_by_inum_trans(struct btree_trans *trans, u64 inode_nr,
+ struct bch_inode_unpacked *inode)
{
- struct btree_iter iter;
+ struct btree_iter *iter;
struct bkey_s_c k;
int ret = -ENOENT;
- for_each_btree_key(&iter, c, BTREE_ID_INODES,
- POS(inode_nr, 0),
- BTREE_ITER_SLOTS, k) {
- switch (k.k->type) {
- case BCH_INODE_FS:
- ret = bch2_inode_unpack(bkey_s_c_to_inode(k), inode);
- break;
- default:
- /* hole, not found */
- break;
- }
+ iter = bch2_trans_get_iter(trans, BTREE_ID_INODES,
+ POS(inode_nr, 0), BTREE_ITER_SLOTS);
+ if (IS_ERR(iter))
+ return PTR_ERR(iter);
- break;
+ k = bch2_btree_iter_peek_slot(iter);
+ if (k.k->type == KEY_TYPE_inode)
+ ret = bch2_inode_unpack(bkey_s_c_to_inode(k), inode);
- }
+ bch2_trans_iter_put(trans, iter);
- return bch2_btree_iter_unlock(&iter) ?: ret;
+ return ret;
+}
+
+int bch2_inode_find_by_inum(struct bch_fs *c, u64 inode_nr,
+ struct bch_inode_unpacked *inode)
+{
+ return bch2_trans_do(c, NULL, 0,
+ bch2_inode_find_by_inum_trans(&trans, inode_nr, inode));
}
#ifdef CONFIG_BCACHEFS_DEBUG