2005-04-17 02:20:36 +04:00
/*
2005-11-02 06:58:39 +03:00
* Copyright ( c ) 2000 - 2001 , 2005 Silicon Graphics , Inc .
* All Rights Reserved .
2005-04-17 02:20:36 +04:00
*
2005-11-02 06:58:39 +03:00
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License as
2005-04-17 02:20:36 +04:00
* published by the Free Software Foundation .
*
2005-11-02 06:58:39 +03:00
* This program is distributed in the hope that it would 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 .
2005-04-17 02:20:36 +04:00
*
2005-11-02 06:58:39 +03:00
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write the Free Software Foundation ,
* Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
2005-04-17 02:20:36 +04:00
*/
# include "xfs.h"
2005-11-02 06:38:42 +03:00
# include "xfs_fs.h"
2005-04-17 02:20:36 +04:00
# include "xfs_types.h"
2005-11-02 06:38:42 +03:00
# include "xfs_bit.h"
2005-04-17 02:20:36 +04:00
# include "xfs_log.h"
# include "xfs_trans.h"
# include "xfs_sb.h"
# include "xfs_ag.h"
# include "xfs_mount.h"
# include "xfs_bmap_btree.h"
2005-11-02 06:38:42 +03:00
# include "xfs_alloc_btree.h"
2005-04-17 02:20:36 +04:00
# include "xfs_ialloc_btree.h"
2005-11-02 06:38:42 +03:00
# include "xfs_dinode.h"
# include "xfs_inode.h"
2005-04-17 02:20:36 +04:00
# include "xfs_btree.h"
# include "xfs_ialloc.h"
# include "xfs_alloc.h"
# include "xfs_error.h"
2012-11-12 15:54:08 +04:00
# include "xfs_trace.h"
2013-04-21 23:53:46 +04:00
# include "xfs_cksum.h"
2005-04-17 02:20:36 +04:00
2008-10-30 08:58:01 +03:00
STATIC int
xfs_inobt_get_minrecs (
struct xfs_btree_cur * cur ,
int level )
{
return cur - > bc_mp - > m_inobt_mnr [ level ! = 0 ] ;
}
2005-04-17 02:20:36 +04:00
2008-10-30 08:53:59 +03:00
STATIC struct xfs_btree_cur *
xfs_inobt_dup_cursor (
struct xfs_btree_cur * cur )
{
return xfs_inobt_init_cursor ( cur - > bc_mp , cur - > bc_tp ,
cur - > bc_private . a . agbp , cur - > bc_private . a . agno ) ;
}
2008-10-30 08:57:16 +03:00
STATIC void
xfs_inobt_set_root (
struct xfs_btree_cur * cur ,
union xfs_btree_ptr * nptr ,
int inc ) /* level change */
{
struct xfs_buf * agbp = cur - > bc_private . a . agbp ;
struct xfs_agi * agi = XFS_BUF_TO_AGI ( agbp ) ;
agi - > agi_root = nptr - > s ;
be32_add_cpu ( & agi - > agi_level , inc ) ;
xfs_ialloc_log_agi ( cur - > bc_tp , agbp , XFS_AGI_ROOT | XFS_AGI_LEVEL ) ;
}
2008-10-30 08:57:03 +03:00
STATIC int
xfs_inobt_alloc_block (
struct xfs_btree_cur * cur ,
union xfs_btree_ptr * start ,
union xfs_btree_ptr * new ,
int length ,
int * stat )
{
xfs_alloc_arg_t args ; /* block allocation args */
int error ; /* error return value */
xfs_agblock_t sbno = be32_to_cpu ( start - > s ) ;
XFS_BTREE_TRACE_CURSOR ( cur , XBT_ENTRY ) ;
memset ( & args , 0 , sizeof ( args ) ) ;
args . tp = cur - > bc_tp ;
args . mp = cur - > bc_mp ;
args . fsbno = XFS_AGB_TO_FSB ( args . mp , cur - > bc_private . a . agno , sbno ) ;
args . minlen = 1 ;
args . maxlen = 1 ;
args . prod = 1 ;
args . type = XFS_ALLOCTYPE_NEAR_BNO ;
error = xfs_alloc_vextent ( & args ) ;
if ( error ) {
XFS_BTREE_TRACE_CURSOR ( cur , XBT_ERROR ) ;
return error ;
}
if ( args . fsbno = = NULLFSBLOCK ) {
XFS_BTREE_TRACE_CURSOR ( cur , XBT_EXIT ) ;
* stat = 0 ;
return 0 ;
}
ASSERT ( args . len = = 1 ) ;
XFS_BTREE_TRACE_CURSOR ( cur , XBT_EXIT ) ;
new - > s = cpu_to_be32 ( XFS_FSB_TO_AGBNO ( args . mp , args . fsbno ) ) ;
* stat = 1 ;
return 0 ;
}
2008-10-30 08:57:51 +03:00
STATIC int
xfs_inobt_free_block (
struct xfs_btree_cur * cur ,
struct xfs_buf * bp )
{
xfs_fsblock_t fsbno ;
int error ;
fsbno = XFS_DADDR_TO_FSB ( cur - > bc_mp , XFS_BUF_ADDR ( bp ) ) ;
error = xfs_free_extent ( cur - > bc_tp , fsbno , 1 ) ;
if ( error )
return error ;
xfs_trans_binval ( cur - > bc_tp , bp ) ;
return error ;
}
2008-10-30 08:57:03 +03:00
2008-10-30 08:55:23 +03:00
STATIC int
xfs_inobt_get_maxrecs (
struct xfs_btree_cur * cur ,
int level )
{
return cur - > bc_mp - > m_inobt_mxr [ level ! = 0 ] ;
}
2008-10-30 08:56:09 +03:00
STATIC void
xfs_inobt_init_key_from_rec (
union xfs_btree_key * key ,
union xfs_btree_rec * rec )
{
key - > inobt . ir_startino = rec - > inobt . ir_startino ;
}
2008-10-30 08:57:40 +03:00
STATIC void
xfs_inobt_init_rec_from_key (
union xfs_btree_key * key ,
union xfs_btree_rec * rec )
{
rec - > inobt . ir_startino = key - > inobt . ir_startino ;
}
STATIC void
xfs_inobt_init_rec_from_cur (
struct xfs_btree_cur * cur ,
union xfs_btree_rec * rec )
{
rec - > inobt . ir_startino = cpu_to_be32 ( cur - > bc_rec . i . ir_startino ) ;
rec - > inobt . ir_freecount = cpu_to_be32 ( cur - > bc_rec . i . ir_freecount ) ;
rec - > inobt . ir_free = cpu_to_be64 ( cur - > bc_rec . i . ir_free ) ;
}
2008-10-30 08:56:09 +03:00
/*
2009-03-29 11:55:42 +04:00
* initial value of ptr for lookup
2008-10-30 08:56:09 +03:00
*/
STATIC void
xfs_inobt_init_ptr_from_cur (
struct xfs_btree_cur * cur ,
union xfs_btree_ptr * ptr )
{
struct xfs_agi * agi = XFS_BUF_TO_AGI ( cur - > bc_private . a . agbp ) ;
ASSERT ( cur - > bc_private . a . agno = = be32_to_cpu ( agi - > agi_seqno ) ) ;
ptr - > s = agi - > agi_root ;
}
STATIC __int64_t
xfs_inobt_key_diff (
struct xfs_btree_cur * cur ,
union xfs_btree_key * key )
{
return ( __int64_t ) be32_to_cpu ( key - > inobt . ir_startino ) -
cur - > bc_rec . i . ir_startino ;
}
2013-04-21 23:53:46 +04:00
static int
2012-11-14 10:52:32 +04:00
xfs_inobt_verify (
2012-11-12 15:54:08 +04:00
struct xfs_buf * bp )
{
struct xfs_mount * mp = bp - > b_target - > bt_mount ;
struct xfs_btree_block * block = XFS_BUF_TO_BLOCK ( bp ) ;
2013-04-21 23:53:46 +04:00
struct xfs_perag * pag = bp - > b_pag ;
2012-11-12 15:54:08 +04:00
unsigned int level ;
2013-04-21 23:53:46 +04:00
/*
* During growfs operations , we can ' t verify the exact owner as the
* perag is not fully initialised and hence not attached to the buffer .
*
* Similarly , during log recovery we will have a perag structure
* attached , but the agi information will not yet have been initialised
* from the on disk AGI . We don ' t currently use any of this information ,
* but beware of the landmine ( i . e . need to check pag - > pagi_init ) if we
* ever do .
*/
switch ( block - > bb_magic ) {
case cpu_to_be32 ( XFS_IBT_CRC_MAGIC ) :
if ( ! xfs_sb_version_hascrc ( & mp - > m_sb ) )
return false ;
if ( ! uuid_equal ( & block - > bb_u . s . bb_uuid , & mp - > m_sb . sb_uuid ) )
return false ;
if ( block - > bb_u . s . bb_blkno ! = cpu_to_be64 ( bp - > b_bn ) )
return false ;
if ( pag & &
be32_to_cpu ( block - > bb_u . s . bb_owner ) ! = pag - > pag_agno )
return false ;
/* fall through */
case cpu_to_be32 ( XFS_IBT_MAGIC ) :
break ;
default :
return 0 ;
}
2012-11-12 15:54:08 +04:00
2013-04-21 23:53:46 +04:00
/* numrecs and level verification */
level = be16_to_cpu ( block - > bb_level ) ;
if ( level > = mp - > m_in_maxlevels )
return false ;
if ( be16_to_cpu ( block - > bb_numrecs ) > mp - > m_inobt_mxr [ level ! = 0 ] )
return false ;
2012-11-12 15:54:08 +04:00
/* sibling pointer verification */
2013-04-21 23:53:46 +04:00
if ( ! block - > bb_u . s . bb_leftsib | |
( be32_to_cpu ( block - > bb_u . s . bb_leftsib ) > = mp - > m_sb . sb_agblocks & &
block - > bb_u . s . bb_leftsib ! = cpu_to_be32 ( NULLAGBLOCK ) ) )
return false ;
if ( ! block - > bb_u . s . bb_rightsib | |
( be32_to_cpu ( block - > bb_u . s . bb_rightsib ) > = mp - > m_sb . sb_agblocks & &
block - > bb_u . s . bb_rightsib ! = cpu_to_be32 ( NULLAGBLOCK ) ) )
return false ;
return true ;
2012-11-14 10:52:32 +04:00
}
static void
2012-11-14 10:54:40 +04:00
xfs_inobt_read_verify (
2012-11-14 10:52:32 +04:00
struct xfs_buf * bp )
{
2013-04-21 23:53:46 +04:00
if ( ! ( xfs_btree_sblock_verify_crc ( bp ) & &
xfs_inobt_verify ( bp ) ) ) {
trace_xfs_btree_corrupt ( bp , _RET_IP_ ) ;
XFS_CORRUPTION_ERROR ( __func__ , XFS_ERRLEVEL_LOW ,
bp - > b_target - > bt_mount , bp - > b_addr ) ;
xfs_buf_ioerror ( bp , EFSCORRUPTED ) ;
}
2012-11-14 10:52:32 +04:00
}
2012-11-12 15:54:08 +04:00
2012-11-14 10:54:40 +04:00
static void
xfs_inobt_write_verify (
2012-11-14 10:52:32 +04:00
struct xfs_buf * bp )
{
2013-04-21 23:53:46 +04:00
if ( ! xfs_inobt_verify ( bp ) ) {
trace_xfs_btree_corrupt ( bp , _RET_IP_ ) ;
XFS_CORRUPTION_ERROR ( __func__ , XFS_ERRLEVEL_LOW ,
bp - > b_target - > bt_mount , bp - > b_addr ) ;
xfs_buf_ioerror ( bp , EFSCORRUPTED ) ;
}
xfs_btree_sblock_calc_crc ( bp ) ;
2012-11-12 15:54:08 +04:00
}
2012-11-14 10:54:40 +04:00
const struct xfs_buf_ops xfs_inobt_buf_ops = {
. verify_read = xfs_inobt_read_verify ,
. verify_write = xfs_inobt_write_verify ,
} ;
2013-04-30 15:39:34 +04:00
# if defined(DEBUG) || defined(XFS_WARN)
2008-10-30 08:58:32 +03:00
STATIC int
xfs_inobt_keys_inorder (
struct xfs_btree_cur * cur ,
union xfs_btree_key * k1 ,
union xfs_btree_key * k2 )
{
return be32_to_cpu ( k1 - > inobt . ir_startino ) <
be32_to_cpu ( k2 - > inobt . ir_startino ) ;
}
STATIC int
xfs_inobt_recs_inorder (
struct xfs_btree_cur * cur ,
union xfs_btree_rec * r1 ,
union xfs_btree_rec * r2 )
{
return be32_to_cpu ( r1 - > inobt . ir_startino ) + XFS_INODES_PER_CHUNK < =
be32_to_cpu ( r2 - > inobt . ir_startino ) ;
}
# endif /* DEBUG */
2008-10-30 08:53:59 +03:00
static const struct xfs_btree_ops xfs_inobt_ops = {
2008-10-30 08:55:34 +03:00
. rec_len = sizeof ( xfs_inobt_rec_t ) ,
. key_len = sizeof ( xfs_inobt_key_t ) ,
2008-10-30 08:53:59 +03:00
. dup_cursor = xfs_inobt_dup_cursor ,
2008-10-30 08:57:16 +03:00
. set_root = xfs_inobt_set_root ,
2008-10-30 08:57:03 +03:00
. alloc_block = xfs_inobt_alloc_block ,
2008-10-30 08:57:51 +03:00
. free_block = xfs_inobt_free_block ,
2008-10-30 08:58:01 +03:00
. get_minrecs = xfs_inobt_get_minrecs ,
2008-10-30 08:55:23 +03:00
. get_maxrecs = xfs_inobt_get_maxrecs ,
2008-10-30 08:56:09 +03:00
. init_key_from_rec = xfs_inobt_init_key_from_rec ,
2008-10-30 08:57:40 +03:00
. init_rec_from_key = xfs_inobt_init_rec_from_key ,
. init_rec_from_cur = xfs_inobt_init_rec_from_cur ,
2008-10-30 08:56:09 +03:00
. init_ptr_from_cur = xfs_inobt_init_ptr_from_cur ,
. key_diff = xfs_inobt_key_diff ,
2012-11-14 10:54:40 +04:00
. buf_ops = & xfs_inobt_buf_ops ,
2013-04-30 15:39:34 +04:00
# if defined(DEBUG) || defined(XFS_WARN)
2008-10-30 08:58:32 +03:00
. keys_inorder = xfs_inobt_keys_inorder ,
. recs_inorder = xfs_inobt_recs_inorder ,
# endif
2008-10-30 08:53:59 +03:00
} ;
/*
* Allocate a new inode btree cursor .
*/
struct xfs_btree_cur * /* new inode btree cursor */
xfs_inobt_init_cursor (
struct xfs_mount * mp , /* file system mount point */
struct xfs_trans * tp , /* transaction pointer */
struct xfs_buf * agbp , /* buffer for agi structure */
xfs_agnumber_t agno ) /* allocation group number */
{
struct xfs_agi * agi = XFS_BUF_TO_AGI ( agbp ) ;
struct xfs_btree_cur * cur ;
cur = kmem_zone_zalloc ( xfs_btree_cur_zone , KM_SLEEP ) ;
cur - > bc_tp = tp ;
cur - > bc_mp = mp ;
cur - > bc_nlevels = be32_to_cpu ( agi - > agi_level ) ;
cur - > bc_btnum = XFS_BTNUM_INO ;
cur - > bc_blocklog = mp - > m_sb . sb_blocklog ;
cur - > bc_ops = & xfs_inobt_ops ;
2013-04-21 23:53:46 +04:00
if ( xfs_sb_version_hascrc ( & mp - > m_sb ) )
cur - > bc_flags | = XFS_BTREE_CRC_BLOCKS ;
2008-10-30 08:53:59 +03:00
cur - > bc_private . a . agbp = agbp ;
cur - > bc_private . a . agno = agno ;
return cur ;
}
2008-10-30 09:11:19 +03:00
/*
* Calculate number of records in an inobt btree block .
*/
int
xfs_inobt_maxrecs (
struct xfs_mount * mp ,
int blocklen ,
int leaf )
{
2008-10-30 09:14:34 +03:00
blocklen - = XFS_INOBT_BLOCK_LEN ( mp ) ;
2008-10-30 09:11:19 +03:00
if ( leaf )
return blocklen / sizeof ( xfs_inobt_rec_t ) ;
return blocklen / ( sizeof ( xfs_inobt_key_t ) + sizeof ( xfs_inobt_ptr_t ) ) ;
}