2019-04-28 18:34:02 +03:00
// SPDX-License-Identifier: GPL-2.0
2016-06-21 02:23:11 +03:00
/*
* Copyright ( C ) 2010 Red Hat , Inc .
2021-08-11 04:33:07 +03:00
* Copyright ( c ) 2016 - 2021 Christoph Hellwig .
2016-06-21 02:23:11 +03:00
*/
# include <linux/fs.h>
# include <linux/iomap.h>
2019-11-22 03:14:49 +03:00
# include "trace.h"
2017-02-04 01:47:37 +03:00
2022-11-29 01:09:17 +03:00
/*
* Advance to the next range we need to map .
*
* If the iomap is marked IOMAP_F_STALE , it means the existing map was not fully
* processed - it was aborted because the extent the iomap spanned may have been
* changed during the operation . In this case , the iteration behaviour is to
* remap the unprocessed range of the iter , and that means we may need to remap
* even when we ' ve made no progress ( i . e . iter - > processed = 0 ) . Hence the
* " finished iterating " case needs to distinguish between
* ( processed = 0 ) meaning we are done and ( processed = 0 & & stale ) meaning we
* need to remap the entire remaining range .
*/
2021-08-11 04:33:07 +03:00
static inline int iomap_iter_advance ( struct iomap_iter * iter )
{
2022-11-29 01:09:17 +03:00
bool stale = iter - > iomap . flags & IOMAP_F_STALE ;
2021-08-11 04:33:07 +03:00
/* handle the previous iteration (if any) */
if ( iter - > iomap . length ) {
2022-11-29 01:09:17 +03:00
if ( iter - > processed < 0 )
2021-08-11 04:33:07 +03:00
return iter - > processed ;
2022-11-29 01:09:17 +03:00
if ( ! iter - > processed & & ! stale )
return 0 ;
2021-08-11 04:33:07 +03:00
if ( WARN_ON_ONCE ( iter - > processed > iomap_length ( iter ) ) )
return - EIO ;
iter - > pos + = iter - > processed ;
iter - > len - = iter - > processed ;
if ( ! iter - > len )
return 0 ;
}
/* clear the state for the next iteration */
iter - > processed = 0 ;
memset ( & iter - > iomap , 0 , sizeof ( iter - > iomap ) ) ;
memset ( & iter - > srcmap , 0 , sizeof ( iter - > srcmap ) ) ;
return 1 ;
}
static inline void iomap_iter_done ( struct iomap_iter * iter )
{
WARN_ON_ONCE ( iter - > iomap . offset > iter - > pos ) ;
WARN_ON_ONCE ( iter - > iomap . length = = 0 ) ;
WARN_ON_ONCE ( iter - > iomap . offset + iter - > iomap . length < = iter - > pos ) ;
2022-11-29 01:09:17 +03:00
WARN_ON_ONCE ( iter - > iomap . flags & IOMAP_F_STALE ) ;
2021-08-11 04:33:07 +03:00
trace_iomap_iter_dstmap ( iter - > inode , & iter - > iomap ) ;
if ( iter - > srcmap . type ! = IOMAP_HOLE )
trace_iomap_iter_srcmap ( iter - > inode , & iter - > srcmap ) ;
}
/**
* iomap_iter - iterate over a ranges in a file
* @ iter : iteration structue
* @ ops : iomap ops provided by the file system
*
* Iterate over filesystem - provided space mappings for the provided file range .
*
* This function handles cleanup of resources acquired for iteration when the
* filesystem indicates there are no more space mappings , which means that this
* function must be called in a loop that continues as long it returns a
* positive value . If 0 or a negative value is returned , the caller must not
* return to the loop body . Within a loop body , there are two ways to break out
* of the loop body : leave @ iter . processed unchanged , or set it to a negative
* errno .
*/
int iomap_iter ( struct iomap_iter * iter , const struct iomap_ops * ops )
{
int ret ;
if ( iter - > iomap . length & & ops - > iomap_end ) {
ret = ops - > iomap_end ( iter - > inode , iter - > pos , iomap_length ( iter ) ,
iter - > processed > 0 ? iter - > processed : 0 ,
iter - > flags , & iter - > iomap ) ;
if ( ret < 0 & & ! iter - > processed )
return ret ;
}
trace_iomap_iter ( iter , ops , _RET_IP_ ) ;
ret = iomap_iter_advance ( iter ) ;
if ( ret < = 0 )
return ret ;
ret = ops - > iomap_begin ( iter - > inode , iter - > pos , iter - > len , iter - > flags ,
& iter - > iomap , & iter - > srcmap ) ;
if ( ret < 0 )
return ret ;
iomap_iter_done ( iter ) ;
return 1 ;
}