2019-07-15 18:50:58 +03:00
// SPDX-License-Identifier: GPL-2.0
/*
2021-08-11 04:33:10 +03:00
* Copyright ( c ) 2016 - 2021 Christoph Hellwig .
2019-07-15 18:50:58 +03:00
*/
# 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
static int iomap_to_fiemap ( struct fiemap_extent_info * fi ,
2021-08-11 04:33:10 +03:00
const struct iomap * iomap , u32 flags )
2019-07-15 18:50:58 +03:00
{
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 ) ;
}
2021-08-11 04:33:10 +03:00
static loff_t iomap_fiemap_iter ( const struct iomap_iter * iter ,
struct fiemap_extent_info * fi , struct iomap * prev )
2019-07-15 18:50:58 +03:00
{
2021-08-11 04:33:10 +03:00
int ret ;
2019-07-15 18:50:58 +03:00
2021-08-11 04:33:10 +03:00
if ( iter - > iomap . type = = IOMAP_HOLE )
return iomap_length ( iter ) ;
2019-07-15 18:50:58 +03:00
2021-08-11 04:33:10 +03:00
ret = iomap_to_fiemap ( fi , prev , 0 ) ;
* prev = iter - > iomap ;
2019-07-15 18:50:58 +03:00
switch ( ret ) {
case 0 : /* success */
2021-08-11 04:33:10 +03:00
return iomap_length ( iter ) ;
2019-07-15 18:50:58 +03:00
case 1 : /* extent array full */
return 0 ;
2021-08-11 04:33:10 +03:00
default : /* error */
2019-07-15 18:50:58 +03:00
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
{
2021-08-11 04:33:10 +03:00
struct iomap_iter iter = {
. inode = inode ,
. pos = start ,
. len = len ,
. flags = IOMAP_REPORT ,
} ;
struct iomap prev = {
. type = IOMAP_HOLE ,
} ;
int ret ;
2019-07-15 18:50:58 +03:00
2021-08-11 04:33:10 +03:00
ret = fiemap_prep ( inode , fi , start , & iter . len , 0 ) ;
2019-07-15 18:50:58 +03:00
if ( ret )
return ret ;
2021-08-11 04:33:10 +03:00
while ( ( ret = iomap_iter ( & iter , ops ) ) > 0 )
iter . processed = iomap_fiemap_iter ( & iter , fi , & prev ) ;
2019-07-15 18:50:58 +03:00
2021-08-11 04:33:10 +03:00
if ( prev . type ! = IOMAP_HOLE ) {
ret = iomap_to_fiemap ( fi , & prev , FIEMAP_EXTENT_LAST ) ;
2019-07-15 18:50:58 +03:00
if ( ret < 0 )
return ret ;
}
2021-08-11 04:33:10 +03:00
/* inode with no (attribute) mapping will give ENOENT */
if ( ret < 0 & & ret ! = - ENOENT )
return ret ;
2019-07-15 18:50:58 +03:00
return 0 ;
}
EXPORT_SYMBOL_GPL ( iomap_fiemap ) ;
/* legacy ->bmap interface. 0 is the error return (!) */
sector_t
iomap_bmap ( struct address_space * mapping , sector_t bno ,
const struct iomap_ops * ops )
{
2021-08-11 04:33:11 +03:00
struct iomap_iter iter = {
. inode = mapping - > host ,
. pos = ( loff_t ) bno < < mapping - > host - > i_blkbits ,
. len = i_blocksize ( mapping - > host ) ,
. flags = IOMAP_REPORT ,
} ;
const unsigned int blkshift = mapping - > host - > i_blkbits - SECTOR_SHIFT ;
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 ;
2021-08-11 04:33:11 +03:00
while ( ( ret = iomap_iter ( & iter , ops ) ) > 0 ) {
if ( iter . iomap . type = = IOMAP_MAPPED )
bno = iomap_sector ( & iter . iomap , iter . pos ) > > blkshift ;
/* leave iter.processed unset to abort loop */
}
2019-11-07 18:28:18 +03:00
if ( ret )
return 0 ;
2021-08-11 04:33:11 +03:00
2019-07-15 18:50:58 +03:00
return bno ;
}
EXPORT_SYMBOL_GPL ( iomap_bmap ) ;