Merge tag 'f2fs-for-5.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeu...
[linux-2.6-microblaze.git] / fs / f2fs / file.c
index 1ff3337..9c8ef33 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/nls.h>
 #include <linux/sched/signal.h>
 #include <linux/fileattr.h>
+#include <linux/fadvise.h>
 
 #include "f2fs.h"
 #include "node.h"
@@ -30,6 +31,7 @@
 #include "xattr.h"
 #include "acl.h"
 #include "gc.h"
+#include "iostat.h"
 #include <trace/events/f2fs.h>
 #include <uapi/linux/f2fs.h>
 
@@ -258,8 +260,7 @@ static int f2fs_do_sync_file(struct file *file, loff_t start, loff_t end,
        };
        unsigned int seq_id = 0;
 
-       if (unlikely(f2fs_readonly(inode->i_sb) ||
-                               is_sbi_flag_set(sbi, SBI_CP_DISABLED)))
+       if (unlikely(f2fs_readonly(inode->i_sb)))
                return 0;
 
        trace_f2fs_sync_file_enter(inode);
@@ -273,7 +274,7 @@ static int f2fs_do_sync_file(struct file *file, loff_t start, loff_t end,
        ret = file_write_and_wait_range(file, start, end);
        clear_inode_flag(inode, FI_NEED_IPU);
 
-       if (ret) {
+       if (ret || is_sbi_flag_set(sbi, SBI_CP_DISABLED)) {
                trace_f2fs_sync_file_exit(inode, cp_reason, datasync, ret);
                return ret;
        }
@@ -298,6 +299,18 @@ static int f2fs_do_sync_file(struct file *file, loff_t start, loff_t end,
                                f2fs_exist_written_data(sbi, ino, UPDATE_INO))
                        goto flush_out;
                goto out;
+       } else {
+               /*
+                * for OPU case, during fsync(), node can be persisted before
+                * data when lower device doesn't support write barrier, result
+                * in data corruption after SPO.
+                * So for strict fsync mode, force to use atomic write sematics
+                * to keep write order in between data/node and last node to
+                * avoid potential data corruption.
+                */
+               if (F2FS_OPTION(sbi).fsync_mode ==
+                               FSYNC_MODE_STRICT && !atomic)
+                       atomic = true;
        }
 go_write:
        /*
@@ -737,6 +750,14 @@ int f2fs_truncate_blocks(struct inode *inode, u64 from, bool lock)
                return err;
 
 #ifdef CONFIG_F2FS_FS_COMPRESSION
+       /*
+        * For compressed file, after release compress blocks, don't allow write
+        * direct, but we should allow write direct after truncate to zero.
+        */
+       if (f2fs_compressed_file(inode) && !free_from
+                       && is_inode_flag_set(inode, FI_COMPRESS_RELEASED))
+               clear_inode_flag(inode, FI_COMPRESS_RELEASED);
+
        if (from != free_from) {
                err = f2fs_truncate_partial_cluster(inode, from, lock);
                if (err)
@@ -1082,7 +1103,6 @@ static int punch_hole(struct inode *inode, loff_t offset, loff_t len)
                }
 
                if (pg_start < pg_end) {
-                       struct address_space *mapping = inode->i_mapping;
                        loff_t blk_start, blk_end;
                        struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
 
@@ -1092,16 +1112,15 @@ static int punch_hole(struct inode *inode, loff_t offset, loff_t len)
                        blk_end = (loff_t)pg_end << PAGE_SHIFT;
 
                        down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
-                       filemap_invalidate_lock(mapping);
+                       filemap_invalidate_lock(inode->i_mapping);
 
-                       truncate_inode_pages_range(mapping, blk_start,
-                                       blk_end - 1);
+                       truncate_pagecache_range(inode, blk_start, blk_end - 1);
 
                        f2fs_lock_op(sbi);
                        ret = f2fs_truncate_hole(inode, pg_start, pg_end);
                        f2fs_unlock_op(sbi);
 
-                       filemap_invalidate_unlock(mapping);
+                       filemap_invalidate_unlock(inode->i_mapping);
                        up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
                }
        }
@@ -3473,8 +3492,8 @@ static int f2fs_release_compress_blocks(struct file *filp, unsigned long arg)
                released_blocks += ret;
        }
 
-       up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
        filemap_invalidate_unlock(inode->i_mapping);
+       up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
 out:
        inode_unlock(inode);
 
@@ -3626,8 +3645,8 @@ static int f2fs_reserve_compress_blocks(struct file *filp, unsigned long arg)
                reserved_blocks += ret;
        }
 
-       up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
        filemap_invalidate_unlock(inode->i_mapping);
+       up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
 
        if (ret >= 0) {
                clear_inode_flag(inode, FI_COMPRESS_RELEASED);
@@ -4290,7 +4309,7 @@ static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
                         * back to buffered IO.
                         */
                        if (!f2fs_force_buffered_io(inode, iocb, from) &&
-                                       allow_outplace_dio(inode, iocb, from))
+                                       f2fs_lfs_mode(F2FS_I_SB(inode)))
                                goto write;
                }
                preallocated = true;
@@ -4330,6 +4349,34 @@ out:
        return ret;
 }
 
+static int f2fs_file_fadvise(struct file *filp, loff_t offset, loff_t len,
+               int advice)
+{
+       struct inode *inode;
+       struct address_space *mapping;
+       struct backing_dev_info *bdi;
+
+       if (advice == POSIX_FADV_SEQUENTIAL) {
+               inode = file_inode(filp);
+               if (S_ISFIFO(inode->i_mode))
+                       return -ESPIPE;
+
+               mapping = filp->f_mapping;
+               if (!mapping || len < 0)
+                       return -EINVAL;
+
+               bdi = inode_to_bdi(mapping->host);
+               filp->f_ra.ra_pages = bdi->ra_pages *
+                       F2FS_I_SB(inode)->seq_file_ra_mul;
+               spin_lock(&filp->f_lock);
+               filp->f_mode &= ~FMODE_RANDOM;
+               spin_unlock(&filp->f_lock);
+               return 0;
+       }
+
+       return generic_fadvise(filp, offset, len, advice);
+}
+
 #ifdef CONFIG_COMPAT
 struct compat_f2fs_gc_range {
        u32 sync;
@@ -4458,4 +4505,5 @@ const struct file_operations f2fs_file_operations = {
 #endif
        .splice_read    = generic_file_splice_read,
        .splice_write   = iter_file_splice_write,
+       .fadvise        = f2fs_file_fadvise,
 };