ntfs3.lists.linux.dev archive mirror
 help / color / mirror / Atom feed
From: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
To: <ntfs3@lists.linux.dev>
Cc: <linux-kernel@vger.kernel.org>, <linux-fsdevel@vger.kernel.org>
Subject: [PATCH 2/2] fs/ntfs3: Enable FALLOC_FL_INSERT_RANGE
Date: Tue, 21 Jun 2022 14:45:57 +0300	[thread overview]
Message-ID: <4fc73e0d-3987-1c2c-5ec7-6b3a94d18f63@paragon-software.com> (raw)
In-Reply-To: <ab1c8348-acde-114f-eb66-0074045731a4@paragon-software.com>

Changed logic in ntfs_fallocate - more clear checks in beginning
instead of the middle of function and added FALLOC_FL_INSERT_RANGE.
Fixes xfstest generic/064
Fixes: 4342306f0f0d ("fs/ntfs3: Add file operations and implementation")

Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
---
  fs/ntfs3/file.c | 97 ++++++++++++++++++++++++++++---------------------
  1 file changed, 55 insertions(+), 42 deletions(-)

diff --git a/fs/ntfs3/file.c b/fs/ntfs3/file.c
index 27c32692513c..bdffe4b8554b 100644
--- a/fs/ntfs3/file.c
+++ b/fs/ntfs3/file.c
@@ -533,21 +533,35 @@ static int ntfs_truncate(struct inode *inode, loff_t new_size)
  static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len)
  {
  	struct inode *inode = file->f_mapping->host;
+	struct address_space *mapping = inode->i_mapping;
  	struct super_block *sb = inode->i_sb;
  	struct ntfs_sb_info *sbi = sb->s_fs_info;
  	struct ntfs_inode *ni = ntfs_i(inode);
  	loff_t end = vbo + len;
  	loff_t vbo_down = round_down(vbo, PAGE_SIZE);
-	loff_t i_size;
+	bool is_supported_holes = is_sparsed(ni) || is_compressed(ni);
+	loff_t i_size, new_size;
+	bool map_locked;
  	int err;
  
  	/* No support for dir. */
  	if (!S_ISREG(inode->i_mode))
  		return -EOPNOTSUPP;
  
-	/* Return error if mode is not supported. */
-	if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE |
-		     FALLOC_FL_COLLAPSE_RANGE)) {
+	/*
+	 * vfs_fallocate checks all possible combinations of mode.
+	 * Do additional checks here before ntfs_set_state(dirty).
+	 */
+	if (mode & FALLOC_FL_PUNCH_HOLE) {
+		if (!is_supported_holes)
+			return -EOPNOTSUPP;
+	} else if (mode & FALLOC_FL_COLLAPSE_RANGE) {
+	} else if (mode & FALLOC_FL_INSERT_RANGE) {
+		if (!is_supported_holes)
+			return -EOPNOTSUPP;
+	} else if (mode &
+		   ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE |
+		     FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_INSERT_RANGE)) {
  		ntfs_inode_warn(inode, "fallocate(0x%x) is not supported",
  				mode);
  		return -EOPNOTSUPP;
@@ -557,6 +571,8 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len)
  
  	inode_lock(inode);
  	i_size = inode->i_size;
+	new_size = max(end, i_size);
+	map_locked = false;
  
  	if (WARN_ON(ni->ni_flags & NI_FLAG_COMPRESSED_MASK)) {
  		/* Should never be here, see ntfs_file_open. */
@@ -564,38 +580,27 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len)
  		goto out;
  	}
  
+	if (mode & (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_COLLAPSE_RANGE |
+		    FALLOC_FL_INSERT_RANGE)) {
+		inode_dio_wait(inode);
+		filemap_invalidate_lock(mapping);
+		map_locked = true;
+	}
+
  	if (mode & FALLOC_FL_PUNCH_HOLE) {
  		u32 frame_size;
  		loff_t mask, vbo_a, end_a, tmp;
  
-		if (!(mode & FALLOC_FL_KEEP_SIZE)) {
-			err = -EINVAL;
-			goto out;
-		}
-
-		err = filemap_write_and_wait_range(inode->i_mapping, vbo,
-						   end - 1);
+		err = filemap_write_and_wait_range(mapping, vbo, end - 1);
  		if (err)
  			goto out;
  
-		err = filemap_write_and_wait_range(inode->i_mapping, end,
-						   LLONG_MAX);
+		err = filemap_write_and_wait_range(mapping, end, LLONG_MAX);
  		if (err)
  			goto out;
  
-		inode_dio_wait(inode);
-
  		truncate_pagecache(inode, vbo_down);
  
-		if (!is_sparsed(ni) && !is_compressed(ni)) {
-			/*
-			 * Normal file, can't make hole.
-			 * TODO: Try to find way to save info about hole.
-			 */
-			err = -EOPNOTSUPP;
-			goto out;
-		}
-
  		ni_lock(ni);
  		err = attr_punch_hole(ni, vbo, len, &frame_size);
  		ni_unlock(ni);
@@ -627,17 +632,11 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len)
  			ni_unlock(ni);
  		}
  	} else if (mode & FALLOC_FL_COLLAPSE_RANGE) {
-		if (mode & ~FALLOC_FL_COLLAPSE_RANGE) {
-			err = -EINVAL;
-			goto out;
-		}
-
  		/*
  		 * Write tail of the last page before removed range since
  		 * it will get removed from the page cache below.
  		 */
-		err = filemap_write_and_wait_range(inode->i_mapping, vbo_down,
-						   vbo);
+		err = filemap_write_and_wait_range(mapping, vbo_down, vbo);
  		if (err)
  			goto out;
  
@@ -645,34 +644,45 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len)
  		 * Write data that will be shifted to preserve them
  		 * when discarding page cache below.
  		 */
-		err = filemap_write_and_wait_range(inode->i_mapping, end,
-						   LLONG_MAX);
+		err = filemap_write_and_wait_range(mapping, end, LLONG_MAX);
  		if (err)
  			goto out;
  
-		/* Wait for existing dio to complete. */
-		inode_dio_wait(inode);
-
  		truncate_pagecache(inode, vbo_down);
  
  		ni_lock(ni);
  		err = attr_collapse_range(ni, vbo, len);
  		ni_unlock(ni);
-	} else {
-		/*
-		 * Normal file: Allocate clusters, do not change 'valid' size.
-		 */
-		loff_t new_size = max(end, i_size);
+	} else if (mode & FALLOC_FL_INSERT_RANGE) {
+		/* Check new size. */
+		err = inode_newsize_ok(inode, new_size);
+		if (err)
+			goto out;
+
+		/* Write out all dirty pages. */
+		err = filemap_write_and_wait_range(mapping, vbo_down,
+						   LLONG_MAX);
+		if (err)
+			goto out;
+		truncate_pagecache(inode, vbo_down);
  
+		ni_lock(ni);
+		err = attr_insert_range(ni, vbo, len);
+		ni_unlock(ni);
+	} else {
+		/* Check new size. */
  		err = inode_newsize_ok(inode, new_size);
  		if (err)
  			goto out;
  
+		/*
+		 * Allocate clusters, do not change 'valid' size.
+		 */
  		err = ntfs_set_size(inode, new_size);
  		if (err)
  			goto out;
  
-		if (is_sparsed(ni) || is_compressed(ni)) {
+		if (is_supported_holes) {
  			CLST vcn_v = ni->i_valid >> sbi->cluster_bits;
  			CLST vcn = vbo >> sbi->cluster_bits;
  			CLST cend = bytes_to_cluster(sbi, end);
@@ -720,6 +730,9 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len)
  	}
  
  out:
+	if (map_locked)
+		filemap_invalidate_unlock(mapping);
+
  	if (err == -EFBIG)
  		err = -ENOSPC;
  
-- 
2.36.1



      parent reply	other threads:[~2022-06-21 11:45 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-06-21 11:44 [PATCH 0/2] fs/ntfs3: FALLOC_FL_INSERT_RANGE support Konstantin Komarov
2022-06-21 11:45 ` [PATCH 1/2] fs/ntfs3: Fallocate (FALLOC_FL_INSERT_RANGE) implementation Konstantin Komarov
2022-06-21 11:45 ` Konstantin Komarov [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4fc73e0d-3987-1c2c-5ec7-6b3a94d18f63@paragon-software.com \
    --to=almaz.alexandrovich@paragon-software.com \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=ntfs3@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).