diff options
Diffstat (limited to 'libbcachefs/inode.c')
-rw-r--r-- | libbcachefs/inode.c | 91 |
1 files changed, 48 insertions, 43 deletions
diff --git a/libbcachefs/inode.c b/libbcachefs/inode.c index 7a8467c4..5b56a628 100644 --- a/libbcachefs/inode.c +++ b/libbcachefs/inode.c @@ -25,14 +25,12 @@ static const u8 bits_table[8] = { 13 * 8 - 8, }; -static int inode_encode_field(u8 *out, u8 *end, const u64 in[2]) +static int inode_encode_field(u8 *out, u8 *end, u64 hi, u64 lo) { - unsigned bytes, bits, shift; - - if (likely(!in[1])) - bits = fls64(in[0]); - else - bits = fls64(in[1]) + 64; + __be64 in[2] = { cpu_to_be64(hi), cpu_to_be64(lo), }; + unsigned shift, bytes, bits = likely(!hi) + ? fls64(lo) + : fls64(hi) + 64; for (shift = 1; shift <= 8; shift++) if (bits < bits_table[shift - 1]) @@ -44,17 +42,7 @@ got_shift: BUG_ON(out + bytes > end); - if (likely(bytes <= 8)) { - u64 b = cpu_to_be64(in[0]); - - memcpy(out, (void *) &b + 8 - bytes, bytes); - } else { - u64 b = cpu_to_be64(in[1]); - - memcpy(out, (void *) &b + 16 - bytes, bytes); - put_unaligned_be64(in[0], out + bytes - 8); - } - + memcpy(out, (u8 *) in + 16 - bytes, bytes); *out |= (1 << 8) >> shift; return bytes; @@ -63,7 +51,9 @@ got_shift: static int inode_decode_field(const u8 *in, const u8 *end, u64 out[2], unsigned *out_bits) { - unsigned bytes, bits, shift; + __be64 be[2] = { 0, 0 }; + unsigned bytes, shift; + u8 *p; if (in >= end) return -1; @@ -77,29 +67,18 @@ static int inode_decode_field(const u8 *in, const u8 *end, */ shift = 8 - __fls(*in); /* 1 <= shift <= 8 */ bytes = byte_table[shift - 1]; - bits = bytes * 8 - shift; if (in + bytes > end) return -1; - /* - * we're assuming it's safe to deref up to 7 bytes < in; this will work - * because keys always start quite a bit more than 7 bytes after the - * start of the btree node header: - */ - if (likely(bytes <= 8)) { - out[0] = get_unaligned_be64(in + bytes - 8); - out[0] <<= 64 - bits; - out[0] >>= 64 - bits; - out[1] = 0; - } else { - out[0] = get_unaligned_be64(in + bytes - 8); - out[1] = get_unaligned_be64(in + bytes - 16); - out[1] <<= 128 - bits; - out[1] >>= 128 - bits; - } + p = (u8 *) be + 16 - bytes; + memcpy(p, in, bytes); + *p ^= (1 << 8) >> shift; + + out[0] = be64_to_cpu(be[0]); + out[1] = be64_to_cpu(be[1]); + *out_bits = out[0] ? 64 + fls64(out[0]) : fls64(out[1]); - *out_bits = out[1] ? 64 + fls64(out[1]) : fls64(out[0]); return bytes; } @@ -109,7 +88,6 @@ void bch2_inode_pack(struct bkey_inode_buf *packed, u8 *out = packed->inode.v.fields; u8 *end = (void *) &packed[1]; u8 *last_nonzero_field = out; - u64 field[2]; unsigned nr_fields = 0, last_nonzero_fieldnr = 0; bkey_inode_init(&packed->inode.k_i); @@ -119,12 +97,10 @@ void bch2_inode_pack(struct bkey_inode_buf *packed, packed->inode.v.i_mode = cpu_to_le16(inode->i_mode); #define BCH_INODE_FIELD(_name, _bits) \ - field[0] = inode->_name; \ - field[1] = 0; \ - out += inode_encode_field(out, end, field); \ + out += inode_encode_field(out, end, 0, inode->_name); \ nr_fields++; \ \ - if (field[0] | field[1]) { \ + if (inode->_name) { \ last_nonzero_field = out; \ last_nonzero_fieldnr = nr_fields; \ } @@ -187,7 +163,7 @@ int bch2_inode_unpack(struct bkey_s_c_inode inode, if (field_bits > sizeof(unpacked->_name) * 8) \ return -1; \ \ - unpacked->_name = field[0]; \ + unpacked->_name = field[1]; \ in += ret; BCH_INODE_FIELDS() @@ -449,3 +425,32 @@ int bch2_cached_dev_inode_find_by_uuid(struct bch_fs *c, uuid_le *uuid, bch2_btree_iter_unlock(&iter); return -ENOENT; } + +#ifdef CONFIG_BCACHEFS_DEBUG +void bch2_inode_pack_test(void) +{ + struct bch_inode_unpacked *u, test_inodes[] = { + { + .i_atime = U64_MAX, + .i_ctime = U64_MAX, + .i_mtime = U64_MAX, + .i_otime = U64_MAX, + .i_size = U64_MAX, + .i_sectors = U64_MAX, + .i_uid = U32_MAX, + .i_gid = U32_MAX, + .i_nlink = U32_MAX, + .i_generation = U32_MAX, + .i_dev = U32_MAX, + }, + }; + + for (u = test_inodes; + u < test_inodes + ARRAY_SIZE(test_inodes); + u++) { + struct bkey_inode_buf p; + + bch2_inode_pack(&p, u); + } +} +#endif |