2018-04-03 20:23:33 +03:00
// SPDX-License-Identifier: GPL-2.0
2007-10-16 00:18:56 +04:00
/*
* Copyright ( C ) 2007 Oracle . All rights reserved .
*/
2012-07-10 06:22:35 +04:00
# include <asm/unaligned.h>
2008-09-29 23:18:18 +04:00
2012-07-10 06:22:35 +04:00
# include "ctree.h"
2020-05-01 00:38:11 +03:00
static bool check_setget_bounds ( const struct extent_buffer * eb ,
const void * ptr , unsigned off , int size )
{
const unsigned long member_offset = ( unsigned long ) ptr + off ;
if ( member_offset > eb - > len ) {
btrfs_warn ( eb - > fs_info ,
" bad eb member start: ptr 0x%lx start %llu member offset %lu size %d " ,
( unsigned long ) ptr , eb - > start , member_offset , size ) ;
return false ;
}
if ( member_offset + size > eb - > len ) {
btrfs_warn ( eb - > fs_info ,
" bad eb member end: ptr 0x%lx start %llu member offset %lu size %d " ,
( unsigned long ) ptr , eb - > start , member_offset , size ) ;
return false ;
}
return true ;
}
2012-07-10 06:22:35 +04:00
/*
2020-05-06 21:54:13 +03:00
* Macro templates that define helpers to read / write extent buffer data of a
* given size , that are also used via ctree . h for access to item members by
* specialized helpers .
2008-09-29 23:18:18 +04:00
*
2020-05-06 21:54:13 +03:00
* Generic helpers :
* - btrfs_set_8 ( for 8 / 16 / 32 / 64 )
* - btrfs_get_8 ( for 8 / 16 / 32 / 64 )
2008-09-29 23:18:18 +04:00
*
2020-05-06 21:54:13 +03:00
* Generic helpers with a token ( cached address of the most recently accessed
* page ) :
* - btrfs_set_token_8 ( for 8 / 16 / 32 / 64 )
* - btrfs_get_token_8 ( for 8 / 16 / 32 / 64 )
2008-09-29 23:18:18 +04:00
*
2020-05-06 21:54:13 +03:00
* The set / get functions handle data spanning two pages transparently , in case
* metadata block size is larger than page . Every pointer to metadata items is
* an offset into the extent buffer page array , cast to a specific type . This
* gives us all the type checking .
2019-08-09 18:12:38 +03:00
*
2020-05-06 21:54:13 +03:00
* The extent buffer pages stored in the array pages do not form a contiguous
* phyusical range , but the API functions assume the linear offset to the range
* from 0 to metadata node size .
2008-09-29 23:18:18 +04:00
*/
2012-07-10 06:22:35 +04:00
# define DEFINE_BTRFS_SETGET_BITS(bits) \
2020-04-29 03:15:56 +03:00
u # # bits btrfs_get_token_ # # bits ( struct btrfs_map_token * token , \
const void * ptr , unsigned long off ) \
2007-10-16 00:18:56 +04:00
{ \
2020-04-29 18:45:33 +03:00
const unsigned long member_offset = ( unsigned long ) ptr + off ; \
2020-12-02 09:48:04 +03:00
const unsigned long idx = get_eb_page_index ( member_offset ) ; \
const unsigned long oip = get_eb_offset_in_page ( token - > eb , \
member_offset ) ; \
2020-04-29 18:45:33 +03:00
const int size = sizeof ( u # # bits ) ; \
2020-04-30 18:57:55 +03:00
u8 lebytes [ sizeof ( u # # bits ) ] ; \
const int part = PAGE_SIZE - oip ; \
2012-07-10 06:22:35 +04:00
\
2019-08-09 18:30:23 +03:00
ASSERT ( token ) ; \
2020-04-29 20:29:04 +03:00
ASSERT ( token - > kaddr ) ; \
2020-05-01 00:38:11 +03:00
ASSERT ( check_setget_bounds ( token - > eb , ptr , off , size ) ) ; \
2020-04-29 18:45:33 +03:00
if ( token - > offset < = member_offset & & \
member_offset + size < = token - > offset + PAGE_SIZE ) { \
return get_unaligned_le # # bits ( token - > kaddr + oip ) ; \
2012-07-10 06:22:35 +04:00
} \
2020-04-30 18:57:55 +03:00
token - > kaddr = page_address ( token - > eb - > pages [ idx ] ) ; \
token - > offset = idx < < PAGE_SHIFT ; \
2021-06-23 16:48:53 +03:00
if ( INLINE_EXTENT_BUFFER_PAGES = = 1 | | oip + size < = PAGE_SIZE ) \
2020-04-29 18:45:33 +03:00
return get_unaligned_le # # bits ( token - > kaddr + oip ) ; \
2020-04-30 18:57:55 +03:00
\
memcpy ( lebytes , token - > kaddr + oip , part ) ; \
2020-04-29 18:45:33 +03:00
token - > kaddr = page_address ( token - > eb - > pages [ idx + 1 ] ) ; \
token - > offset = ( idx + 1 ) < < PAGE_SHIFT ; \
2020-04-30 18:57:55 +03:00
memcpy ( lebytes + part , token - > kaddr , size - part ) ; \
return get_unaligned_le # # bits ( lebytes ) ; \
2007-10-16 00:18:56 +04:00
} \
2019-08-09 18:12:38 +03:00
u # # bits btrfs_get_ # # bits ( const struct extent_buffer * eb , \
const void * ptr , unsigned long off ) \
{ \
2020-04-29 17:04:44 +03:00
const unsigned long member_offset = ( unsigned long ) ptr + off ; \
2020-12-02 09:48:04 +03:00
const unsigned long oip = get_eb_offset_in_page ( eb , member_offset ) ; \
const unsigned long idx = get_eb_page_index ( member_offset ) ; \
2020-04-30 18:57:55 +03:00
char * kaddr = page_address ( eb - > pages [ idx ] ) ; \
2020-04-29 17:04:44 +03:00
const int size = sizeof ( u # # bits ) ; \
2020-04-30 18:57:55 +03:00
const int part = PAGE_SIZE - oip ; \
u8 lebytes [ sizeof ( u # # bits ) ] ; \
2019-08-09 18:12:38 +03:00
\
2020-05-01 00:38:11 +03:00
ASSERT ( check_setget_bounds ( eb , ptr , off , size ) ) ; \
2021-06-23 16:48:53 +03:00
if ( INLINE_EXTENT_BUFFER_PAGES = = 1 | | oip + size < = PAGE_SIZE ) \
2020-04-29 17:04:44 +03:00
return get_unaligned_le # # bits ( kaddr + oip ) ; \
2020-04-30 18:57:55 +03:00
\
memcpy ( lebytes , kaddr + oip , part ) ; \
kaddr = page_address ( eb - > pages [ idx + 1 ] ) ; \
memcpy ( lebytes + part , kaddr , size - part ) ; \
return get_unaligned_le # # bits ( lebytes ) ; \
2019-08-09 18:12:38 +03:00
} \
2020-04-29 03:15:56 +03:00
void btrfs_set_token_ # # bits ( struct btrfs_map_token * token , \
2017-06-29 06:56:53 +03:00
const void * ptr , unsigned long off , \
2020-04-29 03:15:56 +03:00
u # # bits val ) \
2007-10-16 00:18:56 +04:00
{ \
2020-04-29 19:23:37 +03:00
const unsigned long member_offset = ( unsigned long ) ptr + off ; \
2020-12-02 09:48:04 +03:00
const unsigned long idx = get_eb_page_index ( member_offset ) ; \
const unsigned long oip = get_eb_offset_in_page ( token - > eb , \
member_offset ) ; \
2020-04-29 19:23:37 +03:00
const int size = sizeof ( u # # bits ) ; \
2020-04-30 18:57:55 +03:00
u8 lebytes [ sizeof ( u # # bits ) ] ; \
const int part = PAGE_SIZE - oip ; \
2012-07-10 06:22:35 +04:00
\
2019-08-09 18:30:23 +03:00
ASSERT ( token ) ; \
2020-04-29 20:29:04 +03:00
ASSERT ( token - > kaddr ) ; \
2020-05-01 00:38:11 +03:00
ASSERT ( check_setget_bounds ( token - > eb , ptr , off , size ) ) ; \
2020-04-29 19:23:37 +03:00
if ( token - > offset < = member_offset & & \
member_offset + size < = token - > offset + PAGE_SIZE ) { \
put_unaligned_le # # bits ( val , token - > kaddr + oip ) ; \
2012-07-10 06:22:35 +04:00
return ; \
} \
2020-04-30 18:57:55 +03:00
token - > kaddr = page_address ( token - > eb - > pages [ idx ] ) ; \
token - > offset = idx < < PAGE_SHIFT ; \
2021-06-23 16:48:53 +03:00
if ( INLINE_EXTENT_BUFFER_PAGES = = 1 | | oip + size < = PAGE_SIZE ) { \
2020-04-29 19:23:37 +03:00
put_unaligned_le # # bits ( val , token - > kaddr + oip ) ; \
2012-07-10 06:22:35 +04:00
return ; \
} \
2020-04-30 18:57:55 +03:00
put_unaligned_le # # bits ( val , lebytes ) ; \
memcpy ( token - > kaddr + oip , lebytes , part ) ; \
2020-04-29 19:23:37 +03:00
token - > kaddr = page_address ( token - > eb - > pages [ idx + 1 ] ) ; \
token - > offset = ( idx + 1 ) < < PAGE_SHIFT ; \
2020-04-30 18:57:55 +03:00
memcpy ( token - > kaddr , lebytes + part , size - part ) ; \
2019-08-09 18:12:38 +03:00
} \
2020-04-29 04:04:10 +03:00
void btrfs_set_ # # bits ( const struct extent_buffer * eb , void * ptr , \
2019-08-09 18:12:38 +03:00
unsigned long off , u # # bits val ) \
{ \
2020-04-29 19:07:04 +03:00
const unsigned long member_offset = ( unsigned long ) ptr + off ; \
2020-12-02 09:48:04 +03:00
const unsigned long oip = get_eb_offset_in_page ( eb , member_offset ) ; \
const unsigned long idx = get_eb_page_index ( member_offset ) ; \
2020-04-30 18:57:55 +03:00
char * kaddr = page_address ( eb - > pages [ idx ] ) ; \
2020-04-29 19:07:04 +03:00
const int size = sizeof ( u # # bits ) ; \
2020-04-30 18:57:55 +03:00
const int part = PAGE_SIZE - oip ; \
u8 lebytes [ sizeof ( u # # bits ) ] ; \
2019-08-09 18:12:38 +03:00
\
2020-05-01 00:38:11 +03:00
ASSERT ( check_setget_bounds ( eb , ptr , off , size ) ) ; \
2021-06-23 16:48:53 +03:00
if ( INLINE_EXTENT_BUFFER_PAGES = = 1 | | oip + size < = PAGE_SIZE ) { \
2020-04-29 19:07:04 +03:00
put_unaligned_le # # bits ( val , kaddr + oip ) ; \
2019-08-09 18:12:38 +03:00
return ; \
} \
2020-04-30 18:57:55 +03:00
\
put_unaligned_le # # bits ( val , lebytes ) ; \
memcpy ( kaddr + oip , lebytes , part ) ; \
kaddr = page_address ( eb - > pages [ idx + 1 ] ) ; \
memcpy ( kaddr , lebytes + part , size - part ) ; \
2012-07-10 06:22:35 +04:00
}
2007-10-16 00:18:56 +04:00
2012-07-10 06:22:35 +04:00
DEFINE_BTRFS_SETGET_BITS ( 8 )
DEFINE_BTRFS_SETGET_BITS ( 16 )
DEFINE_BTRFS_SETGET_BITS ( 32 )
DEFINE_BTRFS_SETGET_BITS ( 64 )
2007-10-16 00:18:56 +04:00
2017-06-29 06:56:53 +03:00
void btrfs_node_key ( const struct extent_buffer * eb ,
2007-11-06 23:09:29 +03:00
struct btrfs_disk_key * disk_key , int nr )
{
unsigned long ptr = btrfs_node_key_ptr_offset ( nr ) ;
read_eb_member ( eb , ( struct btrfs_key_ptr * ) ptr ,
struct btrfs_key_ptr , key , disk_key ) ;
}