Merge tag 'fuse-update-5.15' of git://git.kernel.org/pub/scm/linux/kernel/git/mszered...
[linux-2.6-microblaze.git] / fs / fuse / file.c
index 621a662..11404f8 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]);
 
@@ -1813,8 +1820,7 @@ static void fuse_writepage_end(struct fuse_mount *fm, struct fuse_args *args,
        fuse_writepage_free(wpa);
 }
 
-static struct fuse_file *__fuse_write_file_get(struct fuse_conn *fc,
-                                              struct fuse_inode *fi)
+static struct fuse_file *__fuse_write_file_get(struct fuse_inode *fi)
 {
        struct fuse_file *ff = NULL;
 
@@ -1829,22 +1835,20 @@ static struct fuse_file *__fuse_write_file_get(struct fuse_conn *fc,
        return ff;
 }
 
-static struct fuse_file *fuse_write_file_get(struct fuse_conn *fc,
-                                            struct fuse_inode *fi)
+static struct fuse_file *fuse_write_file_get(struct fuse_inode *fi)
 {
-       struct fuse_file *ff = __fuse_write_file_get(fc, fi);
+       struct fuse_file *ff = __fuse_write_file_get(fi);
        WARN_ON(!ff);
        return ff;
 }
 
 int fuse_write_inode(struct inode *inode, struct writeback_control *wbc)
 {
-       struct fuse_conn *fc = get_fuse_conn(inode);
        struct fuse_inode *fi = get_fuse_inode(inode);
        struct fuse_file *ff;
        int err;
 
-       ff = __fuse_write_file_get(fc, fi);
+       ff = __fuse_write_file_get(fi);
        err = fuse_flush_times(inode, ff);
        if (ff)
                fuse_file_put(ff, false, false);
@@ -1871,6 +1875,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;
@@ -1894,10 +1912,11 @@ static int fuse_writepage_locked(struct page *page)
                goto err_free;
 
        error = -EIO;
-       wpa->ia.ff = fuse_write_file_get(fc, fi);
+       wpa->ia.ff = fuse_write_file_get(fi);
        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);
@@ -2113,7 +2132,7 @@ static int fuse_writepages_fill(struct page *page,
 
        if (!data->ff) {
                err = -EIO;
-               data->ff = fuse_write_file_get(fc, fi);
+               data->ff = fuse_write_file_get(fi);
                if (!data->ff)
                        goto out_unlock;
        }
@@ -2148,6 +2167,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 +2902,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);