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

Commit ad7fefb1 authored by Theodore Ts'o's avatar Theodore Ts'o
Browse files

Revert "ext4: fix suboptimal seek_{data,hole} extents traversial"



This reverts commit 14516bb7.

This was causing regression test failures with generic/285 with an ext3
filesystem using CONFIG_EXT4_USE_FOR_EXT23.

Signed-off-by: default avatarTheodore Ts'o <tytso@mit.edu>
parent 011fa994
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -5166,7 +5166,7 @@ int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,

	/* fallback to generic here if not in extents fmt */
	if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)))
		return __generic_block_fiemap(inode, fieinfo, start, len,
		return generic_block_fiemap(inode, fieinfo, start, len,
			ext4_get_block);

	if (fiemap_check_flags(fieinfo, EXT4_FIEMAP_FLAGS))
+114 −106
Original line number Diff line number Diff line
@@ -273,19 +273,24 @@ static int ext4_file_open(struct inode * inode, struct file * filp)
 * we determine this extent as a data or a hole according to whether the
 * page cache has data or not.
 */
static int ext4_find_unwritten_pgoff(struct inode *inode, int whence,
				     loff_t endoff, loff_t *offset)
static int ext4_find_unwritten_pgoff(struct inode *inode,
				     int whence,
				     struct ext4_map_blocks *map,
				     loff_t *offset)
{
	struct pagevec pvec;
	unsigned int blkbits;
	pgoff_t index;
	pgoff_t end;
	loff_t endoff;
	loff_t startoff;
	loff_t lastoff;
	int found = 0;

	blkbits = inode->i_sb->s_blocksize_bits;
	startoff = *offset;
	lastoff = startoff;

	endoff = (loff_t)(map->m_lblk + map->m_len) << blkbits;

	index = startoff >> PAGE_CACHE_SHIFT;
	end = endoff >> PAGE_CACHE_SHIFT;
@@ -403,144 +408,147 @@ static int ext4_find_unwritten_pgoff(struct inode *inode, int whence,
static loff_t ext4_seek_data(struct file *file, loff_t offset, loff_t maxsize)
{
	struct inode *inode = file->f_mapping->host;
	struct fiemap_extent_info fie;
	struct fiemap_extent ext[2];
	loff_t next;
	int i, ret = 0;
	struct ext4_map_blocks map;
	struct extent_status es;
	ext4_lblk_t start, last, end;
	loff_t dataoff, isize;
	int blkbits;
	int ret = 0;

	mutex_lock(&inode->i_mutex);
	if (offset >= inode->i_size) {

	isize = i_size_read(inode);
	if (offset >= isize) {
		mutex_unlock(&inode->i_mutex);
		return -ENXIO;
	}
	fie.fi_flags = 0;
	fie.fi_extents_max = 2;
	fie.fi_extents_start = (struct fiemap_extent __user *) &ext;
	while (1) {
		mm_segment_t old_fs = get_fs();

		fie.fi_extents_mapped = 0;
		memset(ext, 0, sizeof(*ext) * fie.fi_extents_max);
	blkbits = inode->i_sb->s_blocksize_bits;
	start = offset >> blkbits;
	last = start;
	end = isize >> blkbits;
	dataoff = offset;

		set_fs(get_ds());
		ret = ext4_fiemap(inode, &fie, offset, maxsize - offset);
		set_fs(old_fs);
		if (ret)
			break;

		/* No extents found, EOF */
		if (!fie.fi_extents_mapped) {
			ret = -ENXIO;
	do {
		map.m_lblk = last;
		map.m_len = end - last + 1;
		ret = ext4_map_blocks(NULL, inode, &map, 0);
		if (ret > 0 && !(map.m_flags & EXT4_MAP_UNWRITTEN)) {
			if (last != start)
				dataoff = (loff_t)last << blkbits;
			break;
		}
		for (i = 0; i < fie.fi_extents_mapped; i++) {
			next = (loff_t)(ext[i].fe_length + ext[i].fe_logical);

			if (offset < (loff_t)ext[i].fe_logical)
				offset = (loff_t)ext[i].fe_logical;
		/*
			 * If extent is not unwritten, then it contains valid
			 * data, mapped or delayed.
		 * If there is a delay extent at this offset,
		 * it will be as a data.
		 */
			if (!(ext[i].fe_flags & FIEMAP_EXTENT_UNWRITTEN))
				goto out;
		ext4_es_find_delayed_extent_range(inode, last, last, &es);
		if (es.es_len != 0 && in_range(last, es.es_lblk, es.es_len)) {
			if (last != start)
				dataoff = (loff_t)last << blkbits;
			break;
		}

		/*
		 * If there is a unwritten extent at this offset,
		 * it will be as a data or a hole according to page
		 * cache that has data or not.
		 */
			if (ext4_find_unwritten_pgoff(inode, SEEK_DATA,
						      next, &offset))
				goto out;

			if (ext[i].fe_flags & FIEMAP_EXTENT_LAST) {
				ret = -ENXIO;
				goto out;
			}
			offset = next;
		}
		if (map.m_flags & EXT4_MAP_UNWRITTEN) {
			int unwritten;
			unwritten = ext4_find_unwritten_pgoff(inode, SEEK_DATA,
							      &map, &dataoff);
			if (unwritten)
				break;
		}
	if (offset > inode->i_size)
		offset = inode->i_size;
out:

		last++;
		dataoff = (loff_t)last << blkbits;
	} while (last <= end);

	mutex_unlock(&inode->i_mutex);
	if (ret)
		return ret;

	return vfs_setpos(file, offset, maxsize);
	if (dataoff > isize)
		return -ENXIO;

	return vfs_setpos(file, dataoff, maxsize);
}

/*
 * ext4_seek_hole() retrieves the offset for SEEK_HOLE
 * ext4_seek_hole() retrieves the offset for SEEK_HOLE.
 */
static loff_t ext4_seek_hole(struct file *file, loff_t offset, loff_t maxsize)
{
	struct inode *inode = file->f_mapping->host;
	struct fiemap_extent_info fie;
	struct fiemap_extent ext[2];
	loff_t next;
	int i, ret = 0;
	struct ext4_map_blocks map;
	struct extent_status es;
	ext4_lblk_t start, last, end;
	loff_t holeoff, isize;
	int blkbits;
	int ret = 0;

	mutex_lock(&inode->i_mutex);
	if (offset >= inode->i_size) {

	isize = i_size_read(inode);
	if (offset >= isize) {
		mutex_unlock(&inode->i_mutex);
		return -ENXIO;
	}

	fie.fi_flags = 0;
	fie.fi_extents_max = 2;
	fie.fi_extents_start = (struct fiemap_extent __user *)&ext;
	while (1) {
		mm_segment_t old_fs = get_fs();

		fie.fi_extents_mapped = 0;
		memset(ext, 0, sizeof(*ext));
	blkbits = inode->i_sb->s_blocksize_bits;
	start = offset >> blkbits;
	last = start;
	end = isize >> blkbits;
	holeoff = offset;

		set_fs(get_ds());
		ret = ext4_fiemap(inode, &fie, offset, maxsize - offset);
		set_fs(old_fs);
		if (ret)
			break;

		/* No extents found */
		if (!fie.fi_extents_mapped)
			break;
	do {
		map.m_lblk = last;
		map.m_len = end - last + 1;
		ret = ext4_map_blocks(NULL, inode, &map, 0);
		if (ret > 0 && !(map.m_flags & EXT4_MAP_UNWRITTEN)) {
			last += ret;
			holeoff = (loff_t)last << blkbits;
			continue;
		}

		for (i = 0; i < fie.fi_extents_mapped; i++) {
			next = (loff_t)(ext[i].fe_logical + ext[i].fe_length);
		/*
			 * If extent is not unwritten, then it contains valid
			 * data, mapped or delayed.
		 * If there is a delay extent at this offset,
		 * we will skip this extent.
		 */
			if (!(ext[i].fe_flags & FIEMAP_EXTENT_UNWRITTEN)) {
				if (offset < (loff_t)ext[i].fe_logical)
					goto out;
				offset = next;
		ext4_es_find_delayed_extent_range(inode, last, last, &es);
		if (es.es_len != 0 && in_range(last, es.es_lblk, es.es_len)) {
			last = es.es_lblk + es.es_len;
			holeoff = (loff_t)last << blkbits;
			continue;
		}

		/*
		 * If there is a unwritten extent at this offset,
		 * it will be as a data or a hole according to page
		 * cache that has data or not.
		 */
			if (ext4_find_unwritten_pgoff(inode, SEEK_HOLE,
						      next, &offset))
				goto out;

			offset = next;
			if (ext[i].fe_flags & FIEMAP_EXTENT_LAST)
				goto out;
		if (map.m_flags & EXT4_MAP_UNWRITTEN) {
			int unwritten;
			unwritten = ext4_find_unwritten_pgoff(inode, SEEK_HOLE,
							      &map, &holeoff);
			if (!unwritten) {
				last += ret;
				holeoff = (loff_t)last << blkbits;
				continue;
			}
		}
	if (offset > inode->i_size)
		offset = inode->i_size;
out:

		/* find a hole */
		break;
	} while (last <= end);

	mutex_unlock(&inode->i_mutex);
	if (ret)
		return ret;

	return vfs_setpos(file, offset, maxsize);
	if (holeoff > isize)
		holeoff = isize;

	return vfs_setpos(file, holeoff, maxsize);
}

/*