Commit c6b02710 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull misc filesystem updates from Jan Kara:

 - Rewrite kmap_local() handling in ext2

 - Convert ext2 direct IO path to iomap (with some infrastructure tweaks
   associated with that)

 - Convert two boilerplate licenses in udf to SPDX identifiers

 - Other small udf, ext2, and quota fixes and cleanups

* tag 'fs_for_v6.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs:
  udf: Fix uninitialized array access for some pathnames
  ext2: Drop fragment support
  quota: fix warning in dqgrab()
  quota: Properly disable quotas when add_dquot_ref() fails
  fs: udf: udftime: Replace LGPL boilerplate with SPDX identifier
  fs: udf: Replace GPL 2.0 boilerplate license notice with SPDX identifier
  fs: Drop wait_unfrozen wait queue
  ext2_find_entry()/ext2_dotdot(): callers don't need page_addr anymore
  ext2_{set_link,delete_entry}(): don't bother with page_addr
  ext2_put_page(): accept any pointer within the page
  ext2_get_page(): saner type
  ext2: use offset_in_page() instead of open-coding it as subtraction
  ext2_rename(): set_link and delete_entry may fail
  ext2: Add direct-io trace points
  ext2: Move direct-io to use iomap
  ext2: Use generic_buffers_fsync() implementation
  ext4: Use generic_buffers_fsync_noflush() implementation
  fs/buffer.c: Add generic_buffers_fsync*() implementation
  ext2/dax: Fix ext2_setsize when len is page aligned
parents 18c9901d 028f6055
Loading
Loading
Loading
Loading
+70 −0
Original line number Diff line number Diff line
@@ -591,6 +591,76 @@ int sync_mapping_buffers(struct address_space *mapping)
}
EXPORT_SYMBOL(sync_mapping_buffers);

/**
 * generic_buffers_fsync_noflush - generic buffer fsync implementation
 * for simple filesystems with no inode lock
 *
 * @file:	file to synchronize
 * @start:	start offset in bytes
 * @end:	end offset in bytes (inclusive)
 * @datasync:	only synchronize essential metadata if true
 *
 * This is a generic implementation of the fsync method for simple
 * filesystems which track all non-inode metadata in the buffers list
 * hanging off the address_space structure.
 */
int generic_buffers_fsync_noflush(struct file *file, loff_t start, loff_t end,
				  bool datasync)
{
	struct inode *inode = file->f_mapping->host;
	int err;
	int ret;

	err = file_write_and_wait_range(file, start, end);
	if (err)
		return err;

	ret = sync_mapping_buffers(inode->i_mapping);
	if (!(inode->i_state & I_DIRTY_ALL))
		goto out;
	if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
		goto out;

	err = sync_inode_metadata(inode, 1);
	if (ret == 0)
		ret = err;

out:
	/* check and advance again to catch errors after syncing out buffers */
	err = file_check_and_advance_wb_err(file);
	if (ret == 0)
		ret = err;
	return ret;
}
EXPORT_SYMBOL(generic_buffers_fsync_noflush);

/**
 * generic_buffers_fsync - generic buffer fsync implementation
 * for simple filesystems with no inode lock
 *
 * @file:	file to synchronize
 * @start:	start offset in bytes
 * @end:	end offset in bytes (inclusive)
 * @datasync:	only synchronize essential metadata if true
 *
 * This is a generic implementation of the fsync method for simple
 * filesystems which track all non-inode metadata in the buffers list
 * hanging off the address_space structure. This also makes sure that
 * a device cache flush operation is called at the end.
 */
int generic_buffers_fsync(struct file *file, loff_t start, loff_t end,
			  bool datasync)
{
	struct inode *inode = file->f_mapping->host;
	int ret;

	ret = generic_buffers_fsync_noflush(file, start, end, datasync);
	if (!ret)
		ret = blkdev_issue_flush(inode->i_sb->s_bdev);
	return ret;
}
EXPORT_SYMBOL(generic_buffers_fsync);

