]> Pileus Git - ~andy/linux/commitdiff
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi...
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 9 Sep 2013 16:18:23 +0000 (09:18 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 9 Sep 2013 16:18:23 +0000 (09:18 -0700)
Pull fuse bugfixes from Miklos Szeredi:
 "Just a bunch of bugfixes"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse:
  fuse: use list_for_each_entry() for list traversing
  fuse: readdir: check for slash in names
  fuse: hotfix truncate_pagecache() issue
  fuse: invalidate inode attributes on xattr modification
  fuse: postpone end_page_writeback() in fuse_writepage_locked()

fs/fuse/dev.c
fs/fuse/dir.c
fs/fuse/file.c
fs/fuse/fuse_i.h
fs/fuse/inode.c

index 1d55f94654000dbc8e8c0de37e0cb32471e3791a..ef74ad5fd362b193d858fdd2cfe3335d951d2a99 100644 (file)
@@ -1765,11 +1765,9 @@ static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code,
 /* Look up request on processing list by unique ID */
 static struct fuse_req *request_find(struct fuse_conn *fc, u64 unique)
 {
-       struct list_head *entry;
+       struct fuse_req *req;
 
-       list_for_each(entry, &fc->processing) {
-               struct fuse_req *req;
-               req = list_entry(entry, struct fuse_req, list);
+       list_for_each_entry(req, &fc->processing, list) {
                if (req->in.h.unique == unique || req->intr_unique == unique)
                        return req;
        }
index 0e6961aae6c02e04414e432abb8b62826907bfbf..3ac91086f41f528c9e570f6925389d968a4076ff 100644 (file)
@@ -1177,6 +1177,8 @@ static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
                        return -EIO;
                if (reclen > nbytes)
                        break;
+               if (memchr(dirent->name, '/', dirent->namelen) != NULL)
+                       return -EIO;
 
                if (!dir_emit(ctx, dirent->name, dirent->namelen,
                               dirent->ino, dirent->type))
@@ -1315,6 +1317,8 @@ static int parse_dirplusfile(char *buf, size_t nbytes, struct file *file,
                        return -EIO;
                if (reclen > nbytes)
                        break;
+               if (memchr(dirent->name, '/', dirent->namelen) != NULL)
+                       return -EIO;
 
                if (!over) {
                        /* We fill entries into dstbuf only as much as
@@ -1585,6 +1589,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;
@@ -1612,8 +1617,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));
@@ -1675,12 +1682,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;
 }
 
@@ -1744,6 +1753,8 @@ static int fuse_setxattr(struct dentry *entry, const char *name,
                fc->no_setxattr = 1;
                err = -EOPNOTSUPP;
        }
+       if (!err)
+               fuse_invalidate_attr(inode);
        return err;
 }
 
@@ -1873,6 +1884,8 @@ static int fuse_removexattr(struct dentry *entry, const char *name)
                fc->no_removexattr = 1;
                err = -EOPNOTSUPP;
        }
+       if (!err)
+               fuse_invalidate_attr(inode);
        return err;
 }
 
index 5c121fe19c5f9b6122b687cc14bbcd7b1bbe0dc9..d409deafc67b2f6c94fb3fa53b96a21c60585d56 100644 (file)
@@ -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;
@@ -1529,7 +1535,6 @@ static int fuse_writepage_locked(struct page *page)
 
        inc_bdi_stat(mapping->backing_dev_info, BDI_WRITEBACK);
        inc_zone_page_state(tmp_page, NR_WRITEBACK_TEMP);
-       end_page_writeback(page);
 
        spin_lock(&fc->lock);
        list_add(&req->writepages_entry, &fi->writepages);
@@ -1537,6 +1542,8 @@ static int fuse_writepage_locked(struct page *page)
        fuse_flush_writepages(inode);
        spin_unlock(&fc->lock);
 
+       end_page_writeback(page);
+
        return 0;
 
 err_free:
index fde7249a3a9608c8c6e49be4316a1d155b7cdfba..5ced199b50bbb19a9dcd8fb42313de4afba26d6c 100644 (file)
@@ -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;
index 0b578598c6ac8a66f17ed7f4511d7ec0cf9132db..e0fe703ee3d681156ed2e2b20610e8ee6d72131a 100644 (file)
@@ -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;
        }