Commit 63b0c403 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull FIEMAP cleanups from Jan Kara:
 "FIEMAP cleanups from Christoph transitioning all remaining filesystems
  supporting FIEMAP (ext2, hpfs) to iomap API and removing the old
  helper"

* tag 'fiemap_for_v5.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs:
  fs: remove generic_block_fiemap
  hpfs: use iomap_fiemap to implement ->fiemap
  ext2: use iomap_fiemap to implement ->fiemap
  ext2: make ext2_iomap_ops available unconditionally
parents 35134319 9acb9c48
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
# SPDX-License-Identifier: GPL-2.0-only
config EXT2_FS
	tristate "Second extended fs support"
	select FS_IOMAP
	help
	  Ext2 is a standard Linux file system for hard disks.

+8 −7
Original line number Diff line number Diff line
@@ -799,7 +799,6 @@ int ext2_get_block(struct inode *inode, sector_t iblock,

}

#ifdef CONFIG_FS_DAX
static int ext2_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
		unsigned flags, struct iomap *iomap, struct iomap *srcmap)
{
@@ -852,16 +851,18 @@ const struct iomap_ops ext2_iomap_ops = {
	.iomap_begin		= ext2_iomap_begin,
	.iomap_end		= ext2_iomap_end,
};
#else
/* Define empty ops for !CONFIG_FS_DAX case to avoid ugly ifdefs */
const struct iomap_ops ext2_iomap_ops;
#endif /* CONFIG_FS_DAX */

int ext2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
		u64 start, u64 len)
{
	return generic_block_fiemap(inode, fieinfo, start, len,
				    ext2_get_block);
	int ret;

	inode_lock(inode);
	len = min_t(u64, len, i_size_read(inode));
	ret = iomap_fiemap(inode, fieinfo, start, len, &ext2_iomap_ops);
	inode_unlock(inode);

	return ret;
}

static int ext2_writepage(struct page *page, struct writeback_control *wbc)
+1 −0
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@
config HPFS_FS
	tristate "OS/2 HPFS file system support"
	depends on BLOCK
	select FS_IOMAP
	help
	  OS/2 is IBM's operating system for PC's, the same as Warp, and HPFS
	  is the file system used for organizing files on OS/2 hard disk
+50 −1
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@

#include "hpfs_fn.h"
#include <linux/mpage.h>
#include <linux/iomap.h>
#include <linux/fiemap.h>

#define BLOCKS(size) (((size) + 511) >> 9)
@@ -116,6 +117,47 @@ static int hpfs_get_block(struct inode *inode, sector_t iblock, struct buffer_he
	return r;
}

static int hpfs_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
		unsigned flags, struct iomap *iomap, struct iomap *srcmap)
{
	struct super_block *sb = inode->i_sb;
	unsigned int blkbits = inode->i_blkbits;
	unsigned int n_secs;
	secno s;

	if (WARN_ON_ONCE(flags & (IOMAP_WRITE | IOMAP_ZERO)))
		return -EINVAL;

	iomap->bdev = inode->i_sb->s_bdev;
	iomap->offset = offset;

	hpfs_lock(sb);
	s = hpfs_bmap(inode, offset >> blkbits, &n_secs);
	if (s) {
		n_secs = hpfs_search_hotfix_map_for_range(sb, s,
				min_t(loff_t, n_secs, length));
		if (unlikely(!n_secs)) {
			s = hpfs_search_hotfix_map(sb, s);
			n_secs = 1;
		}
		iomap->type = IOMAP_MAPPED;
		iomap->flags = IOMAP_F_MERGED;
		iomap->addr = (u64)s << blkbits;
		iomap->length = (u64)n_secs << blkbits;
	} else {
		iomap->type = IOMAP_HOLE;
		iomap->addr = IOMAP_NULL_ADDR;
		iomap->length = 1 << blkbits;
	}

	hpfs_unlock(sb);
	return 0;
}

static const struct iomap_ops hpfs_iomap_ops = {
	.iomap_begin		= hpfs_iomap_begin,
};

static int hpfs_readpage(struct file *file, struct page *page)
{
	return mpage_readpage(page, hpfs_get_block);
@@ -192,7 +234,14 @@ static sector_t _hpfs_bmap(struct address_space *mapping, sector_t block)

static int hpfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, u64 start, u64 len)
{
	return generic_block_fiemap(inode, fieinfo, start, len, hpfs_get_block);
	int ret;

	inode_lock(inode);
	len = min_t(u64, len, i_size_read(inode));
	ret = iomap_fiemap(inode, fieinfo, start, len, &hpfs_iomap_ops);
	inode_unlock(inode);

	return ret;
}

const struct address_space_operations hpfs_aops = {
+0 −203
Original line number Diff line number Diff line
@@ -263,209 +263,6 @@ static long ioctl_file_clone_range(struct file *file,
				args.src_length, args.dest_offset);
}

#ifdef CONFIG_BLOCK

static inline sector_t logical_to_blk(struct inode *inode, loff_t offset)
{
	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)
 * @inode: the inode to map
 * @fieinfo: the fiemap info struct that will be passed back to userspace
 * @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
 * through get_block until we hit the number of extents we want to map, or we
 * go past the end of the file and hit a hole.
 *
 * If it is possible to have data blocks beyond a hole past @inode->i_size, then
 * please do not use this function, it will stop at the first unmapped block
 * beyond i_size.
 *
 * If you use this function directly, you need to do your own locking. Use
 * generic_block_fiemap if you want the locking done for you.
 */