/*
 * Called when we've recently written block `bblock', and it is known that
 * `bblock' was for a buffer_boundary() buffer.  This means that the block at
+4 −1
Original line number Diff line number Diff line
@@ -6,7 +6,10 @@
obj-$(CONFIG_EXT2_FS) += ext2.o

ext2-y := balloc.o dir.o file.o ialloc.o inode.o \
	  ioctl.o namei.o super.o symlink.o
	  ioctl.o namei.o super.o symlink.o trace.o

# For tracepoints to include our trace.h from tracepoint infrastructure
CFLAGS_trace.o := -I$(src)

ext2-$(CONFIG_EXT2_FS_XATTR)	 += xattr.o xattr_user.o xattr_trusted.o
ext2-$(CONFIG_EXT2_FS_POSIX_ACL) += acl.o
+58 −78
Original line number Diff line number Diff line
@@ -186,23 +186,25 @@ static bool ext2_check_page(struct page *page, int quiet, char *kaddr)
 * NOTE: ext2_find_entry() and ext2_dotdot() act as a call to ext2_get_page()
 * and should be treated as a call to ext2_get_page() for nesting purposes.
 */
static struct page * ext2_get_page(struct inode *dir, unsigned long n,
				   int quiet, void **page_addr)
static void *ext2_get_page(struct inode *dir, unsigned long n,
				   int quiet, struct page **page)
{
	struct address_space *mapping = dir->i_mapping;
	struct folio *folio = read_mapping_folio(mapping, n, NULL);
	void *page_addr;

	if (IS_ERR(folio))
		return &folio->page;
	*page_addr = kmap_local_folio(folio, n & (folio_nr_pages(folio) - 1));
		return ERR_CAST(folio);
	page_addr = kmap_local_folio(folio, n & (folio_nr_pages(folio) - 1));
	if (unlikely(!folio_test_checked(folio))) {
		if (!ext2_check_page(&folio->page, quiet, *page_addr))
		if (!ext2_check_page(&folio->page, quiet, page_addr))
			goto fail;
	}
	return &folio->page;
	*page = &folio->page;
	return page_addr;

fail:
	ext2_put_page(&folio->page, *page_addr);
	ext2_put_page(&folio->page, page_addr);
	return ERR_PTR(-EIO);
}

@@ -240,7 +242,7 @@ ext2_validate_entry(char *base, unsigned offset, unsigned mask)
			break;
		p = ext2_next_entry(p);
	}
	return (char *)p - base;
	return offset_in_page(p);
}

