fuse: wait for writepages in syncfs
[linux-2.6-microblaze.git] / fs / fuse / file.c
index 97f860c..2bca7ed 100644 (file)
@@ -198,12 +198,11 @@ void fuse_finish_open(struct inode *inode, struct file *file)
        struct fuse_file *ff = file->private_data;
        struct fuse_conn *fc = get_fuse_conn(inode);
 
-       if (!(ff->open_flags & FOPEN_KEEP_CACHE))
-               invalidate_inode_pages2(inode->i_mapping);
        if (ff->open_flags & FOPEN_STREAM)
                stream_open(inode, file);
        else if (ff->open_flags & FOPEN_NONSEEKABLE)
                nonseekable_open(inode, file);
+
        if (fc->atomic_o_trunc && (file->f_flags & O_TRUNC)) {
                struct fuse_inode *fi = get_fuse_inode(inode);
 
@@ -211,10 +210,14 @@ void fuse_finish_open(struct inode *inode, struct file *file)
                fi->attr_version = atomic64_inc_return(&fc->attr_version);
                i_size_write(inode, 0);
                spin_unlock(&fi->lock);
+               truncate_pagecache(inode, 0);
                fuse_invalidate_attr(inode);
                if (fc->writeback_cache)
                        file_update_time(file);
+       } else if (!(ff->open_flags & FOPEN_KEEP_CACHE)) {
+               invalidate_inode_pages2(inode->i_mapping);
        }
+
        if ((file->f_mode & FMODE_WRITE) && fc->writeback_cache)
                fuse_link_write_file(file);
 }
@@ -389,6 +392,7 @@ struct fuse_writepage_args {
        struct list_head queue_entry;
        struct fuse_writepage_args *next;
        struct inode *inode;
+       struct fuse_sync_bucket *bucket;
 };
 
 static struct fuse_writepage_args *fuse_find_writeback(struct fuse_inode *fi,
@@ -1608,6 +1612,9 @@ static void fuse_writepage_free(struct fuse_writepage_args *wpa)
        struct fuse_args_pages *ap = &wpa->ia.ap;
        int i;
 
+       if (wpa->bucket)
+               fuse_sync_bucket_dec(wpa->bucket);
+
        for (i = 0; i < ap->num_pages; i++)
                __free_page(ap->pages[i]);
 
@@ -1871,6 +1878,20 @@ static struct fuse_writepage_args *fuse_writepage_args_alloc(void)
 
 }
 
+static void fuse_writepage_add_to_bucket(struct fuse_conn *fc,
+                                        struct fuse_writepage_args *wpa)
+{
+       if (!fc->sync_fs)
+               return;
+
+       rcu_read_lock();
+       /* Prevent resurrection of dead bucket in unlikely race with syncfs */
+       do {
+               wpa->bucket = rcu_dereference(fc->curr_bucket);
+       } while (unlikely(!atomic_inc_not_zero(&wpa->bucket->count)));
+       rcu_read_unlock();
+}
+
 static int fuse_writepage_locked(struct page *page)
 {
        struct address_space *mapping = page->mapping;
@@ -1898,6 +1919,7 @@ static int fuse_writepage_locked(struct page *page)
        if (!wpa->ia.ff)
                goto err_nofile;
 
+       fuse_writepage_add_to_bucket(fc, wpa);
        fuse_write_args_fill(&wpa->ia, wpa->ia.ff, page_offset(page), 0);
 
        copy_highpage(tmp_page, page);
@@ -2148,6 +2170,8 @@ static int fuse_writepages_fill(struct page *page,
                        __free_page(tmp_page);
                        goto out_unlock;
                }
+               fuse_writepage_add_to_bucket(fc, wpa);
+
                data->max_pages = 1;
 
                ap = &wpa->ia.ap;
@@ -2881,7 +2905,7 @@ fuse_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
 
 static int fuse_writeback_range(struct inode *inode, loff_t start, loff_t end)
 {
-       int err = filemap_write_and_wait_range(inode->i_mapping, start, end);
+       int err = filemap_write_and_wait_range(inode->i_mapping, start, -1);
 
        if (!err)
                fuse_sync_writes(inode);