2009-04-07 06:01:25 +04:00
/*
* direct . c - NILFS direct block pointer .
*
* Copyright ( C ) 2006 - 2008 Nippon Telegraph and Telephone Corporation .
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* 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 . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
*
* Written by Koji Sato < koji @ osrg . net > .
*/
# include <linux/errno.h>
# include "nilfs.h"
# include "page.h"
# include "direct.h"
# include "alloc.h"
2009-05-24 21:47:14 +04:00
# include "dat.h"
2009-04-07 06:01:25 +04:00
static inline __le64 * nilfs_direct_dptrs ( const struct nilfs_direct * direct )
{
return ( __le64 * )
( ( struct nilfs_direct_node * ) direct - > d_bmap . b_u . u_data + 1 ) ;
}
static inline __u64
nilfs_direct_get_ptr ( const struct nilfs_direct * direct , __u64 key )
{
return nilfs_bmap_dptr_to_ptr ( * ( nilfs_direct_dptrs ( direct ) + key ) ) ;
}
static inline void nilfs_direct_set_ptr ( struct nilfs_direct * direct ,
__u64 key , __u64 ptr )
{
* ( nilfs_direct_dptrs ( direct ) + key ) = nilfs_bmap_ptr_to_dptr ( ptr ) ;
}
static int nilfs_direct_lookup ( const struct nilfs_bmap * bmap ,
__u64 key , int level , __u64 * ptrp )
{
struct nilfs_direct * direct ;
__u64 ptr ;
2009-12-06 09:43:56 +03:00
direct = ( struct nilfs_direct * ) bmap ; /* XXX: use macro for level 1 */
if ( key > NILFS_DIRECT_KEY_MAX | | level ! = 1 )
return - ENOENT ;
ptr = nilfs_direct_get_ptr ( direct , key ) ;
if ( ptr = = NILFS_BMAP_INVALID_PTR )
2009-04-07 06:01:25 +04:00
return - ENOENT ;
if ( ptrp ! = NULL )
* ptrp = ptr ;
return 0 ;
}
2009-05-24 21:47:14 +04:00
static int nilfs_direct_lookup_contig ( const struct nilfs_bmap * bmap ,
__u64 key , __u64 * ptrp ,
unsigned maxblocks )
{
struct nilfs_direct * direct = ( struct nilfs_direct * ) bmap ;
struct inode * dat = NULL ;
__u64 ptr , ptr2 ;
sector_t blocknr ;
int ret , cnt ;
2009-12-06 09:43:56 +03:00
if ( key > NILFS_DIRECT_KEY_MAX )
return - ENOENT ;
ptr = nilfs_direct_get_ptr ( direct , key ) ;
if ( ptr = = NILFS_BMAP_INVALID_PTR )
2009-05-24 21:47:14 +04:00
return - ENOENT ;
if ( NILFS_BMAP_USE_VBN ( bmap ) ) {
dat = nilfs_bmap_get_dat ( bmap ) ;
ret = nilfs_dat_translate ( dat , ptr , & blocknr ) ;
if ( ret < 0 )
return ret ;
ptr = blocknr ;
}
maxblocks = min_t ( unsigned , maxblocks , NILFS_DIRECT_KEY_MAX - key + 1 ) ;
for ( cnt = 1 ; cnt < maxblocks & &
( ptr2 = nilfs_direct_get_ptr ( direct , key + cnt ) ) ! =
NILFS_BMAP_INVALID_PTR ;
cnt + + ) {
if ( dat ) {
ret = nilfs_dat_translate ( dat , ptr2 , & blocknr ) ;
if ( ret < 0 )
return ret ;
ptr2 = blocknr ;
}
if ( ptr2 ! = ptr + cnt )
break ;
}
* ptrp = ptr ;
return cnt ;
}
2009-04-07 06:01:25 +04:00
static __u64
nilfs_direct_find_target_v ( const struct nilfs_direct * direct , __u64 key )
{
__u64 ptr ;
ptr = nilfs_bmap_find_target_seq ( & direct - > d_bmap , key ) ;
if ( ptr ! = NILFS_BMAP_INVALID_PTR )
/* sequential access */
return ptr ;
else
/* block group */
return nilfs_bmap_find_target_in_group ( & direct - > d_bmap ) ;
}
static void nilfs_direct_set_target_v ( struct nilfs_direct * direct ,
__u64 key , __u64 ptr )
{
direct - > d_bmap . b_last_allocated_key = key ;
direct - > d_bmap . b_last_allocated_ptr = ptr ;
}
static int nilfs_direct_insert ( struct nilfs_bmap * bmap , __u64 key , __u64 ptr )
{
2009-08-15 10:34:33 +04:00
struct nilfs_direct * direct = ( struct nilfs_direct * ) bmap ;
2009-04-07 06:01:25 +04:00
union nilfs_bmap_ptr_req req ;
2009-08-15 10:34:33 +04:00
struct inode * dat = NULL ;
struct buffer_head * bh ;
2009-04-07 06:01:25 +04:00
int ret ;
if ( key > NILFS_DIRECT_KEY_MAX )
return - ENOENT ;
if ( nilfs_direct_get_ptr ( direct , key ) ! = NILFS_BMAP_INVALID_PTR )
return - EEXIST ;
2009-08-15 10:34:33 +04:00
if ( NILFS_BMAP_USE_VBN ( bmap ) ) {
req . bpr_ptr = nilfs_direct_find_target_v ( direct , key ) ;
dat = nilfs_bmap_get_dat ( bmap ) ;
}
ret = nilfs_bmap_prepare_alloc_ptr ( bmap , & req , dat ) ;
if ( ! ret ) {
/* ptr must be a pointer to a buffer head. */
bh = ( struct buffer_head * ) ( ( unsigned long ) ptr ) ;
set_buffer_nilfs_volatile ( bh ) ;
2009-04-07 06:01:25 +04:00
2009-08-15 10:34:33 +04:00
nilfs_bmap_commit_alloc_ptr ( bmap , & req , dat ) ;
nilfs_direct_set_ptr ( direct , key , req . bpr_ptr ) ;
2009-04-07 06:01:25 +04:00
2009-08-15 10:34:33 +04:00
if ( ! nilfs_bmap_dirty ( bmap ) )
nilfs_bmap_set_dirty ( bmap ) ;
2009-04-07 06:01:25 +04:00
2009-08-15 10:34:33 +04:00
if ( NILFS_BMAP_USE_VBN ( bmap ) )
nilfs_direct_set_target_v ( direct , key , req . bpr_ptr ) ;
2009-04-07 06:01:25 +04:00
2009-08-15 10:34:33 +04:00
nilfs_bmap_add_blocks ( bmap , 1 ) ;
}
return ret ;
2009-04-07 06:01:25 +04:00
}
static int nilfs_direct_delete ( struct nilfs_bmap * bmap , __u64 key )
{
2009-08-15 10:34:33 +04:00
struct nilfs_direct * direct = ( struct nilfs_direct * ) bmap ;
2009-04-07 06:01:25 +04:00
union nilfs_bmap_ptr_req req ;
2009-08-15 10:34:33 +04:00
struct inode * dat ;
2009-04-07 06:01:25 +04:00
int ret ;
2009-08-15 10:34:33 +04:00
if ( key > NILFS_DIRECT_KEY_MAX | |
2009-04-07 06:01:25 +04:00
nilfs_direct_get_ptr ( direct , key ) = = NILFS_BMAP_INVALID_PTR )
return - ENOENT ;
2009-08-15 10:34:33 +04:00
dat = NILFS_BMAP_USE_VBN ( bmap ) ? nilfs_bmap_get_dat ( bmap ) : NULL ;
req . bpr_ptr = nilfs_direct_get_ptr ( direct , key ) ;
2009-04-07 06:01:25 +04:00
2009-08-15 10:34:33 +04:00
ret = nilfs_bmap_prepare_end_ptr ( bmap , & req , dat ) ;
if ( ! ret ) {
nilfs_bmap_commit_end_ptr ( bmap , & req , dat ) ;
nilfs_direct_set_ptr ( direct , key , NILFS_BMAP_INVALID_PTR ) ;
nilfs_bmap_sub_blocks ( bmap , 1 ) ;
}
return ret ;
2009-04-07 06:01:25 +04:00
}
static int nilfs_direct_last_key ( const struct nilfs_bmap * bmap , __u64 * keyp )
{
struct nilfs_direct * direct ;
__u64 key , lastkey ;
direct = ( struct nilfs_direct * ) bmap ;
lastkey = NILFS_DIRECT_KEY_MAX + 1 ;
for ( key = NILFS_DIRECT_KEY_MIN ; key < = NILFS_DIRECT_KEY_MAX ; key + + )
if ( nilfs_direct_get_ptr ( direct , key ) ! =
NILFS_BMAP_INVALID_PTR )
lastkey = key ;
if ( lastkey = = NILFS_DIRECT_KEY_MAX + 1 )
return - ENOENT ;
* keyp = lastkey ;
return 0 ;
}
static int nilfs_direct_check_insert ( const struct nilfs_bmap * bmap , __u64 key )
{
return key > NILFS_DIRECT_KEY_MAX ;
}
static int nilfs_direct_gather_data ( struct nilfs_bmap * bmap ,
__u64 * keys , __u64 * ptrs , int nitems )
{
struct nilfs_direct * direct ;
__u64 key ;
__u64 ptr ;
int n ;
direct = ( struct nilfs_direct * ) bmap ;
if ( nitems > NILFS_DIRECT_NBLOCKS )
nitems = NILFS_DIRECT_NBLOCKS ;
n = 0 ;
for ( key = 0 ; key < nitems ; key + + ) {
ptr = nilfs_direct_get_ptr ( direct , key ) ;
if ( ptr ! = NILFS_BMAP_INVALID_PTR ) {
keys [ n ] = key ;
ptrs [ n ] = ptr ;
n + + ;
}
}
return n ;
}
int nilfs_direct_delete_and_convert ( struct nilfs_bmap * bmap ,
2009-05-23 19:09:44 +04:00
__u64 key , __u64 * keys , __u64 * ptrs , int n )
2009-04-07 06:01:25 +04:00
{
struct nilfs_direct * direct ;
__le64 * dptrs ;
int ret , i , j ;
/* no need to allocate any resource for conversion */
/* delete */
2009-04-07 06:01:49 +04:00
ret = bmap - > b_ops - > bop_delete ( bmap , key ) ;
2009-04-07 06:01:25 +04:00
if ( ret < 0 )
return ret ;
/* free resources */
if ( bmap - > b_ops - > bop_clear ! = NULL )
2009-04-07 06:01:49 +04:00
bmap - > b_ops - > bop_clear ( bmap ) ;
2009-04-07 06:01:25 +04:00
/* convert */
direct = ( struct nilfs_direct * ) bmap ;
dptrs = nilfs_direct_dptrs ( direct ) ;
for ( i = 0 , j = 0 ; i < NILFS_DIRECT_NBLOCKS ; i + + ) {
if ( ( j < n ) & & ( i = = keys [ j ] ) ) {
dptrs [ i ] = ( i ! = key ) ?
nilfs_bmap_ptr_to_dptr ( ptrs [ j ] ) :
NILFS_BMAP_INVALID_PTR ;
j + + ;
} else
dptrs [ i ] = NILFS_BMAP_INVALID_PTR ;
}
2009-05-23 19:09:44 +04:00
nilfs_direct_init ( bmap ) ;
2009-04-07 06:01:25 +04:00
return 0 ;
}
2009-08-15 10:34:33 +04:00
static int nilfs_direct_propagate ( const struct nilfs_bmap * bmap ,
struct buffer_head * bh )
2009-04-07 06:01:25 +04:00
{
2009-08-15 10:34:33 +04:00
struct nilfs_direct * direct = ( struct nilfs_direct * ) bmap ;
struct nilfs_palloc_req oldreq , newreq ;
struct inode * dat ;
2009-04-07 06:01:25 +04:00
__u64 key ;
__u64 ptr ;
int ret ;
2009-08-15 10:34:33 +04:00
if ( ! NILFS_BMAP_USE_VBN ( bmap ) )
return 0 ;
dat = nilfs_bmap_get_dat ( bmap ) ;
key = nilfs_bmap_data_get_key ( bmap , bh ) ;
2009-04-07 06:01:25 +04:00
ptr = nilfs_direct_get_ptr ( direct , key ) ;
if ( ! buffer_nilfs_volatile ( bh ) ) {
2009-08-15 10:34:33 +04:00
oldreq . pr_entry_nr = ptr ;
newreq . pr_entry_nr = ptr ;
ret = nilfs_dat_prepare_update ( dat , & oldreq , & newreq ) ;
2009-04-07 06:01:25 +04:00
if ( ret < 0 )
return ret ;
2009-08-15 10:34:33 +04:00
nilfs_dat_commit_update ( dat , & oldreq , & newreq ,
bmap - > b_ptr_type = = NILFS_BMAP_PTR_VS ) ;
2009-04-07 06:01:25 +04:00
set_buffer_nilfs_volatile ( bh ) ;
2009-08-15 10:34:33 +04:00
nilfs_direct_set_ptr ( direct , key , newreq . pr_entry_nr ) ;
2009-04-07 06:01:25 +04:00
} else
2009-08-15 10:34:33 +04:00
ret = nilfs_dat_mark_dirty ( dat , ptr ) ;
2009-04-07 06:01:25 +04:00
return ret ;
}
static int nilfs_direct_assign_v ( struct nilfs_direct * direct ,
__u64 key , __u64 ptr ,
struct buffer_head * * bh ,
sector_t blocknr ,
union nilfs_binfo * binfo )
{
2009-08-15 10:34:33 +04:00
struct inode * dat = nilfs_bmap_get_dat ( & direct - > d_bmap ) ;
2009-04-07 06:01:25 +04:00
union nilfs_bmap_ptr_req req ;
int ret ;
req . bpr_ptr = ptr ;
2009-08-15 10:34:33 +04:00
ret = nilfs_dat_prepare_start ( dat , & req . bpr_req ) ;
if ( ! ret ) {
nilfs_dat_commit_start ( dat , & req . bpr_req , blocknr ) ;
binfo - > bi_v . bi_vblocknr = nilfs_bmap_ptr_to_dptr ( ptr ) ;
binfo - > bi_v . bi_blkoff = nilfs_bmap_key_to_dkey ( key ) ;
}
return ret ;
2009-04-07 06:01:25 +04:00
}
static int nilfs_direct_assign_p ( struct nilfs_direct * direct ,
__u64 key , __u64 ptr ,
struct buffer_head * * bh ,
sector_t blocknr ,
union nilfs_binfo * binfo )
{
nilfs_direct_set_ptr ( direct , key , blocknr ) ;
binfo - > bi_dat . bi_blkoff = nilfs_bmap_key_to_dkey ( key ) ;
binfo - > bi_dat . bi_level = 0 ;
return 0 ;
}
static int nilfs_direct_assign ( struct nilfs_bmap * bmap ,
struct buffer_head * * bh ,
sector_t blocknr ,
union nilfs_binfo * binfo )
{
struct nilfs_direct * direct ;
__u64 key ;
__u64 ptr ;
direct = ( struct nilfs_direct * ) bmap ;
key = nilfs_bmap_data_get_key ( bmap , * bh ) ;
2009-04-07 06:01:55 +04:00
if ( unlikely ( key > NILFS_DIRECT_KEY_MAX ) ) {
printk ( KERN_CRIT " %s: invalid key: %llu \n " , __func__ ,
( unsigned long long ) key ) ;
return - EINVAL ;
}
2009-04-07 06:01:25 +04:00
ptr = nilfs_direct_get_ptr ( direct , key ) ;
2009-04-07 06:01:55 +04:00
if ( unlikely ( ptr = = NILFS_BMAP_INVALID_PTR ) ) {
printk ( KERN_CRIT " %s: invalid pointer: %llu \n " , __func__ ,
( unsigned long long ) ptr ) ;
return - EINVAL ;
}
2009-04-07 06:01:25 +04:00
2009-05-24 11:46:37 +04:00
return NILFS_BMAP_USE_VBN ( bmap ) ?
nilfs_direct_assign_v ( direct , key , ptr , bh , blocknr , binfo ) :
nilfs_direct_assign_p ( direct , key , ptr , bh , blocknr , binfo ) ;
2009-04-07 06:01:25 +04:00
}
static const struct nilfs_bmap_operations nilfs_direct_ops = {
. bop_lookup = nilfs_direct_lookup ,
2009-05-24 21:47:14 +04:00
. bop_lookup_contig = nilfs_direct_lookup_contig ,
2009-04-07 06:01:25 +04:00
. bop_insert = nilfs_direct_insert ,
. bop_delete = nilfs_direct_delete ,
. bop_clear = NULL ,
. bop_propagate = nilfs_direct_propagate ,
. bop_lookup_dirty_buffers = NULL ,
. bop_assign = nilfs_direct_assign ,
. bop_mark = NULL ,
. bop_last_key = nilfs_direct_last_key ,
. bop_check_insert = nilfs_direct_check_insert ,
. bop_check_delete = NULL ,
. bop_gather_data = nilfs_direct_gather_data ,
} ;
2009-05-23 19:09:44 +04:00
int nilfs_direct_init ( struct nilfs_bmap * bmap )
2009-04-07 06:01:25 +04:00
{
bmap - > b_ops = & nilfs_direct_ops ;
return 0 ;
}