2007-10-15 16:18:56 -04:00
/*
* Copyright ( C ) 2007 Oracle . All rights reserved .
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public
* License v2 as published by the Free Software Foundation .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* General Public License for more details .
*
* You should have received a copy of the GNU General Public
* License along with this program ; if not , write to the
* Free Software Foundation , Inc . , 59 Temple Place - Suite 330 ,
* Boston , MA 021110 - 1307 , USA .
*/
# include <linux/highmem.h>
2008-09-29 15:18:18 -04:00
/* this is some deeply nasty code. ctree.h has a different
* definition for this BTRFS_SETGET_FUNCS macro , behind a # ifndef
*
* The end result is that anyone who # includes ctree . h gets a
* declaration for the btrfs_set_foo functions and btrfs_foo functions
*
* This file declares the macros and then # includes ctree . h , which results
* in cpp creating the function here based on the template below .
*
* These setget functions do all the extent_buffer related mapping
* required to efficiently read and write specific fields in the extent
* buffers . Every pointer to metadata items in btrfs is really just
* an unsigned long offset into the extent buffer which has been
* cast to a specific type . This gives us all the gcc type checking .
*
* The extent buffer api is used to do all the kmapping and page
* spanning work required to get extent buffers in highmem and have
* a metadata blocksize different from the page size .
2008-12-02 11:18:37 -05:00
*
* The macro starts with a simple function prototype declaration so that
* sparse won ' t complain about it being static .
2008-09-29 15:18:18 -04:00
*/
2007-10-15 16:18:56 -04:00
# define BTRFS_SETGET_FUNCS(name, type, member, bits) \
2008-12-02 11:18:37 -05:00
u # # bits btrfs_ # # name ( struct extent_buffer * eb , type * s ) ; \
void btrfs_set_ # # name ( struct extent_buffer * eb , type * s , u # # bits val ) ; \
2007-10-15 16:18:56 -04:00
u # # bits btrfs_ # # name ( struct extent_buffer * eb , \
type * s ) \
{ \
2008-02-15 10:40:52 -05:00
unsigned long part_offset = ( unsigned long ) s ; \
unsigned long offset = part_offset + offsetof ( type , member ) ; \
type * p ; \
2007-10-15 16:18:56 -04:00
/* ugly, but we want the fast path here */ \
if ( eb - > map_token & & offset > = eb - > map_start & & \
offset + sizeof ( ( ( type * ) 0 ) - > member ) < = eb - > map_start + \
eb - > map_len ) { \
2008-02-15 10:40:52 -05:00
p = ( type * ) ( eb - > kaddr + part_offset - eb - > map_start ) ; \
return le # # bits # # _to_cpu ( p - > member ) ; \
2007-10-15 16:18:56 -04:00
} \
{ \
int err ; \
char * map_token ; \
char * kaddr ; \
int unmap_on_exit = ( eb - > map_token = = NULL ) ; \
unsigned long map_start ; \
unsigned long map_len ; \
2008-12-02 11:18:37 -05:00
u # # bits res ; \
2007-10-15 16:18:56 -04:00
err = map_extent_buffer ( eb , offset , \
2009-01-05 21:25:51 -05:00
sizeof ( ( ( type * ) 0 ) - > member ) , \
2007-10-15 16:18:56 -04:00
& map_token , & kaddr , \
& map_start , & map_len , KM_USER1 ) ; \
if ( err ) { \
2008-12-02 11:18:37 -05:00
__le # # bits leres ; \
read_eb_member ( eb , s , type , member , & leres ) ; \
return le # # bits # # _to_cpu ( leres ) ; \
2007-10-15 16:18:56 -04:00
} \
2008-02-15 10:40:52 -05:00
p = ( type * ) ( kaddr + part_offset - map_start ) ; \
res = le # # bits # # _to_cpu ( p - > member ) ; \
2007-10-15 16:18:56 -04:00
if ( unmap_on_exit ) \
unmap_extent_buffer ( eb , map_token , KM_USER1 ) ; \
return res ; \
} \
} \
void btrfs_set_ # # name ( struct extent_buffer * eb , \
type * s , u # # bits val ) \
{ \
2008-02-15 10:40:52 -05:00
unsigned long part_offset = ( unsigned long ) s ; \
unsigned long offset = part_offset + offsetof ( type , member ) ; \
type * p ; \
2007-10-15 16:18:56 -04:00
/* ugly, but we want the fast path here */ \
if ( eb - > map_token & & offset > = eb - > map_start & & \
offset + sizeof ( ( ( type * ) 0 ) - > member ) < = eb - > map_start + \
eb - > map_len ) { \
2008-02-15 10:40:52 -05:00
p = ( type * ) ( eb - > kaddr + part_offset - eb - > map_start ) ; \
p - > member = cpu_to_le # # bits ( val ) ; \
2007-10-15 16:18:56 -04:00
return ; \
} \
{ \
int err ; \
char * map_token ; \
char * kaddr ; \
int unmap_on_exit = ( eb - > map_token = = NULL ) ; \
unsigned long map_start ; \
unsigned long map_len ; \
err = map_extent_buffer ( eb , offset , \
2009-01-05 21:25:51 -05:00
sizeof ( ( ( type * ) 0 ) - > member ) , \
2007-10-15 16:18:56 -04:00
& map_token , & kaddr , \
& map_start , & map_len , KM_USER1 ) ; \
if ( err ) { \
2008-12-02 11:18:37 -05:00
__le # # bits val2 ; \
val2 = cpu_to_le # # bits ( val ) ; \
write_eb_member ( eb , s , type , member , & val2 ) ; \
2007-10-15 16:18:56 -04:00
return ; \
} \
2008-02-15 10:40:52 -05:00
p = ( type * ) ( kaddr + part_offset - map_start ) ; \
p - > member = cpu_to_le # # bits ( val ) ; \
2007-10-15 16:18:56 -04:00
if ( unmap_on_exit ) \
unmap_extent_buffer ( eb , map_token , KM_USER1 ) ; \
} \
}
# include "ctree.h"
2007-11-06 15:09:29 -05:00
void btrfs_node_key ( struct extent_buffer * eb ,
struct btrfs_disk_key * disk_key , int nr )
{
unsigned long ptr = btrfs_node_key_ptr_offset ( nr ) ;
if ( eb - > map_token & & ptr > = eb - > map_start & &
ptr + sizeof ( * disk_key ) < = eb - > map_start + eb - > map_len ) {
memcpy ( disk_key , eb - > kaddr + ptr - eb - > map_start ,
sizeof ( * disk_key ) ) ;
return ;
} else if ( eb - > map_token ) {
unmap_extent_buffer ( eb , eb - > map_token , KM_USER1 ) ;
eb - > map_token = NULL ;
}
read_eb_member ( eb , ( struct btrfs_key_ptr * ) ptr ,
struct btrfs_key_ptr , key , disk_key ) ;
}