Similar to update size/mtime at the end of fuse_perform_write(), we need to bump the attr version when we update the inode size. Signed-off-by: Amir Goldstein <amir73il@xxxxxxxxx> --- fs/fuse/passthrough.c | 53 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 11 deletions(-) diff --git a/fs/fuse/passthrough.c b/fs/fuse/passthrough.c index 10b370bcc423..8352d6b91e0e 100644 --- a/fs/fuse/passthrough.c +++ b/fs/fuse/passthrough.c @@ -14,15 +14,42 @@ struct fuse_aio_req { struct kiocb *iocb_fuse; }; -static void fuse_aio_cleanup_handler(struct fuse_aio_req *aio_req) +static void fuse_file_start_write(struct file *fuse_file, + struct file *backing_file, + loff_t pos, size_t count) +{ + struct inode *inode = file_inode(fuse_file); + struct fuse_inode *fi = get_fuse_inode(inode); + + if (inode->i_size < pos + count) + set_bit(FUSE_I_SIZE_UNSTABLE, &fi->state); + + file_start_write(backing_file); +} + +static void fuse_file_end_write(struct file *fuse_file, + struct file *backing_file, + loff_t pos, ssize_t res) +{ + struct inode *inode = file_inode(fuse_file); + struct fuse_inode *fi = get_fuse_inode(inode); + + file_end_write(backing_file); + + fuse_write_update_attr(inode, pos, res); + clear_bit(FUSE_I_SIZE_UNSTABLE, &fi->state); +} + +static void fuse_aio_cleanup_handler(struct fuse_aio_req *aio_req, long res) { struct kiocb *iocb = &aio_req->iocb; struct kiocb *iocb_fuse = aio_req->iocb_fuse; + struct file *filp = iocb->ki_filp; + struct file *fuse_filp = iocb_fuse->ki_filp; if (iocb->ki_flags & IOCB_WRITE) { - __sb_writers_acquired(file_inode(iocb->ki_filp)->i_sb, - SB_FREEZE_WRITE); - file_end_write(iocb->ki_filp); + __sb_writers_acquired(file_inode(filp)->i_sb, SB_FREEZE_WRITE); + fuse_file_end_write(fuse_filp, filp, iocb->ki_pos, res); } iocb_fuse->ki_pos = iocb->ki_pos; @@ -35,7 +62,7 @@ static void fuse_aio_rw_complete(struct kiocb *iocb, long res) container_of(iocb, struct fuse_aio_req, iocb); struct kiocb *iocb_fuse = aio_req->iocb_fuse; - fuse_aio_cleanup_handler(aio_req); + fuse_aio_cleanup_handler(aio_req, res); iocb_fuse->ki_complete(iocb_fuse, res); } @@ -71,7 +98,7 @@ ssize_t fuse_passthrough_read_iter(struct kiocb *iocb_fuse, aio_req->iocb.ki_complete = fuse_aio_rw_complete; ret = call_read_iter(passthrough_filp, &aio_req->iocb, iter); if (ret != -EIOCBQUEUED) - fuse_aio_cleanup_handler(aio_req); + fuse_aio_cleanup_handler(aio_req, ret); } out: revert_creds(old_cred); @@ -87,22 +114,25 @@ ssize_t fuse_passthrough_write_iter(struct kiocb *iocb_fuse, struct inode *fuse_inode = file_inode(fuse_filp); struct file *passthrough_filp = ff->passthrough->filp; struct inode *passthrough_inode = file_inode(passthrough_filp); + size_t count = iov_iter_count(iter); const struct cred *old_cred; ssize_t ret; rwf_t rwf; - if (!iov_iter_count(iter)) + if (!count) return 0; inode_lock(fuse_inode); old_cred = override_creds(ff->passthrough->cred); if (is_sync_kiocb(iocb_fuse)) { - file_start_write(passthrough_filp); + fuse_file_start_write(fuse_filp, passthrough_filp, + iocb_fuse->ki_pos, count); rwf = iocb_to_rw_flags(iocb_fuse->ki_flags, FUSE_IOCB_MASK); ret = vfs_iter_write(passthrough_filp, iter, &iocb_fuse->ki_pos, rwf); - file_end_write(passthrough_filp); + fuse_file_end_write(fuse_filp, passthrough_filp, + iocb_fuse->ki_pos, ret); } else { struct fuse_aio_req *aio_req; @@ -112,7 +142,8 @@ ssize_t fuse_passthrough_write_iter(struct kiocb *iocb_fuse, goto out; } - file_start_write(passthrough_filp); + fuse_file_start_write(fuse_filp, passthrough_filp, + iocb_fuse->ki_pos, count); __sb_writers_release(passthrough_inode->i_sb, SB_FREEZE_WRITE); aio_req->iocb_fuse = iocb_fuse; @@ -120,7 +151,7 @@ ssize_t fuse_passthrough_write_iter(struct kiocb *iocb_fuse, aio_req->iocb.ki_complete = fuse_aio_rw_complete; ret = call_write_iter(passthrough_filp, &aio_req->iocb, iter); if (ret != -EIOCBQUEUED) - fuse_aio_cleanup_handler(aio_req); + fuse_aio_cleanup_handler(aio_req, ret); } out: revert_creds(old_cred); -- 2.34.1