2017-03-17 09:18:50 +03:00
/* SPDX-License-Identifier: GPL-2.0 */
# ifndef _BCACHEFS_CHECKSUM_H
# define _BCACHEFS_CHECKSUM_H
# include "bcachefs.h"
# include "extents_types.h"
# include "super-io.h"
2019-01-11 13:11:07 +03:00
# include <linux/crc64.h>
2017-03-17 09:18:50 +03:00
# include <crypto/chacha.h>
2019-05-13 05:23:30 +03:00
static inline bool bch2_checksum_mergeable ( unsigned type )
{
switch ( type ) {
2021-11-11 20:11:33 +03:00
case BCH_CSUM_none :
case BCH_CSUM_crc32c :
case BCH_CSUM_crc64 :
2019-05-13 05:23:30 +03:00
return true ;
default :
return false ;
}
}
struct bch_csum bch2_checksum_merge ( unsigned , struct bch_csum ,
struct bch_csum , size_t ) ;
2017-03-17 09:18:50 +03:00
# define BCH_NONCE_EXTENT cpu_to_le32(1 << 28)
# define BCH_NONCE_BTREE cpu_to_le32(2 << 28)
# define BCH_NONCE_JOURNAL cpu_to_le32(3 << 28)
# define BCH_NONCE_PRIO cpu_to_le32(4 << 28)
# define BCH_NONCE_POLY cpu_to_le32(1 << 31)
struct bch_csum bch2_checksum ( struct bch_fs * , unsigned , struct nonce ,
const void * , size_t ) ;
/*
* This is used for various on disk data structures - bch_sb , prio_set , bset ,
* jset : The checksum is _always_ the first field of these structs
*/
# define csum_vstruct(_c, _type, _nonce, _i) \
( { \
2023-09-13 01:41:22 +03:00
const void * _start = ( ( const void * ) ( _i ) ) + sizeof ( ( _i ) - > csum ) ; \
2017-03-17 09:18:50 +03:00
\
2023-09-13 01:41:22 +03:00
bch2_checksum ( _c , _type , _nonce , _start , vstruct_end ( _i ) - _start ) ; \
2017-03-17 09:18:50 +03:00
} )
2024-01-05 19:59:03 +03:00
static inline void bch2_csum_to_text ( struct printbuf * out ,
enum bch_csum_type type ,
struct bch_csum csum )
{
const u8 * p = ( u8 * ) & csum ;
unsigned bytes = type < BCH_CSUM_NR ? bch_crc_bytes [ type ] : 16 ;
for ( unsigned i = 0 ; i < bytes ; i + + )
prt_hex_byte ( out , p [ i ] ) ;
}
static inline void bch2_csum_err_msg ( struct printbuf * out ,
enum bch_csum_type type ,
struct bch_csum expected ,
struct bch_csum got )
{
2024-04-12 22:17:00 +03:00
prt_str ( out , " checksum error, type " ) ;
bch2_prt_csum_type ( out , type ) ;
prt_str ( out , " : got " ) ;
2024-01-05 19:59:03 +03:00
bch2_csum_to_text ( out , type , got ) ;
prt_str ( out , " should be " ) ;
bch2_csum_to_text ( out , type , expected ) ;
}
2017-03-17 09:18:50 +03:00
int bch2_chacha_encrypt_key ( struct bch_key * , struct nonce , void * , size_t ) ;
int bch2_request_key ( struct bch_sb * , struct bch_key * ) ;
2023-09-24 02:07:16 +03:00
# ifndef __KERNEL__
int bch2_revoke_key ( struct bch_sb * ) ;
# endif
2017-03-17 09:18:50 +03:00
2022-02-19 08:42:12 +03:00
int bch2_encrypt ( struct bch_fs * , unsigned , struct nonce ,
2017-03-17 09:18:50 +03:00
void * data , size_t ) ;
struct bch_csum bch2_checksum_bio ( struct bch_fs * , unsigned ,
struct nonce , struct bio * ) ;
int bch2_rechecksum_bio ( struct bch_fs * , struct bio * , struct bversion ,
struct bch_extent_crc_unpacked ,
struct bch_extent_crc_unpacked * ,
struct bch_extent_crc_unpacked * ,
unsigned , unsigned , unsigned ) ;
2022-11-01 10:37:53 +03:00
int __bch2_encrypt_bio ( struct bch_fs * , unsigned ,
struct nonce , struct bio * ) ;
static inline int bch2_encrypt_bio ( struct bch_fs * c , unsigned type ,
struct nonce nonce , struct bio * bio )
{
return bch2_csum_type_is_encryption ( type )
? __bch2_encrypt_bio ( c , type , nonce , bio )
: 0 ;
}
2017-03-17 09:18:50 +03:00
2023-08-05 22:43:00 +03:00
extern const struct bch_sb_field_ops bch_sb_field_ops_crypt ;
2017-03-17 09:18:50 +03:00
int bch2_decrypt_sb_key ( struct bch_fs * , struct bch_sb_field_crypt * ,
struct bch_key * ) ;
int bch2_disable_encryption ( struct bch_fs * ) ;
int bch2_enable_encryption ( struct bch_fs * , bool ) ;
void bch2_fs_encryption_exit ( struct bch_fs * ) ;
int bch2_fs_encryption_init ( struct bch_fs * ) ;
static inline enum bch_csum_type bch2_csum_opt_to_type ( enum bch_csum_opts type ,
bool data )
{
switch ( type ) {
2021-02-21 03:47:58 +03:00
case BCH_CSUM_OPT_none :
2022-10-22 22:59:53 +03:00
return BCH_CSUM_none ;
2021-02-21 03:47:58 +03:00
case BCH_CSUM_OPT_crc32c :
2022-10-22 22:59:53 +03:00
return data ? BCH_CSUM_crc32c : BCH_CSUM_crc32c_nonzero ;
2021-02-21 03:47:58 +03:00
case BCH_CSUM_OPT_crc64 :
2022-10-22 22:59:53 +03:00
return data ? BCH_CSUM_crc64 : BCH_CSUM_crc64_nonzero ;
2021-06-17 14:42:09 +03:00
case BCH_CSUM_OPT_xxhash :
2022-10-22 22:59:53 +03:00
return BCH_CSUM_xxhash ;
2017-03-17 09:18:50 +03:00
default :
2022-10-22 22:59:53 +03:00
BUG ( ) ;
2017-03-17 09:18:50 +03:00
}
}
static inline enum bch_csum_type bch2_data_checksum_type ( struct bch_fs * c ,
bcachefs: Nocow support
This adds support for nocow mode, where we do writes in-place when
possible. Patch components:
- New boolean filesystem and inode option, nocow: note that when nocow
is enabled, data checksumming and compression are implicitly disabled
- To prevent in-place writes from racing with data moves
(data_update.c) or bucket reuse (i.e. a bucket being reused and
re-allocated while a nocow write is in flight, we have a new locking
mechanism.
Buckets can be locked for either data update or data move, using a
fixed size hash table of two_state_shared locks. We don't have any
chaining, meaning updates and moves to different buckets that hash to
the same lock will wait unnecessarily - we'll want to watch for this
becoming an issue.
- The allocator path also needs to check for in-place writes in flight
to a given bucket before giving it out: thus we add another counter
to bucket_alloc_state so we can track this.
- Fsync now may need to issue cache flushes to block devices instead of
flushing the journal. We add a device bitmask to bch_inode_info,
ei_devs_need_flush, which tracks devices that need to have flushes
issued - note that this will lead to unnecessary flushes when other
codepaths have already issued flushes, we may want to replace this with
a sequence number.
- New nocow write path: look up extents, and if they're writable write
to them - otherwise fall back to the normal COW write path.
XXX: switch to sequence numbers instead of bitmask for devs needing
journal flush
XXX: ei_quota_lock being a mutex means bch2_nocow_write_done() needs to
run in process context - see if we can improve this
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
2022-11-03 00:12:00 +03:00
struct bch_io_opts opts )
2017-03-17 09:18:50 +03:00
{
bcachefs: Nocow support
This adds support for nocow mode, where we do writes in-place when
possible. Patch components:
- New boolean filesystem and inode option, nocow: note that when nocow
is enabled, data checksumming and compression are implicitly disabled
- To prevent in-place writes from racing with data moves
(data_update.c) or bucket reuse (i.e. a bucket being reused and
re-allocated while a nocow write is in flight, we have a new locking
mechanism.
Buckets can be locked for either data update or data move, using a
fixed size hash table of two_state_shared locks. We don't have any
chaining, meaning updates and moves to different buckets that hash to
the same lock will wait unnecessarily - we'll want to watch for this
becoming an issue.
- The allocator path also needs to check for in-place writes in flight
to a given bucket before giving it out: thus we add another counter
to bucket_alloc_state so we can track this.
- Fsync now may need to issue cache flushes to block devices instead of
flushing the journal. We add a device bitmask to bch_inode_info,
ei_devs_need_flush, which tracks devices that need to have flushes
issued - note that this will lead to unnecessary flushes when other
codepaths have already issued flushes, we may want to replace this with
a sequence number.
- New nocow write path: look up extents, and if they're writable write
to them - otherwise fall back to the normal COW write path.
XXX: switch to sequence numbers instead of bitmask for devs needing
journal flush
XXX: ei_quota_lock being a mutex means bch2_nocow_write_done() needs to
run in process context - see if we can improve this
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
2022-11-03 00:12:00 +03:00
if ( opts . nocow )
return 0 ;
2017-03-17 09:18:50 +03:00
if ( c - > sb . encryption_type )
return c - > opts . wide_macs
2021-11-11 20:11:33 +03:00
? BCH_CSUM_chacha20_poly1305_128
: BCH_CSUM_chacha20_poly1305_80 ;
2017-03-17 09:18:50 +03:00
bcachefs: Nocow support
This adds support for nocow mode, where we do writes in-place when
possible. Patch components:
- New boolean filesystem and inode option, nocow: note that when nocow
is enabled, data checksumming and compression are implicitly disabled
- To prevent in-place writes from racing with data moves
(data_update.c) or bucket reuse (i.e. a bucket being reused and
re-allocated while a nocow write is in flight, we have a new locking
mechanism.
Buckets can be locked for either data update or data move, using a
fixed size hash table of two_state_shared locks. We don't have any
chaining, meaning updates and moves to different buckets that hash to
the same lock will wait unnecessarily - we'll want to watch for this
becoming an issue.
- The allocator path also needs to check for in-place writes in flight
to a given bucket before giving it out: thus we add another counter
to bucket_alloc_state so we can track this.
- Fsync now may need to issue cache flushes to block devices instead of
flushing the journal. We add a device bitmask to bch_inode_info,
ei_devs_need_flush, which tracks devices that need to have flushes
issued - note that this will lead to unnecessary flushes when other
codepaths have already issued flushes, we may want to replace this with
a sequence number.
- New nocow write path: look up extents, and if they're writable write
to them - otherwise fall back to the normal COW write path.
XXX: switch to sequence numbers instead of bitmask for devs needing
journal flush
XXX: ei_quota_lock being a mutex means bch2_nocow_write_done() needs to
run in process context - see if we can improve this
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
2022-11-03 00:12:00 +03:00
return bch2_csum_opt_to_type ( opts . data_checksum , true ) ;
2017-03-17 09:18:50 +03:00
}
static inline enum bch_csum_type bch2_meta_checksum_type ( struct bch_fs * c )
{
if ( c - > sb . encryption_type )
2021-11-11 20:11:33 +03:00
return BCH_CSUM_chacha20_poly1305_128 ;
2017-03-17 09:18:50 +03:00
return bch2_csum_opt_to_type ( c - > opts . metadata_checksum , false ) ;
}
static inline bool bch2_checksum_type_valid ( const struct bch_fs * c ,
unsigned type )
{
if ( type > = BCH_CSUM_NR )
return false ;
if ( bch2_csum_type_is_encryption ( type ) & & ! c - > chacha20 )
return false ;
return true ;
}
/* returns true if not equal */
static inline bool bch2_crc_cmp ( struct bch_csum l , struct bch_csum r )
{
/*
* XXX : need some way of preventing the compiler from optimizing this
* into a form that isn ' t constant time . .
*/
return ( ( l . lo ^ r . lo ) | ( l . hi ^ r . hi ) ) ! = 0 ;
}
/* for skipping ahead and encrypting/decrypting at an offset: */
static inline struct nonce nonce_add ( struct nonce nonce , unsigned offset )
{
EBUG_ON ( offset & ( CHACHA_BLOCK_SIZE - 1 ) ) ;
le32_add_cpu ( & nonce . d [ 0 ] , offset / CHACHA_BLOCK_SIZE ) ;
return nonce ;
}
static inline struct nonce null_nonce ( void )
{
struct nonce ret ;
memset ( & ret , 0 , sizeof ( ret ) ) ;
return ret ;
}
static inline struct nonce extent_nonce ( struct bversion version ,
struct bch_extent_crc_unpacked crc )
{
2018-02-24 00:26:10 +03:00
unsigned compression_type = crc_is_compressed ( crc )
? crc . compression_type
: 0 ;
unsigned size = compression_type ? crc . uncompressed_size : 0 ;
2017-03-17 09:18:50 +03:00
struct nonce nonce = ( struct nonce ) { {
[ 0 ] = cpu_to_le32 ( size < < 22 ) ,
[ 1 ] = cpu_to_le32 ( version . lo ) ,
[ 2 ] = cpu_to_le32 ( version . lo > > 32 ) ,
[ 3 ] = cpu_to_le32 ( version . hi |
2018-02-24 00:26:10 +03:00
( compression_type < < 24 ) ) ^ BCH_NONCE_EXTENT ,
2017-03-17 09:18:50 +03:00
} } ;
return nonce_add ( nonce , crc . nonce < < 9 ) ;
}
static inline bool bch2_key_is_encrypted ( struct bch_encrypted_key * key )
{
return le64_to_cpu ( key - > magic ) ! = BCH_KEY_MAGIC ;
}
static inline struct nonce __bch2_sb_key_nonce ( struct bch_sb * sb )
{
__le64 magic = __bch2_sb_magic ( sb ) ;
return ( struct nonce ) { {
[ 0 ] = 0 ,
[ 1 ] = 0 ,
[ 2 ] = ( ( __le32 * ) & magic ) [ 0 ] ,
[ 3 ] = ( ( __le32 * ) & magic ) [ 1 ] ,
} } ;
}
static inline struct nonce bch2_sb_key_nonce ( struct bch_fs * c )
{
__le64 magic = bch2_sb_magic ( c ) ;
return ( struct nonce ) { {
[ 0 ] = 0 ,
[ 1 ] = 0 ,
[ 2 ] = ( ( __le32 * ) & magic ) [ 0 ] ,
[ 3 ] = ( ( __le32 * ) & magic ) [ 1 ] ,
} } ;
}
# endif /* _BCACHEFS_CHECKSUM_H */