2019-05-27 09:55:05 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2005-04-17 02:20:36 +04:00
/*
* Copyright ( C ) International Business Machines Corp . , 2000 - 2004
*/
# include <linux/fs.h>
# include <linux/quotaops.h>
# include "jfs_incore.h"
2005-05-05 00:29:35 +04:00
# include "jfs_inode.h"
2005-04-17 02:20:36 +04:00
# include "jfs_superblock.h"
# include "jfs_dmap.h"
# include "jfs_extent.h"
# include "jfs_debug.h"
/*
* forward references
*/
static int extBalloc ( struct inode * , s64 , s64 * , s64 * ) ;
static s64 extRoundDown ( s64 nb ) ;
2007-06-07 00:28:35 +04:00
# define DPD(a) (printk("(a): %d\n",(a)))
# define DPC(a) (printk("(a): %c\n",(a)))
2005-04-17 02:20:36 +04:00
# define DPL1(a) \
{ \
if ( ( a ) > > 32 ) \
printk ( " (a): %x%08x " , ( a ) ) ; \
else \
printk ( " (a): %x " , ( a ) < < 32 ) ; \
}
# define DPL(a) \
{ \
if ( ( a ) > > 32 ) \
printk ( " (a): %x%08x \n " , ( a ) ) ; \
else \
printk ( " (a): %x \n " , ( a ) < < 32 ) ; \
}
2007-06-07 00:28:35 +04:00
# define DPD1(a) (printk("(a): %d ",(a)))
# define DPX(a) (printk("(a): %08x\n",(a)))
# define DPX1(a) (printk("(a): %08x ",(a)))
# define DPS(a) (printk("%s\n",(a)))
# define DPE(a) (printk("\nENTERING: %s\n",(a)))
# define DPE1(a) (printk("\nENTERING: %s",(a)))
# define DPS1(a) (printk(" %s ",(a)))
2005-04-17 02:20:36 +04:00
/*
* NAME : extAlloc ( )
*
2007-06-07 00:28:35 +04:00
* FUNCTION : allocate an extent for a specified page range within a
2005-04-17 02:20:36 +04:00
* file .
*
* PARAMETERS :
* ip - the inode of the file .
* xlen - requested extent length .
* pno - the starting page number with the file .
* xp - pointer to an xad . on entry , xad describes an
* extent that is used as an allocation hint if the
* xaddr of the xad is non - zero . on successful exit ,
* the xad describes the newly allocated extent .
2006-10-01 10:27:14 +04:00
* abnr - bool indicating whether the newly allocated extent
2005-04-17 02:20:36 +04:00
* should be marked as allocated but not recorded .
*
* RETURN VALUES :
2007-06-07 00:28:35 +04:00
* 0 - success
* - EIO - i / o error .
* - ENOSPC - insufficient disk resources .
2005-04-17 02:20:36 +04:00
*/
int
2006-10-01 10:27:14 +04:00
extAlloc ( struct inode * ip , s64 xlen , s64 pno , xad_t * xp , bool abnr )
2005-04-17 02:20:36 +04:00
{
struct jfs_sb_info * sbi = JFS_SBI ( ip - > i_sb ) ;
s64 nxlen , nxaddr , xoff , hint , xaddr = 0 ;
int rc ;
int xflag ;
/* This blocks if we are low on resources */
txBeginAnon ( ip - > i_sb ) ;
/* Avoid race with jfs_commit_inode() */
2006-01-25 00:22:50 +03:00
mutex_lock ( & JFS_IP ( ip ) - > commit_mutex ) ;
2005-04-17 02:20:36 +04:00
/* validate extent length */
if ( xlen > MAXXLEN )
xlen = MAXXLEN ;
/* get the page's starting extent offset */
xoff = pno < < sbi - > l2nbperpage ;
/* check if an allocation hint was provided */
if ( ( hint = addressXAD ( xp ) ) ) {
/* get the size of the extent described by the hint */
nxlen = lengthXAD ( xp ) ;
/* check if the hint is for the portion of the file
* immediately previous to the current allocation
* request and if hint extent has the same abnr
* value as the current request . if so , we can
* extend the hint extent to include the current
* extent if we can allocate the blocks immediately
* following the hint extent .
*/
if ( offsetXAD ( xp ) + nxlen = = xoff & &
2006-10-01 10:27:14 +04:00
abnr = = ( ( xp - > flag & XAD_NOTRECORDED ) ? true : false ) )
2005-04-17 02:20:36 +04:00
xaddr = hint + nxlen ;
/* adjust the hint to the last block of the extent */
hint + = ( nxlen - 1 ) ;
}
/* allocate the disk blocks for the extent. initially, extBalloc()
2006-10-02 18:55:27 +04:00
* will try to allocate disk blocks for the requested size ( xlen ) .
2011-03-31 05:57:33 +04:00
* if this fails ( xlen contiguous free blocks not available ) , it ' ll
2005-04-17 02:20:36 +04:00
* try to allocate a smaller number of blocks ( producing a smaller
* extent ) , with this smaller number of blocks consisting of the
* requested number of blocks rounded down to the next smaller
* power of 2 number ( i . e . 16 - > 8 ) . it ' ll continue to round down
* and retry the allocation until the number of blocks to allocate
* is smaller than the number of blocks per page .
*/
nxlen = xlen ;
if ( ( rc = extBalloc ( ip , hint ? hint : INOHINT ( ip ) , & nxlen , & nxaddr ) ) ) {
2006-01-25 00:22:50 +03:00
mutex_unlock ( & JFS_IP ( ip ) - > commit_mutex ) ;
2005-04-17 02:20:36 +04:00
return ( rc ) ;
}
/* Allocate blocks to quota. */
2010-03-03 17:05:00 +03:00
rc = dquot_alloc_block ( ip , nxlen ) ;
if ( rc ) {
2005-04-17 02:20:36 +04:00
dbFree ( ip , nxaddr , ( s64 ) nxlen ) ;
2006-01-25 00:22:50 +03:00
mutex_unlock ( & JFS_IP ( ip ) - > commit_mutex ) ;
2010-03-03 17:05:00 +03:00
return rc ;
2005-04-17 02:20:36 +04:00
}
/* determine the value of the extent flag */
2006-10-01 10:27:14 +04:00
xflag = abnr ? XAD_NOTRECORDED : 0 ;
2005-04-17 02:20:36 +04:00
2006-10-02 18:55:27 +04:00
/* if we can extend the hint extent to cover the current request,
2005-04-17 02:20:36 +04:00
* extend it . otherwise , insert a new extent to
* cover the current request .
*/
if ( xaddr & & xaddr = = nxaddr )
rc = xtExtend ( 0 , ip , xoff , ( int ) nxlen , 0 ) ;
else
rc = xtInsert ( 0 , ip , xflag , xoff , ( int ) nxlen , & nxaddr , 0 ) ;
2006-10-02 18:55:27 +04:00
/* if the extend or insert failed,
2005-04-17 02:20:36 +04:00
* free the newly allocated blocks and return the error .
*/
if ( rc ) {
dbFree ( ip , nxaddr , nxlen ) ;
2010-03-03 17:05:00 +03:00
dquot_free_block ( ip , nxlen ) ;
2006-01-25 00:22:50 +03:00
mutex_unlock ( & JFS_IP ( ip ) - > commit_mutex ) ;
2005-04-17 02:20:36 +04:00
return ( rc ) ;
}
/* set the results of the extent allocation */
XADaddress ( xp , nxaddr ) ;
XADlength ( xp , nxlen ) ;
XADoffset ( xp , xoff ) ;
xp - > flag = xflag ;
mark_inode_dirty ( ip ) ;
2006-01-25 00:22:50 +03:00
mutex_unlock ( & JFS_IP ( ip ) - > commit_mutex ) ;
2005-04-17 02:20:36 +04:00
/*
* COMMIT_SyncList flags an anonymous tlock on page that is on
* sync list .
* We need to commit the inode to get the page written disk .
*/
if ( test_and_clear_cflag ( COMMIT_Synclist , ip ) )
jfs_commit_inode ( ip , 0 ) ;
return ( 0 ) ;
}
/*
2007-06-07 00:28:35 +04:00
* NAME : extHint ( )
2005-04-17 02:20:36 +04:00
*
2007-06-07 00:28:35 +04:00
* FUNCTION : produce an extent allocation hint for a file offset .
2005-04-17 02:20:36 +04:00
*
* PARAMETERS :
* ip - the inode of the file .
* offset - file offset for which the hint is needed .
* xp - pointer to the xad that is to be filled in with
* the hint .
*
* RETURN VALUES :
2007-06-07 00:28:35 +04:00
* 0 - success
* - EIO - i / o error .
2005-04-17 02:20:36 +04:00
*/
int extHint ( struct inode * ip , s64 offset , xad_t * xp )
{
struct super_block * sb = ip - > i_sb ;
2009-01-10 00:42:04 +03:00
int nbperpage = JFS_SBI ( sb ) - > nbperpage ;
2005-04-17 02:20:36 +04:00
s64 prev ;
2009-01-10 00:42:04 +03:00
int rc = 0 ;
s64 xaddr ;
int xlen ;
int xflag ;
2005-04-17 02:20:36 +04:00
/* init the hint as "no hint provided" */
XADaddress ( xp , 0 ) ;
/* determine the starting extent offset of the page previous
* to the page containing the offset .
*/
prev = ( ( offset & ~ POFFSET ) > > JFS_SBI ( sb ) - > l2bsize ) - nbperpage ;
2009-01-10 00:42:04 +03:00
/* if the offset is in the first page of the file, no hint provided.
2005-04-17 02:20:36 +04:00
*/
if ( prev < 0 )
2009-01-10 00:42:04 +03:00
goto out ;
2005-04-17 02:20:36 +04:00
2009-01-10 00:42:04 +03:00
rc = xtLookup ( ip , prev , nbperpage , & xflag , & xaddr , & xlen , 0 ) ;
2005-04-17 02:20:36 +04:00
2009-01-10 00:42:04 +03:00
if ( ( rc = = 0 ) & & xlen ) {
if ( xlen ! = nbperpage ) {
2013-06-05 03:39:15 +04:00
jfs_error ( ip - > i_sb , " corrupt xtree \n " ) ;
2009-01-10 00:42:04 +03:00
rc = - EIO ;
}
XADaddress ( xp , xaddr ) ;
XADlength ( xp , xlen ) ;
2009-06-16 22:43:22 +04:00
XADoffset ( xp , prev ) ;
2009-01-10 00:42:04 +03:00
/*
* only preserve the abnr flag within the xad flags
* of the returned hint .
*/
xp - > flag = xflag & XAD_NOTRECORDED ;
} else
rc = 0 ;
2005-04-17 02:20:36 +04:00
2009-01-10 00:42:04 +03:00
out :
return ( rc ) ;
2005-04-17 02:20:36 +04:00
}
/*
2007-06-07 00:28:35 +04:00
* NAME : extRecord ( )
2005-04-17 02:20:36 +04:00
*
2007-06-07 00:28:35 +04:00
* FUNCTION : change a page with a file from not recorded to recorded .
2005-04-17 02:20:36 +04:00
*
* PARAMETERS :
* ip - inode of the file .
* cp - cbuf of the file page .
*
* RETURN VALUES :
2007-06-07 00:28:35 +04:00
* 0 - success
* - EIO - i / o error .
* - ENOSPC - insufficient disk resources .
2005-04-17 02:20:36 +04:00
*/
int extRecord ( struct inode * ip , xad_t * xp )
{
int rc ;
txBeginAnon ( ip - > i_sb ) ;
2006-01-25 00:22:50 +03:00
mutex_lock ( & JFS_IP ( ip ) - > commit_mutex ) ;
2005-04-17 02:20:36 +04:00
/* update the extent */
rc = xtUpdate ( 0 , ip , xp ) ;
2006-01-25 00:22:50 +03:00
mutex_unlock ( & JFS_IP ( ip ) - > commit_mutex ) ;
2005-04-17 02:20:36 +04:00
return rc ;
}
/*
* NAME : extBalloc ( )
*
2007-06-07 00:28:35 +04:00
* FUNCTION : allocate disk blocks to form an extent .
2005-04-17 02:20:36 +04:00
*
* initially , we will try to allocate disk blocks for the
2006-10-02 18:55:27 +04:00
* requested size ( nblocks ) . if this fails ( nblocks
2011-03-31 05:57:33 +04:00
* contiguous free blocks not available ) , we ' ll try to allocate
2005-04-17 02:20:36 +04:00
* a smaller number of blocks ( producing a smaller extent ) , with
* this smaller number of blocks consisting of the requested
* number of blocks rounded down to the next smaller power of 2
* number ( i . e . 16 - > 8 ) . we ' ll continue to round down and
* retry the allocation until the number of blocks to allocate
* is smaller than the number of blocks per page .
2006-10-02 18:55:27 +04:00
*
2005-04-17 02:20:36 +04:00
* PARAMETERS :
* ip - the inode of the file .
* hint - disk block number to be used as an allocation hint .
* * nblocks - pointer to an s64 value . on entry , this value specifies
* the desired number of block to be allocated . on successful
* exit , this value is set to the number of blocks actually
* allocated .
* blkno - pointer to a block address that is filled in on successful
2006-10-02 18:55:27 +04:00
* return with the starting block number of the newly
2005-04-17 02:20:36 +04:00
* allocated block range .
*
* RETURN VALUES :
2007-06-07 00:28:35 +04:00
* 0 - success
* - EIO - i / o error .
* - ENOSPC - insufficient disk resources .
2005-04-17 02:20:36 +04:00
*/
static int
extBalloc ( struct inode * ip , s64 hint , s64 * nblocks , s64 * blkno )
{
struct jfs_inode_info * ji = JFS_IP ( ip ) ;
struct jfs_sb_info * sbi = JFS_SBI ( ip - > i_sb ) ;
s64 nb , nblks , daddr , max ;
int rc , nbperpage = sbi - > nbperpage ;
struct bmap * bmp = sbi - > bmap ;
int ag ;
/* get the number of blocks to initially attempt to allocate.
* we ' ll first try the number of blocks requested unless this
2006-06-26 20:35:02 +04:00
* number is greater than the maximum number of contiguous free
2006-10-02 18:55:27 +04:00
* blocks in the map . in that case , we ' ll start off with the
2005-04-17 02:20:36 +04:00
* maximum free .
*/
max = ( s64 ) 1 < < bmp - > db_maxfreebud ;
if ( * nblocks > = max & & * nblocks > nbperpage )
nb = nblks = ( max > nbperpage ) ? max : nbperpage ;
else
nb = nblks = * nblocks ;
/* try to allocate blocks */
while ( ( rc = dbAlloc ( ip , hint , nb , & daddr ) ) ! = 0 ) {
/* if something other than an out of space error,
* stop and return this error .
*/
if ( rc ! = - ENOSPC )
return ( rc ) ;
/* decrease the allocation request size */
nb = min ( nblks , extRoundDown ( nb ) ) ;
/* give up if we cannot cover a page */
if ( nb < nbperpage )
return ( rc ) ;
}
* nblocks = nb ;
* blkno = daddr ;
if ( S_ISREG ( ip - > i_mode ) & & ( ji - > fileset = = FILESYSTEM_I ) ) {
ag = BLKTOAG ( daddr , sbi ) ;
spin_lock_irq ( & ji - > ag_lock ) ;
if ( ji - > active_ag = = - 1 ) {
atomic_inc ( & bmp - > db_active [ ag ] ) ;
ji - > active_ag = ag ;
} else if ( ji - > active_ag ! = ag ) {
atomic_dec ( & bmp - > db_active [ ji - > active_ag ] ) ;
atomic_inc ( & bmp - > db_active [ ag ] ) ;
ji - > active_ag = ag ;
}
spin_unlock_irq ( & ji - > ag_lock ) ;
}
return ( 0 ) ;
}
/*
2007-06-07 00:28:35 +04:00
* NAME : extRoundDown ( )
2005-04-17 02:20:36 +04:00
*
2007-06-07 00:28:35 +04:00
* FUNCTION : round down a specified number of blocks to the next
2005-04-17 02:20:36 +04:00
* smallest power of 2 number .
*
* PARAMETERS :
* nb - the inode of the file .
*
* RETURN VALUES :
2007-06-07 00:28:35 +04:00
* next smallest power of 2 number .
2005-04-17 02:20:36 +04:00
*/
static s64 extRoundDown ( s64 nb )
{
int i ;
u64 m , k ;
for ( i = 0 , m = ( u64 ) 1 < < 63 ; i < 64 ; i + + , m > > = 1 ) {
if ( m & nb )
break ;
}
i = 63 - i ;
k = ( u64 ) 1 < < i ;
k = ( ( k - 1 ) & nb ) ? k : k > > 1 ;
return ( k ) ;
}