Skip to content

Commit

Permalink
btrfs: Push inode locking and unlocking into buffered/direct write
Browse files Browse the repository at this point in the history
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 assigned after write checks because generic_write_check can
modify iocb->ki_pos.

Signed-off-by: Goldwyn Rodrigues <rgoldwyn@suse.com>
  • Loading branch information
goldwynr authored and intel-lab-lkp committed Sep 21, 2020
1 parent 2022340 commit 2e4ab0a
Showing 1 changed file with 44 additions and 23 deletions.
67 changes: 44 additions & 23 deletions fs/btrfs/file.c
Expand Up @@ -1698,7 +1698,7 @@ static noinline ssize_t btrfs_buffered_write(struct kiocb *iocb,
struct iov_iter *i)
{
struct file *file = iocb->ki_filp;
loff_t pos = iocb->ki_pos;
loff_t pos;
struct inode *inode = file_inode(file);
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
struct page **pages = NULL;
Expand All @@ -1712,14 +1712,29 @@ static noinline ssize_t btrfs_buffered_write(struct kiocb *iocb,
bool only_release_metadata = false;
bool force_page_uptodate = false;
loff_t old_isize = i_size_read(inode);
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 = btrfs_write_check(iocb, i);
if (ret <= 0)
goto out;

pos = iocb->ki_pos;
nrptrs = min(DIV_ROUND_UP(iov_iter_count(i), PAGE_SIZE),
PAGE_SIZE / (sizeof(struct page *)));
nrptrs = min(nrptrs, current->nr_dirtied_pause - current->nr_dirtied);
nrptrs = max(nrptrs, 8);
pages = kmalloc_array(nrptrs, sizeof(struct page *), GFP_KERNEL);
if (!pages)
return -ENOMEM;
if (!pages) {
ret = -ENOMEM;
goto out;
}

while (iov_iter_count(i) > 0) {
struct extent_state *cached_state = NULL;
Expand Down Expand Up @@ -1936,6 +1951,8 @@ static noinline ssize_t btrfs_buffered_write(struct kiocb *iocb,
pagecache_isize_extended(inode, old_isize, iocb->ki_pos);
iocb->ki_pos += num_written;
}
out:
btrfs_inode_unlock(inode, ilock_flags);
return num_written ? num_written : ret;
}

Expand All @@ -1958,15 +1975,33 @@ static ssize_t btrfs_direct_write(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;
loff_t pos;
ssize_t written = 0;
bool relock = false;
ssize_t written_buffered;
loff_t endbyte;
int err;
int ilock_flags = 0;

if (iocb->ki_flags & IOCB_NOWAIT)
ilock_flags |= BTRFS_ILOCK_TRY;

err = btrfs_inode_lock(inode, ilock_flags);
if (err < 0)
return err;

err = btrfs_write_check(iocb, from);
if (err <= 0) {
btrfs_inode_unlock(inode, ilock_flags);
goto out;
}

pos = iocb->ki_pos;

if (check_direct_IO(fs_info, from, pos))
if (check_direct_IO(fs_info, from, pos)) {
btrfs_inode_unlock(inode, ilock_flags);
goto buffered;
}

/*
* If the write DIO is beyond the EOF, we need update
Expand Down Expand Up @@ -1997,8 +2032,10 @@ static ssize_t btrfs_direct_write(struct kiocb *iocb, struct iov_iter *from)
if (relock)
btrfs_inode_lock(inode, 0);

if (written < 0 || !iov_iter_count(from))
return written;
if (written < 0 || !iov_iter_count(from)) {
err = written;
goto out;
}

buffered:
pos = iocb->ki_pos;
Expand Down Expand Up @@ -2036,7 +2073,6 @@ static ssize_t btrfs_file_write_iter(struct kiocb *iocb,
ssize_t num_written = 0;
const bool sync = iocb->ki_flags & IOCB_DSYNC;
ssize_t err;
int ilock_flags = 0;

/*
* If BTRFS flips readonly due to some impossible error
Expand All @@ -2051,19 +2087,6 @@ static ssize_t btrfs_file_write_iter(struct kiocb *iocb,
(iocb->ki_flags & IOCB_NOWAIT))
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 = btrfs_write_check(iocb, from);
if (err <= 0) {
btrfs_inode_unlock(inode, ilock_flags);
return err;
}

if (sync)
atomic_inc(&BTRFS_I(inode)->sync_writers);

Expand Down Expand Up @@ -2106,8 +2129,6 @@ static ssize_t btrfs_file_write_iter(struct kiocb *iocb,
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,
* otherwise subsequent syncs to a file that's been synced in this
Expand Down

0 comments on commit 2e4ab0a

Please sign in to comment.