diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2016-06-08 01:08:05 -0800 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@gmail.com> | 2016-08-28 19:15:13 -0800 |
commit | 24b3bdde02c73e29f1bc609e76f0de90494f9f7b (patch) | |
tree | a29f5839896d5babc8b6f928fcf259d78c052015 | |
parent | 11167650ac5f9368554f5adec9ebf6b02a211414 (diff) |
bcachefs: inode optional fields
-rw-r--r-- | drivers/md/bcache/fs-gc.c | 10 | ||||
-rw-r--r-- | drivers/md/bcache/fs.c | 49 | ||||
-rw-r--r-- | drivers/md/bcache/inode.c | 96 | ||||
-rw-r--r-- | drivers/md/bcache/inode.h | 15 | ||||
-rw-r--r-- | include/uapi/linux/bcache.h | 30 |
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 */ /* |