mirror of
				https://github.com/torvalds/linux.git
				synced 2025-10-31 08:38:45 +02:00 
			
		
		
		
	fs: add iomap_file_dirty
Originally-From: Christoph Hellwig <hch@lst.de> This function uses the iomap infrastructure to re-write all pages in a given range. This is useful for doing a copy-up of COW ranges, and might be useful for scrubbing in the future. Signed-off-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Dave Chinner <dchinner@redhat.com> Signed-off-by: Dave Chinner <david@fromorbit.com>
This commit is contained in:
		
							parent
							
								
									ea78d80866
								
							
						
					
					
						commit
						5f4e5752a8
					
				
					 2 changed files with 84 additions and 0 deletions
				
			
		
							
								
								
									
										82
									
								
								fs/iomap.c
									
									
									
									
									
								
							
							
						
						
									
										82
									
								
								fs/iomap.c
									
									
									
									
									
								
							|  | @ -252,6 +252,88 @@ iomap_file_buffered_write(struct kiocb *iocb, struct iov_iter *iter, | ||||||
| } | } | ||||||
| EXPORT_SYMBOL_GPL(iomap_file_buffered_write); | EXPORT_SYMBOL_GPL(iomap_file_buffered_write); | ||||||
| 
 | 
 | ||||||
|  | static struct page * | ||||||
|  | __iomap_read_page(struct inode *inode, loff_t offset) | ||||||
|  | { | ||||||
|  | 	struct address_space *mapping = inode->i_mapping; | ||||||
|  | 	struct page *page; | ||||||
|  | 
 | ||||||
|  | 	page = read_mapping_page(mapping, offset >> PAGE_SHIFT, NULL); | ||||||
|  | 	if (IS_ERR(page)) | ||||||
|  | 		return page; | ||||||
|  | 	if (!PageUptodate(page)) { | ||||||
|  | 		put_page(page); | ||||||
|  | 		return ERR_PTR(-EIO); | ||||||
|  | 	} | ||||||
|  | 	return page; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static loff_t | ||||||
|  | iomap_dirty_actor(struct inode *inode, loff_t pos, loff_t length, void *data, | ||||||
|  | 		struct iomap *iomap) | ||||||
|  | { | ||||||
|  | 	long status = 0; | ||||||
|  | 	ssize_t written = 0; | ||||||
|  | 
 | ||||||
|  | 	do { | ||||||
|  | 		struct page *page, *rpage; | ||||||
|  | 		unsigned long offset;	/* Offset into pagecache page */ | ||||||
|  | 		unsigned long bytes;	/* Bytes to write to page */ | ||||||
|  | 
 | ||||||
|  | 		offset = (pos & (PAGE_SIZE - 1)); | ||||||
|  | 		bytes = min_t(unsigned long, PAGE_SIZE - offset, length); | ||||||
|  | 
 | ||||||
|  | 		rpage = __iomap_read_page(inode, pos); | ||||||
|  | 		if (IS_ERR(rpage)) | ||||||
|  | 			return PTR_ERR(rpage); | ||||||
|  | 
 | ||||||
|  | 		status = iomap_write_begin(inode, pos, bytes, | ||||||
|  | 				AOP_FLAG_NOFS | AOP_FLAG_UNINTERRUPTIBLE, | ||||||
|  | 				&page, iomap); | ||||||
|  | 		put_page(rpage); | ||||||
|  | 		if (unlikely(status)) | ||||||
|  | 			return status; | ||||||
|  | 
 | ||||||
|  | 		WARN_ON_ONCE(!PageUptodate(page)); | ||||||
|  | 
 | ||||||
|  | 		status = iomap_write_end(inode, pos, bytes, bytes, page); | ||||||
|  | 		if (unlikely(status <= 0)) { | ||||||
|  | 			if (WARN_ON_ONCE(status == 0)) | ||||||
|  | 				return -EIO; | ||||||
|  | 			return status; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		cond_resched(); | ||||||
|  | 
 | ||||||
|  | 		pos += status; | ||||||
|  | 		written += status; | ||||||
|  | 		length -= status; | ||||||
|  | 
 | ||||||
|  | 		balance_dirty_pages_ratelimited(inode->i_mapping); | ||||||
|  | 	} while (length); | ||||||
|  | 
 | ||||||
|  | 	return written; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int | ||||||
|  | iomap_file_dirty(struct inode *inode, loff_t pos, loff_t len, | ||||||
|  | 		struct iomap_ops *ops) | ||||||
|  | { | ||||||
|  | 	loff_t ret; | ||||||
|  | 
 | ||||||
|  | 	while (len) { | ||||||
|  | 		ret = iomap_apply(inode, pos, len, IOMAP_WRITE, ops, NULL, | ||||||
|  | 				iomap_dirty_actor); | ||||||
|  | 		if (ret <= 0) | ||||||
|  | 			return ret; | ||||||
|  | 		pos += ret; | ||||||
|  | 		len -= ret; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL_GPL(iomap_file_dirty); | ||||||
|  | 
 | ||||||
| static int iomap_zero(struct inode *inode, loff_t pos, unsigned offset, | static int iomap_zero(struct inode *inode, loff_t pos, unsigned offset, | ||||||
| 		unsigned bytes, struct iomap *iomap) | 		unsigned bytes, struct iomap *iomap) | ||||||
| { | { | ||||||
|  |  | ||||||
|  | @ -64,6 +64,8 @@ struct iomap_ops { | ||||||
| 
 | 
 | ||||||
| ssize_t iomap_file_buffered_write(struct kiocb *iocb, struct iov_iter *from, | ssize_t iomap_file_buffered_write(struct kiocb *iocb, struct iov_iter *from, | ||||||
| 		struct iomap_ops *ops); | 		struct iomap_ops *ops); | ||||||
|  | int iomap_file_dirty(struct inode *inode, loff_t pos, loff_t len, | ||||||
|  | 		struct iomap_ops *ops); | ||||||
| int iomap_zero_range(struct inode *inode, loff_t pos, loff_t len, | int iomap_zero_range(struct inode *inode, loff_t pos, loff_t len, | ||||||
| 		bool *did_zero, struct iomap_ops *ops); | 		bool *did_zero, struct iomap_ops *ops); | ||||||
| int iomap_truncate_page(struct inode *inode, loff_t pos, bool *did_zero, | int iomap_truncate_page(struct inode *inode, loff_t pos, bool *did_zero, | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Christoph Hellwig
						Christoph Hellwig