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 ) ;
2019-11-09 02:01:39 +03:00
/*
* Convert data space db to the corresponding free db .
*/
static xfs_dir2_db_t
xfs_dir2_db_to_fdb ( struct xfs_da_geometry * geo , xfs_dir2_db_t db )
{
return xfs_dir2_byte_to_db ( geo , XFS_DIR2_FREE_OFFSET ) +
( db / geo - > free_max_bests ) ;
}
/*
* Convert data space db to the corresponding index in a free db .
*/
static int
xfs_dir2_db_to_fdindex ( struct xfs_da_geometry * geo , xfs_dir2_db_t db )
{
return db % geo - > free_max_bests ;
}
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 ;
2019-11-09 01:57:49 +03:00
xfs_dir2_leaf_hdr_from_disk ( dp - > i_mount , & 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
2019-11-09 01:57:52 +03:00
return xfs_dir3_leaf_check_int ( dp - > i_mount , & 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 ;
2019-11-09 02:01:30 +03:00
int maxbests = mp - > m_dir_geo - > free_max_bests ;
2017-02-03 02:14:00 +03:00
unsigned int firstdb ;
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 ;
2020-03-11 20:37:56 +03:00
if ( be64_to_cpu ( hdr3 - > hdr . owner ) ! = dp - > i_ino )
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 ,
2019-11-20 20:46:04 +03:00
unsigned int flags ,
2012-11-12 15:54:13 +04:00
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 ;
2019-11-20 20:46:04 +03:00
err = xfs_da_read_buf ( tp , dp , fbno , flags , bpp , 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 ) {
2020-03-11 20:37:55 +03:00
__xfs_buf_mark_corrupt ( * bpp , fa ) ;
2017-02-03 02:14:00 +03:00
xfs_trans_brelse ( tp , * bpp ) ;
2020-03-11 20:37:55 +03:00
* bpp = NULL ;
2017-02-03 02:14:00 +03:00
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
}
2019-11-09 01:57:52 +03:00
void
xfs_dir2_free_hdr_from_disk (
struct xfs_mount * mp ,
struct xfs_dir3_icfree_hdr * to ,
struct xfs_dir2_free * from )
{
if ( xfs_sb_version_hascrc ( & mp - > m_sb ) ) {
struct xfs_dir3_free * from3 = ( struct xfs_dir3_free * ) from ;
to - > magic = be32_to_cpu ( from3 - > hdr . hdr . magic ) ;
to - > firstdb = be32_to_cpu ( from3 - > hdr . firstdb ) ;
to - > nvalid = be32_to_cpu ( from3 - > hdr . nvalid ) ;
to - > nused = be32_to_cpu ( from3 - > hdr . nused ) ;
2019-11-09 01:58:05 +03:00
to - > bests = from3 - > bests ;
2019-11-09 01:57:52 +03:00
ASSERT ( to - > magic = = XFS_DIR3_FREE_MAGIC ) ;
} else {
to - > magic = be32_to_cpu ( from - > hdr . magic ) ;
to - > firstdb = be32_to_cpu ( from - > hdr . firstdb ) ;
to - > nvalid = be32_to_cpu ( from - > hdr . nvalid ) ;
to - > nused = be32_to_cpu ( from - > hdr . nused ) ;
2019-11-09 01:58:05 +03:00
to - > bests = from - > bests ;
2019-11-09 01:57:52 +03:00
ASSERT ( to - > magic = = XFS_DIR2_FREE_MAGIC ) ;
}
}
2019-11-09 01:57:52 +03:00
static void
xfs_dir2_free_hdr_to_disk (
struct xfs_mount * mp ,
struct xfs_dir2_free * to ,
struct xfs_dir3_icfree_hdr * from )
{
if ( xfs_sb_version_hascrc ( & mp - > m_sb ) ) {
struct xfs_dir3_free * to3 = ( struct xfs_dir3_free * ) to ;
ASSERT ( from - > magic = = XFS_DIR3_FREE_MAGIC ) ;
to3 - > hdr . hdr . magic = cpu_to_be32 ( from - > magic ) ;
to3 - > hdr . firstdb = cpu_to_be32 ( from - > firstdb ) ;
to3 - > hdr . nvalid = cpu_to_be32 ( from - > nvalid ) ;
to3 - > hdr . nused = cpu_to_be32 ( from - > nused ) ;
} else {
ASSERT ( from - > magic = = XFS_DIR2_FREE_MAGIC ) ;
to - > hdr . magic = cpu_to_be32 ( from - > magic ) ;
to - > hdr . firstdb = cpu_to_be32 ( from - > firstdb ) ;
to - > hdr . nvalid = cpu_to_be32 ( from - > nvalid ) ;
to - > hdr . nused = cpu_to_be32 ( from - > nused ) ;
}
}
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 )
{
2019-11-20 20:46:04 +03:00
return __xfs_dir3_free_read ( tp , dp , fbno , 0 , 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 )
{
2019-11-20 20:46:04 +03:00
return __xfs_dir3_free_read ( tp , dp , fbno , XFS_DABUF_MAP_HOLE_OK , bpp ) ;
2013-04-03 09:11:21 +04:00
}
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 ) ,
2019-11-20 20:46:05 +03:00
& bp , XFS_DATA_FORK ) ;
2013-04-03 09:11:21 +04:00
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 ;
2019-11-09 01:57:52 +03:00
xfs_dir2_free_hdr_to_disk ( mp , 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 ,
2019-11-09 01:58:05 +03:00
struct xfs_dir3_icfree_hdr * hdr ,
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 */
{
2019-11-09 01:58:05 +03:00
struct xfs_dir2_free * free = bp - > b_addr ;
2005-04-17 02:20:36 +04:00
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 ,
2019-11-09 01:58:05 +03:00
( char * ) & hdr - > bests [ first ] - ( char * ) free ,
( char * ) & hdr - > bests [ last ] - ( char * ) free +
sizeof ( hdr - > 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 ,
2019-11-09 02:01:29 +03:00
args - > geo - > 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 */
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 */
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
2019-11-09 01:58:05 +03:00
xfs_dir2_free_hdr_from_disk ( dp - > i_mount , & freehdr , fbp - > b_addr ) ;
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 ) >
2019-11-02 19:40:53 +03:00
( uint ) dp - > i_d . di_size / args - > geo - > blksize ) {
2020-03-11 20:37:54 +03:00
xfs_buf_mark_corrupt ( lbp ) ;
2018-03-07 04:08:31 +03:00
return - EFSCORRUPTED ;
2019-11-02 19:40:53 +03:00
}
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 ) ;
2019-11-09 01:58:05 +03:00
for ( i = n = 0 ; i < be32_to_cpu ( ltp - > bestcount ) ; i + + , from + + ) {
off = be16_to_cpu ( * from ) ;
if ( off ! = NULLDATAOFF )
2005-04-17 02:20:36 +04:00
n + + ;
2019-11-09 01:58:05 +03:00
freehdr . bests [ i ] = 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 ) ;
2019-11-09 01:57:52 +03:00
xfs_dir2_free_hdr_to_disk ( dp - > i_mount , fbp - > b_addr , & freehdr ) ;
2019-11-09 01:58:05 +03:00
xfs_dir2_free_log_bests ( args , & freehdr , fbp , 0 , freehdr . nvalid - 1 ) ;
2014-06-06 09:20:54 +04:00
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 ) ;
2019-11-09 01:57:49 +03:00
xfs_dir2_leaf_hdr_from_disk ( dp - > i_mount , & leafhdr , leaf ) ;
2019-11-09 01:57:50 +03:00
ents = leafhdr . ents ;
2005-04-17 02:20:36 +04:00
/*
* Quick check just to make sure we are not going to index
* into other peoples memory
*/
2019-11-02 19:40:53 +03:00
if ( index < 0 ) {
2020-03-11 20:37:54 +03:00
xfs_buf_mark_corrupt ( bp ) ;
2014-06-25 08:58:08 +04:00
return - EFSCORRUPTED ;
2019-11-02 19:40:53 +03:00
}
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 .
*/
2019-11-09 01:57:51 +03:00
if ( leafhdr . count = = args - > geo - > leaf_max_ents ) {
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
2019-11-09 01:57:50 +03:00
xfs_dir2_leaf_hdr_to_disk ( dp - > i_mount , leaf , & leafhdr ) ;
2014-06-06 09:20:54 +04:00
xfs_dir3_leaf_log_header ( args , bp ) ;
2019-11-09 01:57:50 +03:00
xfs_dir3_leaf_log_ents ( args , & leafhdr , 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 ;
2019-11-09 01:57:52 +03:00
xfs_dir2_free_hdr_from_disk ( dp - > i_mount , & hdr , bp - > b_addr ) ;
2013-04-03 09:11:21 +04:00
2019-11-09 02:01:30 +03:00
ASSERT ( ( hdr . firstdb % dp - > i_mount - > m_dir_geo - > free_max_bests ) = = 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_dir3_icleaf_hdr leafhdr ;
2019-11-09 01:57:50 +03:00
xfs_dir2_leaf_hdr_from_disk ( dp - > i_mount , & leafhdr , bp - > b_addr ) ;
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 ;
2019-11-09 01:57:50 +03:00
return be32_to_cpu ( leafhdr . 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_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 ;
2019-11-09 01:57:49 +03:00
xfs_dir2_leaf_hdr_from_disk ( mp , & leafhdr , 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
}
2019-11-09 02:05:37 +03:00
length = xfs_dir2_data_entsize ( mp , args - > namelen ) ;
2005-04-17 02:20:36 +04:00
/*
* Loop over leaf entries with the right hash value .
*/
2019-11-09 01:57:50 +03:00
for ( lep = & leafhdr . ents [ index ] ;
2013-04-12 01:30:21 +04:00
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 ) {
2019-11-09 01:58:05 +03:00
struct xfs_dir3_icfree_hdr freehdr ;
2013-04-03 09:11:21 +04:00
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
*/
2019-11-09 02:01:39 +03:00
newfdb = xfs_dir2_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
*/
2019-11-09 02:01:39 +03:00
fi = xfs_dir2_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
*/
2019-11-09 01:58:05 +03:00
xfs_dir2_free_hdr_from_disk ( mp , & freehdr , free ) ;
2019-11-11 23:53:22 +03:00
if ( XFS_IS_CORRUPT ( mp ,
freehdr . bests [ fi ] = =
cpu_to_be16 ( NULLDATAOFF ) ) ) {
2008-04-17 10:49:43 +04:00
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 ;
2019-11-09 01:58:05 +03:00
if ( be16_to_cpu ( freehdr . 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_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 ;
2019-11-09 01:57:49 +03:00
xfs_dir2_leaf_hdr_from_disk ( mp , & leafhdr , leaf ) ;
2013-04-12 01:30:21 +04:00
2013-10-29 15:11:50 +04:00
xfs_dir3_leaf_check ( dp , bp ) ;
2019-11-02 19:40:53 +03:00
if ( leafhdr . count < = 0 ) {
2020-03-11 20:37:54 +03:00
xfs_buf_mark_corrupt ( bp ) ;
2019-08-12 01:52:26 +03:00
return - EFSCORRUPTED ;
2019-11-02 19:40:53 +03:00
}
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 .
*/
2019-11-09 01:57:50 +03:00
for ( lep = & leafhdr . ents [ index ] ;
2013-04-12 01:30:21 +04:00
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 ) ,
2019-11-20 20:46:04 +03:00
0 , & 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
*/
2019-11-11 23:59:26 +03:00
cmp = xfs_dir2_compname ( args , dep - > name , dep - > namelen ) ;
2008-05-21 10:41:01 +04:00
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 ) ;
2019-11-09 02:05:48 +03:00
args - > filetype = xfs_dir2_data_get_ftype ( mp , 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 ) ) ;
2019-11-09 01:57:50 +03:00
xfs_dir3_leaf_log_ents ( args , dhdr , 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 ) ) ;
2019-11-09 01:57:50 +03:00
xfs_dir3_leaf_log_ents ( args , dhdr , 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 ) ) ;
2019-11-09 01:57:50 +03:00
xfs_dir3_leaf_log_ents ( args , shdr , 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 ;
2019-11-09 01:57:49 +03:00
xfs_dir2_leaf_hdr_from_disk ( dp - > i_mount , & hdr1 , leaf1 ) ;
xfs_dir2_leaf_hdr_from_disk ( dp - > i_mount , & hdr2 , leaf2 ) ;
2019-11-09 01:57:50 +03:00
ents1 = hdr1 . ents ;
ents2 = hdr2 . ents ;
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 ;
2019-11-09 01:57:49 +03:00
xfs_dir2_leaf_hdr_from_disk ( dp - > i_mount , & hdr1 , leaf1 ) ;
xfs_dir2_leaf_hdr_from_disk ( dp - > i_mount , & hdr2 , leaf2 ) ;
2019-11-09 01:57:50 +03:00
ents1 = hdr1 . ents ;
ents2 = hdr2 . ents ;
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 */
2019-11-09 01:57:50 +03:00
xfs_dir2_leaf_hdr_to_disk ( dp - > i_mount , leaf1 , & hdr1 ) ;
xfs_dir2_leaf_hdr_to_disk ( dp - > i_mount , 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
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
2019-11-09 01:57:52 +03:00
xfs_dir2_free_hdr_from_disk ( dp - > i_mount , & freehdr , 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
*/
2019-11-09 01:58:05 +03:00
freehdr . bests [ findex ] = cpu_to_be16 ( longest ) ;
xfs_dir2_free_log_bests ( args , & freehdr , 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 - - ) {
2019-11-09 01:58:05 +03:00
if ( freehdr . bests [ i ] ! = cpu_to_be16 ( NULLDATAOFF ) )
2013-04-03 09:11:21 +04:00
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. */
2019-11-09 01:58:05 +03:00
freehdr . bests [ findex ] = cpu_to_be16 ( NULLDATAOFF ) ;
2013-04-03 09:11:21 +04:00
logfree = 1 ;
}
2019-11-09 01:57:52 +03:00
xfs_dir2_free_hdr_to_disk ( dp - > i_mount , 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 )
2019-11-09 01:58:05 +03:00
xfs_dir2_free_log_bests ( args , & freehdr , 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 */
{
2019-11-09 02:05:38 +03:00
struct xfs_da_geometry * geo = args - > geo ;
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 ;
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 ;
2019-11-09 01:57:49 +03:00
xfs_dir2_leaf_hdr_from_disk ( dp - > i_mount , & leafhdr , leaf ) ;
2013-04-12 01:30:21 +04:00
2005-04-17 02:20:36 +04:00
/*
* Point to the entry we ' re removing .
*/
2019-11-09 01:57:50 +03:00
lep = & leafhdr . ents [ index ] ;
2013-04-12 01:30:21 +04:00
2005-04-17 02:20:36 +04:00
/*
* Extract the data block and offset from the entry .
*/
2019-11-09 02:05:38 +03:00
db = xfs_dir2_dataptr_to_db ( geo , be32_to_cpu ( lep - > address ) ) ;
2005-04-17 02:20:36 +04:00
ASSERT ( dblk - > blkno = = db ) ;
2019-11-09 02:05:38 +03:00
off = xfs_dir2_dataptr_to_off ( 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 + + ;
2019-11-09 01:57:50 +03:00
xfs_dir2_leaf_hdr_to_disk ( dp - > i_mount , 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 ) ;
2019-11-09 01:57:50 +03:00
xfs_dir3_leaf_log_ents ( args , & leafhdr , 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 ) ;
2019-11-09 02:05:39 +03:00
bf = xfs_dir2_data_bestfree_p ( dp - > i_mount , 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 ,
2019-11-09 02:05:37 +03:00
xfs_dir2_data_entsize ( dp - > i_mount , 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 )
2019-11-09 02:06:02 +03:00
xfs_dir2_data_freescan ( dp - > i_mount , 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 .
*/
2019-11-09 02:05:38 +03:00
fdb = xfs_dir2_db_to_fdb ( geo , db ) ;
error = xfs_dir2_free_read ( tp , dp , xfs_dir2_db_to_da ( 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 ;
2019-11-09 01:57:52 +03:00
xfs_dir2_free_hdr_from_disk ( dp - > i_mount , & freehdr , free ) ;
2019-11-09 02:05:38 +03:00
ASSERT ( freehdr . firstdb = = geo - > free_max_bests *
( fdb - xfs_dir2_byte_to_db ( 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 .
*/
2019-11-09 02:05:38 +03:00
findex = xfs_dir2_db_to_fdindex ( 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 ) .
*/
2019-11-09 02:05:38 +03:00
if ( longest = = geo - > blksize - geo - > 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 .
*/
2019-11-09 02:05:38 +03:00
* rval = ( geo - > leaf_hdr_size +
2019-11-09 01:57:50 +03:00
( uint ) sizeof ( leafhdr . ents ) * ( leafhdr . count - leafhdr . stale ) ) <
2019-11-09 02:05:38 +03:00
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 ;
2019-11-09 01:57:49 +03:00
xfs_dir2_leaf_hdr_from_disk ( dp - > i_mount , & leafhdr , leaf ) ;
2019-11-09 01:57:50 +03:00
ents = leafhdr . ents ;
2013-10-29 15:11:50 +04:00
xfs_dir3_leaf_check ( dp , blk - > bp ) ;
2013-04-12 01:30:21 +04:00
count = leafhdr . count - leafhdr . stale ;
2019-11-09 01:57:51 +03:00
bytes = state - > args - > geo - > 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 .
*/
2019-11-20 20:46:03 +03:00
error = xfs_dir3_leafn_read ( state - > args - > trans , dp , blkno , & 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 ;
2019-11-09 01:57:49 +03:00
xfs_dir2_leaf_hdr_from_disk ( dp - > i_mount , & hdr2 , leaf ) ;
2019-11-09 01:57:50 +03:00
ents = hdr2 . ents ;
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
2019-11-09 01:57:49 +03:00
xfs_dir2_leaf_hdr_from_disk ( dp - > i_mount , & savehdr , save_leaf ) ;
xfs_dir2_leaf_hdr_from_disk ( dp - > i_mount , & drophdr , drop_leaf ) ;
2019-11-09 01:57:50 +03:00
sents = savehdr . ents ;
dents = drophdr . ents ;
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 */
2019-11-09 01:57:50 +03:00
xfs_dir2_leaf_hdr_to_disk ( dp - > i_mount , save_leaf , & savehdr ) ;
xfs_dir2_leaf_hdr_to_disk ( dp - > i_mount , 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
}
2019-08-29 19:04:06 +03:00
/*
* Add a new data block to the directory at the free space index that the caller
* has specified .
*/
static int
xfs_dir2_node_add_datablk (
struct xfs_da_args * args ,
struct xfs_da_state_blk * fblk ,
xfs_dir2_db_t * dbno ,
struct xfs_buf * * dbpp ,
struct xfs_buf * * fbpp ,
2019-11-09 01:57:53 +03:00
struct xfs_dir3_icfree_hdr * hdr ,
2019-08-29 19:04:06 +03:00
int * findex )
{
struct xfs_inode * dp = args - > dp ;
struct xfs_trans * tp = args - > trans ;
struct xfs_mount * mp = dp - > i_mount ;
struct xfs_dir2_data_free * bf ;
xfs_dir2_db_t fbno ;
struct xfs_buf * fbp ;
struct xfs_buf * dbp ;
int error ;
/* Not allowed to allocate, return failure. */
2019-08-29 19:04:07 +03:00
if ( args - > total = = 0 )
2019-08-29 19:04:06 +03:00
return - ENOSPC ;
/* Allocate and initialize the new data block. */
error = xfs_dir2_grow_inode ( args , XFS_DIR2_DATA_SPACE , dbno ) ;
if ( error )
return error ;
error = xfs_dir3_data_init ( args , * dbno , & dbp ) ;
if ( error )
return error ;
/*
* Get the freespace block corresponding to the data block
* that was just allocated .
*/
2019-11-09 02:01:39 +03:00
fbno = xfs_dir2_db_to_fdb ( args - > geo , * dbno ) ;
2019-08-29 19:04:06 +03:00
error = xfs_dir2_free_try_read ( tp , dp ,
xfs_dir2_db_to_da ( args - > geo , fbno ) , & fbp ) ;
if ( error )
return error ;
/*
* If there wasn ' t a freespace block , the read will
* return a NULL fbp . Allocate and initialize a new one .
*/
if ( ! fbp ) {
error = xfs_dir2_grow_inode ( args , XFS_DIR2_FREE_SPACE , & fbno ) ;
if ( error )
return error ;
2019-11-11 23:53:22 +03:00
if ( XFS_IS_CORRUPT ( mp ,
xfs_dir2_db_to_fdb ( args - > geo , * dbno ) ! =
fbno ) ) {
2019-08-29 19:04:06 +03:00
xfs_alert ( mp ,
" %s: dir ino %llu needed freesp block %lld for data block %lld, got %lld " ,
__func__ , ( unsigned long long ) dp - > i_ino ,
2019-11-09 02:01:39 +03:00
( long long ) xfs_dir2_db_to_fdb ( args - > geo , * dbno ) ,
2019-08-29 19:04:06 +03:00
( long long ) * dbno , ( long long ) fbno ) ;
if ( fblk ) {
xfs_alert ( mp ,
" fblk " PTR_FMT " blkno %llu index %d magic 0x%x " ,
fblk , ( unsigned long long ) fblk - > blkno ,
fblk - > index , fblk - > magic ) ;
} else {
xfs_alert ( mp , " ... fblk is NULL " ) ;
}
return - EFSCORRUPTED ;
}
/* Get a buffer for the new block. */
error = xfs_dir3_free_get_buf ( args , fbno , & fbp ) ;
if ( error )
return error ;
2019-11-09 01:58:05 +03:00
xfs_dir2_free_hdr_from_disk ( mp , hdr , fbp - > b_addr ) ;
2019-08-29 19:04:06 +03:00
/* Remember the first slot as our empty slot. */
2019-11-09 01:57:53 +03:00
hdr - > firstdb = ( fbno - xfs_dir2_byte_to_db ( args - > geo ,
2019-08-29 19:04:06 +03:00
XFS_DIR2_FREE_OFFSET ) ) *
2019-11-09 02:01:30 +03:00
args - > geo - > free_max_bests ;
2019-08-29 19:04:06 +03:00
} else {
2019-11-09 01:58:05 +03:00
xfs_dir2_free_hdr_from_disk ( mp , hdr , fbp - > b_addr ) ;
2019-08-29 19:04:06 +03:00
}
/* Set the freespace block index from the data block number. */
2019-11-09 02:01:39 +03:00
* findex = xfs_dir2_db_to_fdindex ( args - > geo , * dbno ) ;
2019-08-29 19:04:06 +03:00
/* Extend the freespace table if the new data block is off the end. */
2019-11-09 01:57:53 +03:00
if ( * findex > = hdr - > nvalid ) {
2019-11-09 02:01:30 +03:00
ASSERT ( * findex < args - > geo - > free_max_bests ) ;
2019-11-09 01:57:53 +03:00
hdr - > nvalid = * findex + 1 ;
2019-11-09 01:58:05 +03:00
hdr - > bests [ * findex ] = cpu_to_be16 ( NULLDATAOFF ) ;
2019-08-29 19:04:06 +03:00
}
/*
* If this entry was for an empty data block ( this should always be
* true ) then update the header .
*/
2019-11-09 01:58:05 +03:00
if ( hdr - > bests [ * findex ] = = cpu_to_be16 ( NULLDATAOFF ) ) {
2019-11-09 01:57:53 +03:00
hdr - > nused + + ;
xfs_dir2_free_hdr_to_disk ( mp , fbp - > b_addr , hdr ) ;
2019-08-29 19:04:06 +03:00
xfs_dir2_free_log_header ( args , fbp ) ;
}
/* Update the freespace value for the new block in the table. */
2019-11-09 02:05:39 +03:00
bf = xfs_dir2_data_bestfree_p ( mp , dbp - > b_addr ) ;
2019-11-09 01:58:05 +03:00
hdr - > bests [ * findex ] = bf [ 0 ] . length ;
2019-08-29 19:04:06 +03:00
* dbpp = dbp ;
* fbpp = fbp ;
return 0 ;
}
2019-08-29 19:04:07 +03:00
static int
xfs_dir2_node_find_freeblk (
struct xfs_da_args * args ,
struct xfs_da_state_blk * fblk ,
xfs_dir2_db_t * dbnop ,
struct xfs_buf * * fbpp ,
2019-11-09 01:57:53 +03:00
struct xfs_dir3_icfree_hdr * hdr ,
2019-08-29 19:04:07 +03:00
int * findexp ,
int length )
2005-04-17 02:20:36 +04:00
{
2019-08-29 19:04:07 +03:00
struct xfs_inode * dp = args - > dp ;
struct xfs_trans * tp = args - > trans ;
struct xfs_buf * fbp = NULL ;
2019-08-29 19:04:08 +03:00
xfs_dir2_db_t firstfbno ;
2019-08-29 19:04:07 +03:00
xfs_dir2_db_t lastfbno ;
xfs_dir2_db_t ifbno = - 1 ;
xfs_dir2_db_t dbno = - 1 ;
2019-08-29 19:04:08 +03:00
xfs_dir2_db_t fbno ;
2019-08-29 19:04:07 +03:00
xfs_fileoff_t fo ;
2019-08-29 19:04:07 +03:00
int findex = 0 ;
2019-08-29 19:04:07 +03:00
int error ;
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 ;
findex = fblk - > index ;
2019-11-09 01:58:05 +03:00
xfs_dir2_free_hdr_from_disk ( dp - > i_mount , hdr , fbp - > b_addr ) ;
2005-04-17 02:20:36 +04:00
if ( findex > = 0 ) {
2019-08-29 19:04:07 +03:00
/* caller already found the freespace for us. */
2019-11-09 01:57:53 +03:00
ASSERT ( findex < hdr - > nvalid ) ;
2019-11-09 01:58:05 +03:00
ASSERT ( be16_to_cpu ( hdr - > bests [ findex ] ) ! = NULLDATAOFF ) ;
ASSERT ( be16_to_cpu ( hdr - > bests [ findex ] ) > = length ) ;
2019-11-09 01:57:53 +03:00
dbno = hdr - > firstdb + findex ;
2019-08-29 19:04:06 +03:00
goto found_block ;
2005-04-17 02:20:36 +04:00
}
2019-08-29 19:04:07 +03:00
2013-04-03 09:11:21 +04:00
/*
2019-08-29 19:04:07 +03:00
* The data block looked at didn ' t have enough room .
* We ' ll start at the beginning of the freespace entries .
2013-04-03 09:11:21 +04:00
*/
2019-08-29 19:04:07 +03:00
ifbno = fblk - > blkno ;
2019-08-29 19:04:07 +03:00
xfs_trans_brelse ( tp , fbp ) ;
fbp = NULL ;
fblk - > bp = NULL ;
2005-04-17 02:20:36 +04:00
}
2013-04-03 09:11:21 +04:00
2005-04-17 02:20:36 +04:00
/*
2019-08-29 19:04:07 +03:00
* If we don ' t have a data block yet , we ' re going to scan the freespace
2019-08-29 19:04:07 +03:00
* data for a data block with enough free space in it .
2005-04-17 02:20:36 +04:00
*/
2019-08-29 19:04:07 +03:00
error = xfs_bmap_last_offset ( dp , & fo , XFS_DATA_FORK ) ;
if ( error )
return error ;
lastfbno = xfs_dir2_da_to_db ( args - > geo , ( xfs_dablk_t ) fo ) ;
2019-08-29 19:04:08 +03:00
firstfbno = xfs_dir2_byte_to_db ( args - > geo , XFS_DIR2_FREE_OFFSET ) ;
2019-08-29 19:04:07 +03:00
2019-08-29 19:04:08 +03:00
for ( fbno = lastfbno - 1 ; fbno > = firstfbno ; fbno - - ) {
2019-08-29 19:04:07 +03:00
/* If it's ifbno we already looked at it. */
if ( fbno = = ifbno )
continue ;
2005-04-17 02:20:36 +04:00
/*
2019-08-29 19:04:07 +03:00
* 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 .
2005-04-17 02:20:36 +04:00
*/
2019-08-29 19:04:07 +03:00
error = xfs_dir2_free_try_read ( tp , dp ,
xfs_dir2_db_to_da ( args - > geo , fbno ) ,
& fbp ) ;
if ( error )
return error ;
if ( ! fbp )
continue ;
2019-11-09 01:58:05 +03:00
xfs_dir2_free_hdr_from_disk ( dp - > i_mount , hdr , fbp - > b_addr ) ;
2019-08-29 19:04:07 +03:00
/* Scan the free entry array for a large enough free space. */
2019-11-09 01:57:53 +03:00
for ( findex = hdr - > nvalid - 1 ; findex > = 0 ; findex - - ) {
2019-11-09 01:58:05 +03:00
if ( be16_to_cpu ( hdr - > bests [ findex ] ) ! = NULLDATAOFF & &
be16_to_cpu ( hdr - > bests [ findex ] ) > = length ) {
2019-11-09 01:57:53 +03:00
dbno = hdr - > firstdb + findex ;
2019-08-29 19:04:07 +03:00
goto found_block ;
2005-04-17 02:20:36 +04:00
}
}
2019-08-29 19:04:07 +03:00
/* Didn't find free space, go on to next free block */
xfs_trans_brelse ( tp , fbp ) ;
2005-04-17 02:20:36 +04:00
}
2019-08-29 19:04:07 +03:00
2019-08-29 19:04:07 +03:00
found_block :
* dbnop = dbno ;
* fbpp = fbp ;
* findexp = findex ;
return 0 ;
}
/*
* 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
xfs_dir2_node_addname_int (
struct xfs_da_args * args , /* operation arguments */
struct xfs_da_state_blk * fblk ) /* optional freespace block */
{
struct xfs_dir2_data_unused * dup ; /* data unused entry pointer */
struct xfs_dir2_data_entry * dep ; /* data entry pointer */
struct xfs_dir2_data_hdr * hdr ; /* data block header */
struct xfs_dir2_data_free * bf ;
struct xfs_trans * tp = args - > trans ;
struct xfs_inode * dp = args - > dp ;
2019-11-09 01:57:53 +03:00
struct xfs_dir3_icfree_hdr freehdr ;
2019-08-29 19:04:07 +03:00
struct xfs_buf * dbp ; /* data block buffer */
struct xfs_buf * fbp ; /* freespace buffer */
xfs_dir2_data_aoff_t aoff ;
xfs_dir2_db_t dbno ; /* data block number */
int error ; /* error return value */
int findex ; /* freespace entry index */
int length ; /* length of the new entry */
int logfree = 0 ; /* need to log free entry */
int needlog = 0 ; /* need to log data header */
int needscan = 0 ; /* need to rescan data frees */
__be16 * tagp ; /* data entry tag pointer */
2019-11-09 02:05:37 +03:00
length = xfs_dir2_data_entsize ( dp - > i_mount , args - > namelen ) ;
2019-11-09 01:57:53 +03:00
error = xfs_dir2_node_find_freeblk ( args , fblk , & dbno , & fbp , & freehdr ,
& findex , length ) ;
2019-08-29 19:04:07 +03:00
if ( error )
return error ;
/*
* Now we know if we must allocate blocks , so if we are checking whether
* we can insert without allocation then we can return now .
*/
if ( args - > op_flags & XFS_DA_OP_JUSTCHECK ) {
if ( dbno = = - 1 )
return - ENOSPC ;
return 0 ;
}
2019-08-29 19:04:06 +03:00
2005-04-17 02:20:36 +04:00
/*
* If we don ' t have a data block , we need to allocate one and make
* the freespace entries refer to it .
*/
2019-08-29 19:04:06 +03:00
if ( dbno = = - 1 ) {
/* we're going to have to log the free block index later */
2005-04-17 02:20:36 +04:00
logfree = 1 ;
2019-08-29 19:04:07 +03:00
error = xfs_dir2_node_add_datablk ( args , fblk , & dbno , & dbp , & fbp ,
2019-11-09 01:57:53 +03:00
& freehdr , & findex ) ;
2019-08-29 19:04:06 +03:00
} else {
/* 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 ) ,
2019-11-20 20:46:04 +03:00
0 , & dbp ) ;
2005-04-17 02:20:36 +04:00
}
2019-08-29 19:04:07 +03:00
if ( error )
return error ;
2019-08-29 19:04:06 +03:00
/* setup for data block up now */
hdr = dbp - > b_addr ;
2019-11-09 02:05:39 +03:00
bf = xfs_dir2_data_bestfree_p ( dp - > i_mount , hdr ) ;
2013-04-03 09:11:22 +04:00
ASSERT ( be16_to_cpu ( bf [ 0 ] . length ) > = length ) ;
2019-08-29 19:04:06 +03:00
/* Point to the existing unused space. */
2005-04-17 02:20:36 +04:00
dup = ( xfs_dir2_data_unused_t * )
2013-04-03 09:11:22 +04:00
( ( char * ) hdr + be16_to_cpu ( bf [ 0 ] . offset ) ) ;
2019-08-29 19:04:06 +03:00
/* 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 ;
}
2019-08-29 19:04:06 +03:00
/* Fill in the new entry and log it. */
2005-04-17 02:20:36 +04:00
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 ) ;
2019-11-09 02:05:48 +03:00
xfs_dir2_data_put_ftype ( dp - > i_mount , dep , args - > filetype ) ;
2019-11-09 02:05:37 +03:00
tagp = xfs_dir2_data_entry_tag_p ( dp - > i_mount , 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 ) ;
2019-08-29 19:04:06 +03:00
/* Rescan the freespace and log the data block if needed. */
2005-04-17 02:20:36 +04:00
if ( needscan )
2019-11-09 02:06:02 +03:00
xfs_dir2_data_freescan ( dp - > i_mount , 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 ) ;
2019-08-29 19:04:06 +03:00
/* If the freespace block entry is now wrong, update it. */
2019-11-09 01:58:05 +03:00
if ( freehdr . bests [ findex ] ! = bf [ 0 ] . length ) {
freehdr . bests [ findex ] = bf [ 0 ] . length ;
2005-04-17 02:20:36 +04:00
logfree = 1 ;
}
2019-08-29 19:04:06 +03:00
/* Log the freespace entry if needed. */
2005-04-17 02:20:36 +04:00
if ( logfree )
2019-11-09 01:58:05 +03:00
xfs_dir2_free_log_bests ( args , & freehdr , fbp , findex , findex ) ;
2019-08-29 19:04:06 +03:00
/* Return the data block and offset in args. */
2005-04-17 02:20:36 +04:00
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 ;
}
2019-08-29 19:04:06 +03: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 */
trace_xfs_dir2_node_addname ( args ) ;
/*
* Allocate and initialize the state ( btree cursor ) .
*/
2020-07-22 19:23:18 +03:00
state = xfs_da_state_alloc ( args ) ;
2019-08-29 19:04:06 +03:00
/*
* Look up the name . We ' re not supposed to find it , but
* this gives us the insertion point .
*/
error = xfs_da3_node_lookup_int ( state , & rval ) ;
if ( error )
rval = error ;
if ( rval ! = - ENOENT ) {
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 .
*/
if ( ! ( args - > op_flags & XFS_DA_OP_JUSTCHECK ) )
xfs_da3_fixhashpath ( state , & state - > path ) ;
} else {
/*
* It didn ' t work , we need to split the leaf block .
*/
if ( args - > total = = 0 ) {
ASSERT ( rval = = - ENOSPC ) ;
goto done ;
}
/*
* Split the leaf block and insert the new entry .
*/
rval = xfs_da3_split ( state ) ;
}
done :
xfs_da_state_free ( state ) ;
return rval ;
}
2005-04-17 02:20:36 +04:00
/*
* 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 .
*/
2020-07-22 19:23:18 +03:00
state = xfs_da_state_alloc ( args ) ;
2005-04-17 02:20:36 +04:00
/*
* 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 .
*/
2020-07-22 19:23:18 +03:00
state = xfs_da_state_alloc ( args ) ;
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
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 .
*/
2020-07-22 19:23:18 +03:00
state = xfs_da_state_alloc ( args ) ;
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 ) {
2019-11-09 01:57:50 +03:00
struct xfs_dir3_icleaf_hdr leafhdr ;
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 ) ;
ASSERT ( state - > extravalid ) ;
2019-11-09 01:57:50 +03:00
xfs_dir2_leaf_hdr_from_disk ( state - > mp , & leafhdr ,
blk - > bp - > b_addr ) ;
2005-04-17 02:20:36 +04:00
/*
* 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 ,
2019-11-09 01:57:50 +03:00
be32_to_cpu ( leafhdr . ents [ blk - > index ] . 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 ) ;
2019-11-09 02:05:48 +03:00
xfs_dir2_data_put_ftype ( state - > mp , 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 ;
2019-11-09 01:57:52 +03:00
xfs_dir2_free_hdr_from_disk ( dp - > i_mount , & 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 ;
}