summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2016-08-06 02:40:00 -0800
committerKent Overstreet <kent.overstreet@gmail.com>2016-09-25 06:00:45 -0800
commit8450ff5224cfc14662e8daa04572a796bc669e0e (patch)
tree0b6eb24111bbfe196fcfb63c0d3ab474c32f0b7f
parent5c0dc2453210037dc913e2e1f99db823fbb85099 (diff)
bcachefs: implement i_generation
-rw-r--r--drivers/md/bcache/blockdev.c11
-rw-r--r--drivers/md/bcache/fs.c4
-rw-r--r--drivers/md/bcache/inode.c129
-rw-r--r--drivers/md/bcache/inode.h5
4 files changed, 107 insertions, 42 deletions
diff --git a/drivers/md/bcache/blockdev.c b/drivers/md/bcache/blockdev.c
index 81fc5c8dd360..ad93454e9df4 100644
--- a/drivers/md/bcache/blockdev.c
+++ b/drivers/md/bcache/blockdev.c
@@ -428,9 +428,9 @@ int bch_cached_dev_attach(struct cached_dev *dc, struct cache_set *c)
dc->disk.inode.v.i_ctime = rtime;
dc->disk.inode.v.i_mtime = rtime;
- ret = bch_inode_create(c, &dc->disk.inode.k_i,
- 0, BLOCKDEV_INODE_MAX,
- &c->unused_inode_hint);
+ ret = bch_blockdev_inode_create(c, &dc->disk.inode.k_i,
+ 0, BLOCKDEV_INODE_MAX,
+ &c->unused_inode_hint);
if (ret) {
pr_err("Error %d, not caching %s", ret, buf);
return ret;
@@ -766,8 +766,9 @@ int bch_blockdev_volume_create(struct cache_set *c, u64 size)
inode.v.i_mtime = rtime;
inode.v.i_size = cpu_to_le64(size);
- ret = bch_inode_create(c, &inode.k_i, 0, BLOCKDEV_INODE_MAX,
- &c->unused_inode_hint);
+ ret = bch_blockdev_inode_create(c, &inode.k_i,
+ 0, BLOCKDEV_INODE_MAX,
+ &c->unused_inode_hint);
if (ret) {
pr_err("Can't create volume: %d", ret);
return ret;
diff --git a/drivers/md/bcache/fs.c b/drivers/md/bcache/fs.c
index 21fa1107b571..50809e8f919c 100644
--- a/drivers/md/bcache/fs.c
+++ b/drivers/md/bcache/fs.c
@@ -217,9 +217,7 @@ static struct inode *bch_vfs_inode_create(struct cache_set *c,
get_random_bytes(&bi->i_hash_seed, sizeof(bi->i_hash_seed));
SET_INODE_STR_HASH_TYPE(bi, c->sb.str_hash_type);
- ret = bch_inode_create(c, &bkey_inode.k_i,
- BLOCKDEV_INODE_MAX, 0,
- &c->unused_inode_hint);
+ ret = bch_inode_create(c, &bkey_inode);
if (unlikely(ret)) {
/*
* indicate to bch_evict_inode that the inode was never actually
diff --git a/drivers/md/bcache/inode.c b/drivers/md/bcache/inode.c
index c138c5424c1d..9e4151378da0 100644
--- a/drivers/md/bcache/inode.c
+++ b/drivers/md/bcache/inode.c
@@ -6,6 +6,7 @@
#include "inode.h"
#include "io.h"
#include "keylist.h"
+#include "trans.h"
ssize_t bch_inode_status(char *buf, size_t len, const struct bkey *k)
{
@@ -108,65 +109,127 @@ const struct bkey_ops bch_bkey_inode_ops = {
.val_to_text = bch_inode_to_text,
};
-int bch_inode_create(struct cache_set *c, struct bkey_i *inode,
- u64 min, u64 max, u64 *hint)
+int bch_inode_find_slot(struct cache_set *c, struct btree_iter *iter, u64 max)
{
- struct btree_iter iter;
struct bkey_s_c k;
+
+ while ((k = bch_btree_iter_peek_with_holes(iter)).k) {
+ if (k.k->p.inode >= max)
+ break;
+
+ if (k.k->type < BCH_INODE_FS)
+ return 0;
+
+ /* slot used */
+ bch_btree_iter_advance_pos(iter);
+ }
+
+ return -ENOSPC;
+}
+
+int bch_inode_create(struct cache_set *c, struct bkey_i_inode *inode)
+{
+ struct btree_iter iter;
bool searched_from_start = false;
+ struct bch_trans_inode_create *trans = &c->inode_create;
+ u64 min = BCACHE_ROOT_INO;
+ u64 max = c->opts.inodes_32bit ? U32_MAX : U64_MAX;
+ u64 ino;
int ret;
- if (!max)
- max = ULLONG_MAX;
+ mutex_lock(&c->inode_create_lock);
- if (c->opts.inodes_32bit)
- max = min_t(u64, max, U32_MAX);
+ if (!bch_transaction_active(&trans->t)) {
+ bkey_trans_inode_create_val_init(&trans->k.k_i);
+ trans->k.v.ino = cpu_to_le64(min);
+ bch_transaction_start(c, &trans->t);
+ }
- if (*hint >= max || *hint < min)
- *hint = min;
+ ino = clamp(le64_to_cpu(trans->k.v.ino), min, max);
- if (*hint == min)
+ if (ino == min)
searched_from_start = true;
again:
- bch_btree_iter_init_intent(&iter, c, BTREE_ID_INODES, POS(*hint, 0));
+ bch_btree_iter_init_intent(&iter, c, BTREE_ID_INODES, POS(ino, 0));
- while ((k = bch_btree_iter_peek_with_holes(&iter)).k) {
- if (k.k->p.inode >= max)
+ do {
+ struct bkey_i_trans_inode_create_val new_trans = trans->k;
+
+ ret = bch_inode_find_slot(c, &iter, max);
+ if (ret && !searched_from_start) {
+ bch_btree_iter_unlock(&iter);
+ ino = min;
+ searched_from_start = true;
+ goto again;
+ }
+
+ if (ret)
break;
- if (k.k->type < BCH_INODE_FS) {
- inode->k.p = k.k->p;
+ inode->k.p = iter.pos;
- pr_debug("inserting inode %llu (size %u)",
- inode->k.p.inode, inode->k.u64s);
+ if (inode->k.p.inode < le64_to_cpu(trans->k.v.ino))
+ le64_add_cpu(&new_trans.v.gen, 1);
- ret = bch_btree_insert_at(c, NULL, NULL, NULL,
- BTREE_INSERT_ATOMIC,
- BTREE_INSERT_ENTRY(&iter, inode));
+ /* XXX set inode gen from trans_inode_create gen */
- if (ret == -EINTR)
- continue;
+ new_trans.v.ino = le64_to_cpu(inode->k.p.inode + 1);
- bch_btree_iter_unlock(&iter);
- if (!ret)
- *hint = k.k->p.inode + 1;
+ pr_debug("inserting inode %llu (size %u)",
+ inode->k.p.inode, inode->k.u64s);
+
+ ret = bch_btree_insert_at(c, NULL, NULL, NULL,
+ BTREE_INSERT_ATOMIC,
+ BTREE_INSERT_ENTRY(&iter, &inode->k_i),
+ BTREE_TRANS_ENTRY(&trans->t, &new_trans.k_i));
+ } while (ret == -EINTR);
+
+ bch_btree_iter_unlock(&iter);
+
+ mutex_unlock(&c->inode_create_lock);
+ return ret;
+}
+
+int bch_blockdev_inode_create(struct cache_set *c, struct bkey_i *inode,
+ u64 min, u64 max, u64 *hint)
+{
+ struct btree_iter iter;
+ bool searched_from_start = false;
+ int ret;
+
+ *hint = clamp(*hint, min, max);
+
+ if (*hint == min)
+ searched_from_start = true;
+again:
+ bch_btree_iter_init_intent(&iter, c, BTREE_ID_INODES, POS(*hint, 0));
+
+ do {
+ ret = bch_inode_find_slot(c, &iter, max);
+ if (ret)
+ break;
+
+ inode->k.p = iter.pos;
+ *hint = inode->k.p.inode + 1;
+
+ pr_debug("inserting inode %llu (size %u)",
+ inode->k.p.inode, inode->k.u64s);
+
+ ret = bch_btree_insert_at(c, NULL, NULL, NULL,
+ BTREE_INSERT_ATOMIC,
+ BTREE_INSERT_ENTRY(&iter, inode));
+ } while (ret == -EINTR);
- return ret;
- } else {
- /* slot used */
- bch_btree_iter_advance_pos(&iter);
- }
- }
bch_btree_iter_unlock(&iter);
- if (!searched_from_start) {
+ if (ret == -ENOSPC && !searched_from_start) {
/* Retry from start */
*hint = min;
searched_from_start = true;
goto again;
}
- return -ENOSPC;
+ return ret;
}
int bch_inode_truncate(struct cache_set *c, u64 inode_nr, u64 new_size,
diff --git a/drivers/md/bcache/inode.h b/drivers/md/bcache/inode.h
index 49849e31a0fa..921fea0bd18a 100644
--- a/drivers/md/bcache/inode.h
+++ b/drivers/md/bcache/inode.h
@@ -6,7 +6,10 @@ extern const struct bkey_ops bch_bkey_inode_ops;
ssize_t bch_inode_status(char *, size_t, const struct bkey *);
-int bch_inode_create(struct cache_set *, struct bkey_i *, u64, u64, u64 *);
+int bch_inode_create(struct cache_set *, struct bkey_i_inode *);
+int bch_blockdev_inode_create(struct cache_set *, struct bkey_i *,
+ u64, u64, u64 *);
+
int bch_inode_truncate(struct cache_set *, u64, u64,
struct extent_insert_hook *, u64 *);
int bch_inode_rm(struct cache_set *, u64);