diff options
-rw-r--r-- | fs/fuse/dir.c | 7 | ||||
-rw-r--r-- | fs/fuse/file.c | 8 | ||||
-rw-r--r-- | fs/fuse/fuse_i.h | 2 | ||||
-rw-r--r-- | fs/fuse/inode.c | 3 |
4 files changed, 17 insertions, 3 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index c49b8c722e27..c8334f75c8c9 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -1590,6 +1590,7 @@ int fuse_do_setattr(struct inode *inode, struct iattr *attr, struct file *file) { struct fuse_conn *fc = get_fuse_conn(inode); + struct fuse_inode *fi = get_fuse_inode(inode); struct fuse_req *req; struct fuse_setattr_in inarg; struct fuse_attr_out outarg; @@ -1617,8 +1618,10 @@ int fuse_do_setattr(struct inode *inode, struct iattr *attr, if (IS_ERR(req)) return PTR_ERR(req); - if (is_truncate) + if (is_truncate) { fuse_set_nowrite(inode); + set_bit(FUSE_I_SIZE_UNSTABLE, &fi->state); + } memset(&inarg, 0, sizeof(inarg)); memset(&outarg, 0, sizeof(outarg)); @@ -1680,12 +1683,14 @@ int fuse_do_setattr(struct inode *inode, struct iattr *attr, invalidate_inode_pages2(inode->i_mapping); } + clear_bit(FUSE_I_SIZE_UNSTABLE, &fi->state); return 0; error: if (is_truncate) fuse_release_nowrite(inode); + clear_bit(FUSE_I_SIZE_UNSTABLE, &fi->state); return err; } diff --git a/fs/fuse/file.c b/fs/fuse/file.c index d1715b30f6c4..d409deafc67b 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -629,7 +629,8 @@ static void fuse_read_update_size(struct inode *inode, loff_t size, struct fuse_inode *fi = get_fuse_inode(inode); spin_lock(&fc->lock); - if (attr_ver == fi->attr_version && size < inode->i_size) { + if (attr_ver == fi->attr_version && size < inode->i_size && + !test_bit(FUSE_I_SIZE_UNSTABLE, &fi->state)) { fi->attr_version = ++fc->attr_version; i_size_write(inode, size); } @@ -1032,12 +1033,16 @@ static ssize_t fuse_perform_write(struct file *file, { struct inode *inode = mapping->host; struct fuse_conn *fc = get_fuse_conn(inode); + struct fuse_inode *fi = get_fuse_inode(inode); int err = 0; ssize_t res = 0; if (is_bad_inode(inode)) return -EIO; + if (inode->i_size < pos + iov_iter_count(ii)) + set_bit(FUSE_I_SIZE_UNSTABLE, &fi->state); + do { struct fuse_req *req; ssize_t count; @@ -1073,6 +1078,7 @@ static ssize_t fuse_perform_write(struct file *file, if (res > 0) fuse_write_update_size(inode, pos); + clear_bit(FUSE_I_SIZE_UNSTABLE, &fi->state); fuse_invalidate_attr(inode); return res > 0 ? res : err; diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index fde7249a3a96..5ced199b50bb 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -115,6 +115,8 @@ struct fuse_inode { enum { /** Advise readdirplus */ FUSE_I_ADVISE_RDPLUS, + /** An operation changing file size is in progress */ + FUSE_I_SIZE_UNSTABLE, }; struct fuse_conn; diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 0b578598c6ac..e0fe703ee3d6 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -201,7 +201,8 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr, struct timespec old_mtime; spin_lock(&fc->lock); - if (attr_version != 0 && fi->attr_version > attr_version) { + if ((attr_version != 0 && fi->attr_version > attr_version) || + test_bit(FUSE_I_SIZE_UNSTABLE, &fi->state)) { spin_unlock(&fc->lock); return; } |