2018-06-06 05:42:14 +03:00
// SPDX-License-Identifier: GPL-2.0
2005-04-17 02:20:36 +04:00
/*
2005-11-02 06:58:39 +03:00
* Copyright ( c ) 2000 - 2005 Silicon Graphics , Inc .
2013-04-03 09:11:21 +04:00
* Copyright ( c ) 2013 Red Hat , Inc .
2005-11-02 06:58:39 +03:00
* All Rights Reserved .
2005-04-17 02:20:36 +04:00
*/
# include "xfs.h"
2005-11-02 06:38:42 +03:00
# include "xfs_fs.h"
2019-06-29 05:25:35 +03:00
# include "xfs_shared.h"
2013-10-23 03:51:50 +04:00
# include "xfs_format.h"
2013-10-23 03:50:10 +04:00
# include "xfs_log_format.h"
# include "xfs_trans_resv.h"
2005-04-17 02:20:36 +04:00
# include "xfs_mount.h"
# include "xfs_inode.h"
# include "xfs_bmap.h"
2013-08-12 14:49:37 +04:00
# include "xfs_dir2.h"
2011-07-13 15:43:48 +04:00
# include "xfs_dir2_priv.h"
2005-04-17 02:20:36 +04:00
# include "xfs_error.h"
2009-12-15 02:14:59 +03:00
# include "xfs_trace.h"
2013-10-23 03:50:10 +04:00
# include "xfs_trans.h"
2013-04-03 09:11:21 +04:00
# include "xfs_buf_item.h"
2015-10-12 07:59:25 +03:00
# include "xfs_log.h"
2005-04-17 02:20:36 +04:00
/*
* Function declarations .
*/
2012-06-22 12:50:14 +04:00
static int xfs_dir2_leafn_add ( struct xfs_buf * bp , xfs_da_args_t * args ,
int index ) ;
2005-04-17 02:20:36 +04:00
static void xfs_dir2_leafn_rebalance ( xfs_da_state_t * state ,
xfs_da_state_blk_t * blk1 ,
xfs_da_state_blk_t * blk2 ) ;
2012-06-22 12:50:14 +04:00
static int xfs_dir2_leafn_remove ( xfs_da_args_t * args , struct xfs_buf * bp ,
2005-04-17 02:20:36 +04:00
int index , xfs_da_state_blk_t * dblk ,
int * rval ) ;
static int xfs_dir2_node_addname_int ( xfs_da_args_t * args ,
xfs_da_state_blk_t * fblk ) ;
2013-04-12 01:30:21 +04:00
/*
* Check internal consistency of a leafn block .
*/
# ifdef DEBUG
2018-01-08 21:51:03 +03:00
static xfs_failaddr_t
2013-04-12 01:30:21 +04:00
xfs_dir3_leafn_check (
2013-10-29 15:11:50 +04:00
struct xfs_inode * dp ,
2013-04-12 01:30:21 +04:00
struct xfs_buf * bp )
{
struct xfs_dir2_leaf * leaf = bp - > b_addr ;
struct xfs_dir3_icleaf_hdr leafhdr ;
2013-10-29 15:11:52 +04:00
dp - > d_ops - > leaf_hdr_from_disk ( & leafhdr , leaf ) ;
2013-04-12 01:30:21 +04:00
if ( leafhdr . magic = = XFS_DIR3_LEAFN_MAGIC ) {
struct xfs_dir3_leaf_hdr * leaf3 = bp - > b_addr ;
if ( be64_to_cpu ( leaf3 - > info . blkno ) ! = bp - > b_bn )
2018-01-08 21:51:03 +03:00
return __this_address ;
2013-04-12 01:30:21 +04:00
} else if ( leafhdr . magic ! = XFS_DIR2_LEAFN_MAGIC )
2018-01-08 21:51:03 +03:00
return __this_address ;
2013-04-12 01:30:21 +04:00
2013-10-29 15:11:50 +04:00
return xfs_dir3_leaf_check_int ( dp - > i_mount , dp , & leafhdr , leaf ) ;
2013-04-12 01:30:21 +04:00
}
2018-01-08 21:51:03 +03:00
static inline void
xfs_dir3_leaf_check (
struct xfs_inode * dp ,
struct xfs_buf * bp )
{
xfs_failaddr_t fa ;
fa = xfs_dir3_leafn_check ( dp , bp ) ;
if ( ! fa )
return ;
xfs_corruption_error ( __func__ , XFS_ERRLEVEL_LOW , dp - > i_mount ,
2018-06-04 20:23:54 +03:00
bp - > b_addr , BBTOB ( bp - > b_length ) , __FILE__ , __LINE__ ,
fa ) ;
2018-01-08 21:51:03 +03:00
ASSERT ( 0 ) ;
}
2013-04-12 01:30:21 +04:00
# else
2013-10-29 15:11:50 +04:00
# define xfs_dir3_leaf_check(dp, bp)
2013-04-12 01:30:21 +04:00
# endif
2018-01-08 21:51:03 +03:00
static xfs_failaddr_t
2013-04-03 09:11:21 +04:00
xfs_dir3_free_verify (
2012-11-12 15:54:13 +04:00
struct xfs_buf * bp )
{
2019-06-29 05:27:29 +03:00
struct xfs_mount * mp = bp - > b_mount ;
2012-11-12 15:54:13 +04:00
struct xfs_dir2_free_hdr * hdr = bp - > b_addr ;
2019-02-07 21:45:48 +03:00
if ( ! xfs_verify_magic ( bp , hdr - > magic ) )
return __this_address ;
2013-04-03 09:11:21 +04:00
if ( xfs_sb_version_hascrc ( & mp - > m_sb ) ) {
struct xfs_dir3_blk_hdr * hdr3 = bp - > b_addr ;
2015-07-29 04:53:31 +03:00
if ( ! uuid_equal ( & hdr3 - > uuid , & mp - > m_sb . sb_meta_uuid ) )
2018-01-08 21:51:03 +03:00
return __this_address ;
2013-04-03 09:11:21 +04:00
if ( be64_to_cpu ( hdr3 - > blkno ) ! = bp - > b_bn )
2018-01-08 21:51:03 +03:00
return __this_address ;
2015-10-12 07:59:25 +03:00
if ( ! xfs_log_check_lsn ( mp , be64_to_cpu ( hdr3 - > lsn ) ) )
2018-01-08 21:51:03 +03:00
return __this_address ;
2012-11-12 15:54:13 +04:00
}
2013-04-03 09:11:21 +04:00
/* XXX: should bounds check the xfs_dir3_icfree_hdr here */
2018-01-08 21:51:03 +03:00
return NULL ;
2012-11-14 10:52:32 +04:00
}
2012-11-12 15:54:13 +04:00
2012-11-14 10:52:32 +04:00
static void
2013-04-03 09:11:21 +04:00
xfs_dir3_free_read_verify (
2012-11-14 10:52:32 +04:00
struct xfs_buf * bp )
{
2019-06-29 05:27:29 +03:00
struct xfs_mount * mp = bp - > b_mount ;
2018-01-08 21:51:03 +03:00
xfs_failaddr_t fa ;
2013-04-03 09:11:21 +04:00
2014-02-27 08:23:10 +04:00
if ( xfs_sb_version_hascrc ( & mp - > m_sb ) & &
! xfs_buf_verify_cksum ( bp , XFS_DIR3_FREE_CRC_OFF ) )
2018-01-08 21:51:03 +03:00
xfs_verifier_error ( bp , - EFSBADCRC , __this_address ) ;
else {
fa = xfs_dir3_free_verify ( bp ) ;
if ( fa )
xfs_verifier_error ( bp , - EFSCORRUPTED , fa ) ;
}
2012-11-14 10:52:32 +04:00
}
2012-11-14 10:54:40 +04:00
static void
2013-04-03 09:11:21 +04:00
xfs_dir3_free_write_verify (
2012-11-14 10:52:32 +04:00
struct xfs_buf * bp )
{
2019-06-29 05:27:29 +03:00
struct xfs_mount * mp = bp - > b_mount ;
2018-01-25 00:38:48 +03:00
struct xfs_buf_log_item * bip = bp - > b_log_item ;
2013-04-03 09:11:21 +04:00
struct xfs_dir3_blk_hdr * hdr3 = bp - > b_addr ;
2018-01-08 21:51:03 +03:00
xfs_failaddr_t fa ;
2013-04-03 09:11:21 +04:00
2018-01-08 21:51:03 +03:00
fa = xfs_dir3_free_verify ( bp ) ;
if ( fa ) {
xfs_verifier_error ( bp , - EFSCORRUPTED , fa ) ;
2013-04-03 09:11:21 +04:00
return ;
}
if ( ! xfs_sb_version_hascrc ( & mp - > m_sb ) )
return ;
if ( bip )
hdr3 - > lsn = cpu_to_be64 ( bip - > bli_item . li_lsn ) ;
2014-02-27 08:18:23 +04:00
xfs_buf_update_cksum ( bp , XFS_DIR3_FREE_CRC_OFF ) ;
2012-11-12 15:54:13 +04:00
}
2013-04-03 09:11:29 +04:00
const struct xfs_buf_ops xfs_dir3_free_buf_ops = {
2016-01-04 08:10:19 +03:00
. name = " xfs_dir3_free " ,
2019-02-07 21:45:48 +03:00
. magic = { cpu_to_be32 ( XFS_DIR2_FREE_MAGIC ) ,
cpu_to_be32 ( XFS_DIR3_FREE_MAGIC ) } ,
2013-04-03 09:11:21 +04:00
. verify_read = xfs_dir3_free_read_verify ,
. verify_write = xfs_dir3_free_write_verify ,
2018-01-08 21:51:08 +03:00
. verify_struct = xfs_dir3_free_verify ,
2012-11-14 10:54:40 +04:00
} ;
2017-02-03 02:14:00 +03:00
/* Everything ok in the free block header? */
2018-01-08 21:51:03 +03:00
static xfs_failaddr_t
2017-02-03 02:14:00 +03:00
xfs_dir3_free_header_check (
struct xfs_inode * dp ,
xfs_dablk_t fbno ,
struct xfs_buf * bp )
{
struct xfs_mount * mp = dp - > i_mount ;
unsigned int firstdb ;
int maxbests ;
maxbests = dp - > d_ops - > free_max_bests ( mp - > m_dir_geo ) ;
firstdb = ( xfs_dir2_da_to_db ( mp - > m_dir_geo , fbno ) -
xfs_dir2_byte_to_db ( mp - > m_dir_geo , XFS_DIR2_FREE_OFFSET ) ) *
maxbests ;
if ( xfs_sb_version_hascrc ( & mp - > m_sb ) ) {
struct xfs_dir3_free_hdr * hdr3 = bp - > b_addr ;
if ( be32_to_cpu ( hdr3 - > firstdb ) ! = firstdb )
2018-01-08 21:51:03 +03:00
return __this_address ;
2017-02-03 02:14:00 +03:00
if ( be32_to_cpu ( hdr3 - > nvalid ) > maxbests )
2018-01-08 21:51:03 +03:00
return __this_address ;
2017-02-03 02:14:00 +03:00
if ( be32_to_cpu ( hdr3 - > nvalid ) < be32_to_cpu ( hdr3 - > nused ) )
2018-01-08 21:51:03 +03:00
return __this_address ;
2017-02-03 02:14:00 +03:00
} else {
struct xfs_dir2_free_hdr * hdr = bp - > b_addr ;
if ( be32_to_cpu ( hdr - > firstdb ) ! = firstdb )
2018-01-08 21:51:03 +03:00
return __this_address ;
2017-02-03 02:14:00 +03:00
if ( be32_to_cpu ( hdr - > nvalid ) > maxbests )
2018-01-08 21:51:03 +03:00
return __this_address ;
2017-02-03 02:14:00 +03:00
if ( be32_to_cpu ( hdr - > nvalid ) < be32_to_cpu ( hdr - > nused ) )
2018-01-08 21:51:03 +03:00
return __this_address ;
2017-02-03 02:14:00 +03:00
}
2018-01-08 21:51:03 +03:00
return NULL ;
2017-02-03 02:14:00 +03:00
}
2012-11-14 10:52:32 +04:00
2012-11-12 15:54:13 +04:00
static int
2013-04-03 09:11:21 +04:00
__xfs_dir3_free_read (
2012-11-12 15:54:13 +04:00
struct xfs_trans * tp ,
struct xfs_inode * dp ,
xfs_dablk_t fbno ,
xfs_daddr_t mappedbno ,
struct xfs_buf * * bpp )
{
2018-01-08 21:51:03 +03:00
xfs_failaddr_t fa ;
2013-04-03 09:11:29 +04:00
int err ;
err = xfs_da_read_buf ( tp , dp , fbno , mappedbno , bpp ,
2013-04-03 09:11:21 +04:00
XFS_DATA_FORK , & xfs_dir3_free_buf_ops ) ;
2017-02-03 02:14:00 +03:00
if ( err | | ! * bpp )
return err ;
/* Check things that we can't do in the verifier. */
2018-01-08 21:51:03 +03:00
fa = xfs_dir3_free_header_check ( dp , fbno , * bpp ) ;
if ( fa ) {
xfs_verifier_error ( * bpp , - EFSCORRUPTED , fa ) ;
2017-02-03 02:14:00 +03:00
xfs_trans_brelse ( tp , * bpp ) ;
return - EFSCORRUPTED ;
}
2013-04-03 09:11:29 +04:00
/* try read returns without an error or *bpp if it lands in a hole */
2017-02-03 02:14:00 +03:00
if ( tp )
2013-04-03 09:11:30 +04:00
xfs_trans_buf_set_type ( tp , * bpp , XFS_BLFT_DIR_FREE_BUF ) ;
2017-02-03 02:14:00 +03:00
return 0 ;
2012-11-12 15:54:13 +04:00
}
int
xfs_dir2_free_read (
struct xfs_trans * tp ,
struct xfs_inode * dp ,
xfs_dablk_t fbno ,
struct xfs_buf * * bpp )
{
2013-04-03 09:11:21 +04:00
return __xfs_dir3_free_read ( tp , dp , fbno , - 1 , bpp ) ;
2012-11-12 15:54:13 +04:00
}
static int
xfs_dir2_free_try_read (
struct xfs_trans * tp ,
struct xfs_inode * dp ,
xfs_dablk_t fbno ,
struct xfs_buf * * bpp )
{
2013-04-03 09:11:21 +04:00
return __xfs_dir3_free_read ( tp , dp , fbno , - 2 , bpp ) ;
}
static int
xfs_dir3_free_get_buf (
2014-06-06 09:07:53 +04:00
xfs_da_args_t * args ,
2013-04-03 09:11:21 +04:00
xfs_dir2_db_t fbno ,
struct xfs_buf * * bpp )
{
2014-06-06 09:07:53 +04:00
struct xfs_trans * tp = args - > trans ;
struct xfs_inode * dp = args - > dp ;
2013-04-03 09:11:21 +04:00
struct xfs_mount * mp = dp - > i_mount ;
struct xfs_buf * bp ;
int error ;
struct xfs_dir3_icfree_hdr hdr ;
2014-06-06 09:07:53 +04:00
error = xfs_da_get_buf ( tp , dp , xfs_dir2_db_to_da ( args - > geo , fbno ) ,
2013-04-03 09:11:21 +04:00
- 1 , & bp , XFS_DATA_FORK ) ;
if ( error )
return error ;
2013-04-03 09:11:30 +04:00
xfs_trans_buf_set_type ( tp , bp , XFS_BLFT_DIR_FREE_BUF ) ;
2013-04-03 09:11:21 +04:00
bp - > b_ops = & xfs_dir3_free_buf_ops ;
/*
* Initialize the new block to be empty , and remember
* its first slot as our empty slot .
*/
2013-05-28 12:37:17 +04:00
memset ( bp - > b_addr , 0 , sizeof ( struct xfs_dir3_free_hdr ) ) ;
memset ( & hdr , 0 , sizeof ( hdr ) ) ;
2013-04-03 09:11:21 +04:00
if ( xfs_sb_version_hascrc ( & mp - > m_sb ) ) {
struct xfs_dir3_free_hdr * hdr3 = bp - > b_addr ;
hdr . magic = XFS_DIR3_FREE_MAGIC ;
2013-05-28 12:37:17 +04:00
2013-04-03 09:11:21 +04:00
hdr3 - > hdr . blkno = cpu_to_be64 ( bp - > b_bn ) ;
hdr3 - > hdr . owner = cpu_to_be64 ( dp - > i_ino ) ;
2015-07-29 04:53:31 +03:00
uuid_copy ( & hdr3 - > hdr . uuid , & mp - > m_sb . sb_meta_uuid ) ;
2013-05-28 12:37:17 +04:00
} else
hdr . magic = XFS_DIR2_FREE_MAGIC ;
2013-10-29 15:11:52 +04:00
dp - > d_ops - > free_hdr_to_disk ( bp - > b_addr , & hdr ) ;
2013-04-03 09:11:21 +04:00
* bpp = bp ;
return 0 ;
2012-11-12 15:54:13 +04:00
}
2005-04-17 02:20:36 +04:00
/*
* Log entries from a freespace block .
*/
2009-11-19 18:52:00 +03:00
STATIC void
2005-04-17 02:20:36 +04:00
xfs_dir2_free_log_bests (
2014-06-06 09:20:54 +04:00
struct xfs_da_args * args ,
2012-06-22 12:50:14 +04:00
struct xfs_buf * bp ,
2005-04-17 02:20:36 +04:00
int first , /* first entry to log */
int last ) /* last entry to log */
{
xfs_dir2_free_t * free ; /* freespace structure */
2013-04-03 09:11:21 +04:00
__be16 * bests ;
2005-04-17 02:20:36 +04:00
2012-06-22 12:50:14 +04:00
free = bp - > b_addr ;
2014-06-06 09:20:54 +04:00
bests = args - > dp - > d_ops - > free_bests_p ( free ) ;
2013-04-03 09:11:21 +04:00
ASSERT ( free - > hdr . magic = = cpu_to_be32 ( XFS_DIR2_FREE_MAGIC ) | |
free - > hdr . magic = = cpu_to_be32 ( XFS_DIR3_FREE_MAGIC ) ) ;
2014-06-06 09:20:54 +04:00
xfs_trans_log_buf ( args - > trans , bp ,
2013-04-03 09:11:21 +04:00
( uint ) ( ( char * ) & bests [ first ] - ( char * ) free ) ,
( uint ) ( ( char * ) & bests [ last ] - ( char * ) free +
sizeof ( bests [ 0 ] ) - 1 ) ) ;
2005-04-17 02:20:36 +04:00
}
/*
* Log header from a freespace block .
*/
static void
xfs_dir2_free_log_header (
2014-06-06 09:20:54 +04:00
struct xfs_da_args * args ,
2012-06-22 12:50:14 +04:00
struct xfs_buf * bp )
2005-04-17 02:20:36 +04:00
{
2013-08-12 14:49:44 +04:00
# ifdef DEBUG
2005-04-17 02:20:36 +04:00
xfs_dir2_free_t * free ; /* freespace structure */
2012-06-22 12:50:14 +04:00
free = bp - > b_addr ;
2013-04-03 09:11:21 +04:00
ASSERT ( free - > hdr . magic = = cpu_to_be32 ( XFS_DIR2_FREE_MAGIC ) | |
free - > hdr . magic = = cpu_to_be32 ( XFS_DIR3_FREE_MAGIC ) ) ;
2013-08-12 14:49:44 +04:00
# endif
2014-06-06 09:20:54 +04:00
xfs_trans_log_buf ( args - > trans , bp , 0 ,
args - > dp - > d_ops - > free_hdr_size - 1 ) ;
2005-04-17 02:20:36 +04:00
}
/*
* Convert a leaf - format directory to a node - format directory .
* We need to change the magic number of the leaf block , and copy
* the freespace table out of the leaf block into its own block .
*/
int /* error */
xfs_dir2_leaf_to_node (
xfs_da_args_t * args , /* operation arguments */
2012-06-22 12:50:14 +04:00
struct xfs_buf * lbp ) /* leaf buffer */
2005-04-17 02:20:36 +04:00
{
xfs_inode_t * dp ; /* incore directory inode */
int error ; /* error return value */
2012-06-22 12:50:14 +04:00
struct xfs_buf * fbp ; /* freespace buffer */
2005-04-17 02:20:36 +04:00
xfs_dir2_db_t fdb ; /* freespace block number */
xfs_dir2_free_t * free ; /* freespace structure */
2006-03-17 09:27:19 +03:00
__be16 * from ; /* pointer to freespace entry */
2005-04-17 02:20:36 +04:00
int i ; /* leaf freespace index */
xfs_dir2_leaf_t * leaf ; /* leaf structure */
xfs_dir2_leaf_tail_t * ltp ; /* leaf tail structure */
int n ; /* count of live freespc ents */
xfs_dir2_data_off_t off ; /* freespace entry value */
2006-03-17 09:27:07 +03:00
__be16 * to ; /* pointer to freespace entry */
2005-04-17 02:20:36 +04:00
xfs_trans_t * tp ; /* transaction pointer */
2013-04-03 09:11:21 +04:00
struct xfs_dir3_icfree_hdr freehdr ;
2005-04-17 02:20:36 +04:00
2009-12-15 02:14:59 +03:00
trace_xfs_dir2_leaf_to_node ( args ) ;
2005-04-17 02:20:36 +04:00
dp = args - > dp ;
tp = args - > trans ;
/*
* Add a freespace block to the directory .
*/
if ( ( error = xfs_dir2_grow_inode ( args , XFS_DIR2_FREE_SPACE , & fdb ) ) ) {
return error ;
}
2014-06-06 09:08:18 +04:00
ASSERT ( fdb = = xfs_dir2_byte_to_db ( args - > geo , XFS_DIR2_FREE_OFFSET ) ) ;
2005-04-17 02:20:36 +04:00
/*
* Get the buffer for the new freespace block .
*/
2014-06-06 09:07:53 +04:00
error = xfs_dir3_free_get_buf ( args , fdb , & fbp ) ;
2012-11-14 10:53:49 +04:00
if ( error )
2005-04-17 02:20:36 +04:00
return error ;
2012-11-14 10:53:49 +04:00
2012-06-22 12:50:14 +04:00
free = fbp - > b_addr ;
2013-10-29 15:11:52 +04:00
dp - > d_ops - > free_hdr_from_disk ( & freehdr , free ) ;
2012-06-22 12:50:14 +04:00
leaf = lbp - > b_addr ;
2014-06-06 09:15:59 +04:00
ltp = xfs_dir2_leaf_tail_p ( args - > geo , leaf ) ;
2018-03-07 04:08:31 +03:00
if ( be32_to_cpu ( ltp - > bestcount ) >
( uint ) dp - > i_d . di_size / args - > geo - > blksize )
return - EFSCORRUPTED ;
2013-04-03 09:11:21 +04:00
2005-04-17 02:20:36 +04:00
/*
* Copy freespace entries from the leaf block to the new block .
* Count active entries .
*/
2013-04-03 09:11:21 +04:00
from = xfs_dir2_leaf_bests_p ( ltp ) ;
2013-10-30 22:48:41 +04:00
to = dp - > d_ops - > free_bests_p ( free ) ;
2013-04-03 09:11:21 +04:00
for ( i = n = 0 ; i < be32_to_cpu ( ltp - > bestcount ) ; i + + , from + + , to + + ) {
2006-03-17 09:27:19 +03:00
if ( ( off = be16_to_cpu ( * from ) ) ! = NULLDATAOFF )
2005-04-17 02:20:36 +04:00
n + + ;
2006-03-17 09:27:07 +03:00
* to = cpu_to_be16 ( off ) ;
2005-04-17 02:20:36 +04:00
}
2012-11-14 10:53:49 +04:00
2005-04-17 02:20:36 +04:00
/*
2013-04-03 09:11:21 +04:00
* Now initialize the freespace block header .
2005-04-17 02:20:36 +04:00
*/
2013-04-03 09:11:21 +04:00
freehdr . nused = n ;
freehdr . nvalid = be32_to_cpu ( ltp - > bestcount ) ;
2013-10-29 15:11:52 +04:00
dp - > d_ops - > free_hdr_to_disk ( fbp - > b_addr , & freehdr ) ;
2014-06-06 09:20:54 +04:00
xfs_dir2_free_log_bests ( args , fbp , 0 , freehdr . nvalid - 1 ) ;
xfs_dir2_free_log_header ( args , fbp ) ;
2013-04-03 09:11:21 +04:00
2013-04-12 01:30:21 +04:00
/*
* Converting the leaf to a leafnode is just a matter of changing the
* magic number and the ops . Do the change directly to the buffer as
* it ' s less work ( and less code ) than decoding the header to host
* format and back again .
*/
if ( leaf - > hdr . info . magic = = cpu_to_be16 ( XFS_DIR2_LEAF1_MAGIC ) )
leaf - > hdr . info . magic = cpu_to_be16 ( XFS_DIR2_LEAFN_MAGIC ) ;
else
leaf - > hdr . info . magic = cpu_to_be16 ( XFS_DIR3_LEAFN_MAGIC ) ;
lbp - > b_ops = & xfs_dir3_leafn_buf_ops ;
2013-04-03 09:11:30 +04:00
xfs_trans_buf_set_type ( tp , lbp , XFS_BLFT_DIR_LEAFN_BUF ) ;
2014-06-06 09:20:54 +04:00
xfs_dir3_leaf_log_header ( args , lbp ) ;
2013-10-29 15:11:50 +04:00
xfs_dir3_leaf_check ( dp , lbp ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
/*
* Add a leaf entry to a leaf block in a node - form directory .
* The other work necessary is done from the caller .
*/
static int /* error */
xfs_dir2_leafn_add (
2012-06-22 12:50:14 +04:00
struct xfs_buf * bp , /* leaf buffer */
2019-03-08 03:50:11 +03:00
struct xfs_da_args * args , /* operation arguments */
2005-04-17 02:20:36 +04:00
int index ) /* insertion pt for new entry */
{
2019-03-08 03:50:11 +03:00
struct xfs_dir3_icleaf_hdr leafhdr ;
struct xfs_inode * dp = args - > dp ;
struct xfs_dir2_leaf * leaf = bp - > b_addr ;
struct xfs_dir2_leaf_entry * lep ;
struct xfs_dir2_leaf_entry * ents ;
2005-04-17 02:20:36 +04:00
int compact ; /* compacting stale leaves */
2019-03-08 03:50:11 +03:00
int highstale = 0 ; /* next stale entry */
2005-04-17 02:20:36 +04:00
int lfloghigh ; /* high leaf entry logging */
int lfloglow ; /* low leaf entry logging */
2019-03-08 03:50:11 +03:00
int lowstale = 0 ; /* previous stale entry */
2005-04-17 02:20:36 +04:00
2009-12-15 02:14:59 +03:00
trace_xfs_dir2_leafn_add ( args , index ) ;
2013-10-29 15:11:52 +04:00
dp - > d_ops - > leaf_hdr_from_disk ( & leafhdr , leaf ) ;
2013-10-29 15:11:50 +04:00
ents = dp - > d_ops - > leaf_ents_p ( leaf ) ;
2005-04-17 02:20:36 +04:00
/*
* Quick check just to make sure we are not going to index
* into other peoples memory
*/
if ( index < 0 )
2014-06-25 08:58:08 +04:00
return - EFSCORRUPTED ;
2005-04-17 02:20:36 +04:00
/*
* If there are already the maximum number of leaf entries in
* the block , if there are no stale entries it won ' t fit .
* Caller will do a split . If there are stale entries we ' ll do
* a compact .
*/
2014-06-06 09:15:59 +04:00
if ( leafhdr . count = = dp - > d_ops - > leaf_max_ents ( args - > geo ) ) {
2013-04-12 01:30:21 +04:00
if ( ! leafhdr . stale )
2014-06-25 08:58:08 +04:00
return - ENOSPC ;
2013-04-12 01:30:21 +04:00
compact = leafhdr . stale > 1 ;
2005-04-17 02:20:36 +04:00
} else
compact = 0 ;
2013-04-12 01:30:21 +04:00
ASSERT ( index = = 0 | | be32_to_cpu ( ents [ index - 1 ] . hashval ) < = args - > hashval ) ;
ASSERT ( index = = leafhdr . count | |
be32_to_cpu ( ents [ index ] . hashval ) > = args - > hashval ) ;
2005-04-17 02:20:36 +04:00
2008-05-21 10:42:05 +04:00
if ( args - > op_flags & XFS_DA_OP_JUSTCHECK )
2005-04-17 02:20:36 +04:00
return 0 ;
/*
* Compact out all but one stale leaf entry . Leaves behind
* the entry closest to index .
*/
2013-04-12 01:30:21 +04:00
if ( compact )
xfs_dir3_leaf_compact_x1 ( & leafhdr , ents , & index , & lowstale ,
& highstale , & lfloglow , & lfloghigh ) ;
else if ( leafhdr . stale ) {
/*
* Set impossible logging indices for this case .
*/
lfloglow = leafhdr . count ;
2005-04-17 02:20:36 +04:00
lfloghigh = - 1 ;
}
2011-07-08 16:34:59 +04:00
2005-04-17 02:20:36 +04:00
/*
* Insert the new entry , log everything .
*/
2013-04-12 01:30:21 +04:00
lep = xfs_dir3_leaf_find_entry ( & leafhdr , ents , index , compact , lowstale ,
2011-07-08 16:34:59 +04:00
highstale , & lfloglow , & lfloghigh ) ;
2006-03-17 09:28:18 +03:00
lep - > hashval = cpu_to_be32 ( args - > hashval ) ;
2014-06-06 09:08:18 +04:00
lep - > address = cpu_to_be32 ( xfs_dir2_db_off_to_dataptr ( args - > geo ,
2006-03-17 09:28:18 +03:00
args - > blkno , args - > index ) ) ;
2013-04-12 01:30:21 +04:00
2013-10-29 15:11:52 +04:00
dp - > d_ops - > leaf_hdr_to_disk ( leaf , & leafhdr ) ;
2014-06-06 09:20:54 +04:00
xfs_dir3_leaf_log_header ( args , bp ) ;
xfs_dir3_leaf_log_ents ( args , bp , lfloglow , lfloghigh ) ;
2013-10-29 15:11:50 +04:00
xfs_dir3_leaf_check ( dp , bp ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
# ifdef DEBUG
2013-04-03 09:11:21 +04:00
static void
xfs_dir2_free_hdr_check (
2013-10-29 15:11:52 +04:00
struct xfs_inode * dp ,
2013-04-03 09:11:21 +04:00
struct xfs_buf * bp ,
xfs_dir2_db_t db )
{
struct xfs_dir3_icfree_hdr hdr ;
2013-10-29 15:11:52 +04:00
dp - > d_ops - > free_hdr_from_disk ( & hdr , bp - > b_addr ) ;
2013-04-03 09:11:21 +04:00
2014-06-06 09:15:59 +04:00
ASSERT ( ( hdr . firstdb %
dp - > d_ops - > free_max_bests ( dp - > i_mount - > m_dir_geo ) ) = = 0 ) ;
2013-04-03 09:11:21 +04:00
ASSERT ( hdr . firstdb < = db ) ;
ASSERT ( db < hdr . firstdb + hdr . nvalid ) ;
}
# else
2013-10-29 15:11:52 +04:00
# define xfs_dir2_free_hdr_check(dp, bp, db)
2005-04-17 02:20:36 +04:00
# endif /* DEBUG */
/*
* Return the last hash value in the leaf .
* Stale entries are ok .
*/
xfs_dahash_t /* hash value */
2017-06-16 21:00:13 +03:00
xfs_dir2_leaf_lasthash (
2013-10-29 15:11:50 +04:00
struct xfs_inode * dp ,
2012-06-22 12:50:14 +04:00
struct xfs_buf * bp , /* leaf buffer */
2005-04-17 02:20:36 +04:00
int * count ) /* count of entries in leaf */
{
2013-04-12 01:30:21 +04:00
struct xfs_dir2_leaf * leaf = bp - > b_addr ;
struct xfs_dir2_leaf_entry * ents ;
struct xfs_dir3_icleaf_hdr leafhdr ;
2013-10-29 15:11:52 +04:00
dp - > d_ops - > leaf_hdr_from_disk ( & leafhdr , leaf ) ;
2013-04-12 01:30:21 +04:00
ASSERT ( leafhdr . magic = = XFS_DIR2_LEAFN_MAGIC | |
2017-06-16 21:00:13 +03:00
leafhdr . magic = = XFS_DIR3_LEAFN_MAGIC | |
leafhdr . magic = = XFS_DIR2_LEAF1_MAGIC | |
leafhdr . magic = = XFS_DIR3_LEAF1_MAGIC ) ;
2005-04-17 02:20:36 +04:00
if ( count )
2013-04-12 01:30:21 +04:00
* count = leafhdr . count ;
if ( ! leafhdr . count )
2005-04-17 02:20:36 +04:00
return 0 ;
2013-04-12 01:30:21 +04:00
2013-10-29 15:11:50 +04:00
ents = dp - > d_ops - > leaf_ents_p ( leaf ) ;
2013-04-12 01:30:21 +04:00
return be32_to_cpu ( ents [ leafhdr . count - 1 ] . hashval ) ;
2005-04-17 02:20:36 +04:00
}
/*
2008-04-17 10:49:43 +04:00
* Look up a leaf entry for space to add a name in a node - format leaf block .
* The extrablk in state is a freespace block .
2005-04-17 02:20:36 +04:00
*/
2008-04-17 10:49:43 +04:00
STATIC int
xfs_dir2_leafn_lookup_for_addname (
2012-06-22 12:50:14 +04:00
struct xfs_buf * bp , /* leaf buffer */
2005-04-17 02:20:36 +04:00
xfs_da_args_t * args , /* operation arguments */
int * indexp , /* out: leaf entry index */
xfs_da_state_t * state ) /* state to fill in */
{
2012-06-22 12:50:14 +04:00
struct xfs_buf * curbp = NULL ; /* current data/free buffer */
2008-04-17 10:49:43 +04:00
xfs_dir2_db_t curdb = - 1 ; /* current data block number */
xfs_dir2_db_t curfdb = - 1 ; /* current free block number */
2005-04-17 02:20:36 +04:00
xfs_inode_t * dp ; /* incore directory inode */
int error ; /* error return value */
int fi ; /* free entry index */
2008-04-17 10:49:43 +04:00
xfs_dir2_free_t * free = NULL ; /* free block structure */
2005-04-17 02:20:36 +04:00
int index ; /* leaf entry index */
xfs_dir2_leaf_t * leaf ; /* leaf structure */
2008-04-17 10:49:43 +04:00
int length ; /* length of new data entry */
2005-04-17 02:20:36 +04:00
xfs_dir2_leaf_entry_t * lep ; /* leaf entry */
xfs_mount_t * mp ; /* filesystem mount point */
xfs_dir2_db_t newdb ; /* new data block number */
xfs_dir2_db_t newfdb ; /* new free block number */
xfs_trans_t * tp ; /* transaction pointer */
2013-04-12 01:30:21 +04:00
struct xfs_dir2_leaf_entry * ents ;
struct xfs_dir3_icleaf_hdr leafhdr ;
2005-04-17 02:20:36 +04:00
dp = args - > dp ;
tp = args - > trans ;
mp = dp - > i_mount ;
2012-06-22 12:50:14 +04:00
leaf = bp - > b_addr ;
2013-10-29 15:11:52 +04:00
dp - > d_ops - > leaf_hdr_from_disk ( & leafhdr , leaf ) ;
2013-10-29 15:11:50 +04:00
ents = dp - > d_ops - > leaf_ents_p ( leaf ) ;
2013-04-12 01:30:21 +04:00
2013-10-29 15:11:50 +04:00
xfs_dir3_leaf_check ( dp , bp ) ;
2013-04-12 01:30:21 +04:00
ASSERT ( leafhdr . count > 0 ) ;
2005-04-17 02:20:36 +04:00
/*
* Look up the hash value in the leaf entries .
*/
index = xfs_dir2_leaf_search_hash ( args , bp ) ;
/*
* Do we have a buffer coming in ?
*/
2008-04-17 10:49:43 +04:00
if ( state - > extravalid ) {
/* If so, it's a free block buffer, get the block number. */
2005-04-17 02:20:36 +04:00
curbp = state - > extrablk . bp ;
2008-04-17 10:49:43 +04:00
curfdb = state - > extrablk . blkno ;
2012-06-22 12:50:14 +04:00
free = curbp - > b_addr ;
2013-04-03 09:11:21 +04:00
ASSERT ( free - > hdr . magic = = cpu_to_be32 ( XFS_DIR2_FREE_MAGIC ) | |
free - > hdr . magic = = cpu_to_be32 ( XFS_DIR3_FREE_MAGIC ) ) ;
2005-04-17 02:20:36 +04:00
}
2013-10-29 15:11:48 +04:00
length = dp - > d_ops - > data_entsize ( args - > namelen ) ;
2005-04-17 02:20:36 +04:00
/*
* Loop over leaf entries with the right hash value .
*/
2013-04-12 01:30:21 +04:00
for ( lep = & ents [ index ] ;
index < leafhdr . count & & be32_to_cpu ( lep - > hashval ) = = args - > hashval ;
lep + + , index + + ) {
2005-04-17 02:20:36 +04:00
/*
* Skip stale leaf entries .
*/
2006-03-17 09:28:18 +03:00
if ( be32_to_cpu ( lep - > address ) = = XFS_DIR2_NULL_DATAPTR )
2005-04-17 02:20:36 +04:00
continue ;
/*
* Pull the data block number from the entry .
*/
2014-06-06 09:08:18 +04:00
newdb = xfs_dir2_dataptr_to_db ( args - > geo ,
be32_to_cpu ( lep - > address ) ) ;
2005-04-17 02:20:36 +04:00
/*
* For addname , we ' re looking for a place to put the new entry .
* We want to use a data block with an entry of equal
* hash value to ours if there is one with room .
2008-04-17 10:49:43 +04:00
*
* If this block isn ' t the data block we already have
* in hand , take a look at it .
2005-04-17 02:20:36 +04:00
*/
2008-04-17 10:49:43 +04:00
if ( newdb ! = curdb ) {
2013-04-03 09:11:21 +04:00
__be16 * bests ;
2008-04-17 10:49:43 +04:00
curdb = newdb ;
2005-04-17 02:20:36 +04:00
/*
2008-04-17 10:49:43 +04:00
* Convert the data block to the free block
* holding its freespace information .
2005-04-17 02:20:36 +04:00
*/
2014-06-06 09:15:59 +04:00
newfdb = dp - > d_ops - > db_to_fdb ( args - > geo , newdb ) ;
2005-04-17 02:20:36 +04:00
/*
2008-04-17 10:49:43 +04:00
* If it ' s not the one we have in hand , read it in .
2005-04-17 02:20:36 +04:00
*/
2008-04-17 10:49:43 +04:00
if ( newfdb ! = curfdb ) {
2005-04-17 02:20:36 +04:00
/*
2008-04-17 10:49:43 +04:00
* If we had one before , drop it .
2005-04-17 02:20:36 +04:00
*/
if ( curbp )
2012-06-22 12:50:14 +04:00
xfs_trans_brelse ( tp , curbp ) ;
2012-11-12 15:54:13 +04:00
error = xfs_dir2_free_read ( tp , dp ,
2014-06-06 09:07:53 +04:00
xfs_dir2_db_to_da ( args - > geo ,
newfdb ) ,
2012-11-12 15:54:13 +04:00
& curbp ) ;
2008-04-17 10:49:43 +04:00
if ( error )
2005-04-17 02:20:36 +04:00
return error ;
2012-06-22 12:50:14 +04:00
free = curbp - > b_addr ;
2013-04-03 09:11:21 +04:00
2013-10-29 15:11:52 +04:00
xfs_dir2_free_hdr_check ( dp , curbp , curdb ) ;
2005-04-17 02:20:36 +04:00
}
/*
2008-04-17 10:49:43 +04:00
* Get the index for our entry .
2005-04-17 02:20:36 +04:00
*/
2014-06-06 09:15:59 +04:00
fi = dp - > d_ops - > db_to_fdindex ( args - > geo , curdb ) ;
2005-04-17 02:20:36 +04:00
/*
2008-04-17 10:49:43 +04:00
* If it has room , return it .
2005-04-17 02:20:36 +04:00
*/
2013-10-30 22:48:41 +04:00
bests = dp - > d_ops - > free_bests_p ( free ) ;
2013-04-03 09:11:21 +04:00
if ( unlikely ( bests [ fi ] = = cpu_to_be16 ( NULLDATAOFF ) ) ) {
2008-04-17 10:49:43 +04:00
XFS_ERROR_REPORT ( " xfs_dir2_leafn_lookup_int " ,
XFS_ERRLEVEL_LOW , mp ) ;
if ( curfdb ! = newfdb )
2012-06-22 12:50:14 +04:00
xfs_trans_brelse ( tp , curbp ) ;
2014-06-25 08:58:08 +04:00
return - EFSCORRUPTED ;
2005-04-17 02:20:36 +04:00
}
2008-04-17 10:49:43 +04:00
curfdb = newfdb ;
2013-04-03 09:11:21 +04:00
if ( be16_to_cpu ( bests [ fi ] ) > = length )
2008-04-17 10:49:43 +04:00
goto out ;
2005-04-17 02:20:36 +04:00
}
}
2008-04-17 10:49:43 +04:00
/* Didn't find any space */
fi = - 1 ;
out :
2008-05-21 10:42:05 +04:00
ASSERT ( args - > op_flags & XFS_DA_OP_OKNOENT ) ;
2008-04-17 10:49:43 +04:00
if ( curbp ) {
/* Giving back a free block. */
state - > extravalid = 1 ;
state - > extrablk . bp = curbp ;
state - > extrablk . index = fi ;
state - > extrablk . blkno = curfdb ;
2013-04-03 09:11:21 +04:00
/*
* Important : this magic number is not in the buffer - it ' s for
* buffer type information and therefore only the free / data type
* matters here , not whether CRCs are enabled or not .
*/
2008-04-17 10:49:43 +04:00
state - > extrablk . magic = XFS_DIR2_FREE_MAGIC ;
} else {
state - > extravalid = 0 ;
}
2005-04-17 02:20:36 +04:00
/*
2008-04-17 10:49:43 +04:00
* Return the index , that will be the insertion point .
2005-04-17 02:20:36 +04:00
*/
2008-04-17 10:49:43 +04:00
* indexp = index ;
2014-06-25 08:58:08 +04:00
return - ENOENT ;
2008-04-17 10:49:43 +04:00
}
/*
* Look up a leaf entry in a node - format leaf block .
* The extrablk in state a data block .
*/
STATIC int
xfs_dir2_leafn_lookup_for_entry (
2012-06-22 12:50:14 +04:00
struct xfs_buf * bp , /* leaf buffer */
2008-04-17 10:49:43 +04:00
xfs_da_args_t * args , /* operation arguments */
int * indexp , /* out: leaf entry index */
xfs_da_state_t * state ) /* state to fill in */
{
2012-06-22 12:50:14 +04:00
struct xfs_buf * curbp = NULL ; /* current data/free buffer */
2008-04-17 10:49:43 +04:00
xfs_dir2_db_t curdb = - 1 ; /* current data block number */
xfs_dir2_data_entry_t * dep ; /* data block entry */
xfs_inode_t * dp ; /* incore directory inode */
int error ; /* error return value */
int index ; /* leaf entry index */
xfs_dir2_leaf_t * leaf ; /* leaf structure */
xfs_dir2_leaf_entry_t * lep ; /* leaf entry */
xfs_mount_t * mp ; /* filesystem mount point */
xfs_dir2_db_t newdb ; /* new data block number */
xfs_trans_t * tp ; /* transaction pointer */
2008-05-21 10:41:01 +04:00
enum xfs_dacmp cmp ; /* comparison result */
2013-04-12 01:30:21 +04:00
struct xfs_dir2_leaf_entry * ents ;
struct xfs_dir3_icleaf_hdr leafhdr ;
2008-04-17 10:49:43 +04:00
dp = args - > dp ;
tp = args - > trans ;
mp = dp - > i_mount ;
2012-06-22 12:50:14 +04:00
leaf = bp - > b_addr ;
2013-10-29 15:11:52 +04:00
dp - > d_ops - > leaf_hdr_from_disk ( & leafhdr , leaf ) ;
2013-10-29 15:11:50 +04:00
ents = dp - > d_ops - > leaf_ents_p ( leaf ) ;
2013-04-12 01:30:21 +04:00
2013-10-29 15:11:50 +04:00
xfs_dir3_leaf_check ( dp , bp ) ;
2019-08-12 01:52:26 +03:00
if ( leafhdr . count < = 0 )
return - EFSCORRUPTED ;
2013-04-12 01:30:21 +04:00
2008-04-17 10:49:43 +04:00
/*
* Look up the hash value in the leaf entries .
*/
index = xfs_dir2_leaf_search_hash ( args , bp ) ;
/*
* Do we have a buffer coming in ?
*/
if ( state - > extravalid ) {
curbp = state - > extrablk . bp ;
curdb = state - > extrablk . blkno ;
}
/*
* Loop over leaf entries with the right hash value .
*/
2013-04-12 01:30:21 +04:00
for ( lep = & ents [ index ] ;
index < leafhdr . count & & be32_to_cpu ( lep - > hashval ) = = args - > hashval ;
lep + + , index + + ) {
2008-04-17 10:49:43 +04:00
/*
* Skip stale leaf entries .
*/
if ( be32_to_cpu ( lep - > address ) = = XFS_DIR2_NULL_DATAPTR )
continue ;
2005-04-17 02:20:36 +04:00
/*
2008-04-17 10:49:43 +04:00
* Pull the data block number from the entry .
*/
2014-06-06 09:08:18 +04:00
newdb = xfs_dir2_dataptr_to_db ( args - > geo ,
be32_to_cpu ( lep - > address ) ) ;
2008-04-17 10:49:43 +04:00
/*
* Not adding a new entry , so we really want to find
* the name given to us .
*
* If it ' s a different data block , go get it .
2005-04-17 02:20:36 +04:00
*/
2008-04-17 10:49:43 +04:00
if ( newdb ! = curdb ) {
/*
2008-06-23 07:25:38 +04:00
* If we had a block before that we aren ' t saving
* for a CI name , drop it
2008-04-17 10:49:43 +04:00
*/
2008-06-23 07:25:38 +04:00
if ( curbp & & ( args - > cmpresult = = XFS_CMP_DIFFERENT | |
curdb ! = state - > extrablk . blkno ) )
2012-06-22 12:50:14 +04:00
xfs_trans_brelse ( tp , curbp ) ;
2008-04-17 10:49:43 +04:00
/*
2008-06-23 07:25:38 +04:00
* If needing the block that is saved with a CI match ,
* use it otherwise read in the new data block .
2008-04-17 10:49:43 +04:00
*/
2008-06-23 07:25:38 +04:00
if ( args - > cmpresult ! = XFS_CMP_DIFFERENT & &
newdb = = state - > extrablk . blkno ) {
ASSERT ( state - > extravalid ) ;
curbp = state - > extrablk . bp ;
} else {
2013-04-03 09:11:22 +04:00
error = xfs_dir3_data_read ( tp , dp ,
2014-06-06 09:07:53 +04:00
xfs_dir2_db_to_da ( args - > geo ,
newdb ) ,
2012-11-12 15:54:14 +04:00
- 1 , & curbp ) ;
2008-06-23 07:25:38 +04:00
if ( error )
return error ;
}
2013-04-03 09:11:22 +04:00
xfs_dir3_data_check ( dp , curbp ) ;
2008-04-17 10:49:43 +04:00
curdb = newdb ;
2005-04-17 02:20:36 +04:00
}
/*
2008-04-17 10:49:43 +04:00
* Point to the data entry .
2005-04-17 02:20:36 +04:00
*/
2012-06-22 12:50:14 +04:00
dep = ( xfs_dir2_data_entry_t * ) ( ( char * ) curbp - > b_addr +
2014-06-06 09:08:18 +04:00
xfs_dir2_dataptr_to_off ( args - > geo ,
be32_to_cpu ( lep - > address ) ) ) ;
2008-04-17 10:49:43 +04:00
/*
2008-05-21 10:41:01 +04:00
* Compare the entry and if it ' s an exact match , return
* EEXIST immediately . If it ' s the first case - insensitive
2008-06-23 07:25:38 +04:00
* match , store the block & inode number and continue looking .
2008-04-17 10:49:43 +04:00
*/
2008-05-21 10:41:01 +04:00
cmp = mp - > m_dirnameops - > compname ( args , dep - > name , dep - > namelen ) ;
if ( cmp ! = XFS_CMP_DIFFERENT & & cmp ! = args - > cmpresult ) {
2008-06-23 07:25:38 +04:00
/* If there is a CI match block, drop it */
if ( args - > cmpresult ! = XFS_CMP_DIFFERENT & &
curdb ! = state - > extrablk . blkno )
2012-06-22 12:50:14 +04:00
xfs_trans_brelse ( tp , state - > extrablk . bp ) ;
2008-05-21 10:41:01 +04:00
args - > cmpresult = cmp ;
2008-04-17 10:49:43 +04:00
args - > inumber = be64_to_cpu ( dep - > inumber ) ;
2013-10-29 15:11:48 +04:00
args - > filetype = dp - > d_ops - > data_get_ftype ( dep ) ;
2008-06-23 07:25:38 +04:00
* indexp = index ;
state - > extravalid = 1 ;
state - > extrablk . bp = curbp ;
state - > extrablk . blkno = curdb ;
state - > extrablk . index = ( int ) ( ( char * ) dep -
2012-06-22 12:50:14 +04:00
( char * ) curbp - > b_addr ) ;
2008-06-23 07:25:38 +04:00
state - > extrablk . magic = XFS_DIR2_DATA_MAGIC ;
2013-04-03 09:11:22 +04:00
curbp - > b_ops = & xfs_dir3_data_buf_ops ;
2013-04-03 09:11:30 +04:00
xfs_trans_buf_set_type ( tp , curbp , XFS_BLFT_DIR_DATA_BUF ) ;
2008-05-21 10:41:01 +04:00
if ( cmp = = XFS_CMP_EXACT )
2014-06-25 08:58:08 +04:00
return - EEXIST ;
2005-04-17 02:20:36 +04:00
}
}
2013-04-12 01:30:21 +04:00
ASSERT ( index = = leafhdr . count | | ( args - > op_flags & XFS_DA_OP_OKNOENT ) ) ;
2008-04-17 10:49:43 +04:00
if ( curbp ) {
2008-06-23 07:25:38 +04:00
if ( args - > cmpresult = = XFS_CMP_DIFFERENT ) {
/* Giving back last used data block. */
state - > extravalid = 1 ;
state - > extrablk . bp = curbp ;
state - > extrablk . index = - 1 ;
state - > extrablk . blkno = curdb ;
state - > extrablk . magic = XFS_DIR2_DATA_MAGIC ;
2013-04-03 09:11:22 +04:00
curbp - > b_ops = & xfs_dir3_data_buf_ops ;
2013-04-03 09:11:30 +04:00
xfs_trans_buf_set_type ( tp , curbp , XFS_BLFT_DIR_DATA_BUF ) ;
2008-06-23 07:25:38 +04:00
} else {
/* If the curbp is not the CI match block, drop it */
if ( state - > extrablk . bp ! = curbp )
2012-06-22 12:50:14 +04:00
xfs_trans_brelse ( tp , curbp ) ;
2008-06-23 07:25:38 +04:00
}
2008-04-17 10:49:43 +04:00
} else {
state - > extravalid = 0 ;
}
2005-04-17 02:20:36 +04:00
* indexp = index ;
2014-06-25 08:58:08 +04:00
return - ENOENT ;
2008-04-17 10:49:43 +04:00
}
/*
* Look up a leaf entry in a node - format leaf block .
* If this is an addname then the extrablk in state is a freespace block ,
* otherwise it ' s a data block .
*/
int
xfs_dir2_leafn_lookup_int (
2012-06-22 12:50:14 +04:00
struct xfs_buf * bp , /* leaf buffer */
2008-04-17 10:49:43 +04:00
xfs_da_args_t * args , /* operation arguments */
int * indexp , /* out: leaf entry index */
xfs_da_state_t * state ) /* state to fill in */
{
2008-05-21 10:42:05 +04:00
if ( args - > op_flags & XFS_DA_OP_ADDNAME )
2008-04-17 10:49:43 +04:00
return xfs_dir2_leafn_lookup_for_addname ( bp , args , indexp ,
state ) ;
return xfs_dir2_leafn_lookup_for_entry ( bp , args , indexp , state ) ;
2005-04-17 02:20:36 +04:00
}
/*
* Move count leaf entries from source to destination leaf .
* Log entries and headers . Stale entries are preserved .
*/
static void
2013-04-12 01:30:21 +04:00
xfs_dir3_leafn_moveents (
xfs_da_args_t * args , /* operation arguments */
struct xfs_buf * bp_s , /* source */
struct xfs_dir3_icleaf_hdr * shdr ,
struct xfs_dir2_leaf_entry * sents ,
int start_s , /* source leaf index */
struct xfs_buf * bp_d , /* destination */
struct xfs_dir3_icleaf_hdr * dhdr ,
struct xfs_dir2_leaf_entry * dents ,
int start_d , /* destination leaf index */
int count ) /* count of leaves to copy */
2005-04-17 02:20:36 +04:00
{
2013-04-12 01:30:21 +04:00
int stale ; /* count stale leaves copied */
2005-04-17 02:20:36 +04:00
2009-12-15 02:14:59 +03:00
trace_xfs_dir2_leafn_moveents ( args , start_s , start_d , count ) ;
2005-04-17 02:20:36 +04:00
/*
* Silently return if nothing to do .
*/
2013-04-12 01:30:21 +04:00
if ( count = = 0 )
2005-04-17 02:20:36 +04:00
return ;
2013-04-12 01:30:21 +04:00
2005-04-17 02:20:36 +04:00
/*
* If the destination index is not the end of the current
* destination leaf entries , open up a hole in the destination
* to hold the new entries .
*/
2013-04-12 01:30:21 +04:00
if ( start_d < dhdr - > count ) {
memmove ( & dents [ start_d + count ] , & dents [ start_d ] ,
( dhdr - > count - start_d ) * sizeof ( xfs_dir2_leaf_entry_t ) ) ;
2014-06-06 09:20:54 +04:00
xfs_dir3_leaf_log_ents ( args , bp_d , start_d + count ,
2013-04-12 01:30:21 +04:00
count + dhdr - > count - 1 ) ;
2005-04-17 02:20:36 +04:00
}
/*
* If the source has stale leaves , count the ones in the copy range
* so we can update the header correctly .
*/
2013-04-12 01:30:21 +04:00
if ( shdr - > stale ) {
2005-04-17 02:20:36 +04:00
int i ; /* temp leaf index */
for ( i = start_s , stale = 0 ; i < start_s + count ; i + + ) {
2013-04-12 01:30:21 +04:00
if ( sents [ i ] . address = =
cpu_to_be32 ( XFS_DIR2_NULL_DATAPTR ) )
2005-04-17 02:20:36 +04:00
stale + + ;
}
} else
stale = 0 ;
/*
* Copy the leaf entries from source to destination .
*/
2013-04-12 01:30:21 +04:00
memcpy ( & dents [ start_d ] , & sents [ start_s ] ,
2005-04-17 02:20:36 +04:00
count * sizeof ( xfs_dir2_leaf_entry_t ) ) ;
2014-06-06 09:20:54 +04:00
xfs_dir3_leaf_log_ents ( args , bp_d , start_d , start_d + count - 1 ) ;
2013-04-12 01:30:21 +04:00
2005-04-17 02:20:36 +04:00
/*
* If there are source entries after the ones we copied ,
* delete the ones we copied by sliding the next ones down .
*/
2013-04-12 01:30:21 +04:00
if ( start_s + count < shdr - > count ) {
memmove ( & sents [ start_s ] , & sents [ start_s + count ] ,
2005-04-17 02:20:36 +04:00
count * sizeof ( xfs_dir2_leaf_entry_t ) ) ;
2014-06-06 09:20:54 +04:00
xfs_dir3_leaf_log_ents ( args , bp_s , start_s , start_s + count - 1 ) ;
2005-04-17 02:20:36 +04:00
}
2013-04-12 01:30:21 +04:00
2005-04-17 02:20:36 +04:00
/*
* Update the headers and log them .
*/
2013-04-12 01:30:21 +04:00
shdr - > count - = count ;
shdr - > stale - = stale ;
dhdr - > count + = count ;
dhdr - > stale + = stale ;
2005-04-17 02:20:36 +04:00
}
/*
* Determine the sort order of two leaf blocks .
* Returns 1 if both are valid and leaf2 should be before leaf1 , else 0.
*/
int /* sort order */
xfs_dir2_leafn_order (
2013-10-29 15:11:50 +04:00
struct xfs_inode * dp ,
2013-04-12 01:30:21 +04:00
struct xfs_buf * leaf1_bp , /* leaf1 buffer */
struct xfs_buf * leaf2_bp ) /* leaf2 buffer */
2005-04-17 02:20:36 +04:00
{
2013-04-12 01:30:21 +04:00
struct xfs_dir2_leaf * leaf1 = leaf1_bp - > b_addr ;
struct xfs_dir2_leaf * leaf2 = leaf2_bp - > b_addr ;
struct xfs_dir2_leaf_entry * ents1 ;
struct xfs_dir2_leaf_entry * ents2 ;
struct xfs_dir3_icleaf_hdr hdr1 ;
struct xfs_dir3_icleaf_hdr hdr2 ;
2013-10-29 15:11:52 +04:00
dp - > d_ops - > leaf_hdr_from_disk ( & hdr1 , leaf1 ) ;
dp - > d_ops - > leaf_hdr_from_disk ( & hdr2 , leaf2 ) ;
2013-10-29 15:11:50 +04:00
ents1 = dp - > d_ops - > leaf_ents_p ( leaf1 ) ;
ents2 = dp - > d_ops - > leaf_ents_p ( leaf2 ) ;
2013-04-12 01:30:21 +04:00
if ( hdr1 . count > 0 & & hdr2 . count > 0 & &
( be32_to_cpu ( ents2 [ 0 ] . hashval ) < be32_to_cpu ( ents1 [ 0 ] . hashval ) | |
be32_to_cpu ( ents2 [ hdr2 . count - 1 ] . hashval ) <
be32_to_cpu ( ents1 [ hdr1 . count - 1 ] . hashval ) ) )
2005-04-17 02:20:36 +04:00
return 1 ;
return 0 ;
}
/*
* Rebalance leaf entries between two leaf blocks .
* This is actually only called when the second block is new ,
* though the code deals with the general case .
* A new entry will be inserted in one of the blocks , and that
* entry is taken into account when balancing .
*/
static void
xfs_dir2_leafn_rebalance (
xfs_da_state_t * state , /* btree cursor */
xfs_da_state_blk_t * blk1 , /* first btree block */
xfs_da_state_blk_t * blk2 ) /* second btree block */
{
xfs_da_args_t * args ; /* operation arguments */
int count ; /* count (& direction) leaves */
int isleft ; /* new goes in left leaf */
xfs_dir2_leaf_t * leaf1 ; /* first leaf structure */
xfs_dir2_leaf_t * leaf2 ; /* second leaf structure */
int mid ; /* midpoint leaf index */
2013-04-30 15:39:34 +04:00
# if defined(DEBUG) || defined(XFS_WARN)
2005-04-17 02:20:36 +04:00
int oldstale ; /* old count of stale leaves */
# endif
int oldsum ; /* old total leaf count */
2018-07-18 00:25:01 +03:00
int swap_blocks ; /* swapped leaf blocks */
2013-04-12 01:30:21 +04:00
struct xfs_dir2_leaf_entry * ents1 ;
struct xfs_dir2_leaf_entry * ents2 ;
struct xfs_dir3_icleaf_hdr hdr1 ;
struct xfs_dir3_icleaf_hdr hdr2 ;
2013-10-29 15:11:50 +04:00
struct xfs_inode * dp = state - > args - > dp ;
2005-04-17 02:20:36 +04:00
args = state - > args ;
/*
* If the block order is wrong , swap the arguments .
*/
2018-07-18 00:25:01 +03:00
swap_blocks = xfs_dir2_leafn_order ( dp , blk1 - > bp , blk2 - > bp ) ;
if ( swap_blocks )
swap ( blk1 , blk2 ) ;
2005-04-17 02:20:36 +04:00
2012-06-22 12:50:14 +04:00
leaf1 = blk1 - > bp - > b_addr ;
leaf2 = blk2 - > bp - > b_addr ;
2013-10-29 15:11:52 +04:00
dp - > d_ops - > leaf_hdr_from_disk ( & hdr1 , leaf1 ) ;
dp - > d_ops - > leaf_hdr_from_disk ( & hdr2 , leaf2 ) ;
2013-10-29 15:11:50 +04:00
ents1 = dp - > d_ops - > leaf_ents_p ( leaf1 ) ;
ents2 = dp - > d_ops - > leaf_ents_p ( leaf2 ) ;
2013-04-12 01:30:21 +04:00
oldsum = hdr1 . count + hdr2 . count ;
2013-04-30 15:39:34 +04:00
# if defined(DEBUG) || defined(XFS_WARN)
2013-04-12 01:30:21 +04:00
oldstale = hdr1 . stale + hdr2 . stale ;
2005-04-17 02:20:36 +04:00
# endif
mid = oldsum > > 1 ;
2013-04-12 01:30:21 +04:00
2005-04-17 02:20:36 +04:00
/*
* If the old leaf count was odd then the new one will be even ,
* so we need to divide the new count evenly .
*/
if ( oldsum & 1 ) {
xfs_dahash_t midhash ; /* middle entry hash value */
2013-04-12 01:30:21 +04:00
if ( mid > = hdr1 . count )
midhash = be32_to_cpu ( ents2 [ mid - hdr1 . count ] . hashval ) ;
2005-04-17 02:20:36 +04:00
else
2013-04-12 01:30:21 +04:00
midhash = be32_to_cpu ( ents1 [ mid ] . hashval ) ;
2005-04-17 02:20:36 +04:00
isleft = args - > hashval < = midhash ;
}
/*
* If the old count is even then the new count is odd , so there ' s
* no preferred side for the new entry .
* Pick the left one .
*/
else
isleft = 1 ;
/*
* Calculate moved entry count . Positive means left - to - right ,
* negative means right - to - left . Then move the entries .
*/
2013-04-12 01:30:21 +04:00
count = hdr1 . count - mid + ( isleft = = 0 ) ;
2005-04-17 02:20:36 +04:00
if ( count > 0 )
2013-04-12 01:30:21 +04:00
xfs_dir3_leafn_moveents ( args , blk1 - > bp , & hdr1 , ents1 ,
hdr1 . count - count , blk2 - > bp ,
& hdr2 , ents2 , 0 , count ) ;
2005-04-17 02:20:36 +04:00
else if ( count < 0 )
2013-04-12 01:30:21 +04:00
xfs_dir3_leafn_moveents ( args , blk2 - > bp , & hdr2 , ents2 , 0 ,
blk1 - > bp , & hdr1 , ents1 ,
hdr1 . count , count ) ;
ASSERT ( hdr1 . count + hdr2 . count = = oldsum ) ;
ASSERT ( hdr1 . stale + hdr2 . stale = = oldstale ) ;
/* log the changes made when moving the entries */
2013-10-29 15:11:52 +04:00
dp - > d_ops - > leaf_hdr_to_disk ( leaf1 , & hdr1 ) ;
dp - > d_ops - > leaf_hdr_to_disk ( leaf2 , & hdr2 ) ;
2014-06-06 09:20:54 +04:00
xfs_dir3_leaf_log_header ( args , blk1 - > bp ) ;
xfs_dir3_leaf_log_header ( args , blk2 - > bp ) ;
2013-04-12 01:30:21 +04:00
2013-10-29 15:11:50 +04:00
xfs_dir3_leaf_check ( dp , blk1 - > bp ) ;
xfs_dir3_leaf_check ( dp , blk2 - > bp ) ;
2013-04-12 01:30:21 +04:00
2005-04-17 02:20:36 +04:00
/*
* Mark whether we ' re inserting into the old or new leaf .
*/
2013-04-12 01:30:21 +04:00
if ( hdr1 . count < hdr2 . count )
2018-07-18 00:25:01 +03:00
state - > inleaf = swap_blocks ;
2013-04-12 01:30:21 +04:00
else if ( hdr1 . count > hdr2 . count )
2018-07-18 00:25:01 +03:00
state - > inleaf = ! swap_blocks ;
2005-04-17 02:20:36 +04:00
else
2018-07-18 00:25:01 +03:00
state - > inleaf = swap_blocks ^ ( blk1 - > index < = hdr1 . count ) ;
2005-04-17 02:20:36 +04:00
/*
* Adjust the expected index for insertion .
*/
if ( ! state - > inleaf )
2013-04-12 01:30:21 +04:00
blk2 - > index = blk1 - > index - hdr1 . count ;
2008-04-17 10:49:43 +04:00
/*
* Finally sanity check just to make sure we are not returning a
* negative index
2005-04-17 02:20:36 +04:00
*/
2013-10-29 15:11:50 +04:00
if ( blk2 - > index < 0 ) {
2005-04-17 02:20:36 +04:00
state - > inleaf = 1 ;
blk2 - > index = 0 ;
2013-10-29 15:11:50 +04:00
xfs_alert ( dp - > i_mount ,
2013-10-12 05:59:05 +04:00
" %s: picked the wrong leaf? reverting original leaf: blk1->index %d " ,
2011-03-07 02:08:35 +03:00
__func__ , blk1 - > index ) ;
2005-04-17 02:20:36 +04:00
}
}
2012-11-12 15:54:13 +04:00
static int
2013-04-03 09:11:21 +04:00
xfs_dir3_data_block_free (
2012-11-12 15:54:13 +04:00
xfs_da_args_t * args ,
struct xfs_dir2_data_hdr * hdr ,
struct xfs_dir2_free * free ,
xfs_dir2_db_t fdb ,
int findex ,
struct xfs_buf * fbp ,
int longest )
{
int logfree = 0 ;
2013-04-03 09:11:21 +04:00
__be16 * bests ;
struct xfs_dir3_icfree_hdr freehdr ;
2013-10-29 15:11:52 +04:00
struct xfs_inode * dp = args - > dp ;
2012-11-12 15:54:13 +04:00
2013-10-29 15:11:52 +04:00
dp - > d_ops - > free_hdr_from_disk ( & freehdr , free ) ;
2013-10-30 22:48:41 +04:00
bests = dp - > d_ops - > free_bests_p ( free ) ;
2013-04-03 09:11:21 +04:00
if ( hdr ) {
2012-11-12 15:54:13 +04:00
/*
2013-04-03 09:11:21 +04:00
* Data block is not empty , just set the free entry to the new
* value .
2012-11-12 15:54:13 +04:00
*/
2013-04-03 09:11:21 +04:00
bests [ findex ] = cpu_to_be16 ( longest ) ;
2014-06-06 09:20:54 +04:00
xfs_dir2_free_log_bests ( args , fbp , findex , findex ) ;
2013-04-03 09:11:21 +04:00
return 0 ;
}
2012-11-12 15:54:13 +04:00
2013-04-03 09:11:21 +04:00
/* One less used entry in the free table. */
freehdr . nused - - ;
2012-11-12 15:54:13 +04:00
2013-04-03 09:11:21 +04:00
/*
* If this was the last entry in the table , we can trim the table size
* back . There might be other entries at the end referring to
* non - existent data blocks , get those too .
*/
if ( findex = = freehdr . nvalid - 1 ) {
int i ; /* free entry index */
for ( i = findex - 1 ; i > = 0 ; i - - ) {
if ( bests [ i ] ! = cpu_to_be16 ( NULLDATAOFF ) )
break ;
2012-11-12 15:54:13 +04:00
}
2013-04-03 09:11:21 +04:00
freehdr . nvalid = i + 1 ;
logfree = 0 ;
2012-11-12 15:54:13 +04:00
} else {
2013-04-03 09:11:21 +04:00
/* Not the last entry, just punch it out. */
bests [ findex ] = cpu_to_be16 ( NULLDATAOFF ) ;
logfree = 1 ;
}
2013-10-29 15:11:52 +04:00
dp - > d_ops - > free_hdr_to_disk ( free , & freehdr ) ;
2014-06-06 09:20:54 +04:00
xfs_dir2_free_log_header ( args , fbp ) ;
2013-04-03 09:11:21 +04:00
/*
* If there are no useful entries left in the block , get rid of the
* block if we can .
*/
if ( ! freehdr . nused ) {
int error ;
error = xfs_dir2_shrink_inode ( args , fdb , fbp ) ;
if ( error = = 0 ) {
fbp = NULL ;
logfree = 0 ;
2014-06-25 08:58:08 +04:00
} else if ( error ! = - ENOSPC | | args - > total ! = 0 )
2013-04-03 09:11:21 +04:00
return error ;
2012-11-12 15:54:13 +04:00
/*
2013-04-03 09:11:21 +04:00
* It ' s possible to get ENOSPC if there is no
* space reservation . In this case some one
* else will eventually get rid of this block .
2012-11-12 15:54:13 +04:00
*/
}
/* Log the free entry that changed, unless we got rid of it. */
if ( logfree )
2014-06-06 09:20:54 +04:00
xfs_dir2_free_log_bests ( args , fbp , findex , findex ) ;
2012-11-12 15:54:13 +04:00
return 0 ;
}
2005-04-17 02:20:36 +04:00
/*
* Remove an entry from a node directory .
* This removes the leaf entry and the data entry ,
* and updates the free block if necessary .
*/
static int /* error */
xfs_dir2_leafn_remove (
xfs_da_args_t * args , /* operation arguments */
2012-06-22 12:50:14 +04:00
struct xfs_buf * bp , /* leaf buffer */
2005-04-17 02:20:36 +04:00
int index , /* leaf entry index */
xfs_da_state_blk_t * dblk , /* data block */
int * rval ) /* resulting block needs join */
{
2011-07-08 16:35:38 +04:00
xfs_dir2_data_hdr_t * hdr ; /* data block header */
2005-04-17 02:20:36 +04:00
xfs_dir2_db_t db ; /* data block number */
2012-06-22 12:50:14 +04:00
struct xfs_buf * dbp ; /* data block buffer */
2005-04-17 02:20:36 +04:00
xfs_dir2_data_entry_t * dep ; /* data block entry */
xfs_inode_t * dp ; /* incore directory inode */
xfs_dir2_leaf_t * leaf ; /* leaf structure */
xfs_dir2_leaf_entry_t * lep ; /* leaf entry */
int longest ; /* longest data free entry */
int off ; /* data block entry offset */
int needlog ; /* need to log data header */
int needscan ; /* need to rescan data frees */
xfs_trans_t * tp ; /* transaction pointer */
2013-04-03 09:11:22 +04:00
struct xfs_dir2_data_free * bf ; /* bestfree table */
2013-04-12 01:30:21 +04:00
struct xfs_dir3_icleaf_hdr leafhdr ;
struct xfs_dir2_leaf_entry * ents ;
2005-04-17 02:20:36 +04:00
2009-12-15 02:14:59 +03:00
trace_xfs_dir2_leafn_remove ( args , index ) ;
2005-04-17 02:20:36 +04:00
dp = args - > dp ;
tp = args - > trans ;
2012-06-22 12:50:14 +04:00
leaf = bp - > b_addr ;
2013-10-29 15:11:52 +04:00
dp - > d_ops - > leaf_hdr_from_disk ( & leafhdr , leaf ) ;
2013-10-29 15:11:50 +04:00
ents = dp - > d_ops - > leaf_ents_p ( leaf ) ;
2013-04-12 01:30:21 +04:00
2005-04-17 02:20:36 +04:00
/*
* Point to the entry we ' re removing .
*/
2013-04-12 01:30:21 +04:00
lep = & ents [ index ] ;
2005-04-17 02:20:36 +04:00
/*
* Extract the data block and offset from the entry .
*/
2014-06-06 09:08:18 +04:00
db = xfs_dir2_dataptr_to_db ( args - > geo , be32_to_cpu ( lep - > address ) ) ;
2005-04-17 02:20:36 +04:00
ASSERT ( dblk - > blkno = = db ) ;
2014-06-06 09:08:18 +04:00
off = xfs_dir2_dataptr_to_off ( args - > geo , be32_to_cpu ( lep - > address ) ) ;
2005-04-17 02:20:36 +04:00
ASSERT ( dblk - > index = = off ) ;
2013-04-12 01:30:21 +04:00
2005-04-17 02:20:36 +04:00
/*
* Kill the leaf entry by marking it stale .
* Log the leaf block changes .
*/
2013-04-12 01:30:21 +04:00
leafhdr . stale + + ;
2013-10-29 15:11:52 +04:00
dp - > d_ops - > leaf_hdr_to_disk ( leaf , & leafhdr ) ;
2014-06-06 09:20:54 +04:00
xfs_dir3_leaf_log_header ( args , bp ) ;
2013-04-12 01:30:21 +04:00
2006-03-17 09:28:18 +03:00
lep - > address = cpu_to_be32 ( XFS_DIR2_NULL_DATAPTR ) ;
2014-06-06 09:20:54 +04:00
xfs_dir3_leaf_log_ents ( args , bp , index , index ) ;
2013-04-12 01:30:21 +04:00
2005-04-17 02:20:36 +04:00
/*
* Make the data entry free . Keep track of the longest freespace
* in the data block in case it changes .
*/
dbp = dblk - > bp ;
2012-06-22 12:50:14 +04:00
hdr = dbp - > b_addr ;
2011-07-08 16:35:38 +04:00
dep = ( xfs_dir2_data_entry_t * ) ( ( char * ) hdr + off ) ;
2013-10-29 15:11:49 +04:00
bf = dp - > d_ops - > data_bestfree_p ( hdr ) ;
2013-04-03 09:11:22 +04:00
longest = be16_to_cpu ( bf [ 0 ] . length ) ;
2005-04-17 02:20:36 +04:00
needlog = needscan = 0 ;
2014-06-06 09:20:54 +04:00
xfs_dir2_data_make_free ( args , dbp , off ,
2013-10-29 15:11:48 +04:00
dp - > d_ops - > data_entsize ( dep - > namelen ) , & needlog , & needscan ) ;
2005-04-17 02:20:36 +04:00
/*
* Rescan the data block freespaces for bestfree .
* Log the data block header if needed .
*/
if ( needscan )
2013-10-29 15:11:48 +04:00
xfs_dir2_data_freescan ( dp , hdr , & needlog ) ;
2005-04-17 02:20:36 +04:00
if ( needlog )
2014-06-06 09:20:54 +04:00
xfs_dir2_data_log_header ( args , dbp ) ;
2013-04-03 09:11:22 +04:00
xfs_dir3_data_check ( dp , dbp ) ;
2005-04-17 02:20:36 +04:00
/*
* If the longest data block freespace changes , need to update
* the corresponding freeblock entry .
*/
2013-04-03 09:11:22 +04:00
if ( longest < be16_to_cpu ( bf [ 0 ] . length ) ) {
2005-04-17 02:20:36 +04:00
int error ; /* error return value */
2012-06-22 12:50:14 +04:00
struct xfs_buf * fbp ; /* freeblock buffer */
2005-04-17 02:20:36 +04:00
xfs_dir2_db_t fdb ; /* freeblock block number */
int findex ; /* index in freeblock entries */
xfs_dir2_free_t * free ; /* freeblock structure */
/*
* Convert the data block number to a free block ,
* read in the free block .
*/
2014-06-06 09:15:59 +04:00
fdb = dp - > d_ops - > db_to_fdb ( args - > geo , db ) ;
2014-06-06 09:07:53 +04:00
error = xfs_dir2_free_read ( tp , dp ,
xfs_dir2_db_to_da ( args - > geo , fdb ) ,
2012-11-12 15:54:13 +04:00
& fbp ) ;
2012-11-12 15:54:10 +04:00
if ( error )
2005-04-17 02:20:36 +04:00
return error ;
2012-06-22 12:50:14 +04:00
free = fbp - > b_addr ;
2013-04-03 09:11:21 +04:00
# ifdef DEBUG
{
struct xfs_dir3_icfree_hdr freehdr ;
2013-10-29 15:11:52 +04:00
dp - > d_ops - > free_hdr_from_disk ( & freehdr , free ) ;
2014-06-06 09:15:59 +04:00
ASSERT ( freehdr . firstdb = = dp - > d_ops - > free_max_bests ( args - > geo ) *
2014-06-06 09:08:18 +04:00
( fdb - xfs_dir2_byte_to_db ( args - > geo ,
XFS_DIR2_FREE_OFFSET ) ) ) ;
2013-04-03 09:11:21 +04:00
}
# endif
2005-04-17 02:20:36 +04:00
/*
* Calculate which entry we need to fix .
*/
2014-06-06 09:15:59 +04:00
findex = dp - > d_ops - > db_to_fdindex ( args - > geo , db ) ;
2013-04-03 09:11:22 +04:00
longest = be16_to_cpu ( bf [ 0 ] . length ) ;
2005-04-17 02:20:36 +04:00
/*
* If the data block is now empty we can get rid of it
* ( usually ) .
*/
2014-06-06 09:15:59 +04:00
if ( longest = = args - > geo - > blksize -
2013-10-30 02:15:02 +04:00
dp - > d_ops - > data_entry_offset ) {
2005-04-17 02:20:36 +04:00
/*
* Try to punch out the data block .
*/
error = xfs_dir2_shrink_inode ( args , db , dbp ) ;
if ( error = = 0 ) {
dblk - > bp = NULL ;
2011-07-08 16:35:38 +04:00
hdr = NULL ;
2005-04-17 02:20:36 +04:00
}
/*
* We can get ENOSPC if there ' s no space reservation .
* In this case just drop the buffer and some one else
* will eventually get rid of the empty block .
*/
2014-06-25 08:58:08 +04:00
else if ( ! ( error = = - ENOSPC & & args - > total = = 0 ) )
2005-04-17 02:20:36 +04:00
return error ;
}
/*
* If we got rid of the data block , we can eliminate that entry
* in the free block .
*/
2013-04-03 09:11:21 +04:00
error = xfs_dir3_data_block_free ( args , hdr , free ,
2012-11-12 15:54:13 +04:00
fdb , findex , fbp , longest ) ;
if ( error )
return error ;
2005-04-17 02:20:36 +04:00
}
2012-11-12 15:54:13 +04:00
2013-10-29 15:11:50 +04:00
xfs_dir3_leaf_check ( dp , bp ) ;
2005-04-17 02:20:36 +04:00
/*
2009-03-29 11:55:42 +04:00
* Return indication of whether this leaf block is empty enough
2005-04-17 02:20:36 +04:00
* to justify trying to join it with a neighbor .
*/
2013-10-30 02:15:02 +04:00
* rval = ( dp - > d_ops - > leaf_hdr_size +
2013-04-12 01:30:21 +04:00
( uint ) sizeof ( ents [ 0 ] ) * ( leafhdr . count - leafhdr . stale ) ) <
2014-06-06 09:18:10 +04:00
args - > geo - > magicpct ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
/*
* Split the leaf entries in the old block into old and new blocks .
*/
int /* error */
xfs_dir2_leafn_split (
xfs_da_state_t * state , /* btree cursor */
xfs_da_state_blk_t * oldblk , /* original block */
xfs_da_state_blk_t * newblk ) /* newly created block */
{
xfs_da_args_t * args ; /* operation arguments */
xfs_dablk_t blkno ; /* new leaf block number */
int error ; /* error return value */
2013-10-29 15:11:50 +04:00
struct xfs_inode * dp ;
2005-04-17 02:20:36 +04:00
/*
* Allocate space for a new leaf node .
*/
args = state - > args ;
2013-10-29 15:11:50 +04:00
dp = args - > dp ;
2005-04-17 02:20:36 +04:00
ASSERT ( oldblk - > magic = = XFS_DIR2_LEAFN_MAGIC ) ;
error = xfs_da_grow_inode ( args , & blkno ) ;
if ( error ) {
return error ;
}
/*
* Initialize the new leaf block .
*/
2014-06-06 09:07:53 +04:00
error = xfs_dir3_leaf_get_buf ( args , xfs_dir2_da_to_db ( args - > geo , blkno ) ,
2013-04-12 01:30:21 +04:00
& newblk - > bp , XFS_DIR2_LEAFN_MAGIC ) ;
if ( error )
2005-04-17 02:20:36 +04:00
return error ;
2013-04-12 01:30:21 +04:00
2005-04-17 02:20:36 +04:00
newblk - > blkno = blkno ;
newblk - > magic = XFS_DIR2_LEAFN_MAGIC ;
/*
* Rebalance the entries across the two leaves , link the new
* block into the leaves .
*/
xfs_dir2_leafn_rebalance ( state , oldblk , newblk ) ;
2013-04-24 12:58:02 +04:00
error = xfs_da3_blk_link ( state , oldblk , newblk ) ;
2005-04-17 02:20:36 +04:00
if ( error ) {
return error ;
}
/*
* Insert the new entry in the correct block .
*/
if ( state - > inleaf )
error = xfs_dir2_leafn_add ( oldblk - > bp , args , oldblk - > index ) ;
else
error = xfs_dir2_leafn_add ( newblk - > bp , args , newblk - > index ) ;
/*
* Update last hashval in each block since we added the name .
*/
2017-06-16 21:00:13 +03:00
oldblk - > hashval = xfs_dir2_leaf_lasthash ( dp , oldblk - > bp , NULL ) ;
newblk - > hashval = xfs_dir2_leaf_lasthash ( dp , newblk - > bp , NULL ) ;
2013-10-29 15:11:50 +04:00
xfs_dir3_leaf_check ( dp , oldblk - > bp ) ;
xfs_dir3_leaf_check ( dp , newblk - > bp ) ;
2005-04-17 02:20:36 +04:00
return error ;
}
/*
* Check a leaf block and its neighbors to see if the block should be
* collapsed into one or the other neighbor . Always keep the block
* with the smaller block number .
* If the current block is over 50 % full , don ' t try to join it , return 0.
* If the block is empty , fill in the state structure and return 2.
* If it can be collapsed , fill in the state structure and return 1.
* If nothing can be done , return 0.
*/
int /* error */
xfs_dir2_leafn_toosmall (
xfs_da_state_t * state , /* btree cursor */
int * action ) /* resulting action to take */
{
xfs_da_state_blk_t * blk ; /* leaf block */
xfs_dablk_t blkno ; /* leaf block number */
2012-06-22 12:50:14 +04:00
struct xfs_buf * bp ; /* leaf buffer */
2005-04-17 02:20:36 +04:00
int bytes ; /* bytes in use */
int count ; /* leaf live entry count */
int error ; /* error return value */
int forward ; /* sibling block direction */
int i ; /* sibling counter */
xfs_dir2_leaf_t * leaf ; /* leaf structure */
int rval ; /* result from path_shift */
2013-04-12 01:30:21 +04:00
struct xfs_dir3_icleaf_hdr leafhdr ;
struct xfs_dir2_leaf_entry * ents ;
2013-10-29 15:11:50 +04:00
struct xfs_inode * dp = state - > args - > dp ;
2005-04-17 02:20:36 +04:00
/*
* Check for the degenerate case of the block being over 50 % full .
* If so , it ' s not worth even looking to see if we might be able
* to coalesce with a sibling .
*/
blk = & state - > path . blk [ state - > path . active - 1 ] ;
2013-04-12 01:30:21 +04:00
leaf = blk - > bp - > b_addr ;
2013-10-29 15:11:52 +04:00
dp - > d_ops - > leaf_hdr_from_disk ( & leafhdr , leaf ) ;
2013-10-29 15:11:50 +04:00
ents = dp - > d_ops - > leaf_ents_p ( leaf ) ;
xfs_dir3_leaf_check ( dp , blk - > bp ) ;
2013-04-12 01:30:21 +04:00
count = leafhdr . count - leafhdr . stale ;
2013-10-30 02:15:02 +04:00
bytes = dp - > d_ops - > leaf_hdr_size + count * sizeof ( ents [ 0 ] ) ;
2014-06-06 09:22:04 +04:00
if ( bytes > ( state - > args - > geo - > blksize > > 1 ) ) {
2005-04-17 02:20:36 +04:00
/*
* Blk over 50 % , don ' t try to join .
*/
* action = 0 ;
return 0 ;
}
/*
* Check for the degenerate case of the block being empty .
* If the block is empty , we ' ll simply delete it , no need to
* coalesce it with a sibling block . We choose ( arbitrarily )
* to merge with the forward block unless it is NULL .
*/
if ( count = = 0 ) {
/*
* Make altpath point to the block we want to keep and
* path point to the block we want to drop ( this one ) .
*/
2013-04-12 01:30:21 +04:00
forward = ( leafhdr . forw ! = 0 ) ;
2005-04-17 02:20:36 +04:00
memcpy ( & state - > altpath , & state - > path , sizeof ( state - > path ) ) ;
2013-04-24 12:58:02 +04:00
error = xfs_da3_path_shift ( state , & state - > altpath , forward , 0 ,
2005-04-17 02:20:36 +04:00
& rval ) ;
if ( error )
return error ;
* action = rval ? 2 : 0 ;
return 0 ;
}
/*
* Examine each sibling block to see if we can coalesce with
* at least 25 % free space to spare . We need to figure out
* whether to merge with the forward or the backward block .
* We prefer coalescing with the lower numbered sibling so as
* to shrink a directory over time .
*/
2013-04-12 01:30:21 +04:00
forward = leafhdr . forw < leafhdr . back ;
2005-04-17 02:20:36 +04:00
for ( i = 0 , bp = NULL ; i < 2 ; forward = ! forward , i + + ) {
2013-04-12 01:30:21 +04:00
struct xfs_dir3_icleaf_hdr hdr2 ;
blkno = forward ? leafhdr . forw : leafhdr . back ;
2005-04-17 02:20:36 +04:00
if ( blkno = = 0 )
continue ;
/*
* Read the sibling leaf block .
*/
2013-10-29 15:11:50 +04:00
error = xfs_dir3_leafn_read ( state - > args - > trans , dp ,
2012-11-12 15:54:15 +04:00
blkno , - 1 , & bp ) ;
2012-11-12 15:54:10 +04:00
if ( error )
2005-04-17 02:20:36 +04:00
return error ;
2012-11-12 15:54:15 +04:00
2005-04-17 02:20:36 +04:00
/*
* Count bytes in the two blocks combined .
*/
2013-04-12 01:30:21 +04:00
count = leafhdr . count - leafhdr . stale ;
2014-06-06 09:22:04 +04:00
bytes = state - > args - > geo - > blksize -
( state - > args - > geo - > blksize > > 2 ) ;
2013-04-12 01:30:21 +04:00
2012-06-22 12:50:14 +04:00
leaf = bp - > b_addr ;
2013-10-29 15:11:52 +04:00
dp - > d_ops - > leaf_hdr_from_disk ( & hdr2 , leaf ) ;
2013-10-29 15:11:50 +04:00
ents = dp - > d_ops - > leaf_ents_p ( leaf ) ;
2013-04-12 01:30:21 +04:00
count + = hdr2 . count - hdr2 . stale ;
bytes - = count * sizeof ( ents [ 0 ] ) ;
2005-04-17 02:20:36 +04:00
/*
* Fits with at least 25 % to spare .
*/
if ( bytes > = 0 )
break ;
2012-06-22 12:50:14 +04:00
xfs_trans_brelse ( state - > args - > trans , bp ) ;
2005-04-17 02:20:36 +04:00
}
/*
* Didn ' t like either block , give up .
*/
if ( i > = 2 ) {
* action = 0 ;
return 0 ;
}
2012-06-22 12:50:14 +04:00
2005-04-17 02:20:36 +04:00
/*
* Make altpath point to the block we want to keep ( the lower
* numbered block ) and path point to the block we want to drop .
*/
memcpy ( & state - > altpath , & state - > path , sizeof ( state - > path ) ) ;
if ( blkno < blk - > blkno )
2013-04-24 12:58:02 +04:00
error = xfs_da3_path_shift ( state , & state - > altpath , forward , 0 ,
2005-04-17 02:20:36 +04:00
& rval ) ;
else
2013-04-24 12:58:02 +04:00
error = xfs_da3_path_shift ( state , & state - > path , forward , 0 ,
2005-04-17 02:20:36 +04:00
& rval ) ;
if ( error ) {
return error ;
}
* action = rval ? 0 : 1 ;
return 0 ;
}
/*
* Move all the leaf entries from drop_blk to save_blk .
* This is done as part of a join operation .
*/
void
xfs_dir2_leafn_unbalance (
xfs_da_state_t * state , /* cursor */
xfs_da_state_blk_t * drop_blk , /* dead block */
xfs_da_state_blk_t * save_blk ) /* surviving block */
{
xfs_da_args_t * args ; /* operation arguments */
xfs_dir2_leaf_t * drop_leaf ; /* dead leaf structure */
xfs_dir2_leaf_t * save_leaf ; /* surviving leaf structure */
2013-04-12 01:30:21 +04:00
struct xfs_dir3_icleaf_hdr savehdr ;
struct xfs_dir3_icleaf_hdr drophdr ;
struct xfs_dir2_leaf_entry * sents ;
struct xfs_dir2_leaf_entry * dents ;
2013-10-29 15:11:50 +04:00
struct xfs_inode * dp = state - > args - > dp ;
2005-04-17 02:20:36 +04:00
args = state - > args ;
ASSERT ( drop_blk - > magic = = XFS_DIR2_LEAFN_MAGIC ) ;
ASSERT ( save_blk - > magic = = XFS_DIR2_LEAFN_MAGIC ) ;
2012-06-22 12:50:14 +04:00
drop_leaf = drop_blk - > bp - > b_addr ;
save_leaf = save_blk - > bp - > b_addr ;
2013-04-12 01:30:21 +04:00
2013-10-29 15:11:52 +04:00
dp - > d_ops - > leaf_hdr_from_disk ( & savehdr , save_leaf ) ;
dp - > d_ops - > leaf_hdr_from_disk ( & drophdr , drop_leaf ) ;
sents = dp - > d_ops - > leaf_ents_p ( save_leaf ) ;
dents = dp - > d_ops - > leaf_ents_p ( drop_leaf ) ;
2013-04-12 01:30:21 +04:00
2005-04-17 02:20:36 +04:00
/*
* If there are any stale leaf entries , take this opportunity
* to purge them .
*/
2013-04-12 01:30:21 +04:00
if ( drophdr . stale )
xfs_dir3_leaf_compact ( args , & drophdr , drop_blk - > bp ) ;
if ( savehdr . stale )
xfs_dir3_leaf_compact ( args , & savehdr , save_blk - > bp ) ;
2005-04-17 02:20:36 +04:00
/*
* Move the entries from drop to the appropriate end of save .
*/
2013-04-12 01:30:21 +04:00
drop_blk - > hashval = be32_to_cpu ( dents [ drophdr . count - 1 ] . hashval ) ;
2013-10-29 15:11:50 +04:00
if ( xfs_dir2_leafn_order ( dp , save_blk - > bp , drop_blk - > bp ) )
2013-04-12 01:30:21 +04:00
xfs_dir3_leafn_moveents ( args , drop_blk - > bp , & drophdr , dents , 0 ,
save_blk - > bp , & savehdr , sents , 0 ,
drophdr . count ) ;
2005-04-17 02:20:36 +04:00
else
2013-04-12 01:30:21 +04:00
xfs_dir3_leafn_moveents ( args , drop_blk - > bp , & drophdr , dents , 0 ,
save_blk - > bp , & savehdr , sents ,
savehdr . count , drophdr . count ) ;
save_blk - > hashval = be32_to_cpu ( sents [ savehdr . count - 1 ] . hashval ) ;
/* log the changes made when moving the entries */
2013-10-29 15:11:52 +04:00
dp - > d_ops - > leaf_hdr_to_disk ( save_leaf , & savehdr ) ;
dp - > d_ops - > leaf_hdr_to_disk ( drop_leaf , & drophdr ) ;
2014-06-06 09:20:54 +04:00
xfs_dir3_leaf_log_header ( args , save_blk - > bp ) ;
xfs_dir3_leaf_log_header ( args , drop_blk - > bp ) ;
2013-04-12 01:30:21 +04:00
2013-10-29 15:11:50 +04:00
xfs_dir3_leaf_check ( dp , save_blk - > bp ) ;
xfs_dir3_leaf_check ( dp , drop_blk - > bp ) ;
2005-04-17 02:20:36 +04:00
}
/*
* Top - level node form directory addname routine .
*/
int /* error */
xfs_dir2_node_addname (
xfs_da_args_t * args ) /* operation arguments */
{
xfs_da_state_blk_t * blk ; /* leaf block for insert */
int error ; /* error return value */
int rval ; /* sub-return value */
xfs_da_state_t * state ; /* btree cursor */
2009-12-15 02:14:59 +03:00
trace_xfs_dir2_node_addname ( args ) ;
2005-04-17 02:20:36 +04:00
/*
* Allocate and initialize the state ( btree cursor ) .
*/
state = xfs_da_state_alloc ( ) ;
state - > args = args ;
state - > mp = args - > dp - > i_mount ;
/*
* Look up the name . We ' re not supposed to find it , but
* this gives us the insertion point .
*/
2013-04-24 12:58:02 +04:00
error = xfs_da3_node_lookup_int ( state , & rval ) ;
2005-04-17 02:20:36 +04:00
if ( error )
rval = error ;
2014-06-25 08:58:08 +04:00
if ( rval ! = - ENOENT ) {
2005-04-17 02:20:36 +04:00
goto done ;
}
/*
* Add the data entry to a data block .
* Extravalid is set to a freeblock found by lookup .
*/
rval = xfs_dir2_node_addname_int ( args ,
state - > extravalid ? & state - > extrablk : NULL ) ;
if ( rval ) {
goto done ;
}
blk = & state - > path . blk [ state - > path . active - 1 ] ;
ASSERT ( blk - > magic = = XFS_DIR2_LEAFN_MAGIC ) ;
/*
* Add the new leaf entry .
*/
rval = xfs_dir2_leafn_add ( blk - > bp , args , blk - > index ) ;
if ( rval = = 0 ) {
/*
* It worked , fix the hash values up the btree .
*/
2008-05-21 10:42:05 +04:00
if ( ! ( args - > op_flags & XFS_DA_OP_JUSTCHECK ) )
2013-04-24 12:58:02 +04:00
xfs_da3_fixhashpath ( state , & state - > path ) ;
2005-04-17 02:20:36 +04:00
} else {
/*
* It didn ' t work , we need to split the leaf block .
*/
if ( args - > total = = 0 ) {
2014-06-25 08:58:08 +04:00
ASSERT ( rval = = - ENOSPC ) ;
2005-04-17 02:20:36 +04:00
goto done ;
}
/*
* Split the leaf block and insert the new entry .
*/
2013-04-24 12:58:02 +04:00
rval = xfs_da3_split ( state ) ;
2005-04-17 02:20:36 +04:00
}
done :
xfs_da_state_free ( state ) ;
return rval ;
}
/*
* Add the data entry for a node - format directory name addition .
* The leaf entry is added in xfs_dir2_leafn_add .
* We may enter with a freespace block that the lookup found .
*/
static int /* error */
xfs_dir2_node_addname_int (
xfs_da_args_t * args , /* operation arguments */
xfs_da_state_blk_t * fblk ) /* optional freespace block */
{
2011-07-08 16:35:38 +04:00
xfs_dir2_data_hdr_t * hdr ; /* data block header */
2005-04-17 02:20:36 +04:00
xfs_dir2_db_t dbno ; /* data block number */
2012-06-22 12:50:14 +04:00
struct xfs_buf * dbp ; /* data block buffer */
2005-04-17 02:20:36 +04:00
xfs_dir2_data_entry_t * dep ; /* data entry pointer */
xfs_inode_t * dp ; /* incore directory inode */
xfs_dir2_data_unused_t * dup ; /* data unused entry pointer */
int error ; /* error return value */
xfs_dir2_db_t fbno ; /* freespace block number */
2012-06-22 12:50:14 +04:00
struct xfs_buf * fbp ; /* freespace buffer */
2005-04-17 02:20:36 +04:00
int findex ; /* freespace entry index */
xfs_dir2_free_t * free = NULL ; /* freespace block structure */
xfs_dir2_db_t ifbno ; /* initial freespace block no */
xfs_dir2_db_t lastfbno = 0 ; /* highest freespace block no */
int length ; /* length of the new entry */
int logfree ; /* need to log free entry */
xfs_mount_t * mp ; /* filesystem mount point */
int needlog ; /* need to log data header */
int needscan ; /* need to rescan data frees */
2006-03-17 09:28:27 +03:00
__be16 * tagp ; /* data entry tag pointer */
2005-04-17 02:20:36 +04:00
xfs_trans_t * tp ; /* transaction pointer */
2013-04-03 09:11:21 +04:00
__be16 * bests ;
struct xfs_dir3_icfree_hdr freehdr ;
2013-04-03 09:11:22 +04:00
struct xfs_dir2_data_free * bf ;
2018-03-23 20:06:51 +03:00
xfs_dir2_data_aoff_t aoff ;
2005-04-17 02:20:36 +04:00
dp = args - > dp ;
mp = dp - > i_mount ;
tp = args - > trans ;
2013-10-29 15:11:48 +04:00
length = dp - > d_ops - > data_entsize ( args - > namelen ) ;
2005-04-17 02:20:36 +04:00
/*
* If we came in with a freespace block that means that lookup
* found an entry with our hash value . This is the freespace
* block for that data entry .
*/
if ( fblk ) {
fbp = fblk - > bp ;
/*
* Remember initial freespace block number .
*/
ifbno = fblk - > blkno ;
2012-06-22 12:50:14 +04:00
free = fbp - > b_addr ;
2005-04-17 02:20:36 +04:00
findex = fblk - > index ;
2013-10-30 22:48:41 +04:00
bests = dp - > d_ops - > free_bests_p ( free ) ;
2013-10-29 15:11:52 +04:00
dp - > d_ops - > free_hdr_from_disk ( & freehdr , free ) ;
2013-04-03 09:11:21 +04:00
2005-04-17 02:20:36 +04:00
/*
* This means the free entry showed that the data block had
* space for our entry , so we remembered it .
* Use that data block .
*/
if ( findex > = 0 ) {
2013-04-03 09:11:21 +04:00
ASSERT ( findex < freehdr . nvalid ) ;
ASSERT ( be16_to_cpu ( bests [ findex ] ) ! = NULLDATAOFF ) ;
ASSERT ( be16_to_cpu ( bests [ findex ] ) > = length ) ;
dbno = freehdr . firstdb + findex ;
} else {
/*
* The data block looked at didn ' t have enough room .
* We ' ll start at the beginning of the freespace entries .
*/
2005-04-17 02:20:36 +04:00
dbno = - 1 ;
findex = 0 ;
}
2013-04-03 09:11:21 +04:00
} else {
/*
* Didn ' t come in with a freespace block , so no data block .
*/
2005-04-17 02:20:36 +04:00
ifbno = dbno = - 1 ;
fbp = NULL ;
findex = 0 ;
}
2013-04-03 09:11:21 +04:00
2005-04-17 02:20:36 +04:00
/*
* If we don ' t have a data block yet , we ' re going to scan the
* freespace blocks looking for one . Figure out what the
* highest freespace block number is .
*/
if ( dbno = = - 1 ) {
xfs_fileoff_t fo ; /* freespace block number */
2014-04-14 12:58:05 +04:00
if ( ( error = xfs_bmap_last_offset ( dp , & fo , XFS_DATA_FORK ) ) )
2005-04-17 02:20:36 +04:00
return error ;
2014-06-06 09:07:53 +04:00
lastfbno = xfs_dir2_da_to_db ( args - > geo , ( xfs_dablk_t ) fo ) ;
2005-04-17 02:20:36 +04:00
fbno = ifbno ;
}
/*
* While we haven ' t identified a data block , search the freeblock
* data for a good data block . If we find a null freeblock entry ,
* indicating a hole in the data blocks , remember that .
*/
while ( dbno = = - 1 ) {
/*
* If we don ' t have a freeblock in hand , get the next one .
*/
if ( fbp = = NULL ) {
/*
* Happens the first time through unless lookup gave
* us a freespace block to start with .
*/
if ( + + fbno = = 0 )
2014-06-06 09:08:18 +04:00
fbno = xfs_dir2_byte_to_db ( args - > geo ,
2014-06-06 09:04:41 +04:00
XFS_DIR2_FREE_OFFSET ) ;
2005-04-17 02:20:36 +04:00
/*
* If it ' s ifbno we already looked at it .
*/
if ( fbno = = ifbno )
fbno + + ;
/*
* If it ' s off the end we ' re done .
*/
if ( fbno > = lastfbno )
break ;
/*
* Read the block . There can be holes in the
* freespace blocks , so this might not succeed .
* This should be really rare , so there ' s no reason
* to avoid it .
*/
2012-11-12 15:54:13 +04:00
error = xfs_dir2_free_try_read ( tp , dp ,
2014-06-06 09:07:53 +04:00
xfs_dir2_db_to_da ( args - > geo , fbno ) ,
& fbp ) ;
2012-11-12 15:54:10 +04:00
if ( error )
2005-04-17 02:20:36 +04:00
return error ;
2012-11-12 15:54:10 +04:00
if ( ! fbp )
2005-04-17 02:20:36 +04:00
continue ;
2012-06-22 12:50:14 +04:00
free = fbp - > b_addr ;
2005-04-17 02:20:36 +04:00
findex = 0 ;
}
/*
* Look at the current free entry . Is it good enough ?
2013-04-03 09:11:21 +04:00
*
* The bests initialisation should be where the bufer is read in
* the above branch . But gcc is too stupid to realise that bests
* and the freehdr are actually initialised if they are placed
* there , so we have to do it here to avoid warnings . Blech .
2005-04-17 02:20:36 +04:00
*/
2013-10-30 22:48:41 +04:00
bests = dp - > d_ops - > free_bests_p ( free ) ;
2013-10-29 15:11:52 +04:00
dp - > d_ops - > free_hdr_from_disk ( & freehdr , free ) ;
2013-04-03 09:11:21 +04:00
if ( be16_to_cpu ( bests [ findex ] ) ! = NULLDATAOFF & &
be16_to_cpu ( bests [ findex ] ) > = length )
dbno = freehdr . firstdb + findex ;
2005-04-17 02:20:36 +04:00
else {
/*
* Are we done with the freeblock ?
*/
2013-04-03 09:11:21 +04:00
if ( + + findex = = freehdr . nvalid ) {
2005-04-17 02:20:36 +04:00
/*
* Drop the block .
*/
2012-06-22 12:50:14 +04:00
xfs_trans_brelse ( tp , fbp ) ;
2005-04-17 02:20:36 +04:00
fbp = NULL ;
if ( fblk & & fblk - > bp )
fblk - > bp = NULL ;
}
}
}
/*
* If we don ' t have a data block , we need to allocate one and make
* the freespace entries refer to it .
*/
if ( unlikely ( dbno = = - 1 ) ) {
/*
* Not allowed to allocate , return failure .
*/
2012-06-22 12:50:14 +04:00
if ( ( args - > op_flags & XFS_DA_OP_JUSTCHECK ) | | args - > total = = 0 )
2014-06-25 08:58:08 +04:00
return - ENOSPC ;
2012-06-22 12:50:14 +04:00
2005-04-17 02:20:36 +04:00
/*
* Allocate and initialize the new data block .
*/
if ( unlikely ( ( error = xfs_dir2_grow_inode ( args ,
XFS_DIR2_DATA_SPACE ,
& dbno ) ) | |
2013-04-03 09:11:20 +04:00
( error = xfs_dir3_data_init ( args , dbno , & dbp ) ) ) )
2005-04-17 02:20:36 +04:00
return error ;
2012-06-22 12:50:14 +04:00
2005-04-17 02:20:36 +04:00
/*
* If ( somehow ) we have a freespace block , get rid of it .
*/
if ( fbp )
2012-06-22 12:50:14 +04:00
xfs_trans_brelse ( tp , fbp ) ;
2005-04-17 02:20:36 +04:00
if ( fblk & & fblk - > bp )
fblk - > bp = NULL ;
/*
* Get the freespace block corresponding to the data block
* that was just allocated .
*/
2014-06-06 09:15:59 +04:00
fbno = dp - > d_ops - > db_to_fdb ( args - > geo , dbno ) ;
2012-11-12 15:54:13 +04:00
error = xfs_dir2_free_try_read ( tp , dp ,
2014-06-06 09:07:53 +04:00
xfs_dir2_db_to_da ( args - > geo , fbno ) ,
& fbp ) ;
2012-11-12 15:54:10 +04:00
if ( error )
2005-04-17 02:20:36 +04:00
return error ;
2012-06-22 12:50:14 +04:00
2005-04-17 02:20:36 +04:00
/*
* If there wasn ' t a freespace block , the read will
* return a NULL fbp . Allocate and initialize a new one .
*/
2013-04-03 09:11:21 +04:00
if ( ! fbp ) {
error = xfs_dir2_grow_inode ( args , XFS_DIR2_FREE_SPACE ,
& fbno ) ;
if ( error )
2005-04-17 02:20:36 +04:00
return error ;
2014-06-06 09:15:59 +04:00
if ( dp - > d_ops - > db_to_fdb ( args - > geo , dbno ) ! = fbno ) {
2011-03-07 02:08:35 +03:00
xfs_alert ( mp ,
2015-07-29 04:52:04 +03:00
" %s: dir ino %llu needed freesp block %lld for data block %lld, got %lld ifbno %llu lastfbno %d " ,
2011-03-07 02:08:35 +03:00
__func__ , ( unsigned long long ) dp - > i_ino ,
2014-06-06 09:15:59 +04:00
( long long ) dp - > d_ops - > db_to_fdb (
args - > geo , dbno ) ,
2005-04-17 02:20:36 +04:00
( long long ) dbno , ( long long ) fbno ,
( unsigned long long ) ifbno , lastfbno ) ;
if ( fblk ) {
2011-03-07 02:08:35 +03:00
xfs_alert ( mp ,
2018-01-09 23:02:55 +03:00
" fblk " PTR_FMT " blkno %llu index %d magic 0x%x " ,
2005-04-17 02:20:36 +04:00
fblk ,
( unsigned long long ) fblk - > blkno ,
fblk - > index ,
fblk - > magic ) ;
} else {
2011-03-07 02:08:35 +03:00
xfs_alert ( mp , " ... fblk is NULL " ) ;
2005-04-17 02:20:36 +04:00
}
XFS_ERROR_REPORT ( " xfs_dir2_node_addname_int " ,
XFS_ERRLEVEL_LOW , mp ) ;
2014-06-25 08:58:08 +04:00
return - EFSCORRUPTED ;
2005-04-17 02:20:36 +04:00
}
/*
* Get a buffer for the new block .
*/
2014-06-06 09:07:53 +04:00
error = xfs_dir3_free_get_buf ( args , fbno , & fbp ) ;
2012-11-14 10:53:49 +04:00
if ( error )
2005-04-17 02:20:36 +04:00
return error ;
2013-04-03 09:11:21 +04:00
free = fbp - > b_addr ;
2013-10-30 22:48:41 +04:00
bests = dp - > d_ops - > free_bests_p ( free ) ;
2013-10-29 15:11:52 +04:00
dp - > d_ops - > free_hdr_from_disk ( & freehdr , free ) ;
2005-04-17 02:20:36 +04:00
/*
2013-04-03 09:11:21 +04:00
* Remember the first slot as our empty slot .
2005-04-17 02:20:36 +04:00
*/
2014-06-06 09:04:41 +04:00
freehdr . firstdb =
2014-06-06 09:08:18 +04:00
( fbno - xfs_dir2_byte_to_db ( args - > geo ,
2014-06-06 09:04:41 +04:00
XFS_DIR2_FREE_OFFSET ) ) *
2014-06-06 09:15:59 +04:00
dp - > d_ops - > free_max_bests ( args - > geo ) ;
2005-04-17 02:20:36 +04:00
} else {
2012-06-22 12:50:14 +04:00
free = fbp - > b_addr ;
2013-10-30 22:48:41 +04:00
bests = dp - > d_ops - > free_bests_p ( free ) ;
2013-10-29 15:11:52 +04:00
dp - > d_ops - > free_hdr_from_disk ( & freehdr , free ) ;
2005-04-17 02:20:36 +04:00
}
/*
* Set the freespace block index from the data block number .
*/
2014-06-06 09:15:59 +04:00
findex = dp - > d_ops - > db_to_fdindex ( args - > geo , dbno ) ;
2005-04-17 02:20:36 +04:00
/*
* If it ' s after the end of the current entries in the
* freespace block , extend that table .
*/
2013-04-03 09:11:21 +04:00
if ( findex > = freehdr . nvalid ) {
2014-06-06 09:15:59 +04:00
ASSERT ( findex < dp - > d_ops - > free_max_bests ( args - > geo ) ) ;
2013-04-03 09:11:21 +04:00
freehdr . nvalid = findex + 1 ;
2005-04-17 02:20:36 +04:00
/*
* Tag new entry so nused will go up .
*/
2013-04-03 09:11:21 +04:00
bests [ findex ] = cpu_to_be16 ( NULLDATAOFF ) ;
2005-04-17 02:20:36 +04:00
}
/*
* If this entry was for an empty data block
* ( this should always be true ) then update the header .
*/
2013-04-03 09:11:21 +04:00
if ( bests [ findex ] = = cpu_to_be16 ( NULLDATAOFF ) ) {
freehdr . nused + + ;
2013-10-29 15:11:52 +04:00
dp - > d_ops - > free_hdr_to_disk ( fbp - > b_addr , & freehdr ) ;
2014-06-06 09:20:54 +04:00
xfs_dir2_free_log_header ( args , fbp ) ;
2005-04-17 02:20:36 +04:00
}
/*
* Update the real value in the table .
* We haven ' t allocated the data entry yet so this will
* change again .
*/
2012-06-22 12:50:14 +04:00
hdr = dbp - > b_addr ;
2013-10-29 15:11:49 +04:00
bf = dp - > d_ops - > data_bestfree_p ( hdr ) ;
2013-04-03 09:11:22 +04:00
bests [ findex ] = bf [ 0 ] . length ;
2005-04-17 02:20:36 +04:00
logfree = 1 ;
}
/*
* We had a data block so we don ' t have to make a new one .
*/
else {
/*
* If just checking , we succeeded .
*/
2012-06-22 12:50:14 +04:00
if ( args - > op_flags & XFS_DA_OP_JUSTCHECK )
2005-04-17 02:20:36 +04:00
return 0 ;
2012-06-22 12:50:14 +04:00
2005-04-17 02:20:36 +04:00
/*
* Read the data block in .
*/
2014-06-06 09:07:53 +04:00
error = xfs_dir3_data_read ( tp , dp ,
xfs_dir2_db_to_da ( args - > geo , dbno ) ,
2012-11-12 15:54:14 +04:00
- 1 , & dbp ) ;
2012-06-22 12:50:14 +04:00
if ( error )
2005-04-17 02:20:36 +04:00
return error ;
2012-06-22 12:50:14 +04:00
hdr = dbp - > b_addr ;
2013-10-29 15:11:49 +04:00
bf = dp - > d_ops - > data_bestfree_p ( hdr ) ;
2005-04-17 02:20:36 +04:00
logfree = 0 ;
}
2013-04-03 09:11:22 +04:00
ASSERT ( be16_to_cpu ( bf [ 0 ] . length ) > = length ) ;
2005-04-17 02:20:36 +04:00
/*
* Point to the existing unused space .
*/
dup = ( xfs_dir2_data_unused_t * )
2013-04-03 09:11:22 +04:00
( ( char * ) hdr + be16_to_cpu ( bf [ 0 ] . offset ) ) ;
2005-04-17 02:20:36 +04:00
needscan = needlog = 0 ;
/*
* Mark the first part of the unused space , inuse for us .
*/
2018-03-23 20:06:51 +03:00
aoff = ( xfs_dir2_data_aoff_t ) ( ( char * ) dup - ( char * ) hdr ) ;
error = xfs_dir2_data_use_free ( args , dbp , dup , aoff , length ,
& needlog , & needscan ) ;
if ( error ) {
xfs_trans_brelse ( tp , dbp ) ;
return error ;
}
2005-04-17 02:20:36 +04:00
/*
* Fill in the new entry and log it .
*/
dep = ( xfs_dir2_data_entry_t * ) dup ;
2006-06-09 08:48:37 +04:00
dep - > inumber = cpu_to_be64 ( args - > inumber ) ;
2005-04-17 02:20:36 +04:00
dep - > namelen = args - > namelen ;
memcpy ( dep - > name , args - > name , dep - > namelen ) ;
2013-10-29 15:11:48 +04:00
dp - > d_ops - > data_put_ftype ( dep , args - > filetype ) ;
tagp = dp - > d_ops - > data_entry_tag_p ( dep ) ;
2011-07-08 16:35:38 +04:00
* tagp = cpu_to_be16 ( ( char * ) dep - ( char * ) hdr ) ;
2014-06-06 09:20:54 +04:00
xfs_dir2_data_log_entry ( args , dbp , dep ) ;
2005-04-17 02:20:36 +04:00
/*
* Rescan the block for bestfree if needed .
*/
if ( needscan )
2013-10-29 15:11:48 +04:00
xfs_dir2_data_freescan ( dp , hdr , & needlog ) ;
2005-04-17 02:20:36 +04:00
/*
* Log the data block header if needed .
*/
if ( needlog )
2014-06-06 09:20:54 +04:00
xfs_dir2_data_log_header ( args , dbp ) ;
2005-04-17 02:20:36 +04:00
/*
* If the freespace entry is now wrong , update it .
*/
2013-10-30 22:48:41 +04:00
bests = dp - > d_ops - > free_bests_p ( free ) ; /* gcc is so stupid */
2013-04-03 09:11:22 +04:00
if ( be16_to_cpu ( bests [ findex ] ) ! = be16_to_cpu ( bf [ 0 ] . length ) ) {
bests [ findex ] = bf [ 0 ] . length ;
2005-04-17 02:20:36 +04:00
logfree = 1 ;
}
/*
* Log the freespace entry if needed .
*/
if ( logfree )
2014-06-06 09:20:54 +04:00
xfs_dir2_free_log_bests ( args , fbp , findex , findex ) ;
2005-04-17 02:20:36 +04:00
/*
* Return the data block and offset in args , then drop the data block .
*/
args - > blkno = ( xfs_dablk_t ) dbno ;
2006-03-17 09:28:27 +03:00
args - > index = be16_to_cpu ( * tagp ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
/*
* Lookup an entry in a node - format directory .
2013-04-24 12:58:02 +04:00
* All the real work happens in xfs_da3_node_lookup_int .
2005-04-17 02:20:36 +04:00
* The only real output is the inode number of the entry .
*/
int /* error */
xfs_dir2_node_lookup (
xfs_da_args_t * args ) /* operation arguments */
{
int error ; /* error return value */
int i ; /* btree level */
int rval ; /* operation return value */
xfs_da_state_t * state ; /* btree cursor */
2009-12-15 02:14:59 +03:00
trace_xfs_dir2_node_lookup ( args ) ;
2005-04-17 02:20:36 +04:00
/*
* Allocate and initialize the btree cursor .
*/
state = xfs_da_state_alloc ( ) ;
state - > args = args ;
state - > mp = args - > dp - > i_mount ;
/*
* Fill in the path to the entry in the cursor .
*/
2013-04-24 12:58:02 +04:00
error = xfs_da3_node_lookup_int ( state , & rval ) ;
2005-04-17 02:20:36 +04:00
if ( error )
rval = error ;
2014-06-25 08:58:08 +04:00
else if ( rval = = - ENOENT & & args - > cmpresult = = XFS_CMP_CASE ) {
/* If a CI match, dup the actual name and return -EEXIST */
2008-05-21 10:58:22 +04:00
xfs_dir2_data_entry_t * dep ;
2012-06-22 12:50:14 +04:00
dep = ( xfs_dir2_data_entry_t * )
( ( char * ) state - > extrablk . bp - > b_addr +
state - > extrablk . index ) ;
2008-05-21 10:58:22 +04:00
rval = xfs_dir_cilookup_result ( args , dep - > name , dep - > namelen ) ;
}
2005-04-17 02:20:36 +04:00
/*
* Release the btree blocks and leaf block .
*/
for ( i = 0 ; i < state - > path . active ; i + + ) {
2012-06-22 12:50:14 +04:00
xfs_trans_brelse ( args - > trans , state - > path . blk [ i ] . bp ) ;
2005-04-17 02:20:36 +04:00
state - > path . blk [ i ] . bp = NULL ;
}
/*
* Release the data block if we have it .
*/
if ( state - > extravalid & & state - > extrablk . bp ) {
2012-06-22 12:50:14 +04:00
xfs_trans_brelse ( args - > trans , state - > extrablk . bp ) ;
2005-04-17 02:20:36 +04:00
state - > extrablk . bp = NULL ;
}
xfs_da_state_free ( state ) ;
return rval ;
}
/*
* Remove an entry from a node - format directory .
*/
int /* error */
xfs_dir2_node_removename (
2013-10-06 06:48:25 +04:00
struct xfs_da_args * args ) /* operation arguments */
2005-04-17 02:20:36 +04:00
{
2013-10-06 06:48:25 +04:00
struct xfs_da_state_blk * blk ; /* leaf block */
2005-04-17 02:20:36 +04:00
int error ; /* error return value */
int rval ; /* operation return value */
2013-10-06 06:48:25 +04:00
struct xfs_da_state * state ; /* btree cursor */
2005-04-17 02:20:36 +04:00
2009-12-15 02:14:59 +03:00
trace_xfs_dir2_node_removename ( args ) ;
2005-04-17 02:20:36 +04:00
/*
* Allocate and initialize the btree cursor .
*/
state = xfs_da_state_alloc ( ) ;
state - > args = args ;
state - > mp = args - > dp - > i_mount ;
2013-10-06 06:48:25 +04:00
/* Look up the entry we're deleting, set up the cursor. */
2013-04-24 12:58:02 +04:00
error = xfs_da3_node_lookup_int ( state , & rval ) ;
2008-05-21 10:41:01 +04:00
if ( error )
2013-10-06 06:48:25 +04:00
goto out_free ;
/* Didn't find it, upper layer screwed up. */
2014-06-25 08:58:08 +04:00
if ( rval ! = - EEXIST ) {
2013-10-06 06:48:25 +04:00
error = rval ;
goto out_free ;
2005-04-17 02:20:36 +04:00
}
2013-10-06 06:48:25 +04:00
2005-04-17 02:20:36 +04:00
blk = & state - > path . blk [ state - > path . active - 1 ] ;
ASSERT ( blk - > magic = = XFS_DIR2_LEAFN_MAGIC ) ;
ASSERT ( state - > extravalid ) ;
/*
* Remove the leaf and data entries .
* Extrablk refers to the data block .
*/
error = xfs_dir2_leafn_remove ( args , blk - > bp , blk - > index ,
& state - > extrablk , & rval ) ;
2008-05-21 10:41:01 +04:00
if ( error )
2013-10-06 06:48:25 +04:00
goto out_free ;
2005-04-17 02:20:36 +04:00
/*
* Fix the hash values up the btree .
*/
2013-04-24 12:58:02 +04:00
xfs_da3_fixhashpath ( state , & state - > path ) ;
2005-04-17 02:20:36 +04:00
/*
* If we need to join leaf blocks , do it .
*/
if ( rval & & state - > path . active > 1 )
2013-04-24 12:58:02 +04:00
error = xfs_da3_join ( state ) ;
2005-04-17 02:20:36 +04:00
/*
* If no errors so far , try conversion to leaf format .
*/
if ( ! error )
error = xfs_dir2_node_to_leaf ( state ) ;
2013-10-06 06:48:25 +04:00
out_free :
2005-04-17 02:20:36 +04:00
xfs_da_state_free ( state ) ;
return error ;
}
/*
* Replace an entry ' s inode number in a node - format directory .
*/
int /* error */
xfs_dir2_node_replace (
xfs_da_args_t * args ) /* operation arguments */
{
xfs_da_state_blk_t * blk ; /* leaf block */
2011-07-08 16:35:38 +04:00
xfs_dir2_data_hdr_t * hdr ; /* data block header */
2005-04-17 02:20:36 +04:00
xfs_dir2_data_entry_t * dep ; /* data entry changed */
int error ; /* error return value */
int i ; /* btree level */
xfs_ino_t inum ; /* new inode number */
2015-08-25 03:05:13 +03:00
int ftype ; /* new file type */
2005-04-17 02:20:36 +04:00
xfs_dir2_leaf_t * leaf ; /* leaf structure */
xfs_dir2_leaf_entry_t * lep ; /* leaf entry being changed */
int rval ; /* internal return value */
xfs_da_state_t * state ; /* btree cursor */
2009-12-15 02:14:59 +03:00
trace_xfs_dir2_node_replace ( args ) ;
2005-04-17 02:20:36 +04:00
/*
* Allocate and initialize the btree cursor .
*/
state = xfs_da_state_alloc ( ) ;
state - > args = args ;
state - > mp = args - > dp - > i_mount ;
2015-08-25 03:05:13 +03:00
/*
* We have to save new inode number and ftype since
* xfs_da3_node_lookup_int ( ) is going to overwrite them
*/
2005-04-17 02:20:36 +04:00
inum = args - > inumber ;
2015-08-25 03:05:13 +03:00
ftype = args - > filetype ;
2005-04-17 02:20:36 +04:00
/*
* Lookup the entry to change in the btree .
*/
2013-04-24 12:58:02 +04:00
error = xfs_da3_node_lookup_int ( state , & rval ) ;
2005-04-17 02:20:36 +04:00
if ( error ) {
rval = error ;
}
/*
* It should be found , since the vnodeops layer has looked it up
* and locked it . But paranoia is good .
*/
2014-06-25 08:58:08 +04:00
if ( rval = = - EEXIST ) {
2013-04-12 01:30:21 +04:00
struct xfs_dir2_leaf_entry * ents ;
2005-04-17 02:20:36 +04:00
/*
* Find the leaf entry .
*/
blk = & state - > path . blk [ state - > path . active - 1 ] ;
ASSERT ( blk - > magic = = XFS_DIR2_LEAFN_MAGIC ) ;
2012-06-22 12:50:14 +04:00
leaf = blk - > bp - > b_addr ;
2013-10-29 15:11:50 +04:00
ents = args - > dp - > d_ops - > leaf_ents_p ( leaf ) ;
2013-04-12 01:30:21 +04:00
lep = & ents [ blk - > index ] ;
2005-04-17 02:20:36 +04:00
ASSERT ( state - > extravalid ) ;
/*
* Point to the data entry .
*/
2012-06-22 12:50:14 +04:00
hdr = state - > extrablk . bp - > b_addr ;
2013-04-03 09:11:22 +04:00
ASSERT ( hdr - > magic = = cpu_to_be32 ( XFS_DIR2_DATA_MAGIC ) | |
hdr - > magic = = cpu_to_be32 ( XFS_DIR3_DATA_MAGIC ) ) ;
2005-04-17 02:20:36 +04:00
dep = ( xfs_dir2_data_entry_t * )
2011-07-08 16:35:38 +04:00
( ( char * ) hdr +
2014-06-06 09:08:18 +04:00
xfs_dir2_dataptr_to_off ( args - > geo ,
be32_to_cpu ( lep - > address ) ) ) ;
2006-06-09 08:48:37 +04:00
ASSERT ( inum ! = be64_to_cpu ( dep - > inumber ) ) ;
2005-04-17 02:20:36 +04:00
/*
* Fill in the new inode number and log the entry .
*/
2006-06-09 08:48:37 +04:00
dep - > inumber = cpu_to_be64 ( inum ) ;
2015-08-25 03:05:13 +03:00
args - > dp - > d_ops - > data_put_ftype ( dep , ftype ) ;
2014-06-06 09:20:54 +04:00
xfs_dir2_data_log_entry ( args , state - > extrablk . bp , dep ) ;
2005-04-17 02:20:36 +04:00
rval = 0 ;
}
/*
* Didn ' t find it , and we ' re holding a data block . Drop it .
*/
else if ( state - > extravalid ) {
2012-06-22 12:50:14 +04:00
xfs_trans_brelse ( args - > trans , state - > extrablk . bp ) ;
2005-04-17 02:20:36 +04:00
state - > extrablk . bp = NULL ;
}
/*
* Release all the buffers in the cursor .
*/
for ( i = 0 ; i < state - > path . active ; i + + ) {
2012-06-22 12:50:14 +04:00
xfs_trans_brelse ( args - > trans , state - > path . blk [ i ] . bp ) ;
2005-04-17 02:20:36 +04:00
state - > path . blk [ i ] . bp = NULL ;
}
xfs_da_state_free ( state ) ;
return rval ;
}
/*
* Trim off a trailing empty freespace block .
* Return ( in rvalp ) 1 if we did it , 0 if not .
*/
int /* error */
xfs_dir2_node_trim_free (
xfs_da_args_t * args , /* operation arguments */
xfs_fileoff_t fo , /* free block number */
int * rvalp ) /* out: did something */
{
2012-06-22 12:50:14 +04:00
struct xfs_buf * bp ; /* freespace buffer */
2005-04-17 02:20:36 +04:00
xfs_inode_t * dp ; /* incore directory inode */
int error ; /* error return code */
xfs_dir2_free_t * free ; /* freespace structure */
xfs_trans_t * tp ; /* transaction pointer */
2013-04-03 09:11:21 +04:00
struct xfs_dir3_icfree_hdr freehdr ;
2005-04-17 02:20:36 +04:00
dp = args - > dp ;
tp = args - > trans ;
2016-03-15 03:44:18 +03:00
* rvalp = 0 ;
2005-04-17 02:20:36 +04:00
/*
* Read the freespace block .
*/
2012-11-12 15:54:13 +04:00
error = xfs_dir2_free_try_read ( tp , dp , fo , & bp ) ;
2012-11-12 15:54:10 +04:00
if ( error )
2005-04-17 02:20:36 +04:00
return error ;
/*
* There can be holes in freespace . If fo is a hole , there ' s
* nothing to do .
*/
2012-11-12 15:54:13 +04:00
if ( ! bp )
2005-04-17 02:20:36 +04:00
return 0 ;
2012-06-22 12:50:14 +04:00
free = bp - > b_addr ;
2013-10-29 15:11:52 +04:00
dp - > d_ops - > free_hdr_from_disk ( & freehdr , free ) ;
2013-04-03 09:11:21 +04:00
2005-04-17 02:20:36 +04:00
/*
* If there are used entries , there ' s nothing to do .
*/
2013-04-03 09:11:21 +04:00
if ( freehdr . nused > 0 ) {
2012-06-22 12:50:14 +04:00
xfs_trans_brelse ( tp , bp ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
/*
* Blow the block away .
*/
2014-06-06 09:07:53 +04:00
error = xfs_dir2_shrink_inode ( args ,
xfs_dir2_da_to_db ( args - > geo , ( xfs_dablk_t ) fo ) , bp ) ;
if ( error ) {
2005-04-17 02:20:36 +04:00
/*
* Can ' t fail with ENOSPC since that only happens with no
* space reservation , when breaking up an extent into two
* pieces . This is the last block of an extent .
*/
2014-06-25 08:58:08 +04:00
ASSERT ( error ! = - ENOSPC ) ;
2012-06-22 12:50:14 +04:00
xfs_trans_brelse ( tp , bp ) ;
2005-04-17 02:20:36 +04:00
return error ;
}
/*
* Return that we succeeded .
*/
* rvalp = 1 ;
return 0 ;
}