2012-09-17 20:58:19 +04:00
/*
* Copyright ( C ) Tino Reichardt , 2012
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* 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 . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
# include <linux/fs.h>
# include <linux/slab.h>
# include <linux/blkdev.h>
# include "jfs_incore.h"
# include "jfs_superblock.h"
# include "jfs_discard.h"
# include "jfs_dmap.h"
# include "jfs_debug.h"
/*
* NAME : jfs_issue_discard ( )
*
* FUNCTION : TRIM the specified block range on device , if supported
*
* PARAMETERS :
* ip - pointer to in - core inode
* blkno - starting block number to be trimmed ( 0. . N )
* nblocks - number of blocks to be trimmed
*
* RETURN VALUES :
* none
*
* serialization : IREAD_LOCK ( ipbmap ) held on entry / exit ;
*/
void jfs_issue_discard ( struct inode * ip , u64 blkno , u64 nblocks )
{
struct super_block * sb = ip - > i_sb ;
int r = 0 ;
r = sb_issue_discard ( sb , blkno , nblocks , GFP_NOFS , 0 ) ;
if ( unlikely ( r ! = 0 ) ) {
jfs_err ( " JFS: sb_issue_discard " \
" (%p, %llu, %llu, GFP_NOFS, 0) = %d => failed! \n " ,
sb , ( unsigned long long ) blkno ,
( unsigned long long ) nblocks , r ) ;
}
jfs_info ( " JFS: sb_issue_discard " \
" (%p, %llu, %llu, GFP_NOFS, 0) = %d \n " ,
sb , ( unsigned long long ) blkno ,
( unsigned long long ) nblocks , r ) ;
return ;
}
/*
* NAME : jfs_ioc_trim ( )
*
* FUNCTION : attempt to discard ( TRIM ) all free blocks from the
* filesystem .
*
* PARAMETERS :
* ip - pointer to in - core inode ;
* range - the range , given by user space
*
* RETURN VALUES :
* 0 - success
* - EIO - i / o error
*/
int jfs_ioc_trim ( struct inode * ip , struct fstrim_range * range )
{
struct inode * ipbmap = JFS_SBI ( ip - > i_sb ) - > ipbmap ;
struct bmap * bmp = JFS_SBI ( ip - > i_sb ) - > bmap ;
struct super_block * sb = ipbmap - > i_sb ;
int agno , agno_end ;
2012-10-16 13:38:06 +04:00
u64 start , end , minlen ;
2012-09-17 20:58:19 +04:00
u64 trimmed = 0 ;
/**
* convert byte values to block size of filesystem :
* start : First Byte to trim
* len : number of Bytes to trim from start
* minlen : minimum extent length in Bytes
*/
start = range - > start > > sb - > s_blocksize_bits ;
end = start + ( range - > len > > sb - > s_blocksize_bits ) - 1 ;
minlen = range - > minlen > > sb - > s_blocksize_bits ;
2012-10-16 13:38:06 +04:00
if ( minlen = = 0 )
2012-09-17 20:58:19 +04:00
minlen = 1 ;
2012-10-16 13:38:06 +04:00
if ( minlen > bmp - > db_agsize | |
start > = bmp - > db_mapsize | |
range - > len < sb - > s_blocksize )
return - EINVAL ;
if ( end > = bmp - > db_mapsize )
end = bmp - > db_mapsize - 1 ;
2012-09-17 20:58:19 +04:00
/**
* we trim all ag ' s within the range
*/
agno = BLKTOAG ( start , JFS_SBI ( ip - > i_sb ) ) ;
agno_end = BLKTOAG ( end , JFS_SBI ( ip - > i_sb ) ) ;
while ( agno < = agno_end ) {
trimmed + = dbDiscardAG ( ip , agno , minlen ) ;
agno + + ;
}
range - > len = trimmed < < sb - > s_blocksize_bits ;
return 0 ;
}