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"
2013-10-23 03:50:10 +04:00
# include "xfs_format.h"
# include "xfs_log_format.h"
# include "xfs_trans_resv.h"
2005-11-02 06:38:42 +03:00
# include "xfs_bit.h"
2005-04-17 02:20:36 +04:00
# include "xfs_sb.h"
# include "xfs_ag.h"
# include "xfs_mount.h"
# include "xfs_inode.h"
# include "xfs_bmap.h"
2013-08-12 14:49:42 +04:00
# include "xfs_bmap_util.h"
2013-10-23 03:51:50 +04:00
# include "xfs_bmap_btree.h"
# include "xfs_alloc.h"
2005-04-17 02:20:36 +04:00
# include "xfs_error.h"
2013-10-23 03:50:10 +04:00
# include "xfs_trans.h"
2005-04-17 02:20:36 +04:00
# include "xfs_trans_space.h"
2009-12-15 02:14:59 +03:00
# include "xfs_trace.h"
2010-09-22 04:47:20 +04:00
# include "xfs_buf.h"
2012-10-08 14:56:11 +04:00
# include "xfs_icache.h"
2013-10-23 03:51:50 +04:00
# include "xfs_dinode.h"
2013-10-15 02:17:56 +04:00
# include "xfs_rtalloc.h"
2005-04-17 02:20:36 +04:00
/*
2013-10-15 02:17:56 +04:00
* Read and return the summary information for a given extent size ,
* bitmap block combination .
* Keeps track of a current summary block , so we don ' t keep reading
* it from the buffer cache .
2005-04-17 02:20:36 +04:00
*/
2014-09-09 05:58:42 +04:00
int
2013-10-15 02:17:56 +04:00
xfs_rtget_summary (
xfs_mount_t * mp , /* file system mount structure */
xfs_trans_t * tp , /* transaction pointer */
int log , /* log2 of extent size */
xfs_rtblock_t bbno , /* bitmap block number */
xfs_buf_t * * rbpp , /* in/out: summary block buffer */
xfs_fsblock_t * rsb , /* in/out: summary block number */
xfs_suminfo_t * sum ) /* out: summary info for this block */
2005-04-17 02:20:36 +04:00
{
2014-09-09 05:58:42 +04:00
return xfs_rtmodify_summary_int ( mp , tp , log , bbno , 0 , rbpp , rsb , sum ) ;
2005-04-17 02:20:36 +04:00
}
/*
2013-10-15 02:17:56 +04:00
* Return whether there are any free extents in the size range given
* by low and high , for the bitmap block bbno .
2005-04-17 02:20:36 +04:00
*/
STATIC int /* error */
2013-10-15 02:17:56 +04:00
xfs_rtany_summary (
xfs_mount_t * mp , /* file system mount structure */
2005-04-17 02:20:36 +04:00
xfs_trans_t * tp , /* transaction pointer */
2013-10-15 02:17:56 +04:00
int low , /* low log2 extent size */
int high , /* high log2 extent size */
2005-04-17 02:20:36 +04:00
xfs_rtblock_t bbno , /* bitmap block number */
xfs_buf_t * * rbpp , /* in/out: summary block buffer */
xfs_fsblock_t * rsb , /* in/out: summary block number */
2013-10-15 02:17:56 +04:00
int * stat ) /* out: any good extents here? */
2005-04-17 02:20:36 +04:00
{
int error ; /* error value */
2013-10-15 02:17:56 +04:00
int log ; /* loop counter, log2 of ext. size */
xfs_suminfo_t sum ; /* summary data */
2005-04-17 02:20:36 +04:00
/*
2013-10-15 02:17:56 +04:00
* Loop over logs of extent sizes . Order is irrelevant .
2005-04-17 02:20:36 +04:00
*/
2013-10-15 02:17:56 +04:00
for ( log = low ; log < = high ; log + + ) {
2005-04-17 02:20:36 +04:00
/*
2013-10-15 02:17:56 +04:00
* Get one summary datum .
2005-04-17 02:20:36 +04:00
*/
2013-10-15 02:17:56 +04:00
error = xfs_rtget_summary ( mp , tp , log , bbno , rbpp , rsb , & sum ) ;
2005-04-17 02:20:36 +04:00
if ( error ) {
return error ;
}
/*
2013-10-15 02:17:56 +04:00
* If there are any , return success .
2005-04-17 02:20:36 +04:00
*/
2013-10-15 02:17:56 +04:00
if ( sum ) {
* stat = 1 ;
return 0 ;
2005-04-17 02:20:36 +04:00
}
}
/*
2013-10-15 02:17:56 +04:00
* Found nothing , return failure .
2005-04-17 02:20:36 +04:00
*/
2013-10-15 02:17:56 +04:00
* stat = 0 ;
return 0 ;
}
2005-04-17 02:20:36 +04:00
2013-10-15 02:17:56 +04:00
/*
* Copy and transform the summary file , given the old and new
* parameters in the mount structures .
*/
STATIC int /* error */
xfs_rtcopy_summary (
xfs_mount_t * omp , /* old file system mount point */
xfs_mount_t * nmp , /* new file system mount point */
xfs_trans_t * tp ) /* transaction pointer */
{
xfs_rtblock_t bbno ; /* bitmap block number */
xfs_buf_t * bp ; /* summary buffer */
int error ; /* error return value */
int log ; /* summary level number (log length) */
xfs_suminfo_t sum ; /* summary data */
xfs_fsblock_t sumbno ; /* summary block number */
bp = NULL ;
for ( log = omp - > m_rsumlevels - 1 ; log > = 0 ; log - - ) {
for ( bbno = omp - > m_sb . sb_rbmblocks - 1 ;
( xfs_srtblock_t ) bbno > = 0 ;
bbno - - ) {
error = xfs_rtget_summary ( omp , tp , log , bbno , & bp ,
& sumbno , & sum ) ;
if ( error )
return error ;
if ( sum = = 0 )
continue ;
error = xfs_rtmodify_summary ( omp , tp , log , bbno , - sum ,
& bp , & sumbno ) ;
if ( error )
return error ;
error = xfs_rtmodify_summary ( nmp , tp , log , bbno , sum ,
& bp , & sumbno ) ;
if ( error )
return error ;
ASSERT ( sum > 0 ) ;
}
}
return 0 ;
}
/*
* Mark an extent specified by start and len allocated .
* Updates all the summary information as well as the bitmap .
*/
STATIC int /* error */
xfs_rtallocate_range (
xfs_mount_t * mp , /* file system mount point */
xfs_trans_t * tp , /* transaction pointer */
xfs_rtblock_t start , /* start block to allocate */
xfs_extlen_t len , /* length to allocate */
xfs_buf_t * * rbpp , /* in/out: summary block buffer */
xfs_fsblock_t * rsb ) /* in/out: summary block number */
{
xfs_rtblock_t end ; /* end of the allocated extent */
int error ; /* error value */
xfs_rtblock_t postblock = 0 ; /* first block allocated > end */
xfs_rtblock_t preblock = 0 ; /* first block allocated < start */
end = start + len - 1 ;
/*
* Assume we ' re allocating out of the middle of a free extent .
* We need to find the beginning and end of the extent so we can
* properly update the summary .
*/
error = xfs_rtfind_back ( mp , tp , start , 0 , & preblock ) ;
if ( error ) {
return error ;
}
/*
* Find the next allocated block ( end of free extent ) .
*/
error = xfs_rtfind_forw ( mp , tp , end , mp - > m_sb . sb_rextents - 1 ,
& postblock ) ;
if ( error ) {
return error ;
}
/*
* Decrement the summary information corresponding to the entire
* ( old ) free extent .
*/
error = xfs_rtmodify_summary ( mp , tp ,
XFS_RTBLOCKLOG ( postblock + 1 - preblock ) ,
XFS_BITTOBLOCK ( mp , preblock ) , - 1 , rbpp , rsb ) ;
if ( error ) {
return error ;
}
/*
* If there are blocks not being allocated at the front of the
* old extent , add summary data for them to be free .
*/
if ( preblock < start ) {
error = xfs_rtmodify_summary ( mp , tp ,
XFS_RTBLOCKLOG ( start - preblock ) ,
XFS_BITTOBLOCK ( mp , preblock ) , 1 , rbpp , rsb ) ;
if ( error ) {
return error ;
}
}
/*
* If there are blocks not being allocated at the end of the
* old extent , add summary data for them to be free .
*/
if ( postblock > end ) {
error = xfs_rtmodify_summary ( mp , tp ,
XFS_RTBLOCKLOG ( postblock - end ) ,
XFS_BITTOBLOCK ( mp , end + 1 ) , 1 , rbpp , rsb ) ;
if ( error ) {
return error ;
}
}
/*
* Modify the bitmap to mark this extent allocated .
*/
error = xfs_rtmodify_range ( mp , tp , start , len , 0 ) ;
return error ;
}
/*
* Attempt to allocate an extent minlen < = len < = maxlen starting from
* bitmap block bbno . If we don ' t get maxlen then use prod to trim
* the length , if given . Returns error ; returns starting block in * rtblock .
* The lengths are all in rtextents .
*/
STATIC int /* error */
xfs_rtallocate_extent_block (
xfs_mount_t * mp , /* file system mount point */
xfs_trans_t * tp , /* transaction pointer */
xfs_rtblock_t bbno , /* bitmap block number */
xfs_extlen_t minlen , /* minimum length to allocate */
xfs_extlen_t maxlen , /* maximum length to allocate */
xfs_extlen_t * len , /* out: actual length allocated */
xfs_rtblock_t * nextp , /* out: next block to try */
xfs_buf_t * * rbpp , /* in/out: summary block buffer */
xfs_fsblock_t * rsb , /* in/out: summary block number */
xfs_extlen_t prod , /* extent product factor */
xfs_rtblock_t * rtblock ) /* out: start block allocated */
{
xfs_rtblock_t besti ; /* best rtblock found so far */
xfs_rtblock_t bestlen ; /* best length found so far */
xfs_rtblock_t end ; /* last rtblock in chunk */
int error ; /* error value */
xfs_rtblock_t i ; /* current rtblock trying */
xfs_rtblock_t next ; /* next rtblock to try */
int stat ; /* status from internal calls */
/*
* Loop over all the extents starting in this bitmap block ,
* looking for one that ' s long enough .
*/
for ( i = XFS_BLOCKTOBIT ( mp , bbno ) , besti = - 1 , bestlen = 0 ,
end = XFS_BLOCKTOBIT ( mp , bbno + 1 ) - 1 ;
i < = end ;
i + + ) {
/*
* See if there ' s a free extent of maxlen starting at i .
* If it ' s not so then next will contain the first non - free .
*/
error = xfs_rtcheck_range ( mp , tp , i , maxlen , 1 , & next , & stat ) ;
if ( error ) {
return error ;
}
if ( stat ) {
/*
* i for maxlen is all free , allocate and return that .
*/
error = xfs_rtallocate_range ( mp , tp , i , maxlen , rbpp ,
rsb ) ;
if ( error ) {
return error ;
}
* len = maxlen ;
* rtblock = i ;
return 0 ;
}
/*
* In the case where we have a variable - sized allocation
* request , figure out how big this free piece is ,
* and if it ' s big enough for the minimum , and the best
* so far , remember it .
*/
if ( minlen < maxlen ) {
xfs_rtblock_t thislen ; /* this extent size */
thislen = next - i ;
if ( thislen > = minlen & & thislen > bestlen ) {
besti = i ;
bestlen = thislen ;
}
}
/*
* If not done yet , find the start of the next free space .
*/
if ( next < end ) {
error = xfs_rtfind_forw ( mp , tp , next , end , & i ) ;
if ( error ) {
return error ;
}
} else
break ;
}
/*
* Searched the whole thing & didn ' t find a maxlen free extent .
*/
if ( minlen < maxlen & & besti ! = - 1 ) {
xfs_extlen_t p ; /* amount to trim length by */
/*
* If size should be a multiple of prod , make that so .
*/
if ( prod > 1 & & ( p = do_mod ( bestlen , prod ) ) )
2005-04-17 02:20:36 +04:00
bestlen - = p ;
/*
* Allocate besti for bestlen & return that .
*/
error = xfs_rtallocate_range ( mp , tp , besti , bestlen , rbpp , rsb ) ;
if ( error ) {
return error ;
}
* len = bestlen ;
* rtblock = besti ;
return 0 ;
}
/*
* Allocation failed . Set * nextp to the next block to try .
*/
* nextp = next ;
* rtblock = NULLRTBLOCK ;
return 0 ;
}
/*
* Allocate an extent of length minlen < = len < = maxlen , starting at block
* bno . If we don ' t get maxlen then use prod to trim the length , if given .
* Returns error ; returns starting block in * rtblock .
* The lengths are all in rtextents .
*/
STATIC int /* error */
xfs_rtallocate_extent_exact (
xfs_mount_t * mp , /* file system mount point */
xfs_trans_t * tp , /* transaction pointer */
xfs_rtblock_t bno , /* starting block number to allocate */
xfs_extlen_t minlen , /* minimum length to allocate */
xfs_extlen_t maxlen , /* maximum length to allocate */
xfs_extlen_t * len , /* out: actual length allocated */
xfs_buf_t * * rbpp , /* in/out: summary block buffer */
xfs_fsblock_t * rsb , /* in/out: summary block number */
xfs_extlen_t prod , /* extent product factor */
xfs_rtblock_t * rtblock ) /* out: start block allocated */
{
int error ; /* error value */
xfs_extlen_t i ; /* extent length trimmed due to prod */
int isfree ; /* extent is free */
xfs_rtblock_t next ; /* next block to try (dummy) */
ASSERT ( minlen % prod = = 0 & & maxlen % prod = = 0 ) ;
/*
* Check if the range in question ( for maxlen ) is free .
*/
error = xfs_rtcheck_range ( mp , tp , bno , maxlen , 1 , & next , & isfree ) ;
if ( error ) {
return error ;
}
if ( isfree ) {
/*
* If it is , allocate it and return success .
*/
error = xfs_rtallocate_range ( mp , tp , bno , maxlen , rbpp , rsb ) ;
if ( error ) {
return error ;
}
* len = maxlen ;
* rtblock = bno ;
return 0 ;
}
/*
* If not , allocate what there is , if it ' s at least minlen .
*/
maxlen = next - bno ;
if ( maxlen < minlen ) {
/*
* Failed , return failure status .
*/
* rtblock = NULLRTBLOCK ;
return 0 ;
}
/*
* Trim off tail of extent , if prod is specified .
*/
if ( prod > 1 & & ( i = maxlen % prod ) ) {
maxlen - = i ;
if ( maxlen < minlen ) {
/*
* Now we can ' t do it , return failure status .
*/
* rtblock = NULLRTBLOCK ;
return 0 ;
}
}
/*
* Allocate what we can and return it .
*/
error = xfs_rtallocate_range ( mp , tp , bno , maxlen , rbpp , rsb ) ;
if ( error ) {
return error ;
}
* len = maxlen ;
* rtblock = bno ;
return 0 ;
}
/*
* Allocate an extent of length minlen < = len < = maxlen , starting as near
* to bno as possible . If we don ' t get maxlen then use prod to trim
* the length , if given . The lengths are all in rtextents .
*/
STATIC int /* error */
xfs_rtallocate_extent_near (
xfs_mount_t * mp , /* file system mount point */
xfs_trans_t * tp , /* transaction pointer */
xfs_rtblock_t bno , /* starting block number to allocate */
xfs_extlen_t minlen , /* minimum length to allocate */
xfs_extlen_t maxlen , /* maximum length to allocate */
xfs_extlen_t * len , /* out: actual length allocated */
xfs_buf_t * * rbpp , /* in/out: summary block buffer */
xfs_fsblock_t * rsb , /* in/out: summary block number */
xfs_extlen_t prod , /* extent product factor */
xfs_rtblock_t * rtblock ) /* out: start block allocated */
{
int any ; /* any useful extents from summary */
xfs_rtblock_t bbno ; /* bitmap block number */
int error ; /* error value */
int i ; /* bitmap block offset (loop control) */
int j ; /* secondary loop control */
int log2len ; /* log2 of minlen */
xfs_rtblock_t n ; /* next block to try */
xfs_rtblock_t r ; /* result block */
ASSERT ( minlen % prod = = 0 & & maxlen % prod = = 0 ) ;
/*
* If the block number given is off the end , silently set it to
* the last block .
*/
if ( bno > = mp - > m_sb . sb_rextents )
bno = mp - > m_sb . sb_rextents - 1 ;
/*
* Try the exact allocation first .
*/
error = xfs_rtallocate_extent_exact ( mp , tp , bno , minlen , maxlen , len ,
rbpp , rsb , prod , & r ) ;
if ( error ) {
return error ;
}
/*
* If the exact allocation worked , return that .
*/
if ( r ! = NULLRTBLOCK ) {
* rtblock = r ;
return 0 ;
}
bbno = XFS_BITTOBLOCK ( mp , bno ) ;
i = 0 ;
2008-08-13 09:41:12 +04:00
ASSERT ( minlen ! = 0 ) ;
2005-04-17 02:20:36 +04:00
log2len = xfs_highbit32 ( minlen ) ;
/*
* Loop over all bitmap blocks ( bbno + i is current block ) .
*/
for ( ; ; ) {
/*
* Get summary information of extents of all useful levels
* starting in this bitmap block .
*/
error = xfs_rtany_summary ( mp , tp , log2len , mp - > m_rsumlevels - 1 ,
bbno + i , rbpp , rsb , & any ) ;
if ( error ) {
return error ;
}
/*
* If there are any useful extents starting here , try
* allocating one .
*/
if ( any ) {
/*
* On the positive side of the starting location .
*/
if ( i > = 0 ) {
/*
* Try to allocate an extent starting in
* this block .
*/
error = xfs_rtallocate_extent_block ( mp , tp ,
bbno + i , minlen , maxlen , len , & n , rbpp ,
rsb , prod , & r ) ;
if ( error ) {
return error ;
}
/*
* If it worked , return it .
*/
if ( r ! = NULLRTBLOCK ) {
* rtblock = r ;
return 0 ;
}
}
/*
* On the negative side of the starting location .
*/
else { /* i < 0 */
/*
* Loop backwards through the bitmap blocks from
* the starting point - 1 up to where we are now .
* There should be an extent which ends in this
* bitmap block and is long enough .
*/
for ( j = - 1 ; j > i ; j - - ) {
/*
* Grab the summary information for
* this bitmap block .
*/
error = xfs_rtany_summary ( mp , tp ,
log2len , mp - > m_rsumlevels - 1 ,
bbno + j , rbpp , rsb , & any ) ;
if ( error ) {
return error ;
}
/*
* If there ' s no extent given in the
* summary that means the extent we
* found must carry over from an
* earlier block . If there is an
* extent given , we ' ve already tried
* that allocation , don ' t do it again .
*/
if ( any )
continue ;
error = xfs_rtallocate_extent_block ( mp ,
tp , bbno + j , minlen , maxlen ,
len , & n , rbpp , rsb , prod , & r ) ;
if ( error ) {
return error ;
}
/*
* If it works , return the extent .
*/
if ( r ! = NULLRTBLOCK ) {
* rtblock = r ;
return 0 ;
}
}
/*
* There weren ' t intervening bitmap blocks
* with a long enough extent , or the
* allocation didn ' t work for some reason
* ( i . e . it ' s a little * too short ) .
* Try to allocate from the summary block
* that we found .
*/
error = xfs_rtallocate_extent_block ( mp , tp ,
bbno + i , minlen , maxlen , len , & n , rbpp ,
rsb , prod , & r ) ;
if ( error ) {
return error ;
}
/*
* If it works , return the extent .
*/
if ( r ! = NULLRTBLOCK ) {
* rtblock = r ;
return 0 ;
}
}
}
/*
* Loop control . If we were on the positive side , and there ' s
* still more blocks on the negative side , go there .
*/
if ( i > 0 & & ( int ) bbno - i > = 0 )
i = - i ;
/*
* If positive , and no more negative , but there are more
* positive , go there .
*/
else if ( i > 0 & & ( int ) bbno + i < mp - > m_sb . sb_rbmblocks - 1 )
i + + ;
/*
* If negative or 0 ( just started ) , and there are positive
* blocks to go , go there . The 0 case moves to block 1.
*/
else if ( i < = 0 & & ( int ) bbno - i < mp - > m_sb . sb_rbmblocks - 1 )
i = 1 - i ;
/*
* If negative or 0 and there are more negative blocks ,
* go there .
*/
else if ( i < = 0 & & ( int ) bbno + i > 0 )
i - - ;
/*
* Must be done . Return failure .
*/
else
break ;
}
* rtblock = NULLRTBLOCK ;
return 0 ;
}
/*
* Allocate an extent of length minlen < = len < = maxlen , with no position
* specified . If we don ' t get maxlen then use prod to trim
* the length , if given . The lengths are all in rtextents .
*/
STATIC int /* error */
xfs_rtallocate_extent_size (
xfs_mount_t * mp , /* file system mount point */
xfs_trans_t * tp , /* transaction pointer */
xfs_extlen_t minlen , /* minimum length to allocate */
xfs_extlen_t maxlen , /* maximum length to allocate */
xfs_extlen_t * len , /* out: actual length allocated */
xfs_buf_t * * rbpp , /* in/out: summary block buffer */
xfs_fsblock_t * rsb , /* in/out: summary block number */
xfs_extlen_t prod , /* extent product factor */
xfs_rtblock_t * rtblock ) /* out: start block allocated */
{
int error ; /* error value */
int i ; /* bitmap block number */
int l ; /* level number (loop control) */
xfs_rtblock_t n ; /* next block to be tried */
xfs_rtblock_t r ; /* result block number */
xfs_suminfo_t sum ; /* summary information for extents */
ASSERT ( minlen % prod = = 0 & & maxlen % prod = = 0 ) ;
2008-08-13 09:41:12 +04:00
ASSERT ( maxlen ! = 0 ) ;
2005-04-17 02:20:36 +04:00
/*
* Loop over all the levels starting with maxlen .
* At each level , look at all the bitmap blocks , to see if there
* are extents starting there that are long enough ( > = maxlen ) .
* Note , only on the initial level can the allocation fail if
* the summary says there ' s an extent .
*/
for ( l = xfs_highbit32 ( maxlen ) ; l < mp - > m_rsumlevels ; l + + ) {
/*
* Loop over all the bitmap blocks .
*/
for ( i = 0 ; i < mp - > m_sb . sb_rbmblocks ; i + + ) {
/*
* Get the summary for this level / block .
*/
error = xfs_rtget_summary ( mp , tp , l , i , rbpp , rsb ,
& sum ) ;
if ( error ) {
return error ;
}
/*
* Nothing there , on to the next block .
*/
if ( ! sum )
continue ;
/*
* Try allocating the extent .
*/
error = xfs_rtallocate_extent_block ( mp , tp , i , maxlen ,
maxlen , len , & n , rbpp , rsb , prod , & r ) ;
if ( error ) {
return error ;
}
/*
* If it worked , return that .
*/
if ( r ! = NULLRTBLOCK ) {
* rtblock = r ;
2013-10-15 02:17:56 +04:00
return 0 ;
}
/*
* If the " next block to try " returned from the
* allocator is beyond the next bitmap block ,
* skip to that bitmap block .
*/
if ( XFS_BITTOBLOCK ( mp , n ) > i + 1 )
i = XFS_BITTOBLOCK ( mp , n ) - 1 ;
}
2005-04-17 02:20:36 +04:00
}
/*
2013-10-15 02:17:56 +04:00
* Didn ' t find any maxlen blocks . Try smaller ones , unless
* we ' re asking for a fixed size extent .
2005-04-17 02:20:36 +04:00
*/
2013-10-15 02:17:56 +04:00
if ( minlen > - - maxlen ) {
* rtblock = NULLRTBLOCK ;
return 0 ;
}
ASSERT ( minlen ! = 0 ) ;
ASSERT ( maxlen ! = 0 ) ;
2005-04-17 02:20:36 +04:00
/*
2013-10-15 02:17:56 +04:00
* Loop over sizes , from maxlen down to minlen .
* This time , when we do the allocations , allow smaller ones
* to succeed .
2005-04-17 02:20:36 +04:00
*/
2013-10-15 02:17:56 +04:00
for ( l = xfs_highbit32 ( maxlen ) ; l > = xfs_highbit32 ( minlen ) ; l - - ) {
2005-04-17 02:20:36 +04:00
/*
2013-10-15 02:17:56 +04:00
* Loop over all the bitmap blocks , try an allocation
* starting in that block .
2005-04-17 02:20:36 +04:00
*/
2013-10-15 02:17:56 +04:00
for ( i = 0 ; i < mp - > m_sb . sb_rbmblocks ; i + + ) {
2005-04-17 02:20:36 +04:00
/*
2013-10-15 02:17:56 +04:00
* Get the summary information for this level / block .
2005-04-17 02:20:36 +04:00
*/
2013-10-15 02:17:56 +04:00
error = xfs_rtget_summary ( mp , tp , l , i , rbpp , rsb ,
& sum ) ;
2005-04-17 02:20:36 +04:00
if ( error ) {
return error ;
}
/*
2013-10-15 02:17:56 +04:00
* If nothing there , go on to next .
2005-04-17 02:20:36 +04:00
*/
2013-10-15 02:17:56 +04:00
if ( ! sum )
continue ;
2005-04-17 02:20:36 +04:00
/*
2013-10-15 02:17:56 +04:00
* Try the allocation . Make sure the specified
* minlen / maxlen are in the possible range for
* this summary level .
2005-04-17 02:20:36 +04:00
*/
2013-10-15 02:17:56 +04:00
error = xfs_rtallocate_extent_block ( mp , tp , i ,
XFS_RTMAX ( minlen , 1 < < l ) ,
XFS_RTMIN ( maxlen , ( 1 < < ( l + 1 ) ) - 1 ) ,
len , & n , rbpp , rsb , prod , & r ) ;
2005-04-17 02:20:36 +04:00
if ( error ) {
return error ;
}
/*
2013-10-15 02:17:56 +04:00
* If it worked , return that extent .
*/
if ( r ! = NULLRTBLOCK ) {
* rtblock = r ;
return 0 ;
}
/*
* If the " next block to try " returned from the
* allocator is beyond the next bitmap block ,
* skip to that bitmap block .
2005-04-17 02:20:36 +04:00
*/
2013-10-15 02:17:56 +04:00
if ( XFS_BITTOBLOCK ( mp , n ) > i + 1 )
i = XFS_BITTOBLOCK ( mp , n ) - 1 ;
2005-04-17 02:20:36 +04:00
}
}
/*
2013-10-15 02:17:56 +04:00
* Got nothing , return failure .
2005-04-17 02:20:36 +04:00
*/
2013-10-15 02:17:56 +04:00
* rtblock = NULLRTBLOCK ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
/*
2013-10-15 02:17:56 +04:00
* Allocate space to the bitmap or summary file , and zero it , for growfs .
2005-04-17 02:20:36 +04:00
*/
STATIC int /* error */
2013-10-15 02:17:56 +04:00
xfs_growfs_rt_alloc (
2005-04-17 02:20:36 +04:00
xfs_mount_t * mp , /* file system mount point */
2013-10-15 02:17:56 +04:00
xfs_extlen_t oblocks , /* old count of blocks */
xfs_extlen_t nblocks , /* new count of blocks */
xfs_inode_t * ip ) /* inode (bitmap/summary) */
2005-04-17 02:20:36 +04:00
{
2013-10-15 02:17:56 +04:00
xfs_fileoff_t bno ; /* block number in file */
xfs_buf_t * bp ; /* temporary buffer for zeroing */
int committed ; /* transaction committed flag */
xfs_daddr_t d ; /* disk block address */
int error ; /* error return value */
xfs_fsblock_t firstblock ; /* first block allocated in xaction */
xfs_bmap_free_t flist ; /* list of freed blocks */
xfs_fsblock_t fsbno ; /* filesystem block for bno */
xfs_bmbt_irec_t map ; /* block map output */
int nmap ; /* number of block maps */
int resblks ; /* space reservation */
2005-04-17 02:20:36 +04:00
/*
2013-10-15 02:17:56 +04:00
* Allocate space to the file , as necessary .
2005-04-17 02:20:36 +04:00
*/
2013-10-15 02:17:56 +04:00
while ( oblocks < nblocks ) {
int cancelflags = 0 ;
xfs_trans_t * tp ;
tp = xfs_trans_alloc ( mp , XFS_TRANS_GROWFSRT_ALLOC ) ;
resblks = XFS_GROWFSRT_SPACE_RES ( mp , nblocks - oblocks ) ;
2005-04-17 02:20:36 +04:00
/*
2013-10-15 02:17:56 +04:00
* Reserve space & log for one extent added to the file .
2005-04-17 02:20:36 +04:00
*/
2014-02-07 07:53:50 +04:00
error = xfs_trans_reserve ( tp , & M_RES ( mp ) - > tr_growrtalloc ,
2013-10-15 02:17:56 +04:00
resblks , 0 ) ;
if ( error )
goto error_cancel ;
cancelflags = XFS_TRANS_RELEASE_LOG_RES ;
2005-04-17 02:20:36 +04:00
/*
2013-10-15 02:17:56 +04:00
* Lock the inode .
2005-04-17 02:20:36 +04:00
*/
2013-10-15 02:17:56 +04:00
xfs_ilock ( ip , XFS_ILOCK_EXCL ) ;
xfs_trans_ijoin ( tp , ip , XFS_ILOCK_EXCL ) ;
xfs_bmap_init ( & flist , & firstblock ) ;
/*
* Allocate blocks to the bitmap file .
*/
nmap = 1 ;
cancelflags | = XFS_TRANS_ABORT ;
error = xfs_bmapi_write ( tp , ip , oblocks , nblocks - oblocks ,
XFS_BMAPI_METADATA , & firstblock ,
resblks , & map , & nmap , & flist ) ;
if ( ! error & & nmap < 1 )
2014-06-25 08:58:08 +04:00
error = - ENOSPC ;
2013-10-15 02:17:56 +04:00
if ( error )
goto error_cancel ;
/*
* Free any blocks freed up in the transaction , then commit .
*/
error = xfs_bmap_finish ( & tp , & flist , & committed ) ;
if ( error )
goto error_cancel ;
error = xfs_trans_commit ( tp , XFS_TRANS_RELEASE_LOG_RES ) ;
if ( error )
goto error ;
/*
* Now we need to clear the allocated blocks .
* Do this one block per transaction , to keep it simple .
*/
cancelflags = 0 ;
for ( bno = map . br_startoff , fsbno = map . br_startblock ;
bno < map . br_startoff + map . br_blockcount ;
bno + + , fsbno + + ) {
tp = xfs_trans_alloc ( mp , XFS_TRANS_GROWFSRT_ZERO ) ;
/*
* Reserve log for one block zeroing .
*/
error = xfs_trans_reserve ( tp , & M_RES ( mp ) - > tr_growrtzero ,
0 , 0 ) ;
if ( error )
goto error_cancel ;
/*
* Lock the bitmap inode .
*/
xfs_ilock ( ip , XFS_ILOCK_EXCL ) ;
xfs_trans_ijoin ( tp , ip , XFS_ILOCK_EXCL ) ;
/*
* Get a buffer for the block .
*/
d = XFS_FSB_TO_DADDR ( mp , fsbno ) ;
bp = xfs_trans_get_buf ( tp , mp - > m_ddev_targp , d ,
mp - > m_bsize , 0 ) ;
if ( bp = = NULL ) {
2014-06-25 08:58:08 +04:00
error = - EIO ;
2013-10-15 02:17:56 +04:00
error_cancel :
xfs_trans_cancel ( tp , cancelflags ) ;
goto error ;
}
memset ( bp - > b_addr , 0 , mp - > m_sb . sb_blocksize ) ;
xfs_trans_log_buf ( tp , bp , 0 , mp - > m_sb . sb_blocksize - 1 ) ;
/*
* Commit the transaction .
*/
error = xfs_trans_commit ( tp , 0 ) ;
if ( error )
goto error ;
2005-04-17 02:20:36 +04:00
}
2013-10-15 02:17:56 +04:00
/*
* Go on to the next extent , if any .
*/
oblocks = map . br_startoff + map . br_blockcount ;
2005-04-17 02:20:36 +04:00
}
return 0 ;
2013-10-15 02:17:56 +04:00
error :
return error ;
2005-04-17 02:20:36 +04:00
}
/*
* Visible ( exported ) functions .
*/
/*
* Grow the realtime area of the filesystem .
*/
int
xfs_growfs_rt (
xfs_mount_t * mp , /* mount point for filesystem */
xfs_growfs_rt_t * in ) /* growfs rt input struct */
{
xfs_rtblock_t bmbno ; /* bitmap block number */
xfs_buf_t * bp ; /* temporary buffer */
int error ; /* error return value */
xfs_mount_t * nmp ; /* new (fake) mount structure */
2014-07-30 03:12:05 +04:00
xfs_rfsblock_t nrblocks ; /* new number of realtime blocks */
2005-04-17 02:20:36 +04:00
xfs_extlen_t nrbmblocks ; /* new number of rt bitmap blocks */
2014-07-30 03:12:05 +04:00
xfs_rtblock_t nrextents ; /* new number of realtime extents */
2005-04-17 02:20:36 +04:00
uint8_t nrextslog ; /* new log2 of sb_rextents */
xfs_extlen_t nrsumblocks ; /* new number of summary blocks */
uint nrsumlevels ; /* new rt summary levels */
uint nrsumsize ; /* new size of rt summary, bytes */
xfs_sb_t * nsbp ; /* new superblock */
xfs_extlen_t rbmblocks ; /* current number of rt bitmap blocks */
xfs_extlen_t rsumblocks ; /* current number of rt summary blks */
xfs_sb_t * sbp ; /* old superblock */
xfs_fsblock_t sumbno ; /* summary block number */
sbp = & mp - > m_sb ;
/*
* Initial error checking .
*/
2008-11-26 06:20:06 +03:00
if ( ! capable ( CAP_SYS_ADMIN ) )
2014-06-25 08:58:08 +04:00
return - EPERM ;
2006-06-28 02:42:26 +04:00
if ( mp - > m_rtdev_targp = = NULL | | mp - > m_rbmip = = NULL | |
2005-04-17 02:20:36 +04:00
( nrblocks = in - > newblocks ) < = sbp - > sb_rblocks | |
( sbp - > sb_rblocks & & ( in - > extsize ! = sbp - > sb_rextsize ) ) )
2014-06-25 08:58:08 +04:00
return - EINVAL ;
2007-05-14 12:24:02 +04:00
if ( ( error = xfs_sb_validate_fsb_count ( sbp , nrblocks ) ) )
return error ;
2005-04-17 02:20:36 +04:00
/*
* Read in the last block of the device , make sure it exists .
*/
2012-04-23 09:58:49 +04:00
bp = xfs_buf_read_uncached ( mp - > m_rtdev_targp ,
2010-09-22 04:47:20 +04:00
XFS_FSB_TO_BB ( mp , nrblocks - 1 ) ,
2012-11-12 15:54:01 +04:00
XFS_FSB_TO_BB ( mp , 1 ) , 0 , NULL ) ;
2010-09-22 04:47:20 +04:00
if ( ! bp )
2014-06-25 08:58:08 +04:00
return - EIO ;
2012-11-12 15:54:02 +04:00
if ( bp - > b_error ) {
error = bp - > b_error ;
xfs_buf_relse ( bp ) ;
return error ;
}
2005-04-17 02:20:36 +04:00
xfs_buf_relse ( bp ) ;
2010-09-22 04:47:20 +04:00
2005-04-17 02:20:36 +04:00
/*
* Calculate new parameters . These are the final values to be reached .
*/
nrextents = nrblocks ;
do_div ( nrextents , in - > extsize ) ;
2006-09-28 05:03:53 +04:00
nrbmblocks = howmany_64 ( nrextents , NBBY * sbp - > sb_blocksize ) ;
2005-04-17 02:20:36 +04:00
nrextslog = xfs_highbit32 ( nrextents ) ;
nrsumlevels = nrextslog + 1 ;
nrsumsize = ( uint ) sizeof ( xfs_suminfo_t ) * nrsumlevels * nrbmblocks ;
nrsumblocks = XFS_B_TO_FSB ( mp , nrsumsize ) ;
nrsumsize = XFS_FSB_TO_B ( mp , nrsumblocks ) ;
/*
* New summary size can ' t be more than half the size of
* the log . This prevents us from getting a log overflow ,
* since we ' ll log basically the whole summary file at once .
*/
if ( nrsumblocks > ( mp - > m_sb . sb_logblocks > > 1 ) )
2014-06-25 08:58:08 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
/*
* Get the old block counts for bitmap and summary inodes .
* These can ' t change since other growfs callers are locked out .
*/
rbmblocks = XFS_B_TO_FSB ( mp , mp - > m_rbmip - > i_d . di_size ) ;
rsumblocks = XFS_B_TO_FSB ( mp , mp - > m_rsumip - > i_d . di_size ) ;
/*
* Allocate space to the bitmap and summary files , as necessary .
*/
2011-02-13 16:25:31 +03:00
error = xfs_growfs_rt_alloc ( mp , rbmblocks , nrbmblocks , mp - > m_rbmip ) ;
if ( error )
2005-04-17 02:20:36 +04:00
return error ;
2011-02-13 16:25:31 +03:00
error = xfs_growfs_rt_alloc ( mp , rsumblocks , nrsumblocks , mp - > m_rsumip ) ;
if ( error )
2005-04-17 02:20:36 +04:00
return error ;
2006-09-28 05:03:44 +04:00
/*
* Allocate a new ( fake ) mount / sb .
*/
nmp = kmem_alloc ( sizeof ( * nmp ) , KM_SLEEP ) ;
2005-04-17 02:20:36 +04:00
/*
* Loop over the bitmap blocks .
* We will do everything one bitmap block at a time .
* Skip the current block if it is exactly full .
* This also deals with the case where there were no rtextents before .
*/
for ( bmbno = sbp - > sb_rbmblocks -
( ( sbp - > sb_rextents & ( ( 1 < < mp - > m_blkbit_log ) - 1 ) ) ! = 0 ) ;
bmbno < nrbmblocks ;
bmbno + + ) {
2008-11-28 06:23:34 +03:00
xfs_trans_t * tp ;
int cancelflags = 0 ;
2005-04-17 02:20:36 +04:00
* nmp = * mp ;
nsbp = & nmp - > m_sb ;
/*
* Calculate new sb and mount fields for this round .
*/
nsbp - > sb_rextsize = in - > extsize ;
nsbp - > sb_rbmblocks = bmbno + 1 ;
nsbp - > sb_rblocks =
XFS_RTMIN ( nrblocks ,
nsbp - > sb_rbmblocks * NBBY *
nsbp - > sb_blocksize * nsbp - > sb_rextsize ) ;
nsbp - > sb_rextents = nsbp - > sb_rblocks ;
do_div ( nsbp - > sb_rextents , nsbp - > sb_rextsize ) ;
2008-08-13 09:41:12 +04:00
ASSERT ( nsbp - > sb_rextents ! = 0 ) ;
2005-04-17 02:20:36 +04:00
nsbp - > sb_rextslog = xfs_highbit32 ( nsbp - > sb_rextents ) ;
nrsumlevels = nmp - > m_rsumlevels = nsbp - > sb_rextslog + 1 ;
nrsumsize =
( uint ) sizeof ( xfs_suminfo_t ) * nrsumlevels *
nsbp - > sb_rbmblocks ;
nrsumblocks = XFS_B_TO_FSB ( mp , nrsumsize ) ;
nmp - > m_rsumsize = nrsumsize = XFS_FSB_TO_B ( mp , nrsumblocks ) ;
/*
* Start a transaction , get the log reservation .
*/
tp = xfs_trans_alloc ( mp , XFS_TRANS_GROWFSRT_FREE ) ;
2013-08-12 14:49:59 +04:00
error = xfs_trans_reserve ( tp , & M_RES ( mp ) - > tr_growrtfree ,
0 , 0 ) ;
if ( error )
2008-11-28 06:23:34 +03:00
goto error_cancel ;
2005-04-17 02:20:36 +04:00
/*
* Lock out other callers by grabbing the bitmap inode lock .
*/
2011-02-13 16:25:31 +03:00
xfs_ilock ( mp - > m_rbmip , XFS_ILOCK_EXCL ) ;
2011-09-19 19:00:54 +04:00
xfs_trans_ijoin ( tp , mp - > m_rbmip , XFS_ILOCK_EXCL ) ;
2005-04-17 02:20:36 +04:00
/*
* Update the bitmap inode ' s size .
*/
mp - > m_rbmip - > i_d . di_size =
nsbp - > sb_rbmblocks * nsbp - > sb_blocksize ;
xfs_trans_log_inode ( tp , mp - > m_rbmip , XFS_ILOG_CORE ) ;
cancelflags | = XFS_TRANS_ABORT ;
/*
* Get the summary inode into the transaction .
*/
2011-02-13 16:25:31 +03:00
xfs_ilock ( mp - > m_rsumip , XFS_ILOCK_EXCL ) ;
2011-09-19 19:00:54 +04:00
xfs_trans_ijoin ( tp , mp - > m_rsumip , XFS_ILOCK_EXCL ) ;
2005-04-17 02:20:36 +04:00
/*
* Update the summary inode ' s size .
*/
mp - > m_rsumip - > i_d . di_size = nmp - > m_rsumsize ;
xfs_trans_log_inode ( tp , mp - > m_rsumip , XFS_ILOG_CORE ) ;
/*
* Copy summary data from old to new sizes .
* Do this when the real size ( not block - aligned ) changes .
*/
if ( sbp - > sb_rbmblocks ! = nsbp - > sb_rbmblocks | |
mp - > m_rsumlevels ! = nmp - > m_rsumlevels ) {
error = xfs_rtcopy_summary ( mp , nmp , tp ) ;
if ( error )
2008-11-28 06:23:34 +03:00
goto error_cancel ;
2005-04-17 02:20:36 +04:00
}
/*
* Update superblock fields .
*/
if ( nsbp - > sb_rextsize ! = sbp - > sb_rextsize )
xfs_trans_mod_sb ( tp , XFS_TRANS_SB_REXTSIZE ,
nsbp - > sb_rextsize - sbp - > sb_rextsize ) ;
if ( nsbp - > sb_rbmblocks ! = sbp - > sb_rbmblocks )
xfs_trans_mod_sb ( tp , XFS_TRANS_SB_RBMBLOCKS ,
nsbp - > sb_rbmblocks - sbp - > sb_rbmblocks ) ;
if ( nsbp - > sb_rblocks ! = sbp - > sb_rblocks )
xfs_trans_mod_sb ( tp , XFS_TRANS_SB_RBLOCKS ,
nsbp - > sb_rblocks - sbp - > sb_rblocks ) ;
if ( nsbp - > sb_rextents ! = sbp - > sb_rextents )
xfs_trans_mod_sb ( tp , XFS_TRANS_SB_REXTENTS ,
nsbp - > sb_rextents - sbp - > sb_rextents ) ;
if ( nsbp - > sb_rextslog ! = sbp - > sb_rextslog )
xfs_trans_mod_sb ( tp , XFS_TRANS_SB_REXTSLOG ,
nsbp - > sb_rextslog - sbp - > sb_rextslog ) ;
/*
* Free new extent .
*/
bp = NULL ;
error = xfs_rtfree_range ( nmp , tp , sbp - > sb_rextents ,
nsbp - > sb_rextents - sbp - > sb_rextents , & bp , & sumbno ) ;
2008-11-28 06:23:34 +03:00
if ( error ) {
error_cancel :
xfs_trans_cancel ( tp , cancelflags ) ;
2006-09-28 05:03:44 +04:00
break ;
2008-11-28 06:23:34 +03:00
}
2005-04-17 02:20:36 +04:00
/*
* Mark more blocks free in the superblock .
*/
xfs_trans_mod_sb ( tp , XFS_TRANS_SB_FREXTENTS ,
nsbp - > sb_rextents - sbp - > sb_rextents ) ;
/*
* Update mp values into the real mp structure .
*/
mp - > m_rsumlevels = nrsumlevels ;
mp - > m_rsumsize = nrsumsize ;
2008-04-10 06:21:18 +04:00
error = xfs_trans_commit ( tp , 0 ) ;
2008-11-28 06:23:34 +03:00
if ( error )
2008-04-10 06:21:18 +04:00
break ;
2005-04-17 02:20:36 +04:00
}
2006-09-28 05:03:44 +04:00
2005-04-17 02:20:36 +04:00
/*
2006-09-28 05:03:44 +04:00
* Free the fake mp structure .
2005-04-17 02:20:36 +04:00
*/
2008-05-19 10:31:57 +04:00
kmem_free ( nmp ) ;
2006-09-28 05:03:44 +04:00
2005-04-17 02:20:36 +04:00
return error ;
}
/*
* Allocate an extent in the realtime subvolume , with the usual allocation
* parameters . The length units are all in realtime extents , as is the
* result block number .
*/
int /* error */
xfs_rtallocate_extent (
xfs_trans_t * tp , /* transaction pointer */
xfs_rtblock_t bno , /* starting block number to allocate */
xfs_extlen_t minlen , /* minimum length to allocate */
xfs_extlen_t maxlen , /* maximum length to allocate */
xfs_extlen_t * len , /* out: actual length allocated */
xfs_alloctype_t type , /* allocation type XFS_ALLOCTYPE... */
int wasdel , /* was a delayed allocation extent */
xfs_extlen_t prod , /* extent product factor */
xfs_rtblock_t * rtblock ) /* out: start block allocated */
{
2011-01-25 12:06:19 +03:00
xfs_mount_t * mp = tp - > t_mountp ;
2005-04-17 02:20:36 +04:00
int error ; /* error value */
xfs_rtblock_t r ; /* result allocated block */
xfs_fsblock_t sb ; /* summary file block number */
xfs_buf_t * sumbp ; /* summary file block buffer */
2011-01-25 12:06:19 +03:00
ASSERT ( xfs_isilocked ( mp - > m_rbmip , XFS_ILOCK_EXCL ) ) ;
2005-04-17 02:20:36 +04:00
ASSERT ( minlen > 0 & & minlen < = maxlen ) ;
2011-01-25 12:06:19 +03:00
2005-04-17 02:20:36 +04:00
/*
* If prod is set then figure out what to do to minlen and maxlen .
*/
if ( prod > 1 ) {
xfs_extlen_t i ;
if ( ( i = maxlen % prod ) )
maxlen - = i ;
if ( ( i = minlen % prod ) )
minlen + = prod - i ;
if ( maxlen < minlen ) {
* rtblock = NULLRTBLOCK ;
return 0 ;
}
}
2011-01-25 12:06:19 +03:00
2005-04-17 02:20:36 +04:00
sumbp = NULL ;
/*
* Allocate by size , or near another block , or exactly at some block .
*/
switch ( type ) {
case XFS_ALLOCTYPE_ANY_AG :
error = xfs_rtallocate_extent_size ( mp , tp , minlen , maxlen , len ,
& sumbp , & sb , prod , & r ) ;
break ;
case XFS_ALLOCTYPE_NEAR_BNO :
error = xfs_rtallocate_extent_near ( mp , tp , bno , minlen , maxlen ,
len , & sumbp , & sb , prod , & r ) ;
break ;
case XFS_ALLOCTYPE_THIS_BNO :
error = xfs_rtallocate_extent_exact ( mp , tp , bno , minlen , maxlen ,
len , & sumbp , & sb , prod , & r ) ;
break ;
default :
2014-06-25 08:58:08 +04:00
error = - EIO ;
2005-04-17 02:20:36 +04:00
ASSERT ( 0 ) ;
}
2011-01-25 12:06:19 +03:00
if ( error )
2005-04-17 02:20:36 +04:00
return error ;
2011-01-25 12:06:19 +03:00
2005-04-17 02:20:36 +04:00
/*
* If it worked , update the superblock .
*/
if ( r ! = NULLRTBLOCK ) {
long slen = ( long ) * len ;
ASSERT ( * len > = minlen & & * len < = maxlen ) ;
if ( wasdel )
xfs_trans_mod_sb ( tp , XFS_TRANS_SB_RES_FREXTENTS , - slen ) ;
else
xfs_trans_mod_sb ( tp , XFS_TRANS_SB_FREXTENTS , - slen ) ;
}
* rtblock = r ;
return 0 ;
}
/*
* Initialize realtime fields in the mount structure .
*/
int /* error */
xfs_rtmount_init (
xfs_mount_t * mp ) /* file system mount structure */
{
xfs_buf_t * bp ; /* buffer for last block of subvolume */
xfs_daddr_t d ; /* address of last block of subvolume */
xfs_sb_t * sbp ; /* filesystem superblock copy in mount */
sbp = & mp - > m_sb ;
if ( sbp - > sb_rblocks = = 0 )
return 0 ;
if ( mp - > m_rtdev_targp = = NULL ) {
2011-03-07 02:08:35 +03:00
xfs_warn ( mp ,
" Filesystem has a realtime volume, use rtdev=device option " ) ;
2014-06-25 08:58:08 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
}
mp - > m_rsumlevels = sbp - > sb_rextslog + 1 ;
mp - > m_rsumsize =
( uint ) sizeof ( xfs_suminfo_t ) * mp - > m_rsumlevels *
sbp - > sb_rbmblocks ;
mp - > m_rsumsize = roundup ( mp - > m_rsumsize , sbp - > sb_blocksize ) ;
mp - > m_rbmip = mp - > m_rsumip = NULL ;
/*
* Check that the realtime section is an ok size .
*/
d = ( xfs_daddr_t ) XFS_FSB_TO_BB ( mp , mp - > m_sb . sb_rblocks ) ;
if ( XFS_BB_TO_FSB ( mp , d ) ! = mp - > m_sb . sb_rblocks ) {
2011-03-07 02:08:35 +03:00
xfs_warn ( mp , " realtime mount -- %llu != %llu " ,
2005-04-17 02:20:36 +04:00
( unsigned long long ) XFS_BB_TO_FSB ( mp , d ) ,
( unsigned long long ) mp - > m_sb . sb_rblocks ) ;
2014-06-25 08:58:08 +04:00
return - EFBIG ;
2005-04-17 02:20:36 +04:00
}
2012-04-23 09:58:49 +04:00
bp = xfs_buf_read_uncached ( mp - > m_rtdev_targp ,
2010-09-22 04:47:20 +04:00
d - XFS_FSB_TO_BB ( mp , 1 ) ,
2012-11-12 15:54:01 +04:00
XFS_FSB_TO_BB ( mp , 1 ) , 0 , NULL ) ;
2012-11-12 15:54:02 +04:00
if ( ! bp | | bp - > b_error ) {
2011-03-07 02:08:35 +03:00
xfs_warn ( mp , " realtime device size check failed " ) ;
2012-11-12 15:54:02 +04:00
if ( bp )
xfs_buf_relse ( bp ) ;
2014-06-25 08:58:08 +04:00
return - EIO ;
2005-04-17 02:20:36 +04:00
}
xfs_buf_relse ( bp ) ;
return 0 ;
}
/*
* Get the bitmap and summary inodes into the mount structure
* at mount time .
*/
int /* error */
xfs_rtmount_inodes (
xfs_mount_t * mp ) /* file system mount structure */
{
int error ; /* error return value */
xfs_sb_t * sbp ;
sbp = & mp - > m_sb ;
if ( sbp - > sb_rbmino = = NULLFSINO )
return 0 ;
2010-06-24 05:35:17 +04:00
error = xfs_iget ( mp , NULL , sbp - > sb_rbmino , 0 , 0 , & mp - > m_rbmip ) ;
2005-04-17 02:20:36 +04:00
if ( error )
return error ;
ASSERT ( mp - > m_rbmip ! = NULL ) ;
ASSERT ( sbp - > sb_rsumino ! = NULLFSINO ) ;
2010-06-24 05:35:17 +04:00
error = xfs_iget ( mp , NULL , sbp - > sb_rsumino , 0 , 0 , & mp - > m_rsumip ) ;
2005-04-17 02:20:36 +04:00
if ( error ) {
2008-03-27 10:01:08 +03:00
IRELE ( mp - > m_rbmip ) ;
2005-04-17 02:20:36 +04:00
return error ;
}
ASSERT ( mp - > m_rsumip ! = NULL ) ;
return 0 ;
}
2009-02-04 11:33:58 +03:00
void
xfs_rtunmount_inodes (
struct xfs_mount * mp )
{
if ( mp - > m_rbmip )
IRELE ( mp - > m_rbmip ) ;
if ( mp - > m_rsumip )
IRELE ( mp - > m_rsumip ) ;
}
2005-04-17 02:20:36 +04:00
/*
* Pick an extent for allocation at the start of a new realtime file .
* Use the sequence number stored in the atime field of the bitmap inode .
* Translate this to a fraction of the rtextents , and return the product
* of rtextents and the fraction .
* The fraction sequence is 0 , 1 / 2 , 1 / 4 , 3 / 4 , 1 / 8 , . . . , 7 / 8 , 1 / 16 , . . .
*/
int /* error */
xfs_rtpick_extent (
xfs_mount_t * mp , /* file system mount point */
xfs_trans_t * tp , /* transaction pointer */
xfs_extlen_t len , /* allocation length (rtextents) */
xfs_rtblock_t * pick ) /* result rt extent */
{
xfs_rtblock_t b ; /* result block */
int log2 ; /* log of sequence number */
__uint64_t resid ; /* residual after log removed */
__uint64_t seq ; /* sequence number of file creation */
__uint64_t * seqp ; /* pointer to seqno in inode */
2011-01-25 12:06:19 +03:00
ASSERT ( xfs_isilocked ( mp - > m_rbmip , XFS_ILOCK_EXCL ) ) ;
seqp = ( __uint64_t * ) & mp - > m_rbmip - > i_d . di_atime ;
if ( ! ( mp - > m_rbmip - > i_d . di_flags & XFS_DIFLAG_NEWRTBM ) ) {
mp - > m_rbmip - > i_d . di_flags | = XFS_DIFLAG_NEWRTBM ;
2005-04-17 02:20:36 +04:00
* seqp = 0 ;
}
seq = * seqp ;
if ( ( log2 = xfs_highbit64 ( seq ) ) = = - 1 )
b = 0 ;
else {
resid = seq - ( 1ULL < < log2 ) ;
b = ( mp - > m_sb . sb_rextents * ( ( resid < < 1 ) + 1ULL ) ) > >
( log2 + 1 ) ;
if ( b > = mp - > m_sb . sb_rextents )
b = do_mod ( b , mp - > m_sb . sb_rextents ) ;
if ( b + len > mp - > m_sb . sb_rextents )
b = mp - > m_sb . sb_rextents - len ;
}
* seqp = seq + 1 ;
2011-01-25 12:06:19 +03:00
xfs_trans_log_inode ( tp , mp - > m_rbmip , XFS_ILOG_CORE ) ;
2005-04-17 02:20:36 +04:00
* pick = b ;
return 0 ;
}