2019-07-15 08:50:58 -07:00
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright ( C ) 2017 Red Hat , Inc .
* Copyright ( c ) 2018 Christoph Hellwig .
*/
# include <linux/module.h>
# include <linux/compiler.h>
# include <linux/fs.h>
# include <linux/iomap.h>
# include <linux/pagemap.h>
# include <linux/pagevec.h>
static loff_t
2021-02-25 17:15:52 -08:00
iomap_seek_hole_actor ( struct inode * inode , loff_t start , loff_t length ,
2019-10-18 16:44:10 -07:00
void * data , struct iomap * iomap , struct iomap * srcmap )
2019-07-15 08:50:58 -07:00
{
2021-02-25 17:15:52 -08:00
loff_t offset = start ;
2019-07-15 08:50:58 -07:00
switch ( iomap - > type ) {
case IOMAP_UNWRITTEN :
2021-02-25 17:15:52 -08:00
offset = mapping_seek_hole_data ( inode - > i_mapping , start ,
start + length , SEEK_HOLE ) ;
if ( offset = = start + length )
2019-07-15 08:50:58 -07:00
return length ;
2020-08-23 17:36:59 -05:00
fallthrough ;
2019-07-15 08:50:58 -07:00
case IOMAP_HOLE :
* ( loff_t * ) data = offset ;
return 0 ;
default :
return length ;
}
}
loff_t
iomap_seek_hole ( struct inode * inode , loff_t offset , const struct iomap_ops * ops )
{
loff_t size = i_size_read ( inode ) ;
loff_t length = size - offset ;
loff_t ret ;
/* Nothing to be found before or beyond the end of the file. */
if ( offset < 0 | | offset > = size )
return - ENXIO ;
while ( length > 0 ) {
ret = iomap_apply ( inode , offset , length , IOMAP_REPORT , ops ,
& offset , iomap_seek_hole_actor ) ;
if ( ret < 0 )
return ret ;
if ( ret = = 0 )
break ;
offset + = ret ;
length - = ret ;
}
return offset ;
}
EXPORT_SYMBOL_GPL ( iomap_seek_hole ) ;
static loff_t
2021-02-25 17:15:52 -08:00
iomap_seek_data_actor ( struct inode * inode , loff_t start , loff_t length ,
2019-10-18 16:44:10 -07:00
void * data , struct iomap * iomap , struct iomap * srcmap )
2019-07-15 08:50:58 -07:00
{
2021-02-25 17:15:52 -08:00
loff_t offset = start ;
2019-07-15 08:50:58 -07:00
switch ( iomap - > type ) {
case IOMAP_HOLE :
return length ;
case IOMAP_UNWRITTEN :
2021-02-25 17:15:52 -08:00
offset = mapping_seek_hole_data ( inode - > i_mapping , start ,
start + length , SEEK_DATA ) ;
2019-07-15 08:50:58 -07:00
if ( offset < 0 )
return length ;
2020-08-23 17:36:59 -05:00
fallthrough ;
2019-07-15 08:50:58 -07:00
default :
* ( loff_t * ) data = offset ;
return 0 ;
}
}
loff_t
iomap_seek_data ( struct inode * inode , loff_t offset , const struct iomap_ops * ops )
{
loff_t size = i_size_read ( inode ) ;
loff_t length = size - offset ;
loff_t ret ;
/* Nothing to be found before or beyond the end of the file. */
if ( offset < 0 | | offset > = size )
return - ENXIO ;
while ( length > 0 ) {
ret = iomap_apply ( inode , offset , length , IOMAP_REPORT , ops ,
& offset , iomap_seek_data_actor ) ;
if ( ret < 0 )
return ret ;
if ( ret = = 0 )
break ;
offset + = ret ;
length - = ret ;
}
if ( length < = 0 )
return - ENXIO ;
return offset ;
}
EXPORT_SYMBOL_GPL ( iomap_seek_data ) ;