Cleanup generic block based fiemap
This cleans up a few of the complaints of __generic_block_fiemap. I've fixed all the typing stuff, used inline functions instead of macros, gotten rid of a couple of variables, and made sure the size and block requests are all block aligned. It also fixes a problem where sometimes FIEMAP_EXTENT_LAST wasn't being set properly. Signed-off-by: Josef Bacik <josef@redhat.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
		
					parent
					
						
							
								1918ad77f7
							
						
					
				
			
			
				commit
				
					
						3a3076f4d6
					
				
			
		
					 2 changed files with 56 additions and 41 deletions
				
			
		
							
								
								
									
										92
									
								
								fs/ioctl.c
									
										
									
									
									
								
							
							
						
						
									
										92
									
								
								fs/ioctl.c
									
										
									
									
									
								
							|  | @ -228,14 +228,23 @@ static int ioctl_fiemap(struct file *filp, unsigned long arg) | ||||||
| 
 | 
 | ||||||
| #ifdef CONFIG_BLOCK | #ifdef CONFIG_BLOCK | ||||||
| 
 | 
 | ||||||
| #define blk_to_logical(inode, blk) (blk << (inode)->i_blkbits) | static inline sector_t logical_to_blk(struct inode *inode, loff_t offset) | ||||||
| #define logical_to_blk(inode, offset) (offset >> (inode)->i_blkbits); | { | ||||||
|  | 	return (offset >> inode->i_blkbits); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline loff_t blk_to_logical(struct inode *inode, sector_t blk) | ||||||
|  | { | ||||||
|  | 	return (blk << inode->i_blkbits); | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * __generic_block_fiemap - FIEMAP for block based inodes (no locking) |  * __generic_block_fiemap - FIEMAP for block based inodes (no locking) | ||||||
|  * @inode - the inode to map |  * @inode: the inode to map | ||||||
|  * @arg - the pointer to userspace where we copy everything to |  * @fieinfo: the fiemap info struct that will be passed back to userspace | ||||||
|  * @get_block - the fs's get_block function |  * @start: where to start mapping in the inode | ||||||
|  |  * @len: how much space to map | ||||||
|  |  * @get_block: the fs's get_block function | ||||||
|  * |  * | ||||||
|  * This does FIEMAP for block based inodes.  Basically it will just loop |  * This does FIEMAP for block based inodes.  Basically it will just loop | ||||||
|  * through get_block until we hit the number of extents we want to map, or we |  * through get_block until we hit the number of extents we want to map, or we | ||||||
|  | @ -250,58 +259,63 @@ static int ioctl_fiemap(struct file *filp, unsigned long arg) | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| int __generic_block_fiemap(struct inode *inode, | int __generic_block_fiemap(struct inode *inode, | ||||||
| 			   struct fiemap_extent_info *fieinfo, u64 start, | 			   struct fiemap_extent_info *fieinfo, loff_t start, | ||||||
| 			   u64 len, get_block_t *get_block) | 			   loff_t len, get_block_t *get_block) | ||||||
| { | { | ||||||
| 	struct buffer_head tmp; | 	struct buffer_head map_bh; | ||||||
| 	unsigned long long start_blk; | 	sector_t start_blk, last_blk; | ||||||
| 	long long length = 0, map_len = 0; | 	loff_t isize = i_size_read(inode); | ||||||
| 	u64 logical = 0, phys = 0, size = 0; | 	u64 logical = 0, phys = 0, size = 0; | ||||||
| 	u32 flags = FIEMAP_EXTENT_MERGED; | 	u32 flags = FIEMAP_EXTENT_MERGED; | ||||||
| 	int ret = 0, past_eof = 0, whole_file = 0; | 	bool past_eof = false, whole_file = false; | ||||||
|  | 	int ret = 0; | ||||||
| 
 | 
 | ||||||
| 	if ((ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC))) | 	ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC); | ||||||
|  | 	if (ret) | ||||||
| 		return ret; | 		return ret; | ||||||
| 
 | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * Either the i_mutex or other appropriate locking needs to be held | ||||||
|  | 	 * since we expect isize to not change at all through the duration of | ||||||
|  | 	 * this call. | ||||||
|  | 	 */ | ||||||
|  | 	if (len >= isize) { | ||||||
|  | 		whole_file = true; | ||||||
|  | 		len = isize; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	start_blk = logical_to_blk(inode, start); | 	start_blk = logical_to_blk(inode, start); | ||||||
| 
 | 	last_blk = logical_to_blk(inode, start + len - 1); | ||||||
| 	length = (long long)min_t(u64, len, i_size_read(inode)); |  | ||||||
| 	if (length < len) |  | ||||||
| 		whole_file = 1; |  | ||||||
| 
 |  | ||||||
| 	map_len = length; |  | ||||||
| 
 | 
 | ||||||
| 	do { | 	do { | ||||||
| 		/*
 | 		/*
 | ||||||
| 		 * we set b_size to the total size we want so it will map as | 		 * we set b_size to the total size we want so it will map as | ||||||
| 		 * many contiguous blocks as possible at once | 		 * many contiguous blocks as possible at once | ||||||
| 		 */ | 		 */ | ||||||
| 		memset(&tmp, 0, sizeof(struct buffer_head)); | 		memset(&map_bh, 0, sizeof(struct buffer_head)); | ||||||
| 		tmp.b_size = map_len; | 		map_bh.b_size = len; | ||||||
| 
 | 
 | ||||||
| 		ret = get_block(inode, start_blk, &tmp, 0); | 		ret = get_block(inode, start_blk, &map_bh, 0); | ||||||
| 		if (ret) | 		if (ret) | ||||||
| 			break; | 			break; | ||||||
| 
 | 
 | ||||||
| 		/* HOLE */ | 		/* HOLE */ | ||||||
| 		if (!buffer_mapped(&tmp)) { | 		if (!buffer_mapped(&map_bh)) { | ||||||
| 			length -= blk_to_logical(inode, 1); |  | ||||||
| 			start_blk++; | 			start_blk++; | ||||||
| 
 | 
 | ||||||
| 			/*
 | 			/*
 | ||||||
| 			 * we want to handle the case where there is an | 			 * We want to handle the case where there is an | ||||||
| 			 * allocated block at the front of the file, and then | 			 * allocated block at the front of the file, and then | ||||||
| 			 * nothing but holes up to the end of the file properly, | 			 * nothing but holes up to the end of the file properly, | ||||||
| 			 * to make sure that extent at the front gets properly | 			 * to make sure that extent at the front gets properly | ||||||
| 			 * marked with FIEMAP_EXTENT_LAST | 			 * marked with FIEMAP_EXTENT_LAST | ||||||
| 			 */ | 			 */ | ||||||
| 			if (!past_eof && | 			if (!past_eof && | ||||||
| 			    blk_to_logical(inode, start_blk) >= | 			    blk_to_logical(inode, start_blk) >= isize) | ||||||
| 			    blk_to_logical(inode, 0)+i_size_read(inode)) |  | ||||||
| 				past_eof = 1; | 				past_eof = 1; | ||||||
| 
 | 
 | ||||||
| 			/*
 | 			/*
 | ||||||
| 			 * first hole after going past the EOF, this is our | 			 * First hole after going past the EOF, this is our | ||||||
| 			 * last extent | 			 * last extent | ||||||
| 			 */ | 			 */ | ||||||
| 			if (past_eof && size) { | 			if (past_eof && size) { | ||||||
|  | @ -309,15 +323,18 @@ int __generic_block_fiemap(struct inode *inode, | ||||||
| 				ret = fiemap_fill_next_extent(fieinfo, logical, | 				ret = fiemap_fill_next_extent(fieinfo, logical, | ||||||
| 							      phys, size, | 							      phys, size, | ||||||
| 							      flags); | 							      flags); | ||||||
| 				break; | 			} else if (size) { | ||||||
|  | 				ret = fiemap_fill_next_extent(fieinfo, logical, | ||||||
|  | 							      phys, size, flags); | ||||||
|  | 				size = 0; | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			/* if we have holes up to/past EOF then we're done */ | 			/* if we have holes up to/past EOF then we're done */ | ||||||
| 			if (length <= 0 || past_eof) | 			if (start_blk > last_blk || past_eof || ret) | ||||||
| 				break; | 				break; | ||||||
| 		} else { | 		} else { | ||||||
| 			/*
 | 			/*
 | ||||||
| 			 * we have gone over the length of what we wanted to | 			 * We have gone over the length of what we wanted to | ||||||
| 			 * map, and it wasn't the entire file, so add the extent | 			 * map, and it wasn't the entire file, so add the extent | ||||||
| 			 * we got last time and exit. | 			 * we got last time and exit. | ||||||
| 			 * | 			 * | ||||||
|  | @ -331,7 +348,7 @@ int __generic_block_fiemap(struct inode *inode, | ||||||
| 			 * are good to go, just add the extent to the fieinfo | 			 * are good to go, just add the extent to the fieinfo | ||||||
| 			 * and break | 			 * and break | ||||||
| 			 */ | 			 */ | ||||||
| 			if (length <= 0 && !whole_file) { | 			if (start_blk > last_blk && !whole_file) { | ||||||
| 				ret = fiemap_fill_next_extent(fieinfo, logical, | 				ret = fiemap_fill_next_extent(fieinfo, logical, | ||||||
| 							      phys, size, | 							      phys, size, | ||||||
| 							      flags); | 							      flags); | ||||||
|  | @ -351,11 +368,10 @@ int __generic_block_fiemap(struct inode *inode, | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			logical = blk_to_logical(inode, start_blk); | 			logical = blk_to_logical(inode, start_blk); | ||||||
| 			phys = blk_to_logical(inode, tmp.b_blocknr); | 			phys = blk_to_logical(inode, map_bh.b_blocknr); | ||||||
| 			size = tmp.b_size; | 			size = map_bh.b_size; | ||||||
| 			flags = FIEMAP_EXTENT_MERGED; | 			flags = FIEMAP_EXTENT_MERGED; | ||||||
| 
 | 
 | ||||||
| 			length -= tmp.b_size; |  | ||||||
| 			start_blk += logical_to_blk(inode, size); | 			start_blk += logical_to_blk(inode, size); | ||||||
| 
 | 
 | ||||||
| 			/*
 | 			/*
 | ||||||
|  | @ -363,15 +379,13 @@ int __generic_block_fiemap(struct inode *inode, | ||||||
| 			 * soon as we find a hole that the last extent we found | 			 * soon as we find a hole that the last extent we found | ||||||
| 			 * is marked with FIEMAP_EXTENT_LAST | 			 * is marked with FIEMAP_EXTENT_LAST | ||||||
| 			 */ | 			 */ | ||||||
| 			if (!past_eof && | 			if (!past_eof && logical + size >= isize) | ||||||
| 			    logical+size >= | 				past_eof = true; | ||||||
| 			    blk_to_logical(inode, 0)+i_size_read(inode)) |  | ||||||
| 				past_eof = 1; |  | ||||||
| 		} | 		} | ||||||
| 		cond_resched(); | 		cond_resched(); | ||||||
| 	} while (1); | 	} while (1); | ||||||
| 
 | 
 | ||||||
| 	/* if ret is 1 then we just hit the end of the extent array */ | 	/* If ret is 1 then we just hit the end of the extent array */ | ||||||
| 	if (ret == 1) | 	if (ret == 1) | ||||||
| 		ret = 0; | 		ret = 0; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -2315,8 +2315,9 @@ extern int vfs_fstatat(int , char __user *, struct kstat *, int); | ||||||
| extern int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd, | extern int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd, | ||||||
| 		    unsigned long arg); | 		    unsigned long arg); | ||||||
| extern int __generic_block_fiemap(struct inode *inode, | extern int __generic_block_fiemap(struct inode *inode, | ||||||
| 				  struct fiemap_extent_info *fieinfo, u64 start, | 				  struct fiemap_extent_info *fieinfo, | ||||||
| 				  u64 len, get_block_t *get_block); | 				  loff_t start, loff_t len, | ||||||
|  | 				  get_block_t *get_block); | ||||||
| extern int generic_block_fiemap(struct inode *inode, | extern int generic_block_fiemap(struct inode *inode, | ||||||
| 				struct fiemap_extent_info *fieinfo, u64 start, | 				struct fiemap_extent_info *fieinfo, u64 start, | ||||||
| 				u64 len, get_block_t *get_block); | 				u64 len, get_block_t *get_block); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Josef Bacik
				Josef Bacik