Commit 3a3076f4 authored by Josef Bacik's avatar Josef Bacik Committed by Linus Torvalds

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: default avatarJosef Bacik <josef@redhat.com>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 1918ad77
...@@ -228,14 +228,23 @@ static int ioctl_fiemap(struct file *filp, unsigned long arg) ...@@ -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) ...@@ -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;
start_blk = logical_to_blk(inode, start); /*
* Either the i_mutex or other appropriate locking needs to be held
length = (long long)min_t(u64, len, i_size_read(inode)); * since we expect isize to not change at all through the duration of
if (length < len) * this call.
whole_file = 1; */
if (len >= isize) {
whole_file = true;
len = isize;
}
map_len = length; start_blk = logical_to_blk(inode, start);
last_blk = logical_to_blk(inode, start + len - 1);
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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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); ...@@ -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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment