Commit c3523706 authored by Goldwyn Rodrigues's avatar Goldwyn Rodrigues Committed by David Sterba

btrfs: push inode locking and unlocking into buffered/direct write

Push inode locking and unlocking closer to where we perform the I/O. For
this we need to move the write checks inside the respective functions as
well.

pos is evaluated after generic_write_checks because O_APPEND can change
iocb->ki_pos.
Reviewed-by: default avatarJosef Bacik <josef@toxicpanda.com>
Signed-off-by: default avatarGoldwyn Rodrigues <rgoldwyn@suse.com>
Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent a14b78ad
...@@ -1641,7 +1641,7 @@ static noinline ssize_t btrfs_buffered_write(struct kiocb *iocb, ...@@ -1641,7 +1641,7 @@ static noinline ssize_t btrfs_buffered_write(struct kiocb *iocb,
struct iov_iter *i) struct iov_iter *i)
{ {
struct file *file = iocb->ki_filp; struct file *file = iocb->ki_filp;
loff_t pos = iocb->ki_pos; loff_t pos;
struct inode *inode = file_inode(file); struct inode *inode = file_inode(file);
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
struct page **pages = NULL; struct page **pages = NULL;
...@@ -1651,18 +1651,37 @@ static noinline ssize_t btrfs_buffered_write(struct kiocb *iocb, ...@@ -1651,18 +1651,37 @@ static noinline ssize_t btrfs_buffered_write(struct kiocb *iocb,
u64 lockend; u64 lockend;
size_t num_written = 0; size_t num_written = 0;
int nrptrs; int nrptrs;
int ret = 0; ssize_t ret;
bool only_release_metadata = false; bool only_release_metadata = false;
bool force_page_uptodate = false; bool force_page_uptodate = false;
loff_t old_isize = i_size_read(inode); loff_t old_isize = i_size_read(inode);
unsigned int ilock_flags = 0;
if (iocb->ki_flags & IOCB_NOWAIT)
ilock_flags |= BTRFS_ILOCK_TRY;
ret = btrfs_inode_lock(inode, ilock_flags);
if (ret < 0)
return ret;
ret = generic_write_checks(iocb, i);
if (ret <= 0)
goto out;
ret = btrfs_write_check(iocb, i, ret);
if (ret < 0)
goto out;
pos = iocb->ki_pos;
nrptrs = min(DIV_ROUND_UP(iov_iter_count(i), PAGE_SIZE), nrptrs = min(DIV_ROUND_UP(iov_iter_count(i), PAGE_SIZE),
PAGE_SIZE / (sizeof(struct page *))); PAGE_SIZE / (sizeof(struct page *)));
nrptrs = min(nrptrs, current->nr_dirtied_pause - current->nr_dirtied); nrptrs = min(nrptrs, current->nr_dirtied_pause - current->nr_dirtied);
nrptrs = max(nrptrs, 8); nrptrs = max(nrptrs, 8);
pages = kmalloc_array(nrptrs, sizeof(struct page *), GFP_KERNEL); pages = kmalloc_array(nrptrs, sizeof(struct page *), GFP_KERNEL);
if (!pages) if (!pages) {
return -ENOMEM; ret = -ENOMEM;
goto out;
}
while (iov_iter_count(i) > 0) { while (iov_iter_count(i) > 0) {
struct extent_state *cached_state = NULL; struct extent_state *cached_state = NULL;
...@@ -1857,6 +1876,8 @@ static noinline ssize_t btrfs_buffered_write(struct kiocb *iocb, ...@@ -1857,6 +1876,8 @@ static noinline ssize_t btrfs_buffered_write(struct kiocb *iocb,
pagecache_isize_extended(inode, old_isize, iocb->ki_pos); pagecache_isize_extended(inode, old_isize, iocb->ki_pos);
iocb->ki_pos += num_written; iocb->ki_pos += num_written;
} }
out:
btrfs_inode_unlock(inode, ilock_flags);
return num_written ? num_written : ret; return num_written ? num_written : ret;
} }
...@@ -1879,15 +1900,39 @@ static ssize_t btrfs_direct_write(struct kiocb *iocb, struct iov_iter *from) ...@@ -1879,15 +1900,39 @@ static ssize_t btrfs_direct_write(struct kiocb *iocb, struct iov_iter *from)
struct file *file = iocb->ki_filp; struct file *file = iocb->ki_filp;
struct inode *inode = file_inode(file); struct inode *inode = file_inode(file);
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
loff_t pos = iocb->ki_pos; loff_t pos;
ssize_t written = 0; ssize_t written = 0;
bool relock = false; bool relock = false;
ssize_t written_buffered; ssize_t written_buffered;
loff_t endbyte; loff_t endbyte;
int err; ssize_t err;
unsigned int ilock_flags = 0;
if (iocb->ki_flags & IOCB_NOWAIT)
ilock_flags |= BTRFS_ILOCK_TRY;
if (check_direct_IO(fs_info, from, pos)) err = btrfs_inode_lock(inode, ilock_flags);
if (err < 0)
return err;
err = generic_write_checks(iocb, from);
if (err <= 0) {
btrfs_inode_unlock(inode, ilock_flags);
return err;
}
err = btrfs_write_check(iocb, from, err);
if (err < 0) {
btrfs_inode_unlock(inode, ilock_flags);
goto out;
}
pos = iocb->ki_pos;
if (check_direct_IO(fs_info, from, pos)) {
btrfs_inode_unlock(inode, ilock_flags);
goto buffered; goto buffered;
}
/* /*
* If the write DIO is beyond EOF, we need to update the isize, but it * If the write DIO is beyond EOF, we need to update the isize, but it
...@@ -1917,8 +1962,10 @@ static ssize_t btrfs_direct_write(struct kiocb *iocb, struct iov_iter *from) ...@@ -1917,8 +1962,10 @@ static ssize_t btrfs_direct_write(struct kiocb *iocb, struct iov_iter *from)
if (relock) if (relock)
btrfs_inode_lock(inode, 0); btrfs_inode_lock(inode, 0);
if (written < 0 || !iov_iter_count(from)) if (written < 0 || !iov_iter_count(from)) {
return written; err = written;
goto out;
}
buffered: buffered:
pos = iocb->ki_pos; pos = iocb->ki_pos;
...@@ -1955,8 +2002,6 @@ static ssize_t btrfs_file_write_iter(struct kiocb *iocb, ...@@ -1955,8 +2002,6 @@ static ssize_t btrfs_file_write_iter(struct kiocb *iocb,
struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_root *root = BTRFS_I(inode)->root;
ssize_t num_written = 0; ssize_t num_written = 0;
const bool sync = iocb->ki_flags & IOCB_DSYNC; const bool sync = iocb->ki_flags & IOCB_DSYNC;
ssize_t err;
unsigned int ilock_flags = 0;
/* /*
* If the fs flips readonly due to some impossible error, although we * If the fs flips readonly due to some impossible error, although we
...@@ -1970,25 +2015,6 @@ static ssize_t btrfs_file_write_iter(struct kiocb *iocb, ...@@ -1970,25 +2015,6 @@ static ssize_t btrfs_file_write_iter(struct kiocb *iocb,
(iocb->ki_flags & IOCB_NOWAIT)) (iocb->ki_flags & IOCB_NOWAIT))
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (iocb->ki_flags & IOCB_NOWAIT)
ilock_flags |= BTRFS_ILOCK_TRY;
err = btrfs_inode_lock(inode, ilock_flags);
if (err < 0)
return err;
err = generic_write_checks(iocb, from);
if (err <= 0) {
btrfs_inode_unlock(inode, ilock_flags);
return err;
}
err = btrfs_write_check(iocb, from, err);
if (err < 0) {
btrfs_inode_unlock(inode, ilock_flags);
return err;
}
if (sync) if (sync)
atomic_inc(&BTRFS_I(inode)->sync_writers); atomic_inc(&BTRFS_I(inode)->sync_writers);
...@@ -2031,8 +2057,6 @@ static ssize_t btrfs_file_write_iter(struct kiocb *iocb, ...@@ -2031,8 +2057,6 @@ static ssize_t btrfs_file_write_iter(struct kiocb *iocb,
num_written = btrfs_buffered_write(iocb, from); num_written = btrfs_buffered_write(iocb, from);
} }
btrfs_inode_unlock(inode, ilock_flags);
/* /*
* We also have to set last_sub_trans to the current log transid, * We also have to set last_sub_trans to the current log transid,
* otherwise subsequent syncs to a file that's been synced in this * otherwise subsequent syncs to a file that's been synced in this
...@@ -2048,7 +2072,7 @@ static ssize_t btrfs_file_write_iter(struct kiocb *iocb, ...@@ -2048,7 +2072,7 @@ static ssize_t btrfs_file_write_iter(struct kiocb *iocb,
atomic_dec(&BTRFS_I(inode)->sync_writers); atomic_dec(&BTRFS_I(inode)->sync_writers);
current->backing_dev_info = NULL; current->backing_dev_info = NULL;
return num_written ? num_written : err; return num_written;
} }
int btrfs_release_file(struct inode *inode, struct file *filp) int btrfs_release_file(struct inode *inode, struct file *filp)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment