From: Goldwyn Rodrigues <rgoldwyn@suse.de>
To: linux-fsdevel@vger.kernel.org
Cc: linux-btrfs@vger.kernel.org, david@fromorbit.com, hch@lst.de,
johannes.thumshirn@wdc.com, dsterba@suse.com,
darrick.wong@oracle.com, josef@toxicpanda.com,
Goldwyn Rodrigues <rgoldwyn@suse.com>
Subject: [PATCH 08/14] btrfs: Introduce btrfs_write_check()
Date: Thu, 24 Sep 2020 11:39:15 -0500 [thread overview]
Message-ID: <20200924163922.2547-9-rgoldwyn@suse.de> (raw)
In-Reply-To: <20200924163922.2547-1-rgoldwyn@suse.de>
From: Goldwyn Rodrigues <rgoldwyn@suse.com>
btrfs_write_check() checks for all parameters in one place before
beginning a write. This does away with inode_unlock() after every check.
In the later patches, it will help push inode_lock/unlock() in buffered
and direct write functions respectively.
Signed-off-by: Goldwyn Rodrigues <rgoldwyn@suse.com>
---
fs/btrfs/file.c | 160 +++++++++++++++++++++++++-----------------------
1 file changed, 82 insertions(+), 78 deletions(-)
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index f7e96754d4c9..61885b180c8c 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -1615,6 +1615,86 @@ void btrfs_check_nocow_unlock(struct btrfs_inode *inode)
btrfs_drew_write_unlock(&inode->root->snapshot_lock);
}
+static void update_time_for_write(struct inode *inode)
+{
+ struct timespec64 now;
+
+ if (IS_NOCMTIME(inode))
+ return;
+
+ now = current_time(inode);
+ if (!timespec64_equal(&inode->i_mtime, &now))
+ inode->i_mtime = now;
+
+ if (!timespec64_equal(&inode->i_ctime, &now))
+ inode->i_ctime = now;
+
+ if (IS_I_VERSION(inode))
+ inode_inc_iversion(inode);
+}
+
+static size_t btrfs_write_check(struct kiocb *iocb, struct iov_iter *from)
+{
+ struct file *file = iocb->ki_filp;
+ struct inode *inode = file_inode(file);
+ struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
+ loff_t pos = iocb->ki_pos;
+ size_t count = iov_iter_count(from);
+ int err;
+ loff_t oldsize;
+ loff_t start_pos;
+
+ err = generic_write_checks(iocb, from);
+ if (err <= 0)
+ return err;
+
+ if (iocb->ki_flags & IOCB_NOWAIT) {
+ size_t nocow_bytes = count;
+
+ /*
+ * We will allocate space in case nodatacow is not set,
+ * so bail
+ */
+ if (check_nocow_nolock(BTRFS_I(inode), pos, &nocow_bytes) <= 0)
+ return -EAGAIN;
+ /*
+ * There are holes in the range or parts of the range that must
+ * be COWed (shared extents, RO block groups, etc), so just bail
+ * out.
+ */
+ if (nocow_bytes < count)
+ return -EAGAIN;
+ }
+
+ current->backing_dev_info = inode_to_bdi(inode);
+ err = file_remove_privs(file);
+ if (err)
+ return err;
+
+ /*
+ * We reserve space for updating the inode when we reserve space for the
+ * extent we are going to write, so we will enospc out there. We don't
+ * need to start yet another transaction to update the inode as we will
+ * update the inode when we finish writing whatever data we write.
+ */
+ update_time_for_write(inode);
+
+ start_pos = round_down(pos, fs_info->sectorsize);
+ oldsize = i_size_read(inode);
+ if (start_pos > oldsize) {
+ /* Expand hole size to cover write data, preventing empty gap */
+ loff_t end_pos = round_up(pos + count,
+ fs_info->sectorsize);
+ err = btrfs_cont_expand(inode, oldsize, end_pos);
+ if (err) {
+ current->backing_dev_info = NULL;
+ return err;
+ }
+ }
+
+ return count;
+}
+
static noinline ssize_t btrfs_buffered_write(struct kiocb *iocb,
struct iov_iter *i)
{
@@ -1947,24 +2027,6 @@ static ssize_t btrfs_direct_write(struct kiocb *iocb, struct iov_iter *from)
return written ? written : err;
}
-static void update_time_for_write(struct inode *inode)
-{
- struct timespec64 now;
-
- if (IS_NOCMTIME(inode))
- return;
-
- now = current_time(inode);
- if (!timespec64_equal(&inode->i_mtime, &now))
- inode->i_mtime = now;
-
- if (!timespec64_equal(&inode->i_ctime, &now))
- inode->i_ctime = now;
-
- if (IS_I_VERSION(inode))
- inode_inc_iversion(inode);
-}
-
static ssize_t btrfs_file_write_iter(struct kiocb *iocb,
struct iov_iter *from)
{
@@ -1972,14 +2034,9 @@ static ssize_t btrfs_file_write_iter(struct kiocb *iocb,
struct inode *inode = file_inode(file);
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
struct btrfs_root *root = BTRFS_I(inode)->root;
- u64 start_pos;
- u64 end_pos;
ssize_t num_written = 0;
const bool sync = iocb->ki_flags & IOCB_DSYNC;
ssize_t err;
- loff_t pos;
- size_t count;
- loff_t oldsize;
/*
* If BTRFS flips readonly due to some impossible error,
@@ -2000,65 +2057,12 @@ static ssize_t btrfs_file_write_iter(struct kiocb *iocb,
inode_lock(inode);
}
- err = generic_write_checks(iocb, from);
+ err = btrfs_write_check(iocb, from);
if (err <= 0) {
inode_unlock(inode);
return err;
}
- pos = iocb->ki_pos;
- count = iov_iter_count(from);
- if (iocb->ki_flags & IOCB_NOWAIT) {
- size_t nocow_bytes = count;
-
- /*
- * We will allocate space in case nodatacow is not set,
- * so bail
- */
- if (check_nocow_nolock(BTRFS_I(inode), pos, &nocow_bytes)
- <= 0) {
- inode_unlock(inode);
- return -EAGAIN;
- }
- /*
- * There are holes in the range or parts of the range that must
- * be COWed (shared extents, RO block groups, etc), so just bail
- * out.
- */
- if (nocow_bytes < count) {
- inode_unlock(inode);
- return -EAGAIN;
- }
- }
-
- current->backing_dev_info = inode_to_bdi(inode);
- err = file_remove_privs(file);
- if (err) {
- inode_unlock(inode);
- goto out;
- }
-
- /*
- * We reserve space for updating the inode when we reserve space for the
- * extent we are going to write, so we will enospc out there. We don't
- * need to start yet another transaction to update the inode as we will
- * update the inode when we finish writing whatever data we write.
- */
- update_time_for_write(inode);
-
- start_pos = round_down(pos, fs_info->sectorsize);
- oldsize = i_size_read(inode);
- if (start_pos > oldsize) {
- /* Expand hole size to cover write data, preventing empty gap */
- end_pos = round_up(pos + count,
- fs_info->sectorsize);
- err = btrfs_cont_expand(inode, oldsize, end_pos);
- if (err) {
- inode_unlock(inode);
- goto out;
- }
- }
-
if (sync)
atomic_inc(&BTRFS_I(inode)->sync_writers);
@@ -2116,7 +2120,7 @@ static ssize_t btrfs_file_write_iter(struct kiocb *iocb,
if (sync)
atomic_dec(&BTRFS_I(inode)->sync_writers);
-out:
+
current->backing_dev_info = NULL;
return num_written ? num_written : err;
}
--
2.26.2
next prev parent reply other threads:[~2020-09-24 16:40 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-09-24 16:39 [PATCH 0/14 v3] BTRFS DIO inode locking/D_SYNC fix Goldwyn Rodrigues
2020-09-24 16:39 ` [PATCH 01/14] fs: remove dio_end_io() Goldwyn Rodrigues
2020-09-29 12:16 ` David Sterba
2020-09-24 16:39 ` [PATCH 02/14] btrfs: remove BTRFS_INODE_READDIO_NEED_LOCK Goldwyn Rodrigues
2020-09-24 16:39 ` [PATCH 03/14] iomap: Allow filesystem to call iomap_dio_complete without i_rwsem Goldwyn Rodrigues
2020-09-26 1:49 ` Darrick J. Wong
2020-09-24 16:39 ` [PATCH 04/14] iomap: Call inode_dio_end() before generic_write_sync() Goldwyn Rodrigues
2020-09-26 1:51 ` Darrick J. Wong
2020-09-28 15:04 ` David Sterba
2020-09-28 16:12 ` Darrick J. Wong
2020-09-24 16:39 ` [PATCH 05/14] btrfs: split btrfs_direct_IO to read and write Goldwyn Rodrigues
2020-09-24 16:39 ` [PATCH 06/14] btrfs: Move pos increment and pagecache extension to btrfs_buffered_write() Goldwyn Rodrigues
2020-09-24 16:39 ` [PATCH 07/14] btrfs: Move FS error state bit early during write Goldwyn Rodrigues
2020-09-24 16:39 ` Goldwyn Rodrigues [this message]
2020-10-09 14:21 ` [PATCH 08/14] btrfs: Introduce btrfs_write_check() Josef Bacik
2020-09-24 16:39 ` [PATCH 09/14] btrfs: Introduce btrfs_inode_lock()/unlock() Goldwyn Rodrigues
2020-09-24 16:39 ` [PATCH 10/14] btrfs: Push inode locking and unlocking into buffered/direct write Goldwyn Rodrigues
2020-09-24 16:39 ` [PATCH 11/14] btrfs: Use inode_lock_shared() for direct writes within EOF Goldwyn Rodrigues
2020-10-09 14:25 ` Josef Bacik
2020-09-24 16:39 ` [PATCH 12/14] btrfs: Remove dio_sem Goldwyn Rodrigues
2020-09-24 16:39 ` [PATCH 13/14] btrfs: Call iomap_dio_complete() without inode_lock Goldwyn Rodrigues
2020-09-24 16:39 ` [PATCH 14/14] btrfs: Revert 09745ff88d93 ("btrfs: dio iomap DSYNC workaround") Goldwyn Rodrigues
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=20200924163922.2547-9-rgoldwyn@suse.de \
--to=rgoldwyn@suse.de \
--cc=darrick.wong@oracle.com \
--cc=david@fromorbit.com \
--cc=dsterba@suse.com \
--cc=hch@lst.de \
--cc=johannes.thumshirn@wdc.com \
--cc=josef@toxicpanda.com \
--cc=linux-btrfs@vger.kernel.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=rgoldwyn@suse.com \
/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).