static int __generic_block_fiemap(struct inode *inode,
			   struct fiemap_extent_info *fieinfo, loff_t start,
			   loff_t len, get_block_t *get_block)
{
	struct buffer_head map_bh;
	sector_t start_blk, last_blk;
	loff_t isize = i_size_read(inode);
	u64 logical = 0, phys = 0, size = 0;
	u32 flags = FIEMAP_EXTENT_MERGED;
	bool past_eof = false, whole_file = false;
	int ret = 0;

	ret = fiemap_prep(inode, fieinfo, start, &len, FIEMAP_FLAG_SYNC);
	if (ret)
		return ret;

	/*
	 * Either the i_mutex or other appropriate locking needs to be held
	 * since we expect isize to not change at all through the duration of
	 * this call.
	 */
	if (len >= isize) {
		whole_file = true;
		len = isize;
	}

	/*
	 * Some filesystems can't deal with being asked to map less than
	 * blocksize, so make sure our len is at least block length.
	 */
	if (logical_to_blk(inode, len) == 0)
		len = blk_to_logical(inode, 1);

	start_blk = logical_to_blk(inode, start);
	last_blk = logical_to_blk(inode, start + len - 1);

	do {
		/*
		 * we set b_size to the total size we want so it will map as
		 * many contiguous blocks as possible at once
		 */
		memset(&map_bh, 0, sizeof(struct buffer_head));
		map_bh.b_size = len;

		ret = get_block(inode, start_blk, &map_bh, 0);
		if (ret)
			break;

		/* HOLE */
		if (!buffer_mapped(&map_bh)) {
			start_blk++;

			/*
			 * We want to handle the case where there is an
			 * allocated block at the front of the file, and then
			 * nothing but holes up to the end of the file properly,
			 * to make sure that extent at the front gets properly
			 * marked with FIEMAP_EXTENT_LAST
			 */
			if (!past_eof &&
			    blk_to_logical(inode, start_blk) >= isize)
				past_eof = 1;

			/*
			 * First hole after going past the EOF, this is our
			 * last extent
			 */
			if (past_eof && size) {
				flags = FIEMAP_EXTENT_MERGED|FIEMAP_EXTENT_LAST;
				ret = fiemap_fill_next_extent(fieinfo, logical,
							      phys, size,
							      flags);
			} 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 (start_blk > last_blk || past_eof || ret)
				break;
		} else {
			/*
			 * We have gone over the length of what we wanted to
			 * map, and it wasn't the entire file, so add the extent
			 * we got last time and exit.
			 *
			 * This is for the case where say we want to map all the
			 * way up to the second to the last block in a file, but
			 * the last block is a hole, making the second to last
			 * block FIEMAP_EXTENT_LAST.  In this case we want to
			 * see if there is a hole after the second to last block
			 * so we can mark it properly.  If we found data after
			 * we exceeded the length we were requesting, then we
			 * are good to go, just add the extent to the fieinfo
			 * and break
			 */
			if (start_blk > last_blk && !whole_file) {
				ret = fiemap_fill_next_extent(fieinfo, logical,
							      phys, size,
							      flags);
				break;
			}

			/*
			 * if size != 0 then we know we already have an extent
			 * to add, so add it.
			 */
			if (size) {
				ret = fiemap_fill_next_extent(fieinfo, logical,
							      phys, size,
							      flags);
				if (ret)
					break;
			}

			logical = blk_to_logical(inode, start_blk);
			phys = blk_to_logical(inode, map_bh.b_blocknr);
			size = map_bh.b_size;
			flags = FIEMAP_EXTENT_MERGED;

			start_blk += logical_to_blk(inode, size);

			/*
			 * If we are past the EOF, then we need to make sure as
			 * soon as we find a hole that the last extent we found
			 * is marked with FIEMAP_EXTENT_LAST
			 */
			if (!past_eof && logical + size >= isize)
				past_eof = true;
		}
		cond_resched();
		if (fatal_signal_pending(current)) {
			ret = -EINTR;
			break;
		}

	} while (1);

	/* If ret is 1 then we just hit the end of the extent array */
	if (ret == 1)
		ret = 0;

	return ret;
}

/**
 * generic_block_fiemap - FIEMAP for block based inodes
 * @inode: The inode to map
 * @fieinfo: The mapping information
 * @start: The initial block to map
 * @len: The length of the extect to attempt to map
 * @get_block: The block mapping function for the fs
 *
 * Calls __generic_block_fiemap to map the inode, after taking
 * the inode's mutex lock.
 */

int generic_block_fiemap(struct inode *inode,
			 struct fiemap_extent_info *fieinfo, u64 start,
			 u64 len, get_block_t *get_block)
{
	int ret;
	inode_lock(inode);
	ret = __generic_block_fiemap(inode, fieinfo, start, len, get_block);
	inode_unlock(inode);
	return ret;
}
EXPORT_SYMBOL(generic_block_fiemap);

#endif  /*  CONFIG_BLOCK  */

/*
 * This provides compatibility with legacy XFS pre-allocation ioctls
 * which predate the fallocate syscall.
Loading