Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 242377
b: refs/heads/master
c: 6d9c85e
h: refs/heads/master
i:
  242375: a0fc491
v: v3
  • Loading branch information
Yongqiang Yang authored and Theodore Ts'o committed Feb 27, 2011
1 parent 5ebf322 commit d0a00c0
Show file tree
Hide file tree
Showing 2 changed files with 149 additions and 40 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 4dd89fc6251a6bda2c18e71e7d266e983806579d
refs/heads/master: 6d9c85eb700bd3ac59e63bb9de463dea1aca084c
187 changes: 148 additions & 39 deletions trunk/fs/ext4/extents.c
Original file line number Diff line number Diff line change
Expand Up @@ -3775,45 +3775,170 @@ int ext4_convert_unwritten_extents(struct inode *inode, loff_t offset,
}
return ret > 0 ? ret2 : ret;
}

/*
* Callback function called for each extent to gather FIEMAP information.
*/
static int ext4_ext_fiemap_cb(struct inode *inode, struct ext4_ext_path *path,
struct ext4_ext_cache *newex, struct ext4_extent *ex,
void *data)
{
struct fiemap_extent_info *fieinfo = data;
unsigned char blksize_bits = inode->i_sb->s_blocksize_bits;
__u64 logical;
__u64 physical;
__u64 length;
loff_t size;
__u32 flags = 0;
int error;
int ret = 0;
struct fiemap_extent_info *fieinfo = data;
unsigned char blksize_bits;

logical = (__u64)newex->ec_block << blksize_bits;
blksize_bits = inode->i_sb->s_blocksize_bits;
logical = (__u64)newex->ec_block << blksize_bits;

if (newex->ec_start == 0) {
pgoff_t offset;
struct page *page;
/*
* No extent in extent-tree contains block @newex->ec_start,
* then the block may stay in 1)a hole or 2)delayed-extent.
*
* Holes or delayed-extents are processed as follows.
* 1. lookup dirty pages with specified range in pagecache.
* If no page is got, then there is no delayed-extent and
* return with EXT_CONTINUE.
* 2. find the 1st mapped buffer,
* 3. check if the mapped buffer is both in the request range
* and a delayed buffer. If not, there is no delayed-extent,
* then return.
* 4. a delayed-extent is found, the extent will be collected.
*/
ext4_lblk_t end = 0;
pgoff_t last_offset;
pgoff_t offset;
pgoff_t index;
struct page **pages = NULL;
struct buffer_head *bh = NULL;
struct buffer_head *head = NULL;
unsigned int nr_pages = PAGE_SIZE / sizeof(struct page *);

pages = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (pages == NULL)
return -ENOMEM;

offset = logical >> PAGE_SHIFT;
page = find_get_page(inode->i_mapping, offset);
if (!page || !page_has_buffers(page))
return EXT_CONTINUE;
repeat:
last_offset = offset;
head = NULL;
ret = find_get_pages_tag(inode->i_mapping, &offset,
PAGECACHE_TAG_DIRTY, nr_pages, pages);

if (!(flags & FIEMAP_EXTENT_DELALLOC)) {
/* First time, try to find a mapped buffer. */
if (ret == 0) {
out:
for (index = 0; index < ret; index++)
page_cache_release(pages[index]);
/* just a hole. */
kfree(pages);
return EXT_CONTINUE;
}

bh = page_buffers(page);
/* Try to find the 1st mapped buffer. */
end = ((__u64)pages[0]->index << PAGE_SHIFT) >>
blksize_bits;
if (!page_has_buffers(pages[0]))
goto out;
head = page_buffers(pages[0]);
if (!head)
goto out;

if (!bh)
return EXT_CONTINUE;
bh = head;
do {
if (buffer_mapped(bh)) {
/* get the 1st mapped buffer. */
if (end > newex->ec_block +
newex->ec_len)
/* The buffer is out of
* the request range.
*/
goto out;
goto found_mapped_buffer;
}
bh = bh->b_this_page;
end++;
} while (bh != head);

if (buffer_delay(bh)) {
flags |= FIEMAP_EXTENT_DELALLOC;
page_cache_release(page);
/* No mapped buffer found. */
goto out;
} else {
page_cache_release(page);
return EXT_CONTINUE;
/*Find contiguous delayed buffers. */
if (ret > 0 && pages[0]->index == last_offset)
head = page_buffers(pages[0]);
bh = head;
}

found_mapped_buffer:
if (bh != NULL && buffer_delay(bh)) {
/* 1st or contiguous delayed buffer found. */
if (!(flags & FIEMAP_EXTENT_DELALLOC)) {
/*
* 1st delayed buffer found, record
* the start of extent.
*/
flags |= FIEMAP_EXTENT_DELALLOC;
newex->ec_block = end;
logical = (__u64)end << blksize_bits;
}
/* Find contiguous delayed buffers. */
do {
if (!buffer_delay(bh))
goto found_delayed_extent;
bh = bh->b_this_page;
end++;
} while (bh != head);

for (index = 1; index < ret; index++) {
if (!page_has_buffers(pages[index])) {
bh = NULL;
break;
}
head = page_buffers(pages[index]);
if (!head) {
bh = NULL;
break;
}
if (pages[index]->index !=
pages[0]->index + index) {
/* Blocks are not contiguous. */
bh = NULL;
break;
}
bh = head;
do {
if (!buffer_delay(bh))
/* Delayed-extent ends. */
goto found_delayed_extent;
bh = bh->b_this_page;
end++;
} while (bh != head);
}
} else if (!(flags & FIEMAP_EXTENT_DELALLOC))
/* a hole found. */
goto out;

found_delayed_extent:
newex->ec_len = min(end - newex->ec_block,
(ext4_lblk_t)EXT_INIT_MAX_LEN);
if (ret == nr_pages && bh != NULL &&
newex->ec_len < EXT_INIT_MAX_LEN &&
buffer_delay(bh)) {
/* Have not collected an extent and continue. */
for (index = 0; index < ret; index++)
page_cache_release(pages[index]);
goto repeat;
}

for (index = 0; index < ret; index++)
page_cache_release(pages[index]);
kfree(pages);
}

physical = (__u64)newex->ec_start << blksize_bits;
Expand All @@ -3822,32 +3947,16 @@ static int ext4_ext_fiemap_cb(struct inode *inode, struct ext4_ext_path *path,
if (ex && ext4_ext_is_uninitialized(ex))
flags |= FIEMAP_EXTENT_UNWRITTEN;

/*
* If this extent reaches EXT_MAX_BLOCK, it must be last.
*
* Or if ext4_ext_next_allocated_block is EXT_MAX_BLOCK,
* this also indicates no more allocated blocks.
*
* XXX this might miss a single-block extent at EXT_MAX_BLOCK
*/
if (ext4_ext_next_allocated_block(path) == EXT_MAX_BLOCK ||
newex->ec_block + newex->ec_len - 1 == EXT_MAX_BLOCK) {
loff_t size = i_size_read(inode);
loff_t bs = EXT4_BLOCK_SIZE(inode->i_sb);

size = i_size_read(inode);
if (logical + length >= size)
flags |= FIEMAP_EXTENT_LAST;
if ((flags & FIEMAP_EXTENT_DELALLOC) &&
logical+length > size)
length = (size - logical + bs - 1) & ~(bs-1);
}

error = fiemap_fill_next_extent(fieinfo, logical, physical,
ret = fiemap_fill_next_extent(fieinfo, logical, physical,
length, flags);
if (error < 0)
return error;
if (error == 1)
if (ret < 0)
return ret;
if (ret == 1)
return EXT_BREAK;

return EXT_CONTINUE;
}

Expand Down

0 comments on commit d0a00c0

Please sign in to comment.