Skip to content

Commit

Permalink
fuse: create helper function if DIO write needs exclusive lock
Browse files Browse the repository at this point in the history
This makes the code a bit easier to read and allows to more easily add more
conditions when an exclusive lock is needed.

Signed-off-by: Bernd Schubert <[email protected]>
Signed-off-by: Miklos Szeredi <[email protected]>
  • Loading branch information
bsbernd authored and Miklos Szeredi committed Feb 23, 2024
1 parent 9511176 commit 699cf82
Showing 1 changed file with 45 additions and 18 deletions.
63 changes: 45 additions & 18 deletions fs/fuse/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -1299,6 +1299,47 @@ static ssize_t fuse_perform_write(struct kiocb *iocb, struct iov_iter *ii)
return res;
}

static bool fuse_io_past_eof(struct kiocb *iocb, struct iov_iter *iter)
{
struct inode *inode = file_inode(iocb->ki_filp);

return iocb->ki_pos + iov_iter_count(iter) > i_size_read(inode);
}

/*
* @return true if an exclusive lock for direct IO writes is needed
*/
static bool fuse_dio_wr_exclusive_lock(struct kiocb *iocb, struct iov_iter *from)
{
struct file *file = iocb->ki_filp;
struct fuse_file *ff = file->private_data;
struct inode *inode = file_inode(iocb->ki_filp);

/* Server side has to advise that it supports parallel dio writes. */
if (!(ff->open_flags & FOPEN_PARALLEL_DIRECT_WRITES))
return true;

/*
* Append will need to know the eventual EOF - always needs an
* exclusive lock.
*/
if (iocb->ki_flags & IOCB_APPEND)
return true;

/*
* Combination of page access and direct-io is difficult, shared locks
* actually introduce a conflict.
*/
if (get_fuse_conn(inode)->direct_io_allow_mmap)
return true;

/* Parallel dio beyond EOF is not supported, at least for now. */
if (fuse_io_past_eof(iocb, from))
return true;

return false;
}

static ssize_t fuse_cache_write_iter(struct kiocb *iocb, struct iov_iter *from)
{
struct file *file = iocb->ki_filp;
Expand Down Expand Up @@ -1558,26 +1599,12 @@ static ssize_t fuse_direct_read_iter(struct kiocb *iocb, struct iov_iter *to)
return res;
}

static bool fuse_direct_write_extending_i_size(struct kiocb *iocb,
struct iov_iter *iter)
{
struct inode *inode = file_inode(iocb->ki_filp);

return iocb->ki_pos + iov_iter_count(iter) > i_size_read(inode);
}

static ssize_t fuse_direct_write_iter(struct kiocb *iocb, struct iov_iter *from)
{
struct inode *inode = file_inode(iocb->ki_filp);
struct file *file = iocb->ki_filp;
struct fuse_file *ff = file->private_data;
struct fuse_io_priv io = FUSE_IO_PRIV_SYNC(iocb);
ssize_t res;
bool exclusive_lock =
!(ff->open_flags & FOPEN_PARALLEL_DIRECT_WRITES) ||
get_fuse_conn(inode)->direct_io_allow_mmap ||
iocb->ki_flags & IOCB_APPEND ||
fuse_direct_write_extending_i_size(iocb, from);
bool exclusive_lock = fuse_dio_wr_exclusive_lock(iocb, from);

/*
* Take exclusive lock if
Expand All @@ -1591,10 +1618,10 @@ static ssize_t fuse_direct_write_iter(struct kiocb *iocb, struct iov_iter *from)
else {
inode_lock_shared(inode);

/* A race with truncate might have come up as the decision for
* the lock type was done without holding the lock, check again.
/*
* Previous check was without any lock and might have raced.
*/
if (fuse_direct_write_extending_i_size(iocb, from)) {
if (fuse_io_past_eof(iocb, from)) {
inode_unlock_shared(inode);
inode_lock(inode);
exclusive_lock = true;
Expand Down

0 comments on commit 699cf82

Please sign in to comment.