f2fs: should put a page beyond EOF when preparing a write
[linux-2.6-microblaze.git] / fs / f2fs / file.c
index ceb575f..f30b841 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>
 
@@ -63,6 +65,9 @@ static vm_fault_t f2fs_vm_page_mkwrite(struct vm_fault *vmf)
        if (unlikely(IS_IMMUTABLE(inode)))
                return VM_FAULT_SIGBUS;
 
+       if (is_inode_flag_set(inode, FI_COMPRESS_RELEASED))
+               return VM_FAULT_SIGBUS;
+
        if (unlikely(f2fs_cp_error(sbi))) {
                err = -EIO;
                goto err;
@@ -85,10 +90,6 @@ static vm_fault_t f2fs_vm_page_mkwrite(struct vm_fault *vmf)
                        err = ret;
                        goto err;
                } else if (ret) {
-                       if (ret < F2FS_I(inode)->i_cluster_size) {
-                               err = -EAGAIN;
-                               goto err;
-                       }
                        need_alloc = false;
                }
        }
@@ -117,7 +118,6 @@ static vm_fault_t f2fs_vm_page_mkwrite(struct vm_fault *vmf)
                f2fs_do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, true);
                set_new_dnode(&dn, inode, NULL, NULL, 0);
                err = f2fs_get_block(&dn, page->index);
-               f2fs_put_dnode(&dn);
                f2fs_do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, false);
        }
 
@@ -263,8 +263,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);
@@ -278,7 +277,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;
        }
@@ -303,6 +302,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:
        /*
@@ -742,6 +753,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)
@@ -1087,7 +1106,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);
 
@@ -1099,8 +1117,7 @@ static int punch_hole(struct inode *inode, loff_t offset, loff_t len)
                        down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
                        down_write(&F2FS_I(inode)->i_mmap_sem);
 
-                       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);
@@ -3203,7 +3220,7 @@ int f2fs_precache_extents(struct inode *inode)
                map.m_lblk = m_next_extent;
        }
 
-       return err;
+       return 0;
 }
 
 static int f2fs_ioc_precache_extents(struct file *filp, unsigned long arg)
@@ -3237,7 +3254,7 @@ static int f2fs_ioc_enable_verity(struct file *filp, unsigned long arg)
 
        if (!f2fs_sb_has_verity(F2FS_I_SB(inode))) {
                f2fs_warn(F2FS_I_SB(inode),
-                         "Can't enable fs-verity on inode %lu: the verity feature is not enabled on this filesystem.\n",
+                         "Can't enable fs-verity on inode %lu: the verity feature is not enabled on this filesystem",
                          inode->i_ino);
                return -EOPNOTSUPP;
        }
@@ -3425,7 +3442,7 @@ static int f2fs_release_compress_blocks(struct file *filp, unsigned long arg)
                goto out;
        }
 
-       if (IS_IMMUTABLE(inode)) {
+       if (is_inode_flag_set(inode, FI_COMPRESS_RELEASED)) {
                ret = -EINVAL;
                goto out;
        }
@@ -3434,8 +3451,7 @@ static int f2fs_release_compress_blocks(struct file *filp, unsigned long arg)
        if (ret)
                goto out;
 
-       F2FS_I(inode)->i_flags |= F2FS_IMMUTABLE_FL;
-       f2fs_set_inode_flags(inode);
+       set_inode_flag(inode, FI_COMPRESS_RELEASED);
        inode->i_ctime = current_time(inode);
        f2fs_mark_inode_dirty_sync(inode, true);
 
@@ -3478,8 +3494,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]);
        up_write(&F2FS_I(inode)->i_mmap_sem);
+       up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
 out:
        inode_unlock(inode);
 
@@ -3590,7 +3606,7 @@ static int f2fs_reserve_compress_blocks(struct file *filp, unsigned long arg)
 
        inode_lock(inode);
 
-       if (!IS_IMMUTABLE(inode)) {
+       if (!is_inode_flag_set(inode, FI_COMPRESS_RELEASED)) {
                ret = -EINVAL;
                goto unlock_inode;
        }
@@ -3631,12 +3647,11 @@ static int f2fs_reserve_compress_blocks(struct file *filp, unsigned long arg)
                reserved_blocks += ret;
        }
 
-       up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
        up_write(&F2FS_I(inode)->i_mmap_sem);
+       up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
 
        if (ret >= 0) {
-               F2FS_I(inode)->i_flags &= ~F2FS_IMMUTABLE_FL;
-               f2fs_set_inode_flags(inode);
+               clear_inode_flag(inode, FI_COMPRESS_RELEASED);
                inode->i_ctime = current_time(inode);
                f2fs_mark_inode_dirty_sync(inode, true);
        }
@@ -4023,9 +4038,8 @@ static int f2fs_ioc_decompress_file(struct file *filp, unsigned long arg)
                                                        LLONG_MAX);
 
        if (ret)
-               f2fs_warn(sbi, "%s: The file might be partially decompressed "
-                               "(errno=%d). Please delete the file.\n",
-                               __func__, ret);
+               f2fs_warn(sbi, "%s: The file might be partially decompressed (errno=%d). Please delete the file.",
+                         __func__, ret);
 out:
        inode_unlock(inode);
        file_end_write(filp);
@@ -4097,9 +4111,8 @@ static int f2fs_ioc_compress_file(struct file *filp, unsigned long arg)
        clear_inode_flag(inode, FI_ENABLE_COMPRESS);
 
        if (ret)
-               f2fs_warn(sbi, "%s: The file might be partially compressed "
-                               "(errno=%d). Please delete the file.\n",
-                               __func__, ret);
+               f2fs_warn(sbi, "%s: The file might be partially compressed (errno=%d). Please delete the file.",
+                         __func__, ret);
 out:
        inode_unlock(inode);
        file_end_write(filp);
@@ -4254,6 +4267,11 @@ static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
                goto unlock;
        }
 
+       if (is_inode_flag_set(inode, FI_COMPRESS_RELEASED)) {
+               ret = -EPERM;
+               goto unlock;
+       }
+
        ret = generic_write_checks(iocb, from);
        if (ret > 0) {
                bool preallocated = false;
@@ -4293,7 +4311,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;
@@ -4333,6 +4351,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;
@@ -4461,4 +4507,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,
 };