static inline void ext2_set_de_type(ext2_dirent *de, struct inode *inode)
@@ -271,16 +273,17 @@ ext2_readdir(struct file *file, struct dir_context *ctx)
		EXT2_HAS_INCOMPAT_FEATURE(sb, EXT2_FEATURE_INCOMPAT_FILETYPE);

	for ( ; n < npages; n++, offset = 0) {
		char *kaddr, *limit;
		ext2_dirent *de;
		struct page *page = ext2_get_page(inode, n, 0, (void **)&kaddr);
		struct page *page;
		char *kaddr = ext2_get_page(inode, n, 0, &page);
		char *limit;

		if (IS_ERR(page)) {
		if (IS_ERR(kaddr)) {
			ext2_error(sb, __func__,
				   "bad page in #%lu",
				   inode->i_ino);
			ctx->pos += PAGE_SIZE - offset;
			return PTR_ERR(page);
			return PTR_ERR(kaddr);
		}
		if (unlikely(need_revalidate)) {
			if (offset) {
@@ -296,7 +299,7 @@ ext2_readdir(struct file *file, struct dir_context *ctx)
			if (de->rec_len == 0) {
				ext2_error(sb, __func__,
					"zero-length directory entry");
				ext2_put_page(page, kaddr);
				ext2_put_page(page, de);
				return -EIO;
			}
			if (de->inode) {
@@ -308,7 +311,7 @@ ext2_readdir(struct file *file, struct dir_context *ctx)
				if (!dir_emit(ctx, de->name, de->name_len,
						le32_to_cpu(de->inode),
						d_type)) {
					ext2_put_page(page, kaddr);
					ext2_put_page(page, de);
					return 0;
				}
			}
@@ -336,8 +339,7 @@ ext2_readdir(struct file *file, struct dir_context *ctx)
 * should be treated as a call to ext2_get_page() for nesting purposes.
 */
struct ext2_dir_entry_2 *ext2_find_entry (struct inode *dir,
			const struct qstr *child, struct page **res_page,
			void **res_page_addr)
			const struct qstr *child, struct page **res_page)
{
	const char *name = child->name;
	int namelen = child->len;
@@ -347,40 +349,36 @@ struct ext2_dir_entry_2 *ext2_find_entry (struct inode *dir,
	struct page *page = NULL;
	struct ext2_inode_info *ei = EXT2_I(dir);
	ext2_dirent * de;
	void *page_addr;

	if (npages == 0)
		goto out;

	/* OFFSET_CACHE */
	*res_page = NULL;
	*res_page_addr = NULL;

	start = ei->i_dir_start_lookup;
	if (start >= npages)
		start = 0;
	n = start;
	do {
		char *kaddr;
		page = ext2_get_page(dir, n, 0, &page_addr);
		if (IS_ERR(page))
			return ERR_CAST(page);
		char *kaddr = ext2_get_page(dir, n, 0, &page);
		if (IS_ERR(kaddr))
			return ERR_CAST(kaddr);

		kaddr = page_addr;
		de = (ext2_dirent *) kaddr;
		kaddr += ext2_last_byte(dir, n) - reclen;
		while ((char *) de <= kaddr) {
			if (de->rec_len == 0) {
				ext2_error(dir->i_sb, __func__,
					"zero-length directory entry");
				ext2_put_page(page, page_addr);
				ext2_put_page(page, de);
				goto out;
			}
			if (ext2_match(namelen, name, de))
				goto found;
			de = ext2_next_entry(de);
		}
		ext2_put_page(page, page_addr);
		ext2_put_page(page, kaddr);

		if (++n >= npages)
			n = 0;
@@ -398,7 +396,6 @@ struct ext2_dir_entry_2 *ext2_find_entry (struct inode *dir,

found:
	*res_page = page;
	*res_page_addr = page_addr;
	ei->i_dir_start_lookup = n;
	return de;
}
@@ -415,33 +412,26 @@ struct ext2_dir_entry_2 *ext2_find_entry (struct inode *dir,
 * ext2_find_entry() and ext2_dotdot() act as a call to ext2_get_page() and
 * should be treated as a call to ext2_get_page() for nesting purposes.
 */
struct ext2_dir_entry_2 *ext2_dotdot(struct inode *dir, struct page **p,
				     void **pa)
struct ext2_dir_entry_2 *ext2_dotdot(struct inode *dir, struct page **p)
{
	void *page_addr;
	struct page *page = ext2_get_page(dir, 0, 0, &page_addr);
	ext2_dirent *de = NULL;
	ext2_dirent *de = ext2_get_page(dir, 0, 0, p);

	if (!IS_ERR(page)) {
		de = ext2_next_entry((ext2_dirent *) page_addr);
		*p = page;
		*pa = page_addr;
	}
	return de;
	if (!IS_ERR(de))
		return ext2_next_entry(de);
	return NULL;
}

int ext2_inode_by_name(struct inode *dir, const struct qstr *child, ino_t *ino)
{
	struct ext2_dir_entry_2 *de;
	struct page *page;
	void *page_addr;
	
	de = ext2_find_entry(dir, child, &page, &page_addr);
	de = ext2_find_entry(dir, child, &page);
	if (IS_ERR(de))
		return PTR_ERR(de);

	*ino = le32_to_cpu(de->inode);
	ext2_put_page(page, page_addr);
	ext2_put_page(page, de);
	return 0;
}

@@ -462,11 +452,9 @@ static int ext2_handle_dirsync(struct inode *dir)
}

int ext2_set_link(struct inode *dir, struct ext2_dir_entry_2 *de,
		struct page *page, void *page_addr, struct inode *inode,
		bool update_times)
		struct page *page, struct inode *inode, bool update_times)
{
	loff_t pos = page_offset(page) +
			(char *) de - (char *) page_addr;
	loff_t pos = page_offset(page) + offset_in_page(de);
	unsigned len = ext2_rec_len_from_disk(de->rec_len);
	int err;

@@ -498,7 +486,6 @@ int ext2_add_link (struct dentry *dentry, struct inode *inode)
	unsigned reclen = EXT2_DIR_REC_LEN(namelen);
	unsigned short rec_len, name_len;
	struct page *page = NULL;
	void *page_addr = NULL;
	ext2_dirent * de;
	unsigned long npages = dir_pages(dir);
	unsigned long n;
@@ -511,15 +498,12 @@ int ext2_add_link (struct dentry *dentry, struct inode *inode)
	 * to protect that region.
	 */
	for (n = 0; n <= npages; n++) {
		char *kaddr;
		char *kaddr = ext2_get_page(dir, n, 0, &page);
		char *dir_end;

		page = ext2_get_page(dir, n, 0, &page_addr);
		err = PTR_ERR(page);
		if (IS_ERR(page))
			goto out;
		if (IS_ERR(kaddr))
			return PTR_ERR(kaddr);
		lock_page(page);
		kaddr = page_addr;
		dir_end = kaddr + ext2_last_byte(dir, n);
		de = (ext2_dirent *)kaddr;
		kaddr += PAGE_SIZE - reclen;
@@ -550,14 +534,13 @@ int ext2_add_link (struct dentry *dentry, struct inode *inode)
			de = (ext2_dirent *) ((char *) de + rec_len);
		}
		unlock_page(page);
		ext2_put_page(page, page_addr);
		ext2_put_page(page, kaddr);
	}
	BUG();
	return -EINVAL;

got_it:
	pos = page_offset(page) +
		(char *)de - (char *)page_addr;
	pos = page_offset(page) + offset_in_page(de);
	err = ext2_prepare_chunk(page, pos, rec_len);
	if (err)
		goto out_unlock;
@@ -578,8 +561,7 @@ int ext2_add_link (struct dentry *dentry, struct inode *inode)
	err = ext2_handle_dirsync(dir);
	/* OFFSET_CACHE */
out_put:
	ext2_put_page(page, page_addr);
out:
	ext2_put_page(page, de);
	return err;
out_unlock:
	unlock_page(page);
@@ -590,12 +572,12 @@ int ext2_add_link (struct dentry *dentry, struct inode *inode)
 * ext2_delete_entry deletes a directory entry by merging it with the
 * previous entry. Page is up-to-date.
 */
int ext2_delete_entry (struct ext2_dir_entry_2 *dir, struct page *page,
			char *kaddr)
int ext2_delete_entry(struct ext2_dir_entry_2 *dir, struct page *page)
{
	struct inode *inode = page->mapping->host;
	unsigned from = ((char*)dir - kaddr) & ~(ext2_chunk_size(inode)-1);
	unsigned to = ((char *)dir - kaddr) +
	char *kaddr = (char *)((unsigned long)dir & PAGE_MASK);
	unsigned from = offset_in_page(dir) & ~(ext2_chunk_size(inode)-1);
	unsigned to = offset_in_page(dir) +
				ext2_rec_len_from_disk(dir->rec_len);
	loff_t pos;
	ext2_dirent *pde = NULL;
@@ -606,18 +588,20 @@ int ext2_delete_entry (struct ext2_dir_entry_2 *dir, struct page *page,
		if (de->rec_len == 0) {
			ext2_error(inode->i_sb, __func__,
				"zero-length directory entry");
			err = -EIO;
			goto out;
			return -EIO;
		}
		pde = de;
		de = ext2_next_entry(de);
	}
	if (pde)
		from = (char *)pde - kaddr;
		from = offset_in_page(pde);
	pos = page_offset(page) + from;
	lock_page(page);
	err = ext2_prepare_chunk(page, pos, to - from);
	BUG_ON(err);
	if (err) {
		unlock_page(page);
		return err;
	}
	if (pde)
		pde->rec_len = ext2_rec_len_to_disk(to - from);
	dir->inode = 0;
@@ -625,9 +609,7 @@ int ext2_delete_entry (struct ext2_dir_entry_2 *dir, struct page *page,
	inode->i_ctime = inode->i_mtime = current_time(inode);
	EXT2_I(inode)->i_flags &= ~EXT2_BTREE_FL;
	mark_inode_dirty(inode);
	err = ext2_handle_dirsync(inode);
out:
	return err;
	return ext2_handle_dirsync(inode);
}

/*
@@ -677,19 +659,17 @@ int ext2_make_empty(struct inode *inode, struct inode *parent)
 */
int ext2_empty_dir (struct inode * inode)
{
	void *page_addr = NULL;
	struct page *page = NULL;
	struct page *page;
	char *kaddr;
	unsigned long i, npages = dir_pages(inode);

	for (i = 0; i < npages; i++) {
		char *kaddr;
		ext2_dirent *de;
		page = ext2_get_page(inode, i, 0, &page_addr);

		if (IS_ERR(page))
		kaddr = ext2_get_page(inode, i, 0, &page);
		if (IS_ERR(kaddr))
			return 0;

		kaddr = page_addr;
		de = (ext2_dirent *)kaddr;
		kaddr += ext2_last_byte(inode, i) - EXT2_DIR_REC_LEN(1);

@@ -715,12 +695,12 @@ int ext2_empty_dir (struct inode * inode)
			}
			de = ext2_next_entry(de);
		}
		ext2_put_page(page, page_addr);
		ext2_put_page(page, kaddr);
	}
	return 1;

not_empty:
	ext2_put_page(page, page_addr);
	ext2_put_page(page, kaddr);
	return 0;
}

+5 −18
Original line number Diff line number Diff line
@@ -70,10 +70,7 @@ struct mb_cache;
 * second extended-fs super-block data in memory
 */
struct ext2_sb_info {
	unsigned long s_frag_size;	/* Size of a fragment in bytes */
	unsigned long s_frags_per_block;/* Number of fragments per block */
	unsigned long s_inodes_per_block;/* Number of inodes per block */
	unsigned long s_frags_per_group;/* Number of fragments in a group */
	unsigned long s_blocks_per_group;/* Number of blocks in a group */
	unsigned long s_inodes_per_group;/* Number of inodes in a group */
	unsigned long s_itb_per_group;	/* Number of inode table blocks per group */
@@ -188,15 +185,6 @@ static inline struct ext2_sb_info *EXT2_SB(struct super_block *sb)
#define EXT2_INODE_SIZE(s)		(EXT2_SB(s)->s_inode_size)
#define EXT2_FIRST_INO(s)		(EXT2_SB(s)->s_first_ino)

/*
 * Macro-instructions used to manage fragments
 */
#define EXT2_MIN_FRAG_SIZE		1024
#define	EXT2_MAX_FRAG_SIZE		4096
#define EXT2_MIN_FRAG_LOG_SIZE		  10
#define EXT2_FRAG_SIZE(s)		(EXT2_SB(s)->s_frag_size)
#define EXT2_FRAGS_PER_BLOCK(s)		(EXT2_SB(s)->s_frags_per_block)

/*
 * Structure of a blocks group descriptor
 */
@@ -730,14 +718,12 @@ extern int ext2_inode_by_name(struct inode *dir,
			      const struct qstr *child, ino_t *ino);
extern int ext2_make_empty(struct inode *, struct inode *);
extern struct ext2_dir_entry_2 *ext2_find_entry(struct inode *, const struct qstr *,
						struct page **, void **res_page_addr);
extern int ext2_delete_entry(struct ext2_dir_entry_2 *dir, struct page *page,
			     char *kaddr);
						struct page **);
extern int ext2_delete_entry(struct ext2_dir_entry_2 *dir, struct page *page);
extern int ext2_empty_dir (struct inode *);
extern struct ext2_dir_entry_2 *ext2_dotdot(struct inode *dir, struct page **p, void **pa);
extern struct ext2_dir_entry_2 *ext2_dotdot(struct inode *dir, struct page **p);
int ext2_set_link(struct inode *dir, struct ext2_dir_entry_2 *de,
		struct page *page, void *page_addr, struct inode *inode,
		bool update_times);
		struct page *page, struct inode *inode, bool update_times);
static inline void ext2_put_page(struct page *page, void *page_addr)
{
	kunmap_local(page_addr);
@@ -754,6 +740,7 @@ extern unsigned long ext2_count_free (struct buffer_head *, unsigned);
extern struct inode *ext2_iget (struct super_block *, unsigned long);
extern int ext2_write_inode (struct inode *, struct writeback_control *);
extern void ext2_evict_inode(struct inode *);
void ext2_write_failed(struct address_space *mapping, loff_t to);
extern int ext2_get_block(struct inode *, sector_t, struct buffer_head *, int);
extern int ext2_setattr (struct mnt_idmap *, struct dentry *, struct iattr *);
extern int ext2_getattr (struct mnt_idmap *, const struct path *,
+125 −1
Original line number Diff line number Diff line
@@ -25,9 +25,11 @@
#include <linux/quotaops.h>
#include <linux/iomap.h>
#include <linux/uio.h>
#include <linux/buffer_head.h>
#include "ext2.h"
#include "xattr.h"
#include "acl.h"
#include "trace.h"

#ifdef CONFIG_FS_DAX
static ssize_t ext2_dax_read_iter(struct kiocb *iocb, struct iov_iter *to)
@@ -153,7 +155,7 @@ int ext2_fsync(struct file *file, loff_t start, loff_t end, int datasync)
	int ret;
	struct super_block *sb = file->f_mapping->host->i_sb;

	ret = generic_file_fsync(file, start, end, datasync);
	ret = generic_buffers_fsync(file, start, end, datasync);
	if (ret == -EIO)
		/* We don't really know where the IO error happened... */
		ext2_error(sb, __func__,
@@ -161,12 +163,131 @@ int ext2_fsync(struct file *file, loff_t start, loff_t end, int datasync)
	return ret;
}

static ssize_t ext2_dio_read_iter(struct kiocb *iocb, struct iov_iter *to)
{
	struct file *file = iocb->ki_filp;
	struct inode *inode = file->f_mapping->host;
	ssize_t ret;

	trace_ext2_dio_read_begin(iocb, to, 0);
	inode_lock_shared(inode);
	ret = iomap_dio_rw(iocb, to, &ext2_iomap_ops, NULL, 0, NULL, 0);
	inode_unlock_shared(inode);
	trace_ext2_dio_read_end(iocb, to, ret);

	return ret;
}

static int ext2_dio_write_end_io(struct kiocb *iocb, ssize_t size,
				 int error, unsigned int flags)
{
	loff_t pos = iocb->ki_pos;
	struct inode *inode = file_inode(iocb->ki_filp);

	if (error)
		goto out;

	/*
	 * If we are extending the file, we have to update i_size here before
	 * page cache gets invalidated in iomap_dio_rw(). This prevents racing
	 * buffered reads from zeroing out too much from page cache pages.
	 * Note that all extending writes always happens synchronously with
	 * inode lock held by ext2_dio_write_iter(). So it is safe to update
	 * inode size here for extending file writes.
	 */
	pos += size;
	if (pos > i_size_read(inode)) {
		i_size_write(inode, pos);
		mark_inode_dirty(inode);
	}
out:
	trace_ext2_dio_write_endio(iocb, size, error);
	return error;
}

static const struct iomap_dio_ops ext2_dio_write_ops = {
	.end_io = ext2_dio_write_end_io,
};

static ssize_t ext2_dio_write_iter(struct kiocb *iocb, struct iov_iter *from)
{
	struct file *file = iocb->ki_filp;
	struct inode *inode = file->f_mapping->host;
	ssize_t ret;
	unsigned int flags = 0;
	unsigned long blocksize = inode->i_sb->s_blocksize;
	loff_t offset = iocb->ki_pos;
	loff_t count = iov_iter_count(from);
	ssize_t status = 0;

	trace_ext2_dio_write_begin(iocb, from, 0);
	inode_lock(inode);
	ret = generic_write_checks(iocb, from);
	if (ret <= 0)
		goto out_unlock;

	ret = kiocb_modified(iocb);
	if (ret)
		goto out_unlock;

	/* use IOMAP_DIO_FORCE_WAIT for unaligned or extending writes */
	if (iocb->ki_pos + iov_iter_count(from) > i_size_read(inode) ||
	   (!IS_ALIGNED(iocb->ki_pos | iov_iter_alignment(from), blocksize)))
		flags |= IOMAP_DIO_FORCE_WAIT;

	ret = iomap_dio_rw(iocb, from, &ext2_iomap_ops, &ext2_dio_write_ops,
			   flags, NULL, 0);

	/* ENOTBLK is magic return value for fallback to buffered-io */
	if (ret == -ENOTBLK)
		ret = 0;

	if (ret < 0 && ret != -EIOCBQUEUED)
		ext2_write_failed(inode->i_mapping, offset + count);

	/* handle case for partial write and for fallback to buffered write */
	if (ret >= 0 && iov_iter_count(from)) {
		loff_t pos, endbyte;
		int ret2;

		iocb->ki_flags &= ~IOCB_DIRECT;
		pos = iocb->ki_pos;
		status = generic_perform_write(iocb, from);
		if (unlikely(status < 0)) {
			ret = status;
			goto out_unlock;
		}

		iocb->ki_pos += status;
		ret += status;
		endbyte = pos + status - 1;
		ret2 = filemap_write_and_wait_range(inode->i_mapping, pos,
						    endbyte);
		if (!ret2)
			invalidate_mapping_pages(inode->i_mapping,
						 pos >> PAGE_SHIFT,
						 endbyte >> PAGE_SHIFT);
		if (ret > 0)
			generic_write_sync(iocb, ret);
	}

out_unlock:
	inode_unlock(inode);
	if (status)
		trace_ext2_dio_write_buff_end(iocb, from, status);
	trace_ext2_dio_write_end(iocb, from, ret);
	return ret;
}

static ssize_t ext2_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
{
#ifdef CONFIG_FS_DAX
	if (IS_DAX(iocb->ki_filp->f_mapping->host))
		return ext2_dax_read_iter(iocb, to);
#endif
	if (iocb->ki_flags & IOCB_DIRECT)
		return ext2_dio_read_iter(iocb, to);

	return generic_file_read_iter(iocb, to);
}

@@ -176,6 +297,9 @@ static ssize_t ext2_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
	if (IS_DAX(iocb->ki_filp->f_mapping->host))
		return ext2_dax_write_iter(iocb, from);
#endif
	if (iocb->ki_flags & IOCB_DIRECT)
		return ext2_dio_write_iter(iocb, from);

	return generic_file_write_iter(iocb, from);
}

Loading