2018-09-05 01:46:30 +03:00
// SPDX-License-Identifier: GPL-2.0+
2009-04-07 06:01:25 +04:00
/*
* direct . c - NILFS direct block pointer .
*
* Copyright ( C ) 2006 - 2008 Nippon Telegraph and Telephone Corporation .
*
2016-05-24 02:23:09 +03:00
* Written by Koji Sato .
2009-04-07 06:01:25 +04:00
*/
# 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
2010-07-10 13:07:04 +04:00
static inline __le64 * nilfs_direct_dptrs ( const struct nilfs_bmap * direct )
2009-04-07 06:01:25 +04:00
{
return ( __le64 * )
2010-07-10 13:07:04 +04:00
( ( struct nilfs_direct_node * ) direct - > b_u . u_data + 1 ) ;
2009-04-07 06:01:25 +04:00
}
static inline __u64
2010-07-10 13:07:04 +04:00
nilfs_direct_get_ptr ( const struct nilfs_bmap * direct , __u64 key )
2009-04-07 06:01:25 +04:00
{
2010-07-10 11:50:41 +04:00
return le64_to_cpu ( * ( nilfs_direct_dptrs ( direct ) + key ) ) ;
2009-04-07 06:01:25 +04:00
}
2010-07-10 13:07:04 +04:00
static inline void nilfs_direct_set_ptr ( struct nilfs_bmap * direct ,
2009-04-07 06:01:25 +04:00
__u64 key , __u64 ptr )
{
2010-07-10 11:50:41 +04:00
* ( nilfs_direct_dptrs ( direct ) + key ) = cpu_to_le64 ( ptr ) ;
2009-04-07 06:01:25 +04:00
}
2010-07-10 13:07:04 +04:00
static int nilfs_direct_lookup ( const struct nilfs_bmap * direct ,
2009-04-07 06:01:25 +04:00
__u64 key , int level , __u64 * ptrp )
{
__u64 ptr ;
2009-12-06 09:43:56 +03:00
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 ;
2010-07-13 18:33:51 +04:00
* ptrp = ptr ;
2009-04-07 06:01:25 +04:00
return 0 ;
}
2010-07-10 13:07:04 +04:00
static int nilfs_direct_lookup_contig ( const struct nilfs_bmap * direct ,
2009-05-24 21:47:14 +04:00
__u64 key , __u64 * ptrp ,
2016-05-24 02:23:39 +03:00
unsigned int maxblocks )
2009-05-24 21:47:14 +04:00
{
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 ;
2010-07-10 13:07:04 +04:00
if ( NILFS_BMAP_USE_VBN ( direct ) ) {
dat = nilfs_bmap_get_dat ( direct ) ;
2009-05-24 21:47:14 +04:00
ret = nilfs_dat_translate ( dat , ptr , & blocknr ) ;
if ( ret < 0 )
return ret ;
ptr = blocknr ;
}
2016-05-24 02:23:39 +03:00
maxblocks = min_t ( unsigned int , maxblocks ,
NILFS_DIRECT_KEY_MAX - key + 1 ) ;
2009-05-24 21:47:14 +04:00
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
2010-07-10 13:07:04 +04:00
nilfs_direct_find_target_v ( const struct nilfs_bmap * direct , __u64 key )
2009-04-07 06:01:25 +04:00
{
__u64 ptr ;
2010-07-10 13:07:04 +04:00
ptr = nilfs_bmap_find_target_seq ( direct , key ) ;
2009-04-07 06:01:25 +04:00
if ( ptr ! = NILFS_BMAP_INVALID_PTR )
/* sequential access */
return ptr ;
2016-05-24 02:23:42 +03:00
/* block group */
return nilfs_bmap_find_target_in_group ( direct ) ;
2009-04-07 06:01:25 +04:00
}
static int nilfs_direct_insert ( struct nilfs_bmap * bmap , __u64 key , __u64 ptr )
{
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 ;
2010-07-10 13:07:04 +04:00
if ( nilfs_direct_get_ptr ( bmap , key ) ! = NILFS_BMAP_INVALID_PTR )
2009-04-07 06:01:25 +04:00
return - EEXIST ;
2009-08-15 10:34:33 +04:00
if ( NILFS_BMAP_USE_VBN ( bmap ) ) {
2010-07-10 13:07:04 +04:00
req . bpr_ptr = nilfs_direct_find_target_v ( bmap , key ) ;
2009-08-15 10:34:33 +04:00
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 ) ;
2010-07-10 13:07:04 +04:00
nilfs_direct_set_ptr ( bmap , 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 ) )
2010-07-10 17:21:54 +04:00
nilfs_bmap_set_target_v ( bmap , key , req . bpr_ptr ) ;
2009-04-07 06:01:25 +04:00
2011-03-04 18:19:32 +03:00
nilfs_inode_add_blocks ( bmap - > b_inode , 1 ) ;
2009-08-15 10:34:33 +04:00
}
return ret ;
2009-04-07 06:01:25 +04:00
}
static int nilfs_direct_delete ( struct nilfs_bmap * bmap , __u64 key )
{
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 | |
2010-07-10 13:07:04 +04:00
nilfs_direct_get_ptr ( bmap , key ) = = NILFS_BMAP_INVALID_PTR )
2009-04-07 06:01:25 +04:00
return - ENOENT ;
2009-08-15 10:34:33 +04:00
dat = NILFS_BMAP_USE_VBN ( bmap ) ? nilfs_bmap_get_dat ( bmap ) : NULL ;
2010-07-10 13:07:04 +04:00
req . bpr_ptr = nilfs_direct_get_ptr ( bmap , 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 ) ;
2010-07-10 13:07:04 +04:00
nilfs_direct_set_ptr ( bmap , key , NILFS_BMAP_INVALID_PTR ) ;
2011-03-04 18:19:32 +03:00
nilfs_inode_sub_blocks ( bmap - > b_inode , 1 ) ;
2009-08-15 10:34:33 +04:00
}
return ret ;
2009-04-07 06:01:25 +04:00
}
2015-04-16 22:46:36 +03:00
static int nilfs_direct_seek_key ( const struct nilfs_bmap * direct , __u64 start ,
__u64 * keyp )
{
__u64 key ;
for ( key = start ; key < = NILFS_DIRECT_KEY_MAX ; key + + ) {
if ( nilfs_direct_get_ptr ( direct , key ) ! =
NILFS_BMAP_INVALID_PTR ) {
* keyp = key ;
return 0 ;
}
}
return - ENOENT ;
}
2010-07-10 13:07:04 +04:00
static int nilfs_direct_last_key ( const struct nilfs_bmap * direct , __u64 * keyp )
2009-04-07 06:01:25 +04:00
{
__u64 key , lastkey ;
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 ;
}
2010-07-10 13:07:04 +04:00
static int nilfs_direct_gather_data ( struct nilfs_bmap * direct ,
2009-04-07 06:01:25 +04:00
__u64 * keys , __u64 * ptrs , int nitems )
{
__u64 key ;
__u64 ptr ;
int n ;
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
{
__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 */
2010-07-10 13:07:04 +04:00
dptrs = nilfs_direct_dptrs ( bmap ) ;
2009-04-07 06:01:25 +04:00
for ( i = 0 , j = 0 ; i < NILFS_DIRECT_NBLOCKS ; i + + ) {
if ( ( j < n ) & & ( i = = keys [ j ] ) ) {
dptrs [ i ] = ( i ! = key ) ?
2010-07-10 11:50:41 +04:00
cpu_to_le64 ( ptrs [ j ] ) :
2009-04-07 06:01:25 +04:00
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 ;
}
2010-07-10 16:37:47 +04:00
static int nilfs_direct_propagate ( struct nilfs_bmap * bmap ,
2009-08-15 10:34:33 +04:00
struct buffer_head * bh )
2009-04-07 06:01:25 +04:00
{
2009-08-15 10:34:33 +04:00
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 ) ;
2010-07-10 13:07:04 +04:00
ptr = nilfs_direct_get_ptr ( bmap , key ) ;
2009-04-07 06:01:25 +04:00
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 ) ;
2010-07-10 13:07:04 +04:00
nilfs_direct_set_ptr ( bmap , 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 ;
}
2010-07-10 13:07:04 +04:00
static int nilfs_direct_assign_v ( struct nilfs_bmap * direct ,
2009-04-07 06:01:25 +04:00
__u64 key , __u64 ptr ,
struct buffer_head * * bh ,
sector_t blocknr ,
union nilfs_binfo * binfo )
{
2010-07-10 13:07:04 +04:00
struct inode * dat = nilfs_bmap_get_dat ( direct ) ;
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 ) ;
2010-07-10 11:50:41 +04:00
binfo - > bi_v . bi_vblocknr = cpu_to_le64 ( ptr ) ;
binfo - > bi_v . bi_blkoff = cpu_to_le64 ( key ) ;
2009-08-15 10:34:33 +04:00
}
return ret ;
2009-04-07 06:01:25 +04:00
}
2010-07-10 13:07:04 +04:00
static int nilfs_direct_assign_p ( struct nilfs_bmap * direct ,
2009-04-07 06:01:25 +04:00
__u64 key , __u64 ptr ,
struct buffer_head * * bh ,
sector_t blocknr ,
union nilfs_binfo * binfo )
{
nilfs_direct_set_ptr ( direct , key , blocknr ) ;
2010-07-10 11:50:41 +04:00
binfo - > bi_dat . bi_blkoff = cpu_to_le64 ( key ) ;
2009-04-07 06:01:25 +04:00
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 )
{
__u64 key ;
__u64 ptr ;
key = nilfs_bmap_data_get_key ( bmap , * bh ) ;
2009-04-07 06:01:55 +04:00
if ( unlikely ( key > NILFS_DIRECT_KEY_MAX ) ) {
2016-08-03 00:05:10 +03:00
nilfs_msg ( bmap - > b_inode - > i_sb , KERN_CRIT ,
" %s (ino=%lu): invalid key: %llu " , __func__ ,
bmap - > b_inode - > i_ino , ( unsigned long long ) key ) ;
2009-04-07 06:01:55 +04:00
return - EINVAL ;
}
2010-07-10 13:07:04 +04:00
ptr = nilfs_direct_get_ptr ( bmap , key ) ;
2009-04-07 06:01:55 +04:00
if ( unlikely ( ptr = = NILFS_BMAP_INVALID_PTR ) ) {
2016-08-03 00:05:10 +03:00
nilfs_msg ( bmap - > b_inode - > i_sb , KERN_CRIT ,
" %s (ino=%lu): invalid pointer: %llu " , __func__ ,
bmap - > b_inode - > i_ino , ( unsigned long long ) ptr ) ;
2009-04-07 06:01:55 +04:00
return - EINVAL ;
}
2009-04-07 06:01:25 +04:00
2009-05-24 11:46:37 +04:00
return NILFS_BMAP_USE_VBN ( bmap ) ?
2010-07-10 13:07:04 +04:00
nilfs_direct_assign_v ( bmap , key , ptr , bh , blocknr , binfo ) :
nilfs_direct_assign_p ( bmap , 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 ,
2015-04-16 22:46:36 +03:00
. bop_seek_key = nilfs_direct_seek_key ,
2009-04-07 06:01:25 +04:00
. bop_last_key = nilfs_direct_last_key ,
2015-04-16 22:46:36 +03:00
2009-04-07 06:01:25 +04:00
. 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 ;
}