Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b221349f authored by Yongqiang Yang's avatar Yongqiang Yang Committed by Theodore Ts'o
Browse files

ext4: fix ext4_ext_fiemap_cb() to handle blocks before request range correctly



To get delayed-extent information, ext4_ext_fiemap_cb() looks up
pagecache, it thus collects information starting from a page's
head block.

If blocksize < pagesize, the beginning blocks of a page may lies
before the request range. So ext4_ext_fiemap_cb() should proceed
ignoring them, because they has been handled before. If no mapped
buffer in the range is found in the 1st page, we need to look up
the 2nd page, otherwise delayed-extents after a hole will be ignored.

Without this patch, xfstests 225 will hung on ext4 with 1K block.

Reported-by: default avatarAmir Goldstein <amir73il@users.sourceforge.net>
Signed-off-by: default avatarYongqiang Yang <xiaoqiangnk@gmail.com>
Signed-off-by: default avatar"Theodore Ts'o" <tytso@mit.edu>
parent 072bd7ea
Loading
Loading
Loading
Loading
+35 −14
Original line number Original line Diff line number Diff line
@@ -3688,6 +3688,7 @@ static int ext4_ext_fiemap_cb(struct inode *inode, struct ext4_ext_path *path,
		pgoff_t		last_offset;
		pgoff_t		last_offset;
		pgoff_t		offset;
		pgoff_t		offset;
		pgoff_t		index;
		pgoff_t		index;
		pgoff_t		start_index = 0;
		struct page	**pages = NULL;
		struct page	**pages = NULL;
		struct buffer_head *bh = NULL;
		struct buffer_head *bh = NULL;
		struct buffer_head *head = NULL;
		struct buffer_head *head = NULL;
@@ -3714,39 +3715,57 @@ static int ext4_ext_fiemap_cb(struct inode *inode, struct ext4_ext_path *path,
				kfree(pages);
				kfree(pages);
				return EXT_CONTINUE;
				return EXT_CONTINUE;
			}
			}
			index = 0;


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


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

				if (buffer_mapped(bh) &&
				    end >= newex->ec_block) {
					start_index = index - 1;
					/* get the 1st mapped buffer. */
					goto found_mapped_buffer;
					goto found_mapped_buffer;
				}
				}

				bh = bh->b_this_page;
				bh = bh->b_this_page;
				end++;
				end++;
			} while (bh != head);
			} while (bh != head);


			/* No mapped buffer found. */
			/* 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 out;
			}
			goto next_page;
		} else {
		} else {
			/*Find contiguous delayed buffers. */
			/*Find contiguous delayed buffers. */
			if (ret > 0 && pages[0]->index == last_offset)
			if (ret > 0 && pages[0]->index == last_offset)
				head = page_buffers(pages[0]);
				head = page_buffers(pages[0]);
			bh = head;
			bh = head;
			index = 1;
			start_index = 0;
		}
		}


found_mapped_buffer:
found_mapped_buffer:
@@ -3769,7 +3788,7 @@ static int ext4_ext_fiemap_cb(struct inode *inode, struct ext4_ext_path *path,
				end++;
				end++;
			} while (bh != head);
			} while (bh != head);


			for (index = 1; index < ret; index++) {
			for (; index < ret; index++) {
				if (!page_has_buffers(pages[index])) {
				if (!page_has_buffers(pages[index])) {
					bh = NULL;
					bh = NULL;
					break;
					break;
@@ -3779,8 +3798,10 @@ static int ext4_ext_fiemap_cb(struct inode *inode, struct ext4_ext_path *path,
					bh = NULL;
					bh = NULL;
					break;
					break;
				}
				}

				if (pages[index]->index !=
				if (pages[index]->index !=
					pages[0]->index + index) {
				    pages[start_index]->index + index
				    - start_index) {
					/* Blocks are not contiguous. */
					/* Blocks are not contiguous. */
					bh = NULL;
					bh = NULL;
					break;
					break;