The commit is pushed to "branch-rh7-3.10.0-327.36.1.vz7.20.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git after rh7-3.10.0-327.36.1.vz7.20.15 ------> commit b6b7fc7f1d2dbfef8fb8a8e109e33cb770ce43ac Author: Maxim Patlasov <mpatla...@virtuozzo.com> Date: Thu Dec 15 17:48:29 2016 +0400
fuse: trust server file size unless opened Before the patch, the only way to pick up updated file size from server (in a scenario when local inode was created earlier, then the file was updated from another node) was in fuse_open_common(): > atomic_inc(&fi->num_openers); > > if (atomic_read(&fi->num_openers) == 1) { > err = fuse_getattr_size(inode, file, &size); > ... > spin_lock(&fc->lock); > i_size_write(inode, size); > spin_unlock(&fc->lock); > } This is correct, but someone may ask about i_size w/o open, e.g.: ls -l foo. The patch ensures that every time the server reports us some file size, if no open-s happened yet (num_openers=0), fuse stores that server size in local inode->i_size. This resolves the following problem: # pstorage-mount -c test -l /var/log/f1.log /pcs1 # pstorage-mount -c test -l /var/log/f2.log /pcs2 # date > /pcs1/foo; ls -l /pcs1/foo /pcs2/foo -rwx------ 1 root root 29 Dec 14 16:31 /pcs1/foo -rwx------ 1 root root 29 Dec 14 16:31 /pcs2/foo # date >> /pcs1/foo; ls -l /pcs1/foo /pcs2/foo -rwx------ 1 root root 58 Dec 14 16:31 /pcs1/foo -rwx------ 1 root root 29 Dec 14 16:31 /pcs2/foo https://jira.sw.ru/browse/PSBM-57047 Signed-off-by: Maxim Patlasov <mpatla...@virtuozzo.com> Acked-by: Dmitry Monakhov <dmonak...@openvz.org> --- fs/fuse/file.c | 12 +++++++++++- fs/fuse/fuse_i.h | 3 +++ fs/fuse/inode.c | 4 +++- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 501aa27..1bda994 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -296,12 +296,20 @@ int fuse_open_common(struct inode *inode, struct file *file, bool isdir) u64 size; mutex_lock(&inode->i_mutex); + + spin_lock(&fc->lock); atomic_inc(&fi->num_openers); if (atomic_read(&fi->num_openers) == 1) { + fi->i_size_unstable = 1; + spin_unlock(&fc->lock); err = fuse_getattr_size(inode, file, &size); if (err) { + spin_lock(&fc->lock); atomic_dec(&fi->num_openers); + fi->i_size_unstable = 0; + spin_unlock(&fc->lock); + mutex_unlock(&inode->i_mutex); fuse_release_common(file, FUSE_RELEASE); return err; @@ -309,8 +317,10 @@ int fuse_open_common(struct inode *inode, struct file *file, bool isdir) spin_lock(&fc->lock); i_size_write(inode, size); + fi->i_size_unstable = 0; + spin_unlock(&fc->lock); + } else spin_unlock(&fc->lock); - } mutex_unlock(&inode->i_mutex); } diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 1d24bf6..22eb9c9 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -124,6 +124,9 @@ struct fuse_inode { /** Mostly to detect very first open */ atomic_t num_openers; + + /** Even though num_openers>0, trust server i_size */ + int i_size_unstable; }; /** FUSE inode state bits */ diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 5ccecae..f606deb 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -97,6 +97,7 @@ static struct inode *fuse_alloc_inode(struct super_block *sb) fi->writectr = 0; fi->orig_ino = 0; fi->state = 0; + fi->i_size_unstable = 0; INIT_LIST_HEAD(&fi->write_files); INIT_LIST_HEAD(&fi->rw_files); INIT_LIST_HEAD(&fi->queued_writes); @@ -226,7 +227,8 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr, * extend local i_size without keeping userspace server in sync. So, * attr->size coming from server can be stale. We cannot trust it. */ - if (!is_wb || !S_ISREG(inode->i_mode)) + if (!is_wb || !S_ISREG(inode->i_mode) || + !atomic_read(&fi->num_openers) || fi->i_size_unstable) i_size_write(inode, attr->size); spin_unlock(&fc->lock); _______________________________________________ Devel mailing list Devel@openvz.org https://lists.openvz.org/mailman/listinfo/devel