Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=e00d2c2d4aead747d0fbee99001b00612d1082b0
Commit:     e00d2c2d4aead747d0fbee99001b00612d1082b0
Parent:     c756e0a4d79202535774806f148026e40466a5eb
Author:     Miklos Szeredi <[EMAIL PROTECTED]>
AuthorDate: Tue Oct 16 23:31:01 2007 -0700
Committer:  Linus Torvalds <[EMAIL PROTECTED]>
CommitDate: Wed Oct 17 08:43:03 2007 -0700

    fuse: truncate on spontaneous size change
    
    Memory mappings were only truncated on an explicit truncate, but not when 
the
    file size was changed externally.
    
    Fix this by moving the truncation code from fuse_setattr to
    fuse_change_attributes.
    
    Yes, there are races between write and and external truncation, but we can't
    really do anything about them.
    
    Signed-off-by: Miklos Szeredi <[EMAIL PROTECTED]>
    Signed-off-by: Andrew Morton <[EMAIL PROTECTED]>
    Signed-off-by: Linus Torvalds <[EMAIL PROTECTED]>
---
 fs/fuse/dir.c   |   46 +++++++++++++---------------------------------
 fs/fuse/inode.c |   25 ++++++++++++++++++++-----
 2 files changed, 33 insertions(+), 38 deletions(-)

diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 35e5cab..29fef75 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -980,23 +980,6 @@ static void iattr_to_fattr(struct iattr *iattr, struct 
fuse_setattr_in *arg)
        }
 }
 
-static void fuse_vmtruncate(struct inode *inode, loff_t offset)
-{
-       struct fuse_conn *fc = get_fuse_conn(inode);
-       int need_trunc;
-
-       spin_lock(&fc->lock);
-       need_trunc = inode->i_size > offset;
-       i_size_write(inode, offset);
-       spin_unlock(&fc->lock);
-
-       if (need_trunc) {
-               struct address_space *mapping = inode->i_mapping;
-               unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1);
-               truncate_inode_pages(mapping, offset);
-       }
-}
-
 /*
  * Set attributes, and at the same time refresh them.
  *
@@ -1014,7 +997,6 @@ static int fuse_setattr(struct dentry *entry, struct iattr 
*attr)
        struct fuse_setattr_in inarg;
        struct fuse_attr_out outarg;
        int err;
-       int is_truncate = 0;
 
        if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
                err = inode_change_ok(inode, attr);
@@ -1024,7 +1006,6 @@ static int fuse_setattr(struct dentry *entry, struct 
iattr *attr)
 
        if (attr->ia_valid & ATTR_SIZE) {
                unsigned long limit;
-               is_truncate = 1;
                if (IS_SWAPFILE(inode))
                        return -ETXTBSY;
                limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
@@ -1051,21 +1032,20 @@ static int fuse_setattr(struct dentry *entry, struct 
iattr *attr)
        request_send(fc, req);
        err = req->out.h.error;
        fuse_put_request(fc, req);
-       if (!err) {
-               if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
-                       make_bad_inode(inode);
-                       err = -EIO;
-               } else {
-                       if (is_truncate)
-                               fuse_vmtruncate(inode, outarg.attr.size);
-                       fuse_change_attributes(inode, &outarg.attr);
-                       fi->i_time = time_to_jiffies(outarg.attr_valid,
-                                                    outarg.attr_valid_nsec);
-               }
-       } else if (err == -EINTR)
-               fuse_invalidate_attr(inode);
+       if (err) {
+               if (err == -EINTR)
+                       fuse_invalidate_attr(inode);
+               return err;
+       }
 
-       return err;
+       if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
+               make_bad_inode(inode);
+               return -EIO;
+       }
+
+       fuse_change_attributes(inode, &outarg.attr);
+       fi->i_time = time_to_jiffies(outarg.attr_valid, outarg.attr_valid_nsec);
+       return 0;
 }
 
 static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 95c8a97..b584de3 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -109,20 +109,24 @@ static int fuse_remount_fs(struct super_block *sb, int 
*flags, char *data)
        return 0;
 }
 
+static void fuse_truncate(struct address_space *mapping, loff_t offset)
+{
+       /* See vmtruncate() */
+       unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1);
+       truncate_inode_pages(mapping, offset);
+       unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1);
+}
+
 void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr)
 {
        struct fuse_conn *fc = get_fuse_conn(inode);
-       if (S_ISREG(inode->i_mode) && i_size_read(inode) != attr->size)
-               invalidate_mapping_pages(inode->i_mapping, 0, -1);
+       loff_t oldsize;
 
        inode->i_ino     = attr->ino;
        inode->i_mode    = (inode->i_mode & S_IFMT) + (attr->mode & 07777);
        inode->i_nlink   = attr->nlink;
        inode->i_uid     = attr->uid;
        inode->i_gid     = attr->gid;
-       spin_lock(&fc->lock);
-       i_size_write(inode, attr->size);
-       spin_unlock(&fc->lock);
        inode->i_blocks  = attr->blocks;
        inode->i_atime.tv_sec   = attr->atime;
        inode->i_atime.tv_nsec  = attr->atimensec;
@@ -130,6 +134,17 @@ void fuse_change_attributes(struct inode *inode, struct 
fuse_attr *attr)
        inode->i_mtime.tv_nsec  = attr->mtimensec;
        inode->i_ctime.tv_sec   = attr->ctime;
        inode->i_ctime.tv_nsec  = attr->ctimensec;
+
+       spin_lock(&fc->lock);
+       oldsize = inode->i_size;
+       i_size_write(inode, attr->size);
+       spin_unlock(&fc->lock);
+
+       if (S_ISREG(inode->i_mode) && oldsize != attr->size) {
+               if (attr->size < oldsize)
+                       fuse_truncate(inode->i_mapping, attr->size);
+               invalidate_mapping_pages(inode->i_mapping, 0, -1);
+       }
 }
 
 static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr)
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to