summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/md/bcache/fs-gc.c10
-rw-r--r--drivers/md/bcache/fs.c49
-rw-r--r--drivers/md/bcache/inode.c96
-rw-r--r--drivers/md/bcache/inode.h15
-rw-r--r--include/uapi/linux/bcache.h30
5 files changed, 171 insertions, 29 deletions
diff --git a/drivers/md/bcache/fs-gc.c b/drivers/md/bcache/fs-gc.c
index 99a9a7ac5679..6ec3e1c37a5b 100644
--- a/drivers/md/bcache/fs-gc.c
+++ b/drivers/md/bcache/fs-gc.c
@@ -275,7 +275,7 @@ int bch_gc_inode_nlinks(struct cache_set *c)
static inline bool next_inode(struct cache_set *c, struct bkey_s_c k,
u64 *cur_inum,
- struct bkey_i_inode *inode,
+ struct bch_inode *inode,
struct bch_inode **bi,
u64 *i_size, u16 *i_mode)
{
@@ -283,9 +283,9 @@ static inline bool next_inode(struct cache_set *c, struct bkey_s_c k,
return false;
if (!bch_inode_find_by_inum(c, k.k->p.inode, inode)) {
- *i_mode = le16_to_cpu(inode->v.i_mode);
- *i_size = le64_to_cpu(inode->v.i_size);
- *bi = &inode->v;
+ *i_mode = le16_to_cpu(inode->i_mode);
+ *i_size = le64_to_cpu(inode->i_size);
+ *bi = inode;
} else {
*bi = NULL;
}
@@ -307,7 +307,7 @@ void bch_fsck(struct cache_set *c)
{
struct btree_iter iter;
struct bkey_s_c k;
- struct bkey_i_inode inode;
+ struct bch_inode inode;
struct bch_inode *bi = NULL;
u64 i_size = 0;
u16 i_mode = 0;
diff --git a/drivers/md/bcache/fs.c b/drivers/md/bcache/fs.c
index 1253c1543d90..8bd6697d164a 100644
--- a/drivers/md/bcache/fs.c
+++ b/drivers/md/bcache/fs.c
@@ -62,8 +62,7 @@ int __must_check __bch_write_inode(struct cache_set *c,
{
struct btree_iter iter;
struct inode *inode = &ei->vfs_inode;
- struct bkey_i_inode new_inode;
- struct bch_inode *bi;
+ struct bch_inode bi;
u64 inum = inode->i_ino;
int ret;
@@ -73,6 +72,8 @@ int __must_check __bch_write_inode(struct cache_set *c,
do {
struct bkey_s_c k = bch_btree_iter_peek_with_holes(&iter);
+ struct bkey_s_c_inode old_inode;
+ struct bch_inode_i_generation i_generation;
if (WARN_ONCE(!k.k || k.k->type != BCH_INODE_FS,
"inode %llu not found when updating", inum)) {
@@ -80,33 +81,36 @@ int __must_check __bch_write_inode(struct cache_set *c,
return -ENOENT;
}
- bkey_reassemble(&new_inode.k_i, k);
- bi = &new_inode.v;
+ old_inode = bkey_s_c_to_inode(k);
+ bi = *old_inode.v;
if (set) {
- ret = set(ei, bi, p);
+ ret = set(ei, &bi, p);
if (ret)
goto out;
}
- bi->i_mode = cpu_to_le16(inode->i_mode);
- bi->i_uid = cpu_to_le32(i_uid_read(inode));
- bi->i_gid = cpu_to_le32(i_gid_read(inode));
- bi->i_nlink = cpu_to_le32(inode->i_nlink);
- bi->i_dev = cpu_to_le32(inode->i_rdev);
- bi->i_atime = cpu_to_le64(timespec_to_ns(&inode->i_atime));
- bi->i_mtime = cpu_to_le64(timespec_to_ns(&inode->i_mtime));
- bi->i_ctime = cpu_to_le64(timespec_to_ns(&inode->i_ctime));
-
- ret = bch_btree_insert_at(c, NULL, NULL, &ei->journal_seq,
- BTREE_INSERT_ATOMIC|
- BTREE_INSERT_NOFAIL,
- BTREE_INSERT_ENTRY(&iter, &new_inode.k_i));
+ bi.i_mode = cpu_to_le16(inode->i_mode);
+ bi.i_uid = cpu_to_le32(i_uid_read(inode));
+ bi.i_gid = cpu_to_le32(i_gid_read(inode));
+ bi.i_nlink = cpu_to_le32(inode->i_nlink);
+ bi.i_dev = cpu_to_le32(inode->i_rdev);
+ bi.i_atime = cpu_to_le64(timespec_to_ns(&inode->i_atime));
+ bi.i_mtime = cpu_to_le64(timespec_to_ns(&inode->i_mtime));
+ bi.i_ctime = cpu_to_le64(timespec_to_ns(&inode->i_ctime));
+
+ i_generation.v = cpu_to_le64(inode->i_generation);
+
+ ret = bch_inode_insert_at(&iter,
+ &bi,
+ &i_generation,
+ NULL,
+ &ei->journal_seq, GFP_NOFS);
} while (ret == -EINTR);
if (!ret) {
- ei->i_size = le64_to_cpu(bi->i_size);
- ei->i_flags = le32_to_cpu(bi->i_flags);
+ ei->i_size = le64_to_cpu(bi.i_size);
+ ei->i_flags = le32_to_cpu(bi.i_flags);
}
out:
bch_btree_iter_unlock(&iter);
@@ -1000,6 +1004,7 @@ static void bch_inode_init(struct bch_inode_info *ei,
{
struct inode *inode = &ei->vfs_inode;
const struct bch_inode *bi = bkey_inode.v;
+ struct inode_opt_fields f = bch_inode_opt_fields_get(bi);
pr_debug("init inode %llu with mode %o",
bkey_inode.k->p.inode, bi->i_mode);
@@ -1026,6 +1031,10 @@ static void bch_inode_init(struct bch_inode_info *ei,
ei->str_hash.seed = le64_to_cpu(bi->i_hash_seed);
ei->str_hash.type = INODE_STR_HASH_TYPE(bi);
+ inode->i_generation = f.i_generation
+ ? le64_to_cpu(f.i_generation->v)
+ : 0;
+
inode->i_mapping->a_ops = &bch_address_space_operations;
switch (inode->i_mode & S_IFMT) {
diff --git a/drivers/md/bcache/inode.c b/drivers/md/bcache/inode.c
index 7cbe9b5dc757..dff8c0923590 100644
--- a/drivers/md/bcache/inode.c
+++ b/drivers/md/bcache/inode.c
@@ -214,6 +214,65 @@ int bch_inode_rm(struct cache_set *c, u64 inode_nr)
NULL, NULL, BTREE_INSERT_NOFAIL);
}
+int bch_inode_insert_at(struct btree_iter *iter,
+ const struct bch_inode *inode,
+ const struct bch_inode_i_generation *i_generation,
+ const struct bch_inode_long_times *long_times,
+ u64 *journal_seq, gfp_t gfp)
+{
+ size_t bytes = sizeof(struct bkey_i_inode);
+ struct bkey_i_inode *new_inode;
+ void *p;
+ unsigned i_flags;
+ int ret;
+
+#define count_field(_field) \
+ if (_field && !bch_is_zero((void *) _field, sizeof(*_field))) \
+ bytes += sizeof(*_field); \
+ else \
+ _field = NULL;
+
+ count_field(i_generation);
+ count_field(long_times);
+
+ BUG_ON(bytes & 7);
+
+ new_inode = kmalloc(bytes, gfp);
+ if (!new_inode)
+ return -ENOMEM;
+
+ bkey_init(&new_inode->k);
+ new_inode->k.u64s = bytes / 8;
+ new_inode->k.type = BCH_INODE_FS;
+ new_inode->k.p = iter->pos;
+ new_inode->v = *inode;
+ i_flags = le32_to_cpu(new_inode->v.i_flags);
+
+ p = &(&new_inode->v)[1];
+
+#define encode_field(_field) \
+ if (_field) { \
+ memcpy(p, _field, sizeof(*_field)); \
+ p += sizeof(*_field); \
+ i_flags |= (1 << __BCH_INODE_##_field); \
+ } else { \
+ i_flags &= ~(1 << __BCH_INODE_##_field); \
+ }
+
+ encode_field(i_generation);
+ encode_field(long_times);
+
+ new_inode->v.i_flags = cpu_to_le32(i_flags);
+
+ ret = bch_btree_insert_at(iter->c, NULL, NULL, journal_seq,
+ BTREE_INSERT_ATOMIC|BTREE_INSERT_NOFAIL,
+ BTREE_INSERT_ENTRY(iter, &new_inode->k_i));
+
+ kfree(new_inode);
+
+ return ret;
+}
+
int bch_inode_update(struct cache_set *c, struct bkey_i *inode,
u64 *journal_seq)
{
@@ -221,7 +280,7 @@ int bch_inode_update(struct cache_set *c, struct bkey_i *inode,
}
int bch_inode_find_by_inum(struct cache_set *c, u64 inode_nr,
- struct bkey_i_inode *inode)
+ struct bch_inode *inode)
{
struct btree_iter iter;
struct bkey_s_c k;
@@ -232,7 +291,7 @@ int bch_inode_find_by_inum(struct cache_set *c, u64 inode_nr,
switch (k.k->type) {
case BCH_INODE_FS:
ret = 0;
- bkey_reassemble(&inode->k_i, k);
+ *inode = *bkey_s_c_to_inode(k).v;
break;
default:
/* hole, not found */
@@ -247,6 +306,39 @@ int bch_inode_find_by_inum(struct cache_set *c, u64 inode_nr,
return ret;
}
+struct inode_opt_fields bch_inode_opt_fields_get(const struct bch_inode *inode)
+{
+ size_t offset = sizeof(struct bch_inode);
+ struct inode_opt_fields ret;
+
+#define walk_field(_field, _field_size) \
+ do { \
+ if (le32_to_cpu(inode->i_flags) & \
+ (1 << __BCH_INODE_##_field)) { \
+ struct bch_inode_##_field *field = \
+ (void *) inode + offset; \
+ size_t size = _field_size; \
+ \
+ ret._field = field; \
+ \
+ EBUG_ON(size & 7); \
+ offset += size; \
+ } else { \
+ ret._field = NULL; \
+ } \
+ } while (0)
+
+#define walk_constant_size_field(_field) \
+ walk_field(_field, sizeof(*field))
+
+ walk_constant_size_field(i_generation);
+ walk_constant_size_field(long_times);
+#undef walk_field
+#undef walk_constant_size_field
+
+ return ret;
+}
+
int bch_cached_dev_inode_find_by_uuid(struct cache_set *c, uuid_le *uuid,
struct bkey_i_inode_blockdev *ret)
{
diff --git a/drivers/md/bcache/inode.h b/drivers/md/bcache/inode.h
index a89064a37861..e5a36ca24bb0 100644
--- a/drivers/md/bcache/inode.h
+++ b/drivers/md/bcache/inode.h
@@ -10,10 +10,23 @@ int bch_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);
+
+int bch_inode_insert_at(struct btree_iter *, const struct bch_inode *,
+ const struct bch_inode_i_generation *,
+ const struct bch_inode_long_times *,
+ u64 *, gfp_t);
+
int bch_inode_update(struct cache_set *, struct bkey_i *, u64 *);
-int bch_inode_find_by_inum(struct cache_set *, u64, struct bkey_i_inode *);
+int bch_inode_find_by_inum(struct cache_set *, u64, struct bch_inode *);
int bch_cached_dev_inode_find_by_uuid(struct cache_set *, uuid_le *,
struct bkey_i_inode_blockdev *);
+struct inode_opt_fields {
+ const struct bch_inode_i_generation *i_generation;
+ const struct bch_inode_long_times *long_times;
+};
+
+struct inode_opt_fields bch_inode_opt_fields_get(const struct bch_inode *);
+
#endif
diff --git a/include/uapi/linux/bcache.h b/include/uapi/linux/bcache.h
index 6006d50418cf..5689512c2470 100644
--- a/include/uapi/linux/bcache.h
+++ b/include/uapi/linux/bcache.h
@@ -508,7 +508,7 @@ struct bch_inode {
__le32 i_dev;
__le64 i_hash_seed;
-} __attribute__((packed));
+} __attribute__((packed, aligned(8)));
BKEY_VAL_TYPE(inode, BCH_INODE_FS);
enum {
@@ -527,6 +527,10 @@ enum {
/* not implemented yet: */
__BCH_INODE_HAS_XATTRS = 7, /* has xattrs in xattr btree */
+
+ /* These flags indicate whether optional fields are present: */
+ __BCH_INODE_i_generation= 8,
+ __BCH_INODE_long_times = 9,
};
LE32_BITMASK(INODE_STR_HASH_TYPE, struct bch_inode, i_flags, 28, 32);
@@ -540,6 +544,29 @@ LE32_BITMASK(INODE_STR_HASH_TYPE, struct bch_inode, i_flags, 28, 32);
#define BCH_INODE_I_SECTORS_DIRTY (1 << __BCH_INODE_I_SECTORS_DIRTY)
#define BCH_INODE_HAS_XATTRS (1 << __BCH_INODE_HAS_XATTRS)
+/*
+ * Inode optional fields:
+ *
+ * This is the order that fields are present in:
+ * New fields must be added at the end so that old kernels can read newer
+ * inodes:
+ */
+enum bch_inode_opt_fieldnrs {
+ BCH_INODE_FIELDNR_i_generation,
+ BCH_INODE_FIELDNR_long_times,
+};
+
+struct bch_inode_i_generation {
+ __le64 v;
+} __attribute__((packed, aligned(8)));
+
+struct bch_inode_long_times {
+ __le32 i_atime_high;
+ __le32 i_ctime_high;
+ __le32 i_mtime_high;
+ __le32 pad;
+} __attribute__((packed, aligned(8)));
+
struct bch_inode_blockdev {
struct bch_val v;
@@ -557,6 +584,7 @@ BKEY_VAL_TYPE(inode_blockdev, BCH_INODE_BLOCKDEV);
/* Thin provisioned volume, or cache for another block device? */
LE64_BITMASK(CACHED_DEV, struct bch_inode_blockdev, i_flags, 0, 1)
+
/* Dirents */
/*