2008-07-14 20:08:37 +04:00
/*
* This file is part of UBIFS .
*
* Copyright ( C ) 2006 - 2008 Nokia Corporation .
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation .
*
* This program is distributed in the hope that it will 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 .
*
* You should have received a copy of the GNU General Public License along with
* this program ; if not , write to the Free Software Foundation , Inc . , 51
* Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
*
* Authors : Artem Bityutskiy ( Б и т ю ц к и й А р т ё м )
* Adrian Hunter
*/
/*
* This file contains functions for finding LEBs for various purposes e . g .
* garbage collection . In general , lprops category heaps and lists are used
* for fast access , falling back on scanning the LPT as a last resort .
*/
# include <linux/sort.h>
# include "ubifs.h"
/**
* struct scan_data - data provided to scan callback functions
* @ min_space : minimum number of bytes for which to scan
* @ pick_free : whether it is OK to scan for empty LEBs
* @ lnum : LEB number found is returned here
* @ exclude_index : whether to exclude index LEBs
*/
struct scan_data {
int min_space ;
int pick_free ;
int lnum ;
int exclude_index ;
} ;
/**
* valuable - determine whether LEB properties are valuable .
* @ c : the UBIFS file - system description object
* @ lprops : LEB properties
*
* This function return % 1 if the LEB properties should be added to the LEB
* properties tree in memory . Otherwise % 0 is returned .
*/
static int valuable ( struct ubifs_info * c , const struct ubifs_lprops * lprops )
{
int n , cat = lprops - > flags & LPROPS_CAT_MASK ;
struct ubifs_lpt_heap * heap ;
switch ( cat ) {
case LPROPS_DIRTY :
case LPROPS_DIRTY_IDX :
case LPROPS_FREE :
heap = & c - > lpt_heap [ cat - 1 ] ;
if ( heap - > cnt < heap - > max_cnt )
return 1 ;
if ( lprops - > free + lprops - > dirty > = c - > dark_wm )
return 1 ;
return 0 ;
case LPROPS_EMPTY :
n = c - > lst . empty_lebs + c - > freeable_cnt -
c - > lst . taken_empty_lebs ;
if ( n < c - > lsave_cnt )
return 1 ;
return 0 ;
case LPROPS_FREEABLE :
return 1 ;
case LPROPS_FRDI_IDX :
return 1 ;
}
return 0 ;
}
/**
* scan_for_dirty_cb - dirty space scan callback .
* @ c : the UBIFS file - system description object
* @ lprops : LEB properties to scan
* @ in_tree : whether the LEB properties are in main memory
* @ data : information passed to and from the caller of the scan
*
* This function returns a code that indicates whether the scan should continue
* ( % LPT_SCAN_CONTINUE ) , whether the LEB properties should be added to the tree
* in main memory ( % LPT_SCAN_ADD ) , or whether the scan should stop
* ( % LPT_SCAN_STOP ) .
*/
static int scan_for_dirty_cb ( struct ubifs_info * c ,
const struct ubifs_lprops * lprops , int in_tree ,
struct scan_data * data )
{
int ret = LPT_SCAN_CONTINUE ;
/* Exclude LEBs that are currently in use */
if ( lprops - > flags & LPROPS_TAKEN )
return LPT_SCAN_CONTINUE ;
/* Determine whether to add these LEB properties to the tree */
if ( ! in_tree & & valuable ( c , lprops ) )
ret | = LPT_SCAN_ADD ;
/* Exclude LEBs with too little space */
if ( lprops - > free + lprops - > dirty < data - > min_space )
return ret ;
/* If specified, exclude index LEBs */
if ( data - > exclude_index & & lprops - > flags & LPROPS_INDEX )
return ret ;
/* If specified, exclude empty or freeable LEBs */
if ( lprops - > free + lprops - > dirty = = c - > leb_size ) {
if ( ! data - > pick_free )
return ret ;
/* Exclude LEBs with too little dirty space (unless it is empty) */
} else if ( lprops - > dirty < c - > dead_wm )
return ret ;
/* Finally we found space */
data - > lnum = lprops - > lnum ;
return LPT_SCAN_ADD | LPT_SCAN_STOP ;
}
/**
* scan_for_dirty - find a data LEB with free space .
* @ c : the UBIFS file - system description object
* @ min_space : minimum amount free plus dirty space the returned LEB has to
* have
* @ pick_free : if it is OK to return a free or freeable LEB
* @ exclude_index : whether to exclude index LEBs
*
* This function returns a pointer to the LEB properties found or a negative
* error code .
*/
static const struct ubifs_lprops * scan_for_dirty ( struct ubifs_info * c ,
int min_space , int pick_free ,
int exclude_index )
{
const struct ubifs_lprops * lprops ;
struct ubifs_lpt_heap * heap ;
struct scan_data data ;
int err , i ;
/* There may be an LEB with enough dirty space on the free heap */
heap = & c - > lpt_heap [ LPROPS_FREE - 1 ] ;
for ( i = 0 ; i < heap - > cnt ; i + + ) {
lprops = heap - > arr [ i ] ;
if ( lprops - > free + lprops - > dirty < min_space )
continue ;
if ( lprops - > dirty < c - > dead_wm )
continue ;
return lprops ;
}
/*
* A LEB may have fallen off of the bottom of the dirty heap , and ended
* up as uncategorized even though it has enough dirty space for us now ,
* so check the uncategorized list . N . B . neither empty nor freeable LEBs
* can end up as uncategorized because they are kept on lists not
* finite - sized heaps .
*/
list_for_each_entry ( lprops , & c - > uncat_list , list ) {
if ( lprops - > flags & LPROPS_TAKEN )
continue ;
if ( lprops - > free + lprops - > dirty < min_space )
continue ;
if ( exclude_index & & ( lprops - > flags & LPROPS_INDEX ) )
continue ;
if ( lprops - > dirty < c - > dead_wm )
continue ;
return lprops ;
}
/* We have looked everywhere in main memory, now scan the flash */
if ( c - > pnodes_have > = c - > pnode_cnt )
/* All pnodes are in memory, so skip scan */
return ERR_PTR ( - ENOSPC ) ;
data . min_space = min_space ;
data . pick_free = pick_free ;
data . lnum = - 1 ;
data . exclude_index = exclude_index ;
err = ubifs_lpt_scan_nolock ( c , - 1 , c - > lscan_lnum ,
( ubifs_lpt_scan_callback ) scan_for_dirty_cb ,
& data ) ;
if ( err )
return ERR_PTR ( err ) ;
ubifs_assert ( data . lnum > = c - > main_first & & data . lnum < c - > leb_cnt ) ;
c - > lscan_lnum = data . lnum ;
lprops = ubifs_lpt_lookup_dirty ( c , data . lnum ) ;
if ( IS_ERR ( lprops ) )
return lprops ;
ubifs_assert ( lprops - > lnum = = data . lnum ) ;
ubifs_assert ( lprops - > free + lprops - > dirty > = min_space ) ;
ubifs_assert ( lprops - > dirty > = c - > dead_wm | |
( pick_free & &
lprops - > free + lprops - > dirty = = c - > leb_size ) ) ;
ubifs_assert ( ! ( lprops - > flags & LPROPS_TAKEN ) ) ;
ubifs_assert ( ! exclude_index | | ! ( lprops - > flags & LPROPS_INDEX ) ) ;
return lprops ;
}
/**
* ubifs_find_dirty_leb - find a dirty LEB for the Garbage Collector .
* @ c : the UBIFS file - system description object
* @ ret_lp : LEB properties are returned here on exit
* @ min_space : minimum amount free plus dirty space the returned LEB has to
* have
* @ pick_free : controls whether it is OK to pick empty or index LEBs
*
* This function tries to find a dirty logical eraseblock which has at least
* @ min_space free and dirty space . It prefers to take an LEB from the dirty or
* dirty index heap , and it falls - back to LPT scanning if the heaps are empty
* or do not have an LEB which satisfies the @ min_space criteria .
*
2008-08-25 19:32:57 +04:00
* Note , LEBs which have less than dead watermark of free + dirty space are
* never picked by this function .
2008-07-14 20:08:37 +04:00
*
* The additional @ pick_free argument controls if this function has to return a
* free or freeable LEB if one is present . For example , GC must to set it to % 1 ,
* when called from the journal space reservation function , because the
* appearance of free space may coincide with the loss of enough dirty space
* for GC to succeed anyway .
*
* In contrast , if the Garbage Collector is called from budgeting , it should
* just make free space , not return LEBs which are already free or freeable .
*
* In addition @ pick_free is set to % 2 by the recovery process in order to
* recover gc_lnum in which case an index LEB must not be returned .
2008-08-25 19:32:57 +04:00
*
* This function returns zero and the LEB properties of found dirty LEB in case
* of success , % - ENOSPC if no dirty LEB was found and a negative error code in
* case of other failures . The returned LEB is marked as " taken " .
2008-07-14 20:08:37 +04:00
*/
int ubifs_find_dirty_leb ( struct ubifs_info * c , struct ubifs_lprops * ret_lp ,
int min_space , int pick_free )
{
int err = 0 , sum , exclude_index = pick_free = = 2 ? 1 : 0 ;
const struct ubifs_lprops * lp = NULL , * idx_lp = NULL ;
struct ubifs_lpt_heap * heap , * idx_heap ;
ubifs_get_lprops ( c ) ;
if ( pick_free ) {
int lebs , rsvd_idx_lebs = 0 ;
spin_lock ( & c - > space_lock ) ;
2008-08-25 19:34:45 +04:00
lebs = c - > lst . empty_lebs + c - > idx_gc_cnt ;
2008-07-14 20:08:37 +04:00
lebs + = c - > freeable_cnt - c - > lst . taken_empty_lebs ;
/*
* Note , the index may consume more LEBs than have been reserved
* for it . It is OK because it might be consolidated by GC .
* But if the index takes fewer LEBs than it is reserved for it ,
* this function must avoid picking those reserved LEBs .
*/
2011-03-29 19:04:05 +04:00
if ( c - > bi . min_idx_lebs > = c - > lst . idx_lebs ) {
rsvd_idx_lebs = c - > bi . min_idx_lebs - c - > lst . idx_lebs ;
2008-07-14 20:08:37 +04:00
exclude_index = 1 ;
}
spin_unlock ( & c - > space_lock ) ;
/* Check if there are enough free LEBs for the index */
if ( rsvd_idx_lebs < lebs ) {
/* OK, try to find an empty LEB */
lp = ubifs_fast_find_empty ( c ) ;
if ( lp )
goto found ;
/* Or a freeable LEB */
lp = ubifs_fast_find_freeable ( c ) ;
if ( lp )
goto found ;
} else
/*
* We cannot pick free / freeable LEBs in the below code .
*/
pick_free = 0 ;
} else {
spin_lock ( & c - > space_lock ) ;
2011-03-29 19:04:05 +04:00
exclude_index = ( c - > bi . min_idx_lebs > = c - > lst . idx_lebs ) ;
2008-07-14 20:08:37 +04:00
spin_unlock ( & c - > space_lock ) ;
}
/* Look on the dirty and dirty index heaps */
heap = & c - > lpt_heap [ LPROPS_DIRTY - 1 ] ;
idx_heap = & c - > lpt_heap [ LPROPS_DIRTY_IDX - 1 ] ;
if ( idx_heap - > cnt & & ! exclude_index ) {
idx_lp = idx_heap - > arr [ 0 ] ;
sum = idx_lp - > free + idx_lp - > dirty ;
/*
2008-07-30 13:18:02 +04:00
* Since we reserve thrice as much space for the index than it
2008-07-14 20:08:37 +04:00
* actually takes , it does not make sense to pick indexing LEBs
2008-07-25 15:38:51 +04:00
* with less than , say , half LEB of dirty space . May be half is
* not the optimal boundary - this should be tested and
* checked . This boundary should determine how much we use
* in - the - gaps to consolidate the index comparing to how much
* we use garbage collector to consolidate it . The " half "
* criteria just feels to be fine .
2008-07-14 20:08:37 +04:00
*/
if ( sum < min_space | | sum < c - > half_leb_size )
idx_lp = NULL ;
}
if ( heap - > cnt ) {
lp = heap - > arr [ 0 ] ;
if ( lp - > dirty + lp - > free < min_space )
lp = NULL ;
}
/* Pick the LEB with most space */
if ( idx_lp & & lp ) {
if ( idx_lp - > free + idx_lp - > dirty > = lp - > free + lp - > dirty )
lp = idx_lp ;
} else if ( idx_lp & & ! lp )
lp = idx_lp ;
if ( lp ) {
2008-08-25 19:32:57 +04:00
ubifs_assert ( lp - > free + lp - > dirty > = c - > dead_wm ) ;
2008-07-14 20:08:37 +04:00
goto found ;
}
/* Did not find a dirty LEB on the dirty heaps, have to scan */
dbg_find ( " scanning LPT for a dirty LEB " ) ;
lp = scan_for_dirty ( c , min_space , pick_free , exclude_index ) ;
if ( IS_ERR ( lp ) ) {
err = PTR_ERR ( lp ) ;
goto out ;
}
ubifs_assert ( lp - > dirty > = c - > dead_wm | |
( pick_free & & lp - > free + lp - > dirty = = c - > leb_size ) ) ;
found :
dbg_find ( " found LEB %d, free %d, dirty %d, flags %#x " ,
lp - > lnum , lp - > free , lp - > dirty , lp - > flags ) ;
lp = ubifs_change_lp ( c , lp , LPROPS_NC , LPROPS_NC ,
lp - > flags | LPROPS_TAKEN , 0 ) ;
if ( IS_ERR ( lp ) ) {
err = PTR_ERR ( lp ) ;
goto out ;
}
memcpy ( ret_lp , lp , sizeof ( struct ubifs_lprops ) ) ;
out :
ubifs_release_lprops ( c ) ;
return err ;
}
/**
* scan_for_free_cb - free space scan callback .
* @ c : the UBIFS file - system description object
* @ lprops : LEB properties to scan
* @ in_tree : whether the LEB properties are in main memory
* @ data : information passed to and from the caller of the scan
*
* This function returns a code that indicates whether the scan should continue
* ( % LPT_SCAN_CONTINUE ) , whether the LEB properties should be added to the tree
* in main memory ( % LPT_SCAN_ADD ) , or whether the scan should stop
* ( % LPT_SCAN_STOP ) .
*/
static int scan_for_free_cb ( struct ubifs_info * c ,
const struct ubifs_lprops * lprops , int in_tree ,
struct scan_data * data )
{
int ret = LPT_SCAN_CONTINUE ;
/* Exclude LEBs that are currently in use */
if ( lprops - > flags & LPROPS_TAKEN )
return LPT_SCAN_CONTINUE ;
/* Determine whether to add these LEB properties to the tree */
if ( ! in_tree & & valuable ( c , lprops ) )
ret | = LPT_SCAN_ADD ;
/* Exclude index LEBs */
if ( lprops - > flags & LPROPS_INDEX )
return ret ;
/* Exclude LEBs with too little space */
if ( lprops - > free < data - > min_space )
return ret ;
/* If specified, exclude empty LEBs */
if ( ! data - > pick_free & & lprops - > free = = c - > leb_size )
return ret ;
/*
* LEBs that have only free and dirty space must not be allocated
* because they may have been unmapped already or they may have data
* that is obsolete only because of nodes that are still sitting in a
* wbuf .
*/
if ( lprops - > free + lprops - > dirty = = c - > leb_size & & lprops - > dirty > 0 )
return ret ;
/* Finally we found space */
data - > lnum = lprops - > lnum ;
return LPT_SCAN_ADD | LPT_SCAN_STOP ;
}
/**
* do_find_free_space - find a data LEB with free space .
* @ c : the UBIFS file - system description object
* @ min_space : minimum amount of free space required
* @ pick_free : whether it is OK to scan for empty LEBs
* @ squeeze : whether to try to find space in a non - empty LEB first
*
* This function returns a pointer to the LEB properties found or a negative
* error code .
*/
static
const struct ubifs_lprops * do_find_free_space ( struct ubifs_info * c ,
int min_space , int pick_free ,
int squeeze )
{
const struct ubifs_lprops * lprops ;
struct ubifs_lpt_heap * heap ;
struct scan_data data ;
int err , i ;
if ( squeeze ) {
lprops = ubifs_fast_find_free ( c ) ;
if ( lprops & & lprops - > free > = min_space )
return lprops ;
}
if ( pick_free ) {
lprops = ubifs_fast_find_empty ( c ) ;
if ( lprops )
return lprops ;
}
if ( ! squeeze ) {
lprops = ubifs_fast_find_free ( c ) ;
if ( lprops & & lprops - > free > = min_space )
return lprops ;
}
/* There may be an LEB with enough free space on the dirty heap */
heap = & c - > lpt_heap [ LPROPS_DIRTY - 1 ] ;
for ( i = 0 ; i < heap - > cnt ; i + + ) {
lprops = heap - > arr [ i ] ;
if ( lprops - > free > = min_space )
return lprops ;
}
/*
* A LEB may have fallen off of the bottom of the free heap , and ended
* up as uncategorized even though it has enough free space for us now ,
* so check the uncategorized list . N . B . neither empty nor freeable LEBs
* can end up as uncategorized because they are kept on lists not
* finite - sized heaps .
*/
list_for_each_entry ( lprops , & c - > uncat_list , list ) {
if ( lprops - > flags & LPROPS_TAKEN )
continue ;
if ( lprops - > flags & LPROPS_INDEX )
continue ;
if ( lprops - > free > = min_space )
return lprops ;
}
/* We have looked everywhere in main memory, now scan the flash */
if ( c - > pnodes_have > = c - > pnode_cnt )
/* All pnodes are in memory, so skip scan */
return ERR_PTR ( - ENOSPC ) ;
data . min_space = min_space ;
data . pick_free = pick_free ;
data . lnum = - 1 ;
err = ubifs_lpt_scan_nolock ( c , - 1 , c - > lscan_lnum ,
( ubifs_lpt_scan_callback ) scan_for_free_cb ,
& data ) ;
if ( err )
return ERR_PTR ( err ) ;
ubifs_assert ( data . lnum > = c - > main_first & & data . lnum < c - > leb_cnt ) ;
c - > lscan_lnum = data . lnum ;
lprops = ubifs_lpt_lookup_dirty ( c , data . lnum ) ;
if ( IS_ERR ( lprops ) )
return lprops ;
ubifs_assert ( lprops - > lnum = = data . lnum ) ;
ubifs_assert ( lprops - > free > = min_space ) ;
ubifs_assert ( ! ( lprops - > flags & LPROPS_TAKEN ) ) ;
ubifs_assert ( ! ( lprops - > flags & LPROPS_INDEX ) ) ;
return lprops ;
}
/**
* ubifs_find_free_space - find a data LEB with free space .
* @ c : the UBIFS file - system description object
* @ min_space : minimum amount of required free space
2009-03-03 20:22:53 +03:00
* @ offs : contains offset of where free space starts on exit
2008-07-14 20:08:37 +04:00
* @ squeeze : whether to try to find space in a non - empty LEB first
*
* This function looks for an LEB with at least @ min_space bytes of free space .
* It tries to find an empty LEB if possible . If no empty LEBs are available ,
* this function searches for a non - empty data LEB . The returned LEB is marked
* as " taken " .
*
* This function returns found LEB number in case of success , % - ENOSPC if it
* failed to find a LEB with @ min_space bytes of free space and other a negative
* error codes in case of failure .
*/
2009-03-03 20:22:53 +03:00
int ubifs_find_free_space ( struct ubifs_info * c , int min_space , int * offs ,
2008-07-14 20:08:37 +04:00
int squeeze )
{
const struct ubifs_lprops * lprops ;
int lebs , rsvd_idx_lebs , pick_free = 0 , err , lnum , flags ;
dbg_find ( " min_space %d " , min_space ) ;
ubifs_get_lprops ( c ) ;
/* Check if there are enough empty LEBs for commit */
spin_lock ( & c - > space_lock ) ;
2011-03-29 19:04:05 +04:00
if ( c - > bi . min_idx_lebs > c - > lst . idx_lebs )
rsvd_idx_lebs = c - > bi . min_idx_lebs - c - > lst . idx_lebs ;
2008-07-14 20:08:37 +04:00
else
rsvd_idx_lebs = 0 ;
lebs = c - > lst . empty_lebs + c - > freeable_cnt + c - > idx_gc_cnt -
c - > lst . taken_empty_lebs ;
if ( rsvd_idx_lebs < lebs )
/*
* OK to allocate an empty LEB , but we still don ' t want to go
* looking for one if there aren ' t any .
*/
if ( c - > lst . empty_lebs - c - > lst . taken_empty_lebs > 0 ) {
pick_free = 1 ;
/*
* Because we release the space lock , we must account
* for this allocation here . After the LEB properties
* flags have been updated , we subtract one . Note , the
* result of this is that lprops also decreases
* @ taken_empty_lebs in ' ubifs_change_lp ( ) ' , so it is
* off by one for a short period of time which may
* introduce a small disturbance to budgeting
* calculations , but this is harmless because at the
* worst case this would make the budgeting subsystem
* be more pessimistic than needed .
*
* Fundamentally , this is about serialization of the
* budgeting and lprops subsystems . We could make the
* @ space_lock a mutex and avoid dropping it before
* calling ' ubifs_change_lp ( ) ' , but mutex is more
* heavy - weight , and we want budgeting to be as fast as
* possible .
*/
c - > lst . taken_empty_lebs + = 1 ;
}
spin_unlock ( & c - > space_lock ) ;
lprops = do_find_free_space ( c , min_space , pick_free , squeeze ) ;
if ( IS_ERR ( lprops ) ) {
err = PTR_ERR ( lprops ) ;
goto out ;
}
lnum = lprops - > lnum ;
flags = lprops - > flags | LPROPS_TAKEN ;
lprops = ubifs_change_lp ( c , lprops , LPROPS_NC , LPROPS_NC , flags , 0 ) ;
if ( IS_ERR ( lprops ) ) {
err = PTR_ERR ( lprops ) ;
goto out ;
}
if ( pick_free ) {
spin_lock ( & c - > space_lock ) ;
c - > lst . taken_empty_lebs - = 1 ;
spin_unlock ( & c - > space_lock ) ;
}
2009-03-03 20:22:53 +03:00
* offs = c - > leb_size - lprops - > free ;
2008-07-14 20:08:37 +04:00
ubifs_release_lprops ( c ) ;
2009-03-03 20:22:53 +03:00
if ( * offs = = 0 ) {
2008-07-14 20:08:37 +04:00
/*
* Ensure that empty LEBs have been unmapped . They may not have
* been , for example , because of an unclean unmount . Also
* LEBs that were freeable LEBs ( free + dirty = = leb_size ) will
* not have been unmapped .
*/
err = ubifs_leb_unmap ( c , lnum ) ;
if ( err )
return err ;
}
2009-03-03 20:22:53 +03:00
dbg_find ( " found LEB %d, free %d " , lnum , c - > leb_size - * offs ) ;
ubifs_assert ( * offs < = c - > leb_size - min_space ) ;
2008-07-14 20:08:37 +04:00
return lnum ;
out :
if ( pick_free ) {
spin_lock ( & c - > space_lock ) ;
c - > lst . taken_empty_lebs - = 1 ;
spin_unlock ( & c - > space_lock ) ;
}
ubifs_release_lprops ( c ) ;
return err ;
}
/**
* scan_for_idx_cb - callback used by the scan for a free LEB for the index .
* @ c : the UBIFS file - system description object
* @ lprops : LEB properties to scan
* @ in_tree : whether the LEB properties are in main memory
* @ data : information passed to and from the caller of the scan
*
* This function returns a code that indicates whether the scan should continue
* ( % LPT_SCAN_CONTINUE ) , whether the LEB properties should be added to the tree
* in main memory ( % LPT_SCAN_ADD ) , or whether the scan should stop
* ( % LPT_SCAN_STOP ) .
*/
static int scan_for_idx_cb ( struct ubifs_info * c ,
const struct ubifs_lprops * lprops , int in_tree ,
struct scan_data * data )
{
int ret = LPT_SCAN_CONTINUE ;
/* Exclude LEBs that are currently in use */
if ( lprops - > flags & LPROPS_TAKEN )
return LPT_SCAN_CONTINUE ;
/* Determine whether to add these LEB properties to the tree */
if ( ! in_tree & & valuable ( c , lprops ) )
ret | = LPT_SCAN_ADD ;
/* Exclude index LEBS */
if ( lprops - > flags & LPROPS_INDEX )
return ret ;
/* Exclude LEBs that cannot be made empty */
if ( lprops - > free + lprops - > dirty ! = c - > leb_size )
return ret ;
/*
* We are allocating for the index so it is safe to allocate LEBs with
* only free and dirty space , because write buffers are sync ' d at commit
* start .
*/
data - > lnum = lprops - > lnum ;
return LPT_SCAN_ADD | LPT_SCAN_STOP ;
}
/**
* scan_for_leb_for_idx - scan for a free LEB for the index .
* @ c : the UBIFS file - system description object
*/
static const struct ubifs_lprops * scan_for_leb_for_idx ( struct ubifs_info * c )
{
struct ubifs_lprops * lprops ;
struct scan_data data ;
int err ;
data . lnum = - 1 ;
err = ubifs_lpt_scan_nolock ( c , - 1 , c - > lscan_lnum ,
( ubifs_lpt_scan_callback ) scan_for_idx_cb ,
& data ) ;
if ( err )
return ERR_PTR ( err ) ;
ubifs_assert ( data . lnum > = c - > main_first & & data . lnum < c - > leb_cnt ) ;
c - > lscan_lnum = data . lnum ;
lprops = ubifs_lpt_lookup_dirty ( c , data . lnum ) ;
if ( IS_ERR ( lprops ) )
return lprops ;
ubifs_assert ( lprops - > lnum = = data . lnum ) ;
ubifs_assert ( lprops - > free + lprops - > dirty = = c - > leb_size ) ;
ubifs_assert ( ! ( lprops - > flags & LPROPS_TAKEN ) ) ;
ubifs_assert ( ! ( lprops - > flags & LPROPS_INDEX ) ) ;
return lprops ;
}
/**
* ubifs_find_free_leb_for_idx - find a free LEB for the index .
* @ c : the UBIFS file - system description object
*
* This function looks for a free LEB and returns that LEB number . The returned
* LEB is marked as " taken " , " index " .
*
* Only empty LEBs are allocated . This is for two reasons . First , the commit
* calculates the number of LEBs to allocate based on the assumption that they
* will be empty . Secondly , free space at the end of an index LEB is not
* guaranteed to be empty because it may have been used by the in - the - gaps
* method prior to an unclean unmount .
*
* If no LEB is found % - ENOSPC is returned . For other failures another negative
* error code is returned .
*/
int ubifs_find_free_leb_for_idx ( struct ubifs_info * c )
{
const struct ubifs_lprops * lprops ;
int lnum = - 1 , err , flags ;
ubifs_get_lprops ( c ) ;
lprops = ubifs_fast_find_empty ( c ) ;
if ( ! lprops ) {
lprops = ubifs_fast_find_freeable ( c ) ;
if ( ! lprops ) {
2012-10-09 17:20:15 +04:00
/*
* The first condition means the following : go scan the
* LPT if there are uncategorized lprops , which means
* there may be freeable LEBs there ( UBIFS does not
* store the information about freeable LEBs in the
* master node ) .
*/
if ( c - > in_a_category_cnt ! = c - > main_lebs | |
c - > lst . empty_lebs - c - > lst . taken_empty_lebs > 0 ) {
ubifs_assert ( c - > freeable_cnt = = 0 ) ;
2008-07-14 20:08:37 +04:00
lprops = scan_for_leb_for_idx ( c ) ;
if ( IS_ERR ( lprops ) ) {
err = PTR_ERR ( lprops ) ;
goto out ;
}
}
}
}
if ( ! lprops ) {
err = - ENOSPC ;
goto out ;
}
lnum = lprops - > lnum ;
dbg_find ( " found LEB %d, free %d, dirty %d, flags %#x " ,
lnum , lprops - > free , lprops - > dirty , lprops - > flags ) ;
flags = lprops - > flags | LPROPS_TAKEN | LPROPS_INDEX ;
lprops = ubifs_change_lp ( c , lprops , c - > leb_size , 0 , flags , 0 ) ;
if ( IS_ERR ( lprops ) ) {
err = PTR_ERR ( lprops ) ;
goto out ;
}
ubifs_release_lprops ( c ) ;
/*
* Ensure that empty LEBs have been unmapped . They may not have been ,
* for example , because of an unclean unmount . Also LEBs that were
* freeable LEBs ( free + dirty = = leb_size ) will not have been unmapped .
*/
err = ubifs_leb_unmap ( c , lnum ) ;
if ( err ) {
ubifs_change_one_lp ( c , lnum , LPROPS_NC , LPROPS_NC , 0 ,
LPROPS_TAKEN | LPROPS_INDEX , 0 ) ;
return err ;
}
return lnum ;
out :
ubifs_release_lprops ( c ) ;
return err ;
}
static int cmp_dirty_idx ( const struct ubifs_lprops * * a ,
const struct ubifs_lprops * * b )
{
const struct ubifs_lprops * lpa = * a ;
const struct ubifs_lprops * lpb = * b ;
return lpa - > dirty + lpa - > free - lpb - > dirty - lpb - > free ;
}
static void swap_dirty_idx ( struct ubifs_lprops * * a , struct ubifs_lprops * * b ,
int size )
{
struct ubifs_lprops * t = * a ;
* a = * b ;
* b = t ;
}
/**
* ubifs_save_dirty_idx_lnums - save an array of the most dirty index LEB nos .
* @ c : the UBIFS file - system description object
*
* This function is called each commit to create an array of LEB numbers of
* dirty index LEBs sorted in order of dirty and free space . This is used by
* the in - the - gaps method of TNC commit .
*/
int ubifs_save_dirty_idx_lnums ( struct ubifs_info * c )
{
int i ;
ubifs_get_lprops ( c ) ;
/* Copy the LPROPS_DIRTY_IDX heap */
c - > dirty_idx . cnt = c - > lpt_heap [ LPROPS_DIRTY_IDX - 1 ] . cnt ;
memcpy ( c - > dirty_idx . arr , c - > lpt_heap [ LPROPS_DIRTY_IDX - 1 ] . arr ,
sizeof ( void * ) * c - > dirty_idx . cnt ) ;
/* Sort it so that the dirtiest is now at the end */
sort ( c - > dirty_idx . arr , c - > dirty_idx . cnt , sizeof ( void * ) ,
( int ( * ) ( const void * , const void * ) ) cmp_dirty_idx ,
( void ( * ) ( void * , void * , int ) ) swap_dirty_idx ) ;
dbg_find ( " found %d dirty index LEBs " , c - > dirty_idx . cnt ) ;
if ( c - > dirty_idx . cnt )
dbg_find ( " dirtiest index LEB is %d with dirty %d and free %d " ,
c - > dirty_idx . arr [ c - > dirty_idx . cnt - 1 ] - > lnum ,
c - > dirty_idx . arr [ c - > dirty_idx . cnt - 1 ] - > dirty ,
c - > dirty_idx . arr [ c - > dirty_idx . cnt - 1 ] - > free ) ;
/* Replace the lprops pointers with LEB numbers */
for ( i = 0 ; i < c - > dirty_idx . cnt ; i + + )
c - > dirty_idx . arr [ i ] = ( void * ) ( size_t ) c - > dirty_idx . arr [ i ] - > lnum ;
ubifs_release_lprops ( c ) ;
return 0 ;
}
/**
* scan_dirty_idx_cb - callback used by the scan for a dirty index LEB .
* @ c : the UBIFS file - system description object
* @ lprops : LEB properties to scan
* @ in_tree : whether the LEB properties are in main memory
* @ data : information passed to and from the caller of the scan
*
* This function returns a code that indicates whether the scan should continue
* ( % LPT_SCAN_CONTINUE ) , whether the LEB properties should be added to the tree
* in main memory ( % LPT_SCAN_ADD ) , or whether the scan should stop
* ( % LPT_SCAN_STOP ) .
*/
static int scan_dirty_idx_cb ( struct ubifs_info * c ,
const struct ubifs_lprops * lprops , int in_tree ,
struct scan_data * data )
{
int ret = LPT_SCAN_CONTINUE ;
/* Exclude LEBs that are currently in use */
if ( lprops - > flags & LPROPS_TAKEN )
return LPT_SCAN_CONTINUE ;
/* Determine whether to add these LEB properties to the tree */
if ( ! in_tree & & valuable ( c , lprops ) )
ret | = LPT_SCAN_ADD ;
/* Exclude non-index LEBs */
if ( ! ( lprops - > flags & LPROPS_INDEX ) )
return ret ;
/* Exclude LEBs with too little space */
if ( lprops - > free + lprops - > dirty < c - > min_idx_node_sz )
return ret ;
/* Finally we found space */
data - > lnum = lprops - > lnum ;
return LPT_SCAN_ADD | LPT_SCAN_STOP ;
}
/**
* find_dirty_idx_leb - find a dirty index LEB .
* @ c : the UBIFS file - system description object
*
* This function returns LEB number upon success and a negative error code upon
* failure . In particular , - ENOSPC is returned if a dirty index LEB is not
* found .
*
* Note that this function scans the entire LPT but it is called very rarely .
*/
static int find_dirty_idx_leb ( struct ubifs_info * c )
{
const struct ubifs_lprops * lprops ;
struct ubifs_lpt_heap * heap ;
struct scan_data data ;
int err , i , ret ;
/* Check all structures in memory first */
data . lnum = - 1 ;
heap = & c - > lpt_heap [ LPROPS_DIRTY_IDX - 1 ] ;
for ( i = 0 ; i < heap - > cnt ; i + + ) {
lprops = heap - > arr [ i ] ;
ret = scan_dirty_idx_cb ( c , lprops , 1 , & data ) ;
if ( ret & LPT_SCAN_STOP )
goto found ;
}
list_for_each_entry ( lprops , & c - > frdi_idx_list , list ) {
ret = scan_dirty_idx_cb ( c , lprops , 1 , & data ) ;
if ( ret & LPT_SCAN_STOP )
goto found ;
}
list_for_each_entry ( lprops , & c - > uncat_list , list ) {
ret = scan_dirty_idx_cb ( c , lprops , 1 , & data ) ;
if ( ret & LPT_SCAN_STOP )
goto found ;
}
if ( c - > pnodes_have > = c - > pnode_cnt )
/* All pnodes are in memory, so skip scan */
return - ENOSPC ;
err = ubifs_lpt_scan_nolock ( c , - 1 , c - > lscan_lnum ,
( ubifs_lpt_scan_callback ) scan_dirty_idx_cb ,
& data ) ;
if ( err )
return err ;
found :
ubifs_assert ( data . lnum > = c - > main_first & & data . lnum < c - > leb_cnt ) ;
c - > lscan_lnum = data . lnum ;
lprops = ubifs_lpt_lookup_dirty ( c , data . lnum ) ;
if ( IS_ERR ( lprops ) )
return PTR_ERR ( lprops ) ;
ubifs_assert ( lprops - > lnum = = data . lnum ) ;
ubifs_assert ( lprops - > free + lprops - > dirty > = c - > min_idx_node_sz ) ;
ubifs_assert ( ! ( lprops - > flags & LPROPS_TAKEN ) ) ;
ubifs_assert ( ( lprops - > flags & LPROPS_INDEX ) ) ;
dbg_find ( " found dirty LEB %d, free %d, dirty %d, flags %#x " ,
lprops - > lnum , lprops - > free , lprops - > dirty , lprops - > flags ) ;
lprops = ubifs_change_lp ( c , lprops , LPROPS_NC , LPROPS_NC ,
lprops - > flags | LPROPS_TAKEN , 0 ) ;
if ( IS_ERR ( lprops ) )
return PTR_ERR ( lprops ) ;
return lprops - > lnum ;
}
/**
* get_idx_gc_leb - try to get a LEB number from trivial GC .
* @ c : the UBIFS file - system description object
*/
static int get_idx_gc_leb ( struct ubifs_info * c )
{
const struct ubifs_lprops * lp ;
int err , lnum ;
err = ubifs_get_idx_gc_leb ( c ) ;
if ( err < 0 )
return err ;
lnum = err ;
/*
* The LEB was due to be unmapped after the commit but
* it is needed now for this commit .
*/
lp = ubifs_lpt_lookup_dirty ( c , lnum ) ;
2008-08-21 18:16:40 +04:00
if ( IS_ERR ( lp ) )
2008-07-14 20:08:37 +04:00
return PTR_ERR ( lp ) ;
lp = ubifs_change_lp ( c , lp , LPROPS_NC , LPROPS_NC ,
lp - > flags | LPROPS_INDEX , - 1 ) ;
2008-08-21 18:16:40 +04:00
if ( IS_ERR ( lp ) )
2008-07-14 20:08:37 +04:00
return PTR_ERR ( lp ) ;
dbg_find ( " LEB %d, dirty %d and free %d flags %#x " ,
lp - > lnum , lp - > dirty , lp - > free , lp - > flags ) ;
return lnum ;
}
/**
* find_dirtiest_idx_leb - find dirtiest index LEB from dirtiest array .
* @ c : the UBIFS file - system description object
*/
static int find_dirtiest_idx_leb ( struct ubifs_info * c )
{
const struct ubifs_lprops * lp ;
int lnum ;
while ( 1 ) {
if ( ! c - > dirty_idx . cnt )
return - ENOSPC ;
/* The lprops pointers were replaced by LEB numbers */
lnum = ( size_t ) c - > dirty_idx . arr [ - - c - > dirty_idx . cnt ] ;
lp = ubifs_lpt_lookup ( c , lnum ) ;
if ( IS_ERR ( lp ) )
return PTR_ERR ( lp ) ;
if ( ( lp - > flags & LPROPS_TAKEN ) | | ! ( lp - > flags & LPROPS_INDEX ) )
continue ;
lp = ubifs_change_lp ( c , lp , LPROPS_NC , LPROPS_NC ,
lp - > flags | LPROPS_TAKEN , 0 ) ;
if ( IS_ERR ( lp ) )
return PTR_ERR ( lp ) ;
break ;
}
dbg_find ( " LEB %d, dirty %d and free %d flags %#x " , lp - > lnum , lp - > dirty ,
lp - > free , lp - > flags ) ;
2012-06-09 13:08:23 +04:00
ubifs_assert ( lp - > flags & LPROPS_TAKEN ) ;
ubifs_assert ( lp - > flags & LPROPS_INDEX ) ;
2008-07-14 20:08:37 +04:00
return lnum ;
}
/**
* ubifs_find_dirty_idx_leb - try to find dirtiest index LEB as at last commit .
* @ c : the UBIFS file - system description object
*
* This function attempts to find an untaken index LEB with the most free and
* dirty space that can be used without overwriting index nodes that were in the
* last index committed .
*/
int ubifs_find_dirty_idx_leb ( struct ubifs_info * c )
{
int err ;
ubifs_get_lprops ( c ) ;
/*
* We made an array of the dirtiest index LEB numbers as at the start of
* last commit . Try that array first .
*/
err = find_dirtiest_idx_leb ( c ) ;
/* Next try scanning the entire LPT */
if ( err = = - ENOSPC )
err = find_dirty_idx_leb ( c ) ;
/* Finally take any index LEBs awaiting trivial GC */
if ( err = = - ENOSPC )
err = get_idx_gc_leb ( c ) ;
ubifs_release_lprops ( c ) ;
return err ;
}