/* * Author: Kent Overstreet * * GPLv2 */ #ifndef _BCACHE_H #define _BCACHE_H #include #define BITMASK(name, type, field, offset, size) \ static inline uint64_t name(const type *k) \ { return (k->field >> offset) & ~(((uint64_t) ~0) << size); } \ \ static inline void SET_##name(type *k, uint64_t v) \ { \ k->field &= ~(~((uint64_t) ~0 << size) << offset); \ k->field |= v << offset; \ } static const char bcache_magic[] = { 0xc6, 0x85, 0x73, 0xf6, 0x4e, 0x1a, 0x45, 0xca, 0x82, 0x65, 0xf5, 0x7f, 0x48, 0xba, 0x6d, 0x81 }; /* * Version 0: Cache device * Version 1: Backing device * Version 2: Seed pointer into btree node checksum * Version 3: Cache device with new UUID format * Version 4: Backing device with data offset * Version 5: Cache adn backing devices with compat/incompat/ro_compat * feature sets */ #define BCACHE_SB_VERSION_CDEV 0 #define BCACHE_SB_VERSION_BDEV 1 #define BCACHE_SB_VERSION_CDEV_WITH_UUID 3 #define BCACHE_SB_VERSION_BDEV_WITH_OFFSET 4 #define BCACHE_SB_VERSION_CDEV_WITH_FEATURES 5 #define BCACHE_SB_VERSION_BDEV_WITH_FEATURES 6 #define BCACHE_SB_MAX_VERSION 6 #define SB_SECTOR 8 #define SB_LABEL_SIZE 32 #define SB_JOURNAL_BUCKETS 256U #define BDEV_DATA_START_DEFAULT 16 /* sectors */ #define SB_START (SB_SECTOR * 512) struct cache_sb_disk { __le64 csum; __le64 offset; /* sector where this sb was written */ __le64 version; __u8 magic[16]; __u8 uuid[16]; union { __u8 set_uuid[16]; __le64 set_magic; }; __u8 label[SB_LABEL_SIZE]; __le64 flags; __le64 seq; __le64 feature_compat; __le64 feature_incompat; __le64 feature_ro_compat; __le64 pad[5]; union { struct { /* Cache devices */ __le64 nbuckets; /* device size */ __le16 block_size; /* sectors */ __le16 bucket_size; /* sectors */ __le16 nr_in_set; __le16 nr_this_dev; }; struct { /* Backing devices */ __le64 data_offset; /* * block_size from the cache device section is still used by * backing devices, so don't add anything here until we fix * things to not need it for backing devices anymore */ }; }; __le32 last_mount; /* time overflow in y2106 */ __le16 first_bucket; union { __le16 njournal_buckets; __le16 keys; }; __le64 d[SB_JOURNAL_BUCKETS]; /* journal buckets */ __le16 obso_bucket_size_hi; /* obsoleted */ }; /* * This is for in-memory bcache super block. * NOTE: cache_sb is NOT exactly mapping to cache_sb_disk, the member * size, ordering and even whole struct size may be different * from cache_sb_disk. */ struct cache_sb { __u64 offset; /* sector where this sb was written */ __u64 version; __u8 magic[16]; __u8 uuid[16]; union { __u8 set_uuid[16]; __u64 set_magic; }; __u8 label[SB_LABEL_SIZE]; __u64 flags; __u64 seq; __u64 feature_compat; __u64 feature_incompat; __u64 feature_ro_compat; union { struct { /* Cache devices */ __u64 nbuckets; /* device size */ __u16 block_size; /* sectors */ __u16 nr_in_set; __u16 nr_this_dev; __u32 bucket_size; /* sectors */ }; struct { /* Backing devices */ __u64 data_offset; /* * block_size from the cache device section is still used by * backing devices, so don't add anything here until we fix * things to not need it for backing devices anymore */ }; }; __u32 last_mount; /* time overflow in y2106 */ __u16 first_bucket; union { __u16 njournal_buckets; __u16 keys; }; __u64 d[SB_JOURNAL_BUCKETS]; /* journal buckets */ }; static inline bool SB_IS_BDEV(const struct cache_sb *sb) { return sb->version == BCACHE_SB_VERSION_BDEV || sb->version == BCACHE_SB_VERSION_BDEV_WITH_OFFSET || sb->version == BCACHE_SB_VERSION_BDEV_WITH_FEATURES; } BITMASK(CACHE_SYNC, struct cache_sb, flags, 0, 1); BITMASK(CACHE_DISCARD, struct cache_sb, flags, 1, 1); BITMASK(CACHE_REPLACEMENT, struct cache_sb, flags, 2, 3); #define CACHE_REPLACEMENT_LRU 0U #define CACHE_REPLACEMENT_FIFO 1U #define CACHE_REPLACEMENT_RANDOM 2U BITMASK(BDEV_CACHE_MODE, struct cache_sb, flags, 0, 4); #define CACHE_MODE_WRITETHROUGH 0U #define CACHE_MODE_WRITEBACK 1U #define CACHE_MODE_WRITEAROUND 2U #define CACHE_MODE_NONE 3U BITMASK(BDEV_STATE, struct cache_sb, flags, 61, 2); #define BDEV_STATE_NONE 0U #define BDEV_STATE_CLEAN 1U #define BDEV_STATE_DIRTY 2U #define BDEV_STATE_STALE 3U uint64_t crc64(const void *data, size_t len); #define node(i, j) ((void *) ((i)->d + (j))) #define end(i) node(i, (i)->keys) #define csum_set(i) \ crc64(((void *) (i)) + 8, ((void *) end(i)) - (((void *) (i)) + 8)) /* Feature set definition */ #define BCH_FEATURE_COMPAT 0 #define BCH_FEATURE_RO_COMPAT 1 #define BCH_FEATURE_INCOMPAT 2 #define BCH_FEATURE_TYPE_MASK 0x03 #define BCH_FEATURE_COMPAT_SUPP 0 #define BCH_FEATURE_RO_COMPAT_SUPP 0 #define BCH_FEATURE_INCOMPAT_SUPP (BCH_FEATURE_INCOMPAT_OBSO_LARGE_BUCKET| \ BCH_FEATURE_INCOMPAT_LOG_LARGE_BUCKET_SIZE) #define BCH_HAS_COMPAT_FEATURE(sb, mask) \ ((sb)->feature_compat & (mask)) #define BCH_HAS_RO_COMPAT_FEATURE(sb, mask) \ ((sb)->feature_ro_compat & (mask)) #define BCH_HAS_INCOMPAT_FEATURE(sb, mask) \ ((sb)->feature_incompat & (mask)) /* Feature set definition */ /* Incompat feature set */ /* 32bit bucket size, obsoleted */ #define BCH_FEATURE_INCOMPAT_OBSO_LARGE_BUCKET 0x0001 /* real bucket size is (1 << bucket_size) */ #define BCH_FEATURE_INCOMPAT_LOG_LARGE_BUCKET_SIZE 0x0002 #define BCH_FEATURE_COMPAT_FUNCS(name, flagname) \ static inline int bch_has_feature_##name(struct cache_sb *sb) \ { \ return (((sb)->feature_compat & \ BCH##_FEATURE_COMPAT_##flagname) != 0); \ } \ static inline void bch_set_feature_##name(struct cache_sb *sb) \ { \ if ((sb)->version < BCACHE_SB_VERSION_CDEV_WITH_FEATURES) \ (sb)->version = BCACHE_SB_VERSION_CDEV_WITH_FEATURES; \ (sb)->feature_compat |= \ BCH##_FEATURE_COMPAT_##flagname; \ } \ static inline void bch_clear_feature_##name(struct cache_sb *sb) \ { \ (sb)->feature_compat &= \ ~BCH##_FEATURE_COMPAT_##flagname; \ } #define BCH_FEATURE_RO_COMPAT_FUNCS(name, flagname) \ static inline int bch_has_feature_##name(struct cache_sb *sb) \ { \ return (((sb)->feature_ro_compat & \ BCH##_FEATURE_RO_COMPAT_##flagname) != 0); \ } \ static inline void bch_set_feature_##name(struct cache_sb *sb) \ { \ if ((sb)->version < BCACHE_SB_VERSION_CDEV_WITH_FEATURES) \ (sb)->version = BCACHE_SB_VERSION_CDEV_WITH_FEATURES; \ (sb)->feature_ro_compat |= \ BCH##_FEATURE_RO_COMPAT_##flagname; \ } \ static inline void bch_clear_feature_##name(struct cache_sb *sb) \ { \ (sb)->feature_ro_compat &= \ ~BCH##_FEATURE_RO_COMPAT_##flagname; \ } #define BCH_FEATURE_INCOMPAT_FUNCS(name, flagname) \ static inline int bch_has_feature_##name(struct cache_sb *sb) \ { \ return (((sb)->feature_incompat & \ BCH##_FEATURE_INCOMPAT_##flagname) != 0); \ } \ static inline void bch_set_feature_##name(struct cache_sb *sb) \ { \ if ((sb)->version < BCACHE_SB_VERSION_CDEV_WITH_FEATURES) \ (sb)->version = BCACHE_SB_VERSION_CDEV_WITH_FEATURES; \ (sb)->feature_incompat |= \ BCH##_FEATURE_INCOMPAT_##flagname; \ } \ static inline void bch_clear_feature_##name(struct cache_sb *sb) \ { \ (sb)->feature_incompat &= \ ~BCH##_FEATURE_INCOMPAT_##flagname; \ } BCH_FEATURE_INCOMPAT_FUNCS(obso_large_bucket, OBSO_LARGE_BUCKET); BCH_FEATURE_INCOMPAT_FUNCS(large_bucket, LOG_LARGE_BUCKET_SIZE); #endif