2005-04-17 02:20:36 +04:00
/*
2005-11-02 06:58:39 +03:00
* Copyright ( c ) 2000 - 2003 , 2005 Silicon Graphics , Inc .
2013-04-12 01:30: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
*
2005-11-02 06:58:39 +03:00
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License as
2005-04-17 02:20:36 +04:00
* published by the Free Software Foundation .
*
2005-11-02 06:58:39 +03:00
* This program is distributed in the hope that it would be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
2005-04-17 02:20:36 +04:00
*
2005-11-02 06:58:39 +03:00
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write the Free Software Foundation ,
* Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
2005-04-17 02:20:36 +04:00
*/
# include "xfs.h"
2005-11-02 06:38:42 +03:00
# include "xfs_fs.h"
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_sb.h"
# include "xfs_ag.h"
# include "xfs_mount.h"
2013-10-15 02:17:51 +04:00
# include "xfs_da_format.h"
2005-11-02 06:38:42 +03:00
# include "xfs_da_btree.h"
2005-04-17 02:20:36 +04:00
# 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-12 01:30:21 +04:00
# include "xfs_buf_item.h"
# include "xfs_cksum.h"
2005-04-17 02:20:36 +04:00
/*
* Local function declarations .
*/
2012-06-22 12:50:14 +04:00
static int xfs_dir2_leaf_lookup_int ( xfs_da_args_t * args , struct xfs_buf * * lbpp ,
int * indexp , struct xfs_buf * * dbpp ) ;
2013-04-12 01:30:21 +04:00
static void xfs_dir3_leaf_log_bests ( struct xfs_trans * tp , struct xfs_buf * bp ,
2005-06-21 09:36:52 +04:00
int first , int last ) ;
2013-04-12 01:30:21 +04:00
static void xfs_dir3_leaf_log_tail ( struct xfs_trans * tp , struct xfs_buf * bp ) ;
2005-06-21 09:36:52 +04:00
2013-04-12 01:30:21 +04:00
/*
* Check the internal consistency of a leaf1 block .
* Pop an assert if something is wrong .
*/
# ifdef DEBUG
2013-10-29 15:11:50 +04:00
# define xfs_dir3_leaf_check(dp, bp) \
2013-04-12 01:30:21 +04:00
do { \
2013-10-29 15:11:50 +04:00
if ( ! xfs_dir3_leaf1_check ( ( dp ) , ( bp ) ) ) \
2013-04-12 01:30:21 +04:00
ASSERT ( 0 ) ; \
} while ( 0 ) ;
STATIC bool
xfs_dir3_leaf1_check (
2013-10-29 15:11:50 +04:00
struct xfs_inode * dp ,
2013-04-12 01:30:21 +04:00
struct xfs_buf * bp )
{
struct xfs_dir2_leaf * leaf = bp - > b_addr ;
struct xfs_dir3_icleaf_hdr leafhdr ;
2013-10-29 15:11:52 +04:00
dp - > d_ops - > leaf_hdr_from_disk ( & leafhdr , leaf ) ;
2013-04-12 01:30:21 +04:00
if ( leafhdr . magic = = XFS_DIR3_LEAF1_MAGIC ) {
struct xfs_dir3_leaf_hdr * leaf3 = bp - > b_addr ;
if ( be64_to_cpu ( leaf3 - > info . blkno ) ! = bp - > b_bn )
return false ;
} else if ( leafhdr . magic ! = XFS_DIR2_LEAF1_MAGIC )
return false ;
2013-10-29 15:11:50 +04:00
return xfs_dir3_leaf_check_int ( dp - > i_mount , dp , & leafhdr , leaf ) ;
2013-04-12 01:30:21 +04:00
}
# 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
bool
xfs_dir3_leaf_check_int (
struct xfs_mount * mp ,
2013-10-29 15:11:50 +04:00
struct xfs_inode * dp ,
2013-04-12 01:30:21 +04:00
struct xfs_dir3_icleaf_hdr * hdr ,
struct xfs_dir2_leaf * leaf )
{
struct xfs_dir2_leaf_entry * ents ;
xfs_dir2_leaf_tail_t * ltp ;
int stale ;
int i ;
2013-10-29 15:11:50 +04:00
const struct xfs_dir_ops * ops ;
2013-10-29 15:11:52 +04:00
struct xfs_dir3_icleaf_hdr leafhdr ;
2013-04-12 01:30:21 +04:00
2013-10-29 15:11:50 +04:00
/*
* we can be passed a null dp here from a verifier , so we need to go the
* hard way to get them .
*/
ops = xfs_dir_get_ops ( mp , dp ) ;
2013-10-29 15:11:52 +04:00
if ( ! hdr ) {
ops - > leaf_hdr_from_disk ( & leafhdr , leaf ) ;
hdr = & leafhdr ;
}
2013-10-29 15:11:50 +04:00
ents = ops - > leaf_ents_p ( leaf ) ;
2013-04-12 01:30:21 +04:00
ltp = xfs_dir2_leaf_tail_p ( mp , leaf ) ;
/*
* XXX ( dgc ) : This value is not restrictive enough .
* Should factor in the size of the bests table as well .
* We can deduce a value for that from di_size .
*/
2013-10-29 15:11:50 +04:00
if ( hdr - > count > ops - > leaf_max_ents ( mp ) )
2013-04-12 01:30:21 +04:00
return false ;
/* Leaves and bests don't overlap in leaf format. */
if ( ( hdr - > magic = = XFS_DIR2_LEAF1_MAGIC | |
hdr - > magic = = XFS_DIR3_LEAF1_MAGIC ) & &
( char * ) & ents [ hdr - > count ] > ( char * ) xfs_dir2_leaf_bests_p ( ltp ) )
return false ;
/* Check hash value order, count stale entries. */
for ( i = stale = 0 ; i < hdr - > count ; i + + ) {
if ( i + 1 < hdr - > count ) {
if ( be32_to_cpu ( ents [ i ] . hashval ) >
be32_to_cpu ( ents [ i + 1 ] . hashval ) )
return false ;
}
if ( ents [ i ] . address = = cpu_to_be32 ( XFS_DIR2_NULL_DATAPTR ) )
stale + + ;
}
if ( hdr - > stale ! = stale )
return false ;
return true ;
}
2013-09-03 04:06:58 +04:00
/*
* We verify the magic numbers before decoding the leaf header so that on debug
* kernels we don ' t get assertion failures in xfs_dir3_leaf_hdr_from_disk ( ) due
* to incorrect magic numbers .
*/
2013-04-12 01:30:21 +04:00
static bool
xfs_dir3_leaf_verify (
2012-11-12 15:54:15 +04:00
struct xfs_buf * bp ,
2013-04-12 01:30:21 +04:00
__uint16_t magic )
{
struct xfs_mount * mp = bp - > b_target - > bt_mount ;
struct xfs_dir2_leaf * leaf = bp - > b_addr ;
ASSERT ( magic = = XFS_DIR2_LEAF1_MAGIC | | magic = = XFS_DIR2_LEAFN_MAGIC ) ;
if ( xfs_sb_version_hascrc ( & mp - > m_sb ) ) {
struct xfs_dir3_leaf_hdr * leaf3 = bp - > b_addr ;
2013-09-03 04:06:58 +04:00
__uint16_t magic3 ;
2013-04-12 01:30:21 +04:00
2013-09-03 04:06:58 +04:00
magic3 = ( magic = = XFS_DIR2_LEAF1_MAGIC ) ? XFS_DIR3_LEAF1_MAGIC
: XFS_DIR3_LEAFN_MAGIC ;
2013-04-12 01:30:21 +04:00
2013-09-03 04:06:58 +04:00
if ( leaf3 - > info . hdr . magic ! = cpu_to_be16 ( magic3 ) )
return false ;
2013-04-12 01:30:21 +04:00
if ( ! uuid_equal ( & leaf3 - > info . uuid , & mp - > m_sb . sb_uuid ) )
return false ;
if ( be64_to_cpu ( leaf3 - > info . blkno ) ! = bp - > b_bn )
return false ;
} else {
2013-09-03 04:06:58 +04:00
if ( leaf - > hdr . info . magic ! = cpu_to_be16 ( magic ) )
2013-04-12 01:30:21 +04:00
return false ;
}
2013-09-03 04:06:58 +04:00
2013-10-29 15:11:52 +04:00
return xfs_dir3_leaf_check_int ( mp , NULL , NULL , leaf ) ;
2013-04-12 01:30:21 +04:00
}
static void
__read_verify (
struct xfs_buf * bp ,
__uint16_t magic )
{
struct xfs_mount * mp = bp - > b_target - > bt_mount ;
if ( ( xfs_sb_version_hascrc ( & mp - > m_sb ) & &
! xfs_verify_cksum ( bp - > b_addr , BBTOB ( bp - > b_length ) ,
XFS_DIR3_LEAF_CRC_OFF ) ) | |
! xfs_dir3_leaf_verify ( bp , magic ) ) {
XFS_CORRUPTION_ERROR ( __func__ , XFS_ERRLEVEL_LOW , mp , bp - > b_addr ) ;
xfs_buf_ioerror ( bp , EFSCORRUPTED ) ;
}
}
static void
__write_verify (
struct xfs_buf * bp ,
__uint16_t magic )
2012-11-12 15:54:15 +04:00
{
struct xfs_mount * mp = bp - > b_target - > bt_mount ;
2013-04-12 01:30:21 +04:00
struct xfs_buf_log_item * bip = bp - > b_fspriv ;
struct xfs_dir3_leaf_hdr * hdr3 = bp - > b_addr ;
2012-11-12 15:54:15 +04:00
2013-04-12 01:30:21 +04:00
if ( ! xfs_dir3_leaf_verify ( bp , magic ) ) {
XFS_CORRUPTION_ERROR ( __func__ , XFS_ERRLEVEL_LOW , mp , bp - > b_addr ) ;
2012-11-12 15:54:15 +04:00
xfs_buf_ioerror ( bp , EFSCORRUPTED ) ;
2013-04-12 01:30:21 +04:00
return ;
2012-11-12 15:54:15 +04:00
}
2013-04-12 01:30:21 +04:00
if ( ! xfs_sb_version_hascrc ( & mp - > m_sb ) )
return ;
if ( bip )
hdr3 - > info . lsn = cpu_to_be64 ( bip - > bli_item . li_lsn ) ;
xfs_update_cksum ( bp - > b_addr , BBTOB ( bp - > b_length ) , XFS_DIR3_LEAF_CRC_OFF ) ;
2012-11-14 10:52:32 +04:00
}
2012-11-12 15:54:15 +04:00
2012-11-14 10:52:32 +04:00
static void
2013-04-12 01:30:21 +04:00
xfs_dir3_leaf1_read_verify (
2012-11-14 10:52:32 +04:00
struct xfs_buf * bp )
{
2013-04-12 01:30:21 +04:00
__read_verify ( bp , XFS_DIR2_LEAF1_MAGIC ) ;
2012-11-14 10:52:32 +04:00
}
static void
2013-04-12 01:30:21 +04:00
xfs_dir3_leaf1_write_verify (
2012-11-14 10:52:32 +04:00
struct xfs_buf * bp )
{
2013-04-12 01:30:21 +04:00
__write_verify ( bp , XFS_DIR2_LEAF1_MAGIC ) ;
2012-11-12 15:54:15 +04:00
}
2013-04-12 01:30:21 +04:00
static void
xfs_dir3_leafn_read_verify (
2012-11-14 10:52:32 +04:00
struct xfs_buf * bp )
2012-11-12 15:54:15 +04:00
{
2013-04-12 01:30:21 +04:00
__read_verify ( bp , XFS_DIR2_LEAFN_MAGIC ) ;
2012-11-12 15:54:15 +04:00
}
2013-04-12 01:30:21 +04:00
static void
xfs_dir3_leafn_write_verify (
2012-11-14 10:52:32 +04:00
struct xfs_buf * bp )
2012-11-12 15:54:15 +04:00
{
2013-04-12 01:30:21 +04:00
__write_verify ( bp , XFS_DIR2_LEAFN_MAGIC ) ;
2012-11-12 15:54:15 +04:00
}
2013-04-03 09:11:29 +04:00
const struct xfs_buf_ops xfs_dir3_leaf1_buf_ops = {
2013-04-12 01:30:21 +04:00
. verify_read = xfs_dir3_leaf1_read_verify ,
. verify_write = xfs_dir3_leaf1_write_verify ,
2012-11-14 10:54:40 +04:00
} ;
2013-04-12 01:30:21 +04:00
const struct xfs_buf_ops xfs_dir3_leafn_buf_ops = {
. verify_read = xfs_dir3_leafn_read_verify ,
. verify_write = xfs_dir3_leafn_write_verify ,
2012-11-14 10:54:40 +04:00
} ;
2012-11-12 15:54:15 +04:00
static int
2013-04-12 01:30:21 +04:00
xfs_dir3_leaf_read (
2012-11-12 15:54:15 +04:00
struct xfs_trans * tp ,
struct xfs_inode * dp ,
xfs_dablk_t fbno ,
xfs_daddr_t mappedbno ,
struct xfs_buf * * bpp )
{
2013-04-03 09:11:29 +04:00
int err ;
err = xfs_da_read_buf ( tp , dp , fbno , mappedbno , bpp ,
2013-04-12 01:30:21 +04:00
XFS_DATA_FORK , & xfs_dir3_leaf1_buf_ops ) ;
2013-04-03 09:11:29 +04:00
if ( ! err & & tp )
2013-04-03 09:11:30 +04:00
xfs_trans_buf_set_type ( tp , * bpp , XFS_BLFT_DIR_LEAF1_BUF ) ;
2013-04-03 09:11:29 +04:00
return err ;
2012-11-12 15:54:15 +04:00
}
int
2013-04-12 01:30:21 +04:00
xfs_dir3_leafn_read (
2012-11-12 15:54:15 +04:00
struct xfs_trans * tp ,
struct xfs_inode * dp ,
xfs_dablk_t fbno ,
xfs_daddr_t mappedbno ,
struct xfs_buf * * bpp )
{
2013-04-03 09:11:29 +04:00
int err ;
err = xfs_da_read_buf ( tp , dp , fbno , mappedbno , bpp ,
2013-04-12 01:30:21 +04:00
XFS_DATA_FORK , & xfs_dir3_leafn_buf_ops ) ;
2013-04-03 09:11:29 +04:00
if ( ! err & & tp )
2013-04-03 09:11:30 +04:00
xfs_trans_buf_set_type ( tp , * bpp , XFS_BLFT_DIR_LEAFN_BUF ) ;
2013-04-03 09:11:29 +04:00
return err ;
2013-04-12 01:30:21 +04:00
}
/*
* Initialize a new leaf block , leaf1 or leafn magic accepted .
*/
static void
xfs_dir3_leaf_init (
struct xfs_mount * mp ,
2013-04-03 09:11:29 +04:00
struct xfs_trans * tp ,
2013-04-12 01:30:21 +04:00
struct xfs_buf * bp ,
xfs_ino_t owner ,
__uint16_t type )
{
struct xfs_dir2_leaf * leaf = bp - > b_addr ;
ASSERT ( type = = XFS_DIR2_LEAF1_MAGIC | | type = = XFS_DIR2_LEAFN_MAGIC ) ;
if ( xfs_sb_version_hascrc ( & mp - > m_sb ) ) {
struct xfs_dir3_leaf_hdr * leaf3 = bp - > b_addr ;
memset ( leaf3 , 0 , sizeof ( * leaf3 ) ) ;
leaf3 - > info . hdr . magic = ( type = = XFS_DIR2_LEAF1_MAGIC )
? cpu_to_be16 ( XFS_DIR3_LEAF1_MAGIC )
: cpu_to_be16 ( XFS_DIR3_LEAFN_MAGIC ) ;
leaf3 - > info . blkno = cpu_to_be64 ( bp - > b_bn ) ;
leaf3 - > info . owner = cpu_to_be64 ( owner ) ;
uuid_copy ( & leaf3 - > info . uuid , & mp - > m_sb . sb_uuid ) ;
} else {
memset ( leaf , 0 , sizeof ( * leaf ) ) ;
leaf - > hdr . info . magic = cpu_to_be16 ( type ) ;
}
/*
* If it ' s a leaf - format directory initialize the tail .
* Caller is responsible for initialising the bests table .
*/
if ( type = = XFS_DIR2_LEAF1_MAGIC ) {
struct xfs_dir2_leaf_tail * ltp ;
ltp = xfs_dir2_leaf_tail_p ( mp , leaf ) ;
ltp - > bestcount = 0 ;
bp - > b_ops = & xfs_dir3_leaf1_buf_ops ;
2013-04-03 09:11:30 +04:00
xfs_trans_buf_set_type ( tp , bp , XFS_BLFT_DIR_LEAF1_BUF ) ;
2013-04-03 09:11:29 +04:00
} else {
2013-04-12 01:30:21 +04:00
bp - > b_ops = & xfs_dir3_leafn_buf_ops ;
2013-04-03 09:11:30 +04:00
xfs_trans_buf_set_type ( tp , bp , XFS_BLFT_DIR_LEAFN_BUF ) ;
2013-04-03 09:11:29 +04:00
}
2013-04-12 01:30:21 +04:00
}
int
xfs_dir3_leaf_get_buf (
xfs_da_args_t * args ,
xfs_dir2_db_t bno ,
struct xfs_buf * * bpp ,
__uint16_t magic )
{
struct xfs_inode * dp = args - > dp ;
struct xfs_trans * tp = args - > trans ;
struct xfs_mount * mp = dp - > i_mount ;
struct xfs_buf * bp ;
int error ;
ASSERT ( magic = = XFS_DIR2_LEAF1_MAGIC | | magic = = XFS_DIR2_LEAFN_MAGIC ) ;
ASSERT ( bno > = XFS_DIR2_LEAF_FIRSTDB ( mp ) & &
bno < XFS_DIR2_FREE_FIRSTDB ( mp ) ) ;
error = xfs_da_get_buf ( tp , dp , xfs_dir2_db_to_da ( mp , bno ) , - 1 , & bp ,
XFS_DATA_FORK ) ;
if ( error )
return error ;
2013-04-03 09:11:29 +04:00
xfs_dir3_leaf_init ( mp , tp , bp , dp - > i_ino , magic ) ;
2013-10-29 15:11:50 +04:00
xfs_dir3_leaf_log_header ( tp , dp , bp ) ;
2013-04-12 01:30:21 +04:00
if ( magic = = XFS_DIR2_LEAF1_MAGIC )
xfs_dir3_leaf_log_tail ( tp , bp ) ;
* bpp = bp ;
return 0 ;
2012-11-12 15:54:15 +04:00
}
2005-04-17 02:20:36 +04:00
/*
* Convert a block form directory to a leaf form directory .
*/
int /* error */
xfs_dir2_block_to_leaf (
xfs_da_args_t * args , /* operation arguments */
2012-06-22 12:50:14 +04:00
struct xfs_buf * dbp ) /* input block's buffer */
2005-04-17 02:20:36 +04:00
{
2006-03-17 09:27:19 +03:00
__be16 * bestsp ; /* leaf's bestsp entries */
2005-04-17 02:20:36 +04:00
xfs_dablk_t blkno ; /* leaf block's bno */
2011-07-08 16:35:27 +04:00
xfs_dir2_data_hdr_t * hdr ; /* block header */
2005-04-17 02:20:36 +04:00
xfs_dir2_leaf_entry_t * blp ; /* block's leaf entries */
xfs_dir2_block_tail_t * btp ; /* block's tail */
xfs_inode_t * dp ; /* incore directory inode */
int error ; /* error return code */
2012-06-22 12:50:14 +04:00
struct xfs_buf * lbp ; /* leaf block's buffer */
2005-04-17 02:20:36 +04:00
xfs_dir2_db_t ldb ; /* leaf block's bno */
xfs_dir2_leaf_t * leaf ; /* leaf structure */
xfs_dir2_leaf_tail_t * ltp ; /* leaf's tail */
xfs_mount_t * mp ; /* filesystem mount point */
int needlog ; /* need to log block header */
int needscan ; /* need to rescan bestfree */
xfs_trans_t * tp ; /* transaction pointer */
2013-04-03 09:11:22 +04:00
struct xfs_dir2_data_free * bf ;
2013-04-12 01:30:21 +04:00
struct xfs_dir2_leaf_entry * ents ;
struct xfs_dir3_icleaf_hdr leafhdr ;
2005-04-17 02:20:36 +04:00
2009-12-15 02:14:59 +03:00
trace_xfs_dir2_block_to_leaf ( args ) ;
2005-04-17 02:20:36 +04:00
dp = args - > dp ;
mp = dp - > i_mount ;
tp = args - > trans ;
/*
* Add the leaf block to the inode .
* This interface will only put blocks in the leaf / node range .
* Since that ' s empty now , we ' ll get the root ( block 0 in range ) .
*/
if ( ( error = xfs_da_grow_inode ( args , & blkno ) ) ) {
return error ;
}
2007-06-28 10:43:50 +04:00
ldb = xfs_dir2_da_to_db ( mp , blkno ) ;
2005-04-17 02:20:36 +04:00
ASSERT ( ldb = = XFS_DIR2_LEAF_FIRSTDB ( mp ) ) ;
/*
* Initialize the leaf block , get a buffer for it .
*/
2013-04-12 01:30:21 +04:00
error = xfs_dir3_leaf_get_buf ( args , ldb , & lbp , XFS_DIR2_LEAF1_MAGIC ) ;
if ( error )
2005-04-17 02:20:36 +04:00
return error ;
2013-04-12 01:30:21 +04:00
2012-06-22 12:50:14 +04:00
leaf = lbp - > b_addr ;
hdr = dbp - > b_addr ;
2013-04-03 09:11:22 +04:00
xfs_dir3_data_check ( dp , dbp ) ;
2011-07-08 16:35:27 +04:00
btp = xfs_dir2_block_tail_p ( mp , hdr ) ;
2007-06-28 10:43:50 +04:00
blp = xfs_dir2_block_leaf_p ( btp ) ;
2013-10-29 15:11:49 +04:00
bf = dp - > d_ops - > data_bestfree_p ( hdr ) ;
2013-10-29 15:11:50 +04:00
ents = dp - > d_ops - > leaf_ents_p ( leaf ) ;
2013-04-12 01:30:21 +04:00
2005-04-17 02:20:36 +04:00
/*
* Set the counts in the leaf header .
*/
2013-10-29 15:11:52 +04:00
dp - > d_ops - > leaf_hdr_from_disk ( & leafhdr , leaf ) ;
2013-04-12 01:30:21 +04:00
leafhdr . count = be32_to_cpu ( btp - > count ) ;
leafhdr . stale = be32_to_cpu ( btp - > stale ) ;
2013-10-29 15:11:52 +04:00
dp - > d_ops - > leaf_hdr_to_disk ( leaf , & leafhdr ) ;
2013-10-29 15:11:50 +04:00
xfs_dir3_leaf_log_header ( tp , dp , lbp ) ;
2013-04-12 01:30:21 +04:00
2005-04-17 02:20:36 +04:00
/*
* Could compact these but I think we always do the conversion
* after squeezing out stale entries .
*/
2013-04-12 01:30:21 +04:00
memcpy ( ents , blp , be32_to_cpu ( btp - > count ) * sizeof ( xfs_dir2_leaf_entry_t ) ) ;
2013-10-29 15:11:50 +04:00
xfs_dir3_leaf_log_ents ( tp , dp , lbp , 0 , leafhdr . count - 1 ) ;
2005-04-17 02:20:36 +04:00
needscan = 0 ;
needlog = 1 ;
/*
* Make the space formerly occupied by the leaf entries and block
* tail be free .
*/
2013-10-29 15:11:49 +04:00
xfs_dir2_data_make_free ( tp , dp , dbp ,
2011-07-08 16:35:27 +04:00
( xfs_dir2_data_aoff_t ) ( ( char * ) blp - ( char * ) hdr ) ,
( xfs_dir2_data_aoff_t ) ( ( char * ) hdr + mp - > m_dirblksize -
2005-04-17 02:20:36 +04:00
( char * ) blp ) ,
& needlog , & needscan ) ;
/*
* Fix up the block header , make it a data block .
*/
2013-04-03 09:11:22 +04:00
dbp - > b_ops = & xfs_dir3_data_buf_ops ;
2013-04-03 09:11:30 +04:00
xfs_trans_buf_set_type ( tp , dbp , XFS_BLFT_DIR_DATA_BUF ) ;
2013-04-03 09:11:22 +04:00
if ( hdr - > magic = = cpu_to_be32 ( XFS_DIR2_BLOCK_MAGIC ) )
hdr - > magic = cpu_to_be32 ( XFS_DIR2_DATA_MAGIC ) ;
else
hdr - > magic = cpu_to_be32 ( XFS_DIR3_DATA_MAGIC ) ;
2005-04-17 02:20:36 +04:00
if ( needscan )
2013-10-29 15:11:48 +04:00
xfs_dir2_data_freescan ( dp , hdr , & needlog ) ;
2005-04-17 02:20:36 +04:00
/*
* Set up leaf tail and bests table .
*/
2007-06-28 10:43:50 +04:00
ltp = xfs_dir2_leaf_tail_p ( mp , leaf ) ;
2006-03-17 09:27:28 +03:00
ltp - > bestcount = cpu_to_be32 ( 1 ) ;
2007-06-28 10:43:50 +04:00
bestsp = xfs_dir2_leaf_bests_p ( ltp ) ;
2013-04-03 09:11:20 +04:00
bestsp [ 0 ] = bf [ 0 ] . length ;
2005-04-17 02:20:36 +04:00
/*
* Log the data header and leaf bests table .
*/
if ( needlog )
2013-10-29 15:11:49 +04:00
xfs_dir2_data_log_header ( tp , dp , dbp ) ;
2013-10-29 15:11:50 +04:00
xfs_dir3_leaf_check ( dp , lbp ) ;
2013-04-03 09:11:22 +04:00
xfs_dir3_data_check ( dp , dbp ) ;
2013-04-12 01:30:21 +04:00
xfs_dir3_leaf_log_bests ( tp , lbp , 0 , 0 ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2011-07-13 15:43:48 +04:00
STATIC void
2013-04-12 01:30:21 +04:00
xfs_dir3_leaf_find_stale (
struct xfs_dir3_icleaf_hdr * leafhdr ,
struct xfs_dir2_leaf_entry * ents ,
2011-07-13 15:43:48 +04:00
int index ,
int * lowstale ,
int * highstale )
{
/*
* Find the first stale entry before our index , if any .
*/
for ( * lowstale = index - 1 ; * lowstale > = 0 ; - - * lowstale ) {
2013-04-12 01:30:21 +04:00
if ( ents [ * lowstale ] . address = =
2011-07-13 15:43:48 +04:00
cpu_to_be32 ( XFS_DIR2_NULL_DATAPTR ) )
break ;
}
/*
* Find the first stale entry at or after our index , if any .
* Stop if the result would require moving more entries than using
* lowstale .
*/
2013-04-12 01:30:21 +04:00
for ( * highstale = index ; * highstale < leafhdr - > count ; + + * highstale ) {
if ( ents [ * highstale ] . address = =
2011-07-13 15:43:48 +04:00
cpu_to_be32 ( XFS_DIR2_NULL_DATAPTR ) )
break ;
if ( * lowstale > = 0 & & index - * lowstale < = * highstale - index )
break ;
}
}
2011-07-08 16:34:59 +04:00
struct xfs_dir2_leaf_entry *
2013-04-12 01:30:21 +04:00
xfs_dir3_leaf_find_entry (
struct xfs_dir3_icleaf_hdr * leafhdr ,
struct xfs_dir2_leaf_entry * ents ,
2011-07-08 16:34:59 +04:00
int index , /* leaf table position */
int compact , /* need to compact leaves */
int lowstale , /* index of prev stale leaf */
int highstale , /* index of next stale leaf */
int * lfloglow , /* low leaf logging index */
int * lfloghigh ) /* high leaf logging index */
{
2013-04-12 01:30:21 +04:00
if ( ! leafhdr - > stale ) {
2011-07-08 16:34:59 +04:00
xfs_dir2_leaf_entry_t * lep ; /* leaf entry table pointer */
/*
* Now we need to make room to insert the leaf entry .
*
* If there are no stale entries , just insert a hole at index .
*/
2013-04-12 01:30:21 +04:00
lep = & ents [ index ] ;
if ( index < leafhdr - > count )
2011-07-08 16:34:59 +04:00
memmove ( lep + 1 , lep ,
2013-04-12 01:30:21 +04:00
( leafhdr - > count - index ) * sizeof ( * lep ) ) ;
2011-07-08 16:34:59 +04:00
/*
* Record low and high logging indices for the leaf .
*/
* lfloglow = index ;
2013-04-12 01:30:21 +04:00
* lfloghigh = leafhdr - > count + + ;
2011-07-08 16:34:59 +04:00
return lep ;
}
/*
* There are stale entries .
*
* We will use one of them for the new entry . It ' s probably not at
* the right location , so we ' ll have to shift some up or down first .
*
* If we didn ' t compact before , we need to find the nearest stale
* entries before and after our insertion point .
*/
2011-07-13 15:43:48 +04:00
if ( compact = = 0 )
2013-04-12 01:30:21 +04:00
xfs_dir3_leaf_find_stale ( leafhdr , ents , index ,
& lowstale , & highstale ) ;
2011-07-08 16:34:59 +04:00
/*
* If the low one is better , use it .
*/
if ( lowstale > = 0 & &
2013-04-12 01:30:21 +04:00
( highstale = = leafhdr - > count | |
2011-07-08 16:34:59 +04:00
index - lowstale - 1 < highstale - index ) ) {
ASSERT ( index - lowstale - 1 > = 0 ) ;
2013-04-12 01:30:21 +04:00
ASSERT ( ents [ lowstale ] . address = =
2011-07-08 16:36:05 +04:00
cpu_to_be32 ( XFS_DIR2_NULL_DATAPTR ) ) ;
2011-07-08 16:34:59 +04:00
/*
* Copy entries up to cover the stale entry and make room
* for the new entry .
*/
if ( index - lowstale - 1 > 0 ) {
2013-04-12 01:30:21 +04:00
memmove ( & ents [ lowstale ] , & ents [ lowstale + 1 ] ,
2011-07-08 16:34:59 +04:00
( index - lowstale - 1 ) *
2013-04-12 01:30:21 +04:00
sizeof ( xfs_dir2_leaf_entry_t ) ) ;
2011-07-08 16:34:59 +04:00
}
* lfloglow = MIN ( lowstale , * lfloglow ) ;
* lfloghigh = MAX ( index - 1 , * lfloghigh ) ;
2013-04-12 01:30:21 +04:00
leafhdr - > stale - - ;
return & ents [ index - 1 ] ;
2011-07-08 16:34:59 +04:00
}
/*
* The high one is better , so use that one .
*/
ASSERT ( highstale - index > = 0 ) ;
2013-04-12 01:30:21 +04:00
ASSERT ( ents [ highstale ] . address = = cpu_to_be32 ( XFS_DIR2_NULL_DATAPTR ) ) ;
2011-07-08 16:34:59 +04:00
/*
* Copy entries down to cover the stale entry and make room for the
* new entry .
*/
if ( highstale - index > 0 ) {
2013-04-12 01:30:21 +04:00
memmove ( & ents [ index + 1 ] , & ents [ index ] ,
2011-07-08 16:34:59 +04:00
( highstale - index ) * sizeof ( xfs_dir2_leaf_entry_t ) ) ;
}
* lfloglow = MIN ( index , * lfloglow ) ;
* lfloghigh = MAX ( highstale , * lfloghigh ) ;
2013-04-12 01:30:21 +04:00
leafhdr - > stale - - ;
return & ents [ index ] ;
2011-07-08 16:34:59 +04:00
}
2005-04-17 02:20:36 +04:00
/*
* Add an entry to a leaf form directory .
*/
int /* error */
xfs_dir2_leaf_addname (
xfs_da_args_t * args ) /* operation arguments */
{
2006-03-17 09:27:19 +03:00
__be16 * bestsp ; /* freespace table in leaf */
2005-04-17 02:20:36 +04:00
int compact ; /* need to compact leaves */
2011-07-08 16:35:38 +04:00
xfs_dir2_data_hdr_t * hdr ; /* data block header */
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_data_unused_t * dup ; /* data unused entry */
int error ; /* error return value */
int grown ; /* allocated new data block */
int highstale ; /* index of next stale leaf */
int i ; /* temporary, index */
int index ; /* leaf table position */
2012-06-22 12:50:14 +04:00
struct xfs_buf * lbp ; /* leaf's buffer */
2005-04-17 02:20:36 +04:00
xfs_dir2_leaf_t * leaf ; /* leaf structure */
int length ; /* length of new entry */
xfs_dir2_leaf_entry_t * lep ; /* leaf entry table pointer */
int lfloglow ; /* low leaf logging index */
int lfloghigh ; /* high leaf logging index */
int lowstale ; /* index of prev stale leaf */
xfs_dir2_leaf_tail_t * ltp ; /* leaf tail pointer */
xfs_mount_t * mp ; /* filesystem mount point */
int needbytes ; /* leaf block bytes needed */
int needlog ; /* need to log data header */
int needscan ; /* need to rescan data free */
2006-03-17 09:28:27 +03:00
__be16 * tagp ; /* end of data entry */
2005-04-17 02:20:36 +04:00
xfs_trans_t * tp ; /* transaction pointer */
xfs_dir2_db_t use_block ; /* data block number */
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_dir2_leaf_entry * ents ;
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_leaf_addname ( args ) ;
2005-04-17 02:20:36 +04:00
dp = args - > dp ;
tp = args - > trans ;
mp = dp - > i_mount ;
2012-11-12 15:54:15 +04:00
2013-04-12 01:30:21 +04:00
error = xfs_dir3_leaf_read ( tp , dp , mp - > m_dirleafblk , - 1 , & lbp ) ;
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
/*
* Look up the entry by hash value and name .
* We know it ' s not there , our caller has already done a lookup .
* So the index is of the entry to insert in front of .
* But if there are dup hash values the index is of the first of those .
*/
index = xfs_dir2_leaf_search_hash ( args , lbp ) ;
2012-06-22 12:50:14 +04:00
leaf = lbp - > b_addr ;
2007-06-28 10:43:50 +04:00
ltp = xfs_dir2_leaf_tail_p ( mp , leaf ) ;
2013-10-29 15:11:50 +04:00
ents = dp - > d_ops - > leaf_ents_p ( leaf ) ;
2013-10-29 15:11:52 +04:00
dp - > d_ops - > leaf_hdr_from_disk ( & leafhdr , leaf ) ;
2007-06-28 10:43:50 +04:00
bestsp = xfs_dir2_leaf_bests_p ( ltp ) ;
2013-10-29 15:11:48 +04:00
length = dp - > d_ops - > data_entsize ( args - > namelen ) ;
2013-04-12 01:30:21 +04:00
2005-04-17 02:20:36 +04:00
/*
* See if there are any entries with the same hash value
* and space in their block for the new entry .
* This is good because it puts multiple same - hash value entries
* in a data block , improving the lookup of those entries .
*/
2013-04-12 01:30:21 +04:00
for ( use_block = - 1 , lep = & ents [ index ] ;
index < leafhdr . count & & be32_to_cpu ( lep - > hashval ) = = args - > hashval ;
2005-04-17 02:20:36 +04:00
index + + , lep + + ) {
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 ;
2007-06-28 10:43:50 +04:00
i = xfs_dir2_dataptr_to_db ( mp , be32_to_cpu ( lep - > address ) ) ;
2006-03-17 09:27:28 +03:00
ASSERT ( i < be32_to_cpu ( ltp - > bestcount ) ) ;
2011-07-08 16:36:05 +04:00
ASSERT ( bestsp [ i ] ! = cpu_to_be16 ( NULLDATAOFF ) ) ;
2006-03-17 09:27:19 +03:00
if ( be16_to_cpu ( bestsp [ i ] ) > = length ) {
2005-04-17 02:20:36 +04:00
use_block = i ;
break ;
}
}
/*
* Didn ' t find a block yet , linear search all the data blocks .
*/
if ( use_block = = - 1 ) {
2006-03-17 09:27:28 +03:00
for ( i = 0 ; i < be32_to_cpu ( ltp - > bestcount ) ; i + + ) {
2005-04-17 02:20:36 +04:00
/*
* Remember a block we see that ' s missing .
*/
2011-07-08 16:36:05 +04:00
if ( bestsp [ i ] = = cpu_to_be16 ( NULLDATAOFF ) & &
use_block = = - 1 )
2005-04-17 02:20:36 +04:00
use_block = i ;
2006-03-17 09:27:19 +03:00
else if ( be16_to_cpu ( bestsp [ i ] ) > = length ) {
2005-04-17 02:20:36 +04:00
use_block = i ;
break ;
}
}
}
/*
* How many bytes do we need in the leaf block ?
*/
2011-07-08 16:35:53 +04:00
needbytes = 0 ;
2013-04-12 01:30:21 +04:00
if ( ! leafhdr . stale )
2011-07-08 16:35:53 +04:00
needbytes + = sizeof ( xfs_dir2_leaf_entry_t ) ;
if ( use_block = = - 1 )
needbytes + = sizeof ( xfs_dir2_data_off_t ) ;
2005-04-17 02:20:36 +04:00
/*
* Now kill use_block if it refers to a missing block , so we
* can use it as an indication of allocation needed .
*/
2011-07-08 16:36:05 +04:00
if ( use_block ! = - 1 & & bestsp [ use_block ] = = cpu_to_be16 ( NULLDATAOFF ) )
2005-04-17 02:20:36 +04:00
use_block = - 1 ;
/*
* If we don ' t have enough free bytes but we can make enough
* by compacting out stale entries , we ' ll do that .
*/
2013-04-12 01:30:21 +04:00
if ( ( char * ) bestsp - ( char * ) & ents [ leafhdr . count ] < needbytes & &
leafhdr . stale > 1 )
2005-04-17 02:20:36 +04:00
compact = 1 ;
2013-04-12 01:30:21 +04:00
2005-04-17 02:20:36 +04:00
/*
* Otherwise if we don ' t have enough free bytes we need to
* convert to node form .
*/
2013-04-12 01:30:21 +04:00
else if ( ( char * ) bestsp - ( char * ) & ents [ leafhdr . count ] < needbytes ) {
2005-04-17 02:20:36 +04:00
/*
* Just checking or no space reservation , give up .
*/
2008-05-21 10:42:05 +04:00
if ( ( args - > op_flags & XFS_DA_OP_JUSTCHECK ) | |
args - > total = = 0 ) {
2012-06-22 12:50:14 +04:00
xfs_trans_brelse ( tp , lbp ) ;
2005-04-17 02:20:36 +04:00
return XFS_ERROR ( ENOSPC ) ;
}
/*
* Convert to node form .
*/
error = xfs_dir2_leaf_to_node ( args , lbp ) ;
if ( error )
return error ;
/*
* Then add the new entry .
*/
return xfs_dir2_node_addname ( args ) ;
}
/*
* Otherwise it will fit without compaction .
*/
else
compact = 0 ;
/*
* If just checking , then it will fit unless we needed to allocate
* a new data block .
*/
2008-05-21 10:42:05 +04:00
if ( args - > op_flags & XFS_DA_OP_JUSTCHECK ) {
2012-06-22 12:50:14 +04:00
xfs_trans_brelse ( tp , lbp ) ;
2005-04-17 02:20:36 +04:00
return use_block = = - 1 ? XFS_ERROR ( ENOSPC ) : 0 ;
}
/*
* If no allocations are allowed , return now before we ' ve
* changed anything .
*/
if ( args - > total = = 0 & & use_block = = - 1 ) {
2012-06-22 12:50:14 +04:00
xfs_trans_brelse ( tp , lbp ) ;
2005-04-17 02:20:36 +04:00
return XFS_ERROR ( ENOSPC ) ;
}
/*
* Need to compact the leaf entries , removing stale ones .
* Leave one stale entry behind - the one closest to our
* insertion index - and we ' ll shift that one to our insertion
* point later .
*/
if ( compact ) {
2013-04-12 01:30:21 +04:00
xfs_dir3_leaf_compact_x1 ( & leafhdr , ents , & index , & lowstale ,
& highstale , & lfloglow , & lfloghigh ) ;
2005-04-17 02:20:36 +04:00
}
/*
* There are stale entries , so we ' ll need log - low and log - high
* impossibly bad values later .
*/
2013-04-12 01:30:21 +04:00
else if ( leafhdr . stale ) {
lfloglow = leafhdr . count ;
2005-04-17 02:20:36 +04:00
lfloghigh = - 1 ;
}
/*
* If there was no data block space found , we need to allocate
* a new one .
*/
if ( use_block = = - 1 ) {
/*
* Add the new data block .
*/
if ( ( error = xfs_dir2_grow_inode ( args , XFS_DIR2_DATA_SPACE ,
& use_block ) ) ) {
2012-06-22 12:50:14 +04:00
xfs_trans_brelse ( tp , lbp ) ;
2005-04-17 02:20:36 +04:00
return error ;
}
/*
* Initialize the block .
*/
2013-04-03 09:11:20 +04:00
if ( ( error = xfs_dir3_data_init ( args , use_block , & dbp ) ) ) {
2012-06-22 12:50:14 +04:00
xfs_trans_brelse ( tp , lbp ) ;
2005-04-17 02:20:36 +04:00
return error ;
}
/*
* If we ' re adding a new data block on the end we need to
* extend the bests table . Copy it up one entry .
*/
2006-03-17 09:27:28 +03:00
if ( use_block > = be32_to_cpu ( ltp - > bestcount ) ) {
2005-04-17 02:20:36 +04:00
bestsp - - ;
memmove ( & bestsp [ 0 ] , & bestsp [ 1 ] ,
2006-03-17 09:27:28 +03:00
be32_to_cpu ( ltp - > bestcount ) * sizeof ( bestsp [ 0 ] ) ) ;
2008-02-14 02:03:29 +03:00
be32_add_cpu ( & ltp - > bestcount , 1 ) ;
2013-04-12 01:30:21 +04:00
xfs_dir3_leaf_log_tail ( tp , lbp ) ;
xfs_dir3_leaf_log_bests ( tp , lbp , 0 , be32_to_cpu ( ltp - > bestcount ) - 1 ) ;
2005-04-17 02:20:36 +04:00
}
/*
* If we ' re filling in a previously empty block just log it .
*/
else
2013-04-12 01:30:21 +04:00
xfs_dir3_leaf_log_bests ( tp , lbp , use_block , use_block ) ;
2012-06-22 12:50:14 +04:00
hdr = dbp - > b_addr ;
2013-10-29 15:11:49 +04:00
bf = dp - > d_ops - > data_bestfree_p ( hdr ) ;
2013-04-03 09:11:22 +04:00
bestsp [ use_block ] = bf [ 0 ] . length ;
2005-04-17 02:20:36 +04:00
grown = 1 ;
2012-11-12 15:54:14 +04:00
} else {
/*
* Already had space in some data block .
* Just read that one in .
*/
2013-04-03 09:11:22 +04:00
error = xfs_dir3_data_read ( tp , dp ,
2012-11-12 15:54:14 +04:00
xfs_dir2_db_to_da ( mp , use_block ) ,
- 1 , & dbp ) ;
2012-11-12 15:54:10 +04:00
if ( error ) {
2012-06-22 12:50:14 +04:00
xfs_trans_brelse ( tp , lbp ) ;
2005-04-17 02:20:36 +04:00
return error ;
}
2012-06-22 12:50:14 +04:00
hdr = dbp - > b_addr ;
2013-10-29 15:11:49 +04:00
bf = dp - > d_ops - > data_bestfree_p ( hdr ) ;
2005-04-17 02:20:36 +04:00
grown = 0 ;
}
/*
* Point to the biggest freespace in our data block .
*/
dup = ( xfs_dir2_data_unused_t * )
2013-04-03 09:11:22 +04:00
( ( char * ) hdr + be16_to_cpu ( bf [ 0 ] . offset ) ) ;
2006-03-17 09:27:37 +03:00
ASSERT ( be16_to_cpu ( dup - > length ) > = length ) ;
2005-04-17 02:20:36 +04:00
needscan = needlog = 0 ;
/*
* Mark the initial part of our freespace in use for the new entry .
*/
2013-10-29 15:11:49 +04:00
xfs_dir2_data_use_free ( tp , dp , dbp , dup ,
2011-07-08 16:35:38 +04:00
( xfs_dir2_data_aoff_t ) ( ( char * ) dup - ( char * ) hdr ) , length ,
2005-04-17 02:20:36 +04:00
& needlog , & needscan ) ;
/*
* Initialize our new entry ( at last ) .
*/
dep = ( xfs_dir2_data_entry_t * ) dup ;
2006-06-09 08:48:37 +04:00
dep - > inumber = cpu_to_be64 ( args - > inumber ) ;
2005-04-17 02:20:36 +04:00
dep - > namelen = args - > namelen ;
memcpy ( dep - > name , args - > name , dep - > namelen ) ;
2013-10-29 15:11:48 +04:00
dp - > d_ops - > data_put_ftype ( dep , args - > filetype ) ;
tagp = dp - > d_ops - > data_entry_tag_p ( dep ) ;
2011-07-08 16:35:38 +04:00
* tagp = cpu_to_be16 ( ( char * ) dep - ( char * ) hdr ) ;
2005-04-17 02:20:36 +04:00
/*
* Need to scan fix up the bestfree table .
*/
if ( needscan )
2013-10-29 15:11:48 +04:00
xfs_dir2_data_freescan ( dp , hdr , & needlog ) ;
2005-04-17 02:20:36 +04:00
/*
* Need to log the data block ' s header .
*/
if ( needlog )
2013-10-29 15:11:49 +04:00
xfs_dir2_data_log_header ( tp , dp , dbp ) ;
2013-10-29 15:11:48 +04:00
xfs_dir2_data_log_entry ( tp , dp , dbp , dep ) ;
2005-04-17 02:20:36 +04:00
/*
* If the bests table needs to be changed , do it .
* Log the change unless we ' ve already done that .
*/
2013-04-03 09:11:22 +04:00
if ( be16_to_cpu ( bestsp [ use_block ] ) ! = be16_to_cpu ( bf [ 0 ] . length ) ) {
bestsp [ use_block ] = bf [ 0 ] . length ;
2005-04-17 02:20:36 +04:00
if ( ! grown )
2013-04-12 01:30:21 +04:00
xfs_dir3_leaf_log_bests ( tp , lbp , use_block , use_block ) ;
2005-04-17 02:20:36 +04:00
}
2011-07-08 16:34:59 +04:00
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 ) ;
2005-04-17 02:20:36 +04:00
/*
* Fill in the new leaf entry .
*/
2006-03-17 09:28:18 +03:00
lep - > hashval = cpu_to_be32 ( args - > hashval ) ;
2007-06-28 10:43:50 +04:00
lep - > address = cpu_to_be32 ( xfs_dir2_db_off_to_dataptr ( mp , use_block ,
2006-03-17 09:28:27 +03:00
be16_to_cpu ( * tagp ) ) ) ;
2005-04-17 02:20:36 +04:00
/*
* Log the leaf fields and give up the buffers .
*/
2013-10-29 15:11:52 +04:00
dp - > d_ops - > leaf_hdr_to_disk ( leaf , & leafhdr ) ;
2013-10-29 15:11:50 +04:00
xfs_dir3_leaf_log_header ( tp , dp , lbp ) ;
xfs_dir3_leaf_log_ents ( tp , dp , lbp , lfloglow , lfloghigh ) ;
xfs_dir3_leaf_check ( dp , lbp ) ;
2013-04-03 09:11:22 +04:00
xfs_dir3_data_check ( dp , dbp ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
/*
* Compact out any stale entries in the leaf .
* Log the header and changed leaf entries , if any .
*/
void
2013-04-12 01:30:21 +04:00
xfs_dir3_leaf_compact (
2005-04-17 02:20:36 +04:00
xfs_da_args_t * args , /* operation arguments */
2013-04-12 01:30:21 +04:00
struct xfs_dir3_icleaf_hdr * leafhdr ,
2012-06-22 12:50:14 +04:00
struct xfs_buf * bp ) /* leaf buffer */
2005-04-17 02:20:36 +04:00
{
int from ; /* source leaf index */
xfs_dir2_leaf_t * leaf ; /* leaf structure */
int loglow ; /* first leaf entry to log */
int to ; /* target leaf index */
2013-04-12 01:30:21 +04:00
struct xfs_dir2_leaf_entry * ents ;
2013-10-29 15:11:52 +04:00
struct xfs_inode * dp = args - > dp ;
2005-04-17 02:20:36 +04:00
2012-06-22 12:50:14 +04:00
leaf = bp - > b_addr ;
2013-04-12 01:30:21 +04:00
if ( ! leafhdr - > stale )
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
/*
* Compress out the stale entries in place .
*/
2013-10-29 15:11:52 +04:00
ents = dp - > d_ops - > leaf_ents_p ( leaf ) ;
2013-04-12 01:30:21 +04:00
for ( from = to = 0 , loglow = - 1 ; from < leafhdr - > count ; from + + ) {
if ( ents [ from ] . address = = cpu_to_be32 ( XFS_DIR2_NULL_DATAPTR ) )
2005-04-17 02:20:36 +04:00
continue ;
/*
* Only actually copy the entries that are different .
*/
if ( from > to ) {
if ( loglow = = - 1 )
loglow = to ;
2013-04-12 01:30:21 +04:00
ents [ to ] = ents [ from ] ;
2005-04-17 02:20:36 +04:00
}
to + + ;
}
/*
* Update and log the header , log the leaf entries .
*/
2013-04-12 01:30:21 +04:00
ASSERT ( leafhdr - > stale = = from - to ) ;
leafhdr - > count - = leafhdr - > stale ;
leafhdr - > stale = 0 ;
2013-10-29 15:11:52 +04:00
dp - > d_ops - > leaf_hdr_to_disk ( leaf , leafhdr ) ;
xfs_dir3_leaf_log_header ( args - > trans , dp , bp ) ;
2005-04-17 02:20:36 +04:00
if ( loglow ! = - 1 )
2013-10-29 15:11:52 +04:00
xfs_dir3_leaf_log_ents ( args - > trans , dp , bp , loglow , to - 1 ) ;
2005-04-17 02:20:36 +04:00
}
/*
* Compact the leaf entries , removing stale ones .
* Leave one stale entry behind - the one closest to our
* insertion index - and the caller will shift that one to our insertion
* point later .
* Return new insertion index , where the remaining stale entry is ,
* and leaf logging indices .
*/
void
2013-04-12 01:30:21 +04:00
xfs_dir3_leaf_compact_x1 (
struct xfs_dir3_icleaf_hdr * leafhdr ,
struct xfs_dir2_leaf_entry * ents ,
2005-04-17 02:20:36 +04:00
int * indexp , /* insertion index */
int * lowstalep , /* out: stale entry before us */
int * highstalep , /* out: stale entry after us */
int * lowlogp , /* out: low log index */
int * highlogp ) /* out: high log index */
{
int from ; /* source copy index */
int highstale ; /* stale entry at/after index */
int index ; /* insertion index */
int keepstale ; /* source index of kept stale */
int lowstale ; /* stale entry before index */
int newindex = 0 ; /* new insertion index */
int to ; /* destination copy index */
2013-04-12 01:30:21 +04:00
ASSERT ( leafhdr - > stale > 1 ) ;
2005-04-17 02:20:36 +04:00
index = * indexp ;
2011-07-13 15:43:48 +04:00
2013-04-12 01:30:21 +04:00
xfs_dir3_leaf_find_stale ( leafhdr , ents , index , & lowstale , & highstale ) ;
2011-07-13 15:43:48 +04:00
2005-04-17 02:20:36 +04:00
/*
* Pick the better of lowstale and highstale .
*/
if ( lowstale > = 0 & &
2013-04-12 01:30:21 +04:00
( highstale = = leafhdr - > count | |
2005-04-17 02:20:36 +04:00
index - lowstale < = highstale - index ) )
keepstale = lowstale ;
else
keepstale = highstale ;
/*
* Copy the entries in place , removing all the stale entries
* except keepstale .
*/
2013-04-12 01:30:21 +04:00
for ( from = to = 0 ; from < leafhdr - > count ; from + + ) {
2005-04-17 02:20:36 +04:00
/*
* Notice the new value of index .
*/
if ( index = = from )
newindex = to ;
if ( from ! = keepstale & &
2013-04-12 01:30:21 +04:00
ents [ from ] . address = = cpu_to_be32 ( XFS_DIR2_NULL_DATAPTR ) ) {
2005-04-17 02:20:36 +04:00
if ( from = = to )
* lowlogp = to ;
continue ;
}
/*
* Record the new keepstale value for the insertion .
*/
if ( from = = keepstale )
lowstale = highstale = to ;
/*
* Copy only the entries that have moved .
*/
if ( from > to )
2013-04-12 01:30:21 +04:00
ents [ to ] = ents [ from ] ;
2005-04-17 02:20:36 +04:00
to + + ;
}
ASSERT ( from > to ) ;
/*
* If the insertion point was past the last entry ,
* set the new insertion point accordingly .
*/
if ( index = = from )
newindex = to ;
* indexp = newindex ;
/*
* Adjust the leaf header values .
*/
2013-04-12 01:30:21 +04:00
leafhdr - > count - = from - to ;
leafhdr - > stale = 1 ;
2005-04-17 02:20:36 +04:00
/*
* Remember the low / high stale value only in the " right "
* direction .
*/
if ( lowstale > = newindex )
lowstale = - 1 ;
else
2013-04-12 01:30:21 +04:00
highstale = leafhdr - > count ;
* highlogp = leafhdr - > count - 1 ;
2005-04-17 02:20:36 +04:00
* lowstalep = lowstale ;
* highstalep = highstale ;
}
/*
* Log the bests entries indicated from a leaf1 block .
*/
2005-06-21 09:36:52 +04:00
static void
2013-04-12 01:30:21 +04:00
xfs_dir3_leaf_log_bests (
2005-04-17 02:20:36 +04:00
xfs_trans_t * tp , /* transaction pointer */
2012-06-22 12:50:14 +04:00
struct xfs_buf * bp , /* leaf buffer */
2005-04-17 02:20:36 +04:00
int first , /* first entry to log */
int last ) /* last entry to log */
{
2006-03-17 09:27:19 +03:00
__be16 * firstb ; /* pointer to first entry */
__be16 * lastb ; /* pointer to last entry */
2013-04-12 01:30:21 +04:00
struct xfs_dir2_leaf * leaf = bp - > b_addr ;
2005-04-17 02:20:36 +04:00
xfs_dir2_leaf_tail_t * ltp ; /* leaf tail structure */
2013-04-12 01:30:21 +04:00
ASSERT ( leaf - > hdr . info . magic = = cpu_to_be16 ( XFS_DIR2_LEAF1_MAGIC ) | |
leaf - > hdr . info . magic = = cpu_to_be16 ( XFS_DIR3_LEAF1_MAGIC ) ) ;
2007-06-28 10:43:50 +04:00
ltp = xfs_dir2_leaf_tail_p ( tp - > t_mountp , leaf ) ;
firstb = xfs_dir2_leaf_bests_p ( ltp ) + first ;
lastb = xfs_dir2_leaf_bests_p ( ltp ) + last ;
2012-06-22 12:50:14 +04:00
xfs_trans_log_buf ( tp , bp , ( uint ) ( ( char * ) firstb - ( char * ) leaf ) ,
2005-04-17 02:20:36 +04:00
( uint ) ( ( char * ) lastb - ( char * ) leaf + sizeof ( * lastb ) - 1 ) ) ;
}
/*
* Log the leaf entries indicated from a leaf1 or leafn block .
*/
void
2013-04-12 01:30:21 +04:00
xfs_dir3_leaf_log_ents (
2013-10-29 15:11:50 +04:00
struct xfs_trans * tp ,
struct xfs_inode * dp ,
struct xfs_buf * bp ,
int first ,
int last )
2005-04-17 02:20:36 +04:00
{
xfs_dir2_leaf_entry_t * firstlep ; /* pointer to first entry */
xfs_dir2_leaf_entry_t * lastlep ; /* pointer to last entry */
2013-04-12 01:30:21 +04:00
struct xfs_dir2_leaf * leaf = bp - > b_addr ;
struct xfs_dir2_leaf_entry * ents ;
2005-04-17 02:20:36 +04:00
2011-07-08 16:36:05 +04:00
ASSERT ( leaf - > hdr . info . magic = = cpu_to_be16 ( XFS_DIR2_LEAF1_MAGIC ) | |
2013-04-12 01:30:21 +04:00
leaf - > hdr . info . magic = = cpu_to_be16 ( XFS_DIR3_LEAF1_MAGIC ) | |
leaf - > hdr . info . magic = = cpu_to_be16 ( XFS_DIR2_LEAFN_MAGIC ) | |
leaf - > hdr . info . magic = = cpu_to_be16 ( XFS_DIR3_LEAFN_MAGIC ) ) ;
2013-10-29 15:11:50 +04:00
ents = dp - > d_ops - > leaf_ents_p ( leaf ) ;
2013-04-12 01:30:21 +04:00
firstlep = & ents [ first ] ;
lastlep = & ents [ last ] ;
2012-06-22 12:50:14 +04:00
xfs_trans_log_buf ( tp , bp , ( uint ) ( ( char * ) firstlep - ( char * ) leaf ) ,
2005-04-17 02:20:36 +04:00
( uint ) ( ( char * ) lastlep - ( char * ) leaf + sizeof ( * lastlep ) - 1 ) ) ;
}
/*
* Log the header of the leaf1 or leafn block .
*/
void
2013-04-12 01:30:21 +04:00
xfs_dir3_leaf_log_header (
2012-06-22 12:50:14 +04:00
struct xfs_trans * tp ,
2013-10-29 15:11:50 +04:00
struct xfs_inode * dp ,
2012-06-22 12:50:14 +04:00
struct xfs_buf * bp )
2005-04-17 02:20:36 +04:00
{
2013-04-12 01:30:21 +04:00
struct xfs_dir2_leaf * leaf = bp - > b_addr ;
2005-04-17 02:20:36 +04:00
2011-07-08 16:36:05 +04:00
ASSERT ( leaf - > hdr . info . magic = = cpu_to_be16 ( XFS_DIR2_LEAF1_MAGIC ) | |
2013-04-12 01:30:21 +04:00
leaf - > hdr . info . magic = = cpu_to_be16 ( XFS_DIR3_LEAF1_MAGIC ) | |
leaf - > hdr . info . magic = = cpu_to_be16 ( XFS_DIR2_LEAFN_MAGIC ) | |
leaf - > hdr . info . magic = = cpu_to_be16 ( XFS_DIR3_LEAFN_MAGIC ) ) ;
2012-06-22 12:50:14 +04:00
xfs_trans_log_buf ( tp , bp , ( uint ) ( ( char * ) & leaf - > hdr - ( char * ) leaf ) ,
2013-10-30 02:15:02 +04:00
dp - > d_ops - > leaf_hdr_size - 1 ) ;
2005-04-17 02:20:36 +04:00
}
/*
* Log the tail of the leaf1 block .
*/
2005-06-21 09:36:52 +04:00
STATIC void
2013-04-12 01:30:21 +04:00
xfs_dir3_leaf_log_tail (
2012-06-22 12:50:14 +04:00
struct xfs_trans * tp ,
struct xfs_buf * bp )
2005-04-17 02:20:36 +04:00
{
2013-04-12 01:30:21 +04:00
struct xfs_dir2_leaf * leaf = bp - > b_addr ;
2005-04-17 02:20:36 +04:00
xfs_dir2_leaf_tail_t * ltp ; /* leaf tail structure */
2013-04-12 01:30:21 +04:00
struct xfs_mount * mp = tp - > t_mountp ;
ASSERT ( leaf - > hdr . info . magic = = cpu_to_be16 ( XFS_DIR2_LEAF1_MAGIC ) | |
leaf - > hdr . info . magic = = cpu_to_be16 ( XFS_DIR3_LEAF1_MAGIC ) | |
leaf - > hdr . info . magic = = cpu_to_be16 ( XFS_DIR2_LEAFN_MAGIC ) | |
leaf - > hdr . info . magic = = cpu_to_be16 ( XFS_DIR3_LEAFN_MAGIC ) ) ;
2005-04-17 02:20:36 +04:00
2007-06-28 10:43:50 +04:00
ltp = xfs_dir2_leaf_tail_p ( mp , leaf ) ;
2012-06-22 12:50:14 +04:00
xfs_trans_log_buf ( tp , bp , ( uint ) ( ( char * ) ltp - ( char * ) leaf ) ,
2005-04-17 02:20:36 +04:00
( uint ) ( mp - > m_dirblksize - 1 ) ) ;
}
/*
* Look up the entry referred to by args in the leaf format directory .
* Most of the work is done by the xfs_dir2_leaf_lookup_int routine which
* is also used by the node - format code .
*/
int
xfs_dir2_leaf_lookup (
xfs_da_args_t * args ) /* operation arguments */
{
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 */
int error ; /* error return code */
int index ; /* found entry index */
2012-06-22 12:50:14 +04:00
struct xfs_buf * lbp ; /* leaf buffer */
2005-04-17 02:20:36 +04:00
xfs_dir2_leaf_t * leaf ; /* leaf structure */
xfs_dir2_leaf_entry_t * lep ; /* leaf entry */
xfs_trans_t * tp ; /* transaction pointer */
2013-04-12 01:30:21 +04:00
struct xfs_dir2_leaf_entry * ents ;
2005-04-17 02:20:36 +04:00
2009-12-15 02:14:59 +03:00
trace_xfs_dir2_leaf_lookup ( args ) ;
2005-04-17 02:20:36 +04:00
/*
* Look up name in the leaf block , returning both buffers and index .
*/
if ( ( error = xfs_dir2_leaf_lookup_int ( args , & lbp , & index , & dbp ) ) ) {
return error ;
}
tp = args - > trans ;
dp = args - > dp ;
2013-10-29 15:11:50 +04:00
xfs_dir3_leaf_check ( dp , lbp ) ;
2012-06-22 12:50:14 +04:00
leaf = lbp - > b_addr ;
2013-10-29 15:11:50 +04:00
ents = dp - > d_ops - > leaf_ents_p ( leaf ) ;
2005-04-17 02:20:36 +04:00
/*
* Get to the leaf entry and contained data entry address .
*/
2013-04-12 01:30:21 +04:00
lep = & ents [ index ] ;
2005-04-17 02:20:36 +04:00
/*
* Point to the data entry .
*/
dep = ( xfs_dir2_data_entry_t * )
2012-06-22 12:50:14 +04:00
( ( char * ) dbp - > b_addr +
2007-06-28 10:43:50 +04:00
xfs_dir2_dataptr_to_off ( dp - > i_mount , be32_to_cpu ( lep - > address ) ) ) ;
2005-04-17 02:20:36 +04:00
/*
2008-05-21 10:58:22 +04:00
* Return the found inode number & CI name if appropriate
2005-04-17 02:20:36 +04:00
*/
2006-06-09 08:48:37 +04:00
args - > inumber = be64_to_cpu ( dep - > inumber ) ;
2013-10-29 15:11:48 +04:00
args - > filetype = dp - > d_ops - > data_get_ftype ( dep ) ;
2008-05-21 10:58:22 +04:00
error = xfs_dir_cilookup_result ( args , dep - > name , dep - > namelen ) ;
2012-06-22 12:50:14 +04:00
xfs_trans_brelse ( tp , dbp ) ;
xfs_trans_brelse ( tp , lbp ) ;
2008-05-21 10:58:22 +04:00
return XFS_ERROR ( error ) ;
2005-04-17 02:20:36 +04:00
}
/*
* Look up name / hash in the leaf block .
* Fill in indexp with the found index , and dbpp with the data buffer .
* If not found dbpp will be NULL , and ENOENT comes back .
* lbpp will always be filled in with the leaf buffer unless there ' s an error .
*/
static int /* error */
xfs_dir2_leaf_lookup_int (
xfs_da_args_t * args , /* operation arguments */
2012-06-22 12:50:14 +04:00
struct xfs_buf * * lbpp , /* out: leaf buffer */
2005-04-17 02:20:36 +04:00
int * indexp , /* out: index in leaf block */
2012-06-22 12:50:14 +04:00
struct xfs_buf * * dbpp ) /* out: data buffer */
2005-04-17 02:20:36 +04:00
{
2008-06-27 07:32:11 +04:00
xfs_dir2_db_t curdb = - 1 ; /* current data block number */
2012-06-22 12:50:14 +04:00
struct xfs_buf * dbp = NULL ; /* data buffer */
2005-04-17 02:20:36 +04:00
xfs_dir2_data_entry_t * dep ; /* data entry */
xfs_inode_t * dp ; /* incore directory inode */
int error ; /* error return code */
int index ; /* index in leaf block */
2012-06-22 12:50:14 +04:00
struct xfs_buf * lbp ; /* leaf buffer */
2005-04-17 02:20:36 +04:00
xfs_dir2_leaf_entry_t * lep ; /* leaf entry */
xfs_dir2_leaf_t * leaf ; /* leaf structure */
xfs_mount_t * mp ; /* filesystem mount point */
xfs_dir2_db_t newdb ; /* new data block number */
xfs_trans_t * tp ; /* transaction pointer */
2008-06-27 07:32:11 +04:00
xfs_dir2_db_t cidb = - 1 ; /* case match data block no. */
2008-05-21 10:41:01 +04:00
enum xfs_dacmp cmp ; /* name compare result */
2013-04-12 01:30:21 +04:00
struct xfs_dir2_leaf_entry * ents ;
struct xfs_dir3_icleaf_hdr leafhdr ;
2005-04-17 02:20:36 +04:00
dp = args - > dp ;
tp = args - > trans ;
mp = dp - > i_mount ;
2012-11-12 15:54:15 +04:00
2013-04-12 01:30:21 +04:00
error = xfs_dir3_leaf_read ( tp , dp , mp - > m_dirleafblk , - 1 , & lbp ) ;
2008-06-27 07:32:11 +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
* lbpp = lbp ;
2012-06-22 12:50:14 +04:00
leaf = lbp - > b_addr ;
2013-10-29 15:11:50 +04:00
xfs_dir3_leaf_check ( dp , lbp ) ;
ents = dp - > d_ops - > leaf_ents_p ( leaf ) ;
2013-10-29 15:11:52 +04:00
dp - > d_ops - > leaf_hdr_from_disk ( & leafhdr , leaf ) ;
2013-04-12 01:30:21 +04:00
2005-04-17 02:20:36 +04:00
/*
* Look for the first leaf entry with our hash value .
*/
index = xfs_dir2_leaf_search_hash ( args , lbp ) ;
/*
* Loop over all the entries with the right hash value
* looking to match the name .
*/
2013-04-12 01:30:21 +04:00
for ( lep = & ents [ index ] ;
index < leafhdr . count & & be32_to_cpu ( lep - > hashval ) = = args - > hashval ;
lep + + , index + + ) {
2005-04-17 02:20:36 +04:00
/*
* Skip over 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 ;
/*
* Get the new data block number .
*/
2007-06-28 10:43:50 +04:00
newdb = xfs_dir2_dataptr_to_db ( mp , be32_to_cpu ( lep - > address ) ) ;
2005-04-17 02:20:36 +04:00
/*
* If it ' s not the same as the old data block number ,
* need to pitch the old one and read the new one .
*/
if ( newdb ! = curdb ) {
2008-06-27 07:32:11 +04:00
if ( dbp )
2012-06-22 12:50:14 +04:00
xfs_trans_brelse ( tp , dbp ) ;
2013-04-03 09:11:22 +04:00
error = xfs_dir3_data_read ( tp , dp ,
2012-11-12 15:54:14 +04:00
xfs_dir2_db_to_da ( mp , newdb ) ,
- 1 , & dbp ) ;
2008-05-21 10:41:01 +04:00
if ( error ) {
2012-06-22 12:50:14 +04:00
xfs_trans_brelse ( tp , lbp ) ;
2005-04-17 02:20:36 +04:00
return error ;
}
curdb = newdb ;
}
/*
* Point to the data entry .
*/
2012-06-22 12:50:14 +04:00
dep = ( xfs_dir2_data_entry_t * ) ( ( char * ) dbp - > b_addr +
2008-05-21 10:41:01 +04:00
xfs_dir2_dataptr_to_off ( mp , be32_to_cpu ( lep - > address ) ) ) ;
2005-04-17 02:20:36 +04:00
/*
2008-05-21 10:41:01 +04:00
* Compare name and if it ' s an exact match , return the index
* and buffer . If it ' s the first case - insensitive match , store
* the index and buffer and continue looking for an exact match .
2005-04-17 02:20:36 +04:00
*/
2008-05-21 10:41:01 +04:00
cmp = mp - > m_dirnameops - > compname ( args , dep - > name , dep - > namelen ) ;
if ( cmp ! = XFS_CMP_DIFFERENT & & cmp ! = args - > cmpresult ) {
args - > cmpresult = cmp ;
2005-04-17 02:20:36 +04:00
* indexp = index ;
2008-06-27 07:32:11 +04:00
/* case exact match: return the current buffer. */
2008-05-21 10:41:01 +04:00
if ( cmp = = XFS_CMP_EXACT ) {
* dbpp = dbp ;
return 0 ;
}
2008-06-27 07:32:11 +04:00
cidb = curdb ;
2005-04-17 02:20:36 +04:00
}
}
2008-05-21 10:42:05 +04:00
ASSERT ( args - > op_flags & XFS_DA_OP_OKNOENT ) ;
2008-05-21 10:41:01 +04:00
/*
2008-06-27 07:32:11 +04:00
* Here , we can only be doing a lookup ( not a rename or remove ) .
* If a case - insensitive match was found earlier , re - read the
* appropriate data block if required and return it .
2008-05-21 10:41:01 +04:00
*/
if ( args - > cmpresult = = XFS_CMP_CASE ) {
2008-06-27 07:32:11 +04:00
ASSERT ( cidb ! = - 1 ) ;
if ( cidb ! = curdb ) {
2012-06-22 12:50:14 +04:00
xfs_trans_brelse ( tp , dbp ) ;
2013-04-03 09:11:22 +04:00
error = xfs_dir3_data_read ( tp , dp ,
2012-11-12 15:54:14 +04:00
xfs_dir2_db_to_da ( mp , cidb ) ,
- 1 , & dbp ) ;
2008-06-27 07:32:11 +04:00
if ( error ) {
2012-06-22 12:50:14 +04:00
xfs_trans_brelse ( tp , lbp ) ;
2008-06-27 07:32:11 +04:00
return error ;
}
}
* dbpp = dbp ;
2008-05-21 10:41:01 +04:00
return 0 ;
}
2005-04-17 02:20:36 +04:00
/*
* No match found , return ENOENT .
*/
2008-06-27 07:32:11 +04:00
ASSERT ( cidb = = - 1 ) ;
2005-04-17 02:20:36 +04:00
if ( dbp )
2012-06-22 12:50:14 +04:00
xfs_trans_brelse ( tp , dbp ) ;
xfs_trans_brelse ( tp , lbp ) ;
2005-04-17 02:20:36 +04:00
return XFS_ERROR ( ENOENT ) ;
}
/*
* Remove an entry from a leaf format directory .
*/
int /* error */
xfs_dir2_leaf_removename (
xfs_da_args_t * args ) /* operation arguments */
{
2006-03-17 09:27:19 +03:00
__be16 * bestsp ; /* leaf block best freespace */
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 entry structure */
xfs_inode_t * dp ; /* incore directory inode */
int error ; /* error return code */
xfs_dir2_db_t i ; /* temporary data block # */
int index ; /* index into leaf entries */
2012-06-22 12:50:14 +04:00
struct xfs_buf * lbp ; /* leaf buffer */
2005-04-17 02:20:36 +04:00
xfs_dir2_leaf_t * leaf ; /* leaf structure */
xfs_dir2_leaf_entry_t * lep ; /* leaf entry */
xfs_dir2_leaf_tail_t * ltp ; /* leaf tail structure */
xfs_mount_t * mp ; /* filesystem mount point */
int needlog ; /* need to log data header */
int needscan ; /* need to rescan data frees */
xfs_dir2_data_off_t oldbest ; /* old value of best free */
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_dir2_leaf_entry * ents ;
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_leaf_removename ( args ) ;
2005-04-17 02:20:36 +04:00
/*
* Lookup the leaf entry , get the leaf and data blocks read in .
*/
if ( ( error = xfs_dir2_leaf_lookup_int ( args , & lbp , & index , & dbp ) ) ) {
return error ;
}
dp = args - > dp ;
tp = args - > trans ;
mp = dp - > i_mount ;
2012-06-22 12:50:14 +04:00
leaf = lbp - > b_addr ;
hdr = dbp - > b_addr ;
2013-04-03 09:11:22 +04:00
xfs_dir3_data_check ( dp , dbp ) ;
2013-10-29 15:11:49 +04:00
bf = dp - > d_ops - > data_bestfree_p ( hdr ) ;
2013-10-29 15:11:52 +04:00
dp - > d_ops - > leaf_hdr_from_disk ( & leafhdr , leaf ) ;
2013-10-29 15:11:50 +04:00
ents = dp - > d_ops - > leaf_ents_p ( leaf ) ;
2005-04-17 02:20:36 +04:00
/*
* Point to the leaf entry , use that to point to the data entry .
*/
2013-04-12 01:30:21 +04:00
lep = & ents [ index ] ;
2007-06-28 10:43:50 +04:00
db = xfs_dir2_dataptr_to_db ( mp , be32_to_cpu ( lep - > address ) ) ;
2005-04-17 02:20:36 +04:00
dep = ( xfs_dir2_data_entry_t * )
2011-07-08 16:35:38 +04:00
( ( char * ) hdr + xfs_dir2_dataptr_to_off ( mp , be32_to_cpu ( lep - > address ) ) ) ;
2005-04-17 02:20:36 +04:00
needscan = needlog = 0 ;
2013-04-03 09:11:22 +04:00
oldbest = be16_to_cpu ( bf [ 0 ] . length ) ;
2007-06-28 10:43:50 +04:00
ltp = xfs_dir2_leaf_tail_p ( mp , leaf ) ;
bestsp = xfs_dir2_leaf_bests_p ( ltp ) ;
2006-03-17 09:27:19 +03:00
ASSERT ( be16_to_cpu ( bestsp [ db ] ) = = oldbest ) ;
2005-04-17 02:20:36 +04:00
/*
* Mark the former data entry unused .
*/
2013-10-29 15:11:49 +04:00
xfs_dir2_data_make_free ( tp , dp , dbp ,
2011-07-08 16:35:38 +04:00
( xfs_dir2_data_aoff_t ) ( ( char * ) dep - ( char * ) hdr ) ,
2013-10-29 15:11:48 +04:00
dp - > d_ops - > data_entsize ( dep - > namelen ) , & needlog , & needscan ) ;
2005-04-17 02:20:36 +04:00
/*
* We just mark the leaf entry stale by putting a null in it .
*/
2013-04-12 01:30:21 +04:00
leafhdr . stale + + ;
2013-10-29 15:11:52 +04:00
dp - > d_ops - > leaf_hdr_to_disk ( leaf , & leafhdr ) ;
2013-10-29 15:11:50 +04:00
xfs_dir3_leaf_log_header ( tp , dp , lbp ) ;
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 ) ;
2013-10-29 15:11:50 +04:00
xfs_dir3_leaf_log_ents ( tp , dp , lbp , index , index ) ;
2013-04-12 01:30:21 +04:00
2005-04-17 02:20:36 +04:00
/*
* Scan the freespace in the data block again if necessary ,
* log the data block header if necessary .
*/
if ( needscan )
2013-10-29 15:11:48 +04:00
xfs_dir2_data_freescan ( dp , hdr , & needlog ) ;
2005-04-17 02:20:36 +04:00
if ( needlog )
2013-10-29 15:11:49 +04:00
xfs_dir2_data_log_header ( tp , dp , dbp ) ;
2005-04-17 02:20:36 +04:00
/*
* If the longest freespace in the data block has changed ,
* put the new value in the bests table and log that .
*/
2013-04-03 09:11:22 +04:00
if ( be16_to_cpu ( bf [ 0 ] . length ) ! = oldbest ) {
bestsp [ db ] = bf [ 0 ] . length ;
2013-04-12 01:30:21 +04:00
xfs_dir3_leaf_log_bests ( tp , lbp , db , db ) ;
2005-04-17 02:20:36 +04:00
}
2013-04-03 09:11:22 +04:00
xfs_dir3_data_check ( dp , dbp ) ;
2005-04-17 02:20:36 +04:00
/*
* If the data block is now empty then get rid of the data block .
*/
2013-04-03 09:11:22 +04:00
if ( be16_to_cpu ( bf [ 0 ] . length ) = =
2013-10-30 02:15:02 +04:00
mp - > m_dirblksize - dp - > d_ops - > data_entry_offset ) {
2005-04-17 02:20:36 +04:00
ASSERT ( db ! = mp - > m_dirdatablk ) ;
if ( ( error = xfs_dir2_shrink_inode ( args , db , dbp ) ) ) {
/*
* Nope , can ' t get rid of it because it caused
* allocation of a bmap btree block to do so .
* Just go on , returning success , leaving the
* empty block in place .
*/
2012-06-22 12:50:14 +04:00
if ( error = = ENOSPC & & args - > total = = 0 )
2005-04-17 02:20:36 +04:00
error = 0 ;
2013-10-29 15:11:50 +04:00
xfs_dir3_leaf_check ( dp , lbp ) ;
2005-04-17 02:20:36 +04:00
return error ;
}
dbp = NULL ;
/*
* If this is the last data block then compact the
* bests table by getting rid of entries .
*/
2006-03-17 09:27:28 +03:00
if ( db = = be32_to_cpu ( ltp - > bestcount ) - 1 ) {
2005-04-17 02:20:36 +04:00
/*
* Look for the last active entry ( i ) .
*/
for ( i = db - 1 ; i > 0 ; i - - ) {
2011-07-08 16:36:05 +04:00
if ( bestsp [ i ] ! = cpu_to_be16 ( NULLDATAOFF ) )
2005-04-17 02:20:36 +04:00
break ;
}
/*
* Copy the table down so inactive entries at the
* end are removed .
*/
memmove ( & bestsp [ db - i ] , bestsp ,
2006-03-17 09:27:28 +03:00
( be32_to_cpu ( ltp - > bestcount ) - ( db - i ) ) * sizeof ( * bestsp ) ) ;
2008-02-14 02:03:29 +03:00
be32_add_cpu ( & ltp - > bestcount , - ( db - i ) ) ;
2013-04-12 01:30:21 +04:00
xfs_dir3_leaf_log_tail ( tp , lbp ) ;
xfs_dir3_leaf_log_bests ( tp , lbp , 0 , be32_to_cpu ( ltp - > bestcount ) - 1 ) ;
2005-04-17 02:20:36 +04:00
} else
2006-03-17 09:27:19 +03:00
bestsp [ db ] = cpu_to_be16 ( NULLDATAOFF ) ;
2005-04-17 02:20:36 +04:00
}
/*
* If the data block was not the first one , drop it .
*/
2012-06-22 12:50:14 +04:00
else if ( db ! = mp - > m_dirdatablk )
2005-04-17 02:20:36 +04:00
dbp = NULL ;
2012-06-22 12:50:14 +04:00
2013-10-29 15:11:50 +04:00
xfs_dir3_leaf_check ( dp , lbp ) ;
2005-04-17 02:20:36 +04:00
/*
* See if we can convert to block form .
*/
return xfs_dir2_leaf_to_block ( args , lbp , dbp ) ;
}
/*
* Replace the inode number in a leaf format directory entry .
*/
int /* error */
xfs_dir2_leaf_replace (
xfs_da_args_t * args ) /* operation arguments */
{
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 */
int error ; /* error return code */
int index ; /* index of leaf entry */
2012-06-22 12:50:14 +04:00
struct xfs_buf * lbp ; /* leaf buffer */
2005-04-17 02:20:36 +04:00
xfs_dir2_leaf_t * leaf ; /* leaf structure */
xfs_dir2_leaf_entry_t * lep ; /* leaf entry */
xfs_trans_t * tp ; /* transaction pointer */
2013-04-12 01:30:21 +04:00
struct xfs_dir2_leaf_entry * ents ;
2005-04-17 02:20:36 +04:00
2009-12-15 02:14:59 +03:00
trace_xfs_dir2_leaf_replace ( args ) ;
2005-04-17 02:20:36 +04:00
/*
* Look up the entry .
*/
if ( ( error = xfs_dir2_leaf_lookup_int ( args , & lbp , & index , & dbp ) ) ) {
return error ;
}
dp = args - > dp ;
2012-06-22 12:50:14 +04:00
leaf = lbp - > b_addr ;
2013-10-29 15:11:50 +04:00
ents = dp - > d_ops - > leaf_ents_p ( leaf ) ;
2005-04-17 02:20:36 +04:00
/*
* Point to the leaf entry , get data address from it .
*/
2013-04-12 01:30:21 +04:00
lep = & ents [ index ] ;
2005-04-17 02:20:36 +04:00
/*
* Point to the data entry .
*/
dep = ( xfs_dir2_data_entry_t * )
2012-06-22 12:50:14 +04:00
( ( char * ) dbp - > b_addr +
2007-06-28 10:43:50 +04:00
xfs_dir2_dataptr_to_off ( dp - > i_mount , be32_to_cpu ( lep - > address ) ) ) ;
2006-06-09 08:48:37 +04:00
ASSERT ( args - > inumber ! = be64_to_cpu ( dep - > inumber ) ) ;
2005-04-17 02:20:36 +04:00
/*
* Put the new inode number in , log it .
*/
2006-06-09 08:48:37 +04:00
dep - > inumber = cpu_to_be64 ( args - > inumber ) ;
2013-10-29 15:11:48 +04:00
dp - > d_ops - > data_put_ftype ( dep , args - > filetype ) ;
2005-04-17 02:20:36 +04:00
tp = args - > trans ;
2013-10-29 15:11:48 +04:00
xfs_dir2_data_log_entry ( tp , dp , dbp , dep ) ;
2013-10-29 15:11:50 +04:00
xfs_dir3_leaf_check ( dp , lbp ) ;
2012-06-22 12:50:14 +04:00
xfs_trans_brelse ( tp , lbp ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
/*
* Return index in the leaf block ( lbp ) which is either the first
* one with this hash value , or if there are none , the insert point
* for that hash value .
*/
int /* index value */
xfs_dir2_leaf_search_hash (
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_dahash_t hash = 0 ; /* hash from this entry */
xfs_dahash_t hashwant ; /* hash value looking for */
int high ; /* high leaf index */
int low ; /* low leaf index */
xfs_dir2_leaf_t * leaf ; /* leaf structure */
xfs_dir2_leaf_entry_t * lep ; /* leaf entry */
int mid = 0 ; /* current leaf index */
2013-04-12 01:30:21 +04:00
struct xfs_dir2_leaf_entry * ents ;
struct xfs_dir3_icleaf_hdr leafhdr ;
2005-04-17 02:20:36 +04:00
2012-06-22 12:50:14 +04:00
leaf = lbp - > b_addr ;
2013-10-29 15:11:50 +04:00
ents = args - > dp - > d_ops - > leaf_ents_p ( leaf ) ;
2013-10-29 15:11:52 +04:00
args - > dp - > d_ops - > leaf_hdr_from_disk ( & leafhdr , leaf ) ;
2013-04-12 01:30:21 +04:00
2005-04-17 02:20:36 +04:00
/*
* Note , the table cannot be empty , so we have to go through the loop .
* Binary search the leaf entries looking for our hash value .
*/
2013-04-12 01:30:21 +04:00
for ( lep = ents , low = 0 , high = leafhdr . count - 1 ,
2005-04-17 02:20:36 +04:00
hashwant = args - > hashval ;
low < = high ; ) {
mid = ( low + high ) > > 1 ;
2006-03-17 09:28:18 +03:00
if ( ( hash = be32_to_cpu ( lep [ mid ] . hashval ) ) = = hashwant )
2005-04-17 02:20:36 +04:00
break ;
if ( hash < hashwant )
low = mid + 1 ;
else
high = mid - 1 ;
}
/*
* Found one , back up through all the equal hash values .
*/
if ( hash = = hashwant ) {
2006-03-17 09:28:18 +03:00
while ( mid > 0 & & be32_to_cpu ( lep [ mid - 1 ] . hashval ) = = hashwant ) {
2005-04-17 02:20:36 +04:00
mid - - ;
}
}
/*
* Need to point to an entry higher than ours .
*/
else if ( hash < hashwant )
mid + + ;
return mid ;
}
/*
* Trim off a trailing data block . We know it ' s empty since the leaf
* freespace table says so .
*/
int /* error */
xfs_dir2_leaf_trim_data (
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_dir2_db_t db ) /* data block number */
{
2006-03-17 09:27:19 +03:00
__be16 * bestsp ; /* leaf bests table */
2012-06-22 12:50:14 +04:00
struct xfs_buf * dbp ; /* data block buffer */
2005-04-17 02:20:36 +04:00
xfs_inode_t * dp ; /* incore directory inode */
int error ; /* error return value */
xfs_dir2_leaf_t * leaf ; /* leaf structure */
xfs_dir2_leaf_tail_t * ltp ; /* leaf tail structure */
xfs_mount_t * mp ; /* filesystem mount point */
xfs_trans_t * tp ; /* transaction pointer */
dp = args - > dp ;
mp = dp - > i_mount ;
tp = args - > trans ;
/*
* Read the offending data block . We need its buffer .
*/
2013-04-03 09:11:22 +04:00
error = xfs_dir3_data_read ( tp , dp , xfs_dir2_db_to_da ( mp , db ) , - 1 , & dbp ) ;
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
leaf = lbp - > b_addr ;
2007-06-28 10:43:50 +04:00
ltp = xfs_dir2_leaf_tail_p ( mp , leaf ) ;
2011-07-08 16:35:38 +04:00
# ifdef DEBUG
{
2012-06-22 12:50:14 +04:00
struct xfs_dir2_data_hdr * hdr = dbp - > b_addr ;
2013-10-29 15:11:49 +04:00
struct xfs_dir2_data_free * bf = dp - > d_ops - > data_bestfree_p ( hdr ) ;
2011-07-08 16:35:38 +04:00
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 ) ) ;
ASSERT ( be16_to_cpu ( bf [ 0 ] . length ) = =
2013-10-30 02:15:02 +04:00
mp - > m_dirblksize - dp - > d_ops - > data_entry_offset ) ;
2006-03-17 09:27:28 +03:00
ASSERT ( db = = be32_to_cpu ( ltp - > bestcount ) - 1 ) ;
2011-07-08 16:35:38 +04:00
}
# endif
2005-04-17 02:20:36 +04:00
/*
* Get rid of the data block .
*/
if ( ( error = xfs_dir2_shrink_inode ( args , db , dbp ) ) ) {
ASSERT ( error ! = ENOSPC ) ;
2012-06-22 12:50:14 +04:00
xfs_trans_brelse ( tp , dbp ) ;
2005-04-17 02:20:36 +04:00
return error ;
}
/*
* Eliminate the last bests entry from the table .
*/
2007-06-28 10:43:50 +04:00
bestsp = xfs_dir2_leaf_bests_p ( ltp ) ;
2008-02-14 02:03:29 +03:00
be32_add_cpu ( & ltp - > bestcount , - 1 ) ;
2006-03-17 09:27:28 +03:00
memmove ( & bestsp [ 1 ] , & bestsp [ 0 ] , be32_to_cpu ( ltp - > bestcount ) * sizeof ( * bestsp ) ) ;
2013-04-12 01:30:21 +04:00
xfs_dir3_leaf_log_tail ( tp , lbp ) ;
xfs_dir3_leaf_log_bests ( tp , lbp , 0 , be32_to_cpu ( ltp - > bestcount ) - 1 ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2011-07-08 16:35:53 +04:00
static inline size_t
2013-04-12 01:30:21 +04:00
xfs_dir3_leaf_size (
struct xfs_dir3_icleaf_hdr * hdr ,
2011-07-08 16:35:53 +04:00
int counts )
{
2013-04-12 01:30:21 +04:00
int entries ;
int hdrsize ;
entries = hdr - > count - hdr - > stale ;
if ( hdr - > magic = = XFS_DIR2_LEAF1_MAGIC | |
hdr - > magic = = XFS_DIR2_LEAFN_MAGIC )
hdrsize = sizeof ( struct xfs_dir2_leaf_hdr ) ;
else
hdrsize = sizeof ( struct xfs_dir3_leaf_hdr ) ;
2011-07-08 16:35:53 +04:00
2013-04-12 01:30:21 +04:00
return hdrsize + entries * sizeof ( xfs_dir2_leaf_entry_t )
+ counts * sizeof ( xfs_dir2_data_off_t )
+ sizeof ( xfs_dir2_leaf_tail_t ) ;
2011-07-08 16:35:53 +04:00
}
2005-04-17 02:20:36 +04:00
/*
* Convert node form directory to leaf form directory .
* The root of the node form dir needs to already be a LEAFN block .
* Just return if we can ' t do anything .
*/
int /* error */
xfs_dir2_node_to_leaf (
xfs_da_state_t * state ) /* directory operation state */
{
xfs_da_args_t * args ; /* operation arguments */
xfs_inode_t * dp ; /* incore directory inode */
int error ; /* error return code */
2012-06-22 12:50:14 +04:00
struct xfs_buf * fbp ; /* buffer for freespace block */
2005-04-17 02:20:36 +04:00
xfs_fileoff_t fo ; /* freespace file offset */
xfs_dir2_free_t * free ; /* freespace structure */
2012-06-22 12:50:14 +04:00
struct xfs_buf * lbp ; /* buffer for leaf block */
2005-04-17 02:20:36 +04:00
xfs_dir2_leaf_tail_t * ltp ; /* tail of leaf structure */
xfs_dir2_leaf_t * leaf ; /* leaf structure */
xfs_mount_t * mp ; /* filesystem mount point */
int rval ; /* successful free trim? */
xfs_trans_t * tp ; /* transaction pointer */
2013-04-12 01:30:21 +04:00
struct xfs_dir3_icleaf_hdr leafhdr ;
2013-04-03 09:11:21 +04:00
struct xfs_dir3_icfree_hdr freehdr ;
2005-04-17 02:20:36 +04:00
/*
* There ' s more than a leaf level in the btree , so there must
* be multiple leafn blocks . Give up .
*/
if ( state - > path . active > 1 )
return 0 ;
args = state - > args ;
2009-12-15 02:14:59 +03:00
trace_xfs_dir2_node_to_leaf ( args ) ;
2005-04-17 02:20:36 +04:00
mp = state - > mp ;
dp = args - > dp ;
tp = args - > trans ;
/*
* Get the last offset in the file .
*/
if ( ( error = xfs_bmap_last_offset ( tp , dp , & fo , XFS_DATA_FORK ) ) ) {
return error ;
}
fo - = mp - > m_dirblkfsbs ;
/*
* If there are freespace blocks other than the first one ,
* take this opportunity to remove trailing empty freespace blocks
* that may have been left behind during no - space - reservation
* operations .
*/
while ( fo > mp - > m_dirfreeblk ) {
if ( ( error = xfs_dir2_node_trim_free ( args , fo , & rval ) ) ) {
return error ;
}
if ( rval )
fo - = mp - > m_dirblkfsbs ;
else
return 0 ;
}
/*
* Now find the block just before the freespace block .
*/
if ( ( error = xfs_bmap_last_before ( tp , dp , & fo , XFS_DATA_FORK ) ) ) {
return error ;
}
/*
* If it ' s not the single leaf block , give up .
*/
if ( XFS_FSB_TO_B ( mp , fo ) > XFS_DIR2_LEAF_OFFSET + mp - > m_dirblksize )
return 0 ;
lbp = state - > path . blk [ 0 ] . bp ;
2012-06-22 12:50:14 +04:00
leaf = lbp - > b_addr ;
2013-10-29 15:11:52 +04:00
dp - > d_ops - > leaf_hdr_from_disk ( & leafhdr , leaf ) ;
2013-04-12 01:30:21 +04:00
ASSERT ( leafhdr . magic = = XFS_DIR2_LEAFN_MAGIC | |
leafhdr . magic = = XFS_DIR3_LEAFN_MAGIC ) ;
2005-04-17 02:20:36 +04:00
/*
* Read the freespace block .
*/
2012-11-12 15:54:13 +04:00
error = xfs_dir2_free_read ( tp , dp , mp - > m_dirfreeblk , & 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-10-29 15:11:52 +04:00
dp - > d_ops - > free_hdr_from_disk ( & freehdr , free ) ;
2013-04-03 09:11:21 +04:00
ASSERT ( ! freehdr . firstdb ) ;
2011-07-08 16:35:53 +04:00
2005-04-17 02:20:36 +04:00
/*
* Now see if the leafn and free data will fit in a leaf1 .
* If not , release the buffer and give up .
*/
2013-04-12 01:30:21 +04:00
if ( xfs_dir3_leaf_size ( & leafhdr , freehdr . nvalid ) > mp - > m_dirblksize ) {
2012-06-22 12:50:14 +04:00
xfs_trans_brelse ( tp , fbp ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2011-07-08 16:35:53 +04:00
2005-04-17 02:20:36 +04:00
/*
* If the leaf has any stale entries in it , compress them out .
*/
2013-04-12 01:30:21 +04:00
if ( leafhdr . stale )
xfs_dir3_leaf_compact ( args , & leafhdr , lbp ) ;
2012-11-14 10:53:49 +04:00
2013-04-12 01:30:21 +04:00
lbp - > b_ops = & xfs_dir3_leaf1_buf_ops ;
2013-04-03 09:11:30 +04:00
xfs_trans_buf_set_type ( tp , lbp , XFS_BLFT_DIR_LEAF1_BUF ) ;
2013-04-12 01:30:21 +04:00
leafhdr . magic = ( leafhdr . magic = = XFS_DIR2_LEAFN_MAGIC )
? XFS_DIR2_LEAF1_MAGIC
: XFS_DIR3_LEAF1_MAGIC ;
2012-11-14 10:53:49 +04:00
2005-04-17 02:20:36 +04:00
/*
* Set up the leaf tail from the freespace block .
*/
2007-06-28 10:43:50 +04:00
ltp = xfs_dir2_leaf_tail_p ( mp , leaf ) ;
2013-04-03 09:11:21 +04:00
ltp - > bestcount = cpu_to_be32 ( freehdr . nvalid ) ;
2013-04-12 01:30:21 +04:00
2005-04-17 02:20:36 +04:00
/*
* Set up the leaf bests table .
*/
2013-10-30 22:48:41 +04:00
memcpy ( xfs_dir2_leaf_bests_p ( ltp ) , dp - > d_ops - > free_bests_p ( free ) ,
2013-04-03 09:11:21 +04:00
freehdr . nvalid * sizeof ( xfs_dir2_data_off_t ) ) ;
2013-04-12 01:30:21 +04:00
2013-10-29 15:11:52 +04:00
dp - > d_ops - > leaf_hdr_to_disk ( leaf , & leafhdr ) ;
2013-10-29 15:11:50 +04:00
xfs_dir3_leaf_log_header ( tp , dp , lbp ) ;
2013-04-12 01:30:21 +04:00
xfs_dir3_leaf_log_bests ( tp , lbp , 0 , be32_to_cpu ( ltp - > bestcount ) - 1 ) ;
xfs_dir3_leaf_log_tail ( tp , lbp ) ;
2013-10-29 15:11:50 +04:00
xfs_dir3_leaf_check ( dp , lbp ) ;
2013-04-12 01:30:21 +04:00
2005-04-17 02:20:36 +04:00
/*
* Get rid of the freespace block .
*/
error = xfs_dir2_shrink_inode ( args , XFS_DIR2_FREE_FIRSTDB ( mp ) , fbp ) ;
if ( error ) {
/*
* This can ' t fail here because it can only happen when
* punching out the middle of an extent , and this is an
* isolated block .
*/
ASSERT ( error ! = ENOSPC ) ;
return error ;
}
fbp = NULL ;
/*
* Now see if we can convert the single - leaf directory
* down to a block form directory .
* This routine always kills the dabuf for the leaf , so
* eliminate it from the path .
*/
error = xfs_dir2_leaf_to_block ( args , lbp , NULL ) ;
state - > path . blk [ 0 ] . bp = NULL ;
return error ;
}