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 .
2018-06-20 01:10:57 +03:00
* Copyright ( c ) 2016 - 2018 Christoph Hellwig .
2016-06-21 02:23:11 +03:00
*/
# include <linux/module.h>
# include <linux/compiler.h>
# include <linux/fs.h>
# include <linux/iomap.h>
2017-02-04 01:47:37 +03:00
2016-06-21 02:23:11 +03:00
/*
* Execute a iomap write on a segment of the mapping that spans a
* contiguous range of pages that have identical block mapping state .
*
* This avoids the need to map pages individually , do individual allocations
* for each page and most importantly avoid the need for filesystem specific
* locking per page . Instead , all the operations are amortised over the entire
* range of pages . It is assumed that the filesystems will lock whatever
* resources they require in the iomap_begin call , and release them in the
* iomap_end call .
*/
2016-09-19 04:24:49 +03:00
loff_t
2016-06-21 02:23:11 +03:00
iomap_apply ( struct inode * inode , loff_t pos , loff_t length , unsigned flags ,
2017-01-28 10:20:26 +03:00
const struct iomap_ops * ops , void * data , iomap_actor_t actor )
2016-06-21 02:23:11 +03:00
{
struct iomap iomap = { 0 } ;
loff_t written = 0 , ret ;
/*
* Need to map a range from start position for length bytes . This can
* span multiple pages - it is only guaranteed to return a range of a
* single type of pages ( e . g . all into a hole , all mapped or all
* unwritten ) . Failure at this point has nothing to undo .
*
* If allocation is required for this range , reserve the space now so
* that the allocation is guaranteed to succeed later on . Once we copy
* the data into the page cache pages , then we cannot fail otherwise we
* expose transient stale data . If the reserve fails , we can safely
* back out at this point as there is nothing to undo .
*/
ret = ops - > iomap_begin ( inode , pos , length , flags , & iomap ) ;
if ( ret )
return ret ;
if ( WARN_ON ( iomap . offset > pos ) )
return - EIO ;
2018-01-26 22:11:20 +03:00
if ( WARN_ON ( iomap . length = = 0 ) )
return - EIO ;
2016-06-21 02:23:11 +03:00
/*
* Cut down the length to the one actually provided by the filesystem ,
* as it might not be able to give us the whole size that we requested .
*/
if ( iomap . offset + iomap . length < pos + length )
length = iomap . offset + iomap . length - pos ;
/*
* Now that we have guaranteed that the space allocation will succeed .
* we can do the copy - in page by page without having to worry about
* failures exposing transient data .
*/
written = actor ( inode , pos , length , data , & iomap ) ;
/*
* Now the data has been copied , commit the range we ' ve copied . This
* should not fail unless the filesystem has had a fatal error .
*/
2016-08-17 01:42:34 +03:00
if ( ops - > iomap_end ) {
ret = ops - > iomap_end ( inode , pos , length ,
written > 0 ? written : 0 ,
flags , & iomap ) ;
}
2016-06-21 02:23:11 +03:00
return written ? written : ret ;
}