2005-04-17 02:20:36 +04:00
/*
2005-11-02 06:58:39 +03:00
* Copyright ( c ) 2000 , 2005 Silicon Graphics , Inc .
* All Rights Reserved .
2005-04-17 02:20:36 +04:00
*
2005-11-02 06:58:39 +03:00
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License as
2005-04-17 02:20:36 +04:00
* published by the Free Software Foundation .
*
2005-11-02 06:58:39 +03:00
* This program is distributed in the hope that it would be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
2005-04-17 02:20:36 +04:00
*
2005-11-02 06:58:39 +03:00
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write the Free Software Foundation ,
* Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
2005-04-17 02:20:36 +04:00
*/
# include "xfs.h"
2005-11-02 06:38:42 +03:00
# include "xfs_fs.h"
2013-10-23 03:36:05 +04:00
# include "xfs_shared.h"
2014-11-28 06:25:04 +03: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"
2016-08-03 04:14:35 +03:00
# include "xfs_defer.h"
2013-10-23 03:50:10 +04:00
# include "xfs_trans.h"
2005-04-17 02:20:36 +04:00
# include "xfs_trans_priv.h"
# include "xfs_extfree_item.h"
2015-08-19 02:51:43 +03:00
# include "xfs_alloc.h"
2016-08-03 04:14:35 +03:00
# include "xfs_bmap.h"
2005-04-17 02:20:36 +04:00
/*
* This routine is called to allocate an " extent free intention "
* log item that will hold nextents worth of extents . The
* caller must use all nextents extents , because we are not
* flexible about this at all .
*/
2016-08-03 04:18:10 +03:00
STATIC struct xfs_efi_log_item *
2016-08-03 04:13:47 +03:00
xfs_trans_get_efi ( struct xfs_trans * tp ,
uint nextents )
2005-04-17 02:20:36 +04:00
{
2016-08-03 04:13:47 +03:00
struct xfs_efi_log_item * efip ;
2005-04-17 02:20:36 +04:00
ASSERT ( tp ! = NULL ) ;
ASSERT ( nextents > 0 ) ;
efip = xfs_efi_init ( tp - > t_mountp , nextents ) ;
ASSERT ( efip ! = NULL ) ;
/*
* Get a log_item_desc to point at the new item .
*/
2010-06-23 12:11:15 +04:00
xfs_trans_add_item ( tp , & efip - > efi_item ) ;
return efip ;
2005-04-17 02:20:36 +04:00
}
/*
* This routine is called to indicate that the described
* extent is to be logged as needing to be freed . It should
* be called once for each extent to be freed .
*/
2016-08-03 04:18:10 +03:00
STATIC void
2016-08-03 04:13:47 +03:00
xfs_trans_log_efi_extent ( struct xfs_trans * tp ,
struct xfs_efi_log_item * efip ,
xfs_fsblock_t start_block ,
xfs_extlen_t ext_len )
2005-04-17 02:20:36 +04:00
{
2016-08-03 04:13:47 +03:00
uint next_extent ;
struct xfs_extent * extp ;
2005-04-17 02:20:36 +04:00
tp - > t_flags | = XFS_TRANS_DIRTY ;
2010-06-23 12:11:15 +04:00
efip - > efi_item . li_desc - > lid_flags | = XFS_LID_DIRTY ;
2005-04-17 02:20:36 +04:00
2010-12-20 03:59:49 +03:00
/*
* atomic_inc_return gives us the value after the increment ;
* we want to use it as an array index so we need to subtract 1 from
* it .
*/
next_extent = atomic_inc_return ( & efip - > efi_next_extent ) - 1 ;
2005-04-17 02:20:36 +04:00
ASSERT ( next_extent < efip - > efi_format . efi_nextents ) ;
extp = & ( efip - > efi_format . efi_extents [ next_extent ] ) ;
extp - > ext_start = start_block ;
extp - > ext_len = ext_len ;
}
/*
* This routine is called to allocate an " extent free done "
* log item that will hold nextents worth of extents . The
* caller must use all nextents extents , because we are not
* flexible about this at all .
*/
2016-08-03 04:13:47 +03:00
struct xfs_efd_log_item *
xfs_trans_get_efd ( struct xfs_trans * tp ,
struct xfs_efi_log_item * efip ,
uint nextents )
2005-04-17 02:20:36 +04:00
{
2016-08-03 04:13:47 +03:00
struct xfs_efd_log_item * efdp ;
2005-04-17 02:20:36 +04:00
ASSERT ( tp ! = NULL ) ;
ASSERT ( nextents > 0 ) ;
efdp = xfs_efd_init ( tp - > t_mountp , efip , nextents ) ;
ASSERT ( efdp ! = NULL ) ;
/*
* Get a log_item_desc to point at the new item .
*/
2010-06-23 12:11:15 +04:00
xfs_trans_add_item ( tp , & efdp - > efd_item ) ;
return efdp ;
2005-04-17 02:20:36 +04:00
}
/*
2015-08-19 02:51:43 +03:00
* Free an extent and log it to the EFD . Note that the transaction is marked
* dirty regardless of whether the extent free succeeds or fails to support the
* EFI / EFD lifecycle rules .
2005-04-17 02:20:36 +04:00
*/
2015-08-19 02:51:43 +03:00
int
xfs_trans_free_extent (
struct xfs_trans * tp ,
struct xfs_efd_log_item * efdp ,
xfs_fsblock_t start_block ,
xfs_extlen_t ext_len )
2005-04-17 02:20:36 +04:00
{
uint next_extent ;
2015-08-19 02:51:43 +03:00
struct xfs_extent * extp ;
int error ;
2005-04-17 02:20:36 +04:00
2015-08-19 02:51:43 +03:00
error = xfs_free_extent ( tp , start_block , ext_len ) ;
/*
* Mark the transaction dirty , even on error . This ensures the
* transaction is aborted , which :
*
* 1. ) releases the EFI and frees the EFD
* 2. ) shuts down the filesystem
*/
2005-04-17 02:20:36 +04:00
tp - > t_flags | = XFS_TRANS_DIRTY ;
2010-06-23 12:11:15 +04:00
efdp - > efd_item . li_desc - > lid_flags | = XFS_LID_DIRTY ;
2005-04-17 02:20:36 +04:00
next_extent = efdp - > efd_next_extent ;
ASSERT ( next_extent < efdp - > efd_format . efd_nextents ) ;
extp = & ( efdp - > efd_format . efd_extents [ next_extent ] ) ;
extp - > ext_start = start_block ;
extp - > ext_len = ext_len ;
efdp - > efd_next_extent + + ;
2015-08-19 02:51:43 +03:00
return error ;
2005-04-17 02:20:36 +04:00
}
2016-08-03 04:14:35 +03:00
/* Sort bmap items by AG. */
static int
xfs_extent_free_diff_items (
void * priv ,
struct list_head * a ,
struct list_head * b )
{
struct xfs_mount * mp = priv ;
2016-08-03 04:18:10 +03:00
struct xfs_extent_free_item * ra ;
struct xfs_extent_free_item * rb ;
2016-08-03 04:14:35 +03:00
2016-08-03 04:18:10 +03:00
ra = container_of ( a , struct xfs_extent_free_item , xefi_list ) ;
rb = container_of ( b , struct xfs_extent_free_item , xefi_list ) ;
return XFS_FSB_TO_AGNO ( mp , ra - > xefi_startblock ) -
XFS_FSB_TO_AGNO ( mp , rb - > xefi_startblock ) ;
2016-08-03 04:14:35 +03:00
}
/* Get an EFI. */
STATIC void *
xfs_extent_free_create_intent (
struct xfs_trans * tp ,
unsigned int count )
{
return xfs_trans_get_efi ( tp , count ) ;
}
/* Log a free extent to the intent item. */
STATIC void
xfs_extent_free_log_item (
struct xfs_trans * tp ,
void * intent ,
struct list_head * item )
{
2016-08-03 04:18:10 +03:00
struct xfs_extent_free_item * free ;
2016-08-03 04:14:35 +03:00
2016-08-03 04:18:10 +03:00
free = container_of ( item , struct xfs_extent_free_item , xefi_list ) ;
xfs_trans_log_efi_extent ( tp , intent , free - > xefi_startblock ,
free - > xefi_blockcount ) ;
2016-08-03 04:14:35 +03:00
}
/* Get an EFD so we can process all the free extents. */
STATIC void *
xfs_extent_free_create_done (
struct xfs_trans * tp ,
void * intent ,
unsigned int count )
{
return xfs_trans_get_efd ( tp , intent , count ) ;
}
/* Process a free extent. */
STATIC int
xfs_extent_free_finish_item (
struct xfs_trans * tp ,
struct xfs_defer_ops * dop ,
struct list_head * item ,
void * done_item ,
void * * state )
{
2016-08-03 04:18:10 +03:00
struct xfs_extent_free_item * free ;
2016-08-03 04:14:35 +03:00
int error ;
2016-08-03 04:18:10 +03:00
free = container_of ( item , struct xfs_extent_free_item , xefi_list ) ;
2016-08-03 04:14:35 +03:00
error = xfs_trans_free_extent ( tp , done_item ,
2016-08-03 04:18:10 +03:00
free - > xefi_startblock ,
free - > xefi_blockcount ) ;
2016-08-03 04:14:35 +03:00
kmem_free ( free ) ;
return error ;
}
/* Abort all pending EFIs. */
STATIC void
xfs_extent_free_abort_intent (
void * intent )
{
xfs_efi_release ( intent ) ;
}
/* Cancel a free extent. */
STATIC void
xfs_extent_free_cancel_item (
struct list_head * item )
{
2016-08-03 04:18:10 +03:00
struct xfs_extent_free_item * free ;
2016-08-03 04:14:35 +03:00
2016-08-03 04:18:10 +03:00
free = container_of ( item , struct xfs_extent_free_item , xefi_list ) ;
2016-08-03 04:14:35 +03:00
kmem_free ( free ) ;
}
static const struct xfs_defer_op_type xfs_extent_free_defer_type = {
. type = XFS_DEFER_OPS_TYPE_FREE ,
. max_items = XFS_EFI_MAX_FAST_EXTENTS ,
. diff_items = xfs_extent_free_diff_items ,
. create_intent = xfs_extent_free_create_intent ,
. abort_intent = xfs_extent_free_abort_intent ,
. log_item = xfs_extent_free_log_item ,
. create_done = xfs_extent_free_create_done ,
. finish_item = xfs_extent_free_finish_item ,
. cancel_item = xfs_extent_free_cancel_item ,
} ;
/* Register the deferred op type. */
void
xfs_extent_free_init_defer_op ( void )
{
xfs_defer_init_op_type ( & xfs_extent_free_defer_type ) ;
}