2019-07-15 18:50:58 +03:00
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright ( C ) 2017 Red Hat , Inc .
2021-08-11 04:33:11 +03:00
* Copyright ( c ) 2018 - 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>
# include <linux/pagemap.h>
# include <linux/pagevec.h>
2021-08-11 04:33:11 +03:00
static loff_t iomap_seek_hole_iter ( const struct iomap_iter * iter ,
loff_t * hole_pos )
2019-07-15 18:50:58 +03:00
{
2021-08-11 04:33:11 +03:00
loff_t length = iomap_length ( iter ) ;
2021-02-26 04:15:52 +03:00
2021-08-11 04:33:11 +03:00
switch ( iter - > iomap . type ) {
2019-07-15 18:50:58 +03:00
case IOMAP_UNWRITTEN :
2021-08-11 04:33:11 +03:00
* hole_pos = mapping_seek_hole_data ( iter - > inode - > i_mapping ,
iter - > pos , iter - > pos + length , SEEK_HOLE ) ;
if ( * hole_pos = = iter - > pos + length )
2019-07-15 18:50:58 +03:00
return length ;
2021-08-11 04:33:11 +03:00
return 0 ;
2019-07-15 18:50:58 +03:00
case IOMAP_HOLE :
2021-08-11 04:33:11 +03:00
* hole_pos = iter - > pos ;
2019-07-15 18:50:58 +03:00
return 0 ;
default :
return length ;
}
}
loff_t
2021-08-11 04:33:11 +03:00
iomap_seek_hole ( struct inode * inode , loff_t pos , const struct iomap_ops * ops )
2019-07-15 18:50:58 +03:00
{
loff_t size = i_size_read ( inode ) ;
2021-08-11 04:33:11 +03:00
struct iomap_iter iter = {
. inode = inode ,
. pos = pos ,
. flags = IOMAP_REPORT ,
} ;
int ret ;
2019-07-15 18:50:58 +03:00
/* Nothing to be found before or beyond the end of the file. */
2021-08-11 04:33:11 +03:00
if ( pos < 0 | | pos > = size )
2019-07-15 18:50:58 +03:00
return - ENXIO ;
2021-08-11 04:33:11 +03:00
iter . len = size - pos ;
while ( ( ret = iomap_iter ( & iter , ops ) ) > 0 )
iter . processed = iomap_seek_hole_iter ( & iter , & pos ) ;
if ( ret < 0 )
return ret ;
if ( iter . len ) /* found hole before EOF */
return pos ;
return size ;
2019-07-15 18:50:58 +03:00
}
EXPORT_SYMBOL_GPL ( iomap_seek_hole ) ;
2021-08-11 04:33:12 +03:00
static loff_t iomap_seek_data_iter ( const struct iomap_iter * iter ,
loff_t * hole_pos )
2019-07-15 18:50:58 +03:00
{
2021-08-11 04:33:12 +03:00
loff_t length = iomap_length ( iter ) ;
2021-02-26 04:15:52 +03:00
2021-08-11 04:33:12 +03:00
switch ( iter - > iomap . type ) {
2019-07-15 18:50:58 +03:00
case IOMAP_HOLE :
return length ;
case IOMAP_UNWRITTEN :
2021-08-11 04:33:12 +03:00
* hole_pos = mapping_seek_hole_data ( iter - > inode - > i_mapping ,
iter - > pos , iter - > pos + length , SEEK_DATA ) ;
if ( * hole_pos < 0 )
2019-07-15 18:50:58 +03:00
return length ;
2021-08-11 04:33:12 +03:00
return 0 ;
2019-07-15 18:50:58 +03:00
default :
2021-08-11 04:33:12 +03:00
* hole_pos = iter - > pos ;
2019-07-15 18:50:58 +03:00
return 0 ;
}
}
loff_t
2021-08-11 04:33:12 +03:00
iomap_seek_data ( struct inode * inode , loff_t pos , const struct iomap_ops * ops )
2019-07-15 18:50:58 +03:00
{
loff_t size = i_size_read ( inode ) ;
2021-08-11 04:33:12 +03:00
struct iomap_iter iter = {
. inode = inode ,
. pos = pos ,
. flags = IOMAP_REPORT ,
} ;
int ret ;
2019-07-15 18:50:58 +03:00
/* Nothing to be found before or beyond the end of the file. */
2021-08-11 04:33:12 +03:00
if ( pos < 0 | | pos > = size )
2019-07-15 18:50:58 +03:00
return - ENXIO ;
2021-08-11 04:33:12 +03:00
iter . len = size - pos ;
while ( ( ret = iomap_iter ( & iter , ops ) ) > 0 )
iter . processed = iomap_seek_data_iter ( & iter , & pos ) ;
if ( ret < 0 )
return ret ;
if ( iter . len ) /* found data before EOF */
return pos ;
2021-07-15 19:58:04 +03:00
/* We've reached the end of the file without finding data */
return - ENXIO ;
2019-07-15 18:50:58 +03:00
}
EXPORT_SYMBOL_GPL ( iomap_seek_data ) ;