2019-07-15 18:50:58 +03:00
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright ( c ) 2016 - 2018 Christoph Hellwig .
*/
# include <linux/module.h>
# include <linux/compiler.h>
# include <linux/fs.h>
# include <linux/iomap.h>
2020-05-23 10:30:11 +03:00
# include <linux/fiemap.h>
2019-07-15 18:50:58 +03:00
struct fiemap_ctx {
struct fiemap_extent_info * fi ;
struct iomap prev ;
} ;
static int iomap_to_fiemap ( struct fiemap_extent_info * fi ,
struct iomap * iomap , u32 flags )
{
switch ( iomap - > type ) {
case IOMAP_HOLE :
/* skip holes */
return 0 ;
case IOMAP_DELALLOC :
flags | = FIEMAP_EXTENT_DELALLOC | FIEMAP_EXTENT_UNKNOWN ;
break ;
case IOMAP_MAPPED :
break ;
case IOMAP_UNWRITTEN :
flags | = FIEMAP_EXTENT_UNWRITTEN ;
break ;
case IOMAP_INLINE :
flags | = FIEMAP_EXTENT_DATA_INLINE ;
break ;
}
if ( iomap - > flags & IOMAP_F_MERGED )
flags | = FIEMAP_EXTENT_MERGED ;
if ( iomap - > flags & IOMAP_F_SHARED )
flags | = FIEMAP_EXTENT_SHARED ;
return fiemap_fill_next_extent ( fi , iomap - > offset ,
iomap - > addr ! = IOMAP_NULL_ADDR ? iomap - > addr : 0 ,
iomap - > length , flags ) ;
}
static loff_t
iomap_fiemap_actor ( struct inode * inode , loff_t pos , loff_t length , void * data ,
2019-10-19 02:44:10 +03:00
struct iomap * iomap , struct iomap * srcmap )
2019-07-15 18:50:58 +03:00
{
struct fiemap_ctx * ctx = data ;
loff_t ret = length ;
if ( iomap - > type = = IOMAP_HOLE )
return length ;
ret = iomap_to_fiemap ( ctx - > fi , & ctx - > prev , 0 ) ;
ctx - > prev = * iomap ;
switch ( ret ) {
case 0 : /* success */
return length ;
case 1 : /* extent array full */
return 0 ;
default :
return ret ;
}
}
int iomap_fiemap ( struct inode * inode , struct fiemap_extent_info * fi ,
2020-05-23 10:30:12 +03:00
u64 start , u64 len , const struct iomap_ops * ops )
2019-07-15 18:50:58 +03:00
{
struct fiemap_ctx ctx ;
loff_t ret ;
memset ( & ctx , 0 , sizeof ( ctx ) ) ;
ctx . fi = fi ;
ctx . prev . type = IOMAP_HOLE ;
2020-05-23 10:30:14 +03:00
ret = fiemap_prep ( inode , fi , start , & len , 0 ) ;
2019-07-15 18:50:58 +03:00
if ( ret )
return ret ;
while ( len > 0 ) {
ret = iomap_apply ( inode , start , len , IOMAP_REPORT , ops , & ctx ,
iomap_fiemap_actor ) ;
/* inode with no (attribute) mapping will give ENOENT */
if ( ret = = - ENOENT )
break ;
if ( ret < 0 )
return ret ;
if ( ret = = 0 )
break ;
start + = ret ;
len - = ret ;
}
if ( ctx . prev . type ! = IOMAP_HOLE ) {
ret = iomap_to_fiemap ( fi , & ctx . prev , FIEMAP_EXTENT_LAST ) ;
if ( ret < 0 )
return ret ;
}
return 0 ;
}
EXPORT_SYMBOL_GPL ( iomap_fiemap ) ;
static loff_t
iomap_bmap_actor ( struct inode * inode , loff_t pos , loff_t length ,
2019-10-19 02:44:10 +03:00
void * data , struct iomap * iomap , struct iomap * srcmap )
2019-07-15 18:50:58 +03:00
{
sector_t * bno = data , addr ;
if ( iomap - > type = = IOMAP_MAPPED ) {
addr = ( pos - iomap - > offset + iomap - > addr ) > > inode - > i_blkbits ;
2020-04-30 17:57:46 +03:00
* bno = addr ;
2019-07-15 18:50:58 +03:00
}
return 0 ;
}
/* legacy ->bmap interface. 0 is the error return (!) */
sector_t
iomap_bmap ( struct address_space * mapping , sector_t bno ,
const struct iomap_ops * ops )
{
struct inode * inode = mapping - > host ;
loff_t pos = bno < < inode - > i_blkbits ;
unsigned blocksize = i_blocksize ( inode ) ;
2019-11-07 18:28:18 +03:00
int ret ;
2019-07-15 18:50:58 +03:00
if ( filemap_write_and_wait ( mapping ) )
return 0 ;
bno = 0 ;
2019-11-07 18:28:18 +03:00
ret = iomap_apply ( inode , pos , blocksize , 0 , ops , & bno ,
iomap_bmap_actor ) ;
if ( ret )
return 0 ;
2019-07-15 18:50:58 +03:00
return bno ;
}
EXPORT_SYMBOL_GPL ( iomap_bmap ) ;