On Thu, 29 Sep 2011, Yongqiang Yang wrote: > This patch reimplements fiemap on delayed extent tree. > > Signed-off-by: Yongqiang Yang <xiaoqiangnk@xxxxxxxxx> > --- > fs/ext4/extents.c | 186 +++++++---------------------------------------------- > 1 files changed, 23 insertions(+), 163 deletions(-) > > diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c > index bdbb984..c2ae125 100644 > --- a/fs/ext4/extents.c > +++ b/fs/ext4/extents.c > @@ -3909,193 +3909,53 @@ static int ext4_ext_fiemap_cb(struct inode *inode, ext4_lblk_t next, > struct ext4_ext_cache *newex, struct ext4_extent *ex, > void *data) > { > + struct delayed_extent de; > __u64 logical; > __u64 physical; > __u64 length; > __u32 flags = 0; > + ext4_lblk_t next_del; > int ret = 0; > struct fiemap_extent_info *fieinfo = data; > unsigned char blksize_bits; > > - blksize_bits = inode->i_sb->s_blocksize_bits; > - logical = (__u64)newex->ec_block << blksize_bits; > + de.start = newex->ec_block; > + down_read(&EXT4_I(inode)->i_data_sem); > + next_del = ext4_de_find_extent(inode, &de); > + up_read(&EXT4_I(inode)->i_data_sem); > > + next = min(next_del, next); > if (newex->ec_start == 0) { > /* > * 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; > - pgoff_t start_index = 0; > - 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; > -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; > - } > - index = 0; > - > -next_page: > - /* Try to find the 1st mapped buffer. */ > - end = ((__u64)pages[index]->index << PAGE_SHIFT) >> > - blksize_bits; > - if (!page_has_buffers(pages[index])) > - goto out; > - head = page_buffers(pages[index]); > - if (!head) > - goto out; > - > - index++; > - bh = head; > - do { > - if (end >= newex->ec_block + > - newex->ec_len) > - /* The buffer is out of > - * the request range. > - */ > - goto out; > - > - if (buffer_mapped(bh) && > - end >= newex->ec_block) { > - start_index = index - 1; > - /* get the 1st mapped buffer. */ > - goto found_mapped_buffer; > - } > - > - bh = bh->b_this_page; > - end++; > - } while (bh != head); > - > - /* No mapped buffer in the range found in this page, > - * We need to look up next page. > - */ > - if (index >= ret) { > - /* There is no page left, but we need to limit > - * newex->ec_len. > - */ > - newex->ec_len = end - newex->ec_block; > - goto out; > - } > - goto next_page; > - } else { > - /*Find contiguous delayed buffers. */ > - if (ret > 0 && pages[0]->index == last_offset) > - head = page_buffers(pages[0]); > - bh = head; > - index = 1; > - start_index = 0; > - } > - > -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 < 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[start_index]->index + index > - - start_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; > + if (de.len == 0) > + /* A hole found. */ > + return EXT_CONTINUE; > + > + if (de.start > newex->ec_block) { > + /* A hole found. */ > + newex->ec_len = min(de.start - newex->ec_block, > + newex->ec_len); > + return EXT_CONTINUE; > } > > - for (index = 0; index < ret; index++) > - page_cache_release(pages[index]); > - kfree(pages); > + flags |= FIEMAP_EXTENT_DELALLOC; > + newex->ec_len = de.start + de.len - newex->ec_block; > } > > - physical = (__u64)newex->ec_start << blksize_bits; > - length = (__u64)newex->ec_len << blksize_bits; > - > if (ex && ext4_ext_is_uninitialized(ex)) > flags |= FIEMAP_EXTENT_UNWRITTEN; > > if (next == EXT_MAX_BLOCKS) > flags |= FIEMAP_EXTENT_LAST; As we know now, it is not enough to check for next allocated extent, we also have to check that there is not any delayed extents after this one. Just now I have noticed this lines at the beginning of the function: next_del = ext4_de_find_extent(inode, &de); ... next = min(next_del, next); which takes care of that, so it seems that it will fix both problems, setting FIEMAP_EXTENT_LAST for the last extent in the file and taking care of delayed extents as well. The patch seems fine. Thanks! -Lukas > > + blksize_bits = inode->i_sb->s_blocksize_bits; > + logical = (__u64)newex->ec_block << blksize_bits; > + physical = (__u64)newex->ec_start << blksize_bits; > + length = (__u64)newex->ec_len << blksize_bits; > + > ret = fiemap_fill_next_extent(fieinfo, logical, physical, > length, flags); > if (ret < 0) > -- -- To unsubscribe from this list: send the line "unsubscribe linux-ext4" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html